Advertisement
kssr3951

atupd5

Jan 23rd, 2016
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 24.69 KB | None | 0 0
  1. -- ============================================
  2. -- == Utilities
  3. -- ============================================
  4. local function fileReadAll(filePath)
  5.   local hFile = fs.open(filePath, "r")
  6.   if nil == hFile then
  7.     return nill
  8.   end
  9.   local txt = hFile.readAll()
  10.   hFile.close()
  11.   return txt
  12. end
  13. local function fileOverwrite(filePath, text)
  14.   local hFile = fs.open(filePath, "w")
  15.   hFile.writeLine(text)
  16.   hFile.close()
  17. end
  18. local function saveFile(filePath, data)
  19.   fileOverwrite(filePath, textutils.serialize(data))
  20. end
  21. local function loadFile(filePath)
  22.   local dat = fileReadAll(filePath)
  23.   if nil == dat then
  24.     return nil
  25.   end
  26.   return textutils.unserialize(dat)
  27. end
  28. local function deleteWhenExists(filePath)
  29.   if fs.exists(filePath) then
  30.     fs.delete(filePath)
  31.   end
  32. end
  33. local function startsWith(subject, keyword)
  34.   if nil == subject then
  35.     return false
  36.   end
  37.   if nil == keyword then
  38.     return false
  39.   end
  40.   if string.len(subject) < string.len(keyword) then
  41.     return false
  42.   end
  43.   if string.sub(subject, 1, string.len(keyword)) == keyword then
  44.     return true
  45.   else
  46.     return false
  47.   end
  48. end
  49. local function split(sbj, splitter)
  50.   local rslt = { }
  51.   local i = 0
  52.   while true do
  53.     local idx = string.find(sbj, splitter, i, true)
  54.     if nil == idx then
  55.       table.insert(rslt, string.sub(sbj, i))
  56.       return rslt
  57.     else
  58.       table.insert(rslt, string.sub(sbj, i, idx - 1))
  59.       i = idx + 1
  60.     end
  61.   end
  62. end
  63. LOG_FILE_NAME = "debug.log"
  64. local function debug(txt)
  65.   print(txt)
  66.   local hFile
  67.   if fs.exists(LOG_FILE_NAME) then
  68.     hFile = fs.open(LOG_FILE_NAME, "a")
  69.   else
  70.     hFile = fs.open(LOG_FILE_NAME, "w")
  71.   end
  72.   hFile.writeLine(txt)
  73.   hFile.close()
  74. end
  75. local function splitCommand(line)
  76.   local tmp = string.gsub(line, "[ ]+", "\t")
  77.   return split(tmp, "\t")
  78. end
  79. -- ============================================
  80. -- == Configuration
  81. -- ============================================
  82. local APP_FILE_PATH  = "/atupd5"
  83. local THE_CHANNEL    = 3951
  84. local MSG_SIGNATURE  = "kssr3951's network system"
  85. local BASE_DIRECTORY = "/network/"
  86. local STATUS_DIRECTORY         = BASE_DIRECTORY .. "status"        .. "/"
  87. local PING_DIRECTORY           = BASE_DIRECTORY .. "ping"          .. "/"
  88. local ROUTE_DIRECTORY          = BASE_DIRECTORY .. "route"         .. "/"
  89. local REBOOT_DIRECTORY         = BASE_DIRECTORY .. "reboot"        .. "/"
  90. local REBOOT_HISTORY_DIRECTORY = BASE_DIRECTORY .. "rebootHistory" .. "/"
  91. local LOG_DIRECTORY            = BASE_DIRECTORY .. "logs"          .. "/"
  92. local TASK_DIRECTORY           = BASE_DIRECTORY .. "tasks"         .. "/"
  93. local PING_DIRECTORY           = BASE_DIRECTORY .. "ping"          .. "/"
  94. local ROUTE_FILENAME           = ROUTE_DIRECTORY .. "routeData"
  95. local PING_TIMEOUT = 1
  96. -- LOGGING
  97. LOG_FILE_NAME = LOG_DIRECTORY .. "debug.log"
  98. -- ============================================
  99. -- == Application Utilities
  100. -- ============================================
  101. local function serializeMessage(msg)
  102.   return MSG_SIGNATURE .. textutils.serialize(msg)
  103. end
  104. local function unserializeMessage(msg)
  105.   if false == startsWith(msg, MSG_SIGNATURE) then
  106.     return nil
  107.   else
  108.     return textutils.unserialize(string.sub(msg, string.len(MSG_SIGNATURE) + 1))
  109.   end
  110. end
  111. -- ============================================
  112. -- == Application Common
  113. -- ============================================
  114. local modems = { }
  115. local timers = { }
  116. local function setTimer(time, fileName)
  117.   local timerId = os.startTimer(time)
  118.   timers[timerId] = fileName
  119. end
  120. Timestamp = { }
  121. Timestamp.new = function()
  122.   return
  123.     {
  124.       day = os.day(),
  125.       time = os.time(),
  126.       clock = os.clock()
  127.     }
  128. end
  129. Timestamp.tostring = function(timestamp)
  130.   return tostring(timestamp.day)  .. "-"
  131.       .. tostring(timestamp.time) .. "-"
  132.       .. tostring(timestamp.clock)
  133. end
  134. Timestamp.doSort = function(directory, ascFlg)
  135.   local list = fs.list(directory)
  136.   local tmpList = { }
  137.   for i, v in ipairs(list) do
  138.     if not fs.isDir(v) then
  139.       sp = split(v, "-")
  140.       if 3 <= table.maxn(sp) then
  141.         local elm = { }
  142.         elm.day   = sp[1]
  143.         elm.time  = sp[2]
  144.         elm.clock = sp[3]
  145.         elm.fileName = v
  146.         table.insert(tmpList, elm)
  147.       end
  148.     end
  149.   end
  150.   if true == ascFlg then
  151.     table.sort(tmpList, Timestamp.compareAscFunc)
  152.   else
  153.     table.sort(tmpList, Timestamp.compareDescFunc)
  154.   end
  155.   local rslt = { }
  156.   for i, v in ipairs(tmpList) do
  157.     table.insert(rslt, v.fileName)
  158.   end
  159.   return rslt
  160. end
  161. Timestamp.sortAscByTimestamp = function(directory)
  162.   return Timestamp.doSort(directory, true)
  163. end
  164. Timestamp.sortDescByTimestamp = function(directory)
  165.   return Timestamp.doSort(directory, false)
  166. end
  167. Timestamp.getNewestFile = function(directory)
  168.   if not (fs.exists(directory) and fs.isDir(directory)) then
  169.     return nil
  170.   end
  171.   local list = Timestamp.sortDescByTimestamp(directory)
  172.   if 1 <= #list then
  173.     return list[1]
  174.   else
  175.     return nil
  176.   end
  177. end
  178. Timestamp.compareAscFunc = function(a, b)
  179.   if a.day ~= b.day then
  180.     return tonumber(a.day) < tonumber(b.day)
  181.   elseif a.time ~= b.time then
  182.     return tonumber(a.time) < tonumber(b.time)
  183.   elseif a.clock ~= b.clock then
  184.     return tonumber(a.clock) < tonumber(b.clock)
  185.   end
  186. end
  187. Timestamp.compareDescFunc = function(a, b)
  188.   if a.day ~= b.day then
  189.     return tonumber(a.day) > tonumber(b.day)
  190.   elseif a.time ~= b.time then
  191.     return tonumber(a.time) > tonumber(b.time)
  192.   elseif a.clock ~= b.clock then
  193.     return tonumber(a.clock) > tonumber(b.clock)
  194.   end
  195. end
  196. RouteInfo = { }
  197. RouteInfo.update = function(pingInfo)
  198.   -- 自PCのping結果をrouteDataに変換して保存する
  199.   -- 自PCに隣接しているPCのIDをappendListに追加する
  200.   local myPing = Ping.loadLatestPingData(os.getComputerID())
  201.   local routeData = { }
  202.   local appendList = { }
  203.   for key, val in pairs(myPing) do
  204.     table.insert(appendList, { nodeId = key, stepCount = 2 })
  205.     local tmpDat = { }
  206.     for i, val2 in ipairs(val) do
  207.       if nil == tmpDat[val2.side] then
  208.         tmpDat[val2.side] = { }
  209.         tmpDat[val2.side].multiplicity = 0
  210.         tmpDat[val2.side].maxDistance  = val2.distance
  211.         tmpDat[val2.side].minDistance  = val2.distance
  212.         tmpDat[val2.side].stepCount    = 1
  213.       end
  214.       tmpDat[val2.side].multiplicity = tmpDat[val2.side].multiplicity + 1
  215.       tmpDat[val2.side].maxDistance = math.max(tmpDat[val2.side].maxDistance, val2.distance)
  216.       tmpDat[val2.side].minDistance = math.min(tmpDat[val2.side].minDistance, val2.distance)
  217.     end
  218.     routeData[key] = tmpDat
  219.   end
  220.   -- appendListをループする
  221.   for _, appendData in ipairs(appendList) do
  222.     -- appendData.nodeIdに対応するping情報が有るか確認
  223.     local baseDir2 = ROUTE_DIRECTORY .. tostring(appendData.nodeId) .. "/"
  224.     local newest2 = Timestamp.getNewestFile(baseDir2)
  225.     if nil == newest2 then
  226.       -- 無い場合
  227.       debug(" no ping data for " .. tostring(appendData.nodeId))
  228.     else
  229.       -- 有る場合
  230.       -- appendData.nodeIdに対応するping情報をsbjPingにロード
  231.       local sbjPing = loadFile(baseDir2 .. newest2)
  232.       if nil ~= sbjPing then
  233.         -- appendData.nodeIdに対応するrouteDataをループする
  234.         for parentSide, parentData in pairs(routeData[appendData.nodeId]) do
  235.           local parentPing = Ping.loadLatestPingData(appendData.nodeId)
  236.           for sbjId, sbjDataList in pairs(sbjPing) do
  237.             if sbjId == os.getComputerID() then
  238.             else
  239.               for _, sbjData in ipairs(sbjDataList) do
  240.                 if nil == routeData[sbjId] then
  241.                   table.insert(appendList, { nodeId = sbjId, stepCount = appendData.stepCount + 1 })
  242.                   routeData[sbjId] = { }
  243.                 end
  244.                 if nil == routeData[sbjId][parentSide] then
  245.                   routeData[sbjId][parentSide] = { }
  246.                   routeData[sbjId][parentSide].multiplicity = 0
  247.                   routeData[sbjId][parentSide].maxDistance  = parentData.maxDistance + sbjData.distance
  248.                   routeData[sbjId][parentSide].minDistance  = parentData.minDistance + sbjData.distance
  249.                   routeData[sbjId][parentSide].stepCount    = appendData.stepCount
  250.                 end
  251.                 routeData[sbjId][parentSide].multiplicity = routeData[sbjId][parentSide].multiplicity + 1
  252.                 routeData[sbjId][parentSide].maxDistance  = math.max(routeData[sbjId][parentSide].maxDistance, parentData.maxDistance + sbjData.distance)
  253.                 routeData[sbjId][parentSide].minDistance  = math.min(routeData[sbjId][parentSide].minDistance, parentData.minDistance + sbjData.distance)
  254.               end
  255.             end
  256.           end
  257.         end
  258.       end
  259.     end
  260.   end
  261.   saveFile(ROUTE_FILENAME, routeData)
  262. end
  263. RouteInfo.findSide = function(targetId)
  264.   local routeData = loadFile(ROUTE_FILENAME)
  265.   if nil == routeData then
  266.     return nil
  267.   end
  268.   if nil == routeData[targetId] then
  269.     return nil
  270.   else
  271.     for key, val in pairs(routeData[targetId]) do
  272.       return key -- とりあえず1件目を返す
  273.     end
  274.   end
  275. end
  276. RouteInfo.new = function(data)
  277.   local this = {  }
  278.   return this
  279. end
  280. -- ==============================================
  281. -- CommonMessage
  282. -- ==============================================
  283. CommonMessage = {}
  284. CommonMessage.new = function(typeName)
  285.   local rslt =
  286.     {
  287.       messageId,
  288.       typeName = typeName,
  289.       timestamp = Timestamp.new(),
  290.       commanderId = "",
  291.       targetId = "",
  292.       reply = false,
  293.       fileName,
  294.       timeout = nil,
  295.       senderId
  296.     }
  297.   rslt.fileName = CommonMessage.getFileName(rslt)
  298.   return rslt
  299. end
  300. CommonMessage.getFileName = function(message)
  301.   return Timestamp.tostring(message.timestamp) .. "-" .. message.typeName
  302. end
  303. -- ==============================================
  304. -- Ping
  305. -- ==============================================
  306. Ping = { }
  307. Ping.TYPE_NAME = "PING"
  308. Ping.loadLatestPingData = function(nodeId)
  309.   local baseDir = ROUTE_DIRECTORY .. tostring(nodeId) .. "/"
  310.   local newest = Timestamp.getNewestFile(baseDir)
  311.   if nil == newest then
  312.     return nil
  313.   end
  314.   return loadFile(baseDir .. newest)
  315. end
  316. Ping.savePingInfo = function(action, modemSide, senderDistance)
  317.   local pingInfo = { }
  318.   local pingFolder = ROUTE_DIRECTORY .. action.message.targetId .. "/"
  319.   fs.makeDir(pingFolder)
  320.   if fs.exists(pingFolder .. action.message.fileName) then
  321.     pingInfo = loadFile(pingFolder .. action.message.fileName)
  322.   end
  323.   if nil == pingInfo[action.message.senderId] then
  324.     pingInfo[action.message.senderId] = { }
  325.   end
  326.   local found = false
  327.   for i, v in ipairs(pingInfo[action.message.senderId]) do
  328.     if v.side == modemSide and v.distance == senderDistance then
  329.       found = true
  330.       break
  331.     end
  332.   end
  333.   if not found then
  334.     table.insert(pingInfo[action.message.senderId],
  335.                  { side = modemSide, distance = senderDistance, label = action.message.resultPCsLabel })
  336.   end
  337.   saveFile(pingFolder .. action.message.fileName, pingInfo)
  338. end
  339. Ping.isPingResultExists = function(action)
  340.   local pingFolder = ROUTE_DIRECTORY .. action.message.targetId .. "/"
  341.   if fs.exists(pingFolder .. action.message.fileName) then
  342.     return true
  343.   else
  344.     return false
  345.   end
  346. end
  347. Ping.savePingResult = function(action)
  348.   local pingFolder = ROUTE_DIRECTORY .. action.message.targetId .. "/"
  349.   fs.makeDir(pingFolder)
  350.   fileOverwrite(pingFolder .. action.message.fileName, action.message.pingResult)
  351. end
  352. Ping.getPingResultSummary = function(pingResultData)
  353.   local rslt = { }
  354.   if nil == pingResultData then
  355.     return rslt
  356.   end
  357.   for computerId, dataList in pairs(pingResultData) do
  358.     for _, data in ipairs(dataList) do
  359.       if nil == rslt[computerId] then
  360.         rslt[computerId] = { }
  361.         rslt[computerId].minDistance = data.distance
  362.         rslt[computerId].maxDistance = data.distance
  363.         rslt[computerId].label = data.label
  364.       end
  365.       rslt[computerId].minDistance = math.min(rslt[computerId].minDistance, data.distance)
  366.       rslt[computerId].maxDistance = math.max(rslt[computerId].minDistance, data.distance)
  367.     end
  368.   end
  369.   return rslt
  370. end
  371. Ping.outputPingResultSummary = function(pingResultData, debugFlg)
  372.   local pingRslt = Ping.getPingResultSummary(pingResultData)
  373.   if true == debugFlg then
  374.     debug("ID  distance label")
  375.   else
  376.     print("ID  distance label")
  377.   end
  378.   for key, data in pairs(pingRslt) do
  379.     if true == debugFlg then
  380.       debug(key .. "  " .. tostring(data.minDistance) .. "  " .. tostring(data.label))
  381.     else
  382.       print(key .. "  " .. tostring(data.minDistance) .. "  " .. tostring(data.label))
  383.     end
  384.   end
  385. end
  386. Ping.debugPingResultSummary = function(pingResultData)
  387.   Ping.outputPingResultSummary(pingResultData, true)
  388. end
  389. Ping.printPingResultSummary = function(pingResultData)
  390.   Ping.outputPingResultSummary(pingResultData, false)
  391. end
  392. Ping.new = function(message)
  393.   local obj = { }
  394.   if nil ~= message then
  395.     obj.message = message
  396.   else
  397.     obj.message = CommonMessage.new(Ping.TYPE_NAME)
  398.     obj.message.mode = ""
  399.     obj.message.pingResult = { }
  400.     obj.message.senderDirection = ""
  401.     obj.message.resultPCsLabel = ""
  402.   end
  403.   obj.OnReceive = function(self, modemSide, senderChannel, replyChannel, senderDistance)
  404.     debug("[ping]OnReceive from " .. tostring(self.message.senderId))
  405.     if "REQUEST" == self.message.mode then
  406.       if self.message.senderId == self.message.targetId then
  407.         self.message.mode = "REPLY"
  408.         self.message.senderId = os.getComputerID()
  409.         self.message.resultPCsLabel = os.getComputerLabel()
  410.         --saveFile(TASK_DIRECTORY .. self.message.fileName, self.message)
  411.         modems[modemSide].transmit(THE_CHANNEL, THE_CHANNEL, serializeMessage(self.message))
  412.       end
  413.     elseif "REPLY" == self.message.mode then
  414.       if self.message.senderId ~= os.getComputerID() and self.message.targetId == os.getComputerID() then
  415.         Ping.savePingInfo(self, modemSide, senderDistance)
  416.       end
  417.     elseif "RESULT" == self.message.mode then
  418.       if not Ping.isPingResultExists(self) then
  419.         if self.message.commanderId == os.getComputerID() and self.message.targetId ~= os.getComputerID() then
  420.           -- ping結果がpingを発行したpcに帰ってきた場合
  421.           Ping.printPingResultSummary(textutils.unserialize(self.message.pingResult))
  422.           Ping.savePingResult(self)
  423.           -- ping対象が自分以外の場合、ping結果が到着したタイミングでルート情報を再構築する
  424.           RouteInfo.update()
  425.         else
  426.           local tmpMsg = loadFile(TASK_DIRECTORY .. self.message.fileName)
  427.           if nil ~= tmpMsg and nil ~= tmpMsg.senderDirection then
  428.             -- 行き(往路)でこのpcを通過していれば、保存されたメッセージのsenderDirectionを使ってcommanderのほうに返せるので送信する
  429.             modems[tmpMsg.senderDirection].transmit(THE_CHANNEL, THE_CHANNEL, serializeMessage(self.message))
  430.           end
  431.           -- ping結果を中継するpcもping結果を保存し、ルート情報を再構築する
  432.           Ping.savePingResult(self)
  433.           RouteInfo.update()
  434.         end
  435.       end
  436.     else
  437.       if not fs.exists(TASK_DIRECTORY .. self.message.fileName) then
  438.         self.message.senderDirection = modemSide
  439.         saveFile(TASK_DIRECTORY .. self.message.fileName, self.message)
  440.         if self.message.targetId == os.getComputerID() then
  441.           -- このPCがping対象である場合
  442.           setTimer(self.message.timeout, self.message.fileName)
  443.           self.message.mode     = "REQUEST"
  444.           self.message.senderId = os.getComputerID()
  445.           for _, mdm in pairs(modems) do
  446.             mdm.transmit(THE_CHANNEL, THE_CHANNEL, serializeMessage(self.message))
  447.           end
  448.         else
  449.           local side = RouteInfo.findSide(self.message.targetId)
  450.           if nil ~= side then
  451.             modems[side].transmit(THE_CHANNEL, THE_CHANNEL, serializeMessage(self.message))
  452.           end
  453.         end
  454.       end
  455.     end
  456.   end
  457.   obj.OnTimer = function(self)
  458.     if self.message.commanderId ~= os.getComputerID() then
  459.       self.message.mode = "RESULT"
  460.       local pingFilePath = ROUTE_DIRECTORY .. self.message.targetId .. "/" .. self.message.fileName
  461.       if fs.exists(pingFilePath) then
  462.         self.message.pingResult = fileReadAll(pingFilePath)
  463.       else
  464.         self.message.pingResult = { }
  465.       end
  466.       -- 別PCからpingを指定された場合もルート情報をアップデート
  467.       --RouteInfo.update()
  468.       modems[self.message.senderDirection].transmit(THE_CHANNEL, THE_CHANNEL, serializeMessage(self.message))
  469.       Ping.savePingResult(self)
  470.       RouteInfo.update()
  471.     else
  472.       -- ping対象が自分の場合、タイムアウトのタイミングでルート情報を再構築する
  473.       local tmpPingData = Ping.loadLatestPingData(os.getComputerID())
  474.       Ping.printPingResultSummary(tmpPingData)
  475.       RouteInfo.update()
  476.     end
  477.   end
  478.   obj.OnReboot = function(self)
  479.   end
  480.   return obj
  481. end
  482. -- ==============================================
  483. -- SysUpdate
  484. -- ==============================================
  485. SysUpdate = { }
  486. SysUpdate.TYPE_NAME = "SYS_UPDATE"
  487. SysUpdate.new = function(message)
  488.   local obj = { }
  489.   if nil ~= message then
  490.     obj.message = message
  491.   else
  492.     obj.message = CommonMessage.new(SysUpdate.TYPE_NAME)
  493.   end
  494.   obj.OnReceive = function(self, modemSide, senderChannel, replyChannel, senderDistance)
  495.     if (self.message.commanderId == os.getComputerID()) or
  496.        ("" == self.message.targetId or self.message.targetId == os.getComputerID()) then
  497.       if not fs.exists(REBOOT_HISTORY_DIRECTORY .. self.message.fileName) then
  498.         saveFile(STATUS_DIRECTORY .. "systemUpdateDate", tostring(self.message.timestamp.day) .. "-" .. tostring(self.message.timestamp.time))
  499.         saveFile(REBOOT_DIRECTORY .. self.message.fileName, self.message)
  500.         if self.message.commanderId ~= os.getComputerID() then
  501.           fileOverwrite(self.message.appFileName, self.message.source)
  502.           fileOverwrite("/startup", "shell.run(\"" .. self.message.appFileName .. "\")")
  503.         end
  504.         os.reboot()
  505.       end
  506.     end
  507.   end
  508.   obj.OnTimer = function(self)
  509.   end
  510.   obj.OnReboot = function(self)
  511.     for _, mdm in pairs(modems) do
  512.       mdm.transmit(THE_CHANNEL, THE_CHANNEL, serializeMessage(self.message))
  513.     end
  514.     fs.delete(REBOOT_HISTORY_DIRECTORY .. self.message.fileName)
  515.     saveFile(REBOOT_HISTORY_DIRECTORY .. self.message.fileName, self.message)
  516.     fs.delete(REBOOT_DIRECTORY .. self.message.fileName)
  517.   end
  518.   return obj
  519. end
  520. -- ==============================================
  521. -- loadAction
  522. -- ==============================================
  523. local function loadAction(msg)
  524.   if Ping.TYPE_NAME == msg.typeName then
  525.     return Ping.new(msg)
  526.   elseif SysUpdate.TYPE_NAME == msg.typeName then
  527.     return SysUpdate.new(msg)
  528.   end
  529. end
  530. -- ============================================
  531. -- == Application
  532. -- ============================================
  533. local SIDES = { "top", "bottom", "left", "right", "front", "back" }
  534. local periodicTimer
  535. local function refreshModemInfo()
  536.   local mdmCnt = 0
  537.   for _, side in ipairs(SIDES) do
  538.     if "modem" == peripheral.getType(side) then
  539.       modems[side] = peripheral.wrap(side)
  540.       modems[side].open(THE_CHANNEL)
  541.       mdmCnt = mdmCnt + 1
  542.     end
  543.   end
  544.   debug("modemCount = " .. tostring(mdmCnt))
  545. end
  546. local function printHeader()
  547.   local timestamp = loadFile(STATUS_DIRECTORY .. "systemUpdateDate")
  548.   debug("== =========================================")
  549.   debug("== kssr3951's network component.(atupd5)")
  550.   debug("== last update : " .. tostring(timestamp))
  551.   debug("== computer ID : " .. os.getComputerID())
  552.   debug("== =========================================")
  553.   debug("waiting.")
  554. end
  555. local function send(action)
  556.   if action.message.targetId == os.getComputerID() then
  557.     action:OnReceive()
  558.   end
  559.   if action.message.targetId ~= os.getComputerID() then
  560.     local side = RouteInfo.findSide(action.message.targetId)
  561.     if nil ~= side then
  562.       modems[side].transmit(THE_CHANNEL, THE_CHANNEL, serializeMessage(action.message))
  563.     else
  564.       debug("side for [" .. action.message.targetId .. "] is not found.")
  565.     end
  566.   end
  567. end
  568. -- ============================================
  569. -- == main
  570. -- ============================================
  571. local exitModemLoop
  572. local function timerAction(timerId)
  573.   if periodicTimer == timerId then
  574.     local cx, cy = term.getCursorPos()
  575.     term.setCursorPos(1, 1)
  576.     term.clearLine()
  577.     term.write("[" .. os.day() .. "-" .. os.time() .. "]")
  578.     term.setCursorPos(cx, cy)
  579.     periodicTimer = os.startTimer(3)
  580.     if true == exitModemLoop then
  581.       return false
  582.     end
  583.   else
  584.     local fileName = timers[timerId]
  585.     if nil ~= fileName then
  586.       local action = loadAction(loadFile(TASK_DIRECTORY .. fileName))
  587.       if nil ~= action then
  588.         action:OnTimer()
  589.       end
  590.     end
  591.   end
  592.   return true
  593. end
  594. local function modemAction(modemSide, senderChannel, replyChannel, msg, senderDistance)
  595.   local text = unserializeMessage(msg)
  596.   if nil == text then
  597.     return
  598.   else
  599.   end
  600.   local action = loadAction(text)
  601.   action:OnReceive(modemSide, senderChannel, replyChannel, senderDistance)
  602.   print("waiting.")
  603. end
  604. local function modemLoop()
  605.   exitModemLoop = false
  606.   periodicTimer = os.startTimer(3)
  607.   while true do
  608.     local event, r1, r2, r3, r4, r5 = os.pullEvent()
  609.     if "modem_message" == event then
  610.       modemAction(r1, r2, r3, r4, r5)
  611.     elseif "timer" == event then
  612.       local rslt = timerAction(r1, r2, r3, r4, r5)
  613.       if false == rslt then
  614.         break
  615.       end
  616.     end
  617.   end
  618. end
  619. local function consoleLoop()
  620.   print("*** admin mode ***")
  621.   print("type 'exit' to back to normal mode.")
  622.   print("type 'help' to know how to use.")
  623.   while true do
  624.     term.write("admin>")
  625.     local args = splitCommand(read())
  626.     local command
  627.     if 1 <= #args then
  628.       command = args[1]
  629.     end
  630.     if "exit" == command then
  631.       exitModemLoop = true
  632.       break
  633.     elseif "help" == command then
  634.       print("available commands are below.")
  635.       print("exit help id ping refresh requestRoute sysUpdate")
  636.       print("type 'help (command)' to know detail.")
  637.     elseif "id" == command then
  638.       print("this computer's id is " .. tostring(os.getComputerID()))
  639.     elseif "ping" == command then
  640.       -- non arguements -> ping(me)
  641.       local p = Ping.new()
  642.       p.message.commanderId = os.getComputerID()
  643.       if 2 <= #args and nil ~= tonumber(args[2]) then
  644.         p.message.targetId  = tonumber(args[2])
  645.       else
  646.         p.message.targetId  = os.getComputerID()
  647.       end
  648.       p.message.timeout       = 1.0
  649.       p.message.cacheDayCount = 0.5
  650.       send(p)
  651.     elseif "refresh" == command then
  652.       refreshModemInfo()
  653.     --elseif "requestRoute" == line then
  654.     --  requestRoute(os.day() .. "-" .. os.time(), PING_TIMEOUT, nil)
  655.     elseif "sysUpdate" == command then
  656.       for cnt = 3, 1, -1 do
  657.         term.write(tostring(cnt) .. " ")
  658.         os.sleep(1)
  659.       end
  660.       local s = SysUpdate.new()
  661.       s.message.commanderId = os.getComputerID()
  662.       s.message.appFileName = APP_FILE_PATH
  663.       s.message.source      = fileReadAll(APP_FILE_PATH)
  664.       s:OnReceive()
  665.     elseif "label" == command then
  666.       if 2 == #args and "get" == args[2] then
  667.         local tmp = os.getComputerLabel()
  668.         if nil ~= tmp then
  669.           print(tmp)
  670.         else
  671.           print("")
  672.         end
  673.       elseif 3 == #args and "set" == args[2] then
  674.         os.setComputerLabel(args[3])
  675.       else
  676.         print("Usages:")
  677.         print("label get")
  678.         print("label set <text>")
  679.       end
  680.     else
  681.       print("no such command [" .. command .. "]")
  682.     end
  683.   end
  684. end
  685. local function rebootAction()
  686.   local list = Timestamp.sortAscByTimestamp(REBOOT_DIRECTORY)
  687.   for i, v in ipairs(list) do
  688.     local action = loadAction(loadFile(REBOOT_DIRECTORY .. v))
  689.     action:OnReboot()
  690.   end
  691. end
  692. -- ============================================
  693. -- == main
  694. -- ============================================
  695. fileOverwrite("/startup", "shell.run(\"" .. APP_FILE_PATH .. "\")")
  696. fs.makeDir(STATUS_DIRECTORY)
  697. fs.makeDir(PING_DIRECTORY)
  698. fs.makeDir(ROUTE_DIRECTORY)
  699. fs.makeDir(REBOOT_DIRECTORY)
  700. fs.makeDir(TASK_DIRECTORY)
  701. fs.makeDir(PING_DIRECTORY)
  702. refreshModemInfo()
  703. rebootAction()
  704. printHeader()
  705. exitModemLoop = false
  706. periodicTimer = os.startTimer(3)
  707. while true do
  708.   local event, r1, r2, r3, r4, r5 = os.pullEvent()
  709.   if "modem_message" == event then
  710.     modemAction(r1, r2, r3, r4, r5)
  711.   elseif "timer" == event then
  712.     timerAction(r1, r2, r3, r4, r5)
  713.   elseif "key" == event then
  714.     parallel.waitForAll(consoleLoop, modemLoop)
  715.     print("=== normal mode ===")
  716.     printHeader()
  717.   end
  718. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement