6d224861 came from a --no-checkout worktree whose empty index made the
commit drop every file except two. This restores 05b50d2b's full tree and
correctly adds stacks/stem95su/gdrive-sync.tf + the service-catalog stem95su
entry. Forward-only (parent=6d224861, no force-push); [ci skip] since the
live infra was never applied from the broken commit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
82 lines
2.9 KiB
Lua
82 lines
2.9 KiB
Lua
-- ot-recorder Lua hook: forward every location publish to Dawarich.
|
|
-- Loaded by ot-recorder via `--lua-script`. The hook() function is invoked
|
|
-- synchronously per publish; we fork curl with `&` to keep it fire-and-forget.
|
|
-- Dawarich's points table has UNIQUE (lonlat, timestamp, user_id) — duplicates
|
|
-- are safely dropped. The .rec file is always written regardless of hook result,
|
|
-- so a Dawarich 5xx loses nothing long-term (re-playable via backfill Job).
|
|
|
|
local function escape_shell_single(s)
|
|
return "'" .. tostring(s):gsub("'", "'\\''") .. "'"
|
|
end
|
|
|
|
local function json_escape_string(s)
|
|
return (s:gsub("\\", "\\\\")
|
|
:gsub('"', '\\"')
|
|
:gsub("\n", "\\n")
|
|
:gsub("\r", "\\r")
|
|
:gsub("\t", "\\t"))
|
|
end
|
|
|
|
-- Minimal JSON serializer — scalars, arrays, maps. Owntracks payloads are
|
|
-- all primitive/flat; no bignum or cyclic-ref concerns.
|
|
local function to_json(v)
|
|
local t = type(v)
|
|
if t == "nil" then return "null" end
|
|
if t == "number" then return tostring(v) end
|
|
if t == "boolean" then return tostring(v) end
|
|
if t == "string" then return '"' .. json_escape_string(v) .. '"' end
|
|
if t == "table" then
|
|
if #v > 0 or next(v) == nil then
|
|
local parts = {}
|
|
for i, x in ipairs(v) do parts[i] = to_json(x) end
|
|
return "[" .. table.concat(parts, ",") .. "]"
|
|
end
|
|
local parts = {}
|
|
for k, x in pairs(v) do
|
|
parts[#parts + 1] = '"' .. json_escape_string(tostring(k)) .. '":' .. to_json(x)
|
|
end
|
|
return "{" .. table.concat(parts, ",") .. "}"
|
|
end
|
|
return "null"
|
|
end
|
|
|
|
function otr_init()
|
|
otr.log("dawarich-bridge: init")
|
|
if not os.getenv("DAWARICH_API_KEY") then
|
|
otr.log("dawarich-bridge: WARN DAWARICH_API_KEY unset — hook will skip")
|
|
end
|
|
end
|
|
|
|
function otr_exit()
|
|
otr.log("dawarich-bridge: exit")
|
|
end
|
|
|
|
function otr_hook(topic, _type, data)
|
|
if _type ~= "location" then return end
|
|
local api_key = os.getenv("DAWARICH_API_KEY")
|
|
if not api_key or api_key == "" then
|
|
otr.log("dawarich-bridge: DAWARICH_API_KEY missing — dropping point")
|
|
return
|
|
end
|
|
-- Strip the base64 user avatar: ot-recorder appends a ~120KB `face` field
|
|
-- to enriched payloads which pushes the curl command past ARG_MAX (code=7
|
|
-- "Argument list too long"). Dawarich doesn't need it.
|
|
data.face = nil
|
|
local url = "https://dawarich.viktorbarzin.me/api/v1/owntracks/points?api_key=" .. api_key
|
|
local payload = to_json(data)
|
|
local cmd = table.concat({
|
|
"curl -sS -o /dev/null --max-time 5 -X POST",
|
|
"-H 'Content-Type: application/json'",
|
|
"-d", escape_shell_single(payload),
|
|
escape_shell_single(url),
|
|
"&",
|
|
}, " ")
|
|
local ok, reason, code = os.execute(cmd)
|
|
if not ok then
|
|
otr.log("dawarich-bridge: FAIL tst=" .. tostring(data.tst) ..
|
|
" reason=" .. tostring(reason) .. " code=" .. tostring(code) ..
|
|
" cmd=" .. cmd)
|
|
else
|
|
otr.log("dawarich-bridge: ok tst=" .. tostring(data.tst))
|
|
end
|
|
end
|