Advertisement
1lann

socket.lua

Feb 1st, 2015
385
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.84 KB | None | 0 0
  1.  
  2. --
  3. --  JSON API by Elvis Jerricco: http://pastebin.com/4nRg9CHU
  4. --
  5.  
  6. local encode, encodePretty, parseBoolean, parseNull, parseString, parseArray
  7. local parseObject, parseMember, parseValue, decode, decodeFromFile
  8.  
  9. local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"}
  10.  
  11. local function isArray(t)
  12.     local max = 0
  13.     for k,v in pairs(t) do
  14.         if type(k) ~= "number" then
  15.             return false
  16.         elseif k > max then
  17.             max = k
  18.         end
  19.     end
  20.     return max == #t
  21. end
  22.  
  23. local whites = {['\n']=true; ['r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
  24. function removeWhite(str)
  25.     while whites[str:sub(1, 1)] do
  26.         str = str:sub(2)
  27.     end
  28.     return str
  29. end
  30.  
  31.  
  32. local function encodeCommon(val, pretty, tabLevel, tTracking)
  33.     local str = ""
  34.  
  35.     -- Tabbing util
  36.     local function tab(s)
  37.         str = str .. ("\t"):rep(tabLevel) .. s
  38.     end
  39.  
  40.     local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
  41.         str = str .. bracket
  42.         if pretty then
  43.             str = str .. "\n"
  44.             tabLevel = tabLevel + 1
  45.         end
  46.         for k,v in iterator(val) do
  47.             tab("")
  48.             loopFunc(k,v)
  49.             str = str .. ","
  50.             if pretty then str = str .. "\n" end
  51.         end
  52.         if pretty then
  53.             tabLevel = tabLevel - 1
  54.         end
  55.         if str:sub(-2) == ",\n" then
  56.             str = str:sub(1, -3) .. "\n"
  57.         elseif str:sub(-1) == "," then
  58.             str = str:sub(1, -2)
  59.         end
  60.         tab(closeBracket)
  61.     end
  62.  
  63.     -- Table encoding
  64.     if type(val) == "table" then
  65.         assert(not tTracking[val], "Cannot encode a table holding itself recursively")
  66.         tTracking[val] = true
  67.         if isArray(val) then
  68.             arrEncoding(val, "[", "]", ipairs, function(k,v)
  69.                 str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
  70.             end)
  71.         else
  72.             arrEncoding(val, "{", "}", pairs, function(k,v)
  73.                 assert(type(k) == "string", "JSON object keys must be strings", 2)
  74.                 str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
  75.                 str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
  76.             end)
  77.         end
  78.     -- String encoding
  79.     elseif type(val) == "string" then
  80.         str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
  81.     -- Number encoding
  82.     elseif type(val) == "number" or type(val) == "boolean" then
  83.         str = tostring(val)
  84.     else
  85.         error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
  86.     end
  87.     return str
  88. end
  89.  
  90. function encode(val)
  91.     return encodeCommon(val, false, 0, {})
  92. end
  93.  
  94. function encodePretty(val)
  95.     return encodeCommon(val, true, 0, {})
  96. end
  97.  
  98.  
  99. function parseBoolean(str)
  100.     if str:sub(1, 4) == "true" then
  101.         return true, removeWhite(str:sub(5))
  102.     else
  103.         return false, removeWhite(str:sub(6))
  104.     end
  105. end
  106.  
  107. function parseNull(str)
  108.     return nil, removeWhite(str:sub(5))
  109. end
  110.  
  111. local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true}
  112. function parseNumber(str)
  113.     local i = 1
  114.     while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do
  115.         i = i + 1
  116.     end
  117.     local val = tonumber(str:sub(1, i - 1))
  118.     str = removeWhite(str:sub(i))
  119.     return val, str
  120. end
  121.  
  122. function parseString(str)
  123.     local i,j = str:find('[^\\]"')
  124.     local s = str:sub(2, j - 1)
  125.  
  126.     for k,v in pairs(controls) do
  127.         s = s:gsub(v, k)
  128.     end
  129.     str = removeWhite(str:sub(j + 1))
  130.     return s, str
  131. end
  132.  
  133. function parseArray(str)
  134.     str = removeWhite(str:sub(2))
  135.  
  136.     local val = {}
  137.     local i = 1
  138.     while str:sub(1, 1) ~= "]" do
  139.         local v = nil
  140.         v, str = parseValue(str)
  141.         val[i] = v
  142.         i = i + 1
  143.         str = removeWhite(str)
  144.     end
  145.     str = removeWhite(str:sub(2))
  146.     return val, str
  147. end
  148.  
  149. function parseObject(str)
  150.     str = removeWhite(str:sub(2))
  151.  
  152.     local val = {}
  153.     while str:sub(1, 1) ~= "}" do
  154.         local k, v = nil, nil
  155.         k, v, str = parseMember(str)
  156.         val[k] = v
  157.         str = removeWhite(str)
  158.     end
  159.     str = removeWhite(str:sub(2))
  160.     return val, str
  161. end
  162.  
  163. function parseMember(str)
  164.     local k = nil
  165.     k, str = parseValue(str)
  166.     local val = nil
  167.     val, str = parseValue(str)
  168.     return k, val, str
  169. end
  170.  
  171. function parseValue(str)
  172.     local fchar = str:sub(1, 1)
  173.     if fchar == "{" then
  174.         return parseObject(str)
  175.     elseif fchar == "[" then
  176.         return parseArray(str)
  177.     elseif tonumber(fchar) ~= nil or numChars[fchar] then
  178.         return parseNumber(str)
  179.     elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
  180.         return parseBoolean(str)
  181.     elseif fchar == "\"" then
  182.         return parseString(str)
  183.     elseif str:sub(1, 4) == "null" then
  184.         return parseNull(str)
  185.     end
  186.     return nil
  187. end
  188.  
  189. function decode(str)
  190.     str = removeWhite(str)
  191.     t = parseValue(str)
  192.     return t
  193. end
  194.  
  195. function decodeFromFile(path)
  196.     local file = assert(fs.open(path, "r"))
  197.     return decode(file.readAll())
  198. end
  199.  
  200. --
  201. --  Socket Library. Fast and asynchronous.
  202. --
  203.  
  204. Socket = {}
  205. Socket.__index = Socket
  206.  
  207. Socket.timeout = 30 -- Should be server timeout + 10. DO NOT CHANGE UNLESS
  208.                     -- YOU OWN THE SERVER FOR THE SOCKET CONNECTION, AND
  209.                     -- HAVE CONFIGURED THE SERVER CORRECTLY.
  210.  
  211. Socket.connections = {}
  212. Socket.messages = {}
  213. Socket.timers = {}
  214.  
  215. Socket.emptyResponse = "empty response"
  216. Socket.unexpectedError = "unexpected error"
  217. Socket.httpFailure = "http failure"
  218. Socket.parseError = "parse error"
  219. Socket.verifyFailure = "verify failure"
  220. Socket.serverError = "server error"
  221. Socket.identityTaken = "identifier already in use"
  222. Socket.timeoutError = "timeout"
  223.  
  224. function Socket.randomId()
  225.     return tostring({}):sub(8, -1)
  226. end
  227.  
  228. function Socket.encodePost(data)
  229.     local ret = ""
  230.     for k, v in pairs(data) do
  231.         ret = ret .. textutils.urlEncode(k) .. "=" .. textutils.urlEncode(v) .. "&"
  232.     end
  233.  
  234.     return ret:sub(1, -2)
  235. end
  236.  
  237. function Socket.new(address, identifier)
  238.     local self = setmetatable({}, Socket)
  239.     self:setup(address, identifier)
  240.     table.insert(Socket.connections, self)
  241.     return self
  242. end
  243.  
  244. local function queueSocketFailure(fullAddress, message)
  245.     local requestObject = Socket.messages[fullAddress]
  246.  
  247.     if requestObject then
  248.         if requestObject.listen == "true" then
  249.             os.queueEvent("socket_failure", requestObject.address, "listen",
  250.                 "", requestObject.identifier, message)
  251.         else
  252.             os.queueEvent("socket_failure", requestObject.address, "send",
  253.                 requestObject.channel, requestObject.identifier, message)
  254.         end
  255.     end
  256.  
  257.     Socket.messages[fullAddress] = nil
  258. end
  259.  
  260. local function refreshConnection(fullAddress)
  261.     local requestObject = Socket.messages[fullAddress]
  262.  
  263.     local request = {
  264.         ["identifier"] = requestObject.identifier,
  265.         ["listen"] = "true",
  266.         ["messageId"] = requestObject.messageId
  267.     }
  268.  
  269.     if not http.request(fullAddress, Socket.encodePost(request)) then
  270.         error("Socket: HTTP request failed")
  271.     end
  272.  
  273.     local timer = os.startTimer(Socket.timeout)
  274.     Socket.timers[fullAddress] = timer
  275. end
  276.  
  277. local function handleReceivedMessage(fullAddress, message)
  278.     local requestObject = Socket.messages[fullAddress]
  279.  
  280.     resp, result = pcall(function() return decode(message) end)
  281.     if resp then
  282.         if type(result.MessageId) == "string" and
  283.                 result.MessageId == requestObject.messageId then
  284.             if result.Error then
  285.                 if type(result.Message) == "string" then
  286.                     if result.Message == Socket.identityTaken then
  287.                         queueSocketFailure(fullAddress, Socket.identityTaken)
  288.                     else
  289.                         queueSocketFailure(fullAddress, Socket.serverError)
  290.                     end
  291.                 else
  292.                     queueSocketFailure(fullAddress, Socket.serverError)
  293.                 end
  294.             elseif result.SendSuccess then
  295.                 os.queueEvent("socket_write_success", requestObject.address,
  296.                     requestObject.channel, requestObject.identifier,
  297.                     requestObject.message)
  298.                 Socket.messages[fullAddress] = nil
  299.             elseif result.RefreshConnection then
  300.                 refreshConnection(fullAddress)
  301.             elseif type(result.Queue) == "table" then
  302.                 local queue = result.Queue
  303.                 for k, v in pairs(queue) do
  304.                     if type(v.Channel) == "string" and
  305.                             type(v.Message) == "string" then
  306.                         os.queueEvent("socket_message", requestObject.address,
  307.                             v.Channel, requestObject.identifier, v.Message)
  308.                     end
  309.                 end
  310.                 refreshConnection(fullAddress)
  311.             elseif type(result.Message) == "string" and
  312.                     type(result.Channel) == "string" and
  313.                     result.Message:len() > 0 and result.Channel:len() > 0 then
  314.                 os.queueEvent("socket_message", requestObject.address,
  315.                     result.Channel, requestObject.identifier, result.Message)
  316.                 refreshConnection(fullAddress)
  317.             else
  318.                 queueSocketFailure(fullAddress, Socket.verifyFailure)
  319.             end
  320.         else
  321.             queueSocketFailure(fullAddress, Socket.verifyFailure)
  322.         end
  323.     else
  324.         queueSocketFailure(fullAddress, Socket.parseError)
  325.     end
  326. end
  327.  
  328. local function getSocketFromTimer(id)
  329.     for k, v in pairs(Socket.timers) do
  330.         if v == id then
  331.             return k
  332.         end
  333.     end
  334. end
  335.  
  336. local function getSocketFromDetails(address, identifier)
  337.     for k, v in pairs(Socket.connections) do
  338.         if v.address == address and v.identifier == identifier then
  339.             return v
  340.         end
  341.     end
  342. end
  343.  
  344. function Socket.run()
  345.     while true do
  346.         local event, url, handle, identifier, message = os.pullEvent()
  347.         if event == "timer" then
  348.             local timerAddress = getSocketFromTimer(url)
  349.             if timerAddress then
  350.                 queueSocketFailure(timerAddress, Socket.timeoutError)
  351.             end
  352.         elseif event == "socket_message" then
  353.             local channel = handle
  354.             local socket = getSocketFromDetails(url, identifier)
  355.             if socket then
  356.                 if type(socket.listeners[channel]) == "function" then
  357.                     socket.listeners[channel](message)
  358.                 end
  359.             end
  360.         elseif event == "http_success" then
  361.             if type(url) == "string" and
  362.                     type(handle) == "table" and
  363.                     type(handle.readAll) == "function" then
  364.                 if Socket.messages[url] then
  365.                     if not handle then
  366.                         queueSocketFailure(url, Socket.emptyResponse)
  367.                     else
  368.                         local resp, contents = pcall(handle.readAll)
  369.                         if resp then
  370.                             handleReceivedMessage(url, contents)
  371.                         else
  372.                             queueSocketFailure(url, Socket.unexpectedError)
  373.                         end
  374.                     end
  375.                 end
  376.             end
  377.         elseif event == "http_failure" then
  378.             queueSocketFailure(url, Socket.httpFailure)
  379.         end
  380.     end
  381. end
  382.  
  383. function Socket:setup(address, identifier)
  384.     if self.closed then
  385.         error("u wot m8, use :reconnect plz")
  386.     end
  387.  
  388.     if not identifier then
  389.         identifier = Socket.randomId()
  390.     end
  391.  
  392.     if address:sub(1, 4) ~= "http" then
  393.         error("http prefix required for socket address")
  394.     end
  395.  
  396.     self.address = address
  397.     self.identifier = identifier
  398.     self.listeners = {}
  399.  
  400.     local messageId = Socket.randomId()
  401.     local request = {
  402.         ["identifier"] = identifier,
  403.         ["listen"] = "true",
  404.         ["messageId"] = messageId
  405.     }
  406.  
  407.     fullAddress = address .. "#" .. messageId
  408.     self.fullAddress = fullAddress
  409.     self.listenId = messageId
  410.  
  411.     if not http.request(fullAddress, Socket.encodePost(request)) then
  412.         error("Socket: HTTP request failed")
  413.     end
  414.  
  415.     request["address"] = address
  416.     Socket.messages[fullAddress] = request
  417.  
  418.     local timer = os.startTimer(Socket.timeout)
  419.     Socket.timers[fullAddress] = timer
  420. end
  421.  
  422. function Socket:write(channel, contents)
  423.     if self.closed then
  424.         error("Cannot write to closed socket")
  425.     end
  426.  
  427.     local messageId = Socket.randomId()
  428.  
  429.     local request = {
  430.         ["channel"] = channel,
  431.         ["identifier"] = self.identifier,
  432.         ["listen"] = "false",
  433.         ["messageId"] = messageId,
  434.         ["message"] = contents
  435.     }
  436.  
  437.     fullAddress = self.address .. "#" .. messageId
  438.  
  439.     if not http.request(fullAddress, Socket.encodePost(request)) then
  440.         error("Socket: HTTP request failed")
  441.     end
  442.  
  443.     request["address"] = self.address
  444.     Socket.messages[fullAddress] = request
  445. end
  446.  
  447. function Socket:on(channel, func)
  448.     if self.closed then
  449.         error("Really? You want to attach a listener on a closed socket?")
  450.     end
  451.  
  452.     self.listeners[channel] = func
  453. end
  454.  
  455. function Socket:reconnect()
  456.     self.closed = false
  457.     table.insert(Socket.connections, self)
  458.  
  459.     Socket.messages[self.fullAddress] = {
  460.         ["identifier"] = self.identifier,
  461.         ["messageId"] = self.listenId,
  462.         ["listen"] = "true",
  463.         ["address"] = self.address
  464.     }
  465.  
  466.     refreshConnection(self.fullAddress)
  467. end
  468.  
  469. function Socket:close()
  470.     self.closed = true
  471.     for k, v in pairs(Socket.connections) do
  472.         if v == self then
  473.             table.remove(Socket.connections, k)
  474.             break
  475.         end
  476.     end
  477. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement