-- -- rhctl -- -- Copyright (C) 2009-2014 Christian Pointner -- -- This file is part of rhctl. -- -- rhctl is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- any later version. -- -- rhctl is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with rhctl. If not, see . -- package.path = package.path .. ';/usr/share/rhctl/?.lua' socket = require("socket") current_mode = nil function init_server(host, port) local server = assert(socket.tcp()) assert(server:setoption('reuseaddr', true)) assert(server:bind(host, port)) assert(server:listen(5)) return server end local clients = {} function add_client(hdl) log.printf(log.DEBUG, "new client(" .. hdl:getfd() .. ") from " .. hdl:getpeername()) local client = {} if current_mode then client.buffer = current_mode .. "\n" else client.buffer = "" end client.hdl = hdl client.getfd = function() return hdl:getfd() end client.dirty = function() return hdl:dirty() end table.insert(clients, client) end function remove_client(c) local idx = 0 local found = false for i, client in ipairs(clients) do if client == c then found = true idx = i break end end if found then log.printf(log.DEBUG, "removing client(" .. c.hdl:getfd() .. ")") c.hdl:close() table.remove(clients, idx) end end function cleanup_clients() for _, client in ipairs(clients) do client.hdl:close() end end function clients_get_writeables() local fds = {} for _, client in ipairs(clients) do if client.buffer ~= "" then table.insert(fds, client) end end return fds end function clients_senddata(data) for _, client in ipairs(clients) do client.buffer = client.buffer .. data .. "\n" end end function process_cmd(message) log.printf(log.DEBUG, "received message: '%s'", message) local new_mode = nil local exps = { "Current Mode: (%a+)", "new Mode: (%a+)" } for _, exp in ipairs(exps) do new_mode = string.match(message, exp) if(new_mode) then new_mode = string.lower(new_mode) break end end if(new_mode and new_mode ~= current_mode) then clients_senddata(new_mode) current_mode = new_mode end return 0 end function main_loop(opt) log.printf(log.NOTICE, "main_loop started") local sig = signal.init() local cmdfd = cmd.init() local server = init_server("*", "2345") cmd.send_string("listen mode"); cmd.send_string("status"); local return_value = 0 while return_value == 0 do local readable, writeable, err = socket.select({ sig , cmdfd , server , unpack(clients) }, clients_get_writeables()) if(err) then log.printf(log.ERROR, "select returned with error: %s", err) return_value = -1 else for _, input in ipairs(readable) do if input == sig then return_value = signal.handle() if(return_value == 1) then break end elseif input == cmdfd then return_value = cmd.recv_data(process_cmd) if(return_value ~= 0) then break end elseif input == server then local client = server:accept() if(client == nil) then return_value =-3 break else add_client(client) end else if input.hdl then -- receive is insanely stupid, therefore we must always read one byte only local _, err = input.hdl:receive(1) if err then remove_client(input) end end end end for _, output in ipairs(writeable) do local ret = output.hdl:send(output.buffer) if(ret == nil) then remove_client(output) else output.buffer = string.sub(output.buffer, ret+1) end end end end server:close() cleanup_clients() signal.stop() return return_value end