Advertisement
77wisher77

startUp YamiDimStack

Jun 4th, 2021 (edited)
351
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.16 KB | None | 0 0
  1. local PROGRAM_VERSION = [["1.3"]]
  2. local PROGRAM_VERSION_CONVERTED = "local PROGRAM_VERSION = ".."[["..PROGRAM_VERSION.."]]"
  3. local PROGRAM_LINK = "1RzY7DFx"
  4. -- downloads and installs all Libraries and APIs, downloads any programs that the computer should have based on its label, also updates this very file - how nifty
  5. -- try `wget` shell command, apparently can save a url to file, is shell.wget(url, filename), works, for pastebin use raw links
  6. -- TODO: migrate all ["link"]'s to gitlab links, make repo public, this will avoid silly restrictions on pastebin
  7. --    or use pipelines to push live files to gitlab pages and collect them there via `shell.run("wget", url, filename)`
  8. -- TODO: change over checkVersion() & checkSelf() to wget so files can be collected from gitlab pages
  9. -- TODO: if api is already loaded then should reload it, as it may have been updated
  10. -- TODO: adds checks for remaining disk space (also check type of computer to get total diskspace, or is there a total disk space command?)
  11. -- TODO: add check to see if computer has a label, if not exit and ask user to label computer
  12.  
  13. -- a list of all dependencies (libraries/apis) that wishers programs use
  14.  
  15. local DEPENDENCIES = {
  16.   [1] = {
  17.     ["file"] = "wLibMining",
  18.     ["link"] = "XkajLyXx",
  19.     ["path"] = "wisher/"
  20.   },
  21.   [2] = {
  22.     ["file"] = "wLibVariables",
  23.     ["link"] = "FuGd7TXY",
  24.     ["path"] = "wisher/"
  25.   }
  26. }
  27.  
  28. -- list of all programs
  29. -- programs are nested again to allow downloading multiple programs
  30. -- these programs should sit in the base directory unlike library/apis which sit in the wisher/ directory
  31. local COMPUTER_PROGRAMS = {
  32.   [1] = {
  33.     ["label"] = "stripMine",
  34.     [1] = {
  35.       ["file"] = "stripMine",
  36.       ["link"] = "nVAXKrBz",
  37.       ["autorun"] = false
  38.     },
  39.     [2] = {
  40.       ["file"] = "exhaust",
  41.       ["link"] = "HcBLDp4r",
  42.       ["autorun"] = false
  43.     }
  44.   },
  45.   [2] = {
  46.     ["label"] = "tester",
  47.     [1] = {
  48.       ["file"] = "exhaust",
  49.       ["link"] = "nVAXKrBz",
  50.       ["autorun"] = false
  51.     }
  52.   },
  53.   [3] = {
  54.     ["label"] = "exhaust",
  55.     [1] = {
  56.       ["file"] = "exhaust",
  57.       ["link"] = "nVAXKrBz",
  58.       ["autorun"] = true
  59.     }
  60.   },
  61.   [4] = {
  62.     ["label"] = "b_unirail",
  63.     [1] = {
  64.       ["file"] = "botania_uniRail",
  65.       ["link"] = "0XHwwCkU",
  66.       ["autorun"] = true
  67.     }
  68.   }
  69. }
  70.  
  71. -- table which stores what happened to each file during startup, used for verbose, could be used for debugging or other useful things too
  72. local fileStatus = {
  73.   [1] = {
  74.     ["type"] = "Dependencies",
  75.     [1] = {
  76.       ["status"] = "Fresh Download: "
  77.     },
  78.     [2] = {
  79.     ["status"] = "Loaded: "
  80.     },
  81.     [3] = { -- in-case startup is manually executed after actual startup for some reason
  82.     ["status"] = "Already Loaded: "
  83.     },
  84.     [4] = {
  85.     ["status"] = "Updated: "
  86.     }
  87.   },
  88.   [2] = { -- Programs
  89.     ["type"] = "Programs",
  90.     [1] = {
  91.       ["status"] = "Fresh Download: "
  92.     },
  93.     [2] = {
  94.     ["status"] = "Loaded: "
  95.     },
  96.     [3] = { -- in-case startup is manually executed after actual startup for some reason
  97.     ["status"] = "Already Loaded: "
  98.     },
  99.     [4] = {
  100.     ["status"] = "Updated: "
  101.     }
  102.   }
  103. }
  104. -- fileStatusIndexType - used to determin whether for Dependency or Programs, range 1-2 || MANUALLY SET TO VALUE REQUIRED IN FUNCTION WHICH UTILIZES
  105. -- fileStatusIndexStatus - used to determin whether for Downloaded, Loaded, Already Loaded or updated files range 1-4 in order
  106. -- fileStatusIndexFilename - needs to be logged locally for each IndexStatus
  107.  
  108. -- set this to true if any file fails something it should succeed, e.g. loading api/lib, freshly downloading program, updating program etc.
  109. -- if this is true then print a message to check a log file. and open another window (unfocused) with log?? how do windows work on these computers
  110. -- this is set true inside logFailed() as that is only called when something fails
  111. local fileStatusFailed = false
  112.  
  113. -- used to delete the log on each boot
  114. local logIndex = 0
  115.  
  116. -- helper function to get a particular type of application state, and persist the default if it's not set
  117. function getState(type)
  118.   local DEFAULT_STATE = 0
  119.  
  120.   local filepath = "wisher/_states/_" .. type
  121.  
  122.   if (fs.exists(filepath)) then
  123.     local handle = fs.open(filepath, "r")
  124.     local state = tonumber(handle.read())
  125.  
  126.     handle.close()
  127.  
  128.     return state
  129.   else
  130.     -- persist the default if no state has been persisted already
  131.     return setState(type, DEFAULT_STATE)
  132.   end
  133. end
  134.  
  135. -- helper function to persist a particular type of application state
  136. function setState(type, state)
  137.   local filepath = "wisher/_states/_" .. type
  138.   local handle = fs.open(filepath, "w")
  139.  
  140.   handle.write(state)
  141.   handle.close()
  142.  
  143.   return state
  144. end
  145.  
  146. -- returns the state, can be used for persistence accross file being closed (ie self update) or computer shutting down (chunk unloaded, server restarted etc.)
  147. function getStartupState()
  148.   return getState("startup")
  149. end
  150.  
  151. -- sets the state, used for file persistence
  152. function setStartupState(state)
  153.   setState("startup", state)
  154. end
  155.  
  156. -- used by checkSelf(), start() to determin what to do, 1=upToDate, 2=needs updating, 3=error(file not downloaded/copied), 4=Updated this boot
  157. function getStartupUpdate()
  158.   return getState("startupUpdate")
  159. end
  160.  
  161. -- sets the update status
  162. function setStartupUpdate(state)
  163.   setState("startupUpdate", state)
  164. end
  165.  
  166. -- returns the file PROGRAM_VERSION as a string for a specified file, this should be the first line in any live file
  167. function getVersion(filepath)
  168.   local handle = fs.open(filepath, "r")
  169.   local version = tostring(handle.readLine())
  170.   handle.close()
  171.   return version
  172. end
  173.  
  174. -- Appends the filenames of any failed files to a log with the server system date at the top of the file ie
  175. -- "programName: ".."status".." ".."failed"
  176. -- will mention whether it failed to download, update etc.
  177. -- sets fileStatusFailed to true which is used to print a message to read the log
  178. function logFailed(programName, programStatus)
  179.   local filepath = "wisher/_log/_startup"
  180.   logIndex = logIndex + 1
  181.  
  182.   if (logIndex == 1) then -- if this is the first file to be logged this boot then delete the previous log file to save storage space
  183.     fs.delete(filepath)
  184.   end
  185.  
  186.   local handle = fs.open(filepath, "a")
  187.  
  188.   if (logIndex == 1) then handle.writeLine(os.date()) end -- top line should be date for clarification
  189.  
  190.   handle.writeLine(programName .. ": " .. programStatus .. "Failed")
  191.   handle.close()
  192.   fileStatusFailed = true
  193. end
  194.  
  195. --  checks if a file needs updating by downloading and comparing the version number
  196. --  logs updates into fileStatus{}, logs fails to logFailed()
  197. --    we can always assume the 2nd fileStatus index is 4 since 4 = updated
  198. function checkVersion(fileCurrent, fileLink, verboseIndexType, verboseIndexFilename, ...)
  199.   --make sure to pass file path and file name if library for fileCurrent
  200.   local fileBasename = fileCurrent
  201.   local isUpdate = false
  202.  
  203.   if (#arg == 5) then
  204.     fileBasename = arg[5] -- used for checkDependecies where the fileCurrent includes path, this is to neaten verbose
  205.   end
  206.  
  207.   local remoteFileName = fileCurrent .. "VerCheck"
  208.   local localFileVersion = getVersion(fileCurrent)
  209.   shell.run("pastebin", "get", fileLink, remoteFileName)
  210.  
  211.   if (not fs.exists(remoteFileName)) then
  212.     -- if the file failed to download then log updated failed
  213.     logFailed(fileBasename, fileStatus[verboseIndexType][4])
  214.   end
  215.  
  216.   if (fs.exists(remoteFileName)) then
  217.     -- if the file successfully downloaded then proceed with logic and log the fileStatus
  218.     local remoteFileVersion = getVersion(remoteFileName)
  219.  
  220.     if (not (localFileVersion == remoteFileVersion)) then -- if the remoteFile version is different then delete current and rename new
  221.       fs.delete(fileCurrent)
  222.       fs.move(remoteFileName, fileCurrent)
  223.       fileStatus[verboseIndexType][4][verboseIndexFilename] = fileBasename
  224.       isUpdate = true
  225.     end
  226.  
  227.     if (localFileVersion == remoteFileVersion) then -- if file versions match then delete the comparison file
  228.       fs.delete(remoteFileName)
  229.     end
  230.   end
  231.  
  232.   return isUpdate
  233. end
  234.  
  235. -- Checks to see if this very program needs updating
  236. -- sets a value in a file to used persistently to determin whether the file needs updating
  237. -- refer to getStartupUpdate() comments to know what the numbers mean
  238. function checkSelf()
  239.   local fileCurrent = "startup"
  240.   local remoteFileName = fileCurrent .. "VerCheck"
  241.   shell.run("pastebin", "get", PROGRAM_LINK, remoteFileName)
  242.  
  243.   if (not fs.exists(remoteFileName)) then
  244.     setStartupUpdate(3)
  245.     return
  246.   end
  247.  
  248.   if (fs.exists(remoteFileName)) then
  249.     local remoteFileVersion = getVersion(remoteFileName)
  250.  
  251.     if (not (PROGRAM_VERSION_CONVERTED == remoteFileVersion)) then
  252.       fs.copy(fileCurrent, fileCurrent .. "Updater")
  253.  
  254.       if (fs.exists(fileCurrent .. "Updater")) then
  255.         setStartupUpdate(2)
  256.         return
  257.       end
  258.  
  259.       if (not (fs.exists(fileCurrent .. "Updater"))) then
  260.         setStartupUpdate(3)
  261.         return
  262.       end
  263.     end
  264.  
  265.     if (PROGRAM_VERSION_CONVERTED == remoteFileVersion) then
  266.         fs.delete(remoteFileName)
  267.         setStartupUpdate(1)
  268.         return
  269.     end
  270.   end
  271. end
  272.  
  273. -- Ensures all Libraries/Apis are downloaded, logs successes to fileStatus{}, logs failures to logFailed()
  274. function checkDependencies()
  275.   local libList = {} -- for libs physically located on the robot
  276.   local apiExist = false
  277.   local fileStatusIndexUpdate = 1 -- needs to be logged locally for each IndexStatus, index for the Filename, starts at 1 since we pass this into checkVersion() args, update if returns true, therefore first run must be 1 not 0
  278.   local fileStatusIndexDownload = 0
  279.  
  280.   for i, v in ipairs(DEPENDENCIES) do
  281.     local libName = DEPENDENCIES[i]["path"] .. DEPENDENCIES[i]["file"]
  282.     local libLink = DEPENDENCIES[i]["link"]
  283.     libList[i] = shell.resolveProgram(libName) -- attempts to add the filename of dependency[i] to libList to prove it exists
  284.  
  285.     if (libList[i] == libName) then --if the lib exists then check its version
  286.       apiExist = true
  287.  
  288.         if (checkVersion(libName, libLink, 1, fileStatusIndexUpdate, DEPENDENCIES[i]["file"])) then -- only update index if checkVersion actually updates
  289.           fileStatusIndexUpdate = fileStatusIndexUpdate + 1
  290.         end
  291.     end
  292.  
  293.     if (apiExist == false) then -- if the lib doesnt exist, download it by using the link in dependancy[i]
  294.       shell.run("pastebin", "get", libLink, libName)
  295.  
  296.       if (fs.exists(libName)) then
  297.         fileStatusIndexDownload = fileStatusIndexDownload + 1
  298.         fileStatus[1][1][fileStatusIndexDownload] = DEPENDENCIES[i]["file"]
  299.       end
  300.  
  301.       if (not fs.exists(libName)) then
  302.           -- if the file did not download then log this
  303.           logFailed(DEPENDENCIES[i]["file"], fileStatus[1][1])
  304.       end
  305.     end
  306.     apiExist = false
  307.   end
  308. end
  309.  
  310. -- Dynamically initializes DEPENDENCIES globally, only if one with the same name doesnt already exist, logs successes to fileStatus{}, failures to logFailed()
  311. function initializeDependencies()
  312.   local fileStatusIndexAlready = 0 -- needs to be logged locally for each IndexStatus
  313.   local fileStatusIndexLoaded = 0
  314.  
  315.   for keyLibIndex, valueLibName in ipairs(DEPENDENCIES) do
  316.     local libraryName = DEPENDENCIES[keyLibIndex]["file"]
  317.     local libraryPath = DEPENDENCIES[keyLibIndex]["path"] .. DEPENDENCIES[keyLibIndex]["file"]
  318.  
  319.     if (_G[libraryName]) then
  320.       fileStatusIndexAlready = fileStatusIndexAlready + 1
  321.       fileStatus[1][3][fileStatusIndexAlready] = libraryName
  322.     end
  323.  
  324.     if (not _G[libraryName]) then
  325.       _G[libraryName] = require(libraryPath)
  326.       fileStatusIndexLoaded = fileStatusIndexLoaded + 1
  327.       fileStatus[1][2][fileStatusIndexLoaded] = libraryName
  328.  
  329.       if (not _G[libraryName]) then
  330.           -- if the file still isn't loaded then log it didnt load, it should have loaded by now
  331.           logFailed(libraryName, fileStatus[1][2])
  332.       end
  333.     end
  334.   end
  335. end
  336.  
  337. -- Checks label of computer and downloads appropriate program/s, logs successes to fileStatus{}, logs failures to logFailed()
  338. function checkPrograms()
  339.   local computerType = os.getComputerLabel()
  340.   computerType = string.lower(computerType)
  341.   local programList = {}
  342.   local programListIndex = 0 -- need to manually index this since our loops are inside loops and the numbers would get funky if we used their iterator
  343.   local programExist = false
  344.   local fileStatusIndexUpdate = 1 -- needs to start at 1 as checkVersion() parses this, only update if true is received back
  345.   local fileStatusIndexDownload = 0
  346.  
  347.   for iOne, vOne in ipairs(COMPUTER_PROGRAMS) do
  348.     local computerLabel = COMPUTER_PROGRAMS[iOne]["label"]
  349.     computerLabel = string.lower(computerLabel)
  350.  
  351.     for iTwo, vTwo in ipairs(COMPUTER_PROGRAMS[iOne]) do
  352.       programListIndex = programListIndex + 1
  353.       local programName = COMPUTER_PROGRAMS[iOne][iTwo]["file"]
  354.       local programLink = COMPUTER_PROGRAMS[iOne][iTwo]["link"]
  355.       programList[programListIndex] = shell.resolveProgram(programName)
  356.  
  357.       if (string.find(computerType, computerLabel)) then -- only download programs if the computer label matches the table label
  358.         if (programList[programListIndex] == programName) then -- checks if file already exists
  359.           programExist = true
  360.  
  361.           if checkVersion(programName, programLink, 2, fileStatusIndexUpdate) then
  362.             fileStatusIndexUpdate = fileStatusIndexUpdate + 1
  363.           end
  364.         end
  365.  
  366.         if (programExist == false) then -- if file doesnt exist, download
  367.           shell.run("pastebin", "get", programLink, programName)
  368.  
  369.           if (fs.exists(programName)) then
  370.             fileStatusIndexDownload = fileStatusIndexDownload + 1
  371.             fileStatus[2][1][fileStatusIndexDownload] = programName
  372.           end
  373.  
  374.           if (not fs.exists(programName)) then
  375.               logFailed(programName, fileStatus[2][1])
  376.           end
  377.         end
  378.       end
  379.       programExist = false
  380.     end
  381.   end
  382. end
  383.  
  384. -- cleans the screen then prints how each file was handled, ie Downloaded, Loaded, Already Loaded, Updated, also informs startup version
  385. function verboseFileStatus()
  386.   -- need 3 loops? Type loop, Status loop, filename loop
  387.   shell.run("clear")
  388.  
  389.   for iType, vType in ipairs(fileStatus) do
  390.     print(fileStatus[iType]["type"])
  391.  
  392.       for iStatus, vStatus in ipairs(fileStatus[iType]) do
  393.         write(fileStatus[iType][iStatus]["status"])
  394.  
  395.         for iFilename, vFilename in ipairs(fileStatus[iType][iStatus]) do
  396.         write(vFilename .. " ")
  397.         end
  398.  
  399.         write("\n")
  400.       end
  401.   end
  402.  
  403.   print("Startup File Version: " .. PROGRAM_VERSION)
  404. end
  405.  
  406. --  returns the program name to run, or false if none.
  407. --  only returns program name if ONLY 1 program is set to autorun, if more than 1 progam should be run automatically than handle within THAT program
  408. function shouldInitializeProgram()
  409.   local computerLabel = os.getComputerLabel()
  410.   local programName
  411.   local isAutorun = false
  412.   local autorunCount = 0
  413.  
  414.   for i, v in pairs(COMPUTER_PROGRAMS) do
  415.     if (computerLabel == COMPUTER_PROGRAMS[i]["label"]) then
  416.         for ia, va in pairs(COMPUTER_PROGRAMS[i]) do
  417.           if (COMPUTER_PROGRAMS[i][ia]["autorun"]) then
  418.               programName = COMPUTER_PROGRAMS[i][ia]["file"]
  419.               isAutorun = true
  420.               autorunCount = autorunCount + 1
  421.           end
  422.         end
  423.     end
  424.   end
  425.  
  426.   if (isAutorun) and (autorunCount == 1) then
  427.     return programName
  428.   end
  429.  
  430.   if (autorunCount > 1) then
  431.     isAutorun = false
  432.     return isAutorun
  433.   end
  434.  
  435.   if (not isAutorun) then
  436.     return isAutorun
  437.   end
  438. end
  439.  
  440. -- Main function, first checks if it needs to update itself, then updates dependencies, initializes dependencies, updates programs, verboses what happened to all prior, then initializes autorun program if there is ONE
  441. function start()
  442.   local fileCurrent = "startup"
  443.   local fileUpdater = fileCurrent .. "Updater"
  444.   local fileRemote = fileCurrent .. "VerCheck"
  445.  
  446.   -- state list: 0=start of file, 1=open copy to update self, 2=close original update original,3=open original and close updater and delete files, 4=Check/Init Dependencies - Check programs - verbose - autorun
  447.   if (getStartupState() == 0) then -- if just booted
  448.     checkSelf()
  449.  
  450.     if (getStartupUpdate() ~= 2) then
  451.       -- if startup is upToDate OR failed to check properly, then do everything else
  452.       setStartupState(4)
  453.     end
  454.  
  455.     if (getStartupUpdate() == 2) then
  456.       -- if startup needs updating then begin that process
  457.       setStartupState(1)
  458.       shell.run(fileUpdater)
  459.       return
  460.     end
  461.   end
  462.  
  463.   if (getStartupState() == 1) then -- if needs updating then
  464.     --rename updated file to startup, delete original startup, launch startup again
  465.     fs.delete(fileCurrent)
  466.     if (not fs.exists(fileCurrent)) then fs.move(fileRemote, fileCurrent) end
  467.  
  468.     setStartupState(2)
  469.     shell.run(fileCurrent)
  470.     return
  471.   end
  472.  
  473.   if (getStartupState() == 2) then --if updated then
  474.     -- delete updater, then continue with normal startup
  475.     fs.delete(fileUpdater)
  476.     setStartupState(3)
  477.     os.reboot()
  478.   end
  479.  
  480.   if (getStartupState() == 3) then -- if finished updating & rebooted then set that value and finish remaining startup processes
  481.     setStartupUpdate(4)
  482.     setStartupState(4)
  483.   end
  484.  
  485.   if (getStartupState() == 4) then -- normal startup stuff
  486.     checkDependencies()
  487.     initializeDependencies()
  488.     checkPrograms()
  489.     verboseFileStatus()
  490.  
  491.     if (getStartupUpdate() == 4) then print("Startup was updated!") end
  492.  
  493.     if (getStartupUpdate() == 3) then -- if self-update failed, log to logFailed()
  494.       logFailed("Startup", "Updated: ")
  495.     end
  496.  
  497.     if (fileStatusFailed) then
  498.       print("Something went wrong, check log for details")
  499.     end
  500.   end
  501.  
  502.   setStartupState(0) -- so the next boot sequence or run of startup will continue from the top of start()
  503.   fs.delete("wisher/_states/_startupUpdate") -- regenerate startupUpdate information each completed boot sequence
  504.  
  505.   if (shouldInitializeProgram() ~= false) then
  506.     -- if shouldInitializeProgram returns any value that ISNT false
  507.     sleep(5) -- time to read screen verbose before executing autorun
  508.     shell.run(shouldInitializeProgram())
  509.     return
  510.   end
  511. end
  512.  
  513. start()
  514.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement