File: luasocket_console.lua

package info (click to toggle)
spring 98.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 41,928 kB
  • ctags: 60,665
  • sloc: cpp: 356,167; ansic: 39,434; python: 12,228; java: 12,203; awk: 5,856; sh: 1,719; xml: 997; perl: 405; php: 253; objc: 194; makefile: 72; sed: 2
file content (140 lines) | stat: -rw-r--r-- 3,189 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

if not (Spring.GetConfigInt("LuaSocketEnabled", 0) == 1) then
	Spring.Echo("LuaSocketEnabled is disabled")
	return false
end

function widget:GetInfo()
return {
	name    = "ip console for spring",
	desc    = "opens a telnet console on localhost:8201",
	author  = "abma",
	date    = "Feb. 2012",
	license = "GNU GPL, v2 or later",
	layer   = 0,
	enabled = true,
}
end

--VFS.Include(LUAUI_DIRNAME .. "Widgets/socket/socket.lua")

local socket = socket

local set

local host = "localhost"
local port = 8201

local function newset()
    local reverse = {}
    local set = {}
    return setmetatable(set, {__index = {
        insert = function(set, value)
            if not reverse[value] then
                table.insert(set, value)
                reverse[value] = table.getn(set)
            end
        end,
        remove = function(set, value)
            local index = reverse[value]
            if index then
                reverse[value] = nil
                local top = table.remove(set)
                if top ~= value then
                    reverse[top] = index
                    set[index] = top
                end
            end
        end
    }})
end


-- initiates a connection to host:port, returns true on success
local function SocketListen(host, port)
	server = socket.bind(host, port)
	if server==nil then
		Spring.Echo("Error binding to " .. host .. ":" .. port)
		return false
	end
	server:settimeout(0)
	set = newset()
	set:insert(server)
	return true
end

function widget:Initialize()
	SocketListen(host, port)
end

local data
-- called when data was received through a connection
local function SocketDataReceived(sock, str)
	Spring.SendCommands(str)
end

local headersent
-- called when data can be written to a socket
local function SocketWriteAble(sock)
	if data~=nil then
		sock:send(data)
		data=nil
	end
end

-- called when a connection is closed
local function SocketClosed(sock)
	Spring.Echo("closed connection")
end

local function ClientConnected(sock)
	local client, err = sock:accept()
	if client == nil  then
		Spring.Echo("Accept failed: " .. err)
	end
	client:settimeout(0)
	set:insert(client)
	ip, port = sock:getsockname()
	Spring.Echo("Accepted connection from " .. ip ..":" .. port)
end

function widget:AddConsoleLine(line)
	if data == nil then
		data = line
	else
		data = data .."\n" .. line
	end
end

function widget:Update()
	if set==nil or #set<=0 then
		return
	end
	-- get sockets ready for read
	local readable, writeable, err = socket.select(set, set, 0)
	if err~=nil then
		-- some error happened in select
		if err=="timeout" then
			-- nothing to do, return
			return
		end
		Spring.Echo("Error in select: " .. error)
	end
	for _, input in ipairs(readable) do
		if input==server then -- server socket got readable (client connected)
			ClientConnected(input)
		else
			local s, status, partial = input:receive('*a') --try to read all data
			if status == "timeout" or status == nil then
				SocketDataReceived(input, s or partial)
			elseif status == "closed" then
				SocketClosed(input)
				input:close()
				set:remove(input)
			end
		end
	end
	for __, output in ipairs(writeable) do
		SocketWriteAble(output)
	end
end