From 97613ed2641e1c23743e43b83bf7abe6734a271f Mon Sep 17 00:00:00 2001 From: Gerard Hickey Date: Sat, 6 Apr 2024 18:31:39 -0400 Subject: [PATCH 1/6] Replace luci.jsonc with pure Lua JSON library Signed-off-by: Gerard Hickey --- .github/workflows/build-packages.yaml | 10 +- .../workflow-meshchat-debian-package.yaml | 42 ++ ...=> workflow-meshchat-openwrt-package.yaml} | 4 +- lib/json.lua | 388 ++++++++++++++++++ meshchat | 14 +- package/populate-meshchat-fs.sh | 34 +- package/update-version.sh | 1 + 7 files changed, 471 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/workflow-meshchat-debian-package.yaml rename .github/workflows/{workflow-meshchat-package.yaml => workflow-meshchat-openwrt-package.yaml} (96%) create mode 100644 lib/json.lua diff --git a/.github/workflows/build-packages.yaml b/.github/workflows/build-packages.yaml index 2a0c345..c5c92f4 100644 --- a/.github/workflows/build-packages.yaml +++ b/.github/workflows/build-packages.yaml @@ -19,18 +19,18 @@ jobs: echo "build_version=$version" >> $GITHUB_OUTPUT - build-meshchat-package: + build-meshchat-openwrt-package: needs: calculate-version uses: - ./.github/workflows/workflow-meshchat-package.yaml + ./.github/workflows/workflow-meshchat-openwrt-package.yaml with: build_version: ${{ needs.calculate-version.outputs.build_version }} build_dir: package/meshchat-ipkg - build-meshchat-api-package: + build-meshchat-debian-package: needs: calculate-version uses: - ./.github/workflows/workflow-meshchat-api-package.yaml + ./.github/workflows/workflow-meshchat-debian-package.yaml with: build_version: ${{ needs.calculate-version.outputs.build_version }} - build_dir: package/meshchat-ipkg + build_dir: package/meshchat-deb diff --git a/.github/workflows/workflow-meshchat-debian-package.yaml b/.github/workflows/workflow-meshchat-debian-package.yaml new file mode 100644 index 0000000..13a0f89 --- /dev/null +++ b/.github/workflows/workflow-meshchat-debian-package.yaml @@ -0,0 +1,42 @@ +name: Build MeshChat Package +on: + workflow_call: + inputs: + build_version: + required: true + type: string + build_dir: + required: true + type: string + ref: + required: false + type: string + default: ${{ github.ref_name }} + +jobs: + create-meshchat-debian-package: + runs-on: ubuntu-latest + # container: + # image: registry.gitlab.com/wt0f/gitlab-runner-images/shell:latest + outputs: + package_file: ${{ steps.detect-package-file.outputs.file }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ inputs.ref }} + # - run: info "Populating the filesystem with MeshChat files" + - run: echo ${{ inputs.build_version }} > VERSION + - run: package/populate-meshchat-fs.sh ${{ inputs.build_dir }} debian + # - run: info "Updating version numbers to " + - run: package/update-version.sh ${{ inputs.build_dir }} + # - run: info "Packing up MeshChat files" + - run: dpkg-deb --root-owner-group --build ${{ inputs.build_dir }} + - run: mv meshchat-deb.deb meshchat_${{ inputs.build_version }}_all.deb + - id: detect-package-file + run: echo "file=meshchat_${{inputs.build_version }}_all.deb" >> $GITHUB_OUTPUT + - run: echo "${{ steps.detect-package-file.outputs.file }}" + - uses: actions/upload-artifact@v4 + with: + name: ${{ steps.detect-package-file.outputs.file }} + path: ${{ steps.detect-package-file.outputs.file }} diff --git a/.github/workflows/workflow-meshchat-package.yaml b/.github/workflows/workflow-meshchat-openwrt-package.yaml similarity index 96% rename from .github/workflows/workflow-meshchat-package.yaml rename to .github/workflows/workflow-meshchat-openwrt-package.yaml index bee92b0..46ea64c 100644 --- a/.github/workflows/workflow-meshchat-package.yaml +++ b/.github/workflows/workflow-meshchat-openwrt-package.yaml @@ -14,7 +14,7 @@ on: default: ${{ github.ref_name }} jobs: - create-meshchat-package: + create-meshchat-openwrt-package: runs-on: ubuntu-latest # container: # image: registry.gitlab.com/wt0f/gitlab-runner-images/shell:latest @@ -27,7 +27,7 @@ jobs: ref: ${{ inputs.ref }} # - run: info "Populating the filesystem with MeshChat files" - run: echo ${{ inputs.build_version }} > VERSION - - run: package/populate-meshchat-fs.sh ${{ inputs.build_dir }} + - run: package/populate-meshchat-fs.sh ${{ inputs.build_dir }} openwrt # - run: info "Updating version numbers to " - run: package/update-version.sh ${{ inputs.build_dir }} # - run: info "Packing up MeshChat files" diff --git a/lib/json.lua b/lib/json.lua new file mode 100644 index 0000000..711ef78 --- /dev/null +++ b/lib/json.lua @@ -0,0 +1,388 @@ +-- +-- json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} + +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + + while j <= #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + + elseif x == 92 then -- `\`: Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + + elseif x == 34 then -- `"`: End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + + j = j + 1 + end + + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json diff --git a/meshchat b/meshchat index 9a3c507..2747936 100755 --- a/meshchat +++ b/meshchat @@ -38,7 +38,7 @@ package.path = package.path .. ";/www/cgi-bin/?.lua" require('luci.http') -local json = require("luci.jsonc") +local json = require("json") require("nixio") require("meshchatconfig") require("meshchatlib") @@ -119,7 +119,7 @@ function config() debug = debug, } - print(json.stringify(settings)) + print(json.encode(settings)) end --- Send a message to the MeshChat instance. @@ -288,7 +288,7 @@ function messages() -- order messages according to time table.sort(messages, function(a, b) return a.epoch > b.epoch end) - output:write(json.stringify(messages)) + output:write(json.encode(messages)) output:flush() end @@ -330,7 +330,7 @@ function sync_status() table.sort(status, function(a, b) return a.epoch > b.epoch end) - print(json.stringify(status)) + print(json.encode(status)) end --- Return a list of messages as text. @@ -472,7 +472,7 @@ function users() table.sort(users, function(a, b) return a.epoch > b.epoch end) - print(json.stringify(users)) + print(json.encode(users)) end --- Return a list of files as plain text. @@ -612,7 +612,7 @@ function files() table.sort(files, function(a, b) return a.epoch > b.epoch end) - print(json.stringify({ + print(json.encode({ stats = stats, files = files })) @@ -743,7 +743,7 @@ function hosts() table.sort(hosts, function(a, b) return a.hostname < b.hostname end) - print(json.stringify(hosts)) + print(json.encode(hosts)) end --- Return a list of hosts as plain text. diff --git a/package/populate-meshchat-fs.sh b/package/populate-meshchat-fs.sh index 656df9b..6f98c85 100755 --- a/package/populate-meshchat-fs.sh +++ b/package/populate-meshchat-fs.sh @@ -4,6 +4,7 @@ # creates the filesystem image for the MeshChat API package. IPK_DIR=$1 +OSNAME=$2 # Populate the CONTROL portion of the package mkdir -p $IPK_DIR/CONTROL @@ -12,11 +13,28 @@ sed -i "s%\$GITHUB_SERVER_URL%$GITHUB_SERVER_URL%" $IPK_DIR/CONTROL/control sed -i "s%\$GITHUB_REPOSITORY%$GITHUB_REPOSITORY%" $IPK_DIR/CONTROL/control # Populate the filesystem image for the package -install -d $IPK_DIR/www/meshchat -install www/* $IPK_DIR/www/meshchat -install -d $IPK_DIR/www/cgi-bin -install -m 755 meshchat $IPK_DIR/www/cgi-bin -install -m 644 meshchatlib.lua $IPK_DIR/www/cgi-bin -install -m 644 meshchatconfig.lua $IPK_DIR/www/cgi-bin -install -D support/meshchatsync-init.d -m 755 $IPK_DIR/etc/init.d/meshchatsync -install -D support/meshchatsync -m 755 $IPK_DIR/usr/local/bin/meshchatsync +if [[ "$OSNAME" == "debian" ]]; then + install -d $IPK_DIR/DEBIAN + install -m 644 package/meshchat/* $IPK_DIR/DEBIAN + install -d $IPK_DIR/var/www/html/meshchat + install www/* $IPK_DIR/var/www/html/meshchat + install -d $IPK_DIR/usr/lib/cgi-bin + install -m 755 meshchat $IPK_DIR/usr/lib/cgi-bin + install -m 644 meshchatlib.lua $IPK_DIR/usr/lib/cgi-bin + install -m 644 meshchatconfig.lua $IPK_DIR/usr/lib/cgi-bin + install -D support/meshchatsync-init.d -m 755 $IPK_DIR/etc/init.d/meshchatsync + install -D support/meshchatsync -m 755 $IPK_DIR/usr/local/bin/meshchatsync + install -d $IPK_DIR/usr/local/lib/lua/5.4/net + install -m 644 lib/json.lua $IPK_DIR/usr/local/lib/lua/5.4/net +elif [[ "$OSNAME" == "openwrt" ]]; then + install -d $IPK_DIR/www/meshchat + install www/* $IPK_DIR/www/meshchat + install -d $IPK_DIR/www/cgi-bin + install -m 755 meshchat $IPK_DIR/www/cgi-bin + install -m 644 meshchatlib.lua $IPK_DIR/www/cgi-bin + install -m 644 meshchatconfig.lua $IPK_DIR/www/cgi-bin + install -D support/meshchatsync-init.d -m 755 $IPK_DIR/etc/init.d/meshchatsync + install -D support/meshchatsync -m 755 $IPK_DIR/usr/local/bin/meshchatsync + install -d $IPK_DIR/usr/lib/lua + install -m 644 lib/json.lua $IPK_DIR/usr/lib/lua +fi diff --git a/package/update-version.sh b/package/update-version.sh index 9e169c8..76f8d04 100755 --- a/package/update-version.sh +++ b/package/update-version.sh @@ -39,6 +39,7 @@ echo "${version}" > VERSION echo "Updating code references to version ${version}" sed -i "s/^Version:.*/Version: $version/" $IPK_DIR/CONTROL/control +sed -i "s/^Version:.*/Version: $version/" $IPK_DIR/DEBIAN/control # Update the version in meshchatconfig.lua if present if [[ -f $IPK_DIR/www/cgi-bin/meshchatconfig.lua ]]; then From 379c2418e4940ec851e39c381dd959b2a9b05c12 Mon Sep 17 00:00:00 2001 From: Gerard Hickey Date: Sat, 6 Apr 2024 18:58:38 -0400 Subject: [PATCH 2/6] Divide debian and openwrt package metadata files Signed-off-by: Gerard Hickey --- .../workflow-meshchat-debian-package.yaml | 2 +- package/debian/control | 10 +++++ package/{meshchat => debian}/postinst | 0 package/{meshchat => debian}/preinst | 0 package/{meshchat => debian}/prerm | 0 package/meshchat-api/control | 10 ----- package/{meshchat => openwrt}/control | 2 +- package/openwrt/postinst | 38 +++++++++++++++++++ package/openwrt/preinst | 19 ++++++++++ package/openwrt/prerm | 8 ++++ package/populate-meshchat-api-fs.sh | 15 -------- package/populate-meshchat-fs.sh | 19 ++++++---- 12 files changed, 89 insertions(+), 34 deletions(-) create mode 100644 package/debian/control rename package/{meshchat => debian}/postinst (100%) rename package/{meshchat => debian}/preinst (100%) rename package/{meshchat => debian}/prerm (100%) delete mode 100755 package/meshchat-api/control rename package/{meshchat => openwrt}/control (74%) create mode 100755 package/openwrt/postinst create mode 100755 package/openwrt/preinst create mode 100755 package/openwrt/prerm delete mode 100755 package/populate-meshchat-api-fs.sh diff --git a/.github/workflows/workflow-meshchat-debian-package.yaml b/.github/workflows/workflow-meshchat-debian-package.yaml index 13a0f89..114a2c2 100644 --- a/.github/workflows/workflow-meshchat-debian-package.yaml +++ b/.github/workflows/workflow-meshchat-debian-package.yaml @@ -32,7 +32,7 @@ jobs: - run: package/update-version.sh ${{ inputs.build_dir }} # - run: info "Packing up MeshChat files" - run: dpkg-deb --root-owner-group --build ${{ inputs.build_dir }} - - run: mv meshchat-deb.deb meshchat_${{ inputs.build_version }}_all.deb + - run: mv package/meshchat-deb.deb meshchat_${{ inputs.build_version }}_all.deb - id: detect-package-file run: echo "file=meshchat_${{inputs.build_version }}_all.deb" >> $GITHUB_OUTPUT - run: echo "${{ steps.detect-package-file.outputs.file }}" diff --git a/package/debian/control b/package/debian/control new file mode 100644 index 0000000..27438a1 --- /dev/null +++ b/package/debian/control @@ -0,0 +1,10 @@ +Package: meshchat +Version: +Depends: lua5.4 +Provides: +Source: package/meshchat +Section: net +Priority: optional +Maintainer: Gerard Hickey +Architecture: all +Description: P2P distributed chat for mesh networks diff --git a/package/meshchat/postinst b/package/debian/postinst similarity index 100% rename from package/meshchat/postinst rename to package/debian/postinst diff --git a/package/meshchat/preinst b/package/debian/preinst similarity index 100% rename from package/meshchat/preinst rename to package/debian/preinst diff --git a/package/meshchat/prerm b/package/debian/prerm similarity index 100% rename from package/meshchat/prerm rename to package/debian/prerm diff --git a/package/meshchat-api/control b/package/meshchat-api/control deleted file mode 100755 index 0761bf2..0000000 --- a/package/meshchat-api/control +++ /dev/null @@ -1,10 +0,0 @@ -Package: meshchat-api -Version: -Depends: lua -Provides: -Source: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY -Section: net -Priority: optional -Maintainer: Tim Wilkinson (KN6PLV) and Trevor Paskett (K7FPV) -Architecture: all -Description: P2P distributed chat for mesh networks diff --git a/package/meshchat/control b/package/openwrt/control similarity index 74% rename from package/meshchat/control rename to package/openwrt/control index d78266e..0791ad5 100644 --- a/package/meshchat/control +++ b/package/openwrt/control @@ -5,6 +5,6 @@ Provides: Source: package/meshchat Section: net Priority: optional -Maintainer: Tim Wilkinson (KN6PLV) and Trevor Paskett (K7FPV) +Maintainer: Gerard Hickey Architecture: all Description: P2P distributed chat for mesh networks diff --git a/package/openwrt/postinst b/package/openwrt/postinst new file mode 100755 index 0000000..67004c2 --- /dev/null +++ b/package/openwrt/postinst @@ -0,0 +1,38 @@ +#!/bin/sh + +grep "|8080|meshchat" /etc/config.mesh/_setup.services.dmz &> /dev/null +DMZPRESENT=$? +grep "|8080|meshchat" /etc/config.mesh/_setup.services.nat &> /dev/null +NATPRESENT=$? +NODEMODE=$(uci -q -c /etc/local/uci/ get hsmmmesh.settings.config) +RAND=$(awk 'BEGIN{srand();print int(rand()*10000) }') +RESTART=0 + +if [ "$DMZPRESENT" != 0 ]; then + echo "MeshChat-$RAND|1|http|$(uname -n)|8080|meshchat" >> /etc/config.mesh/_setup.services.dmz + RESTART=1 +fi + +if [ "$NATPRESENT" != 0 ]; then + echo "MeshChat-$RAND|1|http|$(uname -n)|8080|meshchat" >> /etc/config.mesh/_setup.services.nat + RESTART=1 +fi + +if [ "$NODEMODE" = "mesh" -a "$RESTART" = "1" ]; then + echo "Applying service announcement" + /usr/local/bin/node-setup -a -p mesh &> /dev/null + /etc/init.d/olsrd restart &> /dev/null +fi + +/etc/init.d/meshchatsync enable +/etc/init.d/meshchatsync start + +echo "
" + +echo "Mesh Chat has been setup at http://$(uname -n):8080/meshchat" +echo "
" +if [ "$RESTART" = "1" ]; then + echo "An advertised service has been added for Mesh Chat on the Services configuration page" +fi + +exit 0 diff --git a/package/openwrt/preinst b/package/openwrt/preinst new file mode 100755 index 0000000..9864975 --- /dev/null +++ b/package/openwrt/preinst @@ -0,0 +1,19 @@ +#!/bin/sh + +/etc/init.d/meshchatsync stop > /dev/null 2> /dev/null + +mkdir -p /www/meshchat + +# if there is not a meshchat_local.lua, then prepare one +if [ ! -f /www/cgi-bin/meshchat_local.lua ]; then + if [ -f /www/cgi-bin/meshchatconfig.lua ]; then + cp /www/cgi-bin/meshchatconfig.lua /www/cgi-bin/meshchat_local.lua + + # remove vars that should not be in meshchat_local.lua + sed -i "/^protocol_version/d; /^app_version/d" /www/cgi-bin/meshchat_local.lua + else + touch /www/cgi-bin/meshchat_local.lua + fi +fi + +exit 0 diff --git a/package/openwrt/prerm b/package/openwrt/prerm new file mode 100755 index 0000000..eb6c0f7 --- /dev/null +++ b/package/openwrt/prerm @@ -0,0 +1,8 @@ +#!/bin/sh + +/etc/init.d/meshchatsync disable +/etc/init.d/meshchatsync stop + +rm -rf /tmp/meshchat + +exit 0 diff --git a/package/populate-meshchat-api-fs.sh b/package/populate-meshchat-api-fs.sh deleted file mode 100755 index f68f50a..0000000 --- a/package/populate-meshchat-api-fs.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# This script runs from the top of the project directory and -# creates the filesystem image for the MeshChat API package. - -IPK_DIR=$1 - -# Populate the CONTROL portion of the package -mkdir -p $IPK_DIR/CONTROL -cp -p package/meshchat-api/* $IPK_DIR/CONTROL/ -sed -i "s%\$GITHUB_SERVER_URL%$GITHUB_SERVER_URL%" $IPK_DIR/CONTROL/control -sed -i "s%\$GITHUB_REPOSITORY%$GITHUB_REPOSITORY%" $IPK_DIR/CONTROL/control - -# Populate the filesystem image for the package -install -D api/meshchat -m 755 $IPK_DIR/www/cgi-bin/meshchat diff --git a/package/populate-meshchat-fs.sh b/package/populate-meshchat-fs.sh index 6f98c85..5d5d177 100755 --- a/package/populate-meshchat-fs.sh +++ b/package/populate-meshchat-fs.sh @@ -6,16 +6,15 @@ IPK_DIR=$1 OSNAME=$2 -# Populate the CONTROL portion of the package -mkdir -p $IPK_DIR/CONTROL -cp -p package/meshchat/* $IPK_DIR/CONTROL/ -sed -i "s%\$GITHUB_SERVER_URL%$GITHUB_SERVER_URL%" $IPK_DIR/CONTROL/control -sed -i "s%\$GITHUB_REPOSITORY%$GITHUB_REPOSITORY%" $IPK_DIR/CONTROL/control # Populate the filesystem image for the package if [[ "$OSNAME" == "debian" ]]; then - install -d $IPK_DIR/DEBIAN - install -m 644 package/meshchat/* $IPK_DIR/DEBIAN + # Populate the CONTROL portion of the package + mkdir -p $IPK_DIR/DEBIAN + cp -p package/debian/* $IPK_DIR/DEBIAN/ + sed -i "s%\$GITHUB_SERVER_URL%$GITHUB_SERVER_URL%" $IPK_DIR/DEBIAN/control + sed -i "s%\$GITHUB_REPOSITORY%$GITHUB_REPOSITORY%" $IPK_DIR/DEBIAN/control + install -d $IPK_DIR/var/www/html/meshchat install www/* $IPK_DIR/var/www/html/meshchat install -d $IPK_DIR/usr/lib/cgi-bin @@ -27,6 +26,12 @@ if [[ "$OSNAME" == "debian" ]]; then install -d $IPK_DIR/usr/local/lib/lua/5.4/net install -m 644 lib/json.lua $IPK_DIR/usr/local/lib/lua/5.4/net elif [[ "$OSNAME" == "openwrt" ]]; then + # Populate the CONTROL portion of the package + mkdir -p $IPK_DIR/CONTROL + cp -p package/openwrt/* $IPK_DIR/CONTROL/ + sed -i "s%\$GITHUB_SERVER_URL%$GITHUB_SERVER_URL%" $IPK_DIR/CONTROL/control + sed -i "s%\$GITHUB_REPOSITORY%$GITHUB_REPOSITORY%" $IPK_DIR/CONTROL/control + install -d $IPK_DIR/www/meshchat install www/* $IPK_DIR/www/meshchat install -d $IPK_DIR/www/cgi-bin From 301d5c0dc8509b09c6634b4a86590935055d352d Mon Sep 17 00:00:00 2001 From: Gerard Hickey Date: Sun, 7 Apr 2024 09:55:26 -0400 Subject: [PATCH 3/6] Replace nixio modules with pure Lua functions Signed-off-by: Gerard Hickey --- meshchat | 139 +++++++++++++++++++++---------------------- meshchatlib.lua | 136 +++++++++++++++++++++++++++++++----------- support/meshchatsync | 74 +++++++++++------------ 3 files changed, 208 insertions(+), 141 deletions(-) diff --git a/meshchat b/meshchat index 2747936..3efb354 100755 --- a/meshchat +++ b/meshchat @@ -38,10 +38,9 @@ package.path = package.path .. ";/www/cgi-bin/?.lua" require('luci.http') -local json = require("json") -require("nixio") require("meshchatconfig") -require("meshchatlib") +local json = require("json") +local lib = require("meshchatlib") --- -- @module meshchat @@ -49,7 +48,7 @@ require("meshchatlib") local query = {} local uploadfilename if os.getenv("QUERY_STRING") ~= "" or os.getenv("REQUEST_METHOD") == "POST" then - local request = luci.http.Request(nixio.getenv(), + local request = luci.http.Request(lib.getenv(), function() local v = io.read(1024) if not v then @@ -65,7 +64,7 @@ if os.getenv("QUERY_STRING") ~= "" or os.getenv("REQUEST_METHOD") == "POST" then if meta and meta.file then uploadfilename = meta.file end - nixio.fs.mkdir(tmp_upload_dir) + mkdir(tmp_upload_dir) fp = io.open(tmp_upload_dir .. "/file", "w") end if chunk then @@ -113,8 +112,8 @@ function config() local settings = { version = app_version, protocol_verison = protocol_version, - node = node_name(), - zone = zone_name(), + node = lib.node_name(), + zone = lib.zone_name(), default_channel = default_channel, debug = debug, } @@ -166,21 +165,21 @@ function send_message() epoch = query.epoch end - get_lock() + lib.get_lock(lock_file) local f = io.open(messages_db_file, "a") if not f then - release_lock() + lib.release_lock(lock_file) -- TODO return a proper error code on failure die("Cannot send message") end - f:write(id .. "\t" .. epoch .. "\t" .. message .. "\t" .. query.call_sign .. "\t" .. node_name() .. "\t" .. platform .. "\t" .. query.channel .. "\n") + f:write(id .. "\t" .. epoch .. "\t" .. message .. "\t" .. query.call_sign .. "\t" .. lib.node_name() .. "\t" .. platform .. "\t" .. query.channel .. "\n") f:close() - sort_and_trim_db() - save_messages_db_version() + lib.sort_and_trim_db() + lib.save_messages_db_version() - release_lock() + lib.release_lock(lock_file) print([[{"status":200, "response":"OK"}]]) end @@ -220,9 +219,9 @@ function messages() print("\r") io.flush() - get_lock() + lib.get_lock(lock_file) - local node = node_name() + local node = lib.node_name() -- read in message DB and parse the contents local messages = {} @@ -246,7 +245,7 @@ function messages() local users = {} -- read the users status file - if nixio.fs.stat(local_users_status_file) then + if lib.file_exists(local_users_status_file) then for line in io.lines(local_users_status_file) do local call_sign = line:match("^([^\t]+)\t") @@ -283,7 +282,7 @@ function messages() end end - release_lock() + lib.release_lock(lock_file) -- order messages according to time table.sort(messages, function(a, b) return a.epoch > b.epoch end) @@ -312,10 +311,10 @@ function sync_status() print("Content-type: application/json\r") print("\r") - get_lock() + lib.get_lock(lock_file) local status = {} - if nixio.fs.stat(sync_status_file) then + if lib.file_exists(sync_status_file) then for line in io.lines(sync_status_file) do local node, epoch = line:match("^(.*)\t(.*)$") @@ -326,7 +325,7 @@ function sync_status() end end - release_lock() + lib.release_lock(lock_file) table.sort(status, function(a, b) return a.epoch > b.epoch end) @@ -335,7 +334,7 @@ end --- Return a list of messages as text. function messages_raw() - get_lock() + lib.get_lock(lock_file) local md5 = file_md5(messages_db_file) local lines = {} @@ -344,7 +343,7 @@ function messages_raw() lines[#lines + 1] = line end - release_lock() + lib.release_lock(lock_file) print("Content-MD5: " .. md5 .. "\r") print("Content-type: text/plain\r") @@ -358,11 +357,11 @@ end --- Return the current MD5 has of the messages database. function messages_md5() - get_lock() + lib.get_lock(lock_file) - local md5 = file_md5(messages_db_file) + local md5 = lib.file_md5(messages_db_file) - release_lock() + lib.release_lock(lock_file) print("Content-type: text/plain\r") print("\r") @@ -371,16 +370,16 @@ end --- Package the raw messages as the messages.txt file. function messages_download() - get_lock() + lib.get_lock() - local md5 = file_md5(messages_db_file) + local md5 = lib.file_md5(messages_db_file) local lines = {} for line in io.lines(messages_db_file) do lines[#lines + 1] = line end - release_lock() + lib.release_lock(lock_file) print("Content-MD5: " .. md5 .. "\r") print("Content-Disposition: attachment; filename=messages.txt;\r") @@ -395,16 +394,16 @@ end --- Return the list of users as raw text. function users_raw() - get_lock() + lib.get_lock(lock_file) - local md5 = file_md5(local_users_status_file) + local md5 = lib.file_md5(local_users_status_file) local lines = {} for line in io.lines(local_users_status_file) do lines[#lines + 1] = line end - release_lock() + lib.release_lock(lock_file) print("Content-MD5: " .. md5 .. "\r") print("Content-type: text/plain\r") @@ -438,7 +437,7 @@ function users() print("Content-type: application/json\r") print("\r") - get_lock() + lib.get_lock(lock_file) local users = {} for line in io.lines(local_users_status_file) @@ -468,7 +467,7 @@ function users() end end - release_lock() + lib.release_lock(lock_file) table.sort(users, function(a, b) return a.epoch > b.epoch end) @@ -477,24 +476,24 @@ end --- Return a list of files as plain text. function local_files_raw() - get_lock() + lib.get_lock(lock_file) - local tmp_file = meshchat_path .. "/meshchat_files_local." .. nixio.getpid() + local tmp_file = meshchat_path .. "/meshchat_files_local." .. math.random(5000) local f = io.open(tmp_file, "w") if not f then die("Cannot list local files") end - local name = node_name() .. ":" .. os.getenv("SERVER_PORT") - for file in nixio.fs.dir(local_files_dir) + local name = lib.node_name() .. ":" .. os.getenv("SERVER_PORT") + for file in lib.filelist(local_files_dir) do - local stat = nixio.fs.stat(local_files_dir .. "/" .. file) + local stat = lib.file_exists(local_files_dir .. "/" .. file) f:write(file .. "\t" .. name .. "\t" .. stat.size .. "\t" .. stat.mtime .. platform .. "\n") end f:close() - local md5 = file_md5(tmp_file) + local md5 = lib.file_md5(tmp_file) - release_lock() + lib.release_lock(lock_file) print("Content-MD5: " .. md5 .. "\r") print("Content-type: text/plain\r") @@ -505,7 +504,7 @@ function local_files_raw() print(line) end - nixio.fs.remove(tmp_file) + lib.unlink(tmp_file) end --- Return a specified file as a download. @@ -525,17 +524,17 @@ function file_download() local file = query.file local file_path = local_files_dir .. "/" .. file - if file == "" or not nixio.fs.stat(file_path) then + if file == "" or not lib.file_exists(file_path) then error("no file") return end - get_lock() + lib.get_lock(lock_file) - local md5 = file_md5(file_path) + local md5 = lib.file_md5(file_path) local f = io.open(file_path, "rb") - release_lock() + lib.release_lock(lock_file) print("Content-MD5: " .. md5 .. "\r") print("Content-Disposition: attachment; filename=\"" .. file .. "\";\r") @@ -570,13 +569,13 @@ function files() print("Content-type: application/json\r") print("\r") - get_lock() + lib.get_lock(lock_file) local files = {} - local node = node_name() .. ":" .. os.getenv("SERVER_PORT") - for file in nixio.fs.dir(local_files_dir) + local node = lib.node_name() .. ":" .. os.getenv("SERVER_PORT") + for file in lib.filelist(local_files_dir) do - local stat = nixio.fs.stat(local_files_dir .. "/" .. file) + local stat = lib.file_exists(local_files_dir .. "/" .. file) files[#files + 1] = { file = file, epoch = stat.mtime, @@ -586,7 +585,7 @@ function files() } files[#files]["local"] = 1 end - for file in nixio.fs.dir(meshchat_path) + for file in lib.filelist(meshchat_path) do if file:match("^remote_files%.") then for line in io.lines(meshchat_path .. "/" .. file) @@ -606,9 +605,9 @@ function files() end end - local stats = file_storage_stats() + local stats = lib.file_storage_stats() - release_lock() + lib.release_lock(lock_file) table.sort(files, function(a, b) return a.epoch > b.epoch end) @@ -620,7 +619,7 @@ end --- Delete the specified file. function delete_file() - nixio.fs.remove(local_files_dir .. "/" .. query.file) + lib.unlink(local_files_dir .. "/" .. query.file) print("Content-type: application/json\r") print("\r") print([[{"status":200, "response":"OK"}]]) @@ -630,7 +629,7 @@ end function messages_version() print("Content-type: text/plain\r") print("\r") - print(get_messages_db_version()) + print(lib.get_messages_db_version()) end --- Return a JSON document of the messages database. @@ -638,9 +637,9 @@ function messages_version_ui() print("Content-type: application/json\r") print("\r") - print(string.format([[{"messages_version":%s}]], get_messages_db_version())) + print(string.format([[{"messages_version":%s}]], lib.get_messages_db_version())) - get_lock() + lib.get_lock(lock_file) local users = {} for line in io.lines(local_users_status_file) @@ -651,7 +650,7 @@ function messages_version_ui() end end - local node = node_name() + local node = lib.node_name() local epoch = os.time() if tonumber(query.epoch) > epoch then epoch = query.epoch @@ -676,7 +675,7 @@ function messages_version_ui() f:close() end - release_lock() + lib.release_lock(lock_file) end --- Return a JSON document describing all the hosts. @@ -699,7 +698,7 @@ function hosts() print("Content-type: application/json\r") print("\r") - local node = node_name() + local node = lib.node_name() local hosts = {} for line in io.lines("/var/dhcp.leases") do @@ -711,10 +710,10 @@ function hosts() } end - for line in io.lines("/etc/config.mesh/_setup.dhcp.dmz") + for line in io.lines("/etc/mesh/_setup.dhcp.dmz") do local mac, num, hostname = line:match("^(%S+)%s(%S+)%s(%S+)$") - local ip = gethostbyname(hostname) + local ip = lib.gethostbyname(hostname) hosts[#hosts + 1] = { ip = ip, hostname = hostname, @@ -722,7 +721,7 @@ function hosts() } end - for _, remote_node in ipairs(node_list()) + for _, remote_node in ipairs(lib.node_list()) do local f = io.popen("/usr/bin/curl --retry 0 --connect-timeout " .. connect_timeout .. " --speed-time " .. speed_time .. " --speed-limit " .. speed_limit .. " http://" .. remote_node .. ":8080/cgi-bin/meshchat?action=hosts_raw 2> /dev/null") if f then @@ -761,10 +760,10 @@ function hosts_raw() } end - for line in io.lines("/etc/config.mesh/_setup.dhcp.dmz") + for line in io.lines("/etc/mesh/_setup.dhcp.dmz") do local mac, num, hostname = line:match("^(%S+)%s(%S+)%s(%S+)$") - local ip = gethostbyname(hostname) + local ip = lib.gethostbyname(hostname) hosts[#hosts + 1] = { ip = ip, hostname = hostname @@ -779,19 +778,19 @@ end --- Store a file into the file directory. function upload_file() - local new_file_size = nixio.fs.stat(tmp_upload_dir .. "/file").size + local new_file_size = lib.file_exists(tmp_upload_dir .. "/file").size - get_lock() + lib.get_lock(lock_file) - local stats = file_storage_stats() + local stats = lib.file_storage_stats() - release_lock() + lib.release_lock(lock_file) print("Content-type: application/json\r") print("\r") if new_file_size > stats.files_free then - nixio.fs.remove(tmp_upload_dir .. "/file") + lib.unlink(tmp_upload_dir .. "/file") print([[{"status":500, "response":"Not enough storage, delete some files"}]]) else local fi = io.open(tmp_upload_dir .. "/file", "r") @@ -799,7 +798,7 @@ function upload_file() fo:write(fi:read("*a")) fi:close() fo:close() - nixio.fs.remove(tmp_upload_dir .. "/file") + lib.unlink(tmp_upload_dir .. "/file") print([[{"status":200, "response":"OK"}]]) end end diff --git a/meshchatlib.lua b/meshchatlib.lua index f409ea2..6b69be4 100755 --- a/meshchatlib.lua +++ b/meshchatlib.lua @@ -34,8 +34,10 @@ --]] -require("nixio") require("uci") +require("socket") + +local M = {} --- @module meshchatlib @@ -43,7 +45,7 @@ require("uci") -- -- @tparam string msg Message to display -- -function die(msg) +function M:die(msg) os.exit(-1) end @@ -52,7 +54,7 @@ end -- @tparam string cmd Command line to execute -- @treturn string stdout of the command -- -function capture(cmd) +function M:capture(cmd) local f = io.popen(cmd) if not f then return "" @@ -62,6 +64,55 @@ function capture(cmd) return output end +-- TODO remove AAMM specific parts +function M:filelist(dir) + local files = {} + for file in io.popen("ls -1 " .. dir .. "/*.txt"):lines() do + file = file:gsub(Config.aam_dir .. "/", "") + table.insert(files, file) + end + return files +end + +function M:file_exists(path) + local f = io.open(path, "r") + return f ~= nil and io.close(f) +end + +function M:file_size(path) + local f = io.open(path, "r") + local size = f:seek("end") + f:close() + return size +end + +function M:file_mtime(path) + local proc = io.popen("ls --full-time " .. path, "r") + local file_info = proc:read("*all") + proc:close() + -- -rw-r--r-- 1 root root 0 2023-09-29 00:32:22 -0400 foo + + local yr, mo, da, hr, mi, se, tz = file_info:match("[-rwx]+%s+%d+%s%w+%s+%w+%s+%d+%s(%d+)-(%d+)-(%d+)%s(%d+):(%d+):(%d+)%s([-+%d]+)%s") + local offset = (tz / 100) * 3600 + return os.time({year=yr, month=mo, day=da, hour=hr, min=mi, sec=se}) - offset +end + +function M:mkdir(path) + os.execute('mkdir ' .. path .. ' >/dev/null 2>&1') +end + +function M:unlink(path) + os.execute('rm ' .. path .. ' >/dev/null 2>&1') +end + +function M:chmod(path, mode) + os.execute('chmod ' .. mode .. ' ' .. path .. ' >/dev/null 2>&1') +end + +function M:rename(src, dest) + os.execute('mv ' .. src .. ' ' .. dest .. ' >/dev/null 2>&1') +end + --- -- Retrieve the current node name. -- @@ -70,7 +121,7 @@ end -- -- @treturn string Name of current node -- -function node_name() +function M:node_name() return uci.cursor("/etc/local/uci"):get("hsmmmesh", "settings", "node") or "" end @@ -79,14 +130,14 @@ end -- -- @treturn string Name of MeshChat zone -- -function zone_name() +function M:zone_name() local dmz_mode = uci.cursor("/etc/config.mesh"):get("aredn", "@dmz[0]", "mode") local servfile = "/etc/config.mesh/_setup.services.nat" -- LAN mode is not set to NAT if dmz_mode ~= "0" then servfile = "/etc/config.mesh/_setup.services.dmz" end - if nixio.fs.access(servfile) then + if M.file_exists(servfile) then for line in io.lines(servfile) do local zone = line:match("^(.*)|.*|.*|.*|.*|meshchat$") @@ -98,18 +149,21 @@ function zone_name() return "MeshChat" end -messages_db_file = messages_db_file_orig .. "." .. zone_name() +messages_db_file = messages_db_file_orig .. "." .. M.zone_name() -local lock_fd -function get_lock() - if not lock_fd then - lock_fd = nixio.open(lock_file, "w", "666") +local lock_fd = false +function M:get_lock(lock_file) + while (not os.execute("mkdir " .. lock_file .. " >/dev/null 2>&1")) do + socket.select(nil, nil, 0.2) end - lock_fd:lock("lock") + lock_fd = true end -function release_lock() - lock_fd:lock("ulock") +function M:release_lock(lock_file) + if (lock_fd) then + os.execute("rmdir " .. lock_file) + lock_fd = false + end end --- Generate the MD5 sum of a file. @@ -124,15 +178,15 @@ end -- @tparam string file Path to file -- @treturn string Result of `md5sum` of the file -- -function file_md5(file) - if not nixio.fs.stat(file) then +function M:file_md5(file) + if not file_exists(file) then return "" end local output = capture("md5sum " .. file:gsub(" ", "\\ ")):match("^(%S+)%s") return output and output or "" end -function get_messages_db_version() +function M:get_messages_db_version() for line in io.lines(messages_version_file) do line = line:gsub("\n$", "") @@ -140,14 +194,14 @@ function get_messages_db_version() end end -function save_messages_db_version() +function M:save_messages_db_version() local f = io.open(messages_version_file, "w") - f:write(get_messages_version_file() .. "\n") + f:write(M.get_messages_version_file() .. "\n") f:close() - nixio.fs.chmod(messages_version_file, "666") + M.chmod(messages_version_file, "666") end -function get_messages_version_file() +function M:get_messages_version_file() local sum = 0 for line in io.lines(messages_db_file) do @@ -170,11 +224,11 @@ end -- -- @treturn string Generated hash value -- -function hash() - return capture("echo " .. os.time() .. math.random(99999) .. " | md5sum"):sub(1, 8) +function M:hash() + return M.capture("echo " .. os.time() .. math.random(99999) .. " | md5sum"):sub(1, 8) end -function sort_and_trim_db() +function M:sort_and_trim_db() local valid_time = os.time() + valid_future_message_time local unused_count = max_messages_db_size local messages = {} @@ -212,7 +266,7 @@ function sort_and_trim_db() f:close() end -function file_storage_stats() +function M:file_storage_stats() local lines = capture("df -k " .. local_files_dir) local blocks, used, available, perc = lines:match("(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%%") used = tonumber(used) * 1024 @@ -220,9 +274,9 @@ function file_storage_stats() local total = used + available local local_files_bytes = 0 - for file in nixio.fs.dir(local_files_dir) + for file in M.filelist(local_files_dir) do - local_files_bytes = local_files_bytes + nixio.fs.stat(local_files_dir .. "/" .. file).size + local_files_bytes = local_files_bytes + M.file_size(local_files_dir .. "/" .. file) end if max_file_storage - local_files_bytes < 0 then @@ -238,19 +292,19 @@ function file_storage_stats() } end -function gethostbyname(hostname) +function M:gethostbyname(hostname) return capture("nslookup " .. hostname):match("Address 1:%s*([%d%.]+)") end -function node_list() - if not nixio.fs.stat("/var/run/services_olsr") then +function M:node_list() + if not M.file_exists("/var/run/services_olsr") then return {} end - local local_node = node_name():lower() - local zone = zone_name() + local local_node = M.node_name():lower() + local zone = M.zone_name() local nodes = {} - local pattern = "http://(%S+):(%d+)/meshchat|tcp|" .. str_escape(zone) .. "%s" + local pattern = "http://(%S+):(%d+)/meshchat|tcp|" .. M.str_escape(zone) .. "%s" for line in io.lines("/var/run/services_olsr") do local node, port = line:match(pattern) @@ -280,6 +334,20 @@ end -- @tparam string str String to encode -- @treturn string Encoded string -- -function str_escape(str) +function M:str_escape(str) return str:gsub("%(", "%%("):gsub("%)", "%%)"):gsub("%%", "%%%%"):gsub("%.", "%%."):gsub("%+", "%%+"):gsub("-", "%%-"):gsub("%*", "%%*"):gsub("%[", "%%["):gsub("%?", "%%?"):gsub("%^", "%%^"):gsub("%$", "%%$") end + + +function M:getenv() + local osEnv = {} + + for line in io.popen("set"):lines() do + envName = line:match("^[^=]+") + osEnv[envName] = os.getenv(envName) + end + + return osEnv +end + +return M diff --git a/support/meshchatsync b/support/meshchatsync index b10631b..96fb3ec 100755 --- a/support/meshchatsync +++ b/support/meshchatsync @@ -36,42 +36,41 @@ --]] package.path = package.path .. ";/www/cgi-bin/?.lua" -require("nixio") require("meshchatconfig") -require("meshchatlib") +local lib = require("meshchatlib") local sync_status = {} local non_mesh_chat_nodes = {} -local node = node_name() +local node = lib.node_name() -if not nixio.fs.stat(meshchat_path) then - nixio.fs.mkdir(meshchat_path) - nixio.fs.mkdir(local_files_dir) +if not lib.file_exists(meshchat_path) then + lib.mkdir(meshchat_path) + lib.mkdir(local_files_dir) end -if not nixio.fs.stat(messages_db_file) then +if not lib.file_exists(messages_db_file) then io.open(messages_db_file, "w"):close() - nixio.fs.chmod(messages_db_file, "666") + lib.chmod(messages_db_file, "666") end io.open(local_users_status_file, "a"):close() io.open(remote_users_status_file, "a"):close() -save_messages_db_version() +lib.save_messages_db_version() -nixio.fs.chmod(meshchat_path, "666") +lib.chmod(meshchat_path, "666") io.open(lock_file, "a"):close() function log_status() local cur_status = {} - if not nixio.fs.stat(sync_status_file) then + if not lib.file_exists(sync_status_file) then io.open(sync_status_file, "w"):close() end - get_lock() + lib.get_lock() for line in io.lines(sync_status_file) do @@ -94,7 +93,7 @@ function log_status() f:close() end - release_lock() + lib.release_lock() end function merge_messages() @@ -107,7 +106,7 @@ function merge_messages() rmsg[key] = line end - get_lock() + lib.get_lock() for line in io.lines(messages_db_file) do @@ -126,11 +125,11 @@ function merge_messages() f:close() end - sort_and_trim_db() + lib.sort_and_trim_db() - save_messages_db_version() + lib.save_messages_db_version() - release_lock() + lib.release_lock() end function merge_users() @@ -145,7 +144,7 @@ function merge_users() end end - get_lock() + lib.get_lock() for line in io.lines(remote_users_status_file) do @@ -174,12 +173,12 @@ function merge_users() f:close() end - release_lock() + lib.release_lock() end while true do - local nodes = node_list() + local nodes = lib.node_list() sync_status = {} @@ -200,14 +199,14 @@ do port = ":8080" end - local version = get_messages_db_version() + local version = lib.get_messages_db_version() -- Poll non mesh chat nodes at a longer interval if non_mesh_chat_nodes[remote_node] and os.time() < non_mesh_chat_nodes[remote_node] then break end - nixio.fs.remove(meshchat_path .. "/remote_users") + lib.unlink(meshchat_path .. "/remote_users") -- Get remote users file local f = io.popen("/usr/bin/curl --retry 0 --connect-timeout " .. connect_timeout .. " --speed-time " .. speed_time .. " --speed-limit " .. speed_limit .. " -sD - \"http://" .. remote_node .. port .. "/cgi-bin/meshchat?action=users_raw&platform=" .. platform .. "&node=" .. node .. "\" -o " .. meshchat_path .. "/remote_users 2>&1") @@ -222,9 +221,9 @@ do local md5 = output:match("Content%-MD5:%s([0-9a-f]+)\r\n") if md5 then - local f_md5 = file_md5(meshchat_path .. "/remote_users") + local f_md5 = lib.file_md5(meshchat_path .. "/remote_users") if md5 == f_md5 then - local cur_size = nixio.fs.stat(meshchat_path .. "/remote_users").size + local cur_size = lib.file_exists(meshchat_path .. "/remote_users").size if cur_size > 0 then merge_users() end @@ -232,25 +231,25 @@ do end -- Get remote files file - nixio.fs.remove(meshchat_path .. "/remote_files") + lib.unlink(meshchat_path .. "/remote_files") f = io.popen("/usr/bin/curl --retry 0 --connect-timeout " .. connect_timeout .. " --speed-time " .. speed_time .. " --speed-limit " .. speed_limit .. " -sD - \"http://" .. remote_node .. port .. "/cgi-bin/meshchat?action=local_files_raw\" -o " .. meshchat_path .. "/remote_files 2>&1") output = f:read("*a") f:close() md5 = output:match("Content%-MD5:%s([0-9a-f]+)\r\n") if md5 then - local f_md5 = file_md5(meshchat_path .. "/remote_files") - nixio.fs.remove(meshchat_path .. "/remote_files." .. remote_node) + local f_md5 = lib.file_md5(meshchat_path .. "/remote_files") + lib.unlink(meshchat_path .. "/remote_files." .. remote_node) if md5 == f_md5 then - local cur_size = nixio.fs.stat(meshchat_path .. "/remote_files").size + local cur_size = lib.file_exists(meshchat_path .. "/remote_files").size if cur_size > 0 then - nixio.fs.rename(meshchat_path .. "/remote_files", meshchat_path .. "/remote_files." .. remote_node) + lib.rename(meshchat_path .. "/remote_files", meshchat_path .. "/remote_files." .. remote_node) end end end -- Get remote messages - nixio.fs.remove(meshchat_path .. "/remote_messages") + lib.unlink(meshchat_path .. "/remote_messages") f = io.popen("/usr/bin/curl --retry 0 --connect-timeout " .. connect_timeout .. " --speed-time " .. speed_time .. " --speed-limit " .. speed_limit .. " \"http://" .. remote_node .. port .. "/cgi-bin/meshchat?action=messages_version\" -o - 2> /dev/null") local remote_version = f:read("*a") @@ -267,12 +266,12 @@ do local output = f:read("*a") f:close() - if nixio.fs.stat(meshchat_path .. "/remote_messages") then + if lib.file_exists(meshchat_path .. "/remote_messages") then local md5 = output:match("Content%-MD5:%s([0-9a-f]+)\r\n") if md5 then - local f_md5 = file_md5(meshchat_path .. "/remote_messages") + local f_md5 = lib.file_md5(meshchat_path .. "/remote_messages") if md5 == f_md5 then - local cur_size = nixio.fs.stat(meshchat_path .. "/remote_messages").size + local cur_size = lib.file_exists(meshchat_path .. "/remote_messages").size if cur_size > 0 then sync_status[remote_node] = os.time() merge_messages() @@ -285,9 +284,10 @@ do log_status() - nixio.fs.remove(meshchat_path .. "/remote_messages") - nixio.fs.remove(meshchat_path .. "/remote_users") - nixio.fs.remove(meshchat_path .. "/remote_files") + lib.unlink(meshchat_path .. "/remote_messages") + lib.unlink(meshchat_path .. "/remote_users") + lib.unlink(meshchat_path .. "/remote_files") - nixio.nanosleep(poll_interval, 0) + -- sleep for poll_interval seconds + os.execute('sleep ' .. poll_interval .. ' >/dev/null 2>&1') end From c39a8e4ca2099683cb48fcef8b6f5443e05f3c83 Mon Sep 17 00:00:00 2001 From: Gerard Hickey Date: Sun, 5 May 2024 15:14:33 -0400 Subject: [PATCH 4/6] Replace luci calls with pure Lua code Signed-off-by: Gerard Hickey --- meshchat | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/meshchat b/meshchat index 3efb354..f0bad74 100755 --- a/meshchat +++ b/meshchat @@ -37,26 +37,29 @@ package.path = package.path .. ";/www/cgi-bin/?.lua" -require('luci.http') -require("meshchatconfig") local json = require("json") local lib = require("meshchatlib") +local url = require("net/url") +require("meshchatconfig") --- -- @module meshchat local query = {} local uploadfilename -if os.getenv("QUERY_STRING") ~= "" or os.getenv("REQUEST_METHOD") == "POST" then - local request = luci.http.Request(lib.getenv(), - function() - local v = io.read(1024) - if not v then - io.close() - end - return v - end - ) + +if os.getenv("QUERY_STRING") ~= "" then + -- Process a GET request + query = url.parseQuery(os.getenv("QUERY_STRING")) +elseif os.getenv("REQUEST_METHOD") == "POST" then + -- Process a POST request + local request = '' + while v = io.read(1024) do + request = request .. v + end + + query = url.parseQuery(request) + local fp request:setfilehandler( function(meta, chunk, eof) From 90b5a6b3306789a1c82acd719ac7d94ef7cda0eb Mon Sep 17 00:00:00 2001 From: Gerard Hickey Date: Tue, 30 Jul 2024 20:06:52 -0400 Subject: [PATCH 5/6] Update Debian packaging files Signed-off-by: Gerard Hickey --- package/debian/control | 2 +- package/debian/postinst | 32 -------------------------------- package/debian/preinst | 12 ++++++------ 3 files changed, 7 insertions(+), 39 deletions(-) diff --git a/package/debian/control b/package/debian/control index 27438a1..d846370 100644 --- a/package/debian/control +++ b/package/debian/control @@ -1,6 +1,6 @@ Package: meshchat Version: -Depends: lua5.4 +Depends: lua5.4, nginx Provides: Source: package/meshchat Section: net diff --git a/package/debian/postinst b/package/debian/postinst index 67004c2..7394745 100755 --- a/package/debian/postinst +++ b/package/debian/postinst @@ -1,38 +1,6 @@ #!/bin/sh -grep "|8080|meshchat" /etc/config.mesh/_setup.services.dmz &> /dev/null -DMZPRESENT=$? -grep "|8080|meshchat" /etc/config.mesh/_setup.services.nat &> /dev/null -NATPRESENT=$? -NODEMODE=$(uci -q -c /etc/local/uci/ get hsmmmesh.settings.config) -RAND=$(awk 'BEGIN{srand();print int(rand()*10000) }') -RESTART=0 - -if [ "$DMZPRESENT" != 0 ]; then - echo "MeshChat-$RAND|1|http|$(uname -n)|8080|meshchat" >> /etc/config.mesh/_setup.services.dmz - RESTART=1 -fi - -if [ "$NATPRESENT" != 0 ]; then - echo "MeshChat-$RAND|1|http|$(uname -n)|8080|meshchat" >> /etc/config.mesh/_setup.services.nat - RESTART=1 -fi - -if [ "$NODEMODE" = "mesh" -a "$RESTART" = "1" ]; then - echo "Applying service announcement" - /usr/local/bin/node-setup -a -p mesh &> /dev/null - /etc/init.d/olsrd restart &> /dev/null -fi - /etc/init.d/meshchatsync enable /etc/init.d/meshchatsync start -echo "
" - -echo "Mesh Chat has been setup at http://$(uname -n):8080/meshchat" -echo "
" -if [ "$RESTART" = "1" ]; then - echo "An advertised service has been added for Mesh Chat on the Services configuration page" -fi - exit 0 diff --git a/package/debian/preinst b/package/debian/preinst index 9864975..29acc87 100755 --- a/package/debian/preinst +++ b/package/debian/preinst @@ -2,17 +2,17 @@ /etc/init.d/meshchatsync stop > /dev/null 2> /dev/null -mkdir -p /www/meshchat +mkdir -p /var/www/html/meshchat # if there is not a meshchat_local.lua, then prepare one -if [ ! -f /www/cgi-bin/meshchat_local.lua ]; then - if [ -f /www/cgi-bin/meshchatconfig.lua ]; then - cp /www/cgi-bin/meshchatconfig.lua /www/cgi-bin/meshchat_local.lua +if [ ! -f /usr/lib/cgi-bin/meshchat_local.lua ]; then + if [ -f /usr/lib/cgi-bin/meshchatconfig.lua ]; then + cp /usr/lib/cgi-bin/meshchatconfig.lua /usr/lib/cgi-bin/meshchat_local.lua # remove vars that should not be in meshchat_local.lua - sed -i "/^protocol_version/d; /^app_version/d" /www/cgi-bin/meshchat_local.lua + sed -i "/^protocol_version/d; /^app_version/d" /usr/lib/cgi-bin/meshchat_local.lua else - touch /www/cgi-bin/meshchat_local.lua + touch /usr/lib/cgi-bin/meshchat_local.lua fi fi From d65affa820841328ec26edf5e1e1c12afc6300bd Mon Sep 17 00:00:00 2001 From: Gerard Hickey Date: Tue, 30 Jul 2024 20:56:58 -0400 Subject: [PATCH 6/6] Remove Provides line from Debian control file Signed-off-by: Gerard Hickey --- package/debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/package/debian/control b/package/debian/control index d846370..6718924 100644 --- a/package/debian/control +++ b/package/debian/control @@ -1,7 +1,6 @@ Package: meshchat Version: Depends: lua5.4, nginx -Provides: Source: package/meshchat Section: net Priority: optional