12pink

os_init.lua

Apr 24th, 2025 (edited)
439
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.62 KB | None | 0 0
  1. local signal_src = [[
  2. -- -----------------------------------------------------------------------------
  3. --               Batched Yield-Safe Signal Implementation                     --
  4. -- This is a Signal class which has effectively identical behavior to a       --
  5. -- normal RBXScriptSignal, with the only difference being a couple extra      --
  6. -- stack frames at the bottom of the stack trace when an error is thrown.     --
  7. -- This implementation caches runner coroutines, so the ability to yield in   --
  8. -- the signal handlers comes at minimal extra cost over a naive signal        --
  9. -- implementation that either always or never spawns a thread.                --
  10. --                                                                            --
  11. -- License:                                                                   --
  12. --   Licensed under the MIT license.                                          --
  13. --                                                                            --
  14. -- Authors:                                                                   --
  15. --   stravant - July 31st, 2021 - Created the file.                           --
  16. --   sleitnick - August 3rd, 2021 - Modified for Knit.                        --
  17. -- -----------------------------------------------------------------------------
  18.  
  19. -- Signal types
  20. export type Connection = {
  21.     Disconnect: (self: Connection) -> (),
  22.     Destroy: (self: Connection) -> (),
  23.     Connected: boolean,
  24. }
  25.  
  26. export type Signal<T...> = {
  27.     Fire: (self: Signal<T...>, T...) -> (),
  28.     FireDeferred: (self: Signal<T...>, T...) -> (),
  29.     Connect: (self: Signal<T...>, fn: (T...) -> ()) -> Connection,
  30.     Once: (self: Signal<T...>, fn: (T...) -> ()) -> Connection,
  31.     DisconnectAll: (self: Signal<T...>) -> (),
  32.     GetConnections: (self: Signal<T...>) -> { Connection },
  33.     Destroy: (self: Signal<T...>) -> (),
  34.     Wait: (self: Signal<T...>) -> T...,
  35. }
  36.  
  37. -- The currently idle thread to run the next handler on
  38. local freeRunnerThread = nil
  39.  
  40. -- Function which acquires the currently idle handler runner thread, runs the
  41. -- function fn on it, and then releases the thread, returning it to being the
  42. -- currently idle one.
  43. -- If there was a currently idle runner thread already, that's okay, that old
  44. -- one will just get thrown and eventually GCed.
  45. local function acquireRunnerThreadAndCallEventHandler(fn, ...)
  46.     local acquiredRunnerThread = freeRunnerThread
  47.     freeRunnerThread = nil
  48.     fn(...)
  49.     -- The handler finished running, this runner thread is free again.
  50.     freeRunnerThread = acquiredRunnerThread
  51. end
  52.  
  53. -- Coroutine runner that we create coroutines of. The coroutine can be
  54. -- repeatedly resumed with functions to run followed by the argument to run
  55. -- them with.
  56. local function runEventHandlerInFreeThread(...)
  57.     acquireRunnerThreadAndCallEventHandler(...)
  58.     while true do
  59.         acquireRunnerThreadAndCallEventHandler(coroutine.yield())
  60.     end
  61. end
  62.  
  63. --[=[
  64.     @within Signal
  65.     @interface SignalConnection
  66.     .Connected boolean
  67.     .Disconnect (SignalConnection) -> ()
  68.  
  69.     Represents a connection to a signal.
  70.     ```lua
  71.     local connection = signal:Connect(function() end)
  72.     print(connection.Connected) --> true
  73.     connection:Disconnect()
  74.     print(connection.Connected) --> false
  75.     ```
  76. ]=]
  77.  
  78. -- Connection class
  79. local Connection = {}
  80. Connection.__index = Connection
  81.  
  82. function Connection:Disconnect()
  83.     if not self.Connected then
  84.         return
  85.     end
  86.     self.Connected = false
  87.  
  88.     -- Unhook the node, but DON'T clear it. That way any fire calls that are
  89.     -- currently sitting on this node will be able to iterate forwards off of
  90.     -- it, but any subsequent fire calls will not hit it, and it will be GCed
  91.     -- when no more fire calls are sitting on it.
  92.     if self._signal._handlerListHead == self then
  93.         self._signal._handlerListHead = self._next
  94.     else
  95.         local prev = self._signal._handlerListHead
  96.         while prev and prev._next ~= self do
  97.             prev = prev._next
  98.         end
  99.         if prev then
  100.             prev._next = self._next
  101.         end
  102.     end
  103. end
  104.  
  105. Connection.Destroy = Connection.Disconnect
  106.  
  107. -- Make Connection strict
  108. setmetatable(Connection, {
  109.     __index = function(_tb, key)
  110.         error(("Attempt to get Connection::%s (not a valid member)"):format(tostring(key)), 2)
  111.     end,
  112.     __newindex = function(_tb, key, _value)
  113.         error(("Attempt to set Connection::%s (not a valid member)"):format(tostring(key)), 2)
  114.     end,
  115. })
  116.  
  117. --[=[
  118.     @within Signal
  119.     @type ConnectionFn (...any) -> ()
  120.  
  121.     A function connected to a signal.
  122. ]=]
  123.  
  124. --[=[
  125.     @class Signal
  126.  
  127.     A Signal is a data structure that allows events to be dispatched
  128.     and observed.
  129.  
  130.     This implementation is a direct copy of the de facto standard, [GoodSignal](https://devforum.roblox.com/t/lua-signal-class-comparison-optimal-goodsignal-class/1387063),
  131.     with some added methods and typings.
  132.  
  133.     For example:
  134.     ```lua
  135.     local signal = Signal.new()
  136.  
  137.     -- Subscribe to a signal:
  138.     signal:Connect(function(msg)
  139.         print("Got message:", msg)
  140.     end)
  141.  
  142.     -- Dispatch an event:
  143.     signal:Fire("Hello world!")
  144.     ```
  145. ]=]
  146. local Signal = {}
  147. Signal.__index = Signal
  148.  
  149. --[=[
  150.     Constructs a new Signal
  151.  
  152.     @return Signal
  153. ]=]
  154. function Signal.new<T...>(): Signal<T...>
  155.     local self = setmetatable({
  156.         _handlerListHead = false,
  157.         _proxyHandler = nil,
  158.         _yieldedThreads = nil,
  159.     }, Signal)
  160.  
  161.     return self
  162. end
  163.  
  164. --[=[
  165.     Constructs a new Signal that wraps around an RBXScriptSignal.
  166.  
  167.     @param rbxScriptSignal RBXScriptSignal -- Existing RBXScriptSignal to wrap
  168.     @return Signal
  169.  
  170.     For example:
  171.     ```lua
  172.     local signal = Signal.Wrap(workspace.ChildAdded)
  173.     signal:Connect(function(part) print(part.Name .. " added") end)
  174.     Instance.new("Part").Parent = workspace
  175.     ```
  176. ]=]
  177. function Signal.Wrap<T...>(rbxScriptSignal: RBXScriptSignal): Signal<T...>
  178.     assert(
  179.         typeof(rbxScriptSignal) == "RBXScriptSignal",
  180.         "Argument #1 to Signal.Wrap must be a RBXScriptSignal; got " .. typeof(rbxScriptSignal)
  181.     )
  182.  
  183.     local signal = Signal.new()
  184.     signal._proxyHandler = rbxScriptSignal:Connect(function(...)
  185.         signal:Fire(...)
  186.     end)
  187.  
  188.     return signal
  189. end
  190.  
  191. --[=[
  192.     Checks if the given object is a Signal.
  193.  
  194.     @param obj any -- Object to check
  195.     @return boolean -- `true` if the object is a Signal.
  196. ]=]
  197. function Signal.Is(obj: any): boolean
  198.     return type(obj) == "table" and getmetatable(obj) == Signal
  199. end
  200.  
  201. --[=[
  202.     @param fn ConnectionFn
  203.     @return SignalConnection
  204.  
  205.     Connects a function to the signal, which will be called anytime the signal is fired.
  206.     ```lua
  207.     signal:Connect(function(msg, num)
  208.         print(msg, num)
  209.     end)
  210.  
  211.     signal:Fire("Hello", 25)
  212.     ```
  213. ]=]
  214. function Signal:Connect(fn)
  215.     local connection = setmetatable({
  216.         Connected = true,
  217.         _signal = self,
  218.         _fn = fn,
  219.         _next = false,
  220.     }, Connection)
  221.  
  222.     if self._handlerListHead then
  223.         connection._next = self._handlerListHead
  224.         self._handlerListHead = connection
  225.     else
  226.         self._handlerListHead = connection
  227.     end
  228.  
  229.     return connection
  230. end
  231.  
  232. --[=[
  233.     @deprecated v1.3.0 -- Use `Signal:Once` instead.
  234.     @param fn ConnectionFn
  235.     @return SignalConnection
  236. ]=]
  237. function Signal:ConnectOnce(fn)
  238.     return self:Once(fn)
  239. end
  240.  
  241. --[=[
  242.     @param fn ConnectionFn
  243.     @return SignalConnection
  244.  
  245.     Connects a function to the signal, which will be called the next time the signal fires. Once
  246.     the connection is triggered, it will disconnect itself.
  247.     ```lua
  248.     signal:Once(function(msg, num)
  249.         print(msg, num)
  250.     end)
  251.  
  252.     signal:Fire("Hello", 25)
  253.     signal:Fire("This message will not go through", 10)
  254.     ```
  255. ]=]
  256. function Signal:Once(fn)
  257.     local connection
  258.     local done = false
  259.  
  260.     connection = self:Connect(function(...)
  261.         if done then
  262.             return
  263.         end
  264.  
  265.         done = true
  266.         connection:Disconnect()
  267.         fn(...)
  268.     end)
  269.  
  270.     return connection
  271. end
  272.  
  273. function Signal:GetConnections()
  274.     local items = {}
  275.  
  276.     local item = self._handlerListHead
  277.     while item do
  278.         table.insert(items, item)
  279.         item = item._next
  280.     end
  281.  
  282.     return items
  283. end
  284.  
  285. -- Disconnect all handlers. Since we use a linked list it suffices to clear the
  286. -- reference to the head handler.
  287. --[=[
  288.     Disconnects all connections from the signal.
  289.     ```lua
  290.     signal:DisconnectAll()
  291.     ```
  292. ]=]
  293. function Signal:DisconnectAll()
  294.     local item = self._handlerListHead
  295.     while item do
  296.         item.Connected = false
  297.         item = item._next
  298.     end
  299.     self._handlerListHead = false
  300.  
  301.     --local yieldedThreads = rawget(self, "_yieldedThreads")
  302.     local yieldedThreads = self._yieldedThreads
  303.     if yieldedThreads then
  304.         for thread in yieldedThreads do
  305.             if coroutine.status(thread) == "suspended" then
  306.                 warn(debug.traceback(thread, "signal disconnected; yielded thread cancelled", 2))
  307.                 task.cancel(thread)
  308.             end
  309.         end
  310.         table.clear(self._yieldedThreads)
  311.     end
  312. end
  313.  
  314. -- Signal:Fire(...) implemented by running the handler functions on the
  315. -- coRunnerThread, and any time the resulting thread yielded without returning
  316. -- to us, that means that it yielded to the Roblox scheduler and has been taken
  317. -- over by Roblox scheduling, meaning we have to make a new coroutine runner.
  318. --[=[
  319.     @param ... any
  320.  
  321.     Fire the signal, which will call all of the connected functions with the given arguments.
  322.     ```lua
  323.     signal:Fire("Hello")
  324.  
  325.     -- Any number of arguments can be fired:
  326.     signal:Fire("Hello", 32, {Test = "Test"}, true)
  327.     ```
  328. ]=]
  329. function Signal:Fire(...)
  330.     local item = self._handlerListHead
  331.     while item do
  332.         if item.Connected then
  333.             if not freeRunnerThread then
  334.                 freeRunnerThread = coroutine.create(runEventHandlerInFreeThread)
  335.             end
  336.             task.spawn(freeRunnerThread, item._fn, ...)
  337.         end
  338.         item = item._next
  339.     end
  340. end
  341.  
  342. --[=[
  343.     @param ... any
  344.  
  345.     Same as `Fire`, but uses `task.defer` internally & doesn't take advantage of thread reuse.
  346.     ```lua
  347.     signal:FireDeferred("Hello")
  348.     ```
  349. ]=]
  350. function Signal:FireDeferred(...)
  351.     local item = self._handlerListHead
  352.     while item do
  353.         local conn = item
  354.         task.defer(function(...)
  355.             if conn.Connected then
  356.                 conn._fn(...)
  357.             end
  358.         end, ...)
  359.         item = item._next
  360.     end
  361. end
  362.  
  363. --[=[
  364.     @return ... any
  365.     @yields
  366.  
  367.     Yields the current thread until the signal is fired, and returns the arguments fired from the signal.
  368.     Yielding the current thread is not always desirable. If the desire is to only capture the next event
  369.     fired, using `Once` might be a better solution.
  370.     ```lua
  371.     task.spawn(function()
  372.         local msg, num = signal:Wait()
  373.         print(msg, num) --> "Hello", 32
  374.     end)
  375.     signal:Fire("Hello", 32)
  376.     ```
  377. ]=]
  378. function Signal:Wait()
  379.     --local yieldedThreads = rawget(self, "_yieldedThreads")
  380.     local yieldedThreads = self._yieldedThreads
  381.     if not yieldedThreads then
  382.         yieldedThreads = {}
  383.         --rawset(self, "_yieldedThreads", yieldedThreads)
  384.         self._yieldedThreads = yieldedThreads
  385.     end
  386.  
  387.     local thread = coroutine.running()
  388.     yieldedThreads[thread] = true
  389.  
  390.     self:Once(function(...)
  391.         yieldedThreads[thread] = nil
  392.  
  393.         if coroutine.status(thread) == "suspended" then
  394.             task.spawn(thread, ...)
  395.         end
  396.     end)
  397.  
  398.     return coroutine.yield()
  399. end
  400.  
  401. --[=[
  402.     Cleans up the signal.
  403.  
  404.     Technically, this is only necessary if the signal is created using
  405.     `Signal.Wrap`. Connections should be properly GC'd once the signal
  406.     is no longer referenced anywhere. However, it is still good practice
  407.     to include ways to strictly clean up resources. Calling `Destroy`
  408.     on a signal will also disconnect all connections immediately.
  409.     ```lua
  410.     signal:Destroy()
  411.     ```
  412. ]=]
  413. function Signal:Destroy()
  414.     self:DisconnectAll()
  415.  
  416.     --local proxyHandler = rawget(self, "_proxyHandler")
  417.     local proxyHandler = self._proxyHandler
  418.     if proxyHandler then
  419.         proxyHandler:Disconnect()
  420.     end
  421. end
  422.  
  423. -- -- im evil. make signal NOT strict >:)
  424. -- Make signal strict
  425. --setmetatable(Signal, {
  426. --  __index = function(_tb, key)
  427. --      error(("Attempt to get Signal::%s (not a valid member)"):format(tostring(key)), 2)
  428. --  end,
  429. --  __newindex = function(_tb, key, _value)
  430. --      error(("Attempt to set Signal::%s (not a valid member)"):format(tostring(key)), 2)
  431. --  end,
  432. --})
  433.  
  434. return table.freeze({
  435.     new = Signal.new,
  436.     Wrap = Signal.Wrap,
  437.     Is = Signal.Is,
  438. })
  439. ]]
  440.  
  441.  
  442. local init_dirs = {"/bin", "/etc", "/lib", "/boot"}
  443.  
  444. for _, dir in init_dirs do
  445.     fs:mkdir(dir)
  446. end
  447.  
  448. --// Binaries
  449. fs:writefile("/bin/ls.lua", [[
  450. return function(args)
  451.     local path = args[1] or fs:pwd()
  452.     local dirs = fs:readdir(path)
  453.     table.insert(dirs, 1, "..")
  454.     local concatted = table.concat(dirs, "  ")
  455.     print(concatted)
  456.     stdout("Directory listing of " .. fs:resolve(path))
  457.     stdout(concatted)
  458.     return -1
  459. end]])
  460. fs:writefile("/bin/mkdir.lua", [[
  461. return function(args)
  462.     if not args[1] then
  463.         stdout("No directory provided")
  464.         return 1
  465.     end
  466.     fs:mkdir(args[1])
  467.     return -1
  468. end]])
  469. fs:writefile("/bin/dl.lua", [[
  470. return function(args)
  471.     local modem = require("/dev/modem")
  472.     response = modem:GetAsync(args[1])
  473.     fs:writefile(args[2], response)
  474. end]])
  475. fs:writefile("/bin/cat.lua", [[
  476. return function(args)
  477.     stdout(fs:readfile(args[1]))
  478.     print(fs:readfile(args[1]))
  479.     return -1
  480. end]])
  481. fs:writefile("/bin/dbg_print_ring.lua", [[
  482. return function(args)
  483.     stdout(pilot.getRing())
  484.     return -1
  485. end]])
  486. fs:writefile("/bin/shutdown.lua", [[return function(args)
  487.     syscall.shutdown()
  488. end]])
  489. fs:writefile("/bin/repr_test.lua", [[return function(args)
  490.     print(require("repr")(fs._Fs))
  491. end]])
  492. fs:writefile("/boot/tasks.lua", [[return function(args)
  493.     print("lua profile")
  494. end]])
  495. fs:writefile("/bin/trigger.lua", [[return function(args)
  496.     syscall.trigger_port(tonumber(args[1]))
  497.     return -1
  498. end]])
  499.     fs:writefile("/bin/wipedisk.lua", [[return function(args)
  500.         require("/dev/disk"):WriteAll{}
  501. syscall.shutdown()
  502.         stdout("Disk wiped")
  503.         return -1
  504.     end]])
  505.     fs:writefile("/bin/exists.lua", [[return function(args)
  506.         stdout(fs:exists(args[1]))
  507.         return -1
  508.     end]])
  509.     fs:writefile("/bin/rm.lua", [[return function(args)
  510.         fs:remove(args[1])
  511.     end]])
  512.  
  513.  
  514. --// Libraries
  515. fs:writefile("/lib/signal.lua", signal_src)
  516.  
  517. --fs:writefile("/boot/tasks.lua", [[return function(args)
  518. --    syscall.exec_code(fs:readfile())
  519. --end]])
  520.  
  521. local function send_inp_to_pid(pid, inp)
  522.     local is_pid_open = fs:exists("/proc/"..pid)
  523.     if not is_pid_open then return end
  524.    
  525.     require("/proc/"..pid.."/event/stdin"):Fire(inp)
  526. end
  527.  
  528. fs:writefile("/bin/getcharge.lua", [[return function(args)
  529.     local capacity = fs:readfile("/sys/power/capacity")
  530.     local remaining = fs:readfile("/sys/power/remaining")
  531.     stdout(
  532.         math.round(
  533.             (remaining / capacity)*100
  534.         ) ..
  535.         " % remaining (" .. remaining.. " / " .. capacity .. " )")
  536. end]])
  537.  
  538. fs:writefile("/bin/shell.lua", [[return function(args, pid)
  539.     print("start")
  540.     local stdin = require("/proc/"..pid.."/event/stdin")
  541.     while task.wait() do
  542.         local input = stdin:Wait()
  543.         print("Input!")
  544.         print(input)
  545.    
  546.         if input:sub(1,1) == "\n" then input = input:sub(2) end
  547.    
  548.         local args = input:split(" ")
  549.         local cmd = args[1]
  550.         table.remove(args,1)
  551.    
  552.         if cmd == "pwd" then
  553.             stdout(fs:pwd())
  554.         elseif cmd == "cd" then
  555.             fs:chdir(args[1])
  556.         else
  557.             local found_path
  558.    
  559.             local testpath_1 = "/bin/"..cmd..".lua"
  560.             local cwd = fs:pwd()
  561.             if cwd:sub(-1) == "/" then cwd = cwd:sub(1, -2) end
  562.             local testpath_2 = cwd.."/"..cmd..".lua"
  563.  
  564.             print(testpath_1)
  565.             print(testpath_2)
  566.        
  567.             if fs:exists(testpath_1) then
  568.                 found_path = testpath_1
  569.             elseif fs:exists(testpath_2) then
  570.                 found_path = testpath_2
  571.             end
  572.            
  573.             if not found_path then
  574.                 stdout("Binary not found.")
  575.                 continue
  576.             end
  577.            
  578.             local pid, thread = syscall.exec_code(fs:readfile(found_path), args)
  579.             local relayConnection = stdin:Connect(function(inp)
  580.                 send_input_to_pid(pid, inp)
  581.             end)
  582.             repeat task.wait() until coroutine.status(thread) == "dead"
  583.             relayConnection:Disconnect()
  584.         end
  585.     end
  586. end]])
Advertisement
Add Comment
Please, Sign In to add comment