Advertisement
Epoc

RailStatus : IG Server

Aug 25th, 2013
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.86 KB | None | 0 0
  1. --    ___              _       _      ___     _               _                    
  2. --   | _ \   __ _     (_)     | |    / __|   | |_    __ _    | |_    _  _     ___  
  3. --   |   /  / _` |    | |     | |    \__ \   |  _|  / _` |   |  _|  | +| |   (_-<  
  4. --   |_|_\  \__,_|   _|_|_   _|_|_   |___/   _\__|  \__,_|   _\__|   \_,_|   /__/_  
  5. -- _|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|
  6. -- "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'
  7. --
  8. --                              RailStatus : IG Server
  9. --
  10. -- La seconde génération de RailStatus (http://pastebin.com/js3pN87r), un programme permettant
  11. -- de connaître en temps réel et en jeu (in game) le statut des aiguillages d'un réseau ferroviaire en
  12. -- utilisant RailCraft, ComputerCraft et RedPower
  13. --
  14. -- Utilisation :
  15. -- 1. Dans un ordinateur, importer ce programme depuis Pastebin :
  16. --     pastebin get KAy0Kqfw railstatusigs
  17. -- 2. Lancer le programme :
  18. --     railstatusig [ID de la carte] [URL de base d'appel vers l'API]
  19. --     Exemple : railstatusigs 1 http://exemple.fr/api
  20. --
  21. -- Client : http://pastebin.com/KsJ9gukb
  22. -- Dépôt Github : https://github.com/EaSyCompanyFr/RailStatus
  23.  
  24. term.clear()
  25. term.setCursorPos(1,1)
  26.  
  27. print("RailStatus : IG Server is starting...")
  28.  
  29. -- Arguments passés au programme
  30. args = {...}
  31.  
  32. if table.getn(args) < 2 then
  33.   print("  One or more parameters are missing")
  34.   return
  35. end
  36.  
  37. -- --------------------------------------------------------
  38. -- Constantes
  39.  
  40. -- Tableau de correspondance nom de couleur > identifiant décimal
  41. COLORS_ARRAY = {}
  42.  
  43. COLORS_ARRAY["white"] = colors.white
  44. COLORS_ARRAY["orange"] = colors.orange
  45. COLORS_ARRAY["magenta"] = colors.magenta
  46. COLORS_ARRAY["lightBlue"] = colors.lightBlue
  47. COLORS_ARRAY["yellow"] = colors.yellow
  48. COLORS_ARRAY["lime"] = colors.lime
  49. COLORS_ARRAY["pink"] = colors.pink
  50. COLORS_ARRAY["gray"] = colors.gray
  51. COLORS_ARRAY["lightGray"] = colors.lightGray
  52. COLORS_ARRAY["cyan"] = colors.cyan
  53. COLORS_ARRAY["purple"] = colors.purple
  54. COLORS_ARRAY["blue"] = colors.blue
  55. COLORS_ARRAY["brown"] = colors.brown
  56. COLORS_ARRAY["green"] = colors.green
  57. COLORS_ARRAY["red"] = colors.red
  58. COLORS_ARRAY["black"] = colors.black
  59.  
  60. -- Récupération du premier type de périphérique détecté
  61. function getFirstPeripheralSide(peripheral_type)
  62.   for k,side in pairs(redstone.getSides()) do
  63.     if peripheral.isPresent(side) and peripheral.getType(side) == peripheral_type then
  64.       return side
  65.     end
  66.   end
  67.  
  68.   return false
  69. end
  70.  
  71. -- De quel côté est branché le moniteur avancé pour afficher la carte
  72. MONITOR_SIDE = getFirstPeripheralSide("monitor")
  73.  
  74. if not MONITOR_SIDE then
  75.   print("  Advanced monitor not detected on this computer")
  76.   return
  77. end
  78.  
  79. MONITOR = peripheral.wrap(MONITOR_SIDE)
  80.  
  81. -- Si le moniteur n'est pas de type avancé
  82. if not MONITOR.isColor() then
  83.   print("  And advanced monitor is required")
  84.   return
  85. end
  86.  
  87. print("  Advanced monitor side : "..MONITOR_SIDE)
  88.  
  89. -- Modem
  90. MODEM_SIDE = getFirstPeripheralSide("modem")
  91.  
  92. if not MODEM_SIDE then
  93.   print(" Modem not detected on this computer")
  94.   return
  95. end
  96.  
  97. print("  Modem side : "..MODEM_SIDE)
  98.  
  99. -- ID de la carte à utiliser
  100. MAP_ID = args[1]
  101.  
  102. print("  Map ID : "..MAP_ID)
  103.  
  104. -- URL de base d'appel vers l'API
  105. API_ENDPOINT = args[2]
  106.  
  107. print("  Endpoint : "..API_ENDPOINT)
  108.  
  109. print("  Computer ID : "..os.getComputerID())
  110.  
  111. print("")
  112. print("To stop RailStatus : IG, hold CTRL+T for some seconds.")
  113.  
  114. -- --------------------------------------------------------
  115. -- Fonctions et librairies
  116.  
  117. -- JSON4Lua: JSON encoding / decoding support for the Lua language.
  118. -- json Module.
  119. -- Author: Craig Mason-Jones
  120. -- Homepage: http://json.luaforge.net/
  121. -- Version: 0.9.40
  122. -- This module is released under the MIT License (MIT).
  123.  
  124. local base = _G
  125. local decode_scanArray
  126. local decode_scanComment
  127. local decode_scanConstant
  128. local decode_scanNumber
  129. local decode_scanObject
  130. local decode_scanString
  131. local decode_scanWhitespace
  132. local encodeString
  133. local isArray
  134. local isEncodable
  135.  
  136. local function encode (v)
  137.   -- Handle nil values
  138.   if v==nil then
  139.     return "null"
  140.   end
  141.  
  142.   local vtype = base.type(v)  
  143.  
  144.   -- Handle strings
  145.   if vtype=='string' then    
  146.     return '"' .. encodeString(v) .. '"'            -- Need to handle encoding in string
  147.   end
  148.  
  149.   -- Handle booleans
  150.   if vtype=='number' or vtype=='boolean' then
  151.     return base.tostring(v)
  152.   end
  153.  
  154.   -- Handle tables
  155.   if vtype=='table' then
  156.     local rval = {}
  157.     -- Consider arrays separately
  158.     local bArray, maxCount = isArray(v)
  159.     if bArray then
  160.       for i = 1,maxCount do
  161.         table.insert(rval, encode(v[i]))
  162.       end
  163.     else        -- An object, not an array
  164.       for i,j in base.pairs(v) do
  165.         if isEncodable(i) and isEncodable(j) then
  166.           table.insert(rval, '"' .. encodeString(i) .. '":' .. encode(j))
  167.         end
  168.       end
  169.     end
  170.     if bArray then
  171.       return '[' .. table.concat(rval,',') ..']'
  172.     else
  173.       return '{' .. table.concat(rval,',') .. '}'
  174.     end
  175.   end
  176.  
  177.   -- Handle null values
  178.   if vtype=='function' and v==null then
  179.     return 'null'
  180.   end
  181.  
  182.   base.assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. base.tostring(v))
  183. end
  184.  
  185. local function decode(s, startPos)
  186.   startPos = startPos and startPos or 1
  187.   startPos = decode_scanWhitespace(s,startPos)
  188.   base.assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
  189.   local curChar = string.sub(s,startPos,startPos)
  190.   -- Object
  191.   if curChar=='{' then
  192.     return decode_scanObject(s,startPos)
  193.   end
  194.   -- Array
  195.   if curChar=='[' then
  196.     return decode_scanArray(s,startPos)
  197.   end
  198.   -- Number
  199.   if string.find("+-0123456789.e", curChar, 1, true) then
  200.     return decode_scanNumber(s,startPos)
  201.   end
  202.   -- String
  203.   if curChar==[["]] or curChar==[[']] then
  204.    return decode_scanString(s,startPos)
  205.  end
  206.  if string.sub(s,startPos,startPos+1)=='/*' then
  207.    return decode(s, decode_scanComment(s,startPos))
  208.  end
  209.  -- Otherwise, it must be a constant
  210.  return decode_scanConstant(s,startPos)
  211. end
  212.  
  213. local function null()
  214.  return null -- so json.null() will also return null ;-)
  215. end
  216.  
  217. function decode_scanArray(s,startPos)
  218.  local array = {}      -- The return value
  219.  local stringLen = string.len(s)
  220.  base.assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
  221.  startPos = startPos + 1
  222.  -- Infinite loop for array elements
  223.  repeat
  224.    startPos = decode_scanWhitespace(s,startPos)
  225.    base.assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
  226.    local curChar = string.sub(s,startPos,startPos)
  227.    if (curChar==']') then
  228.      return array, startPos+1
  229.    end
  230.    if (curChar==',') then
  231.      startPos = decode_scanWhitespace(s,startPos+1)
  232.    end
  233.    base.assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
  234.    object, startPos = decode(s,startPos)
  235.    table.insert(array,object)
  236.  until false
  237. end
  238.  
  239. function decode_scanComment(s, startPos)
  240.  base.assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
  241.  local endPos = string.find(s,'*/',startPos+2)
  242.  base.assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
  243.  return endPos+2  
  244. end
  245.  
  246. function decode_scanConstant(s, startPos)
  247.  local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
  248.  local constNames = {"true","false","null"}
  249.  
  250.  for i,k in base.pairs(constNames) do
  251.    --print ("[" .. string.sub(s,startPos, startPos + string.len(k) -1) .."]", k)
  252.    if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
  253.      return consts[k], startPos + string.len(k)
  254.    end
  255.  end
  256.  base.assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
  257. end
  258.  
  259. function decode_scanNumber(s,startPos)
  260.  local endPos = startPos+1
  261.  local stringLen = string.len(s)
  262.  local acceptableChars = "+-0123456789.e"
  263.  while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
  264.        and endPos<=stringLen
  265.        ) do
  266.    endPos = endPos + 1
  267.  end
  268.  local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)
  269.  local stringEval = base.loadstring(stringValue)
  270.  base.assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
  271.  return stringEval(), endPos
  272. end
  273.  
  274. function decode_scanObject(s,startPos)
  275.  local object = {}
  276.  local stringLen = string.len(s)
  277.  local key, value
  278.  base.assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
  279.  startPos = startPos + 1
  280.  repeat
  281.    startPos = decode_scanWhitespace(s,startPos)
  282.    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
  283.    local curChar = string.sub(s,startPos,startPos)
  284.    if (curChar=='}') then
  285.      return object,startPos+1
  286.    end
  287.    if (curChar==',') then
  288.      startPos = decode_scanWhitespace(s,startPos+1)
  289.    end
  290.    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
  291.    -- Scan the key
  292.    key, startPos = decode(s,startPos)
  293.    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
  294.    startPos = decode_scanWhitespace(s,startPos)
  295.    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
  296.    base.assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
  297.    startPos = decode_scanWhitespace(s,startPos+1)
  298.    base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
  299.    value, startPos = decode(s,startPos)
  300.    object[key]=value
  301.  until false   -- infinite loop while key-value pairs are found
  302. end
  303.  
  304. function decode_scanString(s,startPos)
  305.  base.assert(startPos, 'decode_scanString(..) called without start position')
  306.  local startChar = string.sub(s,startPos,startPos)
  307.  base.assert(startChar==[[']] or startChar==[["]],'decode_scanString called for a non-string')
  308.   local escaped = false
  309.   local endPos = startPos + 1
  310.   local bEnded = false
  311.   local stringLen = string.len(s)
  312.   repeat
  313.     local curChar = string.sub(s,endPos,endPos)
  314.     -- Character escaping is only used to escape the string delimiters
  315.     if not escaped then
  316.       if curChar==[[\]] then
  317.         escaped = true
  318.       else
  319.         bEnded = curChar==startChar
  320.       end
  321.     else
  322.       -- If we're escaped, we accept the current character come what may
  323.       escaped = false
  324.     end
  325.     endPos = endPos + 1
  326.     base.assert(endPos <= stringLen+1, "String decoding failed: unterminated string at position " .. endPos)
  327.   until bEnded
  328.   local stringValue = 'return ' .. string.sub(s, startPos, endPos-1)
  329.   local stringEval = base.loadstring(stringValue)
  330.   base.assert(stringEval, 'Failed to load string [ ' .. stringValue .. '] in JSON4Lua.decode_scanString at position ' .. startPos .. ' : ' .. endPos)
  331.   return stringEval(), endPos  
  332. end
  333.  
  334. function decode_scanWhitespace(s,startPos)
  335.   local whitespace=" \n\r\t"
  336.   local stringLen = string.len(s)
  337.   while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true)  and startPos <= stringLen) do
  338.     startPos = startPos + 1
  339.   end
  340.   return startPos
  341. end
  342.  
  343. function encodeString(s)
  344.   s = string.gsub(s,'\\','\\\\')
  345.   s = string.gsub(s,'"','\\"')
  346.   s = string.gsub(s,'\n','\\n')
  347.   s = string.gsub(s,'\t','\\t')
  348.   return s
  349. end
  350.  
  351. function isArray(t)
  352.   -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
  353.   -- (with the possible exception of 'n')
  354.   local maxIndex = 0
  355.   for k,v in base.pairs(t) do
  356.     if (base.type(k)=='number' and math.floor(k)==k and 1<=k) then      -- k,v is an indexed pair
  357.       if (not isEncodable(v)) then return false end     -- All array elements must be encodable
  358.       maxIndex = math.max(maxIndex,k)
  359.     else
  360.       if (k=='n') then
  361.         if v ~= table.getn(t) then return false end  -- False if n does not hold the number of elements
  362.       else -- Else of (k=='n')
  363.         if isEncodable(v) then return false end
  364.       end  -- End of (k~='n')
  365.     end -- End of k,v not an indexed pair
  366.   end  -- End of loop across all pairs
  367.   return true, maxIndex
  368. end
  369.  
  370. function isEncodable(o)
  371.   local t = base.type(o)
  372.   return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or (t=='function' and o==null)
  373. end
  374.  
  375. -- Convertit un table en chaîne de caractères paramètres POST
  376. function tableToURIString(t)
  377.   local ret = ""
  378.   local i = 1
  379.  
  380.   for key,value in pairs(t) do
  381.     ret = ret..textutils.urlEncode(key).."="..textutils.urlEncode(value)
  382.  
  383.     if table.getn(t) ~= i then
  384.       ret = ret.."&"
  385.     end
  386.  
  387.     i = i + 1
  388.   end
  389.  
  390.   return ret
  391. end
  392.  
  393. -- Explose une chaîne de caractères selon un séparateur
  394. function split(pString, pPattern)
  395.   local Table = {}
  396.   local fpat = "(.-)" .. pPattern
  397.   local last_end = 1
  398.   local s, e, cap = pString:find(fpat, 1)
  399.   while s do
  400.     if s ~= 1 or cap ~= "" then
  401.      table.insert(Table,cap)
  402.     end
  403.     last_end = e+1
  404.     s, e, cap = pString:find(fpat, last_end)
  405.   end
  406.   if last_end <= #pString then
  407.     cap = pString:sub(last_end)
  408.     table.insert(Table, cap)
  409.   end
  410.   return Table
  411. end
  412.  
  413. -- --------------------------------------------------------
  414. -- Démarrage du programme
  415.  
  416. rednet.open(MODEM_SIDE)
  417.  
  418. MONITOR.setTextScale(0.5);
  419.  
  420. -- Récupération de la carte
  421. raw = http.get(API_ENDPOINT.."/"..MAP_ID)
  422.  
  423. if raw == nil then
  424.   print("Unable to get the map data")
  425.   return
  426. end
  427.  
  428. map_data = decode(raw.readAll())
  429.  
  430. term.redirect(MONITOR)
  431. term.clear()
  432.  
  433. -- Tableau contenant la liste des positions des aiguillages en fonction de l'identifiant de l'ordi et de la couleur de l'aiguillage
  434. SWITCH_LIST = {}
  435.  
  436. -- Tableau contenant la liste des aiguillages en fonction de leur position
  437. SWITCH_LIST_POS = {}
  438.  
  439. -- Affichage de la carte du réseau ferroviaire
  440. for iy = 1, map_data["map_height"], 1 do
  441.   for ix = 1, map_data["map_width"], 1 do
  442.     local block = map_data["map_data"][iy..""][ix..""]
  443.    
  444.     if block["type"] == "switch" then
  445.       color = colors.red
  446.  
  447.       if SWITCH_LIST[block["computer-id"]] == nil then
  448.         SWITCH_LIST[block["computer-id"]] = {}
  449.       end
  450.  
  451.       if SWITCH_LIST[block["computer-id"]][block["switch-color"]] == nil then
  452.         SWITCH_LIST[block["computer-id"]][block["switch-color"]] = {}
  453.       end
  454.  
  455.       SWITCH_LIST[block["computer-id"]][block["switch-color"]]["x"] = ix;
  456.       SWITCH_LIST[block["computer-id"]][block["switch-color"]]["y"] = iy;
  457.  
  458.       if SWITCH_LIST_POS[iy..""] == nil then
  459.         SWITCH_LIST_POS[iy..""] = {}
  460.       end
  461.  
  462.       if SWITCH_LIST_POS[iy..""][ix..""] == nil then
  463.         SWITCH_LIST_POS[iy..""][ix..""] = {}
  464.       end
  465.  
  466.       SWITCH_LIST_POS[iy..""][ix..""]["computer-id"] = block["computer-id"];
  467.       SWITCH_LIST_POS[iy..""][ix..""]["switch-color"] = block["switch-color"];
  468.     elseif block["type"] == "rail" or block["type"] == "rail-bottom" or block["type"] == "rail-top" or block["type"] == "rail-left" or block["type"] == "rail-right" then
  469.       color = colors.brown
  470.     elseif block["type"] == "group" then
  471.       color = colors.white
  472.     else
  473.       color = colors.black
  474.     end
  475.  
  476.     paintutils.drawPixel(ix, iy, color)
  477.   end
  478. end
  479.  
  480. -- Mise à jour de la carte si aiguillage changé
  481. while true do
  482.   local event, p1, p2, p3 = os.pullEvent()
  483.  
  484.   if event == 'rednet_message' then
  485.     local senderId = p1
  486.     local message = p2
  487.     local distance = p3
  488.  
  489.     local message_splitted = split(message, "|")
  490.  
  491.     local computer_sender_id = message_splitted[1]..""
  492.     local bundled_cable = textutils.unserialize(message_splitted[2])
  493.     local real_computer_id = message_splitted[3]
  494.  
  495.     for key,value in pairs(bundled_cable) do
  496.       if SWITCH_LIST[computer_sender_id][key] ~= nil then
  497.         if value == 1 then
  498.           color = colors.lime
  499.         else
  500.           color = colors.red
  501.         end
  502.  
  503.         local x = SWITCH_LIST[computer_sender_id][key]["x"]..""
  504.         local y = SWITCH_LIST[computer_sender_id][key]["y"]..""
  505.  
  506.         SWITCH_LIST_POS[y][x]["real_computer_id"] = real_computer_id
  507.  
  508.         paintutils.drawPixel(SWITCH_LIST[computer_sender_id][key]["x"], SWITCH_LIST[computer_sender_id][key]["y"], color)
  509.       end
  510.     end
  511.  
  512.     http.request(API_ENDPOINT, "ci="..computer_sender_id.."&"..tableToURIString(bundled_cable)) -- Mise à jour de la carte web
  513.   elseif event == 'monitor_touch' then
  514.     local side = p1
  515.     local xPos = p2..""
  516.     local yPos = p3..""
  517.    
  518.     if SWITCH_LIST_POS[yPos] ~= nil and SWITCH_LIST_POS[yPos][xPos] ~= nil then
  519.       rednet.send(tonumber(SWITCH_LIST_POS[yPos][xPos]["real_computer_id"]), COLORS_ARRAY[SWITCH_LIST_POS[yPos][xPos]["switch-color"]], true)
  520.     end
  521.   end
  522. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement