Advertisement
Oeed

Quest Server

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