We didnt start the fire
This commit is contained in:
		
							parent
							
								
									68422b9343
								
							
						
					
					
						commit
						b7ad80b226
					
				
							
								
								
									
										244
									
								
								keypadOS.lua
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								keypadOS.lua
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,244 +0,0 @@
 | 
			
		|||
local __BUNDLER_FILES = {}
 | 
			
		||||
local __DEFAULT_IMPORT = require
 | 
			
		||||
local require = function(path)
 | 
			
		||||
    if __BUNDLER_FILES[path] then
 | 
			
		||||
        return __BUNDLER_FILES[path]()
 | 
			
		||||
    else
 | 
			
		||||
        return __DEFAULT_IMPORT(path)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
local __UPDATE_HASH = "56dffe1d3654b028310d4c9dc976b7c7cc8c9d5a"
 | 
			
		||||
rawset(__BUNDLER_FILES, "updater.lua", function ()
 | 
			
		||||
    local utils = require("utils.lua")
 | 
			
		||||
    local config = require("config.lua")
 | 
			
		||||
    local LAST_USED = os.time()
 | 
			
		||||
    local mod = {}
 | 
			
		||||
    if not __UPDATE_HASH then
 | 
			
		||||
        __UPDATE_HASH = "WHATTHEFUCK";
 | 
			
		||||
    end
 | 
			
		||||
    local function checkForUpdate()
 | 
			
		||||
        local current_time = os.time()
 | 
			
		||||
        local difference = math.abs(current_time - LAST_USED)
 | 
			
		||||
        if difference > .5 then
 | 
			
		||||
            print("INFO: Updating! (diff: " .. tostring(difference) .. ")")
 | 
			
		||||
            local update_code_request = http.get(config.release_url .. "?x=" .. tostring(math.random(11111111, 99999999))) -- I HATE CACHE REEEEEEEEEEEEEEEEE
 | 
			
		||||
            if update_code_request then
 | 
			
		||||
                local update_code_text = update_code_request.readAll()
 | 
			
		||||
                if update_code_text then
 | 
			
		||||
                    if string.find(update_code_text, "^local __BUNDLER_FILES = {}") then
 | 
			
		||||
                        if fs.exists("backup.lua") then
 | 
			
		||||
                            fs.delete("backup.lua")
 | 
			
		||||
                        end
 | 
			
		||||
                        fs.copy("startup.lua", "backup.lua")
 | 
			
		||||
                        if not string.find(update_code_text, __UPDATE_HASH) then
 | 
			
		||||
                            http.post(config.ntfy_url, "Computer #" .. tostring( os.getComputerID() ) .. " updating")
 | 
			
		||||
                            local file = fs.open("startup.lua", "w")
 | 
			
		||||
                            file.write(update_code_text)
 | 
			
		||||
                            file.close()
 | 
			
		||||
                            os.reboot()
 | 
			
		||||
                        else
 | 
			
		||||
                            print("Nothing changed, not updating.")
 | 
			
		||||
                            LAST_USED = os.time()
 | 
			
		||||
                            return
 | 
			
		||||
                        end
 | 
			
		||||
                    else
 | 
			
		||||
                        print("Bad file download (core)")
 | 
			
		||||
                    end
 | 
			
		||||
                else
 | 
			
		||||
                    print("Bad mem read (core)")
 | 
			
		||||
                end
 | 
			
		||||
            else
 | 
			
		||||
                print("Bad download (core)")
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    function mod.UpdateChecker()
 | 
			
		||||
        while true do
 | 
			
		||||
            local status, err = pcall(checkForUpdate)
 | 
			
		||||
            if not status and err ~= "Terminated" then
 | 
			
		||||
                http.post(config.ntfy_url, err, {Priority = "urgent"}) 
 | 
			
		||||
            end
 | 
			
		||||
            sleep(1)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    function mod.GetBasalt()
 | 
			
		||||
        if fs.exists("basalt.lua") then
 | 
			
		||||
            utils.MonPrint("Basalt found!")
 | 
			
		||||
        else
 | 
			
		||||
            utils.MonPrint("Downloading basalt...")
 | 
			
		||||
            local basalt_code = http.get(config.basalt_url).readAll()
 | 
			
		||||
            utils.MonPrint("Installing basalt...")
 | 
			
		||||
            local file = fs.open("basalt.lua", "w")
 | 
			
		||||
            if not file then
 | 
			
		||||
                utils.MonPrint("failed to get basalt")
 | 
			
		||||
                sleep(60)
 | 
			
		||||
                os.reboot()
 | 
			
		||||
            end
 | 
			
		||||
            file.write(utils.Cast(basalt_code))
 | 
			
		||||
            file.close()
 | 
			
		||||
            utils.MonPrint("Rebooting...")
 | 
			
		||||
            os.reboot()
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return mod
 | 
			
		||||
end)
 | 
			
		||||
rawset(__BUNDLER_FILES, "config.lua", function ()
 | 
			
		||||
    local config = {
 | 
			
		||||
        correctPin = "42069",
 | 
			
		||||
        release_url = "https://git.mcorangehq.xyz/xomf/keypadOS/raw/branch/main/keypadOS.lua",
 | 
			
		||||
        basalt_url = "https://raw.githubusercontent.com/Pyroxenium/Basalt/master/docs/versions/latest.lua",
 | 
			
		||||
        ntfy_url = "https://ntfy.sh/keypadOS_alerts",
 | 
			
		||||
        config_path = "keypadOS.config.lua"
 | 
			
		||||
    }
 | 
			
		||||
    local DEFAULT_CONFIG =  "return {\n" ..
 | 
			
		||||
                            "    group=\"default\",\n" ..
 | 
			
		||||
                            "}\n"
 | 
			
		||||
    function config.ReadConfig()
 | 
			
		||||
        if not fs.exists(config.config_path) then
 | 
			
		||||
            local f = fs.open(config.config_path, "w")
 | 
			
		||||
            f.write(DEFAULT_CONFIG)
 | 
			
		||||
            f.close();
 | 
			
		||||
        end
 | 
			
		||||
        local cfg = require(config.config_path)
 | 
			
		||||
        return cfg
 | 
			
		||||
    end
 | 
			
		||||
    return config
 | 
			
		||||
end)
 | 
			
		||||
rawset(__BUNDLER_FILES, "ui.lua", function ()
 | 
			
		||||
    local utils = require("utils.lua")
 | 
			
		||||
    local basalt = require("basalt")
 | 
			
		||||
    local config = require("config.lua")
 | 
			
		||||
    local updater = require("updater.lua")
 | 
			
		||||
    local monitor = utils.Cast(peripheral.find("monitor"))
 | 
			
		||||
    local drive = utils.Cast(peripheral.find("drive"))
 | 
			
		||||
    local mod = {}
 | 
			
		||||
    local function resetEverything(ui)
 | 
			
		||||
        sleep(2)
 | 
			
		||||
        ui.pin = ""
 | 
			
		||||
        ui.pinLabel:setText("")
 | 
			
		||||
        redstone.setOutput("front", false)
 | 
			
		||||
        ui.enterButton:setBackground(colors.blue)
 | 
			
		||||
    end
 | 
			
		||||
    local function unlockDoor(ui)
 | 
			
		||||
        if drive.isDiskPresent() then
 | 
			
		||||
            if drive.getDiskLabel() == config.correctPin then
 | 
			
		||||
                ui.pin = config.correctPin
 | 
			
		||||
                drive:ejectDisk()
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        basalt.debug("test")
 | 
			
		||||
        if ui.pin == config.correctPin then
 | 
			
		||||
            ui.enterButton:setBackground(colors.green)
 | 
			
		||||
            ui.pinLabel:setText("Welcome")
 | 
			
		||||
            redstone.setOutput("front", true)
 | 
			
		||||
            if drive.isDiskPresent() then
 | 
			
		||||
                if drive.getDiskLabel() == nil then
 | 
			
		||||
                    drive.setDiskLabel(config.correctPin)
 | 
			
		||||
                    ui.pinLabel:setText("Crd set")
 | 
			
		||||
                    drive:ejectDisk()
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            ui.pinLabel:setText("Wrong")
 | 
			
		||||
            ui.enterButton:setBackground(colors.red)
 | 
			
		||||
        end
 | 
			
		||||
        ui.main:addThread():start(function()
 | 
			
		||||
                resetEverything(ui)
 | 
			
		||||
        end)
 | 
			
		||||
    end
 | 
			
		||||
    local function addToPin(ui, i)
 | 
			
		||||
        if #ui.pin >= 5 then
 | 
			
		||||
            return
 | 
			
		||||
        end
 | 
			
		||||
        ui.pin = ui.pin .. tostring(i)
 | 
			
		||||
        ui.pinLabel:setText(ui.pin)
 | 
			
		||||
    end
 | 
			
		||||
    function mod.InitUi()
 | 
			
		||||
        local ui = {
 | 
			
		||||
            pin = "",
 | 
			
		||||
            main = basalt.addMonitor(),
 | 
			
		||||
        }
 | 
			
		||||
        ui.main:setMonitor(monitor)
 | 
			
		||||
        ui.pinLabel = ui.main:addLabel()
 | 
			
		||||
            :setText("")
 | 
			
		||||
            :setFontSize(1)
 | 
			
		||||
        ui.enterButton = ui.main:addButton()
 | 
			
		||||
            :setText(">>>>")
 | 
			
		||||
            :setBackground(colors.blue)
 | 
			
		||||
            :setPosition(6,2)
 | 
			
		||||
            :setSize(1.5,3.2)
 | 
			
		||||
            :onClick(function()
 | 
			
		||||
                unlockDoor(ui)
 | 
			
		||||
            end)
 | 
			
		||||
        local btnX = 1
 | 
			
		||||
        local btnY = 2
 | 
			
		||||
        ui.main:addButton()
 | 
			
		||||
            :setPosition(1, 5)
 | 
			
		||||
            :setText("0")
 | 
			
		||||
            :setSize(6,1)
 | 
			
		||||
            :onClick(function()
 | 
			
		||||
                addToPin(ui, 0)
 | 
			
		||||
            end)
 | 
			
		||||
        for i = 1, 9 do
 | 
			
		||||
            ui.main:addButton()
 | 
			
		||||
                :setPosition(btnX, btnY)
 | 
			
		||||
                :setText(tostring(i))
 | 
			
		||||
                :setSize(2,1)
 | 
			
		||||
                :onClick(function()
 | 
			
		||||
                    addToPin(ui, i)
 | 
			
		||||
                end)
 | 
			
		||||
            btnX = btnX + 2
 | 
			
		||||
            if btnX >= 6 then
 | 
			
		||||
                btnY = btnY + 1
 | 
			
		||||
                btnX = 1
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        local status, err = pcall(function ()
 | 
			
		||||
            parallel.waitForAll(basalt.autoUpdate, updater.UpdateChecker)
 | 
			
		||||
        end)
 | 
			
		||||
        if not status and err ~= "Terminated" then
 | 
			
		||||
            print("Error detected: " .. err)
 | 
			
		||||
            http.post(config.ntfy_url, err, {Priority = "urgent"}) --exposed ntfy url no spam me pls
 | 
			
		||||
            sleep(5)
 | 
			
		||||
            utils.MonReset(0.5)
 | 
			
		||||
            fs.delete("basalt.lua")
 | 
			
		||||
            fs.delete("startup.lua")
 | 
			
		||||
            fs.copy("backup.lua", "startup.lua")
 | 
			
		||||
            os.reboot()
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    return mod
 | 
			
		||||
end)
 | 
			
		||||
rawset(__BUNDLER_FILES, "utils.lua", function ()
 | 
			
		||||
    local utils = {}
 | 
			
		||||
    function utils.Cast(object)
 | 
			
		||||
        return object
 | 
			
		||||
    end
 | 
			
		||||
    local MONITOR = utils.Cast(peripheral.find("monitor"))
 | 
			
		||||
    local MONITOR_Y = 1
 | 
			
		||||
    function utils.MonPrint(text)
 | 
			
		||||
        MONITOR.setCursorPos(1,MONITOR_Y)
 | 
			
		||||
        MONITOR.write(text)
 | 
			
		||||
        MONITOR_Y = MONITOR_Y + 1
 | 
			
		||||
    end
 | 
			
		||||
    function utils.MonReset(scale)
 | 
			
		||||
        MONITOR.clear()
 | 
			
		||||
        MONITOR.setTextScale(scale)
 | 
			
		||||
    end
 | 
			
		||||
    return utils;
 | 
			
		||||
end)
 | 
			
		||||
rawset(__BUNDLER_FILES, "main.lua", function ()
 | 
			
		||||
    local utils = require("utils.lua")
 | 
			
		||||
    local updater = require("updater.lua")
 | 
			
		||||
    local main = {}
 | 
			
		||||
    KEYPADOS_VERSION = "4.0"
 | 
			
		||||
    function main.Main()
 | 
			
		||||
        utils.MonReset(0.5)
 | 
			
		||||
        updater.GetBasalt()
 | 
			
		||||
        utils.MonPrint("keypadOS v" .. KEYPADOS_VERSION)
 | 
			
		||||
        utils.MonReset(1)
 | 
			
		||||
        require("ui.lua").InitUi()
 | 
			
		||||
    end
 | 
			
		||||
    return main
 | 
			
		||||
end)
 | 
			
		||||
require("main.lua").Main()
 | 
			
		||||
							
								
								
									
										406
									
								
								rtmc.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										406
									
								
								rtmc.lua
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,406 @@
 | 
			
		|||
local __BUNDLER_FILES = {}
 | 
			
		||||
local __DEFAULT_IMPORT = require
 | 
			
		||||
local require = function(path)
 | 
			
		||||
    if __BUNDLER_FILES[path] then
 | 
			
		||||
        return __BUNDLER_FILES[path]()
 | 
			
		||||
    else
 | 
			
		||||
        return __DEFAULT_IMPORT(path)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
rawset(__BUNDLER_FILES, "main.lua", function ()
 | 
			
		||||
    local updater = require("updater");
 | 
			
		||||
    local MODULE_PATH = "keypadOS.lua";
 | 
			
		||||
    local MODULE_URL = "https://git.mcorangehq.xyz/xomf/keypadOS/raw/branch/keypad/keypadOS.lua";
 | 
			
		||||
    local function updaterLoop(upd)
 | 
			
		||||
        while true do
 | 
			
		||||
            upd:checkAndUpdateAll();
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    local function _start()
 | 
			
		||||
        local upd = updater.new();
 | 
			
		||||
        upd:addEntry(MODULE_PATH, "keypad", MODULE_URL);
 | 
			
		||||
        parallel.waitForAny(function() updaterLoop(upd) end, require(MODULE_PATH))
 | 
			
		||||
    end
 | 
			
		||||
    local mod = {};
 | 
			
		||||
    mod.main = _start;
 | 
			
		||||
    return mod;
 | 
			
		||||
end)
 | 
			
		||||
rawset(__BUNDLER_FILES, "log.lua", function ()
 | 
			
		||||
    local log = {};
 | 
			
		||||
    log.__index = log;
 | 
			
		||||
    function log.error(...)
 | 
			
		||||
        print("[ERROR] " .. ...);
 | 
			
		||||
    end
 | 
			
		||||
    function log.warn(...)
 | 
			
		||||
        print("[WARN] " .. ...);
 | 
			
		||||
    end
 | 
			
		||||
    function log.info(...)
 | 
			
		||||
        print("[INFO] " .. ...);
 | 
			
		||||
    end
 | 
			
		||||
    function log.debug(...)
 | 
			
		||||
        print("[DEBUG] " .. ...);
 | 
			
		||||
    end
 | 
			
		||||
    return log;
 | 
			
		||||
end)
 | 
			
		||||
rawset(__BUNDLER_FILES, "json.lua", function ()
 | 
			
		||||
    local json = { _version = "0.1.2" }
 | 
			
		||||
    local encode
 | 
			
		||||
    local escape_char_map = {
 | 
			
		||||
      [ "\\" ] = "\\",
 | 
			
		||||
      [ "\"" ] = "\"",
 | 
			
		||||
      [ "\b" ] = "b",
 | 
			
		||||
      [ "\f" ] = "f",
 | 
			
		||||
      [ "\n" ] = "n",
 | 
			
		||||
      [ "\r" ] = "r",
 | 
			
		||||
      [ "\t" ] = "t",
 | 
			
		||||
    }
 | 
			
		||||
    local escape_char_map_inv = { [ "/" ] = "/" }
 | 
			
		||||
    for k, v in pairs(escape_char_map) do
 | 
			
		||||
      escape_char_map_inv[v] = k
 | 
			
		||||
    end
 | 
			
		||||
    local function escape_char(c)
 | 
			
		||||
      return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
 | 
			
		||||
    end
 | 
			
		||||
    local function encode_nil(val)
 | 
			
		||||
      return "null"
 | 
			
		||||
    end
 | 
			
		||||
    local function encode_table(val, stack)
 | 
			
		||||
      local res = {}
 | 
			
		||||
      stack = stack or {}
 | 
			
		||||
      if stack[val] then error("circular reference") end
 | 
			
		||||
      stack[val] = true
 | 
			
		||||
      if rawget(val, 1) ~= nil or next(val) == nil then
 | 
			
		||||
        local n = 0
 | 
			
		||||
        for k in pairs(val) do
 | 
			
		||||
          if type(k) ~= "number" then
 | 
			
		||||
            error("invalid table: mixed or invalid key types")
 | 
			
		||||
          end
 | 
			
		||||
          n = n + 1
 | 
			
		||||
        end
 | 
			
		||||
        if n ~= #val then
 | 
			
		||||
          error("invalid table: sparse array")
 | 
			
		||||
        end
 | 
			
		||||
        for i, v in ipairs(val) do
 | 
			
		||||
          table.insert(res, encode(v, stack))
 | 
			
		||||
        end
 | 
			
		||||
        stack[val] = nil
 | 
			
		||||
        return "[" .. table.concat(res, ",") .. "]"
 | 
			
		||||
      else
 | 
			
		||||
        for k, v in pairs(val) do
 | 
			
		||||
          if type(k) ~= "string" then
 | 
			
		||||
            error("invalid table: mixed or invalid key types")
 | 
			
		||||
          end
 | 
			
		||||
          table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
 | 
			
		||||
        end
 | 
			
		||||
        stack[val] = nil
 | 
			
		||||
        return "{" .. table.concat(res, ",") .. "}"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    local function encode_string(val)
 | 
			
		||||
      return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
 | 
			
		||||
    end
 | 
			
		||||
    local function encode_number(val)
 | 
			
		||||
      if val ~= val or val <= -math.huge or val >= math.huge then
 | 
			
		||||
        error("unexpected number value '" .. tostring(val) .. "'")
 | 
			
		||||
      end
 | 
			
		||||
      return string.format("%.14g", val)
 | 
			
		||||
    end
 | 
			
		||||
    local type_func_map = {
 | 
			
		||||
      [ "nil"     ] = encode_nil,
 | 
			
		||||
      [ "table"   ] = encode_table,
 | 
			
		||||
      [ "string"  ] = encode_string,
 | 
			
		||||
      [ "number"  ] = encode_number,
 | 
			
		||||
      [ "boolean" ] = tostring,
 | 
			
		||||
    }
 | 
			
		||||
    encode = function(val, stack)
 | 
			
		||||
      local t = type(val)
 | 
			
		||||
      local f = type_func_map[t]
 | 
			
		||||
      if f then
 | 
			
		||||
        return f(val, stack)
 | 
			
		||||
      end
 | 
			
		||||
      error("unexpected type '" .. t .. "'")
 | 
			
		||||
    end
 | 
			
		||||
    function json.encode(val)
 | 
			
		||||
      return ( encode(val) )
 | 
			
		||||
    end
 | 
			
		||||
    local parse
 | 
			
		||||
    local function create_set(...)
 | 
			
		||||
      local res = {}
 | 
			
		||||
      for i = 1, select("#", ...) do
 | 
			
		||||
        res[ select(i, ...) ] = true
 | 
			
		||||
      end
 | 
			
		||||
      return res
 | 
			
		||||
    end
 | 
			
		||||
    local space_chars   = create_set(" ", "\t", "\r", "\n")
 | 
			
		||||
    local delim_chars   = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
 | 
			
		||||
    local escape_chars  = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
 | 
			
		||||
    local literals      = create_set("true", "false", "null")
 | 
			
		||||
    local literal_map = {
 | 
			
		||||
      [ "true"  ] = true,
 | 
			
		||||
      [ "false" ] = false,
 | 
			
		||||
      [ "null"  ] = nil,
 | 
			
		||||
    }
 | 
			
		||||
    local function next_char(str, idx, set, negate)
 | 
			
		||||
      for i = idx, #str do
 | 
			
		||||
        if set[str:sub(i, i)] ~= negate then
 | 
			
		||||
          return i
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
      return #str + 1
 | 
			
		||||
    end
 | 
			
		||||
    local function decode_error(str, idx, msg)
 | 
			
		||||
      local line_count = 1
 | 
			
		||||
      local col_count = 1
 | 
			
		||||
      for i = 1, idx - 1 do
 | 
			
		||||
        col_count = col_count + 1
 | 
			
		||||
        if str:sub(i, i) == "\n" then
 | 
			
		||||
          line_count = line_count + 1
 | 
			
		||||
          col_count = 1
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
      error( string.format("%s at line %d col %d", msg, line_count, col_count) )
 | 
			
		||||
    end
 | 
			
		||||
    local function codepoint_to_utf8(n)
 | 
			
		||||
      local f = math.floor
 | 
			
		||||
      if n <= 0x7f then
 | 
			
		||||
        return string.char(n)
 | 
			
		||||
      elseif n <= 0x7ff then
 | 
			
		||||
        return string.char(f(n / 64) + 192, n % 64 + 128)
 | 
			
		||||
      elseif n <= 0xffff then
 | 
			
		||||
        return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
 | 
			
		||||
      elseif n <= 0x10ffff then
 | 
			
		||||
        return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
 | 
			
		||||
                           f(n % 4096 / 64) + 128, n % 64 + 128)
 | 
			
		||||
      end
 | 
			
		||||
      error( string.format("invalid unicode codepoint '%x'", n) )
 | 
			
		||||
    end
 | 
			
		||||
    local function parse_unicode_escape(s)
 | 
			
		||||
      local n1 = tonumber( s:sub(1, 4),  16 )
 | 
			
		||||
      local n2 = tonumber( s:sub(7, 10), 16 )
 | 
			
		||||
      if n2 then
 | 
			
		||||
        return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
 | 
			
		||||
      else
 | 
			
		||||
        return codepoint_to_utf8(n1)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    local function parse_string(str, i)
 | 
			
		||||
      local res = ""
 | 
			
		||||
      local j = i + 1
 | 
			
		||||
      local k = j
 | 
			
		||||
      while j <= #str do
 | 
			
		||||
        local x = str:byte(j)
 | 
			
		||||
        if x < 32 then
 | 
			
		||||
          decode_error(str, j, "control character in string")
 | 
			
		||||
        elseif x == 92 then -- `\`: Escape
 | 
			
		||||
          res = res .. str:sub(k, j - 1)
 | 
			
		||||
          j = j + 1
 | 
			
		||||
          local c = str:sub(j, j)
 | 
			
		||||
          if c == "u" then
 | 
			
		||||
            local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
 | 
			
		||||
                     or str:match("^%x%x%x%x", j + 1)
 | 
			
		||||
                     or decode_error(str, j - 1, "invalid unicode escape in string")
 | 
			
		||||
            res = res .. parse_unicode_escape(hex)
 | 
			
		||||
            j = j + #hex
 | 
			
		||||
          else
 | 
			
		||||
            if not escape_chars[c] then
 | 
			
		||||
              decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
 | 
			
		||||
            end
 | 
			
		||||
            res = res .. escape_char_map_inv[c]
 | 
			
		||||
          end
 | 
			
		||||
          k = j + 1
 | 
			
		||||
        elseif x == 34 then -- `"`: End of string
 | 
			
		||||
          res = res .. str:sub(k, j - 1)
 | 
			
		||||
          return res, j + 1
 | 
			
		||||
        end
 | 
			
		||||
        j = j + 1
 | 
			
		||||
      end
 | 
			
		||||
      decode_error(str, i, "expected closing quote for string")
 | 
			
		||||
    end
 | 
			
		||||
    local function parse_number(str, i)
 | 
			
		||||
      local x = next_char(str, i, delim_chars)
 | 
			
		||||
      local s = str:sub(i, x - 1)
 | 
			
		||||
      local n = tonumber(s)
 | 
			
		||||
      if not n then
 | 
			
		||||
        decode_error(str, i, "invalid number '" .. s .. "'")
 | 
			
		||||
      end
 | 
			
		||||
      return n, x
 | 
			
		||||
    end
 | 
			
		||||
    local function parse_literal(str, i)
 | 
			
		||||
      local x = next_char(str, i, delim_chars)
 | 
			
		||||
      local word = str:sub(i, x - 1)
 | 
			
		||||
      if not literals[word] then
 | 
			
		||||
        decode_error(str, i, "invalid literal '" .. word .. "'")
 | 
			
		||||
      end
 | 
			
		||||
      return literal_map[word], x
 | 
			
		||||
    end
 | 
			
		||||
    local function parse_array(str, i)
 | 
			
		||||
      local res = {}
 | 
			
		||||
      local n = 1
 | 
			
		||||
      i = i + 1
 | 
			
		||||
      while 1 do
 | 
			
		||||
        local x
 | 
			
		||||
        i = next_char(str, i, space_chars, true)
 | 
			
		||||
        if str:sub(i, i) == "]" then
 | 
			
		||||
          i = i + 1
 | 
			
		||||
          break
 | 
			
		||||
        end
 | 
			
		||||
        x, i = parse(str, i)
 | 
			
		||||
        res[n] = x
 | 
			
		||||
        n = n + 1
 | 
			
		||||
        i = next_char(str, i, space_chars, true)
 | 
			
		||||
        local chr = str:sub(i, i)
 | 
			
		||||
        i = i + 1
 | 
			
		||||
        if chr == "]" then break end
 | 
			
		||||
        if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
 | 
			
		||||
      end
 | 
			
		||||
      return res, i
 | 
			
		||||
    end
 | 
			
		||||
    local function parse_object(str, i)
 | 
			
		||||
      local res = {}
 | 
			
		||||
      i = i + 1
 | 
			
		||||
      while 1 do
 | 
			
		||||
        local key, val
 | 
			
		||||
        i = next_char(str, i, space_chars, true)
 | 
			
		||||
        if str:sub(i, i) == "}" then
 | 
			
		||||
          i = i + 1
 | 
			
		||||
          break
 | 
			
		||||
        end
 | 
			
		||||
        if str:sub(i, i) ~= '"' then
 | 
			
		||||
          decode_error(str, i, "expected string for key")
 | 
			
		||||
        end
 | 
			
		||||
        key, i = parse(str, i)
 | 
			
		||||
        i = next_char(str, i, space_chars, true)
 | 
			
		||||
        if str:sub(i, i) ~= ":" then
 | 
			
		||||
          decode_error(str, i, "expected ':' after key")
 | 
			
		||||
        end
 | 
			
		||||
        i = next_char(str, i + 1, space_chars, true)
 | 
			
		||||
        val, i = parse(str, i)
 | 
			
		||||
        res[key] = val
 | 
			
		||||
        i = next_char(str, i, space_chars, true)
 | 
			
		||||
        local chr = str:sub(i, i)
 | 
			
		||||
        i = i + 1
 | 
			
		||||
        if chr == "}" then break end
 | 
			
		||||
        if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
 | 
			
		||||
      end
 | 
			
		||||
      return res, i
 | 
			
		||||
    end
 | 
			
		||||
    local char_func_map = {
 | 
			
		||||
      [ '"' ] = parse_string,
 | 
			
		||||
      [ "0" ] = parse_number,
 | 
			
		||||
      [ "1" ] = parse_number,
 | 
			
		||||
      [ "2" ] = parse_number,
 | 
			
		||||
      [ "3" ] = parse_number,
 | 
			
		||||
      [ "4" ] = parse_number,
 | 
			
		||||
      [ "5" ] = parse_number,
 | 
			
		||||
      [ "6" ] = parse_number,
 | 
			
		||||
      [ "7" ] = parse_number,
 | 
			
		||||
      [ "8" ] = parse_number,
 | 
			
		||||
      [ "9" ] = parse_number,
 | 
			
		||||
      [ "-" ] = parse_number,
 | 
			
		||||
      [ "t" ] = parse_literal,
 | 
			
		||||
      [ "f" ] = parse_literal,
 | 
			
		||||
      [ "n" ] = parse_literal,
 | 
			
		||||
      [ "[" ] = parse_array,
 | 
			
		||||
      [ "{" ] = parse_object,
 | 
			
		||||
    }
 | 
			
		||||
    parse = function(str, idx)
 | 
			
		||||
      local chr = str:sub(idx, idx)
 | 
			
		||||
      local f = char_func_map[chr]
 | 
			
		||||
      if f then
 | 
			
		||||
        return f(str, idx)
 | 
			
		||||
      end
 | 
			
		||||
      decode_error(str, idx, "unexpected character '" .. chr .. "'")
 | 
			
		||||
    end
 | 
			
		||||
    function json.decode(str)
 | 
			
		||||
      if type(str) ~= "string" then
 | 
			
		||||
        error("expected argument of type string, got " .. type(str))
 | 
			
		||||
      end
 | 
			
		||||
      local res, idx = parse(str, next_char(str, 1, space_chars, true))
 | 
			
		||||
      idx = next_char(str, idx, space_chars, true)
 | 
			
		||||
      if idx <= #str then
 | 
			
		||||
        decode_error(str, idx, "trailing garbage")
 | 
			
		||||
      end
 | 
			
		||||
      return res
 | 
			
		||||
    end
 | 
			
		||||
    return json
 | 
			
		||||
end)
 | 
			
		||||
rawset(__BUNDLER_FILES, "updater.lua", function ()
 | 
			
		||||
    local log = require("log");
 | 
			
		||||
    local json = require("json");
 | 
			
		||||
    local _;
 | 
			
		||||
    local updater  = {};
 | 
			
		||||
    updater.__index = updater;
 | 
			
		||||
    function updater.new()
 | 
			
		||||
    	local c = setmetatable({}, updater);
 | 
			
		||||
        c.last_check = os.time();
 | 
			
		||||
        c.threshold = ((20*60)/24/60) * 5;
 | 
			
		||||
        c.api_url = "https://git.mcorangehq.xyz/api/v1/repos/xomf/keypadOS";
 | 
			
		||||
        c.curr_commit_hash = "";
 | 
			
		||||
        c.updated_files["startup.lua"] = {
 | 
			
		||||
            url = "https://git.mcorangehq.xyz/xomf/keypadOS/raw/branch/main/rtmc.lua",
 | 
			
		||||
            branch = "main"
 | 
			
		||||
        };
 | 
			
		||||
    	return c
 | 
			
		||||
    end
 | 
			
		||||
    function updater:addEntry(path, branch, url)
 | 
			
		||||
        self.updated_files[path] = {
 | 
			
		||||
            branch = branch,
 | 
			
		||||
            url = url
 | 
			
		||||
        };
 | 
			
		||||
    end
 | 
			
		||||
    function updater:checkAndUpdateAll()
 | 
			
		||||
        for path, entry in pairs(self.updated_files) do
 | 
			
		||||
            if self:check(entry.branch) then
 | 
			
		||||
                self:update(path, entry.url);
 | 
			
		||||
                os.reboot();
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    function updater:check(branch)
 | 
			
		||||
        local curr = os.time();
 | 
			
		||||
        if (math.abs(curr - self.last_check) >= self.threshold) and (self.curr_commit_hash ~= "") then
 | 
			
		||||
            self.last_check = curr;
 | 
			
		||||
            return true;
 | 
			
		||||
        end
 | 
			
		||||
        local req, rerr = http.get(self.api_url .. "/commits?sha="..branch);
 | 
			
		||||
        if not req then
 | 
			
		||||
            log.error("Updater:check: Could not send request: " .. rerr);
 | 
			
		||||
            return false;
 | 
			
		||||
        end
 | 
			
		||||
        local body, berr = req.readAll();
 | 
			
		||||
        if not req then
 | 
			
		||||
            log.error("Updater:check: Could not get body of request: " .. berr);
 | 
			
		||||
            return false;
 | 
			
		||||
        end
 | 
			
		||||
        local data = json.decode(body);
 | 
			
		||||
        if self.curr_commit_hash == "" then
 | 
			
		||||
            self.curr_commit_hash = data[1].hash;
 | 
			
		||||
        elseif data[1].hash == self.curr_commit_hash then
 | 
			
		||||
            return true;
 | 
			
		||||
        end
 | 
			
		||||
        return false;
 | 
			
		||||
    end
 | 
			
		||||
    function updater:update(path, url)
 | 
			
		||||
        local req, rerr = http.get(url .. "?x=" .. tostring(math.random(0,69420)));
 | 
			
		||||
        if not req then
 | 
			
		||||
            log.error("Updater:update: Could not send request for update: " .. rerr);
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
        local body, berr = req.readAll();
 | 
			
		||||
        if not body then
 | 
			
		||||
            log.error("Updater:update: Could not get file for update: " .. berr);
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
        if fs.exists(path .. ".bak") then
 | 
			
		||||
            fs.delete(path .. ".bak");
 | 
			
		||||
        end
 | 
			
		||||
        fs.copy(path, path..".bak");
 | 
			
		||||
        local fd = fs.open(path, "w");
 | 
			
		||||
        fd.write(body);
 | 
			
		||||
        fd.close();
 | 
			
		||||
    end
 | 
			
		||||
    function updater:notify()
 | 
			
		||||
    end
 | 
			
		||||
    return updater;
 | 
			
		||||
end)
 | 
			
		||||
require("main.lua").Main()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,28 +0,0 @@
 | 
			
		|||
local config = {
 | 
			
		||||
    correctPin = "42069",
 | 
			
		||||
    release_url = "https://git.mcorangehq.xyz/xomf/keypadOS/raw/branch/main/keypadOS.lua",
 | 
			
		||||
    basalt_url = "https://raw.githubusercontent.com/Pyroxenium/Basalt/master/docs/versions/latest.lua",
 | 
			
		||||
    ntfy_url = "https://ntfy.sh/keypadOS_alerts",
 | 
			
		||||
    config_path = "keypadOS.config.lua"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local DEFAULT_CONFIG =  "return {\n" ..
 | 
			
		||||
                        "    group=\"default\",\n" ..
 | 
			
		||||
                        "}\n"
 | 
			
		||||
 | 
			
		||||
--- @class Config
 | 
			
		||||
--- @field group string
 | 
			
		||||
 | 
			
		||||
--- Read current configs, create if doesnt exist :3
 | 
			
		||||
---@return Config
 | 
			
		||||
function config.ReadConfig()
 | 
			
		||||
    if not fs.exists(config.config_path) then
 | 
			
		||||
        local f = fs.open(config.config_path, "w")
 | 
			
		||||
        f.write(DEFAULT_CONFIG)
 | 
			
		||||
        f.close();
 | 
			
		||||
    end
 | 
			
		||||
    local cfg = require(config.config_path)
 | 
			
		||||
    return cfg
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return config
 | 
			
		||||
							
								
								
									
										388
									
								
								src/json.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								src/json.lua
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,388 @@
 | 
			
		|||
--
 | 
			
		||||
-- json.lua
 | 
			
		||||
--
 | 
			
		||||
-- Copyright (c) 2020 rxi
 | 
			
		||||
--
 | 
			
		||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
-- this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
-- the Software without restriction, including without limitation the rights to
 | 
			
		||||
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
			
		||||
-- of the Software, and to permit persons to whom the Software is furnished to do
 | 
			
		||||
-- so, subject to the following conditions:
 | 
			
		||||
--
 | 
			
		||||
-- The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
-- copies or substantial portions of the Software.
 | 
			
		||||
--
 | 
			
		||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
-- SOFTWARE.
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
local json = { _version = "0.1.2" }
 | 
			
		||||
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-- Encode
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
local encode
 | 
			
		||||
 | 
			
		||||
local escape_char_map = {
 | 
			
		||||
  [ "\\" ] = "\\",
 | 
			
		||||
  [ "\"" ] = "\"",
 | 
			
		||||
  [ "\b" ] = "b",
 | 
			
		||||
  [ "\f" ] = "f",
 | 
			
		||||
  [ "\n" ] = "n",
 | 
			
		||||
  [ "\r" ] = "r",
 | 
			
		||||
  [ "\t" ] = "t",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local escape_char_map_inv = { [ "/" ] = "/" }
 | 
			
		||||
for k, v in pairs(escape_char_map) do
 | 
			
		||||
  escape_char_map_inv[v] = k
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function escape_char(c)
 | 
			
		||||
  return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function encode_nil(val)
 | 
			
		||||
  return "null"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function encode_table(val, stack)
 | 
			
		||||
  local res = {}
 | 
			
		||||
  stack = stack or {}
 | 
			
		||||
 | 
			
		||||
  -- Circular reference?
 | 
			
		||||
  if stack[val] then error("circular reference") end
 | 
			
		||||
 | 
			
		||||
  stack[val] = true
 | 
			
		||||
 | 
			
		||||
  if rawget(val, 1) ~= nil or next(val) == nil then
 | 
			
		||||
    -- Treat as array -- check keys are valid and it is not sparse
 | 
			
		||||
    local n = 0
 | 
			
		||||
    for k in pairs(val) do
 | 
			
		||||
      if type(k) ~= "number" then
 | 
			
		||||
        error("invalid table: mixed or invalid key types")
 | 
			
		||||
      end
 | 
			
		||||
      n = n + 1
 | 
			
		||||
    end
 | 
			
		||||
    if n ~= #val then
 | 
			
		||||
      error("invalid table: sparse array")
 | 
			
		||||
    end
 | 
			
		||||
    -- Encode
 | 
			
		||||
    for i, v in ipairs(val) do
 | 
			
		||||
      table.insert(res, encode(v, stack))
 | 
			
		||||
    end
 | 
			
		||||
    stack[val] = nil
 | 
			
		||||
    return "[" .. table.concat(res, ",") .. "]"
 | 
			
		||||
 | 
			
		||||
  else
 | 
			
		||||
    -- Treat as an object
 | 
			
		||||
    for k, v in pairs(val) do
 | 
			
		||||
      if type(k) ~= "string" then
 | 
			
		||||
        error("invalid table: mixed or invalid key types")
 | 
			
		||||
      end
 | 
			
		||||
      table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
 | 
			
		||||
    end
 | 
			
		||||
    stack[val] = nil
 | 
			
		||||
    return "{" .. table.concat(res, ",") .. "}"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function encode_string(val)
 | 
			
		||||
  return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function encode_number(val)
 | 
			
		||||
  -- Check for NaN, -inf and inf
 | 
			
		||||
  if val ~= val or val <= -math.huge or val >= math.huge then
 | 
			
		||||
    error("unexpected number value '" .. tostring(val) .. "'")
 | 
			
		||||
  end
 | 
			
		||||
  return string.format("%.14g", val)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local type_func_map = {
 | 
			
		||||
  [ "nil"     ] = encode_nil,
 | 
			
		||||
  [ "table"   ] = encode_table,
 | 
			
		||||
  [ "string"  ] = encode_string,
 | 
			
		||||
  [ "number"  ] = encode_number,
 | 
			
		||||
  [ "boolean" ] = tostring,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
encode = function(val, stack)
 | 
			
		||||
  local t = type(val)
 | 
			
		||||
  local f = type_func_map[t]
 | 
			
		||||
  if f then
 | 
			
		||||
    return f(val, stack)
 | 
			
		||||
  end
 | 
			
		||||
  error("unexpected type '" .. t .. "'")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function json.encode(val)
 | 
			
		||||
  return ( encode(val) )
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
-- Decode
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
local parse
 | 
			
		||||
 | 
			
		||||
local function create_set(...)
 | 
			
		||||
  local res = {}
 | 
			
		||||
  for i = 1, select("#", ...) do
 | 
			
		||||
    res[ select(i, ...) ] = true
 | 
			
		||||
  end
 | 
			
		||||
  return res
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local space_chars   = create_set(" ", "\t", "\r", "\n")
 | 
			
		||||
local delim_chars   = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
 | 
			
		||||
local escape_chars  = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
 | 
			
		||||
local literals      = create_set("true", "false", "null")
 | 
			
		||||
 | 
			
		||||
local literal_map = {
 | 
			
		||||
  [ "true"  ] = true,
 | 
			
		||||
  [ "false" ] = false,
 | 
			
		||||
  [ "null"  ] = nil,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function next_char(str, idx, set, negate)
 | 
			
		||||
  for i = idx, #str do
 | 
			
		||||
    if set[str:sub(i, i)] ~= negate then
 | 
			
		||||
      return i
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  return #str + 1
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function decode_error(str, idx, msg)
 | 
			
		||||
  local line_count = 1
 | 
			
		||||
  local col_count = 1
 | 
			
		||||
  for i = 1, idx - 1 do
 | 
			
		||||
    col_count = col_count + 1
 | 
			
		||||
    if str:sub(i, i) == "\n" then
 | 
			
		||||
      line_count = line_count + 1
 | 
			
		||||
      col_count = 1
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  error( string.format("%s at line %d col %d", msg, line_count, col_count) )
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function codepoint_to_utf8(n)
 | 
			
		||||
  -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
 | 
			
		||||
  local f = math.floor
 | 
			
		||||
  if n <= 0x7f then
 | 
			
		||||
    return string.char(n)
 | 
			
		||||
  elseif n <= 0x7ff then
 | 
			
		||||
    return string.char(f(n / 64) + 192, n % 64 + 128)
 | 
			
		||||
  elseif n <= 0xffff then
 | 
			
		||||
    return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
 | 
			
		||||
  elseif n <= 0x10ffff then
 | 
			
		||||
    return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
 | 
			
		||||
                       f(n % 4096 / 64) + 128, n % 64 + 128)
 | 
			
		||||
  end
 | 
			
		||||
  error( string.format("invalid unicode codepoint '%x'", n) )
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function parse_unicode_escape(s)
 | 
			
		||||
  local n1 = tonumber( s:sub(1, 4),  16 )
 | 
			
		||||
  local n2 = tonumber( s:sub(7, 10), 16 )
 | 
			
		||||
   -- Surrogate pair?
 | 
			
		||||
  if n2 then
 | 
			
		||||
    return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
 | 
			
		||||
  else
 | 
			
		||||
    return codepoint_to_utf8(n1)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function parse_string(str, i)
 | 
			
		||||
  local res = ""
 | 
			
		||||
  local j = i + 1
 | 
			
		||||
  local k = j
 | 
			
		||||
 | 
			
		||||
  while j <= #str do
 | 
			
		||||
    local x = str:byte(j)
 | 
			
		||||
 | 
			
		||||
    if x < 32 then
 | 
			
		||||
      decode_error(str, j, "control character in string")
 | 
			
		||||
 | 
			
		||||
    elseif x == 92 then -- `\`: Escape
 | 
			
		||||
      res = res .. str:sub(k, j - 1)
 | 
			
		||||
      j = j + 1
 | 
			
		||||
      local c = str:sub(j, j)
 | 
			
		||||
      if c == "u" then
 | 
			
		||||
        local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
 | 
			
		||||
                 or str:match("^%x%x%x%x", j + 1)
 | 
			
		||||
                 or decode_error(str, j - 1, "invalid unicode escape in string")
 | 
			
		||||
        res = res .. parse_unicode_escape(hex)
 | 
			
		||||
        j = j + #hex
 | 
			
		||||
      else
 | 
			
		||||
        if not escape_chars[c] then
 | 
			
		||||
          decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
 | 
			
		||||
        end
 | 
			
		||||
        res = res .. escape_char_map_inv[c]
 | 
			
		||||
      end
 | 
			
		||||
      k = j + 1
 | 
			
		||||
 | 
			
		||||
    elseif x == 34 then -- `"`: End of string
 | 
			
		||||
      res = res .. str:sub(k, j - 1)
 | 
			
		||||
      return res, j + 1
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    j = j + 1
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  decode_error(str, i, "expected closing quote for string")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function parse_number(str, i)
 | 
			
		||||
  local x = next_char(str, i, delim_chars)
 | 
			
		||||
  local s = str:sub(i, x - 1)
 | 
			
		||||
  local n = tonumber(s)
 | 
			
		||||
  if not n then
 | 
			
		||||
    decode_error(str, i, "invalid number '" .. s .. "'")
 | 
			
		||||
  end
 | 
			
		||||
  return n, x
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function parse_literal(str, i)
 | 
			
		||||
  local x = next_char(str, i, delim_chars)
 | 
			
		||||
  local word = str:sub(i, x - 1)
 | 
			
		||||
  if not literals[word] then
 | 
			
		||||
    decode_error(str, i, "invalid literal '" .. word .. "'")
 | 
			
		||||
  end
 | 
			
		||||
  return literal_map[word], x
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function parse_array(str, i)
 | 
			
		||||
  local res = {}
 | 
			
		||||
  local n = 1
 | 
			
		||||
  i = i + 1
 | 
			
		||||
  while 1 do
 | 
			
		||||
    local x
 | 
			
		||||
    i = next_char(str, i, space_chars, true)
 | 
			
		||||
    -- Empty / end of array?
 | 
			
		||||
    if str:sub(i, i) == "]" then
 | 
			
		||||
      i = i + 1
 | 
			
		||||
      break
 | 
			
		||||
    end
 | 
			
		||||
    -- Read token
 | 
			
		||||
    x, i = parse(str, i)
 | 
			
		||||
    res[n] = x
 | 
			
		||||
    n = n + 1
 | 
			
		||||
    -- Next token
 | 
			
		||||
    i = next_char(str, i, space_chars, true)
 | 
			
		||||
    local chr = str:sub(i, i)
 | 
			
		||||
    i = i + 1
 | 
			
		||||
    if chr == "]" then break end
 | 
			
		||||
    if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
 | 
			
		||||
  end
 | 
			
		||||
  return res, i
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local function parse_object(str, i)
 | 
			
		||||
  local res = {}
 | 
			
		||||
  i = i + 1
 | 
			
		||||
  while 1 do
 | 
			
		||||
    local key, val
 | 
			
		||||
    i = next_char(str, i, space_chars, true)
 | 
			
		||||
    -- Empty / end of object?
 | 
			
		||||
    if str:sub(i, i) == "}" then
 | 
			
		||||
      i = i + 1
 | 
			
		||||
      break
 | 
			
		||||
    end
 | 
			
		||||
    -- Read key
 | 
			
		||||
    if str:sub(i, i) ~= '"' then
 | 
			
		||||
      decode_error(str, i, "expected string for key")
 | 
			
		||||
    end
 | 
			
		||||
    key, i = parse(str, i)
 | 
			
		||||
    -- Read ':' delimiter
 | 
			
		||||
    i = next_char(str, i, space_chars, true)
 | 
			
		||||
    if str:sub(i, i) ~= ":" then
 | 
			
		||||
      decode_error(str, i, "expected ':' after key")
 | 
			
		||||
    end
 | 
			
		||||
    i = next_char(str, i + 1, space_chars, true)
 | 
			
		||||
    -- Read value
 | 
			
		||||
    val, i = parse(str, i)
 | 
			
		||||
    -- Set
 | 
			
		||||
    res[key] = val
 | 
			
		||||
    -- Next token
 | 
			
		||||
    i = next_char(str, i, space_chars, true)
 | 
			
		||||
    local chr = str:sub(i, i)
 | 
			
		||||
    i = i + 1
 | 
			
		||||
    if chr == "}" then break end
 | 
			
		||||
    if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
 | 
			
		||||
  end
 | 
			
		||||
  return res, i
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local char_func_map = {
 | 
			
		||||
  [ '"' ] = parse_string,
 | 
			
		||||
  [ "0" ] = parse_number,
 | 
			
		||||
  [ "1" ] = parse_number,
 | 
			
		||||
  [ "2" ] = parse_number,
 | 
			
		||||
  [ "3" ] = parse_number,
 | 
			
		||||
  [ "4" ] = parse_number,
 | 
			
		||||
  [ "5" ] = parse_number,
 | 
			
		||||
  [ "6" ] = parse_number,
 | 
			
		||||
  [ "7" ] = parse_number,
 | 
			
		||||
  [ "8" ] = parse_number,
 | 
			
		||||
  [ "9" ] = parse_number,
 | 
			
		||||
  [ "-" ] = parse_number,
 | 
			
		||||
  [ "t" ] = parse_literal,
 | 
			
		||||
  [ "f" ] = parse_literal,
 | 
			
		||||
  [ "n" ] = parse_literal,
 | 
			
		||||
  [ "[" ] = parse_array,
 | 
			
		||||
  [ "{" ] = parse_object,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
parse = function(str, idx)
 | 
			
		||||
  local chr = str:sub(idx, idx)
 | 
			
		||||
  local f = char_func_map[chr]
 | 
			
		||||
  if f then
 | 
			
		||||
    return f(str, idx)
 | 
			
		||||
  end
 | 
			
		||||
  decode_error(str, idx, "unexpected character '" .. chr .. "'")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function json.decode(str)
 | 
			
		||||
  if type(str) ~= "string" then
 | 
			
		||||
    error("expected argument of type string, got " .. type(str))
 | 
			
		||||
  end
 | 
			
		||||
  local res, idx = parse(str, next_char(str, 1, space_chars, true))
 | 
			
		||||
  idx = next_char(str, idx, space_chars, true)
 | 
			
		||||
  if idx <= #str then
 | 
			
		||||
    decode_error(str, idx, "trailing garbage")
 | 
			
		||||
  end
 | 
			
		||||
  return res
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
return json
 | 
			
		||||
							
								
								
									
										17
									
								
								src/log.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/log.lua
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
local log = {};
 | 
			
		||||
log.__index = log;
 | 
			
		||||
 | 
			
		||||
function log.error(...)
 | 
			
		||||
    print("[ERROR] " .. ...);
 | 
			
		||||
end
 | 
			
		||||
function log.warn(...)
 | 
			
		||||
    print("[WARN] " .. ...);
 | 
			
		||||
end
 | 
			
		||||
function log.info(...)
 | 
			
		||||
    print("[INFO] " .. ...);
 | 
			
		||||
end
 | 
			
		||||
function log.debug(...)
 | 
			
		||||
    print("[DEBUG] " .. ...);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return log;
 | 
			
		||||
							
								
								
									
										31
									
								
								src/main.lua
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								src/main.lua
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,20 +1,23 @@
 | 
			
		|||
-- keycardOS "bootloader", has no access to basalt
 | 
			
		||||
-- intended for checking for updates, and automatically updating basalt if it is missing
 | 
			
		||||
local utils = require("utils.lua")
 | 
			
		||||
local updater = require("updater.lua")
 | 
			
		||||
local main = {}
 | 
			
		||||
local updater = require("updater");
 | 
			
		||||
 | 
			
		||||
local MODULE_PATH = "keypadOS.lua";
 | 
			
		||||
local MODULE_URL = "https://git.mcorangehq.xyz/xomf/keypadOS/raw/branch/keypad/keypadOS.lua";
 | 
			
		||||
 | 
			
		||||
KEYPADOS_VERSION = "4.0"
 | 
			
		||||
 | 
			
		||||
function main.Main()
 | 
			
		||||
    utils.MonReset(0.5)
 | 
			
		||||
    updater.GetBasalt()
 | 
			
		||||
    utils.MonPrint("keypadOS v" .. KEYPADOS_VERSION)
 | 
			
		||||
    utils.MonReset(1)
 | 
			
		||||
    require("ui.lua").InitUi()
 | 
			
		||||
--- @param upd Updater
 | 
			
		||||
local function updaterLoop(upd)
 | 
			
		||||
    while true do
 | 
			
		||||
        upd:checkAndUpdateAll();
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function _start()
 | 
			
		||||
    local upd = updater.new();
 | 
			
		||||
    upd:addEntry(MODULE_PATH, "keypad", MODULE_URL);
 | 
			
		||||
 | 
			
		||||
return main
 | 
			
		||||
    parallel.waitForAny(function() updaterLoop(upd) end, require(MODULE_PATH))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local mod = {};
 | 
			
		||||
mod.main = _start;
 | 
			
		||||
return mod;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										135
									
								
								src/ui.lua
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								src/ui.lua
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,135 +0,0 @@
 | 
			
		|||
local utils = require("utils.lua")
 | 
			
		||||
local basalt = require("basalt")
 | 
			
		||||
local config = require("config.lua")
 | 
			
		||||
local updater = require("updater.lua")
 | 
			
		||||
--- @type Monitor
 | 
			
		||||
local monitor = utils.Cast(peripheral.find("monitor"))
 | 
			
		||||
--- @type drive
 | 
			
		||||
local drive = utils.Cast(peripheral.find("drive"))
 | 
			
		||||
 | 
			
		||||
local mod = {}
 | 
			
		||||
 | 
			
		||||
--- @class Ui
 | 
			
		||||
--- @field pin string
 | 
			
		||||
--- @field main any
 | 
			
		||||
--- @field pinLabel any
 | 
			
		||||
--- @field enterButton any
 | 
			
		||||
--- @field resetEverything function
 | 
			
		||||
--- @field unlockDoor function
 | 
			
		||||
--- @field addToPin function
 | 
			
		||||
 | 
			
		||||
--- @param ui Ui
 | 
			
		||||
local function resetEverything(ui)
 | 
			
		||||
    sleep(2)
 | 
			
		||||
    ui.pin = ""
 | 
			
		||||
    ui.pinLabel:setText("")
 | 
			
		||||
    redstone.setOutput("front", false)
 | 
			
		||||
    ui.enterButton:setBackground(colors.blue)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @param ui Ui
 | 
			
		||||
local function unlockDoor(ui)
 | 
			
		||||
    if drive.isDiskPresent() then
 | 
			
		||||
        if drive.getDiskLabel() == config.correctPin then
 | 
			
		||||
            ui.pin = config.correctPin
 | 
			
		||||
            drive:ejectDisk()
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    basalt.debug("test")
 | 
			
		||||
    if ui.pin == config.correctPin then
 | 
			
		||||
        ui.enterButton:setBackground(colors.green)
 | 
			
		||||
        ui.pinLabel:setText("Welcome")
 | 
			
		||||
        redstone.setOutput("front", true)
 | 
			
		||||
 | 
			
		||||
        if drive.isDiskPresent() then
 | 
			
		||||
            if drive.getDiskLabel() == nil then
 | 
			
		||||
                drive.setDiskLabel(config.correctPin)
 | 
			
		||||
                ui.pinLabel:setText("Crd set")
 | 
			
		||||
                drive:ejectDisk()
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    else
 | 
			
		||||
        ui.pinLabel:setText("Wrong")
 | 
			
		||||
        ui.enterButton:setBackground(colors.red)
 | 
			
		||||
    end
 | 
			
		||||
    ui.main:addThread():start(function()
 | 
			
		||||
            resetEverything(ui)
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @param ui Ui
 | 
			
		||||
local function addToPin(ui, i)
 | 
			
		||||
 | 
			
		||||
    if #ui.pin >= 5 then
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    ui.pin = ui.pin .. tostring(i)
 | 
			
		||||
    ui.pinLabel:setText(ui.pin)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mod.InitUi()
 | 
			
		||||
    local ui = {
 | 
			
		||||
        pin = "",
 | 
			
		||||
        main = basalt.addMonitor(),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ui.main:setMonitor(monitor)
 | 
			
		||||
    ui.pinLabel = ui.main:addLabel()
 | 
			
		||||
        :setText("")
 | 
			
		||||
        :setFontSize(1)
 | 
			
		||||
 | 
			
		||||
    ui.enterButton = ui.main:addButton()
 | 
			
		||||
        :setText(">>>>")
 | 
			
		||||
        :setBackground(colors.blue)
 | 
			
		||||
        :setPosition(6,2)
 | 
			
		||||
        :setSize(1.5,3.2)
 | 
			
		||||
        :onClick(function()
 | 
			
		||||
            unlockDoor(ui)
 | 
			
		||||
        end)
 | 
			
		||||
 | 
			
		||||
    local btnX = 1
 | 
			
		||||
    local btnY = 2
 | 
			
		||||
 | 
			
		||||
    ui.main:addButton()
 | 
			
		||||
        :setPosition(1, 5)
 | 
			
		||||
        :setText("0")
 | 
			
		||||
        :setSize(6,1)
 | 
			
		||||
        :onClick(function()
 | 
			
		||||
            addToPin(ui, 0)
 | 
			
		||||
        end)
 | 
			
		||||
 | 
			
		||||
    for i = 1, 9 do
 | 
			
		||||
        ui.main:addButton()
 | 
			
		||||
            :setPosition(btnX, btnY)
 | 
			
		||||
            :setText(tostring(i))
 | 
			
		||||
            :setSize(2,1)
 | 
			
		||||
            :onClick(function()
 | 
			
		||||
                addToPin(ui, i)
 | 
			
		||||
            end)
 | 
			
		||||
        btnX = btnX + 2
 | 
			
		||||
        if btnX >= 6 then
 | 
			
		||||
            btnY = btnY + 1
 | 
			
		||||
            btnX = 1
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local status, err = pcall(function ()
 | 
			
		||||
        parallel.waitForAll(basalt.autoUpdate, updater.UpdateChecker)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    if not status and err ~= "Terminated" then
 | 
			
		||||
        print("Error detected: " .. err)
 | 
			
		||||
        http.post(config.ntfy_url, err, {Priority = "urgent"}) --exposed ntfy url no spam me pls
 | 
			
		||||
        sleep(5)
 | 
			
		||||
        utils.MonReset(0.5)
 | 
			
		||||
        fs.delete("basalt.lua")
 | 
			
		||||
        fs.delete("startup.lua")
 | 
			
		||||
        fs.copy("backup.lua", "startup.lua")
 | 
			
		||||
        os.reboot()
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return mod
 | 
			
		||||
							
								
								
									
										160
									
								
								src/updater.lua
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								src/updater.lua
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,87 +1,103 @@
 | 
			
		|||
local utils = require("utils.lua")
 | 
			
		||||
local config = require("config.lua")
 | 
			
		||||
local LAST_USED = os.time()
 | 
			
		||||
local log = require("log");
 | 
			
		||||
local json = require("json");
 | 
			
		||||
 | 
			
		||||
local mod = {}
 | 
			
		||||
--- @class UpdaterEntry
 | 
			
		||||
--- @field url string
 | 
			
		||||
--- @field branch string
 | 
			
		||||
local _;
 | 
			
		||||
 | 
			
		||||
-- For lsp, shouldnt ever be check for true
 | 
			
		||||
if not __UPDATE_HASH then
 | 
			
		||||
    __UPDATE_HASH = "WHATTHEFUCK";
 | 
			
		||||
--- @class Updater
 | 
			
		||||
--- @field last_check integer
 | 
			
		||||
--- @field threshold integer in hours (mc time)
 | 
			
		||||
--- @field api_url string
 | 
			
		||||
--- @field curr_commit_hash string
 | 
			
		||||
--- @field updated_files table<string, UpdaterEntry> {path: {url, branch}}
 | 
			
		||||
local updater  = {};
 | 
			
		||||
updater.__index = updater;
 | 
			
		||||
 | 
			
		||||
function updater.new()
 | 
			
		||||
	local c = setmetatable({}, updater);
 | 
			
		||||
    c.last_check = os.time();
 | 
			
		||||
    c.threshold = ((20*60)/24/60) * 5;
 | 
			
		||||
    c.api_url = "https://git.mcorangehq.xyz/api/v1/repos/xomf/keypadOS";
 | 
			
		||||
    c.curr_commit_hash = "";
 | 
			
		||||
    c.updated_files["startup.lua"] = {
 | 
			
		||||
        url = "https://git.mcorangehq.xyz/xomf/keypadOS/raw/branch/main/rtmc.lua",
 | 
			
		||||
        branch = "main"
 | 
			
		||||
    };
 | 
			
		||||
	return c
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function checkForUpdate()
 | 
			
		||||
    local current_time = os.time()
 | 
			
		||||
    local difference = math.abs(current_time - LAST_USED)
 | 
			
		||||
    -- print("INFO: Checking for update... difference: " .. tostring(difference))
 | 
			
		||||
    --its been considerable time since the keypad was interacted with
 | 
			
		||||
    --therefore it's time to force an update down the users throat (microsoft moment)
 | 
			
		||||
    if difference > .5 then
 | 
			
		||||
        print("INFO: Updating! (diff: " .. tostring(difference) .. ")")
 | 
			
		||||
        local update_code_request = http.get(config.release_url .. "?x=" .. tostring(math.random(11111111, 99999999))) -- I HATE CACHE REEEEEEEEEEEEEEEEE
 | 
			
		||||
        if update_code_request then
 | 
			
		||||
            local update_code_text = update_code_request.readAll()
 | 
			
		||||
            if update_code_text then
 | 
			
		||||
                if string.find(update_code_text, "^local __BUNDLER_FILES = {}") then
 | 
			
		||||
                    -- Make backup
 | 
			
		||||
                    if fs.exists("backup.lua") then
 | 
			
		||||
                        fs.delete("backup.lua")
 | 
			
		||||
                    end
 | 
			
		||||
                    fs.copy("startup.lua", "backup.lua")
 | 
			
		||||
function updater:addEntry(path, branch, url)
 | 
			
		||||
    self.updated_files[path] = {
 | 
			
		||||
        branch = branch,
 | 
			
		||||
        url = url
 | 
			
		||||
    };
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
                    if not string.find(update_code_text, __UPDATE_HASH) then
 | 
			
		||||
                        http.post(config.ntfy_url, "Computer #" .. tostring( os.getComputerID() ) .. " updating")
 | 
			
		||||
                        local file = fs.open("startup.lua", "w")
 | 
			
		||||
                        file.write(update_code_text)
 | 
			
		||||
                        file.close()
 | 
			
		||||
                        os.reboot()
 | 
			
		||||
                    else
 | 
			
		||||
                        print("Nothing changed, not updating.")
 | 
			
		||||
                        LAST_USED = os.time()
 | 
			
		||||
                        return
 | 
			
		||||
                    end
 | 
			
		||||
                else
 | 
			
		||||
                    print("Bad file download (core)")
 | 
			
		||||
                end
 | 
			
		||||
            else
 | 
			
		||||
                print("Bad mem read (core)")
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            print("Bad download (core)")
 | 
			
		||||
function updater:checkAndUpdateAll()
 | 
			
		||||
    for path, entry in pairs(self.updated_files) do
 | 
			
		||||
        if self:check(entry.branch) then
 | 
			
		||||
            self:update(path, entry.url);
 | 
			
		||||
            os.reboot();
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mod.UpdateChecker()
 | 
			
		||||
    while true do
 | 
			
		||||
        local status, err = pcall(checkForUpdate)
 | 
			
		||||
        if not status and err ~= "Terminated" then
 | 
			
		||||
            http.post(config.ntfy_url, err, {Priority = "urgent"}) 
 | 
			
		||||
        end
 | 
			
		||||
        sleep(1)
 | 
			
		||||
function updater:check(branch)
 | 
			
		||||
    local curr = os.time();
 | 
			
		||||
    if (math.abs(curr - self.last_check) >= self.threshold) and (self.curr_commit_hash ~= "") then
 | 
			
		||||
        self.last_check = curr;
 | 
			
		||||
        return true;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local req, rerr = http.get(self.api_url .. "/commits?sha="..branch);
 | 
			
		||||
    if not req then
 | 
			
		||||
        log.error("Updater:check: Could not send request: " .. rerr);
 | 
			
		||||
        return false;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local body, berr = req.readAll();
 | 
			
		||||
    if not req then
 | 
			
		||||
        log.error("Updater:check: Could not get body of request: " .. berr);
 | 
			
		||||
        return false;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local data = json.decode(body);
 | 
			
		||||
    if self.curr_commit_hash == "" then
 | 
			
		||||
        self.curr_commit_hash = data[1].hash;
 | 
			
		||||
    elseif data[1].hash == self.curr_commit_hash then
 | 
			
		||||
        return true;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mod.GetBasalt()
 | 
			
		||||
    if fs.exists("basalt.lua") then
 | 
			
		||||
        utils.MonPrint("Basalt found!")
 | 
			
		||||
    else
 | 
			
		||||
        utils.MonPrint("Downloading basalt...")
 | 
			
		||||
        local basalt_code = http.get(config.basalt_url).readAll()
 | 
			
		||||
        utils.MonPrint("Installing basalt...")
 | 
			
		||||
 | 
			
		||||
        local file = fs.open("basalt.lua", "w")
 | 
			
		||||
        if not file then
 | 
			
		||||
            utils.MonPrint("failed to get basalt")
 | 
			
		||||
            sleep(60)
 | 
			
		||||
            os.reboot()
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        file.write(utils.Cast(basalt_code))
 | 
			
		||||
        file.close()
 | 
			
		||||
 | 
			
		||||
        utils.MonPrint("Rebooting...")
 | 
			
		||||
        os.reboot()
 | 
			
		||||
function updater:update(path, url)
 | 
			
		||||
    local req, rerr = http.get(url .. "?x=" .. tostring(math.random(0,69420)));
 | 
			
		||||
    if not req then
 | 
			
		||||
        log.error("Updater:update: Could not send request for update: " .. rerr);
 | 
			
		||||
        return;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local body, berr = req.readAll();
 | 
			
		||||
    if not body then
 | 
			
		||||
        log.error("Updater:update: Could not get file for update: " .. berr);
 | 
			
		||||
        return;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if fs.exists(path .. ".bak") then
 | 
			
		||||
        fs.delete(path .. ".bak");
 | 
			
		||||
    end
 | 
			
		||||
    fs.copy(path, path..".bak");
 | 
			
		||||
 | 
			
		||||
    local fd = fs.open(path, "w");
 | 
			
		||||
    fd.write(body);
 | 
			
		||||
    fd.close();
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return mod
 | 
			
		||||
function updater:notify()
 | 
			
		||||
    -- http.post(config.ntfy_url, "Computer #" .. tostring( os.getComputerID() ) .. " updating")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return updater;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,26 +0,0 @@
 | 
			
		|||
local utils = {}
 | 
			
		||||
 | 
			
		||||
-- Type coersion for lsp
 | 
			
		||||
---@generic T
 | 
			
		||||
---@param object any
 | 
			
		||||
---@return T
 | 
			
		||||
function utils.Cast(object)
 | 
			
		||||
    return object
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- @type Monitor
 | 
			
		||||
local MONITOR = utils.Cast(peripheral.find("monitor"))
 | 
			
		||||
local MONITOR_Y = 1
 | 
			
		||||
function utils.MonPrint(text)
 | 
			
		||||
    MONITOR.setCursorPos(1,MONITOR_Y)
 | 
			
		||||
    MONITOR.write(text)
 | 
			
		||||
    MONITOR_Y = MONITOR_Y + 1
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function utils.MonReset(scale)
 | 
			
		||||
    MONITOR.clear()
 | 
			
		||||
    MONITOR.setTextScale(scale)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return utils;
 | 
			
		||||
							
								
								
									
										27
									
								
								x.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								x.py
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,12 +1,11 @@
 | 
			
		|||
#!/usr/bin/python
 | 
			
		||||
import hashlib
 | 
			
		||||
OUTPUT="keypadOS.lua";
 | 
			
		||||
OUTPUT="rtmc.lua";
 | 
			
		||||
FILES= [
 | 
			
		||||
    "updater.lua",
 | 
			
		||||
    "config.lua",
 | 
			
		||||
    "ui.lua",
 | 
			
		||||
    "utils.lua",
 | 
			
		||||
    "main.lua",
 | 
			
		||||
    "log.lua",
 | 
			
		||||
    "json.lua",
 | 
			
		||||
    "updater.lua"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
MINIMISE=True
 | 
			
		||||
| 
						 | 
				
			
			@ -34,11 +33,11 @@ def minimise(buf: str) -> str:
 | 
			
		|||
        newbuf += line + "\n";
 | 
			
		||||
    return newbuf;
 | 
			
		||||
 | 
			
		||||
def get_hash(buf: str) -> str:
 | 
			
		||||
    hasher = hashlib.sha1();
 | 
			
		||||
 | 
			
		||||
    hasher.update(bytes(buf, "utf-8"));
 | 
			
		||||
    return hasher.hexdigest();
 | 
			
		||||
# def get_hash(buf: str) -> str:
 | 
			
		||||
#    hasher = hashlib.sha1();
 | 
			
		||||
#
 | 
			
		||||
#    hasher.update(bytes(buf, "utf-8"));
 | 
			
		||||
#    return hasher.hexdigest();
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    buf = ""
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +50,7 @@ def main():
 | 
			
		|||
    buf += "        return __DEFAULT_IMPORT(path)\n";
 | 
			
		||||
    buf += "    end\n";
 | 
			
		||||
    buf += "end\n";
 | 
			
		||||
    buf += "local __UPDATE_HASH = __BUNDLER_REPLACE_HASH__\n";
 | 
			
		||||
    # buf += "local __UPDATE_HASH = __BUNDLER_REPLACE_HASH__\n";
 | 
			
		||||
    for file in FILES:
 | 
			
		||||
        print(f"=== FILE: {file}");
 | 
			
		||||
        buf += read_file(file);
 | 
			
		||||
| 
						 | 
				
			
			@ -60,10 +59,10 @@ def main():
 | 
			
		|||
 | 
			
		||||
    if MINIMISE:
 | 
			
		||||
        buf = minimise(buf);
 | 
			
		||||
    update_hash = get_hash(buf);
 | 
			
		||||
    buf = buf.replace("__BUNDLER_REPLACE_HASH__", f"\"{update_hash}\"");
 | 
			
		||||
    #update_hash = get_hash(buf);
 | 
			
		||||
    # buf = buf.replace("__BUNDLER_REPLACE_HASH__", f"\"{update_hash}\"");
 | 
			
		||||
 | 
			
		||||
    print(f"=== UPDATE HASH: {update_hash}")
 | 
			
		||||
    #print(f"=== UPDATE HASH: {update_hash}")
 | 
			
		||||
    with open(OUTPUT, "w", encoding="utf-8") as f:
 | 
			
		||||
        f.write(buf);
 | 
			
		||||
    print("DONE");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user