Newer
Older
Kristify / src / init.lua
-- make a copy of package.path
local sSrc = fs.getDir(shell.getRunningProgram())
local sRoot = fs.combine(sSrc, "..")
local sData = fs.combine(sRoot, "data")
local sPage = fs.combine(sData, "pages")

local ctx

local nErrors = 0
local function init(...)
    -- [Context]
    ctx = { products = {}, theme = {}, config = {}, pages = {} }
    ctx.path = {
        page = sPage,
        src = sSrc,
        data = sData
    }

    -- Logger
    ctx.logger = require("logger"):new({ debugging = settings.get("kristify.debug"),
        log2file = settings.get("kristify.log2file") })


    -- [Pages]
    local pages = fs.list(sPage)
    for i = 1, #pages do
        local f = fs.open(fs.combine(sPage, pages[i]), 'r')
        ctx.pages[pages[i]] = f.readAll()
        f.close()
    end

    -- [Data] (config,theme,products, etc.)
    local function loadStr(str, begin, env)
        if not begin then begin = "" end
        local success, result = pcall(loadstring(begin .. str, "t", env))
        if success and type(result) == "table" then
            return result
        end
        return false
    end

    local function loadLuaFile(path, env)
        if fs.exists(path) and not fs.isDir(path) then
            local f = fs.open(path, 'r')
            local c = f.readAll()
            f.close()
            local result = loadStr(c, "", env)
            if not result then
                ctx.logger:error("Could not load \'" .. path .. "\' properly!\n" .. tostring(result))
                sleep(1)
            end
            return result
        else
            ctx.logger:error("Could not load \'" .. path .. "\'!")
            sleep(0.5)
        end
        return false
    end

    -- theme
    local col = { white = 0x1, orange = 0x2, magenta = 0x4, lightBlue = 0x8, yellow = 0x10, lime = 0x20, pink = 0x40,
        grey = 0x80, lightGrey = 0x100, cyan = 0x200, purple = 0x400, blue = 0x800, brown = 0x1000, green = 0x2000,
        red = 0x4000, black = 0x8000 }
    local inferiorcol = col;
    inferiorcol.gray = col.grey;
    inferiorcol.lightGray = col.lightGrey
    local result = loadLuaFile(fs.combine(sPage, "theme.lua"), { colours = col, colors = inferiorcol })
    if result then
        ctx.theme = result
    end
    -- config
    result = loadLuaFile(fs.combine(sData, "config.lua"))
    if result then
        ctx.config = result
    end
    -- products
    result = loadLuaFile(fs.combine(sData, "products.lua"))
    if result then
        ctx.products = result
    end

    -- Set debug mode
    settings.define("kristify.debug", {
        description = "If kristify should be debugging",
        default = false,
        type = "boolean"
    })

    settings.define("kristify.log2file", {
        description = "If kristify should log to a file",
        default = false,
        type = "boolean"
    })

    -- Load Basalt
    local basalt = {}
    if not fs.exists(fs.combine(ctx.path.src, "lib", "basalt")) then
        local authenticate = _G._GIT_API_KEY and { Authorization = "Bearer " .. _G._GIT_API_KEY }
        local basaltDL, err, errCode = http.get("https://raw.githubusercontent.com/Kristify/kristify/main/src/libs/basalt.lua"
            , authenticate)
        if not basaltDL then
            ctx.logger:error("Couldn't load Basalt into memory! Reason: \'" ..
                err .. "\' (code " .. errCode.getResponseCode() .. ')')
            return
        end

        basalt = load(basaltDL.readAll())()
        basaltDL.close()
    else
        basalt = require("basalt")
    end
    ctx.basalt = basalt

    -- Load scripts
    ctx.kristly = require(fs.combine("libs", "kristly"))
    ctx.utils = require("utils")
    ctx.webhooks = require("webhook")

    -- Check errors
    local function bAssert(condition, errormsg)
      if condition then
        ctx.logger:error(errormsg)
        nErrors = nErrors+1
        return false
      end
      return true
    end
    
    local function configExpect(name, typ)
        local curTyp = type(ctx.config[name])
        if curTyp ~= typ then
            ctx.logger:error("Bad value for \'"..name.."\' in config; Expected \'"..typ.."\', got \'"..curTyp.."\'.")
            nErrors = nErrors+1
            return false
        elseif curTyp == "string" and ctx.config[name] == "" then
            ctx.logger:warn("Value \'"..name.."\' in config should not be empty.")

        end
        return true
    end
    
    configExpect("pkey", "string")
    if configExpect("name", "string") then
        bAssert(ctx.utils.endsWith(ctx.config.name or "", ".kst"), "Remove \'.kst\' from the name.")
    end
    configExpect("webhooks", "table")
    configExpect("sounds", "table")

    local modem = peripheral.find("modem")
    if not modem then
       ctx.logger:error("Kristify is not connected to a network! (aka. wired modem)")
    elseif type(ctx.config.self) == "string" and modem.getNameLocal() ~= (ctx.config.self or "") then
        ctx.logger:error("Given turtle in config does not exist!")
    else configExpect("self", "string")
    end

    if configExpect("storage", "table") then
        bAssert(#ctx.config.storage==0 or ctx.config.storage[1] == "", "Storage table in config is empty or invalid!")
        for _,inv in pairs(ctx.config.storage) do
            if not peripheral.wrap(inv) then
                ctx.logger:error("Inventory \'"..inv.."\' does not exist!")
                nErrors = nErrors+1
            end
        end
    end
    if configExpect("monSide", "string") then
      bAssert(not peripheral.wrap(ctx.config.monSide), "Given monitor side does not exist!")
    end
    

    -- Load libs, related to peripherals
    ctx.speakerLib = require("speaker")
    ctx.speakerLib.config = ctx.config

    ctx.logger.debug("Loading in inv lib")
    ctx.logger.debug("Configured storage: " .. textutils.serialize(ctx.config.storage))
    ctx.storage = require(fs.combine("libs", "inv"))(ctx.config.storage or {})

    return ctx
end

-- INIT
term.clear()
term.setCursorPos(1, 1)
local args = table.pack(...)
xpcall(function()
    init(table.unpack(args, 1, args.n))
end, function(err)
    ctx.logger:error(err)
end)

-- MAIN
local function execFile(sPath)
    local script, err = loadfile(sPath, "t", _ENV)
    if not script then
        ctx.logger:error(err)
        nErrors = nErrors+1
        return
    end
    local result,output = pcall(script, ctx)
    if not result then
        if output == "terminated" then
            -- Close websockets
            return
        end
        ctx.logger:error(output)
        nErrors = nErrors+1
    end
end

if nErrors == 0 then
    parallel.waitForAny(
        function()
            execFile(fs.combine(sSrc, "backend.lua"))
        end,
        function()
            execFile(fs.combine(sSrc, "frontend.lua"))
        end
    )
end

if nErrors > 0 then
    ctx.logger:warn("\'"..nErrors.."\' error(s). Press any key to exit.")
    sleep(0.5)
    os.pullEvent("key")
end