1
0
mirror of https://github.com/kepler155c/opus synced 2025-05-01 15:04:13 +00:00

move multishell functionality to kernel

This commit is contained in:
kepler155c@gmail.com 2018-01-10 16:46:37 -05:00
parent 13ec8ea04f
commit d224f5df25
20 changed files with 467 additions and 409 deletions

View File

@ -58,33 +58,37 @@ local function nextUID()
return Event.uid - 1
end
function Event.on(event, fn)
function Event.on(events, fn)
events = type(events) == 'table' and events or { events }
local handler = setmetatable({
uid = nextUID(),
event = events,
fn = fn,
}, { __index = Routine })
for _,event in pairs(events) do
local handlers = Event.types[event]
if not handlers then
handlers = { }
Event.types[event] = handlers
end
local handler = {
uid = nextUID(),
event = event,
fn = fn,
}
handlers[handler.uid] = handler
setmetatable(handler, { __index = Routine })
end
return handler
end
function Event.off(h)
if h and h.event then
Event.types[h.event][h.uid] = nil
for _,event in pairs(h.event) do
Event.types[event][h.uid] = nil
end
end
end
local function addTimer(interval, recurring, fn)
local timerId = os.startTimer(interval)
local handler
@ -133,20 +137,18 @@ function Event.waitForEvent(event, timeout)
end
function Event.addRoutine(fn)
local r = {
local r = setmetatable({
co = coroutine.create(fn),
uid = nextUID()
}
setmetatable(r, { __index = Routine })
Event.routines[r.uid] = r
}, { __index = Routine })
Event.routines[r.uid] = r
r:resume()
return r
end
function Event.pullEvents(...)
for _, fn in ipairs({ ... }) do
Event.addRoutine(fn)
end
@ -162,7 +164,6 @@ function Event.exitPullEvents()
end
local function processHandlers(event)
local handlers = Event.types[event]
if handlers then
for _,h in pairs(handlers) do
@ -184,7 +185,6 @@ local function tokeys(t)
end
local function processRoutines(...)
local keys = tokeys(Event.routines)
for _,key in ipairs(keys) do
local r = Event.routines[key]
@ -200,7 +200,6 @@ function Event.processEvent(e)
end
function Event.pullEvent(eventType)
while true do
local e = { os.pullEventRaw() }

View File

@ -1,5 +1,6 @@
local Util = require('util')
local keyboard = _G.device.keyboard
local keys = _G.keys
local os = _G.os
@ -10,28 +11,31 @@ local modifiers = Util.transpose {
}
local input = {
pressed = { },
state = { },
}
function input:modifierPressed()
return self.pressed[keys.leftCtrl] or
self.pressed[keys.rightCtrl] or
self.pressed[keys.leftAlt] or
self.pressed[keys.rightAlt]
return keyboard.state[keys.leftCtrl] or
keyboard.state[keys.rightCtrl] or
keyboard.state[keys.leftAlt] or
keyboard.state[keys.rightAlt]
end
function input:toCode(ch, code)
local result = { }
if self.pressed[keys.leftCtrl] or self.pressed[keys.rightCtrl] then
if keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl] or
code == keys.leftCtrl or code == keys.rightCtrl then
table.insert(result, 'control')
end
if self.pressed[keys.leftAlt] or self.pressed[keys.rightAlt] then
if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or
code == keys.leftAlt or code == keys.rightAlt then
table.insert(result, 'alt')
end
if self.pressed[keys.leftShift] or self.pressed[keys.rightShift] then
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or
code == keys.leftShift or code == keys.rightShift then
if code and modifiers[code] then
table.insert(result, 'shift')
elseif #ch == 1 then
@ -48,7 +52,7 @@ function input:toCode(ch, code)
end
function input:reset()
self.pressed = { }
self.state = { }
self.fired = nil
self.timer = nil
@ -64,7 +68,7 @@ function input:translate(event, code, p1, p2)
return input:toCode(keys.getName(code), code)
end
else
self.pressed[code] = true
self.state[code] = true
if self:modifierPressed() and not modifiers[code] or code == 57 then
self.fired = true
return input:toCode(keys.getName(code), code)
@ -81,18 +85,18 @@ function input:translate(event, code, p1, p2)
elseif event == 'key_up' then
if not self.fired then
if self.pressed[code] then
if self.state[code] then
self.fired = true
local ch = input:toCode(keys.getName(code), code)
self.pressed[code] = nil
self.state[code] = nil
return ch
end
end
self.pressed[code] = nil
self.state[code] = nil
elseif event == 'paste' then
self.pressed[keys.leftCtrl] = nil
self.pressed[keys.rightCtrl] = nil
--self.state[keys.leftCtrl] = nil
--self.state[keys.rightCtrl] = nil
self.fired = true
return input:toCode('paste', 255)

View File

@ -68,6 +68,7 @@ local function encodeCommon(val, pretty, tabLevel, tTracking)
str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
end)
else
debug(val)
arrEncoding(val, "{", "}", pairs, function(k,v)
assert(type(k) == "string", "JSON object keys must be strings", 2)
str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
@ -94,6 +95,13 @@ function json.encodePretty(val)
return encodeCommon(val, true, 0, {})
end
function json.encodeToFile(path, val)
local file = io.open(path, "w")
assert(file, "Unable to open file")
file:write(json.encodePretty(val))
file:close()
end
------------------------------------------------------------------ decoding
local decodeControls = {}

View File

@ -2,6 +2,8 @@ local Event = require('event')
local Socket = require('socket')
local Util = require('util')
local os = _G.os
local Peripheral = Util.shallowCopy(_G.peripheral)
function Peripheral.getList()
@ -176,12 +178,12 @@ local function getProxy(pi)
if proxy.type == 'monitor' then
Event.addRoutine(function()
while true do
local event = socket:read()
if not event then
local data = socket:read()
if not data then
break
end
if not Util.empty(event) then
os.queueEvent(table.unpack(event))
if data.fn and data.fn == 'event' then
os.queueEvent(table.unpack(data.data))
end
end
end)

View File

@ -43,26 +43,23 @@ end
--[[-- Top Level Manager --]]--
local Manager = class()
function Manager:init()
local running = false
local function keyFunction(event, code, held)
local ch = Input:translate(event, code, held)
-- single thread all input events
local function singleThread(event, fn)
Event.on(event, function(_, ...)
if not running then
running = true
fn(...)
running = false
else
Input:translate(event, ...)
if ch and self.currentPage then
local target = self.currentPage.focused or self.currentPage
self:inputEvent(target,
{ type = 'key', key = ch, element = target })
self.currentPage:sync()
end
end)
end
Event.on('multishell_focus', function()
Input:reset()
end)
local handlers = {
char = keyFunction,
key_up = keyFunction,
key = keyFunction,
singleThread('term_resize', function(side)
term_resize = function(_, side)
if self.currentPage then
-- the parent doesn't have any children set...
-- that's why we have to resize both the parent and the current page
@ -75,9 +72,9 @@ function Manager:init()
self.currentPage:sync()
end
end
end)
end,
singleThread('mouse_scroll', function(direction, x, y)
mouse_scroll = function(_, direction, x, y)
if self.currentPage then
local event = self.currentPage:pointToChild(x, y)
local directions = {
@ -90,18 +87,20 @@ function Manager:init()
{ type = 'key', key = directions[direction] })
self.currentPage:sync()
end
end)
end,
-- this should be moved to the device !
singleThread('monitor_touch', function(side, x, y)
monitor_touch = function(_, side, x, y)
Input:translate('mouse_click', 1, x, y)
local ch = Input:translate('mouse_up', 1, x, y)
if self.currentPage then
if self.currentPage.parent.device.side == side then
self:click('mouse_click', 1, x, y)
self:click(ch, 1, x, y)
end
end
end)
end,
singleThread('mouse_click', function(button, x, y)
mouse_click = function(_, button, x, y)
Input:translate('mouse_click', button, x, y)
if self.currentPage then
@ -113,9 +112,9 @@ function Manager:init()
end
end
end
end)
end,
singleThread('mouse_up', function(button, x, y)
mouse_up = function(_, button, x, y)
local ch = Input:translate('mouse_up', button, x, y)
if ch == 'control-shift-mouse_click' then -- hack
@ -130,9 +129,9 @@ function Manager:init()
self:click(ch, button, x, y)
end
end
end)
end,
singleThread('mouse_drag', function(button, x, y)
mouse_drag = function(_, button, x, y)
local ch = Input:translate('mouse_drag', button, x, y)
if ch and self.currentPage then
local event = self.currentPage:pointToChild(x, y)
@ -140,28 +139,23 @@ function Manager:init()
self:inputEvent(event.element, event)
self.currentPage:sync()
end
end)
end,
singleThread('paste', function(text)
paste = function(_, text)
Input:translate('paste')
self:emitEvent({ type = 'paste', text = text })
self.currentPage:sync()
end,
}
-- use 1 handler to single thread all events
Event.on({
'char', 'key_up', 'key', 'term_resize',
'mouse_scroll', 'monitor_touch', 'mouse_click',
'mouse_up', 'mouse_drag', 'paste' },
function(event, ...)
handlers[event](event, ...)
end)
local function keyFunction(event, code, held)
local ch = Input:translate(event, code, held)
if ch and self.currentPage then
local target = self.currentPage.focused or self.currentPage
self:inputEvent(target,
{ type = 'key', key = ch, element = target })
self.currentPage:sync()
end
end
singleThread('char', function(code, held) keyFunction('char', code, held) end)
singleThread('key_up', function(code, held) keyFunction('key_up', code, held) end)
singleThread('key', function(code, held) keyFunction('key', code, held) end)
end
function Manager:configure(appName, ...)

View File

@ -460,6 +460,8 @@ function Util.toBytes(n)
if not tonumber(n) then error('Util.toBytes: n must be a number', 2) end
if n >= 1000000 or n <= -1000000 then
return string.format('%sM', math.floor(n/1000000 * 10) / 10)
elseif n >= 10000 or n <= -10000 then
return string.format('%sK', math.floor(n/1000))
elseif n >= 1000 or n <= -1000 then
return string.format('%sK', math.floor(n/1000 * 10) / 10)
end
@ -549,7 +551,6 @@ end
-- end word wrapping
function Util.wordWrap(str, limit)
local longLines = Util.split(str)
local lines = { }
@ -560,6 +561,23 @@ function Util.wordWrap(str, limit)
return lines
end
function Util.args(arg)
local tab = { remainder = { } }
local k = 1
while k <= #arg do
local v = arg[k]
if string.sub(v, 1, 1) == '-' then
local jopt = string.sub(v, 2)
tab[ jopt ] = arg[ k + 1 ]
k = k + 1
else
table.insert(tab.remainder, v)
end
k = k + 1
end
return tab
end
-- http://lua-users.org/wiki/AlternativeGetOpt
local function getopt( arg, options )
local tab = {}

View File

@ -6,11 +6,12 @@ end
_G.requireInjector()
local Config = require('config')
local Input = require('input')
local Util = require('util')
local colors = _G.colors
local fs = _G.fs
local kernel = _G.kernel
local keyboard = _G.device.keyboard
local keys = _G.keys
local multishell = _ENV.multishell
local os = _G.os
@ -28,8 +29,6 @@ local overviewId
local runningTab
local tabsDirty = false
local closeInd = '*'
local hooks = { }
local hotkeys = { }
local downState = { }
multishell.term = term.current()
@ -124,11 +123,11 @@ local function selectTab(tab)
if currentTab and currentTab ~= tab then
currentTab.window.setVisible(false)
if coroutine.status(currentTab.co) == 'suspended' then
--if coroutine.status(currentTab.co) == 'suspended' then
-- the process that opens a new tab won't get the lose focus event
-- os.queueEvent('multishell_notifyfocus', currentTab.tabId)
--resumeTab(currentTab, 'multishell_losefocus')
end
--end
if tab and not currentTab.hidden then
tab.previousTabId = currentTab.tabId
end
@ -137,7 +136,9 @@ local function selectTab(tab)
if tab ~= currentTab then
currentTab = tab
tab.window.setVisible(true)
resumeTab(tab, 'multishell_focus')
Util.clear(keyboard.state) --- reset keyboard state
-- why not just queue event with tab ID if we want to notify
--resumeTab(tab, 'multishell_focus')
end
end
@ -197,14 +198,6 @@ local function launchProcess(tab)
return tab
end
function multishell.addHotkey(code, fn)
hotkeys[code] = fn
end
function multishell.removeHotkey(code)
hotkeys[code] = nil
end
function multishell.getFocus()
return currentTab.tabId
end
@ -309,31 +302,7 @@ function multishell.getCount()
return Util.size(tabs)
end
function multishell.hook(event, fn)
if type(event) == 'table' then
for _,v in pairs(event) do
multishell.hook(v, fn)
end
else
if not hooks[event] then
hooks[event] = { }
end
table.insert(hooks[event], fn)
end
end
-- you can only unhook from within the function that hooked
function multishell.unhook(event, fn)
local eventHooks = hooks[event]
if eventHooks then
Util.removeByValue(eventHooks, fn)
if #eventHooks == 0 then
hooks[event] = nil
end
end
end
multishell.hook('multishell_terminate', function(_, eventData)
kernel.hook('multishell_terminate', function(_, eventData)
local tabId = eventData[1] or -1
local tab = tabs[tabId]
@ -345,7 +314,7 @@ multishell.hook('multishell_terminate', function(_, eventData)
return true
end)
multishell.hook('multishell_redraw', function()
kernel.hook('multishell_redraw', function()
tabsDirty = false
local function write(x, text, bg, fg)
@ -413,7 +382,7 @@ multishell.hook('multishell_redraw', function()
return true
end)
multishell.hook('term_resize', function(_, eventData)
kernel.hook('term_resize', function(_, eventData)
if not eventData[1] then --- TEST
w,h = parentTerm.getSize()
@ -433,40 +402,16 @@ multishell.hook('term_resize', function(_, eventData)
end
end)
-- downstate should be stored in the tab (maybe)
multishell.hook('key_up', function(_, eventData)
--[[
kernel.hook('key_up', function(_, eventData)
local code = eventData[1]
if downState[code] ~= currentTab then
downState[code] = nil
if not keyboard.state[code] then
return true
end
downState[code] = nil
end)
]]
multishell.hook('key', function(_, eventData)
local code = eventData[1]
local firstPress = not eventData[2]
if firstPress then
downState[code] = currentTab
else
--key was pressed initially in a previous window
if downState[code] ~= currentTab then
return true
end
end
end)
multishell.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData)
local code = Input:translate(event, eventData[1], eventData[2])
if code and hotkeys[code] then
hotkeys[code](event, eventData)
end
end)
multishell.hook('mouse_click', function(_, eventData)
kernel.hook('mouse_click', function(_, eventData)
local x, y = eventData[2], eventData[3]
if y == 1 then
if x == 1 then
@ -492,7 +437,7 @@ multishell.hook('mouse_click', function(_, eventData)
eventData[3] = eventData[3] - 1
end)
multishell.hook({ 'mouse_up', 'mouse_drag' }, function(event, eventData)
kernel.hook({ 'mouse_up', 'mouse_drag' }, function(event, eventData)
if downState.mouse ~= currentTab then
-- don't send mouse up as the mouse click event was on another window
if event == 'mouse_up' then
@ -504,7 +449,7 @@ multishell.hook({ 'mouse_up', 'mouse_drag' }, function(event, eventData)
eventData[3] = eventData[3] - 1
end)
multishell.hook('mouse_scroll', function(_, eventData)
kernel.hook('mouse_scroll', function(_, eventData)
local dir, y = eventData[1], eventData[3]
if y == 1 then
@ -592,7 +537,7 @@ while true do
local sEvent = table.remove(tEventData, 1)
local stopPropagation
local eventHooks = hooks[sEvent]
local eventHooks = kernel.hooks[sEvent]
if eventHooks then
for i = #eventHooks, 1, -1 do
stopPropagation = eventHooks[i](sEvent, tEventData)

View File

@ -5,21 +5,25 @@ local Socket = require('socket')
local Terminal = require('terminal')
local Util = require('util')
local multishell = _ENV.multishell
local os = _G.os
local read = _G.read
local term = _G.term
local remoteId
local args = { ... }
if #args == 1 then
remoteId = tonumber(args[1])
else
local args = Util.args({ ... })
local remoteId = tonumber(table.remove(args.remainder, 1))
if not remoteId then
print('Enter host ID')
remoteId = tonumber(read())
end
if not remoteId then
error('Syntax: telnet <host ID>')
error('Syntax: telnet [-title TITLE] ID [PROGRAM]')
end
if args.title then
multishell.setTitle(multishell.getCurrent(), args.title)
end
print('connecting...')
@ -39,6 +43,7 @@ socket:write({
width = w,
height = h,
isColor = ct.isColor(),
program = args.remainder,
})
Event.addRoutine(function()
@ -48,7 +53,7 @@ Event.addRoutine(function()
break
end
for _,v in ipairs(data) do
ct[v.f](unpack(v.args))
ct[v.f](table.unpack(v.args))
end
end
end)

View File

@ -2,16 +2,17 @@ _G.requireInjector()
local Util = require('util')
local multishell = _ENV.multishell
local kernel = _G.kernel
local keyboard = _G.device.keyboard
local textutils = _G.textutils
local data
multishell.hook('clipboard_copy', function(_, args)
kernel.hook('clipboard_copy', function(_, args)
data = args[1]
end)
multishell.addHotkey('shift-paste', function(_, args)
keyboard.addHotkey('shift-paste', function(_, args)
if type(data) == 'table' then
local s, m = pcall(textutils.serialize, data)
data = (s and m) or Util.tostring(data)

View File

@ -2,10 +2,11 @@ _G.requireInjector()
local Util = require('util')
local keyboard = _G.device.keyboard
local multishell = _ENV.multishell
-- overview
multishell.addHotkey('control-o', function()
keyboard.addHotkey('control-o', function()
for _,tab in pairs(multishell.getTabs()) do
if tab.isOverview then
multishell.setFocus(tab.tabId)
@ -14,7 +15,7 @@ multishell.addHotkey('control-o', function()
end)
-- restart tab
multishell.addHotkey('control-backspace', function()
keyboard.addHotkey('control-backspace', function()
local tabs = multishell.getTabs()
local tabId = multishell.getFocus()
local tab = tabs[tabId]
@ -28,7 +29,7 @@ multishell.addHotkey('control-backspace', function()
end)
-- next tab
multishell.addHotkey('control-tab', function()
keyboard.addHotkey('control-tab', function()
local tabs = multishell.getTabs()
local visibleTabs = { }
local currentTabId = multishell.getFocus()

View File

@ -2,7 +2,6 @@
local colors = _G.colors
local fs = _G.fs
local http = _G.http
local shell = _ENV.shell
local term = _G.term
local w, h = term.getSize()
@ -40,6 +39,7 @@ local sandboxEnv = setmetatable({ }, { __index = _G })
for k,v in pairs(_ENV) do
sandboxEnv[k] = v
end
sandboxEnv.multishell = _ENV.multishell or { }
local function makeEnv()
local env = setmetatable({ }, { __index = _G })
@ -86,44 +86,7 @@ else
fs.mount('', 'gitfs', GIT_REPO)
end
local Util = run('sys/apis/util.lua')
-- user environment
if not fs.exists('usr/apps') then
fs.makeDir('usr/apps')
end
if not fs.exists('usr/autorun') then
fs.makeDir('usr/autorun')
end
if not fs.exists('usr/etc/fstab') then
Util.writeFile('usr/etc/fstab', 'usr gitfs kepler155c/opus-apps/develop')
end
if not fs.exists('usr/config/shell') then
Util.writeTable('usr/config/shell', {
aliases = shell.aliases(),
path = 'usr/apps:sys/apps:' .. shell.path(),
lua_path = '/sys/apis:/usr/apis',
})
end
-- shell environment
local config = Util.readTable('usr/config/shell')
if config.aliases then
for k in pairs(shell.aliases()) do
shell.clearAlias(k)
end
for k,v in pairs(config.aliases) do
shell.setAlias(k, v)
end
end
shell.setPath(config.path)
sandboxEnv.LUA_PATH = config.lua_path
-- extensions
local dir = 'sys/extensions'
for _,file in ipairs(fs.list(dir)) do
run('sys/apps/shell', fs.combine(dir, file))
end
run('sys/kernel.lua')
-- install user file systems
fs.loadTab('usr/etc/fstab')

View File

@ -4,8 +4,88 @@ local Peripheral = require('peripheral')
_G.device = Peripheral.getList()
-- register the main term in the devices list
_G.device.terminal = _G.term.current()
_G.device.terminal.side = 'terminal'
_G.device.terminal.type = 'terminal'
_G.device.terminal.name = 'terminal'
_G.device.keyboard = {
side = 'keyboard',
type = 'keyboard',
name = 'keyboard',
hotkeys = { },
state = { },
}
_G.device.mouse = {
side = 'mouse',
type = 'mouse',
name = 'mouse',
state = { },
}
local Input = require('input')
local Util = require('util')
local device = _G.device
local kernel = _G.kernel
local keyboard = _G.device.keyboard
local os = _G.os
kernel.hook('peripheral', function(_, eventData)
local side = eventData[1]
if side then
local dev = Peripheral.addDevice(device, side)
if dev then
os.queueEvent('device_attach', dev.name)
end
end
end)
kernel.hook('peripheral_detach', function(_, eventData)
local side = eventData[1]
if side then
local dev = Util.find(device, 'side', side)
if dev then
os.queueEvent('device_detach', dev.name)
device[dev.name] = nil
end
end
end)
kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData)
local code = eventData[1]
-- maintain global keyboard state
if event == 'key' then
keyboard.state[code] = true
elseif event == 'key_up' then
if not keyboard.state[code] then
return true -- ensure key ups are only generated if a key down was sent
end
keyboard.state[code] = nil
end
-- and fire hotkeys
local hotkey = Input:translate(event, eventData[1], eventData[2])
if hotkey and keyboard.hotkeys[hotkey] then
keyboard.hotkeys[hotkey](event, eventData)
end
end)
function keyboard.addHotkey(code, fn)
keyboard.hotkeys[code] = fn
end
function keyboard.removeHotkey(code)
keyboard.hotkeys[code] = nil
end
kernel.hook('monitor_touch', function(event, eventData)
local monitor = Peripheral.getBySide(eventData[1])
if monitor and monitor.eventChannel then
monitor.eventChannel(event, table.unpack(eventData))
return true -- stop propagation
end
end)

View File

@ -0,0 +1,16 @@
local kernel = _G.kernel
local multishell = _ENV.multishell
_G.network = { }
kernel.hook('device_attach', function(_, eventData)
if eventData[1] == 'wireless_modem' then
local s, m = multishell.openTab({
path = 'sys/services/network.lua',
hidden = true
})
if not s and m then
debug(m)
end
end
end)

83
sys/kernel.lua Normal file
View File

@ -0,0 +1,83 @@
local sandboxEnv = setmetatable({ }, { __index = _G })
for k,v in pairs(_ENV) do
sandboxEnv[k] = v
end
_G.requireInjector()
local Util = require('util')
_G.kernel = {
hooks = { }
}
local kernel = _G.kernel
local fs = _G.fs
local shell = _ENV.shell
-- user environment
if not fs.exists('usr/apps') then
fs.makeDir('usr/apps')
end
if not fs.exists('usr/autorun') then
fs.makeDir('usr/autorun')
end
if not fs.exists('usr/etc/fstab') then
Util.writeFile('usr/etc/fstab', 'usr gitfs kepler155c/opus-apps/develop')
end
if not fs.exists('usr/config/shell') then
Util.writeTable('usr/config/shell', {
aliases = shell.aliases(),
path = 'usr/apps:sys/apps:' .. shell.path(),
lua_path = '/sys/apis:/usr/apis',
})
end
-- shell environment
local config = Util.readTable('usr/config/shell')
if config.aliases then
for k in pairs(shell.aliases()) do
shell.clearAlias(k)
end
for k,v in pairs(config.aliases) do
shell.setAlias(k, v)
end
end
shell.setPath(config.path)
_G.LUA_PATH = config.lua_path
-- any function that runs in a kernel hook does not run in
-- a separate coroutine or have a window. an error in a hook
-- function will crash the system.
function kernel.hook(event, fn)
if type(event) == 'table' then
for _,v in pairs(event) do
kernel.hook(v, fn)
end
else
if not kernel.hooks[event] then
kernel.hooks[event] = { }
end
table.insert(kernel.hooks[event], fn)
end
end
-- you can only unhook from within the function that hooked
function kernel.unhook(event, fn)
local eventHooks = kernel.hooks[event]
if eventHooks then
Util.removeByValue(eventHooks, fn)
if #eventHooks == 0 then
kernel.hooks[event] = nil
end
end
end
-- extensions
local dir = 'sys/extensions'
for _,file in ipairs(fs.list(dir)) do
local s, m = Util.run(sandboxEnv, 'sys/apps/shell', fs.combine(dir, file))
if not s then
error(m)
end
end

View File

@ -5,7 +5,6 @@
local Event = require('event')
local Peripheral = require('peripheral')
local Socket = require('socket')
local Util = require('util')
Event.addRoutine(function()
print('peripheral: listening on port 189')
@ -19,6 +18,8 @@ Event.addRoutine(function()
if uri then
local peripheral = Peripheral.lookup(uri)
-- only 1 proxy of this device can happen at one time
-- need to prevent multiple shares
if not peripheral then
print('peripheral: invalid peripheral ' .. uri)
else
@ -28,7 +29,7 @@ Event.addRoutine(function()
}
if peripheral.blit then
peripheral = Util.shallowCopy(peripheral)
--peripheral = Util.shallowCopy(peripheral)
peripheral.fastBlit = function(data)
for _,v in ipairs(data) do
peripheral[v.fn](unpack(v.args))
@ -47,12 +48,12 @@ Event.addRoutine(function()
socket:write(proxy)
if proxy.type == 'monitor' then
local h
h = Event.on('monitor_touch', function(...)
if not socket:write({ ... }) then
Event.off(h)
peripheral.eventChannel = function(...)
socket:write({
fn = 'event',
data = { ... }
})
end
end)
end
while true do
@ -61,9 +62,14 @@ Event.addRoutine(function()
print('peripheral: lost connection from ' .. socket.dhost)
break
end
if peripheral[data.fn] then
socket:write({ peripheral[data.fn](table.unpack(data.args)) })
end
end
peripheral.eventChannel = nil
peripheral.fastBlit = nil
end
end
end)
end

View File

@ -48,7 +48,7 @@ local function telnetHost(socket)
end
local shellThread = Event.addRoutine(function()
os.run(_ENV, 'sys/apps/shell')
os.run(_ENV, 'sys/apps/shell', table.unpack(termInfo.program))
Event.exitPullEvents()
end)

View File

@ -1,47 +0,0 @@
_G.requireInjector()
local Event = require('event')
local Peripheral = require('peripheral')
local Util = require('util')
local colors = _G.colors
local device = _G.device
local multishell = _ENV.multishell
local os = _G.os
local term = _G.term
multishell.setTitle(multishell.getCurrent(), 'Devices')
local attachColor = colors.green
local detachColor = colors.red
if not term.isColor() then
attachColor = colors.white
detachColor = colors.lightGray
end
Event.on('peripheral', function(_, side)
if side then
local dev = Peripheral.addDevice(device, side)
if dev then
term.setTextColor(attachColor)
Util.print('[%s] %s attached', dev.side, dev.name)
os.queueEvent('device_attach', dev.name)
end
end
end)
Event.on('peripheral_detach', function(_, side)
if side then
local dev = Util.find(device, 'side', side)
if dev then
term.setTextColor(detachColor)
Util.print('[%s] %s detached', dev.side, dev.name)
os.queueEvent('device_detach', dev.name)
device[dev.name] = nil
end
end
end)
print('waiting for peripheral changes')
Event.pullEvents()

View File

@ -3,6 +3,7 @@ _G.requireInjector()
local Terminal = require('terminal')
local Util = require('util')
local keyboard = _G.device.keyboard
local multishell = _ENV.multishell
local os = _G.os
local term = _G.term
@ -25,7 +26,7 @@ end
print('Debug started')
print('Press ^d to activate debug window')
multishell.addHotkey('control-d', function()
keyboard.addHotkey('control-d', function()
local currentId = multishell.getFocus()
if currentId ~= tabId then
previousId = currentId
@ -40,4 +41,4 @@ os.pullEventRaw('terminate')
print('Debug stopped')
_G.debug = function() end
multishell.removeHotkey('control-d')
keyboard.removeHotkey('control-d')

View File

@ -1,73 +1,45 @@
_G.requireInjector()
local Event = require('event')
local Util = require('util')
local device = _G.device
local fs = _G.fs
local multishell = _ENV.multishell
local network = _G.network
local os = _G.os
local printError = _G.printError
local network = { }
_G.network = network
if not device.wireless_modem then
return
end
multishell.setTitle(multishell.getCurrent(), 'Net Daemon')
local function netUp()
_G.requireInjector()
print('Net daemon started')
local Event = require('event')
for _,file in pairs(fs.list('sys/network')) do
for _,file in pairs(fs.list('sys/network')) do
local fn, msg = Util.run(_ENV, 'sys/network/' .. file)
if not fn then
printError(msg)
end
end
end
Event.on('device_detach', function()
Event.on('device_detach', function()
if not device.wireless_modem then
Event.exitPullEvents()
end
end)
end)
Event.pullEvents()
Event.pullEvents()
for _,c in pairs(network) do
for _,c in pairs(network) do
c.active = false
os.queueEvent('network_detach', c)
end
os.queueEvent('network_down')
Event.pullEvent('network_down')
Util.clear(_G.network)
end
os.queueEvent('network_down')
Event.pullEvent('network_down')
print('Net daemon started')
local function startNetwork()
print('Starting network services')
local success, msg = Util.runFunction(
Util.shallowCopy(_ENV), netUp)
if not success and msg then
printError(msg)
end
print('Network services stopped')
end
if device.wireless_modem then
startNetwork()
else
print('No modem detected')
end
while true do
local _, deviceName = os.pullEvent('device_attach')
if deviceName == 'wireless_modem' then
startNetwork()
end
end
Util.clear(_G.network)
print('Net daemon stopped')

View File

@ -21,6 +21,7 @@ _G.transport = transport
function transport.open(socket)
transport.sockets[socket.sport] = socket
socket.activityTimer = os.clock()
end
function transport.read(socket)
@ -34,16 +35,18 @@ function transport.write(socket, data)
--debug('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq }))
socket.transmit(socket.dport, socket.dhost, data)
local timerId = os.startTimer(3)
--local timerId = os.startTimer(3)
transport.timers[timerId] = socket
socket.timers[socket.wseq] = timerId
--transport.timers[timerId] = socket
--socket.timers[socket.wseq] = timerId
socket.wseq = socket.wseq + 1
end
function transport.ping(socket)
--debug('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq }))
if os.clock() - socket.activityTimer > 10 then
socket.activityTimer = os.clock()
socket.transmit(socket.dport, socket.dhost, {
type = 'PING',
seq = -1,
@ -52,6 +55,7 @@ function transport.ping(socket)
local timerId = os.startTimer(3)
transport.timers[timerId] = socket
socket.timers[-1] = timerId
end
end
function transport.close(socket)
@ -67,7 +71,7 @@ while true do
local socket = transport.timers[timerId]
if socket and socket.connected then
print('transport timeout - closing socket ' .. socket.sport)
debug('transport timeout - closing socket ' .. socket.sport)
socket:close()
transport.timers[timerId] = nil
end
@ -88,18 +92,21 @@ while true do
if ackTimerId then
os.cancelTimer(ackTimerId)
socket.timers[msg.seq] = nil
socket.activityTimer = os.clock()
transport.timers[ackTimerId] = nil
end
elseif msg.type == 'PING' then
socket.activityTimer = os.clock()
socket.transmit(socket.dport, socket.dhost, {
type = 'ACK',
seq = msg.seq,
})
elseif msg.type == 'DATA' and msg.data then
socket.activityTimer = os.clock()
if msg.seq ~= socket.rseq then
print('transport seq error - closing socket ' .. socket.sport)
debug('transport seq error - closing socket ' .. socket.sport)
socket:close()
else
socket.rseq = socket.rseq + 1
@ -111,10 +118,10 @@ while true do
end
--debug('>> ' .. Util.tostring({ type = 'ACK', seq = msg.seq }))
socket.transmit(socket.dport, socket.dhost, {
type = 'ACK',
seq = msg.seq,
})
--socket.transmit(socket.dport, socket.dhost, {
-- type = 'ACK',
-- seq = msg.seq,
--})
end
end
end