-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathServer.lua
240 lines (234 loc) · 12.4 KB
/
Server.lua
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
require "Pack"
require "Visualintercom"
SERVER_PORT = 5009
MASTER_AUTH = 0x84
TCP_BUFFER = 26
local server = {
clients = {},
clientsCnt = 0,
--socket = nil,
sendAll = function(self, message)
for cli,info in pairs(self.clients) do
cli:Write(message)
end
end,
notifyOthers = function(self, client, message)
for cli,info in pairs(self.clients) do
if (cli ~= client) then
cli:Write(message)
end
end
end,
broadcast = function(self, client, message)
local info = self.clients[client]
print("broadcast for client " .. tostring(client) .. " info: " ..tostring(info))
if (info ~= nil) then
self:notifyOthers(client, message)
client:Write(message)
end
end,
stripControlCharacters = function(self, data)
local ret = ""
for i in string.gmatch(data, "%C+") do
ret = ret .. i
end
return ret
end,
stop = function(self)
if (self.socket ~= nil) then
self.socket:Close()
self.socket = nil
-- Make a copy of all clients and reset the map.
-- This ensures that calls to self:broadcast() and self:notifyOthers()
-- during the shutdown process get ignored. All we want the clients to
-- see is the shutdown message.
local clients = self.clients
self.clients = {}
self.clientsCnt = 0
for cli,info in pairs(clients) do
print("Disconnecting " .. cli:GetRemoteAddress().ip .. ":" .. cli:GetRemoteAddress().port)
cli:Write(""):Close(true)
end
end
end,
start = function(self, maxClients, bindAddr, port, done)
local calledDone = false
self.socket = C4:CreateTCPServer()
:Option("reuseaddr",1)
:OnResolve(
function(srv, endpoints)
-- You do not need to set this callback function if you only want default behavior.
-- You can return an index into the endpoints array that is provided, if you would like to choose
-- listening on a specific address. By default, the first entry is used. Note that you can mess
-- with this table as you wish, but any changes will not be looked at. Not even if you change the
-- ip/port in one of the entries. All that matters is the index into the original array that was
-- provided. If you return 0, the server will not bind to any address and will not listen for
-- anything, and it will call the OnError handler with error code 22 (Invalid argument)
-- return 1 -- This is default behavior
-- return 0 -- Abort the listen request
print("Server " .. tostring(srv) .. " resolved listening address")
for i = 1, #endpoints do
print("Available endpoints: [" .. i .. "] ip=" .. endpoints[i].ip .. ":" .. endpoints[i].port)
end
end
)
:OnListen(
function(srv, endpoint)
-- Handling this callback is optional. It merely lets you know that the server is now actually listening.
local addr = srv:GetLocalAddress()
C4:UpdateProperty("Server Status", "Server listen success")
print("Server " .. tostring(srv) .. " chose endpoint " .. endpoint.ip .. ":" .. endpoint.port .. ", listening on " .. addr.ip .. ":" .. addr.port)
if (not calledDone) then
calledDone = true
done(true, addr)
end
end
)
:OnError(
function(srv, code, msg, op)
-- code is the system error code (as a number)
-- msg is the error message as a string
print("Server " .. tostring(srv) .. " Error " .. code .. " (" .. msg .. ")")
C4:UpdateProperty("Server Status", "Server error")
if (not calledDone) then
calledDone = true
done(false, msg)
end
end
)
:OnAccept(
function(srv, client)
-- srv is the instance C4:CreateTCPServer() returned
-- client is a C4LuaTcpClient instance of the new connection that was just accepted
C4:UpdateProperty("Server Status", "A client accept success")
print("Connection on server " .. tostring(srv) .. " accepted, client: " .. tostring(client))
--client:Write(vi:author())
client:ReadUpTo(TCP_BUFFER)
if (self.clientsCnt >= maxClients) then
client:Write(""):Close(true)
return
else
self.clients[client] = client
self.clientsCnt = self.clientsCnt + 1
end
local info = {}
client:OnRead(
function(cli, strData)
--hexdump(strData, function(s) print("server recieve:<------ " .. s) end)
local pack = Pack:create()
local vi = Visualintercom:create()
if pack.head(strData) == VI_HEAD then
if pack.cmd(strData) ~= 0x10 then
hexdump(strData, function(s) print("server:<------ " .. s) end)
end
if pack.cmd(strData) == 0x20 then
local v = pack.decode(strData)
vi:lightContol(v.extaddr,v.addr,v.state)
elseif pack.cmd(strData) == 0x24 then -- fresh air from vi
local v = pack.decodeFresh(strData)
vi:freshControl(v.extaddr,v.addr,v.action,v.value)
elseif pack.cmd(strData) == 0x21 then
local v = pack.decode(strData)
vi:curtainContol(v.extaddr,v.addr,v.state)
elseif pack.cmd(strData) == 0x22 then
local air = pack.decodeAir(strData)
vi:airControl(air.extaddr,air.addr,air.state,air.mode,air.temp,air.speed)
elseif pack.cmd(strData) == 0x23 then
local sceneID = pack.sceneID(strData)
vi:sceneControl(sceneID)
elseif pack.cmd(strData) == 0x12 then
--cli:Write(vi:updateState())
end
elseif pack.head(strData) == 0x01 then
if pack.cmd(strData) == 0x50 then
local air = pack.decodeAirFB(strData)
print(air.temp,air.power,air.mode,air.speed,air.setemp)
C4:SetVariable("CURRENT_TEMPRETURE", tostring(air.temp))
C4:SetVariable("IS_ON", tostring(air.power))
C4:SetVariable("CURRENT_MODE", tostring(air.mode))
C4:SetVariable("SETTING_TEMPRETURE", tostring(air.setemp))
C4:SetVariable("CURRENT_SPEED", tostring(air.speed))
elseif pack.cmd(strData) == 0x03 then
pack.decodeFreshFB(strData)
end
else
function handle(key)
C4:SetVariable("KEY_ID", tostring(key))
C4:FireEvent("key event")
local data =nil
for i =1 , 4 do
C4:SetTimer(i*500, function()
if i==key then
data = pack.lightonHex(i)
else
data = pack.lightoffHex(i)
end
cli:Write(tohex(data))
end)
end
end
if strData == pack.keyHex(1) or strData == pack.keyHexLight(1) then
handle(1)
elseif strData == pack.keyHex(2) or strData == pack.keyHexLight(2) then
handle(2)
elseif strData == pack.keyHex(3) or strData == pack.keyHexLight(3) then
handle(3)
elseif strData == pack.keyHex(4) or strData == pack.keyHexLight(4) then
handle(4)
end
end
cli:ReadUpTo(TCP_BUFFER)
end
)
:OnWrite(
function(cli)
-- cli is the C4LuaTcpClient instance (same as client in the OnAccept handler). This callback is called when
-- all data was sent.
print("Server " .. tostring(srv) .. " Client " .. tostring(client) .. " Data was sent.")
cli:ReadUpTo(TCP_BUFFER)
end
)
:OnDisconnect(
function(cli, errCode, errMsg)
-- cli is the C4LuaTcpClient instance (same as client in the OnAccept handler) that the data was read on
-- errCode is the system error code (as a number). On a graceful disconnect, this value is 0.
-- errMsg is the error message as a string.
if (errCode == 0) then
print("Server " .. tostring(srv) .. " Client " .. tostring(client) .. " Disconnected gracefully.")
else
print("Server " .. tostring(srv) .. " Client " .. tostring(client) .. " Disconnected with error " .. errCode .. " (" .. errMsg .. ")")
end
self.clients[cli] = nil
self.clientsCnt = self.clientsCnt - 1
end
)
:OnError(
function(cli, code, msg, op)
-- cli is the C4LuaTcpClient instance (same as client in the OnAccept handler) that the data was read on
-- code is the system error code (as a number)
-- msg is the error message as a string
-- op indicates what type of operation failed: "read", "write"
print("Server " .. tostring(srv) .. " Client " .. tostring(client) .. " Error " .. code .. " (" .. msg .. ") on " .. op)
end
)
:Write("")
:ReadUntil("\r\n")
end
)
:Listen(bindAddr, port)
if (self.socket ~= nil) then
return self
end
end
}
-- Start the server with a limit of 5 concurrent connections, listen on all interfaces on a randomly available port. The server will shut down after 10 minutes.
function tcpServer()
server:start(10, "*", SERVER_PORT, function(success, info)
if (success) then
print("Server listening on " .. info.ip .. ":" .. info.port)
else
print("Could not start server: " .. info)
end
end)
return server
end