From 646add28a267cb1d6cc919798d90699424a0915b Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Thu, 11 May 2023 21:55:53 +0300 Subject: [PATCH] initial commit --- .luarc.json | 17 ++++++ README.md | 3 + client.lua | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ server.lua | 137 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 .luarc.json create mode 100644 README.md create mode 100644 client.lua create mode 100644 server.lua diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..dc4d25a --- /dev/null +++ b/.luarc.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", + "Lua.diagnostics.disable": [ + "undefined-field" + ], + "Lua.diagnostics.globals": [ + "peripheral", + "rednet", + "fs", + "textutils", + "term", + "colors", + "paintutils", + "keys" + ], + "Lua.runtime.version": "Lua 5.1" +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a710822 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Wireless todo list + +Setup a server on which you can store a todo list and access it from a pocket computer. diff --git a/client.lua b/client.lua new file mode 100644 index 0000000..824f200 --- /dev/null +++ b/client.lua @@ -0,0 +1,158 @@ +local PROTOCOL = "wireless-todo" + +local function pprint(...) + local pretty = require("cc.pretty") + pretty.pretty_print(...) +end + +local function isWirelessModem(peripheral_name) + return peripheral.getType(peripheral_name) == "modem" + and peripheral.call(peripheral_name, "isWireless") +end + +local function getWirelessModem() + for _, name in ipairs(peripheral.getNames()) do + if isWirelessModem(name) then + return name + end + end +end + +local function splitTextByWidth(text, max_width) + local lines = {} + local current_line = "" + for whitespace, word in text:gmatch("(%s*)([^%s]+)") do + if #current_line + #whitespace + #word > max_width then + table.insert(lines, current_line) + current_line = word + else + current_line = current_line..whitespace..word + end + end + if #current_line > 0 then + table.insert(lines, current_line) + end + return lines +end + +local function drawTodo(todo) + local w, h = term.getSize() + local x, y = term.getCursorPos() + local lines = splitTextByWidth(todo.text, w-4) + paintutils.drawFilledBox(x, y, w, y+#lines-1) + term.setCursorPos(x, y) + + term.write("[ ] ") + if todo.marked then + x, y = term.getCursorPos() + term.setCursorPos(x-3, y) + term.setTextColor(colors.green) + term.write("x") + term.setTextColor(colors.white) + term.setCursorPos(x, y) + end + + x, y = term.getCursorPos() + for i, line in ipairs(lines) do + term.setCursorPos(x, y+i-1) + term.write(line) + end + term.setCursorPos(1, y+#lines) +end + +local function drawTodos(todos, selected_todo) + local w, h = term.getSize() + term.clear() + term.setCursorPos(1, 1) + term.setTextColor(colors.orange) + print("===== Wireless Todo ======") + + term.setTextColor(colors.white) + for i, todo in ipairs(todos) do + if i == selected_todo then + term.setBackgroundColor(colors.gray) + drawTodo(todo) + term.setBackgroundColor(colors.black) + else + drawTodo(todo) + end + + local _, y = term.getCursorPos() + end +end + +local function getTodoUnderMouse(todos, x, y) + local w, h = term.getSize() + + local todo_y = 2 + for i, todo in ipairs(todos) do + local todo_height = #splitTextByWidth(todo.text, w-4) + if todo_y <= y and y < todo_y+todo_height then + return i + end + todo_y = todo_y + todo_height + end +end + +local function main() + local modem_name = getWirelessModem() + if not modem_name then + print("ERROR: please attach a wireless modem") + return + end + + rednet.open(modem_name) + term.clear() + term.setCursorPos(1, 1) + print("Starting...") + + local servers = {rednet.lookup(PROTOCOL)} + local server = servers[1] + + local selected_todo = 1 + local todos = { + { + text = "Foo bar baz", + marked = false, + }, + { + text = "Nobis doloremque explicabo qui amet nihil perspiciatis. ", + marked = false, + }, + { text = "Biz baz", marked = false }, + { text = "Biz baz", marked = true }, + { + text = "Nobis doloremque explicabo qui amet nihil perspiciatis. foao ado ao", + marked = false, + } + } + rednet.send(server, "get", PROTOCOL) + while true do + local event = {os.pullEvent()} + if event[1] == "rednet_message" and event[4] == PROTOCOL then + -- todos = textutils.unserialise(event[3]) + elseif event[1] == "mouse_up" then + local todo_index = getTodoUnderMouse(todos, event[3], event[4]) + if todo_index then + selected_todo = todo_index + end + elseif event[1] == "key_up" then + local key = event[2] + if key == keys.up then + selected_todo = math.max(selected_todo-1, 1) + elseif key == keys.down then + selected_todo = math.min(selected_todo+1, #todos) + elseif key == keys.space then + todos[selected_todo].marked = not todos[selected_todo].marked + end + end + + drawTodos(todos, selected_todo) + end + + -- local _, response = rednet.receive(PROTOCOL) + -- pprint(textutils.unserialise(response)) +end + +-- pprint(splitTextByWidth("foo bar baz", 10)) +main() diff --git a/server.lua b/server.lua new file mode 100644 index 0000000..357bfde --- /dev/null +++ b/server.lua @@ -0,0 +1,137 @@ +local PROTOCOL = "wireless-todo" +local TODOS_FILE = "todos.data.lua" + +local function pprint(...) + local pretty = require("cc.pretty") + pretty.pretty_print(...) +end + +local function isWirelessModem(peripheral_name) + return peripheral.getType(peripheral_name) == "modem" + and peripheral.call(peripheral_name, "isWireless") +end + +local function getWirelessModem() + for _, name in ipairs(peripheral.getNames()) do + if isWirelessModem(name) then + return name + end + end +end + +local function readTodos(filename) + if fs.exists(filename) then + return loadfile(filename)() + else + return {} + end +end + +local function writeTodos(filename, todos) + local f = fs.open(filename, "w") + f.write("return ") + f.write(textutils.serialise(todos)) + f.close() +end + +local function includeValue(set, value) + for _, v in ipairs(set) do + if v == value then + return + end + end + + table.insert(set, value) +end + +local function decodeMessage(message) + local parts = {} + for part in message:gmatch("([^\n]+)") do + table.insert(parts, part) + end + return parts +end + +local function sendToMultiple(recipients, payload, protocol, except_recepient) + for _, recipient in ipairs(recipients) do + if recipient ~= except_recepient then + rednet.send(recipient, payload, protocol) + end + end +end + +local function main(hostname) + if not hostname then + print("ERROR: please provide a hostname") + return + end + + local modem_name = getWirelessModem() + if not modem_name then + print("ERROR: please attach a wireless modem") + return + end + + rednet.open(modem_name) + rednet.host(PROTOCOL, hostname) + + local seen_users = {} + local todos = readTodos(TODOS_FILE) + + local function updateUsersTodos(except_user) + writeTodos(TODOS_FILE, todos) + local payload = textutils.serialise(todos, { compact = true }) + sendToMultiple(seen_users, payload, PROTOCOL, except_user) + end + + while true do + local sender, message = rednet.receive(PROTOCOL) + print(sender, message) + local parts = decodeMessage(message) + pprint(parts) + if parts[1] == "get" then + includeValue(seen_users, sender) + local payload = textutils.serialise(todos, { compact = true }) + rednet.send(sender, payload, PROTOCOL) + elseif parts[1] == "edit" then + local index = tonumber(parts[2]) + todos[index].text = parts[3] + + updateUsersTodos(sender) + elseif parts[1] == "mark" then + local index = tonumber(parts[2]) + todos[index].marked = true + + updateUsersTodos(sender) + elseif parts[1] == "unmark" then + local index = tonumber(parts[2]) + todos[index].marked = false + + updateUsersTodos(sender) + elseif parts[1] == "add" then + table.insert(todos, { + text = parts[2] or "", + marked = false + }) + + updateUsersTodos(sender) + elseif parts[1] == "remove" then + local index = tonumber(parts[2]) + table.remove(todos, index) + + updateUsersTodos(sender) + elseif parts[1] == "move-up" then + local index = tonumber(parts[2]) + -- TOOD: finish this + + updateUsersTodos(sender) + elseif parts[1] == "move-down" then + local index = tonumber(parts[2]) + -- TOOD: finish this + + updateUsersTodos(sender) + end + end +end + +main(...)