Compare commits

..

13 Commits

Author SHA1 Message Date
Rph :3
92d97c8773 Base for the actor system (just some docs) 2025-03-27 18:54:01 +01:00
Rph :3
e5cd5c6e71 Dev mode (auto-run updater) 2025-03-27 18:53:48 +01:00
2fcea0909d Merge pull request 'Improvements to installation process' (#1) from dev-server into main
Reviewed-on: #1
2025-03-27 17:46:53 +01:00
Rph :3
4ff7e3216c Implement setting alternative repo bases with the snowier.repo_base setting 2025-03-27 17:42:56 +01:00
Rph :3
6edfa118b1 Implement dev server 2025-03-27 17:42:45 +01:00
Rph :3
3772d67726 Add flake with Bun 2025-03-27 17:25:19 +01:00
7e21413e7b update installer to cleanup /tmp/ entirely 2025-03-27 10:57:10 +01:00
80f91cbcd9 oops 2025-03-27 10:01:33 +01:00
4d157bfee4 Write basic bootloader 2025-03-27 09:57:14 +01:00
db862f12ef hack might have been because of emulation bug..? 2025-03-25 19:29:22 +01:00
fc349f46e4 Always emulate bitwise operations for CC 2025-03-25 19:26:22 +01:00
6cf175e5f0 polish up installer 2025-03-25 19:20:04 +01:00
c7d7f9be98 Squashed commit of the following:
commit 51f79d4749
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 19:14:15 2025 +0100

    reduce useless downloads

commit 86d335f53e
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 19:13:26 2025 +0100

    fix everywhere

commit 3d23d1b618
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 19:10:54 2025 +0100

    update hashes

commit bbf2d23eb4
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 19:10:30 2025 +0100

    try this instead

commit 5c0cf083d9
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 19:05:42 2025 +0100

    istg if that was the problem

commit ac23c993d0
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 18:44:26 2025 +0100

    Fix other dumb mistake

commit 610893222b
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 18:43:41 2025 +0100

    Fix dumb mistake

commit bb0ee3e64e
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 18:42:33 2025 +0100

    Try fixing sha256 not loading

commit b0f8c1267a
Merge: e079d75 17e3a3b
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 17:46:06 2025 +0100

    Merge branch 'main' of git.colon-three.com:kodi/snowier

commit e079d75fab
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 17:45:55 2025 +0100

    Add debug print

commit 17e3a3b5a8
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 15:51:28 2025 +0100

    Second attempt to fix sha256

commit d575f3c98c
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 15:39:40 2025 +0100

    Fix typo

commit f8ef3b0210
Author: Kodi Craft <kodi@kdcf.me>
Date:   Tue Mar 25 15:38:42 2025 +0100

    Try using different implementation of sha256
2025-03-25 19:16:40 +01:00
15 changed files with 440 additions and 42 deletions

1
dev-server/.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

2
dev-server/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.direnv
node_modules

47
dev-server/bun.lock Normal file
View File

@@ -0,0 +1,47 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "dev-server",
"dependencies": {
"@elysiajs/static": "^1.2.0",
"elysia": "^1.2.25",
},
"devDependencies": {
"@types/bun": "latest",
},
"peerDependencies": {
"typescript": "^5",
},
},
},
"packages": {
"@elysiajs/static": ["@elysiajs/static@1.2.0", "", { "dependencies": { "node-cache": "^5.1.2" }, "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-oLpAi8c+maPpA0XhhK3BELaIjIG+nXg/K9p8cFfW4q5ayRD59a3MOMOOGgpiXZkHJzLPWcouhhyyLAYtaANW4g=="],
"@sinclair/typebox": ["@sinclair/typebox@0.34.31", "", {}, "sha512-qQ71T9DsITbX3dVCrcBERbs11YuSMg3wZPnT472JhqhWGPdiLgyvihJXU8m+ADJtJvRdjATIiACJD22dEknBrQ=="],
"@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="],
"@types/node": ["@types/node@22.13.14", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w=="],
"@types/ws": ["@types/ws@8.18.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw=="],
"bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="],
"clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"elysia": ["elysia@1.2.25", "", { "dependencies": { "@sinclair/typebox": "^0.34.27", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-WsdQpORJvb4uszzeqYT0lg97knw1iBW1NTzJ1Jm57tiHg+DfAotlWXYbjmvQ039ssV0fYELDHinLLoUazZkEHg=="],
"memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="],
"node-cache": ["node-cache@5.1.2", "", { "dependencies": { "clone": "2.x" } }, "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
}
}

61
dev-server/flake.lock generated Normal file
View File

@@ -0,0 +1,61 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1742923925,
"narHash": "sha256-biPjLws6FiBVUUDHEMFq5pUQL84Wf7PntPYdo3oKkFw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "25d1b84f5c90632a623c48d83a2faf156451e6b1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"utils": "utils"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

17
dev-server/flake.nix Normal file
View File

@@ -0,0 +1,17 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, utils }:
utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in {
devShell = with pkgs; mkShell {
buildInputs = with pkgs; [ bun ];
};
}
);
}

35
dev-server/index.ts Normal file
View File

@@ -0,0 +1,35 @@
import { Elysia } from 'elysia'
import { staticPlugin } from "@elysiajs/static"
import { stat, readdir, readFile } from "node:fs/promises"
import { createHash } from "node:crypto";
type IndexEntry = { src: string, dest: string, hash: string };
async function scanDir(scanIn: string, base: string, outputBase: string): Promise<IndexEntry[]> {
let files = await readdir(scanIn + "/" + base);
let results: IndexEntry[] = [];
for (let file of files) {
if (await stat(scanIn + "/" + base + "/" + file).then(r => r.isDirectory())) {
results = [...results, ...(await scanDir(scanIn, base + "/" + file, outputBase + file + "/"))]
} else {
results.push({
src: base + "/" + file,
dest: outputBase + file,
hash: createHash('sha256').update(await readFile(scanIn + "/" + base + "/" + file)).digest('hex')
});
}
}
return results;
}
new Elysia()
.get("/index.json", async () => scanDir("..", "src", "/"))
.get("/sha256.lua", async () => Bun.file("../sha256.lua"))
.use(staticPlugin({
assets: "../src",
prefix: "/src"
}))
.get("/install.lua", async () => Bun.file("../install.lua"))
.listen(parseInt(process.env.PORT || "3000"))

16
dev-server/package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "dev-server",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
},
"dependencies": {
"@elysiajs/static": "^1.2.0",
"elysia": "^1.2.25"
}
}

28
dev-server/tsconfig.json Normal file
View File

@@ -0,0 +1,28 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["esnext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

View File

@@ -2,6 +2,11 @@
{ {
"src": "src/startup.lua", "src": "src/startup.lua",
"dest": "/startup.lua", "dest": "/startup.lua",
"hash": "07219cd9561b41ce1f39209958076c471b17855679c968b42767b0122423c782" "hash": "38b4f27b677716688ce5c27f416a3e4605e03d1a07f76df7b5ef1cedf4f355ea"
},
{
"src": "src/kernel/entry.lua",
"dest": "/kernel/entry.lua",
"hash": "5d17a09860a3d14346105e363c0b3333bf720c75c4670add778fd20a736dafb7"
} }
] ]

View File

@@ -1,4 +1,5 @@
local repoRoot = "https://git.colon-three.com/kodi/snowier/raw/branch/main/" local defaultRoot = "https://git.colon-three.com/kodi/snowier/raw/branch/main/"
local repoRoot = settings.get("snowier.repo_base") or defaultRoot
local URLs = { local URLs = {
fileIndex = repoRoot .. "index.json", fileIndex = repoRoot .. "index.json",
@@ -12,6 +13,11 @@ function log.info(value)
print("[I] " .. value) print("[I] " .. value)
end end
--- @param value string
function log.debug(value)
print("[D] " .. value)
end
--- @param value string --- @param value string
function log.error(value) function log.error(value)
printError("[E] " .. value) printError("[E] " .. value)
@@ -28,11 +34,12 @@ local function main()
shafile.close() shafile.close()
sharequest.close() sharequest.close()
end end
package.path = package.path .. ";/?;/?.lua" -- hack to solve 'wget run'
local hash = require("sha256") local hash = require("sha256")
log.info("Downloading index file") log.info("Downloading index file")
local indexrequest = http.get(URLs.fileIndex) local indexrequest = http.get(URLs.fileIndex)
local index = textutils.unserializeJson(request.readAll()) local index = textutils.unserializeJSON(indexrequest.readAll())
indexrequest.close() indexrequest.close()
if (index == nil) then if (index == nil) then
@@ -52,12 +59,13 @@ local function main()
local destfile = fs.open(v.dest, "r") local destfile = fs.open(v.dest, "r")
local filehash = hash.sha256(destfile.readAll()) local filehash = hash.sha256(destfile.readAll())
destfile.close() destfile.close()
if filehash ~= v.sha256 then if filehash ~= v.hash then
toDownload[#toDownload+1] = v toDownload[#toDownload+1] = v
end end
end end
end end
if #toDownload > 0 then
log.info(#toDownload .. " files to download") log.info(#toDownload .. " files to download")
for k, v in ipairs(toDownload) do for k, v in ipairs(toDownload) do
if not fs.exists("/tmp") then if not fs.exists("/tmp") then
@@ -76,14 +84,20 @@ local function main()
tempfile.close() tempfile.close()
if filehash ~= v.hash then if filehash ~= v.hash then
log.error("File " .. v.dest .. " (from " .. v.src .. ") has a mismatched hash.") log.error("File " .. v.dest .. " (from " .. v.src .. ") has a mismatched hash.")
log.error("Installation aborted.") log.error("Installation aborted. Remember to clean /tmp manually.")
return return
end end
end end
log.info("Installing") log.info("Installing")
for k, v in ipairs(toDownload) do for k, v in ipairs(toDownload) do
fs.move("/tmp/" .. v.hash .. ".lua", v.dest) fs.delete(v.dest)
fs.copy("/tmp/" .. v.hash .. ".lua", v.dest)
end
fs.delete("/tmp/")
else
log.info("Nothing to do")
end end
log.info("Installation complete!") log.info("Installation complete!")

View File

@@ -193,6 +193,9 @@ if print_debug_messages then
print(" "..method) print(" "..method)
end end
-- For computercraft, use emulated mode for the sake of compatibility
branch = "EMUL"
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- BASIC 32-BIT BITWISE FUNCTIONS -- BASIC 32-BIT BITWISE FUNCTIONS
@@ -208,8 +211,6 @@ if branch == "FFI" or branch == "LJ" or branch == "LIB32" then
-- Your system has 32-bit bitwise library (either "bit" or "bit32") -- Your system has 32-bit bitwise library (either "bit" or "bit32")
-- ADJUSTED FOR COMPUTERCRAFT
AND = b.band -- 2 arguments AND = b.band -- 2 arguments
OR = b.bor -- 2 arguments OR = b.bor -- 2 arguments
XOR = b.bxor -- 2..5 arguments XOR = b.bxor -- 2..5 arguments
@@ -219,17 +220,17 @@ if branch == "FFI" or branch == "LJ" or branch == "LIB32" then
SHR = b.brshift SHR = b.brshift
-- ROL = b.rol or b.lrotate -- second argument is integer 0..31 -- ROL = b.rol or b.lrotate -- second argument is integer 0..31
-- ROR = b.ror or b.rrotate -- second argument is integer 0..31 -- ROR = b.ror or b.rrotate -- second argument is integer 0..31
function ROL(x, n) --function ROL(x, n)
x = x % 2^32 * 2^n -- x = x % 2^32 * 2^n
local r = x % 2^32 -- local r = x % 2^32
return r + (x - r) / 2^32 -- return r + (x - r) / 2^32
end --end
function ROR(x, n) --function ROR(x, n)
x = x % 2^32 / 2^n -- x = x % 2^32 / 2^n
local r = x % 1 -- local r = x % 1
return r * 2^32 + (x - r) -- return r * 2^32 + (x - r)
end --end
NOT = b.bnot -- only for LuaJIT NOT = b.bnot -- only for LuaJIT
NORM = b.tobit -- only for LuaJIT NORM = b.tobit -- only for LuaJIT

7
src/kernel/entry.lua Normal file
View File

@@ -0,0 +1,7 @@
-- kernel entrypoint
-- this is responsible for initializing core kernel services
-- required to advance to the next step of the OS
require 'kernel.system'
os.run({}, "/rom/programs/advanced/multishell.lua") -- placeholder

117
src/kernel/system.lua Normal file
View File

@@ -0,0 +1,117 @@
--[[
The Erica Actor System ([Er]lang + A[kka])
Each actor has:
- Coroutine
- Mailbox
- Address
- Extra Addresses
- State
- Child IDs
The Actor System utilizes coroutine yielding for all invocations of the system. No global APIs are exposed by the system.
The following calls are available to actors:
- spawn function:handler table?:options
The options table exposes the following:
- addressBase | default: seedocs | If not provided, the address will take this form: "$currentAddress/$childId" and childId gets incremented
| in local state.
| If provided, the global address base counter gets updated and the provided address base is used.
| Actors created without an address base are considered child actors of the current actor,
| and their status updates (death) will emit status update events to the next immediate parent.
| The death of an actor will kill all of it's children recursively.
- localNamespace| default: nil | If set, adds the localNamespace into the address of the newly spawned actor.
- extraAddresses| default: {} | Logic for global base addresses, that are used to add receive-only extra addresses to this actor.
The returned value is: bStatus, tAddress?
- bStatus: True if successful, false if failed
- tAddress: Address of newly spawned actor
- tell addressPredicate:string ...content
Any instances of `?` in addressPredicate are replaced with a random valid instance.
Adds a message of "content" to the mailbox of the target actor
The returned value is: bStatus, sData?
- bStatus: True if successful, false if failed
- sData: The error string if status is false, for example no valid instances.
If status is true, actor address that received this tell.
- announce addressPredicate:string ...content
Any instances of `?` in addressPredicate are replaced with all valid instances.
Adds a message of "content" to the mailbox of the target actor
The returned value is: bStatus, data?
- bStatus: True if successful, false if failed
- data: The error string if status is false, for example no valid instances.
If status is true, amount of actors that received this announcement.
- ask addressPredicate:string timeout:number ...content
Suspends this actor until the responseHandle is used with the "reply" or "fail" syscall,
or until the timeout elapses. The timeout elapsing invalidates the handle and makes calls to "reply" or "fail" fail silently.
The return value is:
- bStatus: If the ask was successful
- ...data: If the status is false, this contains the reason for the error.
If the status is true, the first value is the actor asked, and subsequent data contains the response from the actor asked.
- reply askHandle:string ...data
Replies to an ask. Returns nil.
- fail askHandle:string ...reason
Fails an ask. Returns nil.
- idle timeout:number receiveUnfiltered?:bool
Notifies the actor system that this actor is ready to process events. Values returned by this call are described below, in the signals section.
If receiveUnfiltered is set, the actor will receive "hostEvent" signals without any filtering.
Signals:
- timeout
When the idle call times out. No extra params
- message sourceAddress:string {content}
When a message is received from another actor.
- ask replyHandle:string sourceAddress:string {content}
When an ask is received from another actor. Good idea to immediately fail any asks that the current actor doesn't recognize.
- childStatus address:string {newStatus}
When a child's status updates (coroutine.status() call)
- hostEvent {data}
ComputerCraft event from the top level coroutine.yield() call. Use with caution, generally this should only be used by actors
that propagate events to announcement channels.
Addresses
There are 3 types of address:
- Fully Qualified Address
- Local Address
- Relative Address
Fully Qualified addresses take on the following format:
systemId .. ":/" .. localAddressWithinSystem
The purpose of fully qualified addresses is to be provided by the system to actors to have unambigous resolution of actors.
User-written code generally shouldn't need to use fully qualified addresses, because their primary use case is future compatibility
with a version of this system that allows multi-node operation (and setting wildcards on systemId)
Local Addresses are full addresses within a single system.
The "child:" prefix is reserved in address parts only for automatically-generated addresses, and manual usage of it in addresses
is considered undefined behavior.
Here is an example address of the first actor spawned within the "com/colon-three/someApp" namespace:
"com/colon-three/someApp/1" (subsequent actors are 2, 3, 4, etc. Monotonically increasing, but not guaranteed. Do not rely on this.)
If that actor then makes a child, that child's address is:
"com/colon-three/someApp/1/child:1"
And if that child makes another child, that child's address is:
"com/colon-three/someApp/1/child:1/child:1"
If that actor makes a child with the local namespace of "someNs", the address will be:
"com/colon-three/someApp/1/someNs/child:2" (because child:1 for this actor already exists, and namespaces are for filtering only.)
Every address of an actual actor ends with either a plain number, or the "child:number" template.
Relative Addresses:
Used only in calls, and taking the following format:
".." - refer to the parent actor. IGNORES NAMESPACES!!!
"../someNs" - refer to parent actor's "someNs". Ignores the current actor's namespace.
"./someNs" - refer to the current actor's someNs namespace.
Allows asking the parent something, or the parent broadcasting something to all of it's children, or children in a specific namespace.
This is generally only useful with `?` in asks or broadcasts, because a child's ID shouldn't be considered predictable.
]]
local tActors = {}
local tAddressBases = {}

View File

@@ -1 +1,48 @@
print("Hello, World!") -- Bootloader
-- This script is only responsible for killing rednet and jumping to the kernel
-- based on some code rph wrote and gave me
if settings.get("snowier.auto_update") then
local defaultRoot = "https://git.colon-three.com/kodi/snowier/raw/branch/main/"
local repoRoot = settings.get("snowier.repo_base") or defaultRoot
shell.run("wget run " .. repoRoot .. "install.lua")
end
local function main()
if not _G["rednet"] then
return
end
local o = os.pullEventRaw
os.pullEventRaw = function()
local a = table.pack(o())
if a[1] == "modem_message" then
if string.match(debug.traceback(), "/rom/apis/rednet.lua") then
print("[D] Rednet called os.pullEventRaw, crashing")
error("nya")
end
end
return table.unpack(a)
end
local p = _G.printError
_G.printError = function()
print("[D] Got printError call, cleaning and jumping to kernel")
_G.printError = p
_G.os.pullEventRaw = o
_G["rednet"] = nil
os.run({
-- This is an odd hack. We should look into not doing this to run the kernel.
["require"]=require
}, "/kernel/entry.lua")
end
print("[D] Queueing bogus modem message")
os.queueEvent("modem_message")
end
main()

View File

@@ -4,7 +4,7 @@
open index.json open index.json
| each {|entry| | each {|entry|
{src: $entry.src, dest: $entry.dest, {src: $entry.src, dest: $entry.dest,
hash: (cat $entry.src | hash sha256)} hash: (open $entry.src | hash sha256)}
} }
| collect | collect
| save -f index.json | save -f index.json