Last active
September 16, 2021 13:11
-
-
Save lukacat10/16e1a06d89b5829f743e398ce99cf81f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package.preload["argparse"] = function(...) | |
local function errorf(msg, ...) | |
error(msg:format(...), 0) | |
end | |
local function setter(arg, result, value) | |
result[arg.name] = value or true | |
end | |
local parser = { __name = "ArgParser" } | |
parser.__index = parser | |
function parser:add(names, arg) | |
if type(names) == "string" then names = { names } end | |
arg.names = names | |
for i = 1, #names do | |
local name = names[i] | |
if name:sub(1, 2) == "--" then self.options[name:sub(3)] = arg | |
elseif name:sub(1, 1) == "-" then self.flags[name:sub(2)] = arg | |
else self.arguments[#self.arguments + 1] = arg; arg.argument = true end | |
end | |
table.insert(self.list, #self.list, arg) | |
if arg.action == nil then arg.action = setter end | |
if arg.required == nil then arg.required = names[1]:sub(1, 1) ~= "-" end | |
if arg.name == nil then arg.name = names[1]:gsub("^-+", "") end | |
if arg.mvar == nil then arg.mvar = arg.name:upper() end | |
end | |
function parser:parse(...) | |
local args = table.pack(...) | |
local i, n = 1, #args | |
local arg_idx = 1 | |
local result = {} | |
while i <= n do | |
local arg = args[i] | |
i = i + 1 | |
if arg:find("^%-%-([^=]+)=(.+)$") then | |
local name, value = arg:match("^%-%-([^=]+)=(.+)$") | |
local arg = self.options[name] | |
if not arg then errorf("Unknown argument %q", name) end | |
if not arg.many and result[arg.name] ~= nil then errorf("%s has already been set", name) end | |
if not arg.value then errorf("%s does not accept a value", name) end | |
arg:action(result, value) | |
elseif arg:find("^%-%-(.*)$") then | |
local name = arg:match("^%-%-(.*)$") | |
local arg = self.options[name] | |
if not arg then errorf("Unknown argument %q", name) end | |
if not arg.many and result[arg.name] ~= nil then errorf("%s has already been set", name) end | |
if arg.value then | |
local value = args[i] | |
i = i + 1 | |
if not value then errorf("%s needs a value", name) end | |
arg:action(result, value) | |
else | |
arg:action(result) | |
end | |
elseif arg:find("^%-(.+)$") then | |
local flags = arg:match("^%-(.+)$") | |
for j = 1, #flags do | |
local name = flags:sub(j, j) | |
local arg = self.flags[name] | |
if not arg then errorf("Unknown argument %q", name) end | |
if not arg.many and result[arg.name] ~= nil then errorf("%s has already been set", name) end | |
if arg.value then | |
local value | |
if j == #flags then | |
value = args[i] | |
i = i + 1 | |
else | |
value = flags:sub(j + 1) | |
end | |
if not value then errorf("%s expects a value", name) end | |
arg:action(result, value) | |
break | |
else | |
arg:action(result) | |
end | |
end | |
else | |
local argument = self.arguments[arg_idx] | |
if argument then | |
argument:action(result, arg) | |
arg_idx = arg_idx + 1 | |
else | |
errorf("Unexpected argument %q", arg) | |
end | |
end | |
end | |
for i = 1, #self.list do | |
local arg = self.list[i] | |
if arg and arg.required and result[arg.name] == nil then | |
errorf("%s is required (use -h to see usage)", arg.name) | |
end | |
end | |
return result | |
end | |
local function get_usage(arg) | |
local name | |
if arg.argument then name = arg.mvar | |
elseif arg.value then name = arg.names[1] .. "=" .. arg.mvar | |
else name = arg.names[1] | |
end | |
if #arg.names > 1 then name = name .. "," .. table.concat(arg.names, ",", 2) end | |
return name | |
end | |
local function create(prefix) | |
local parser = setmetatable({ | |
options = {}, | |
flags = {}, | |
arguments = {}, | |
list = {}, | |
}, parser) | |
parser:add({ "-h", "--help", "-?" }, { | |
value = false, required = false, | |
doc = "Show this help message", | |
action = function() | |
if prefix then print(prefix) print() end | |
print("USAGE") | |
local max = 0 | |
for i = 1, #parser.list do max = math.max(max, #get_usage(parser.list[i])) end | |
local format = " %-" .. max .. "s %s" | |
for i = 1, #parser.list do | |
local arg = parser.list[i] | |
print(format:format(get_usage(arg), arg.doc or "")) | |
end | |
error("", 0) | |
end, | |
}) | |
return parser | |
end | |
local function is_help(cmd) | |
return cmd == "help" or cmd == "--help" or cmd == "-h" or cmd == "-?" | |
end | |
return { create = create, is_help = is_help } | |
end | |
package.preload["json"] = function(...) | |
local tonumber = tonumber | |
local function skip_delim(str, pos, delim, err_if_missing) | |
pos = pos + #str:match('^%s*', pos) | |
if str:sub(pos, pos) ~= delim then | |
if err_if_missing then error('Expected ' .. delim) end | |
return pos, false | |
end | |
return pos + 1, true | |
end | |
local esc_map = { b = '\b', f = '\f', n = '\n', r = '\r', t = '\t' } | |
local function parse_str_val(str, pos) | |
local out, n = {}, 0 | |
if pos > #str then error("Malformed JSON (in string)") end | |
while true do | |
local c = str:sub(pos, pos) | |
if c == '"' then return table.concat(out, "", 1, n), pos + 1 end | |
n = n + 1 | |
if c == '\\' then | |
local nextc = str:sub(pos + 1, pos + 1) | |
if not nextc then error("Malformed JSON (in string)") end | |
if nextc == "u" then | |
local num = tonumber(str:sub(pos + 2, pos + 5), 16) | |
if not num then error("Malformed JSON (in unicode string) ") end | |
if num <= 255 then | |
pos, out[n] = pos + 6, string.char(num) | |
else | |
pos, out[n] = pos + 6, "?" | |
end | |
else | |
pos, out[n] = pos + 2, esc_map[nextc] or nextc | |
end | |
else | |
pos, out[n] = pos + 1, c | |
end | |
end | |
end | |
local function parse_num_val(str, pos) | |
local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) | |
local val = tonumber(num_str) | |
if not val then error('Error parsing number at position ' .. pos .. '.') end | |
return val, pos + #num_str | |
end | |
local null = {} | |
local literals = {['true'] = true, ['false'] = false, ['null'] = null } | |
local escapes = {} | |
for i = 0, 255 do | |
local c = string.char(i) | |
if i >= 32 and i <= 126 | |
then escapes[c] = c | |
else escapes[c] = ("\\u00%02x"):format(i) | |
end | |
end | |
escapes["\t"], escapes["\n"], escapes["\r"], escapes["\""], escapes["\\"] = "\\t", "\\n", "\\r", "\\\"", "\\\\" | |
local function parse(str, pos, end_delim) | |
pos = pos or 1 | |
if pos > #str then error('Reached unexpected end of input.') end | |
local pos = pos + #str:match('^%s*', pos) | |
local first = str:sub(pos, pos) | |
if first == '{' then | |
local obj, key, delim_found = {}, true, true | |
pos = pos + 1 | |
while true do | |
key, pos = parse(str, pos, '}') | |
if key == nil then return obj, pos end | |
if not delim_found then error('Comma missing between object items.') end | |
pos = skip_delim(str, pos, ':', true) | |
obj[key], pos = parse(str, pos) | |
pos, delim_found = skip_delim(str, pos, ',') | |
end | |
elseif first == '[' then | |
local arr, val, delim_found = {}, true, true | |
pos = pos + 1 | |
while true do | |
val, pos = parse(str, pos, ']') | |
if val == nil then return arr, pos end | |
if not delim_found then error('Comma missing between array items.') end | |
arr[#arr + 1] = val | |
pos, delim_found = skip_delim(str, pos, ',') | |
end | |
elseif first == '"' then | |
return parse_str_val(str, pos + 1) | |
elseif first == '-' or first:match('%d') then | |
return parse_num_val(str, pos) | |
elseif first == end_delim then | |
return nil, pos + 1 | |
else | |
for lit_str, lit_val in pairs(literals) do | |
local lit_end = pos + #lit_str - 1 | |
if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end | |
end | |
local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) | |
error('Invalid json syntax starting at ' .. pos_info_str) | |
end | |
end | |
local format, gsub, tostring, pairs, next, type, concat | |
= string.format, string.gsub, tostring, pairs, next, type, table.concat | |
local function stringify_impl(t, out, n) | |
local ty = type(t) | |
if ty == "table" then | |
local first_ty = type(next(t)) | |
if first_ty == "nil" then | |
out[n], n = "{}", n + 1 | |
return n | |
elseif first_ty == "string" then | |
out[n], n = "{", n + 1 | |
local first = true | |
for k, v in pairs(t) do | |
if first then first = false else out[n], n = ",", n + 1 end | |
out[n] = format("\"%s\":", k) | |
n = stringify_impl(v, out, n + 1) | |
end | |
out[n], n = "}", n + 1 | |
return n | |
elseif first_ty == "number" then | |
out[n], n = "[", n + 1 | |
for i = 1, #t do | |
if i > 1 then out[n], n = ",", n + 1 end | |
n = stringify_impl(t[i], out, n) | |
end | |
out[n], n = "]", n + 1 | |
return n | |
else | |
error("Cannot serialize key " .. first_ty) | |
end | |
elseif ty == "string" then | |
if t:match("^[ -~]*$") then | |
out[n], n = gsub(format("%q", t), "\n", "n"), n + 1 | |
else | |
out[n], n = "\"" .. gsub(t, ".", escapes) .. "\"", n + 1 | |
end | |
return n | |
elseif ty == "number" or ty == "boolean" then | |
out[n],n = tostring(t), n + 1 | |
return n | |
elseif ty == "function" then | |
out[n], n = tostring(t), n+ 1 | |
else error("Cannot serialize type " .. ty) | |
end | |
end | |
local function stringify(object) | |
local buffer = {} | |
local n = stringify_impl(object, buffer, 1) | |
return concat(buffer, "", 1, n - 1) | |
end | |
local function try_parse(msg) | |
local ok, res = pcall(parse, msg) | |
if ok then return res else return nil, res end | |
end | |
return { | |
stringify = stringify, | |
try_parse = try_parse, | |
parse = parse, | |
null = null | |
} | |
end | |
local tonumber, type, keys = tonumber, type, keys | |
local argparse = require "argparse" | |
local hson = require "json" | |
local current_path = shell.getRunningProgram() | |
local current_name = fs.getName(current_path) | |
local arguments = argparse.create(current_name .. ": Run Lua on this computer from the World Wide Web") | |
arguments:add({ "url" }, { doc = "The url of the websocket" }) | |
arguments:add({ "turtleid" }, { doc = "The id to give to the turtle" }) | |
arguments:add({ "password" }, { doc = "The password for this connect" }) | |
local args = arguments:parse(...) | |
local turtleid = args.turtleid | |
local url = args.url | |
local password = args.password | |
local remote, err = http.websocket(url) | |
if not remote then error("Cannot connect to cloud-catcher server: " .. err, 0) end | |
function codesnip(ws, received) | |
loadstring("returned={"..received.."}")() | |
ws.send(textutils.serializeJSON(returned)) | |
end | |
function connect() | |
local ws, err = http.websocket(url) | |
if ws then | |
ws.send(turtleid) | |
ws.send(password) | |
while true do | |
received = ws.receive() | |
if received ~= nil then | |
print(received) | |
ok, err = pcall(codesnip, ws, received) | |
if ok == false then | |
print("errored!") | |
ws.send(err) | |
end | |
end | |
end | |
ws.close() | |
end | |
while true do | |
pcall(connect) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment