mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-16 15:38:05 +11:00
Added 'omniterm' - basic terminal app
Omniterm, + some sort of RPC->net interface, should allow applications that just need a text console to run, and have a nice transparent interface between local and remote control. And in any case, it should definitely work for the more likely use case of wanting to have a chat over a local OpenComputers network in a base.
This commit is contained in:
parent
2ae3f9a93a
commit
ea6b987c21
268
apps/omniterm.lua
Normal file
268
apps/omniterm.lua
Normal file
@ -0,0 +1,268 @@
|
||||
-- OmniTerm: multi-driver terminal
|
||||
-- Has RPC (lets apps use OmniTerm as a helper. Protocol commands are "msg", "join".),
|
||||
-- Echo (test),
|
||||
--
|
||||
|
||||
local table, unicode, math, proc, lang = A.request("table", "unicode", "math", "proc", "lang")
|
||||
|
||||
local app = {}
|
||||
local termWidth = 25
|
||||
-- console buffer cannot scroll left/right
|
||||
local consoleBuffer = lang.getTable()
|
||||
if not consoleBuffer then
|
||||
consoleBuffer = {
|
||||
--1234512345123451234512345
|
||||
"OmniTerm Interfaces:",
|
||||
"rpc:<appId> |RPC",
|
||||
"tun:<CA> |Linked Card",
|
||||
"net:<RA>:<pt>|Net.Card",
|
||||
--Allows talking with everybody on a network.
|
||||
"net:<pt> |Net.Card-BC",
|
||||
--Allows talking with MineOS Chat... in theory...
|
||||
"moschat:<RA> |MineOS Chat",
|
||||
"componentlist|Components.",
|
||||
"Exit with Ctrl-W."
|
||||
}
|
||||
end
|
||||
|
||||
local lineBuffer = ""
|
||||
local function incomingSubLine(txt)
|
||||
for i = 1, #consoleBuffer - 1 do
|
||||
consoleBuffer[i] = consoleBuffer[i + 1]
|
||||
end
|
||||
consoleBuffer[#consoleBuffer] = txt
|
||||
end
|
||||
local function incomingLine(txt)
|
||||
txt = unicode.safeTextFormat(txt)
|
||||
-- Note: >2 wide characters can *stay away*. Well away.
|
||||
-- The result will always leave a 1-char gap at the end of a line,
|
||||
-- which suffices to allow wide characters to work properly.
|
||||
while unicode.len(txt) > termWidth do
|
||||
incomingSubLine(unicode.sub(txt, 1, termWidth - 1))
|
||||
txt = " " .. unicode.sub(txt, termWidth)
|
||||
end
|
||||
incomingSubLine(txt)
|
||||
end
|
||||
local function outgoingLine(txt)
|
||||
end
|
||||
local function driverShutdown()
|
||||
end
|
||||
-- Driver utils
|
||||
local function parseAddrPort(id)
|
||||
if id:match("[a-f0-9%-]+:[0-9]+") ~= id then
|
||||
error("Bad Syntax (<proto>:<hw-addr>:<port>)")
|
||||
end
|
||||
local addr = id:match("[a-f0-9%-]+")
|
||||
local port = tonumber(id:match(":[0-9]+"):sub(2))
|
||||
return addr, port
|
||||
end
|
||||
local drivers = {
|
||||
-- rpc:appID
|
||||
rpc = function (id)
|
||||
proc.sendRPC(id, "join")
|
||||
app.rpc = function (srcP, srcD, cmd, txt)
|
||||
if srcD == id then
|
||||
if cmd == "msg" then
|
||||
incomingLine(tostring(txt))
|
||||
A.timer(0.01)
|
||||
end
|
||||
end
|
||||
end
|
||||
outgoingLine = function (txt)
|
||||
proc.sendRPC(id, "msg", txt)
|
||||
end
|
||||
end,
|
||||
-- tun:<addr>
|
||||
tun = function (id)
|
||||
local cT = A.request("c.tunnel")
|
||||
local tunnel = nil
|
||||
if id ~= "" then
|
||||
for v in cT.list() do
|
||||
if v.address:sub(1, id:len()) == id then tunnel = v end
|
||||
end
|
||||
end
|
||||
if not tunnel then error("Couldn't find that tunnel.") end
|
||||
app.event = function (...)
|
||||
local ev = {...}
|
||||
if ev[1] == "modem_message" then
|
||||
if ev[2] == tunnel.address then
|
||||
incomingLine(tostring(ev[6]))
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
outgoingLine = function (txt)
|
||||
tunnel.send(txt)
|
||||
end
|
||||
end,
|
||||
-- net:targetAddr:port
|
||||
-- Uses all modems to send to a target. (Tunnels do not count.)
|
||||
net = function (id)
|
||||
local addr = nil
|
||||
local port = tonumber(id)
|
||||
if not port then
|
||||
addr, port = parseAddrPort(id)
|
||||
end
|
||||
local cM = A.request("c.modem")
|
||||
for v in cM.list() do
|
||||
v.open(port)
|
||||
if v.isWireless() then
|
||||
-- Probably not the best, but it'll do until a proper strength controller is written.
|
||||
-- I don't know if it's set to full strength by default, and that's critical!
|
||||
v.setStrength(400)
|
||||
end
|
||||
end
|
||||
app.event = function (...)
|
||||
local a = {...}
|
||||
if a[1] == "modem_message" then
|
||||
if (a[3] == addr) or (not addr) then
|
||||
if a[4] == port then
|
||||
incomingLine(tostring(a[6]))
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
outgoingLine = function (txt)
|
||||
for v in cM.list() do
|
||||
if addr then
|
||||
v.send(addr, port, txt)
|
||||
else
|
||||
v.broadcast(port, txt)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
-- moschat:<address>
|
||||
-- Allows basic communication with MineOS Chat systems, in theory.
|
||||
-- In practice? This is untested against real MineOS.
|
||||
moschat = function (id)
|
||||
local port = 899 -- MOSChat port
|
||||
local cM = A.request("c.modem")
|
||||
for v in cM.list() do
|
||||
v.open(port)
|
||||
end
|
||||
app.event = function (...)
|
||||
local a = {...}
|
||||
if a[1] == "modem_message" then
|
||||
if a[3] == id then
|
||||
if a[4] == port then
|
||||
if a[6] == "HereIsMessageToYou" then
|
||||
incomingLine(tostring(a[8]))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
outgoingLine = function (txt)
|
||||
for v in cM.list() do
|
||||
v.send(id, port, "HereIsMessageToYou", nil, txt)
|
||||
end
|
||||
end
|
||||
end,
|
||||
-- echo:postfix
|
||||
-- Echoes back any line sent, plus a postfix.
|
||||
echo = function (id)
|
||||
outgoingLine = function (txt)
|
||||
incomingLine(txt .. id)
|
||||
end
|
||||
end,
|
||||
-- componentlist
|
||||
-- Used to list components
|
||||
-- Useful because OpenComputers stupidly cuts off text,
|
||||
-- which is really bad when you need the *whole* ID...
|
||||
-- >.< like when doing anything involving networking.
|
||||
componentlist = function (id)
|
||||
local stat = A.request("stat")
|
||||
outgoingLine = function (txt)
|
||||
incomingLine("Components [" .. txt .. "]:")
|
||||
for ad, tp in stat.componentList() do
|
||||
if tp == txt then
|
||||
incomingLine(ad)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
local hasDriver = false
|
||||
local function typedLine(txt)
|
||||
if not hasDriver then
|
||||
-- Initialize driver
|
||||
local dname = txt:match("^[^:]+")
|
||||
if not dname then
|
||||
incomingLine("You must specify what to connect to.")
|
||||
return
|
||||
end
|
||||
if not drivers[dname] then
|
||||
incomingLine("No such driver '" .. dname .. "'")
|
||||
return
|
||||
end
|
||||
txt = txt:sub(dname:len() + 2)
|
||||
incomingLine("Connecting with driver '" .. dname .. "'")
|
||||
local ok, err = pcall(drivers[dname], txt)
|
||||
if not ok then
|
||||
incomingLine("Error: " .. err)
|
||||
else
|
||||
local a = ""
|
||||
for i = 1, termWidth do a = a .. "-" end
|
||||
incomingLine(a)
|
||||
hasDriver = true
|
||||
end
|
||||
else
|
||||
incomingLine(txt)
|
||||
outgoingLine(txt)
|
||||
end
|
||||
end
|
||||
|
||||
-- triggered by drivers that can't directly cause redraws
|
||||
function app.update()
|
||||
return true
|
||||
end
|
||||
|
||||
function app.get_ch(x, y)
|
||||
local l, lp = consoleBuffer[y], 0
|
||||
if y == #consoleBuffer + 1 then
|
||||
lp = unicode.len(lineBuffer) - math.floor(termWidth / 2)
|
||||
if lp < 1 then lp = 1 end
|
||||
l, lp = unicode.safeTextFormat(lineBuffer, lp)
|
||||
lp = lp - 1
|
||||
end
|
||||
return unicode.sub(l, x + lp, x + lp)
|
||||
end
|
||||
|
||||
local ctrlFlag = false
|
||||
function app.key(ka, kc, down)
|
||||
if kc == 29 then
|
||||
ctrlFlag = down
|
||||
return false
|
||||
end
|
||||
if ctrlFlag then
|
||||
if down then
|
||||
if kc == 17 then -- W
|
||||
driverShutdown()
|
||||
A.die()
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
if down then
|
||||
if ka ~= 0 then
|
||||
if ka == 13 then
|
||||
typedLine(lineBuffer)
|
||||
lineBuffer = ""
|
||||
return true
|
||||
else
|
||||
if ka == 8 then
|
||||
lineBuffer = unicode.sub(lineBuffer, 1, unicode.len(lineBuffer) - 1)
|
||||
return true
|
||||
else
|
||||
lineBuffer = lineBuffer .. unicode.char(ka)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return app, termWidth, #consoleBuffer + 1
|
Loading…
Reference in New Issue
Block a user