finished http implementation working on spm and liveboot env
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1,7 @@
|
||||
local http=require("http")
|
||||
local ok,err = xpcall(http.get, debug.traceback, "http://localhost:8000/spm.json")
|
||||
if not ok then
|
||||
print(err)
|
||||
else
|
||||
print(err.body)
|
||||
end
|
||||
@@ -26,8 +26,7 @@ local function parseUrl(url)
|
||||
end
|
||||
|
||||
local function buildRequest(req)
|
||||
local host, path =
|
||||
parseUrl(req.url)
|
||||
local host, path = parseUrl(req.url)
|
||||
|
||||
if not host then
|
||||
return nil, path
|
||||
@@ -75,73 +74,39 @@ local function buildRequest(req)
|
||||
return table.concat(out, "\r\n")
|
||||
end
|
||||
|
||||
local function parseResponse(raw)
|
||||
local headerEnd =
|
||||
raw:find(
|
||||
"\r\n\r\n",
|
||||
1,
|
||||
true
|
||||
)
|
||||
|
||||
if not headerEnd then
|
||||
return nil, "EBADMSG"
|
||||
local function parseResponse(response)
|
||||
local headerBlock, body = response:match("^(.-)\r\n\r\n(.*)$")
|
||||
if not headerBlock then
|
||||
return nil, "invalid HTTP response"
|
||||
end
|
||||
|
||||
local headerPart =
|
||||
raw:sub(1, headerEnd - 1)
|
||||
|
||||
local body =
|
||||
raw:sub(headerEnd + 4)
|
||||
|
||||
local lines = {}
|
||||
|
||||
for line in headerPart:gmatch("[^\r\n]+") do
|
||||
lines[#lines + 1] = line
|
||||
end
|
||||
|
||||
local _, code, msg =
|
||||
lines[1]:match(
|
||||
"^(HTTP/%S+)%s+(%d+)%s*(.*)$"
|
||||
)
|
||||
|
||||
local headers = {}
|
||||
|
||||
for i = 2, #lines do
|
||||
local k, v =
|
||||
lines[i]:match(
|
||||
"^([^:]+):%s*(.*)$"
|
||||
)
|
||||
-- Parse status line
|
||||
local statusLine, rest = headerBlock:match("^(.-)\r\n(.*)$")
|
||||
if not statusLine then
|
||||
statusLine = headerBlock
|
||||
rest = ""
|
||||
end
|
||||
|
||||
if k then
|
||||
headers[k:lower()] = v
|
||||
local version, code, message = statusLine:match("^(HTTP/%d+%.%d+)%s+(%d+)%s+(.*)$")
|
||||
|
||||
-- Parse headers
|
||||
for line in (rest .. "\r\n"):gmatch("(.-)\r\n") do
|
||||
local key, value = line:match("^([^:]+):%s*(.*)$")
|
||||
if key then
|
||||
headers[key:lower()] = value
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
code = tonumber(code),
|
||||
message = msg,
|
||||
headers = headers,
|
||||
body = body
|
||||
code=tonumber(code),
|
||||
message=message,
|
||||
headers=headers,
|
||||
body=body
|
||||
}
|
||||
end
|
||||
|
||||
local function readAll(fd)
|
||||
local out = ""
|
||||
|
||||
while true do
|
||||
local chunk =
|
||||
syscall.read(fd, 4096)
|
||||
|
||||
if not chunk or chunk == "" then
|
||||
break
|
||||
end
|
||||
|
||||
out = out .. chunk
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
function http.request(req)
|
||||
local raw, err =
|
||||
buildRequest(req)
|
||||
@@ -151,34 +116,50 @@ function http.request(req)
|
||||
end
|
||||
|
||||
local fd =
|
||||
syscall.socket(0, 0)
|
||||
syscall.socket()
|
||||
|
||||
if not fd then
|
||||
return nil, "ESOCKET"
|
||||
end
|
||||
|
||||
local ok, err =
|
||||
syscall.connect(fd, req.url)
|
||||
local host, path = parseUrl(req.url)
|
||||
|
||||
if not host then
|
||||
syscall.close(fd)
|
||||
return nil, path
|
||||
end
|
||||
|
||||
local proto = req.url:match("^(https?://)")
|
||||
|
||||
local base = proto .. host
|
||||
|
||||
local ok, err = syscall.connect(fd, base)
|
||||
|
||||
if not ok then
|
||||
syscall.close(fd)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local ok2, err2 =
|
||||
syscall.write(fd, raw)
|
||||
local ok2, err2 = syscall.write(fd, raw)
|
||||
|
||||
if not ok2 then
|
||||
syscall.close(fd)
|
||||
return nil, err2
|
||||
end
|
||||
|
||||
local resp =
|
||||
readAll(fd)
|
||||
local out = {}
|
||||
|
||||
while true do
|
||||
local chunk = syscall.read(fd, 4096)
|
||||
if chunk == "" then
|
||||
break
|
||||
end
|
||||
|
||||
out[#out+1] = chunk
|
||||
end
|
||||
|
||||
syscall.close(fd)
|
||||
|
||||
return parseResponse(resp)
|
||||
return parseResponse(table.concat(out))
|
||||
end
|
||||
|
||||
function http.get(url, headers)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Core library for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,3 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
GHXX (Advanced Computers)
|
||||
@@ -0,0 +1 @@
|
||||
firmware for Advanced Computers
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1 @@
|
||||
firmware for CraftOS PC
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -9,25 +9,15 @@ kernel.cct.httpqueue = kernel.cct.httpqueue or {}
|
||||
kernel.cct.httpresponse = kernel.cct.httpresponse or {}
|
||||
kernel.cct.httperror = kernel.cct.httperror or {}
|
||||
|
||||
local function parseRawRequest(raw)
|
||||
local sepLen = 4
|
||||
|
||||
local headerEnd =
|
||||
raw:find("\r\n\r\n", 1, true)
|
||||
|
||||
if not headerEnd then
|
||||
headerEnd =
|
||||
raw:find("\n\n", 1, true)
|
||||
|
||||
sepLen = 2
|
||||
end
|
||||
local function parseRawRequest(raw, address)
|
||||
local headerEnd = raw:find("\r\n\r\n", 1, true)
|
||||
|
||||
local headerPart
|
||||
local body = ""
|
||||
|
||||
if headerEnd then
|
||||
headerPart = raw:sub(1, headerEnd - 1)
|
||||
body = raw:sub(headerEnd + sepLen)
|
||||
body = raw:sub(headerEnd + 4)
|
||||
else
|
||||
headerPart = raw
|
||||
end
|
||||
@@ -42,37 +32,25 @@ local function parseRawRequest(raw)
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
|
||||
local method, path =
|
||||
lines[1]:match("^(%S+)%s+(%S+)")
|
||||
|
||||
if not method or not path then
|
||||
return nil, "EBADMSG"
|
||||
local split=string.split(lines[1], " ")
|
||||
if #split~=3 then
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
local method, path, ver = table.unpack(split)
|
||||
|
||||
local headers = {}
|
||||
|
||||
for i = 2, #lines do
|
||||
local k, v =
|
||||
lines[i]:match("^([^:]+):%s*(.*)$")
|
||||
|
||||
local k, v = lines[i]:match("^([^:]+):%s*(.*)$")
|
||||
if k then
|
||||
headers[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
local host = headers.Host or headers.host
|
||||
|
||||
if not host and not path:match("^https?://") then
|
||||
return nil, "EHOSTUNREACH"
|
||||
end
|
||||
|
||||
local url
|
||||
|
||||
if path:match("^https?://") then
|
||||
url = path
|
||||
else
|
||||
url = "http://" .. host .. path
|
||||
if path:sub(1,1)~="/" then
|
||||
return nil, "EINVAL"
|
||||
end
|
||||
local url = address..path
|
||||
|
||||
local req = {
|
||||
url = url,
|
||||
@@ -84,7 +62,7 @@ local function parseRawRequest(raw)
|
||||
req.body = body
|
||||
end
|
||||
|
||||
return req
|
||||
return req, url
|
||||
end
|
||||
|
||||
local function buildResponse(resp)
|
||||
@@ -93,37 +71,19 @@ local function buildResponse(resp)
|
||||
end
|
||||
|
||||
local code, msg = resp.getResponseCode()
|
||||
|
||||
local headers =
|
||||
resp:getResponseHeaders()
|
||||
|
||||
local body =
|
||||
resp:readAll() or ""
|
||||
local headers = resp.getResponseHeaders()
|
||||
local body = resp.readAll() or ""
|
||||
resp.close()
|
||||
|
||||
local out = {
|
||||
"HTTP/1.1 " ..
|
||||
tostring(code) ..
|
||||
" " ..
|
||||
tostring(msg)
|
||||
tostring(msg or "")
|
||||
}
|
||||
|
||||
local hasLength = false
|
||||
|
||||
for k, v in pairs(headers or {}) do
|
||||
if k:lower() == "content-length" then
|
||||
hasLength = true
|
||||
end
|
||||
|
||||
out[#out + 1] =
|
||||
tostring(k) ..
|
||||
": " ..
|
||||
tostring(v)
|
||||
end
|
||||
|
||||
if not hasLength then
|
||||
out[#out + 1] =
|
||||
"Content-Length: " ..
|
||||
tostring(#body)
|
||||
for i,v in pairs(headers) do
|
||||
out[#out+1] = i..": "..v
|
||||
end
|
||||
|
||||
out[#out + 1] = ""
|
||||
@@ -139,155 +99,91 @@ function handler.connect(fd, address)
|
||||
return nil, "EBADF"
|
||||
end
|
||||
|
||||
fdo.socket.rbuf = ""
|
||||
fdo.socket.closed = false
|
||||
fdo.socket.httpid = nil
|
||||
|
||||
fdo.handle.write = function(raw)
|
||||
local req, err =
|
||||
parseRawRequest(raw)
|
||||
local req, url = parseRawRequest(raw, address)
|
||||
|
||||
if not req then
|
||||
return nil, err
|
||||
return nil, url
|
||||
end
|
||||
|
||||
local id =
|
||||
tostring(kernel.uuid())
|
||||
|
||||
fdo.socket.httpid = id
|
||||
|
||||
kernel.cct.httpqueue[id] = true
|
||||
|
||||
local ok, err =
|
||||
http.request(req, id)
|
||||
kernel.cct.httpqueue[url] = true
|
||||
local ok, err = http.request(req)
|
||||
|
||||
if not ok then
|
||||
kernel.cct.httpqueue[id] = nil
|
||||
kernel.cct.httpqueue[url] = nil
|
||||
return nil, err
|
||||
end
|
||||
if fdo.socket.active then
|
||||
fdo.socket.content=nil
|
||||
fdo.socket.file.close()
|
||||
fdo.socket.file=nil
|
||||
end
|
||||
fdo.socket.active=true
|
||||
fdo.socket.url=url
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
fdo.handle.read = function(count)
|
||||
count = count or 4096
|
||||
|
||||
local sock = fdo.socket
|
||||
|
||||
if #sock.rbuf > 0 then
|
||||
local out =
|
||||
sock.rbuf:sub(1, count)
|
||||
|
||||
sock.rbuf =
|
||||
sock.rbuf:sub(count + 1)
|
||||
|
||||
return out
|
||||
if not fdo.socket.active then
|
||||
return
|
||||
end
|
||||
|
||||
local id = sock.httpid
|
||||
|
||||
if not id then
|
||||
return ""
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
end
|
||||
|
||||
local function finish(resp)
|
||||
sock.rbuf =
|
||||
buildResponse(resp) or ""
|
||||
|
||||
local out =
|
||||
sock.rbuf:sub(1, count)
|
||||
|
||||
sock.rbuf =
|
||||
sock.rbuf:sub(count + 1)
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
if kernel.cct.httpresponse[id] then
|
||||
local resp =
|
||||
kernel.cct.httpresponse[id]
|
||||
|
||||
kernel.cct.httpresponse[id] = nil
|
||||
kernel.cct.httpqueue[id] = nil
|
||||
|
||||
return finish(resp)
|
||||
end
|
||||
|
||||
if kernel.cct.httperror[id] then
|
||||
local err =
|
||||
kernel.cct.httperror[id]
|
||||
|
||||
kernel.cct.httperror[id] = nil
|
||||
kernel.cct.httpqueue[id] = nil
|
||||
|
||||
return nil, err
|
||||
end
|
||||
|
||||
kernel.currentTask.status = "D"
|
||||
|
||||
local coro
|
||||
|
||||
coro = function()
|
||||
if kernel.cct.httpresponse[id] then
|
||||
local resp =
|
||||
kernel.cct.httpresponse[id]
|
||||
|
||||
kernel.cct.httpresponse[id] = nil
|
||||
kernel.cct.httpqueue[id] = nil
|
||||
|
||||
kernel.asyncReturn(
|
||||
finish(resp)
|
||||
)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if kernel.cct.httperror[id] then
|
||||
local err =
|
||||
kernel.cct.httperror[id]
|
||||
|
||||
kernel.cct.httperror[id] = nil
|
||||
kernel.cct.httpqueue[id] = nil
|
||||
|
||||
kernel.asyncReturn(
|
||||
nil,
|
||||
err
|
||||
)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
kernel.currentTask.ksh =
|
||||
coroutine.create(function()
|
||||
local ok, err =
|
||||
xpcall(
|
||||
coro,
|
||||
debug.traceback
|
||||
)
|
||||
|
||||
if not ok then
|
||||
kernel.asyncReturn(
|
||||
nil,
|
||||
err
|
||||
)
|
||||
if not fdo.socket.file then
|
||||
kernel.currentTask.io=function()
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
return fdo.socket.file.read(count)
|
||||
end
|
||||
end)
|
||||
end
|
||||
kernel.currentTask.status="D"
|
||||
return
|
||||
else
|
||||
return fdo.socket.file.read(count)
|
||||
end
|
||||
end
|
||||
|
||||
fdo.handle.seek = function(whence, offset)
|
||||
if not fdo.socket.active then
|
||||
return
|
||||
end
|
||||
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
end
|
||||
|
||||
if not fdo.socket.file then
|
||||
kernel.currentTask.io=function()
|
||||
if not kernel.cct.httpqueue[fdo.socket.url] then
|
||||
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
||||
kernel.cct.httpqueue[fdo.socket.url]=nil
|
||||
kernel.cct.httpresponse[fdo.socket.url]=nil
|
||||
return fdo.socket.file.seek(whence, offset)
|
||||
end
|
||||
end
|
||||
kernel.currentTask.status="D"
|
||||
return
|
||||
else
|
||||
return fdo.socket.file.seek(whence, offset)
|
||||
end
|
||||
end
|
||||
|
||||
fdo.handle.close = function()
|
||||
fdo.socket.closed = true
|
||||
|
||||
local id =
|
||||
fdo.socket.httpid
|
||||
|
||||
if id then
|
||||
kernel.cct.httpqueue[id] = nil
|
||||
kernel.cct.httpresponse[id] = nil
|
||||
kernel.cct.httperror[id] = nil
|
||||
end
|
||||
fdo.socket.file.close()
|
||||
fdo.socket.active=false
|
||||
kernel.cct.httpqueue[fdo.socket.url] = nil
|
||||
kernel.cct.httpresponse[fdo.socket.url] = nil
|
||||
kernel.cct.httperror[fdo.socket.url] = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -74,11 +74,16 @@ kernel.processes.cctdeamon = function()
|
||||
kernel.cct.fifo.push("[nT")
|
||||
end
|
||||
elseif eventType == "http_success" then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httpresponse[event[2]]=event[3]
|
||||
if kernel.cct.httpqueue[event[2]] then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httpresponse[event[2]]=event[3]
|
||||
end
|
||||
elseif eventType == "http_failure" then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httperror[event[2]]=event[3]
|
||||
if kernel.cct.httpqueue[event[2]] then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httperror[event[2]]=event[3]
|
||||
kernel.cct.httpresponse[event[2]]=event[4]
|
||||
end
|
||||
end
|
||||
|
||||
timeout = false
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
firmware for ComputerCraft Tweaked
|
||||
@@ -0,0 +1 @@
|
||||
1.3.0
|
||||
@@ -0,0 +1 @@
|
||||
Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
firmware for Opencomputers
|
||||
@@ -0,0 +1 @@
|
||||
0.1.0
|
||||
@@ -0,0 +1,3 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
Spsf
|
||||
@@ -193,6 +193,100 @@ function kernel.newUUID()
|
||||
return uuid
|
||||
end
|
||||
|
||||
function kernel.sfile(str, writeable)
|
||||
local buf = {str or ""}
|
||||
local pos = 1
|
||||
local closed = false
|
||||
|
||||
local function content()
|
||||
return table.concat(buf)
|
||||
end
|
||||
|
||||
local function set_content(s)
|
||||
buf = {s}
|
||||
end
|
||||
|
||||
local function flush()
|
||||
str=content()
|
||||
end
|
||||
|
||||
local file = {}
|
||||
|
||||
function file.read(n)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
if not n then
|
||||
local out = s:sub(pos)
|
||||
pos = len + 1
|
||||
return out
|
||||
end
|
||||
|
||||
local out = s:sub(pos, pos + n - 1)
|
||||
pos = pos + #out
|
||||
return out
|
||||
end
|
||||
|
||||
if writeable then
|
||||
function file.write(data)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local before = s:sub(1, pos - 1)
|
||||
local after = s:sub(pos + #data)
|
||||
|
||||
set_content(before .. data .. after)
|
||||
pos = pos + #data
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function file.seek(whence, offset)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
whence = whence or "cur"
|
||||
offset = offset or 0
|
||||
|
||||
if whence == "set" then
|
||||
pos = offset + 1
|
||||
elseif whence == "cur" then
|
||||
pos = pos + offset
|
||||
elseif whence == "end" then
|
||||
pos = len + offset + 1
|
||||
else
|
||||
error("invalid whence")
|
||||
end
|
||||
|
||||
if pos < 1 then pos = 1 end
|
||||
if pos > len + 1 then pos = len + 1 end
|
||||
|
||||
return pos - 1
|
||||
end
|
||||
|
||||
function file.close()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
closed = true
|
||||
end
|
||||
|
||||
function file.flush()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
end
|
||||
|
||||
function file.content()
|
||||
return str
|
||||
end
|
||||
|
||||
return file
|
||||
end
|
||||
|
||||
kernel.syscalls={}
|
||||
local modules={[0]={}}
|
||||
for i=0, 100 do
|
||||
@@ -297,6 +391,7 @@ kernel.syscalls["halt"]=function()
|
||||
end
|
||||
end
|
||||
|
||||
kernel.saveLog()
|
||||
kernel.log("Running modules")
|
||||
for _,p in ipairs(modules) do
|
||||
for _,v in ipairs(p) do
|
||||
@@ -310,6 +405,7 @@ for _,p in ipairs(modules) do
|
||||
local status, err = xpcall(func,debug.traceback, kernel)
|
||||
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 0x00FFFF) end
|
||||
if kernel.config.moreLogsaves then kernel.saveLog() end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -9,55 +9,39 @@ kernel.reqcache = cache
|
||||
|
||||
local function require(module, ...)
|
||||
if cache[module] then return cache[module].ret end
|
||||
kernel.currentTask.status = "D"
|
||||
local args = {...}
|
||||
kernel.currentTask.ksh = coroutine.create(function()
|
||||
local coro = function()
|
||||
for _, path in ipairs(kernel.searchpaths) do
|
||||
local filepath = path:gsub("?", module)
|
||||
if kernel.vfs.exists(filepath) then
|
||||
if kernel.vfs.type(filepath) == "directory" then
|
||||
filepath = filepath .. "/init.lua"
|
||||
if kernel.vfs.type(filepath) == "directory" then
|
||||
kernel.asyncReturn(false, "Module not found: "..module)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local fd = kernel.vfs.open(filepath, "r")
|
||||
local chunks = {}
|
||||
while true do
|
||||
local chunk = kernel.vfs.read(fd, 4096)
|
||||
if not chunk or chunk == "" then break end
|
||||
chunks[#chunks + 1] = chunk
|
||||
coroutine.yield()
|
||||
end
|
||||
kernel.vfs.close(fd)
|
||||
local data = table.concat(chunks)
|
||||
local func, err = load(data, "@"..module, "t", kernel._U)
|
||||
if not func then
|
||||
kernel.asyncReturn(false, "Error loading module "..module..": "..tostring(err))
|
||||
return
|
||||
end
|
||||
local ok, ret = xpcall(func, debug.traceback, table.unpack(args))
|
||||
if not ok then
|
||||
kernel.asyncReturn(false, "Error running module "..module..": "..tostring(ret))
|
||||
return
|
||||
end
|
||||
cache[module] = {ret = ret, expires = kernel.EFI:getEpochMs() + 120000}
|
||||
kernel.asyncReturn(true, ret)
|
||||
return
|
||||
for _, path in ipairs(kernel.searchpaths) do
|
||||
local filepath = path:gsub("?", module)
|
||||
if kernel.vfs.exists(filepath) then
|
||||
if kernel.vfs.type(filepath) == "directory" then
|
||||
filepath = filepath .. "/init.lua"
|
||||
if kernel.vfs.type(filepath) == "directory" then
|
||||
error("Module not found: "..module)
|
||||
end
|
||||
coroutine.yield()
|
||||
end
|
||||
kernel.asyncReturn(false, "Module not found: "..module)
|
||||
local fd = kernel.vfs.open(filepath, "r")
|
||||
local chunks = {}
|
||||
while true do
|
||||
local chunk = kernel.vfs.read(fd, 4096)
|
||||
if not chunk or chunk == "" then break end
|
||||
chunks[#chunks + 1] = chunk
|
||||
end
|
||||
kernel.vfs.close(fd)
|
||||
local data = table.concat(chunks)
|
||||
local func, err = load(data, "@"..module, "t", kernel._U)
|
||||
if not func then
|
||||
error("Error loading module "..module..": "..tostring(err))
|
||||
end
|
||||
local ok, ret = xpcall(func, debug.traceback, table.unpack(args))
|
||||
if not ok then
|
||||
error("Error running module "..module..": "..tostring(ret))
|
||||
end
|
||||
cache[module] = {ret = ret, expires = kernel.EFI:getEpochMs() + 120000}
|
||||
return ret
|
||||
end
|
||||
local status, err = xpcall(coro, debug.traceback)
|
||||
if not status then
|
||||
kernel.asyncReturn(false, "Error in require coroutine for module "..module..": "..tostring(err))
|
||||
end
|
||||
end)
|
||||
coroutine.yield()
|
||||
end
|
||||
error("Module not found: "..module)
|
||||
end
|
||||
|
||||
kernel.syscalls["require"] = require
|
||||
_G.require = function(...) return syscall.require(...) end
|
||||
_G.require = function(...) return require(...) end
|
||||
@@ -217,7 +217,7 @@ data[".meta"]=strFile(buildMeta({
|
||||
log="/var/log/syslog.log"
|
||||
}))
|
||||
|
||||
if kernel.EFI:getEEPROM() then
|
||||
if kernel.EFI.getEEPROM then
|
||||
function data.eeprom(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
@@ -255,7 +255,7 @@ if kernel.EFI:getEEPROM() then
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.EFI:getNvram() then
|
||||
if kernel.EFI.getNvram then
|
||||
function data.nvram(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
|
||||
@@ -22,7 +22,7 @@ local function getHandler(address)
|
||||
end
|
||||
end
|
||||
|
||||
function socket.socket(domain, socktype)
|
||||
function socket.socket()
|
||||
local fd = kernel.vfs.newfd({
|
||||
handle = {},
|
||||
|
||||
@@ -54,7 +54,7 @@ function socket.socket(domain, socktype)
|
||||
local fdo = kernel.currentTask.fd[fd]
|
||||
|
||||
fdo.handle.read = function()
|
||||
return ""
|
||||
return nil, "ENOTCONN"
|
||||
end
|
||||
|
||||
fdo.handle.write = function()
|
||||
|
||||
@@ -396,22 +396,16 @@ function kernel.main()
|
||||
end
|
||||
|
||||
if task.status == "D" then
|
||||
if task.ksh then
|
||||
coroutine.resume(task.ksh)
|
||||
if coroutine.status(task.ksh) == "dead" then
|
||||
task.ksh = nil
|
||||
if task.status == "D" then
|
||||
task.status = "R"
|
||||
end
|
||||
|
||||
if kernel.config.debugSyscalls then
|
||||
kernel.log("Task " .. task.pid .. " IO wait completed", "DBUG", 0x00FFFF)
|
||||
local sysret = task.syscallReturn
|
||||
for i = 2, #sysret do
|
||||
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
||||
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
if task.io then
|
||||
local ret = {xpcall(task.io, debug.traceback)}
|
||||
if not ret[1] then
|
||||
task.syscallReturn = {false, table.unpack(ret, 2)}
|
||||
task.status = "R"
|
||||
task.io=nil
|
||||
elseif #ret>1 then
|
||||
task.syscallReturn = {true, table.unpack(ret, 2)}
|
||||
task.status = "R"
|
||||
task.io=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,6 +25,7 @@ kernel.tasks["1"] = {
|
||||
else
|
||||
kernel.panic("Init system exited: " .. tostring(err))
|
||||
end
|
||||
kernel.saveLog()
|
||||
end),
|
||||
|
||||
name = "sysinit",
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
if not kernel.vfs.exists("/root") then kernel.vfs.mkdir("/root") end
|
||||
|
||||
kernel.processes.login = function()
|
||||
local ok, err = pcall(kernel.hpv.execspawn, "/bin/login", "login")
|
||||
if not ok then
|
||||
kernel.log("Failed to exec /bin/login: " .. tostring(err), "ERROR", 0xFF0000)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
Hyperion kernel package
|
||||
@@ -0,0 +1 @@
|
||||
1.5.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Lua
|
||||
@@ -0,0 +1 @@
|
||||
Bit32 package for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1 @@
|
||||
blake2s package for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,3 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
Spsf
|
||||
@@ -0,0 +1,169 @@
|
||||
--:Minify:--
|
||||
syscall.open("/dev/input/keyboard1", "r") --stdin (fd 0)
|
||||
syscall.open("/dev/tty/1", "w") --stdout (fd 1)
|
||||
syscall.open("/dev/null", "w") --stderr (fd 2)
|
||||
|
||||
|
||||
local MAX_ATTEMPTS = 3
|
||||
|
||||
local function readLine(mask)
|
||||
local input = ""
|
||||
while true do
|
||||
local ch = syscall.read(0)
|
||||
if not ch or ch == "" then
|
||||
elseif ch == "\n" then
|
||||
syscall.write(1, "\n")
|
||||
return input
|
||||
elseif ch == "\b" then
|
||||
if #input > 0 then
|
||||
input = input:sub(1, -2)
|
||||
syscall.write(1, "\b \b")
|
||||
end
|
||||
else
|
||||
input = input .. ch
|
||||
syscall.write(1, mask or ch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function firstBoot()
|
||||
local shadow = ""
|
||||
local _fd, _fderr = pcall(function()
|
||||
local fd = syscall.open("/etc/shadow", "r")
|
||||
shadow = syscall.read(fd, 65535) or ""
|
||||
syscall.close(fd)
|
||||
end)
|
||||
if shadow:match("%S") then return end
|
||||
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "HyperionOS First Boot Setup\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "No root password is set. Please create one now.\n\n")
|
||||
|
||||
while true do
|
||||
syscall.write(1, "New root password: ")
|
||||
local pw1 = readLine("*")
|
||||
syscall.write(1, "Confirm password: ")
|
||||
local pw2 = readLine("*")
|
||||
|
||||
if pw1 ~= pw2 then
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Passwords do not match. Try again.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
elseif #pw1 < 6 then
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Password too short (minimum 6 characters).\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
else
|
||||
local ok, err = syscall.setpassword(0, pw1)
|
||||
if ok then
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "Root password set.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(0.5)
|
||||
break
|
||||
else
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Error: " .. tostring(err) .. "\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function spawnShell(username, uid, shell, homedir)
|
||||
local existsOk, existsErr = pcall(syscall.exists, shell)
|
||||
if not existsOk or not existsErr then
|
||||
syscall.write(1, "login: shell not found: " .. shell .. "\n")
|
||||
sleep(2)
|
||||
return false
|
||||
end
|
||||
|
||||
local accessOk, accessErr = pcall(syscall.access, shell, "rx")
|
||||
|
||||
syscall.setEnviron("HOME", homedir)
|
||||
syscall.setEnviron("USER", username)
|
||||
syscall.setEnviron("SHELL", shell)
|
||||
syscall.setEnviron("PATH", "/bin/")
|
||||
|
||||
local setuidOk, setuidErr = pcall(syscall.setuid, uid)
|
||||
if not setuidOk then
|
||||
syscall.write(1, "login: setuid failed: " .. tostring(setuidErr) .. "\n")
|
||||
sleep(2)
|
||||
return false
|
||||
end
|
||||
|
||||
local chdirOk, chdirErr = pcall(syscall.chdir, homedir)
|
||||
if not chdirOk then
|
||||
pcall(syscall.chdir, "/")
|
||||
end
|
||||
|
||||
local ok, err = pcall(syscall.execspawn, shell, username .. ":shell")
|
||||
if not ok then
|
||||
syscall.write(1, "login: failed to launch shell: " .. tostring(err) .. "\n")
|
||||
sleep(2)
|
||||
return false
|
||||
end
|
||||
|
||||
syscall.exit(0)
|
||||
end
|
||||
|
||||
local function doLogin()
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.devctl(1, "sbgc", 0x000000)
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
|
||||
local hostname = syscall.getHostname() or "hyperion"
|
||||
syscall.write(1, "HyperionOS\n")
|
||||
syscall.write(1, hostname .. " login\n\n")
|
||||
|
||||
local attempts = 0
|
||||
while attempts < MAX_ATTEMPTS do
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "Username: ")
|
||||
local username = readLine(nil)
|
||||
|
||||
if username ~= "" then
|
||||
|
||||
syscall.write(1, "Password: ")
|
||||
local password = readLine("*")
|
||||
local uid = syscall.getuidbyname(username)
|
||||
|
||||
local ok, err = syscall.login(uid, password)
|
||||
if ok then
|
||||
local uid = syscall.getuid()
|
||||
local pwent = syscall.getpasswd(uid)
|
||||
|
||||
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||
local homedir = (pwent and pwent.homedir) or "/"
|
||||
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "\nWelcome, " .. username .. "!\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(0.3)
|
||||
|
||||
spawnShell(username, uid, shell, homedir)
|
||||
return -- back to login prompt
|
||||
else
|
||||
attempts = attempts + 1
|
||||
sleep(1)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Login incorrect.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Maximum login attempts exceeded.\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(5)
|
||||
end
|
||||
|
||||
firstBoot()
|
||||
while true do
|
||||
doLogin()
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
core utilities for user management
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Haoqian He
|
||||
@@ -0,0 +1 @@
|
||||
Libdeflate for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0-release
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
package providing kernel support for framebuffers and graphics
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Spsf
|
||||
@@ -0,0 +1 @@
|
||||
Official Hyperion shell package
|
||||
@@ -0,0 +1 @@
|
||||
1.3.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1 @@
|
||||
ini parser
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -1,12 +0,0 @@
|
||||
[
|
||||
"Hyperion-kernel",
|
||||
"Hyperion-core",
|
||||
"hysh",
|
||||
"lua",
|
||||
"micro",
|
||||
"sysinit",
|
||||
"bit32",
|
||||
"json",
|
||||
"muxzcat",
|
||||
"spm"
|
||||
]
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1 @@
|
||||
Hyperion os live installer
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
rxi
|
||||
@@ -0,0 +1 @@
|
||||
JSON library for Hyperion
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Spsf
|
||||
@@ -0,0 +1 @@
|
||||
Interactive lua shell
|
||||
@@ -0,0 +1 @@
|
||||
1.2.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Spsf
|
||||
@@ -0,0 +1 @@
|
||||
micro text editor
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,3 @@
|
||||
Hyperion
|
||||
Mark Langen
|
||||
Astronand (added goto support)
|
||||
@@ -0,0 +1 @@
|
||||
lua minifier
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1 @@
|
||||
Proportional Integral Derivative library
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
+65
-3
@@ -1,6 +1,68 @@
|
||||
local args={...}
|
||||
|
||||
local json=require("json")
|
||||
local http=require("http")
|
||||
local rootRepo="https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm/spm.src"
|
||||
-- local test repo
|
||||
local rootRepo="http://localhost:8000/spm.json"
|
||||
--local rootRepo="https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm.json"
|
||||
|
||||
local json = require("json")
|
||||
local http = require("http")
|
||||
local deflate = require("deflate")
|
||||
|
||||
local function checkRepo(repo)
|
||||
local resp = http.get(repo)
|
||||
if resp.code ~= 200 then
|
||||
return false
|
||||
end
|
||||
local repojson = json.decode(resp.body)
|
||||
if not repojson then
|
||||
return false
|
||||
end
|
||||
return true, repojson
|
||||
end
|
||||
|
||||
local function getRepos(root)
|
||||
local repos = {}
|
||||
local visited = {}
|
||||
|
||||
local queue = {root}
|
||||
local head = 1
|
||||
|
||||
while head <= #queue do
|
||||
local url = queue[head]
|
||||
head = head + 1
|
||||
|
||||
if not visited[url] then
|
||||
visited[url] = true
|
||||
|
||||
local ok, repo = checkRepo(url)
|
||||
if ok then
|
||||
table.insert(repos, {
|
||||
url = url,
|
||||
data = repo
|
||||
})
|
||||
|
||||
if repo.refs then
|
||||
for _, ref in ipairs(repo.refs) do
|
||||
if not visited[ref] then
|
||||
queue[#queue + 1] = ref
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return repos
|
||||
end
|
||||
|
||||
local function getPkg(name)
|
||||
|
||||
end
|
||||
|
||||
if args[1] == "install" then
|
||||
local pkg=getPkg(args[2])
|
||||
elseif args[1] == "sync" then
|
||||
error("not implemented")
|
||||
elseif args[1] == "remove" then
|
||||
error("not implemented")
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
Simple Package Manager
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -1,8 +1,9 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local fs=require("fs")
|
||||
kernel.log("Sysinit started...")
|
||||
kernel.saveLog()
|
||||
local fs=require("fs")
|
||||
kernel.log("Loaded fs")
|
||||
|
||||
for i,v in pairs(kernel.processes) do
|
||||
kernel.log("Spawning kernel task "..i)
|
||||
@@ -16,30 +17,32 @@ for i,v in pairs(kernel.processes) do
|
||||
end, i)
|
||||
end
|
||||
|
||||
if not fs.exists("/bin/startup") then
|
||||
fs.mkdir("/bin/startup")
|
||||
-- config file path setup
|
||||
if not fs.exists("/etc/sysinit/") then
|
||||
kernel.log("Creating conf path")
|
||||
fs.mkdir("/etc/sysinit/")
|
||||
fs.mkdir("/etc/sysinit/autorun/")
|
||||
fs.mkdir("/etc/sysinit/system/")
|
||||
fs.mkdir("/etc/sysinit/user/")
|
||||
end
|
||||
|
||||
local files = fs.list("/bin/startup")
|
||||
if not files then error("Failed to list /bin/startup") end
|
||||
local files = fs.list("/etc/sysinit/autorun/")
|
||||
if not files then error("Failed to list autorun") end
|
||||
for i,v in ipairs(files) do
|
||||
if v:sub(-4) == ".lua" then
|
||||
local filepath = "/bin/startup/" .. v
|
||||
kernel.log("Executing startup script: " .. filepath)
|
||||
local startupFunc, err = load(fs.readAllText(filepath), "@" .. filepath)
|
||||
if not startupFunc then
|
||||
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||
else
|
||||
syscall.spawn(function()
|
||||
syscall.setuid(1)
|
||||
local status, err = pcall(startupFunc)
|
||||
if not status then
|
||||
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Successfully executed startup script: " .. filepath)
|
||||
end
|
||||
end, "startup:" .. v)
|
||||
end
|
||||
local filepath = "/etc/sysinit/autorun/" .. v
|
||||
kernel.log("Executing startup script: " .. filepath)
|
||||
local startupFunc, err = load(fs.readAllText(filepath), "@" .. filepath)
|
||||
if not startupFunc then
|
||||
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||
else
|
||||
syscall.spawn(function()
|
||||
local status, err = pcall(startupFunc)
|
||||
if not status then
|
||||
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Successfully executed startup script: " .. filepath)
|
||||
end
|
||||
end, "startup:" .. v)
|
||||
end
|
||||
end
|
||||
kernel.saveLog()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
System init package
|
||||
@@ -0,0 +1 @@
|
||||
1.1.0
|
||||
@@ -0,0 +1,5 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
pts@fazekas.hu
|
||||
JackMacWindows
|
||||
hanzhao
|
||||
@@ -0,0 +1 @@
|
||||
XZ compression library
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import shutil
|
||||
import tarfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
SOURCE = ROOT / "Src"
|
||||
PACKAGE_ROOT = ROOT / "packages"
|
||||
PACKAGE_DIR = PACKAGE_ROOT / "raw"
|
||||
|
||||
# main repo
|
||||
#API_ROOT = "https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main"
|
||||
|
||||
# local repo
|
||||
API_ROOT = "http://localhost:8000"
|
||||
|
||||
DEFAULT_VERSION = "0.0.0"
|
||||
DEFAULT_DESCRIPTION = "No description provided"
|
||||
DEFAULT_AUTHORS = []
|
||||
DEFAULT_DEPENDENCIES = []
|
||||
|
||||
|
||||
def debug(message):
|
||||
print(f"[COMPILE] {message}", flush=True)
|
||||
|
||||
|
||||
def sha256(path):
|
||||
hasher = hashlib.sha256()
|
||||
|
||||
with open(path, "rb") as file:
|
||||
while chunk := file.read(1024 * 1024):
|
||||
hasher.update(chunk)
|
||||
|
||||
return hasher.hexdigest()
|
||||
|
||||
|
||||
def exclude(info):
|
||||
blocked = (".git", "__pycache__", ".pyc")
|
||||
|
||||
if any(item in info.name.split("/") for item in blocked):
|
||||
return None
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def read_file(folder, names, default):
|
||||
for name in names:
|
||||
file = folder / name
|
||||
|
||||
if file.exists():
|
||||
return file.read_text(encoding="utf-8").strip()
|
||||
|
||||
return default
|
||||
|
||||
|
||||
def read_authors(folder):
|
||||
authors_file = folder / "authors.txt"
|
||||
|
||||
if not authors_file.exists():
|
||||
return DEFAULT_AUTHORS
|
||||
|
||||
authors = []
|
||||
|
||||
for line in authors_file.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
|
||||
if line:
|
||||
authors.append(line)
|
||||
|
||||
return authors if authors else DEFAULT_AUTHORS
|
||||
|
||||
|
||||
def read_dependencies(folder):
|
||||
dependencies_file = folder / "dependencies.txt"
|
||||
|
||||
if not dependencies_file.exists():
|
||||
return DEFAULT_DEPENDENCIES
|
||||
|
||||
dependencies = []
|
||||
|
||||
for line in dependencies_file.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
|
||||
if line:
|
||||
dependencies.append(line)
|
||||
|
||||
return dependencies if dependencies else DEFAULT_DEPENDENCIES
|
||||
|
||||
|
||||
def create_package(folder):
|
||||
name = folder.name
|
||||
|
||||
tarball = PACKAGE_DIR / f"{name}.tar.gz"
|
||||
pkg_file = PACKAGE_ROOT / f"{name}.pkg"
|
||||
|
||||
if tarball.exists():
|
||||
debug(f"Replacing {tarball.name}")
|
||||
tarball.unlink()
|
||||
|
||||
debug(f"Packing {name}")
|
||||
|
||||
with tarfile.open(tarball, "w:gz") as archive:
|
||||
archive.add(folder, arcname=name, filter=exclude)
|
||||
|
||||
package_hash = sha256(tarball)
|
||||
|
||||
metadata = {
|
||||
"id": name,
|
||||
"description": read_file(
|
||||
folder,
|
||||
["description.md", "description.txt"],
|
||||
DEFAULT_DESCRIPTION,
|
||||
),
|
||||
"authors": read_authors(folder),
|
||||
"dependencies": read_dependencies(folder),
|
||||
"version": read_file(
|
||||
folder,
|
||||
["version.txt"],
|
||||
DEFAULT_VERSION,
|
||||
),
|
||||
"hash": package_hash,
|
||||
"tarball": f"{API_ROOT}/packages/raw/{name}.tar.xz",
|
||||
}
|
||||
|
||||
with open(pkg_file, "w", encoding="utf-8") as file:
|
||||
json.dump(metadata, file, indent=4)
|
||||
file.write("\n")
|
||||
|
||||
debug(f"Generated {pkg_file.name}")
|
||||
debug(f"{name}: {package_hash}")
|
||||
|
||||
return tarball
|
||||
|
||||
def load_spm():
|
||||
spm_file = ROOT / "spm.json"
|
||||
|
||||
if not spm_file.exists():
|
||||
return {
|
||||
"refs": {},
|
||||
"maintainers": [],
|
||||
"packages": {}
|
||||
}
|
||||
|
||||
with open(spm_file, "r", encoding="utf-8") as file:
|
||||
data = json.load(file)
|
||||
|
||||
data.setdefault("refs", {})
|
||||
data.setdefault("maintainers", [])
|
||||
data.setdefault("packages", {})
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def update_spm():
|
||||
spm = load_spm()
|
||||
|
||||
packages = {}
|
||||
|
||||
for pkg in sorted(PACKAGE_ROOT.glob("*.pkg")):
|
||||
with open(pkg, "r", encoding="utf-8") as file:
|
||||
metadata = json.load(file)
|
||||
|
||||
packages[metadata["id"]] = f"{API_ROOT}/packages/{pkg.name}"
|
||||
|
||||
spm["packages"] = packages
|
||||
|
||||
with open(ROOT / "spm.json", "w", encoding="utf-8") as file:
|
||||
json.dump(spm, file, indent=4)
|
||||
file.write("\n")
|
||||
|
||||
debug("Generated spm.json")
|
||||
|
||||
def main():
|
||||
if not SOURCE.exists():
|
||||
debug("Src directory missing")
|
||||
return 1
|
||||
|
||||
if PACKAGE_ROOT.exists():
|
||||
shutil.rmtree(PACKAGE_ROOT)
|
||||
|
||||
PACKAGE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for folder in sorted(SOURCE.iterdir()):
|
||||
if folder.is_dir():
|
||||
create_package(folder)
|
||||
|
||||
update_spm()
|
||||
debug("Complete")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,233 +0,0 @@
|
||||
term.clear()
|
||||
term.setTextColor(colors.white)
|
||||
term.setCursorPos(1,1)
|
||||
print("HyperionOS CCT Installer //")
|
||||
local w,h = term.getSize()
|
||||
local exitall,releasename,packagelist=false,"",{}
|
||||
|
||||
local function printc(...)
|
||||
local args={...}
|
||||
for i=1, #args do
|
||||
if type(args[i]) == "number" then
|
||||
term.setTextColor(args[i])
|
||||
else
|
||||
term.write(args[i])
|
||||
end
|
||||
end
|
||||
print("")
|
||||
end
|
||||
|
||||
local function download(url)
|
||||
printc(colors.gray, "[ ", colors.green, " FETCH ", colors.gray, " ] ", colors.white, url)
|
||||
local data,err=http.get(url)
|
||||
if not data then error(err) end
|
||||
local text=data.readAll()
|
||||
data.close()
|
||||
return text
|
||||
end
|
||||
|
||||
local function writeFile(path, data)
|
||||
printc(colors.gray, "[ ", colors.green, "WRITING", colors.gray, " ] ", colors.white, path)
|
||||
local file=fs.open(path, "w")
|
||||
file.write(data)
|
||||
file.close()
|
||||
end
|
||||
|
||||
print("Installing JSON to /hyinstall/json...")
|
||||
writeFile("/hyinstall/json",download("https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/misc/json"))
|
||||
print("Loading JSON...")
|
||||
local json=loadfile("/hyinstall/json")()
|
||||
|
||||
local function printTitle()
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
term.setTextColor(colors.white)
|
||||
print("HyperionOS CCT Installer //")
|
||||
print("Orange is prerelease...")
|
||||
term.setCursorPos(1,h-1)
|
||||
print("DESCLAIMER: This will wipe your system on install...")
|
||||
term.write("Bspc: Back | Enter: execute | Tab: description")
|
||||
end
|
||||
|
||||
local function pc(text, y, c)
|
||||
local x=(w/2)-#text/2
|
||||
term.setTextColor(c)
|
||||
term.setCursorPos(x, y)
|
||||
term.write(text)
|
||||
end
|
||||
|
||||
local function drawMenu(menu, sel)
|
||||
local y=(h/2)-#menu/2
|
||||
for i,v in ipairs(menu) do
|
||||
if i==sel then
|
||||
pc("[ "..v.name.." ]", y+i, v.color)
|
||||
else
|
||||
pc(v.name, y+i, v.color)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function desc(description)
|
||||
term.clear()
|
||||
term.setTextColor(colors.white)
|
||||
term.setCursorPos(1,1)
|
||||
print("HyperionOS CCT Installer //\n")
|
||||
print(description)
|
||||
term.setCursorPos(1,h)
|
||||
term.write("Press enter to continue...")
|
||||
while not exitall do
|
||||
local _,key = os.pullEvent("key")
|
||||
if key==keys.enter then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function menu(m)
|
||||
local exit,sel=false,1
|
||||
while not exit and not exitall do
|
||||
printTitle()
|
||||
drawMenu(m, sel)
|
||||
local _,key = os.pullEvent("key")
|
||||
if key==keys.down then
|
||||
if sel<#m then
|
||||
sel=sel+1
|
||||
end
|
||||
elseif key==keys.up then
|
||||
if sel>1 then
|
||||
sel=sel-1
|
||||
end
|
||||
elseif key==keys.enter then
|
||||
m[sel].func()
|
||||
elseif key==keys.tab then
|
||||
desc(m[sel].desc)
|
||||
elseif key==keys.backspace then
|
||||
exit=true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local releases,page={},1
|
||||
while true do
|
||||
local raw=download("https://git.astronand.dev/api/v1/repos/Hyperion/HyperionOS/releases?page="..tostring(page).."&limit=1")
|
||||
if raw=="[]\n" then
|
||||
break
|
||||
end
|
||||
releases[page]=json.decode(raw)[1]
|
||||
page=page+1
|
||||
end
|
||||
|
||||
local function makePage(start, num)
|
||||
local m={}
|
||||
for i=start, num do
|
||||
if not releases[i] then break end
|
||||
local release=releases[i]
|
||||
m[#m+1]={
|
||||
name=release.name,
|
||||
desc=release.body,
|
||||
color=release.prerelease and colors.orange or colors.white,
|
||||
func=function()
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
local data=download("https://git.astronand.dev/Hyperion/HyperionOS/raw/tag/"..release.tag_name.."/Src/install.json")
|
||||
if not data then
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
print("Unable to find package list for ver "..release.tag_name..":\n"..err)
|
||||
sleep(3)
|
||||
return
|
||||
end
|
||||
releasename=release.tag_name
|
||||
packagelist=json.decode(data)
|
||||
exitall=true
|
||||
end
|
||||
}
|
||||
end
|
||||
if #releases>start+num then
|
||||
m[#m+1]={
|
||||
name="Next",
|
||||
desc="Next menu",
|
||||
color=colors.cyan,
|
||||
func=function()
|
||||
local menudata=makePage(start+num, num)
|
||||
menu(menudata)
|
||||
end
|
||||
}
|
||||
end
|
||||
return m
|
||||
end
|
||||
|
||||
printTitle()
|
||||
menu(makePage(1,5))
|
||||
if not exitall then error("Exited") end
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
term.setTextColor(colors.white)
|
||||
term.write("Formating disk in ")
|
||||
for i=5, 1, -1 do
|
||||
term.write(tostring(i))
|
||||
sleep(.25)
|
||||
for v=1, 3 do
|
||||
term.write(".")
|
||||
sleep(.25)
|
||||
end
|
||||
end
|
||||
print("")
|
||||
|
||||
local function delDir(dir)
|
||||
printc(colors.gray, "[ ", colors.green, " LSDIR ", colors.gray, " ] ", colors.white, dir)
|
||||
local list=fs.list(dir)
|
||||
printc(colors.gray, "[ ", colors.red, " DELET ", colors.gray, " ] ", colors.white, dir)
|
||||
for i=1, #list do
|
||||
if fs.isDir(dir..list[i]) then
|
||||
if dir..list[i] ~= "/rom" then
|
||||
delDir(dir..list[i].."/")
|
||||
fs.delete(dir..list[i])
|
||||
end
|
||||
else
|
||||
fs.delete(dir..list[i])
|
||||
printc(colors.gray, "[ ", colors.red, " DELET ", colors.gray, " ] ", colors.white, dir..list[i])
|
||||
end
|
||||
sleep(.01)
|
||||
end
|
||||
sleep(.15)
|
||||
end
|
||||
|
||||
delDir("/")
|
||||
|
||||
print("")
|
||||
printc(colors.cyan, " \\\\Installing//")
|
||||
print("")
|
||||
printc(colors.white, "Getting package list...")
|
||||
|
||||
local function installdir(path, dir, pkg)
|
||||
local data=json.decode(download("https://git.astronand.dev/api/v1/repos/Hyperion/HyperionOS/contents/prod/"..pkg..dir.."?ref="..releasename))
|
||||
if not data then error("Uh Oh: JSON decode error...") end
|
||||
for i=1, #data do
|
||||
local entry=data[i]
|
||||
if entry.type == "dir" then
|
||||
installdir(path, dir..entry.name.."/", pkg)
|
||||
elseif entry.type == "file" then
|
||||
writeFile(path..dir..entry.name, download(entry.download_url))
|
||||
else
|
||||
error("Uh Oh: unknown entrytype "..entry.path)
|
||||
end
|
||||
sleep(.01)
|
||||
end
|
||||
sleep(.15)
|
||||
end
|
||||
|
||||
local function installpkg(pkg)
|
||||
installdir("/$", "/", pkg)
|
||||
end
|
||||
|
||||
for i=1, #packagelist do
|
||||
installpkg(packagelist[i])
|
||||
end
|
||||
|
||||
installpkg("Hyperion-firmware-cct")
|
||||
fs.copy("/$/boot/cct/eeprom", "/startup.lua")
|
||||
|
||||
printc(colors.white, "Rebooting...")
|
||||
sleep(1)
|
||||
os.reboot()
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "Hyperion-core",
|
||||
"description": "Core library for Hyperion",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "e83a8dc42a871c1e16cd56c214cf0ca4bb0079432dc8bd198abbe11d6cf31d4e",
|
||||
"tarball": "http://localhost:8000/packages/raw/Hyperion-core.tar.xz"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "Hyperion-firmware-ac",
|
||||
"description": "firmware for Advanced Computers",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand",
|
||||
"GHXX (Advanced Computers)"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "f64be830fc02394eeb9c049a528ed47b97430c6682a577c789d16303dcaad6fc",
|
||||
"tarball": "http://localhost:8000/packages/raw/Hyperion-firmware-ac.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "Hyperion-firmware-ccpc",
|
||||
"description": "firmware for CraftOS PC",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "f3f030d6f6faa137f9950f0ce4ccc598a9b29c729380c100c920fad5aa254076",
|
||||
"tarball": "http://localhost:8000/packages/raw/Hyperion-firmware-ccpc.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "Hyperion-firmware-cct",
|
||||
"description": "firmware for ComputerCraft Tweaked",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.3.0",
|
||||
"hash": "dd69c26ba6f46acb99d6f839474fc50283524bd99df7f67a5d300a749af86dde",
|
||||
"tarball": "http://localhost:8000/packages/raw/Hyperion-firmware-cct.tar.xz"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"id": "Hyperion-firmware-oc",
|
||||
"description": "firmware for Opencomputers",
|
||||
"authors": [
|
||||
"Hyperion"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "0.1.0",
|
||||
"hash": "8b1bbff272dd07f0e5023c90007ec8d3a84f5b29a59449a75894319c86ee10cd",
|
||||
"tarball": "http://localhost:8000/packages/raw/Hyperion-firmware-oc.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "Hyperion-kernel",
|
||||
"description": "Hyperion kernel package",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand",
|
||||
"Spsf"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.5.0",
|
||||
"hash": "a17552597f1a4e661804bcf23d26e19664cb6f75cb3058357603df59b033155a",
|
||||
"tarball": "http://localhost:8000/packages/raw/Hyperion-kernel.tar.xz"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "bit32",
|
||||
"description": "Bit32 package for Hyperion",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Lua"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "9bc32da8ab97f899e85faeb47064433ef4a167e45924c0e583d30f901551bdf5",
|
||||
"tarball": "http://localhost:8000/packages/raw/bit32.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "blake2s",
|
||||
"description": "blake2s package for Hyperion",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "c32e2bbeba5d8609f720bce59fad0505d490ee22a6e54b4d830a524e609ac415",
|
||||
"tarball": "http://localhost:8000/packages/raw/blake2s.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "coreutils",
|
||||
"description": "core utilities for user management",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand",
|
||||
"Spsf"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "c52244c7fd2ca96780ed684327ebb55872757a4f6c8d90e18367ec4e0d8f10ad",
|
||||
"tarball": "http://localhost:8000/packages/raw/coreutils.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "deflate",
|
||||
"description": "Libdeflate for Hyperion",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Haoqian He"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0-release",
|
||||
"hash": "43a3df0e6da39aa97c0ee0ce4217e9acffadba4178d03dae5c66bf4627147644",
|
||||
"tarball": "http://localhost:8000/packages/raw/deflate.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "gfxterm",
|
||||
"description": "package providing kernel support for framebuffers and graphics",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "88eb9f9bb7bb86fb7752601c67e4ab62e88fb7562057a83c101aaf7ffc3ccdc0",
|
||||
"tarball": "http://localhost:8000/packages/raw/gfxterm.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "hysh",
|
||||
"description": "Official Hyperion shell package",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Spsf"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.3.0",
|
||||
"hash": "d0baaeb889eeaa38a9f100c4954b8f30c36c220ba73d8b8fa878e0fcaeaadb15",
|
||||
"tarball": "http://localhost:8000/packages/raw/hysh.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "iniparse",
|
||||
"description": "ini parser",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "f26f900027066dc2f498a4ccb8306f48c93210e7869b11f4aef9900f2e00e066",
|
||||
"tarball": "http://localhost:8000/packages/raw/iniparse.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "installer",
|
||||
"description": "Hyperion os live installer",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"Astronand"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "8623a44260062d0066aecc683b45c2ea9e6f438fd74cef050e7bcac7daa33a4f",
|
||||
"tarball": "http://localhost:8000/packages/raw/installer.tar.xz"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "json",
|
||||
"description": "JSON library for Hyperion",
|
||||
"authors": [
|
||||
"Hyperion",
|
||||
"rxi"
|
||||
],
|
||||
"dependencies": [],
|
||||
"version": "1.0.0",
|
||||
"hash": "8344035d687f5cafb8c918d6bddd2ba5a7d6c2025aa43def84b942a614583282",
|
||||
"tarball": "http://localhost:8000/packages/raw/json.tar.xz"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user