Advertisement
Derek1017

CC Web Browser - Server

Jul 13th, 2015
311
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 30.34 KB | None | 0 0
  1. -- CC Web Browser - Server --
  2. -- Made By derekseitz --
  3.  
  4. --  To extract all the files, run: "<filename> --extract" in the Shell --
  5. local files = {["Views"]={["toolbar.view"]="{\
  6.  [\"Width\"]=\"100%\",\
  7.  [\"Height\"]=3,\
  8.  [\"Type\"]=\"View\",\
  9.  [\"BackgroundColour\"]=128,\
  10.  [\"Children\"]={\
  11.    [1]={\
  12.      [\"Y\"]=2,\
  13.      [\"X\"]=2,\
  14.      [\"Name\"]=\"GoStopButton\",\
  15.      [\"Type\"]=\"Button\",\
  16.      [\"Text\"]=\">\",\
  17.      [\"BackgroundColour\"]=1,\
  18.      [\"TextColour\"]=128\
  19.    },\
  20.    [2]={\
  21.      [\"Y\"]=2,\
  22.      [\"X\"]=\"100%,-23\",\
  23.      [\"Name\"]=\"LogButton\",\
  24.      [\"Type\"]=\"Button\",\
  25.      [\"Text\"]=\"Log\",\
  26.      [\"BackgroundColour\"]=1,\
  27.      [\"TextColour\"]=128,\
  28.      [\"Toggle\"]=false\
  29.    },\
  30.    [3]={\
  31.      [\"Y\"]=2,\
  32.      [\"X\"]=\"100%,-17\",\
  33.      [\"Name\"]=\"SettingsButton\",\
  34.      [\"Type\"]=\"Button\",\
  35.      [\"Text\"]=\"Settings\",\
  36.      [\"BackgroundColour\"]=1,\
  37.      [\"TextColour\"]=128,\
  38.      [\"Toggle\"]=false\
  39.    },\
  40.    [4]={\
  41.      [\"Y\"]=2,\
  42.      [\"X\"]=\"100%,-6\",\
  43.      [\"Name\"]=\"QuitButton\",\
  44.      [\"Type\"]=\"Button\",\
  45.      [\"Text\"]=\"Quit\",\
  46.      [\"BackgroundColour\"]=1,\
  47.      [\"TextColour\"]=128\
  48.    },\
  49.    [5]={\
  50.      [\"Y\"]=2,\
  51.      [\"X\"]=6,\
  52.      [\"Name\"]=\"StatusLabel\",\
  53.      [\"Type\"]=\"Label\",\
  54.      [\"Text\"]=\"Stopped\",\
  55.      [\"TextColour\"]=1\
  56.    },\
  57.  },\
  58. }",["main.view"]="{\
  59.  [\"Children\"]={\
  60.    [1]={\
  61.      [\"Y\"]=1,\
  62.      [\"X\"]=1,\
  63.      [\"Name\"]=\"Toolbar\",\
  64.      [\"Type\"]=\"View\",\
  65.      [\"InheritView\"]=\"toolbar\"\
  66.    },\
  67.    [2]={\
  68.      [\"X\"]=1,\
  69.      [\"Y\"]=4,\
  70.      [\"Name\"]=\"SettingsView\",\
  71.      [\"Type\"]=\"SettingsView\",\
  72.      [\"Width\"]=\"100%\",\
  73.      [\"Height\"]=\"100%,-3\",\
  74.      [\"Visible\"]=false,\
  75.      [\"InheritView\"]=\"settings\"\
  76.    },\
  77.    [3]={\
  78.      [\"X\"]=1,\
  79.      [\"Y\"]=4,\
  80.      [\"Name\"]=\"LogView\",\
  81.      [\"Type\"]=\"LogView\",\
  82.      [\"Width\"]=\"100%\",\
  83.      [\"Height\"]=\"100%,-3\",\
  84.      [\"Visible\"]=false\
  85.    },\
  86.  },\
  87.  [\"BackgroundColour\"]=1,\
  88.  [\"ToolBarColour\"]=128,\
  89.  [\"ToolBarTextColour\"]=1\
  90. }",["nomodem.view"]="{\
  91.  [\"Children\"]={\
  92.    [1]={\
  93.      [\"Y\"]=\"50%,-2\",\
  94.      [\"X\"]=1,\
  95.      [\"Width\"]=\"100%\",\
  96.      [\"Type\"]=\"Label\",\
  97.      [\"Text\"]=\"No Modem Attached!\",\
  98.      [\"TextColour\"]=16384,\
  99.      [\"Align\"]=\"Center\"\
  100.    },\
  101.    [2]={\
  102.      [\"Y\"]=\"50%\",\
  103.      [\"X\"]=\"10%\",\
  104.      [\"Width\"]=\"80%\",\
  105.      [\"Type\"]=\"Label\",\
  106.      [\"Text\"]=\"Please attach a wireless modem to use CC Web Browser Server.\",\
  107.      [\"Align\"]=\"Center\"\
  108.    },\
  109.    [3]={\
  110.      [\"Y\"]=\"100%,-1\",\
  111.      [\"X\"]=\"100%,-6\",\
  112.      [\"Name\"]=\"QuitButton\",\
  113.      [\"Type\"]=\"Button\",\
  114.      [\"Text\"]=\"Quit\",\
  115.    },\
  116.  },\
  117.  [\"BackgroundColour\"]=1,\
  118.  [\"ToolBarColour\"]=128,\
  119.  [\"ToolBarTextColour\"]=1\
  120. }",["settings.view"]="{\
  121.  [\"Children\"]={\
  122.    [1]={\
  123.      [\"Y\"]=2,\
  124.      [\"X\"]=3,\
  125.      [\"Type\"]=\"Label\",\
  126.      [\"Text\"]=\"Server Address\",\
  127.      [\"TextColour\"]=128\
  128.    },\
  129.    [2]={\
  130.      [\"Y\"]=2,\
  131.      [\"X\"]=19,\
  132.      [\"Type\"]=\"Label\",\
  133.      [\"Text\"]=\"wifi://\",\
  134.      [\"TextColour\"]=256\
  135.    },\
  136.    [3]={\
  137.      [\"Y\"]=2,\
  138.      [\"X\"]=26,\
  139.      [\"Width\"]=20,\
  140.      [\"Name\"]=\"AddressTextBox\",\
  141.      [\"Type\"]=\"TextBox\",\
  142.      [\"Placeholder\"]=\"e.g. basesite\",\
  143.    },\
  144.    [4]={\
  145.      [\"Y\"]=5,\
  146.      [\"X\"]=3,\
  147.      [\"Width\"]=\"100%,-4\",\
  148.      [\"Type\"]=\"Label\",\
  149.      [\"Text\"]=\"Ok... so maybe there aren't that many settings. But hey, at least it's easy to use.\",\
  150.      [\"TextColour\"]=256\
  151.    },\
  152.    [5]={\
  153.      [\"Y\"]=9,\
  154.      [\"X\"]=3,\
  155.      [\"Type\"]=\"Label\",\
  156.      [\"Text\"]=\"CC Web Browser Server v1.0.0\",\
  157.    },\
  158.    [6]={\
  159.      [\"Y\"]=11,\
  160.      [\"X\"]=3,\
  161.      [\"Width\"]=\"100%,-4\",\
  162.      [\"Type\"]=\"Label\",\
  163.      [\"Text\"]=\"CC Web Browser and CC Web Browser Server were made by derekseitz\",\
  164.      [\"TextColour\"]=128\
  165.    },\
  166.  },\
  167. }",},["README.md"]="CC-Web-Browser-Server\
  168. ============\
  169. \
  170. A wireless modem based CCML server for CC Web Browser",["startup"]="local bedrockPath='' if OneOS then OneOS.LoadAPI('/System/API/Bedrock.lua', false)elseif fs.exists(bedrockPath..'/Bedrock')then os.loadAPI(bedrockPath..'/Bedrock')else if http then print('Downloading CC Web Browser...')local h=http.get('http://pastebin.com/raw.php?i=0MgKNqpN')if h then local f=fs.open(bedrockPath..'/Bedrock','w')f.write(h.readAll())f.close()h.close()os.loadAPI(bedrockPath..'/Bedrock')else error('Failed to download Bedrock. Is your internet working?') end else error('This program needs to download Bedrock to work. Please enable HTTP.') end end if Bedrock then Bedrock.BasePath = bedrockPath Bedrock.ProgramPath = shell.getRunningProgram() end\
  171. \
  172. local program = Bedrock:Initialise()\
  173. \
  174. os.loadAPI(program.ProgramPath .. '/APIs/Peripheral')\
  175. os.loadAPI(program.ProgramPath .. '/APIs/Wireless')\
  176. \
  177. local serverRunning = false\
  178. \
  179. local messageLevel = {\
  180.     Info    = 'Info',\
  181.     Success = 'Success',\
  182.     Warning = 'Warning',\
  183.     Error   = 'Error',\
  184. }\
  185. \
  186. local function logMsg(msg, level)\
  187.     level = level or messageLevel.Info\
  188.     program:GetObject('LogView'):AddItem('[' .. level .. '] '..msg, level)\
  189. end\
  190. \
  191. local defaultSettings = {\
  192.     address = nil\
  193. }\
  194. \
  195. local settings = {}\
  196. \
  197. local function saveSettings()\
  198.     logMsg('Saving settings.')\
  199.     local f = fs.open('.QuestServer.settings', 'w')\
  200.     settings.address = program:GetObject('AddressTextBox').Text\
  201.     if f then\
  202.         f.write(textutils.serialize(settings))\
  203.         f.close()\
  204.     end\
  205. end\
  206. \
  207. local function loadSettings()\
  208.     logMsg('Loading settings.')\
  209.     local f = fs.open('.QuestServer.settings', 'r')\
  210.     if f then\
  211.         settings = textutils.unserialize(f.readAll())\
  212.         f.close()\
  213.     else\
  214.         logMsg('No settings file, using default.', messageLevel.Warning)\
  215.         settings = defaultSettings\
  216.         saveSettings()\
  217.     end\
  218. \
  219.     program:GetObject('AddressTextBox').Text = settings.address or ''\
  220. end\
  221. \
  222. local function switchView(name)\
  223.     local viewNames = {\
  224.         'Settings',\
  225.         'Log',\
  226.     }\
  227. \
  228.     for i, v in ipairs(viewNames) do\
  229.         if name == v then\
  230.             program:GetObject(v .. 'View').Visible = true\
  231.             program:GetObject(v .. 'Button').Toggle = true\
  232.         else\
  233.             program:GetObject(v .. 'View').Visible = false\
  234.             program:GetObject(v .. 'Button').Toggle = false\
  235.         end\
  236.     end\
  237. \
  238.     program:SetActiveObject()\
  239. end\
  240. \
  241. local availableTimer = nil\
  242. \
  243. local startServer = nil\
  244. local stopServer = nil\
  245. \
  246. local function checkNameAvailable(name)\
  247.     logMsg('Checking address clashes: '..name)\
  248.     if name:match(\"%W\") then\
  249.         logMsg('Invalid address!', messageLevel.Error)\
  250.         stopServer('Invalid Address')\
  251.         switchView('Settings')\
  252.     else\
  253.         Wireless.SendMessage(Wireless.Channels.QuestServerNameAvailable, name)\
  254.         availableTimer = program:StartTimer(function()\
  255.             if availableTimer and name == settings.address then\
  256.                 logMsg('No address clashes found!', messageLevel.Success)\
  257.                 availableTimer = nil\
  258.                 startServer(true)\
  259.             end\
  260.         end, 1)\
  261.     end\
  262. end\
  263. \
  264. function stopServer(reason)\
  265.     logMsg('Stopping server: ' .. reason or 'Stopped', messageLevel.Warning)\
  266.     serverRunning = false\
  267.     program:GetObject('GoStopButton').Text = '>'\
  268.     program:GetObject('StatusLabel').Text = reason or 'Stopped'\
  269. end\
  270. \
  271. function startServer(available)\
  272.     logMsg('Starting server...')\
  273.     if settings.address and #settings.address > 0 then\
  274.         if available then\
  275.             logMsg('Server started!', messageLevel.Success)\
  276.             serverRunning = true\
  277.             program:GetObject('GoStopButton').Text = 'x'\
  278.             program:GetObject('StatusLabel').Text = 'Running'\
  279.         else\
  280.             program:GetObject('StatusLabel').Text = 'Checking Name'\
  281.             checkNameAvailable(settings.address)\
  282.         end\
  283.     else\
  284.         logMsg('Server could not start, address not set!', messageLevel.Error)\
  285.         stopServer('Address Not Set')\
  286.         switchView('Settings')\
  287.     end\
  288. end\
  289. \
  290. program.OnKeyChar = function(self, event, keychar)\
  291.     if keychar == '\\\\' then\
  292.         os.reboot()\
  293.     end\
  294. end\
  295. \
  296. program:RegisterEvent('modem_message', function(self, event, side, channel, replyChannel, message, distance)\
  297.     Wireless.HandleMessage(event, side, channel, replyChannel, message, distance)\
  298. end)\
  299. \
  300. local function split(str, pat)\
  301.   local t = {}\
  302.   local fpat = \"(.-)\" .. pat\
  303.   local last_end = 1\
  304.   local s, e, cap = str:find(fpat, 1)\
  305.   while s do\
  306.      if s ~= 1 or cap ~= \"\" then\
  307.      table.insert(t,cap)\
  308.      end\
  309.      last_end = e+1\
  310.      s, e, cap = str:find(fpat, last_end)\
  311.   end\
  312.   if last_end <= #str then\
  313.      cap = str:sub(last_end)\
  314.      table.insert(t, cap)\
  315.   end\
  316.   return t\
  317. end\
  318. \
  319. local function findLast(haystack, needle)\
  320.    local i=haystack:match(\".*\"..needle..\"()\")\
  321.    if i==nil then return nil else return i-1 end\
  322. end\
  323. \
  324. local hex_to_char = function(x)\
  325.  return string.char(tonumber(x, 16))\
  326. end\
  327. \
  328. local function urlUnencode( str )\
  329.     -- essentially reverses textutils.urlDecode\
  330.    if str then\
  331.        str = string.gsub(str, \"+\", \" \")\
  332.        str = string.gsub(str, \"\\r\\n\", \"\\n\")\
  333.        term.setTextColor(colors.black)\
  334.        str = str:gsub(\"%%(%x%x)\", hex_to_char)\
  335.    end\
  336.    return str    \
  337. end\
  338. \
  339. local function urlComponents(url)\
  340.     if url then\
  341.         urlUnencode(textutils.urlEncode(url))\
  342.         local components = {}\
  343.         local parts = split(url, '[\\\\/]+')\
  344.         if url:find('://') and parts[1]:sub(#parts[1]) == ':' then\
  345.             components.protocol = parts[1]:sub(1, #parts[1]-1)\
  346.             components.sansprotocol = url:sub(#components.protocol + 4)\
  347.             components.host = parts[2]\
  348.             components.fullhost = components.protocol .. '://' .. parts[2] .. '/'\
  349.             components.filename = fs.getName(url)\
  350.             components.filepath = url:sub(#components.fullhost)\
  351.             if components.filename == components.host then\
  352.                 components.filename = ''\
  353.             end\
  354.             components.base = url:sub(1, findLast(url, '/'))\
  355.             components.get = {}\
  356.             components.filepathsansget = components.sansprotocol\
  357.             if url:find('?') then\
  358.                 local start = url:find('?')\
  359.                 components.filepathsansget = url:sub(#components.protocol + 4, start - 1)\
  360.                 local getString = url:sub(start + 1)\
  361.                 local values = split(getString, '&')\
  362.                 for i, v in ipairs(values) do\
  363.                     local keyvalue = split(v, '=')\
  364.                     components.get[keyvalue[1]] =  urlUnencode(keyvalue[2])\
  365.                 end\
  366.             end\
  367.             return components\
  368.         end\
  369.     end\
  370. end\
  371. \
  372. local function resolveFile(path)\
  373.     local parts = split(path, '[\\\\/]+')\
  374.     local realPath = '/Server Files'\
  375.     if #parts == 0 then\
  376.         parts = {''}\
  377.     end\
  378.     for i, v in ipairs(parts) do\
  379.         local tmpPath\
  380.         if #v == 0 then\
  381.             tmpPath = realPath\
  382.         else\
  383.             tmpPath = realPath .. '/' ..v\
  384.         end\
  385.         if fs.exists(tmpPath) then\
  386.             if fs.isDir(tmpPath) and i == #parts then\
  387.                 local attempts = {\
  388.                     tmpPath .. '/index.ccml',\
  389.                     tmpPath .. '/index.html',\
  390.                 }\
  391. \
  392.                 for i2, v2 in ipairs(attempts) do\
  393.                     if fs.exists(v2) then\
  394.                         return v2\
  395.                     end\
  396.                 end\
  397.                 return nil\
  398.             end\
  399.             realPath = tmpPath\
  400.         else\
  401.             return nil\
  402.         end\
  403.     end\
  404.     return realPath\
  405. end\
  406. \
  407. Wireless.Responder = function(event, side, channel, replyChannel, message, distance)\
  408.     if channel == Wireless.Channels.QuestServerRequest and serverRunning then\
  409.         if message.content:find('wifi://') == 1 then\
  410.             local parts = urlComponents(message.content)\
  411.             if parts.host and parts.host == settings.address then\
  412.                 local path = resolveFile(parts.filepath)\
  413.                 local content\
  414.                 if path then\
  415.                     local f = fs.open(path, 'r')\
  416.                     if f then\
  417.                         content = f.readAll()\
  418.                         logMsg('File request successful: '..message.content, messageLevel.Success)\
  419.                     end\
  420.                 end\
  421.                 if not content then\
  422.                     logMsg('File request failed: '..message.content, messageLevel.Warning)\
  423.                 end\
  424.                 Wireless.SendMessage(replyChannel, {url = message.content, content = content}, nil, message.messageID)\
  425.             end\
  426.         end\
  427.     elseif channel == Wireless.Channels.QuestServerNameAvailable then\
  428.         if message.content == settings.address then\
  429.             logMsg('External address clash request clashed with this server: '..message.content, messageLevel.Warning)\
  430.             Wireless.SendMessage(replyChannel, 'IN_USE', nil, message.messageID)\
  431.         end\
  432.     elseif channel == Wireless.Channels.QuestServerNameAvailableReply and running then\
  433.         availableTimer = nil\
  434.         logMsg('Address clash request failed, address in use: '..message.content, messageLevel.Error)\
  435.         stopServer('Address In Use')\
  436.         switchView('Settings')\
  437.     end\
  438. end\
  439. \
  440. local debounce = nil\
  441. \
  442. program.OnTimer = function(self, event, timer)\
  443.     if timer == debounce then\
  444.         saveSettings()\
  445.     end\
  446. end\
  447. \
  448. program:Run(function()\
  449.     if Wireless.Present() then\
  450.         program:LoadView('main')\
  451. \
  452.         if not fs.exists('/Server Files/') then\
  453.             fs.makeDir('/Server Files/')\
  454.             local f = fs.open('/Server Files/index.ccml', 'w')\
  455.             if f then\
  456.                 f.write([[<!DOCTYPE ccml>\
  457. <html>\
  458.    <head>\
  459.        <title>Welcome to your CC Web Browser Server Website!</title>\
  460.    </head>\
  461. \
  462.    <body>\
  463.        <br>\
  464.        <h colour=\"green\">Welcome to your CC Web Browser Server Website!</h>\
  465.        <br>\
  466.        <center>\
  467.             <p width=\"46\" align=\"center\">\
  468.                 The files for this website are stored in the /Server Files/ folder on the server.\
  469.             </p>\
  470.             <br>\
  471.             <p width=\"46\" align=\"center\">\
  472.                 If you haven't made a CC Web Browser web page before you should look for the CCML tutorial on the ComputerCraft forums.\
  473.             </p>\
  474.        </center>\
  475.    </body>\
  476. </html>]])\
  477.                 f.close()\
  478.             end\
  479.         end\
  480. \
  481.         loadSettings()\
  482.         Wireless.Initialise()\
  483. \
  484.         switchView('Log')\
  485.         startServer()\
  486. \
  487.         program:GetObject('SettingsButton').OnClick = function(self, event, side, x, y)\
  488.             switchView('Settings')\
  489.         end\
  490. \
  491.         program:GetObject('LogButton').OnClick = function(self, event, side, x, y)\
  492.             switchView('Log')\
  493.         end\
  494. \
  495.         program:GetObject('GoStopButton').OnClick = function(self, event, side, x, y)\
  496.             if serverRunning then\
  497.                 stopServer()\
  498.             else\
  499.                 startServer()\
  500.             end\
  501.         end\
  502. \
  503.         program:GetObject('AddressTextBox').OnChange = function(self, event, keychar)\
  504.             if settings.address ~= program:GetObject('AddressTextBox').Text then\
  505.                 stopServer('Address Changed')\
  506.                 debounce = os.startTimer(1)\
  507.             end\
  508.         end\
  509. \
  510.     else\
  511.         program:LoadView('nomodem')\
  512.     end\
  513. \
  514.     program:GetObject('QuitButton').OnClick = function(self, event, side, x, y)\
  515.         term.setBackgroundColour(colours.black)\
  516.         term.setTextColor(colours.white)\
  517.         term.clear()\
  518.         term.setCursorPos(1, 1)\
  519.         print('Thanks for using CC Web Browser Server by derekseitz')\
  520.         program:Quit()\
  521.     end\
  522. end)",["Objects"]={["SettingsView.lua"]="Inherit = 'View'",["LogView.lua"]="Inherit = 'View'\
  523. Log = nil\
  524. \
  525. SaveLog = function(self)\
  526.     local str = table.concat(self.Log, '\\n')\
  527.     local f = fs.open('QuestServer.log', 'w')\
  528.     if f then\
  529.         f.write(str)\
  530.         f.close()\
  531.     end\
  532. end\
  533. \
  534. AddItem = function(self, str, level)\
  535.     local messageColours = {\
  536.         Info    = colours.blue,\
  537.         Success = colours.green,\
  538.         Warning = colours.orange,\
  539.         Error   = colours.red,\
  540.     }\
  541.     table.insert(self.Log, str)\
  542. \
  543.     local y = 1\
  544. \
  545.     for i, v in ipairs(self.Children) do\
  546.         y = y + v.Height\
  547.     end\
  548. \
  549.     self:AddObject({\
  550.         X = 1,\
  551.         Y = y,\
  552.         Width = \"100%\",\
  553.         Type = 'Label',\
  554.         Text = str,\
  555.         TextColour = messageColours[level]\
  556.     })\
  557.     \
  558.     self:SaveLog()\
  559. end\
  560. \
  561. OnLoad = function(self)\
  562.     self.Log = {}\
  563. end",},["APIs"]={["Peripheral"]="GetPeripheral = function(_type)\
  564.     for i, p in ipairs(GetPeripherals()) do\
  565.         if p.Type == _type then\
  566.             return p\
  567.         end\
  568.     end\
  569. end\
  570. \
  571. Call = function(type, ...)\
  572.     local tArgs = {...}\
  573.     local p = GetPeripheral(type)\
  574.     peripheral.call(p.Side, unpack(tArgs))\
  575. end\
  576. \
  577. local getNames = peripheral.getNames or function()\
  578.     local tResults = {}\
  579.     for n,sSide in ipairs( rs.getSides() ) do\
  580.         if peripheral.isPresent( sSide ) then\
  581.             table.insert( tResults, sSide )\
  582.             local isWireless = false\
  583.             if pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then\
  584.                 isWireless = true\
  585.             end     \
  586.             if peripheral.getType( sSide ) == \"modem\" and not isWireless then\
  587.                 local tRemote = peripheral.call( sSide, \"getNamesRemote\" )\
  588.                 for n,sName in ipairs( tRemote ) do\
  589.                     table.insert( tResults, sName )\
  590.                 end\
  591.             end\
  592.         end\
  593.     end\
  594.     return tResults\
  595. end\
  596. \
  597. GetPeripherals = function(filterType)\
  598.     local peripherals = {}\
  599.     for i, side in ipairs(getNames()) do\
  600.         local name = peripheral.getType(side):gsub(\"^%l\", string.upper)\
  601.         local code = string.upper(side:sub(1,1))\
  602.         if side:find('_') then\
  603.             code = side:sub(side:find('_')+1)\
  604.         end\
  605. \
  606.         local dupe = false\
  607.         for i, v in ipairs(peripherals) do\
  608.             if v[1] == name .. ' ' .. code then\
  609.                 dupe = true\
  610.             end\
  611.         end\
  612. \
  613.         if not dupe then\
  614.             local _type = peripheral.getType(side)\
  615.             local formattedType = _type:sub(1, 1):upper() .. _type:sub(2, -1)\
  616.             local isWireless = false\
  617.             if _type == 'modem' then\
  618.                 if not pcall(function()isWireless = peripheral.call(side, 'isWireless') end) then\
  619.                     isWireless = true\
  620.                 end     \
  621.                 if isWireless then\
  622.                     _type = 'wireless_modem'\
  623.                     formattedType = 'Wireless Modem'\
  624.                     name = 'W '..name\
  625.                 end\
  626.             end\
  627.             if not filterType or _type == filterType then\
  628.                 table.insert(peripherals, {Name = name:sub(1,8) .. ' '..code, Fullname = name .. ' ('..side:sub(1, 1):upper() .. side:sub(2, -1)..')', Side = side, Type = _type, Wireless = isWireless, FormattedType = formattedType})\
  629.             end\
  630.         end\
  631.     end\
  632.     return peripherals\
  633. end\
  634. \
  635. GetSide = function(side)\
  636.     for i, p in ipairs(GetPeripherals()) do\
  637.         if p.Side == side then\
  638.             return p\
  639.         end\
  640.     end\
  641. end\
  642. \
  643. PresentNamed = function(name)\
  644.     return peripheral.isPresent(name)\
  645. end\
  646. \
  647. CallType = function(type, ...)\
  648.     local tArgs = {...}\
  649.     local p = GetPeripheral(type)\
  650.     return peripheral.call(p.Side, unpack(tArgs))\
  651. end\
  652. \
  653. CallNamed = function(name, ...)\
  654.     local tArgs = {...}\
  655.     return peripheral.call(name, unpack(tArgs))\
  656. end\
  657. \
  658. GetInfo = function(p)\
  659.     local info = {}\
  660.     local buttons = {}\
  661.     if p.Type == 'computer' then\
  662.         local id = peripheral.call(p.Side:lower(),'getID')\
  663.         if id then\
  664.             info = {\
  665.                 ID = tostring(id)\
  666.             }\
  667.         else\
  668.             info = {}\
  669.         end\
  670.     elseif p.Type == 'drive' then\
  671.         local discType = 'No Disc'\
  672.         local discID = nil\
  673.         local mountPath = nil\
  674.         local discLabel = nil\
  675.         local songName = nil\
  676.         if peripheral.call(p.Side:lower(), 'isDiskPresent') then\
  677.             if peripheral.call(p.Side:lower(), 'hasData') then\
  678.                 discType = 'Data'\
  679.                 discID = peripheral.call(p.Side:lower(), 'getDiskID')\
  680.                 if discID then\
  681.                     discID = tostring(discID)\
  682.                 else\
  683.                     discID = 'None'\
  684.                 end\
  685.                 mountPath = '/'..peripheral.call(p.Side:lower(), 'getMountPath')..'/'\
  686.                 discLabel = peripheral.call(p.Side:lower(), 'getDiskLabel')\
  687.             else\
  688.                 discType = 'Audio'\
  689.                 songName = peripheral.call(p.Side:lower(), 'getAudioTitle')\
  690.             end\
  691.         end\
  692.         if mountPath then\
  693.             table.insert(buttons, {Text = 'View Files', OnClick = function(self, event, side, x, y)GoToPath(mountPath)end})\
  694.         elseif discType == 'Audio' then\
  695.             table.insert(buttons, {Text = 'Play', OnClick = function(self, event, side, x, y)\
  696.                 if self.Text == 'Play' then\
  697.                     disk.playAudio(p.Side:lower())\
  698.                     self.Text = 'Stop'\
  699.                 else\
  700.                     disk.stopAudio(p.Side:lower())\
  701.                     self.Text = 'Play'\
  702.                 end\
  703.             end})\
  704.         else\
  705.             diskOpenButton = nil\
  706.         end\
  707.         if discType ~= 'No Disc' then\
  708.             table.insert(buttons, {Text = 'Eject', OnClick = function(self, event, side, x, y)disk.eject(p.Side:lower()) sleep(0) RefreshFiles() end})\
  709.         end\
  710. \
  711.         info = {\
  712.             ['Disc Type'] = discType,\
  713.             ['Disc Label'] = discLabel,\
  714.             ['Song Title'] = songName,\
  715.             ['Disc ID'] = discID,\
  716.             ['Mount Path'] = mountPath\
  717.         }\
  718.     elseif p.Type == 'printer' then\
  719.         local pageSize = 'No Loaded Page'\
  720.         local _, err = pcall(function() return tostring(peripheral.call(p.Side:lower(), 'getPgaeSize')) end)\
  721.         if not err then\
  722.             pageSize = tostring(peripheral.call(p.Side:lower(), 'getPageSize'))\
  723.         end\
  724.         info = {\
  725.             ['Paper Level'] = tostring(peripheral.call(p.Side:lower(), 'getPaperLevel')),\
  726.             ['Paper Size'] = pageSize,\
  727.             ['Ink Level'] = tostring(peripheral.call(p.Side:lower(), 'getInkLevel'))\
  728.         }\
  729.     elseif p.Type == 'modem' then\
  730.         info = {\
  731.             ['Connected Peripherals'] = tostring(#peripheral.call(p.Side:lower(), 'getNamesRemote'))\
  732.         }\
  733.     elseif p.Type == 'monitor' then\
  734.         local w, h = peripheral.call(p.Side:lower(), 'getSize')\
  735.         local screenType = 'Black and White'\
  736.         if peripheral.call(p.Side:lower(), 'isColour') then\
  737.             screenType = 'Colour'\
  738.         end\
  739.         local buttonTitle = 'Use as Screen'\
  740.         if OneOS.Settings:GetValues()['Monitor'] == p.Side:lower() then\
  741.             buttonTitle = 'Use Computer Screen'\
  742.         end\
  743.         table.insert(buttons, {Text = buttonTitle, OnClick = function(self, event, side, x, y)\
  744.                 self.Bedrock:DisplayAlertWindow('Reboot Required', \"To change screen you'll need to reboot your computer.\", {'Reboot', 'Cancel'}, function(value)\
  745.                     if value == 'Reboot' then\
  746.                         if buttonTitle == 'Use Computer Screen' then\
  747.                             OneOS.Settings:SetValue('Monitor', nil)\
  748.                         else\
  749.                             OneOS.Settings:SetValue('Monitor', p.Side:lower())\
  750.                         end\
  751.                         OneOS.Reboot()\
  752.                     end\
  753.                 end)\
  754.             end\
  755.         })\
  756.         info = {\
  757.             ['Type'] = screenType,\
  758.             ['Width'] = tostring(w),\
  759.             ['Height'] = tostring(h),\
  760.         }\
  761.     end\
  762.     info.Buttons = buttons\
  763.     return info\
  764. end",["Wireless"]="--This is just the OneOS Wireless API\
  765. \
  766. --OneOS uses channels between 4200 and 4300, avoid use where possible\
  767. \
  768. Channels = {\
  769.     Ignored = 4299,\
  770.     Ping = 4200,\
  771.     PingReply = 4201,\
  772.     QuestServerRequest = 4250,\
  773.     QuestServerRequestReply = 4251,\
  774.     QuestServerNameAvailable = 4252,\
  775.     QuestServerNameAvailableReply = 4253,\
  776. }\
  777. \
  778. local function isOpen(channel)\
  779.     return Peripheral.CallType('wireless_modem', 'isOpen', channel)\
  780. end\
  781. \
  782. local function open(channel)\
  783.     if not isOpen(channel) then\
  784.         Peripheral.CallType('wireless_modem', 'open', channel)\
  785.     end\
  786. end\
  787. \
  788. Open = open\
  789. \
  790. local function close(channel)\
  791.     Peripheral.CallType('wireless_modem', 'close', channel)\
  792. end\
  793. \
  794. local function closeAll()\
  795.     Peripheral.CallType('wireless_modem', 'closeAll')\
  796. end\
  797. \
  798. local function transmit(channel, replyChannel, message)\
  799.     Peripheral.CallType('wireless_modem', 'transmit', channel, replyChannel, textutils.serialize(message))\
  800. end\
  801. \
  802. function Present()\
  803.     if Peripheral.GetPeripheral('wireless_modem') == nil then\
  804.         return false\
  805.     else\
  806.         return true\
  807.     end\
  808. end\
  809. \
  810. local function FormatMessage(message, messageID, destinationID)\
  811.     return {\
  812.         content = textutils.serialize(message),\
  813.         senderID = os.getComputerID(),\
  814.         senderName = os.getComputerLabel(),\
  815.         channel = channel,\
  816.         replyChannel = reply,\
  817.         messageID = messageID or math.random(10000),\
  818.         destinationID = destinationID\
  819.     }\
  820. end\
  821. \
  822. local Timeout = function(func, time)\
  823.     time = time or 1\
  824.     parallel.waitForAny(func, function()\
  825.         sleep(time)\
  826.         --log('Timeout!'..time)\
  827.     end)\
  828. end\
  829. \
  830. RecieveMessage = function(_channel, messageID, timeout)\
  831.     open(_channel)\
  832.     local done = false\
  833.     local event, side, channel, replyChannel, message = nil\
  834.     Timeout(function()\
  835.         while not done do\
  836.             event, side, channel, replyChannel, message = os.pullEvent('modem_message')\
  837.             if channel ~= _channel then\
  838.                 event, side, channel, replyChannel, message = nil\
  839.             else\
  840.                 message = textutils.unserialize(message)\
  841.                 message.content = textutils.unserialize(message.content)\
  842.                 if messageID and messageID ~= message.messageID or (message.destinationID ~= nil and message.destinationID ~= os.getComputerID()) then\
  843.                     event, side, channel, replyChannel, message = nil\
  844.                 else\
  845.                     done = true\
  846.                 end\
  847.             end\
  848.         end\
  849.     end,\
  850.     timeout)\
  851.     return event, side, channel, replyChannel, message\
  852. end\
  853. \
  854. Initialise = function()\
  855.     if Present() then\
  856.         for i, c in pairs(Channels) do\
  857.             open(c)\
  858.         end\
  859.     end\
  860. end\
  861. \
  862. HandleMessage = function(event, side, channel, replyChannel, message, distance)\
  863.     message = textutils.unserialize(message)\
  864.     message.content = textutils.unserialize(message.content)\
  865. \
  866.     if channel == Channels.Ping then\
  867.         if message.content == 'Ping!' then\
  868.             SendMessage(replyChannel, 'Pong!', nil, message.messageID)\
  869.         end\
  870.     elseif message.destinationID ~= nil and message.destinationID ~= os.getComputerID() then\
  871.     elseif Wireless.Responder then\
  872.         Wireless.Responder(event, side, channel, replyChannel, message, distance)\
  873.     end\
  874. end\
  875. \
  876. SendMessage = function(channel, message, reply, messageID, destinationID)\
  877.     reply = reply or channel + 1\
  878.     open(channel)\
  879.     open(reply)\
  880.     local _message = FormatMessage(message, messageID, destinationID)\
  881.     transmit(channel, reply, _message)\
  882.     return _message\
  883. end\
  884. \
  885. Ping = function()\
  886.     local message = SendMessage(Channels.Ping, 'Ping!', Channels.PingReply)\
  887.     RecieveMessage(Channels.PingReply, message.messageID)\
  888. end",},}
  889.  
  890. local function run(tArgs)
  891.  
  892.   local fnFile, err = loadstring(files['startup'], 'startup')
  893.   if err then
  894.     error(err)
  895.   end
  896.  
  897.   local function split(str, pat)
  898.      local t = {}
  899.      local fpat = "(.-)" .. pat
  900.      local last_end = 1
  901.      local s, e, cap = str:find(fpat, 1)
  902.      while s do
  903.         if s ~= 1 or cap ~= "" then
  904.      table.insert(t,cap)
  905.         end
  906.         last_end = e+1
  907.         s, e, cap = str:find(fpat, last_end)
  908.      end
  909.      if last_end <= #str then
  910.         cap = str:sub(last_end)
  911.         table.insert(t, cap)
  912.      end
  913.      return t
  914.   end
  915.  
  916.   local function resolveTreeForPath(path, single)
  917.     local _files = files
  918.     local parts = split(path, '/')
  919.     if parts then
  920.       for i, v in ipairs(parts) do
  921.         if #v > 0 then
  922.           if _files[v] then
  923.             _files = _files[v]
  924.           else
  925.             _files = nil
  926.             break
  927.           end
  928.         end
  929.       end
  930.     elseif #path > 0 and path ~= '/' then
  931.       _files = _files[path]
  932.     end
  933.     if not single or type(_files) == 'string' then
  934.       return _files
  935.     end
  936.   end
  937.  
  938.   local oldFs = fs
  939.   local env
  940.   env = {
  941.     fs = {
  942.       list = function(path)
  943.               local list = {}
  944.               if fs.exists(path) then
  945.             list = fs.list(path)
  946.               end
  947.         for k, v in pairs(resolveTreeForPath(path)) do
  948.           if not fs.exists(path .. '/' ..k) then
  949.             table.insert(list, k)
  950.           end
  951.         end
  952.         return list
  953.       end,
  954.  
  955.       exists = function(path)
  956.         if fs.exists(path) then
  957.           return true
  958.         elseif resolveTreeForPath(path) then
  959.           return true
  960.         else
  961.           return false
  962.         end
  963.       end,
  964.  
  965.       isDir = function(path)
  966.         if fs.isDir(path) then
  967.           return true
  968.         else
  969.           local tree = resolveTreeForPath(path)
  970.           if tree and type(tree) == 'table' then
  971.             return true
  972.           else
  973.             return false
  974.           end
  975.         end
  976.       end,
  977.  
  978.       isReadOnly = function(path)
  979.         if not fs.isReadOnly(path) then
  980.           return false
  981.         else
  982.           return true
  983.         end
  984.       end,
  985.  
  986.       getName = fs.getName,
  987.  
  988.       getSize = fs.getSize,
  989.  
  990.       getFreespace = fs.getFreespace,
  991.  
  992.       makeDir = fs.makeDir,
  993.  
  994.       move = fs.move,
  995.  
  996.       copy = fs.copy,
  997.  
  998.       delete = fs.delete,
  999.  
  1000.       combine = fs.combine,
  1001.  
  1002.       open = function(path, mode)
  1003.         if fs.exists(path) then
  1004.           return fs.open(path, mode)
  1005.         elseif type(resolveTreeForPath(path)) == 'string' then
  1006.           local handle = {close = function()end}
  1007.           if mode == 'r' then
  1008.             local content = resolveTreeForPath(path)
  1009.             handle.readAll = function()
  1010.               return content
  1011.             end
  1012.  
  1013.             local line = 1
  1014.             local lines = split(content, '\n')
  1015.             handle.readLine = function()
  1016.               if line > #lines then
  1017.                 return nil
  1018.               else
  1019.                 return lines[line]
  1020.               end
  1021.               line = line + 1
  1022.             end
  1023.                       return handle
  1024.           else
  1025.             error('Cannot write to read-only file (compilr archived).')
  1026.           end
  1027.         else
  1028.           return fs.open(path, mode)
  1029.         end
  1030.       end
  1031.     },
  1032.  
  1033.     loadfile = function( _sFile )
  1034.         local file = env.fs.open( _sFile, "r" )
  1035.         if file then
  1036.             local func, err = loadstring( file.readAll(), fs.getName( _sFile ) )
  1037.             file.close()
  1038.             return func, err
  1039.         end
  1040.         return nil, "File not found: ".._sFile
  1041.     end,
  1042.  
  1043.     dofile = function( _sFile )
  1044.         local fnFile, e = env.loadfile( _sFile )
  1045.         if fnFile then
  1046.             setfenv( fnFile, getfenv(2) )
  1047.             return fnFile()
  1048.         else
  1049.             error( e, 2 )
  1050.         end
  1051.     end
  1052.   }
  1053.  
  1054.   setmetatable( env, { __index = _G } )
  1055.  
  1056.   local tAPIsLoading = {}
  1057.   env.os.loadAPI = function( _sPath )
  1058.       local sName = fs.getName( _sPath )
  1059.       if tAPIsLoading[sName] == true then
  1060.           printError( "API "..sName.." is already being loaded" )
  1061.           return false
  1062.       end
  1063.       tAPIsLoading[sName] = true
  1064.          
  1065.       local tEnv = {}
  1066.       setmetatable( tEnv, { __index = env } )
  1067.       local fnAPI, err = env.loadfile( _sPath )
  1068.       if fnAPI then
  1069.           setfenv( fnAPI, tEnv )
  1070.           fnAPI()
  1071.       else
  1072.           printError( err )
  1073.           tAPIsLoading[sName] = nil
  1074.           return false
  1075.       end
  1076.      
  1077.       local tAPI = {}
  1078.       for k,v in pairs( tEnv ) do
  1079.           tAPI[k] =  v
  1080.       end
  1081.      
  1082.       env[sName] = tAPI    
  1083.       tAPIsLoading[sName] = nil
  1084.       return true
  1085.   end
  1086.  
  1087.   env.shell = shell
  1088.  
  1089.   setfenv( fnFile, env )
  1090.   fnFile(unpack(tArgs))
  1091. end
  1092.  
  1093. local function extract()
  1094.     local function node(path, tree)
  1095.         if type(tree) == 'table' then
  1096.             fs.makeDir(path)
  1097.             for k, v in pairs(tree) do
  1098.                 node(path .. '/' .. k, v)
  1099.             end
  1100.         else
  1101.             local f = fs.open(path, 'w')
  1102.             if f then
  1103.                 f.write(tree)
  1104.                 f.close()
  1105.             end
  1106.         end
  1107.     end
  1108.     node('', files)
  1109. end
  1110.  
  1111. local tArgs = {...}
  1112. if #tArgs == 1 and tArgs[1] == '--extract' then
  1113.   extract()
  1114. else
  1115.   run(tArgs)
  1116. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement