|
@@ -19,31 +19,30 @@
|
|
|
-- Try to load luv (libuv bindings for async operations)
|
|
-- Try to load luv (libuv bindings for async operations)
|
|
|
local luv_ok, luv = pcall(require, "luv")
|
|
local luv_ok, luv = pcall(require, "luv")
|
|
|
|
|
|
|
|
--- Try to load websocket library
|
|
|
|
|
-local ws_client = nil
|
|
|
|
|
-local has_websocket, websocket = pcall(require, "websocket")
|
|
|
|
|
-
|
|
|
|
|
-if has_websocket then
|
|
|
|
|
- ws_client = websocket.client.sync()
|
|
|
|
|
-end
|
|
|
|
|
-
|
|
|
|
|
--- Try to load HTTP library as fallback
|
|
|
|
|
-local http_client = nil
|
|
|
|
|
-local has_http, http = pcall(require, "ssl/https") or pcall(require, "http")
|
|
|
|
|
-if has_http then
|
|
|
|
|
- http_client = http
|
|
|
|
|
-end
|
|
|
|
|
|
|
+-- ============================================================================
|
|
|
|
|
+-- HTTP POST (direct curl - works on minimal OpenWrt)
|
|
|
|
|
+-- ============================================================================
|
|
|
|
|
|
|
|
--- Shell-based HTTP fallback (works on minimal OpenWrt)
|
|
|
|
|
-local function http_post_shell(url, data)
|
|
|
|
|
|
|
+local function http_post(event_type, data)
|
|
|
|
|
+ local json = '{"router_id":"' .. cfg.router_id .. '","event":"' .. event_type .. '","data":' .. data .. '}'
|
|
|
|
|
+ local url = cfg.url:gsub("wss", "https"):gsub("ws", "http")
|
|
|
|
|
+ if url == cfg.url then url = cfg.url .. "/api/events" end
|
|
|
|
|
+
|
|
|
local cmd = string.format(
|
|
local cmd = string.format(
|
|
|
- 'curl -s -X POST -H "Content-Type: application/json" -d "%s" "%s" 2>/dev/null',
|
|
|
|
|
- data:gsub('"', '\\"'), url
|
|
|
|
|
|
|
+ 'curl -s -X POST "%s" -H "Content-Type: application/json" -d "%s" 2>/dev/null',
|
|
|
|
|
+ url, json:gsub('"', '\\"')
|
|
|
)
|
|
)
|
|
|
- local f = io.popen(cmd)
|
|
|
|
|
- local resp = f and f:read("*a") or ""
|
|
|
|
|
|
|
+ local f = io.popen(cmd, "r")
|
|
|
|
|
+ local result = f and f:read("*a") or ""
|
|
|
if f then f:close() end
|
|
if f then f:close() end
|
|
|
- return resp ~= ""
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if result and result:match("OK") then
|
|
|
|
|
+ log("info", "Event " .. event_type .. " OK")
|
|
|
|
|
+ return true
|
|
|
|
|
+ else
|
|
|
|
|
+ log("warn", "Event " .. event_type .. " fail: " .. result:sub(1, 50))
|
|
|
|
|
+ return false
|
|
|
|
|
+ end
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- ============================================================================
|
|
@@ -610,74 +609,22 @@ local function main()
|
|
|
-- Idle work - check WebSocket periodically
|
|
-- Idle work - check WebSocket periodically
|
|
|
end)
|
|
end)
|
|
|
|
|
|
|
|
- -- WebSocket/HTTP connection - try to connect and stay connected
|
|
|
|
|
- local function ws_loop()
|
|
|
|
|
- log("info", "Connecting to server...")
|
|
|
|
|
-
|
|
|
|
|
- -- Try WebSocket first
|
|
|
|
|
- if ws_client then
|
|
|
|
|
- sock = ws.connect(cfg.url)
|
|
|
|
|
- end
|
|
|
|
|
-
|
|
|
|
|
- -- Fallback to HTTP POST if no WebSocket
|
|
|
|
|
- if not sock then
|
|
|
|
|
- -- Send events via curl (shell fallback)
|
|
|
|
|
- local url = cfg.url:gsub("wss", "https"):gsub("ws", "http")
|
|
|
|
|
- if url == cfg.url then url = cfg.url .. "/events" end
|
|
|
|
|
-
|
|
|
|
|
- -- POST buffered events
|
|
|
|
|
- local sent = false
|
|
|
|
|
- for _, event in ipairs(buffer.events) do
|
|
|
|
|
- if http_post_shell(url, event) then
|
|
|
|
|
- log("info", "Event sent: " .. event)
|
|
|
|
|
- sent = true
|
|
|
|
|
- end
|
|
|
|
|
- end
|
|
|
|
|
- if sent then
|
|
|
|
|
- buffer.clear()
|
|
|
|
|
- end
|
|
|
|
|
- sock = "http" -- Mark as connected
|
|
|
|
|
- end
|
|
|
|
|
-
|
|
|
|
|
- if sock then
|
|
|
|
|
- log("info", "Connected!")
|
|
|
|
|
- retries = 0
|
|
|
|
|
-
|
|
|
|
|
- -- Flush buffer
|
|
|
|
|
- buffer.flush(function(data)
|
|
|
|
|
- return ws.send(sock, data)
|
|
|
|
|
- end)
|
|
|
|
|
-
|
|
|
|
|
- -- Stay connected - reconnect timer will handle reconnection
|
|
|
|
|
- local ws_timer = luv.new_timer()
|
|
|
|
|
- luv.timer_start(ws_timer, 5000, 5000, function()
|
|
|
|
|
- if ws.connected(sock) then
|
|
|
|
|
- -- Periodic flush
|
|
|
|
|
- buffer.flush(function(data)
|
|
|
|
|
- return ws.send(sock, data)
|
|
|
|
|
- end)
|
|
|
|
|
- else
|
|
|
|
|
- -- Disconnected, reconnect
|
|
|
|
|
- ws.close(sock)
|
|
|
|
|
- sock = nil
|
|
|
|
|
- buffer.save()
|
|
|
|
|
- ws_loop() -- Reconnect
|
|
|
|
|
- end
|
|
|
|
|
- end)
|
|
|
|
|
- else
|
|
|
|
|
- log("err", "Connection failed")
|
|
|
|
|
- retries = retries + 1
|
|
|
|
|
-
|
|
|
|
|
- -- Retry after delay
|
|
|
|
|
- local retry_timer = luv.new_timer()
|
|
|
|
|
- luv.timer_start(retry_timer, cfg.reconnect_delay * 1000, 0, function()
|
|
|
|
|
- ws_loop()
|
|
|
|
|
- end)
|
|
|
|
|
- end
|
|
|
|
|
- end
|
|
|
|
|
|
|
+ -- Direct HTTP POST on each event (like minimal version)
|
|
|
|
|
+ log("info", "Using direct HTTP POST (curl)")
|
|
|
|
|
|
|
|
- -- Start WebSocket loop
|
|
|
|
|
- ws_loop()
|
|
|
|
|
|
|
+ -- The monitors call buffer.add() which stores events.
|
|
|
|
|
+ -- We need a periodic flush that calls http_post()
|
|
|
|
|
+ local flush_timer = luv.new_timer()
|
|
|
|
|
+ luv.timer_start(flush_timer, 10000, 10000, function()
|
|
|
|
|
+ -- Flush buffered events
|
|
|
|
|
+ for _, event_json in ipairs(buffer.events) do
|
|
|
|
|
+ local event_type = "unknown"
|
|
|
|
|
+ event_type = event_json:match('"type":"([^"]+)"') or event_type
|
|
|
|
|
+ local data = event_json -- Already JSON
|
|
|
|
|
+ http_post(event_type, data)
|
|
|
|
|
+ end
|
|
|
|
|
+ buffer.clear()
|
|
|
|
|
+ end)
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- Run the event loop
|
|
-- Run the event loop
|