myspace / CommonLua /Core /luasocket.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
11.4 kB
local sockProcess = sockProcess
---
--- Provides a new LuaSocket object with default settings.
---
--- @param self table The LuaSocket table
--- @param obj table An optional table to use as the new LuaSocket object
--- @return table The new LuaSocket object
function LuaSocket.new(self, obj)
end
--- Handles the connection acceptance event.
---
--- @param self table The LuaSocket table
--- @param socket table The accepted socket
--- @param host string The host of the accepted socket
--- @param port number The port of the accepted socket
function LuaSocket.OnAccept(self, socket, host, port)
end
--- Handles the connection event.
---
--- @param self table The LuaSocket table
--- @param err string The error message, if any
--- @param host string The host of the connected socket
--- @param port number The port of the connected socket
function LuaSocket.OnConnect(self, err, host, port)
end
--- Handles the disconnection event.
---
--- @param self table The LuaSocket table
--- @param reason string The reason for the disconnection
function LuaSocket.OnDisconnect(self, reason)
end
--- Handles the data reception event.
---
--- @param self table The LuaSocket table
--- @param msg string The received message
function LuaSocket.OnReceive(self, msg)
end
--- Logs the traffic (incoming or outgoing) if logging is enabled.
---
--- @param self table The LuaSocket table
--- @param type string The type of traffic ("incoming" or "outgoing")
--- @param str string The traffic data to log
function LuaSocket.traffic_log(self, type, str)
end
--- Connects the LuaSocket object to the specified address and port.
---
--- @param self table The LuaSocket table
--- @param addr string The address to connect to
--- @param port number The port to connect to
--- @param timeout number The connection timeout in milliseconds
function LuaSocket.connect(self, addr, port, timeout)
end
--- Reads the next available packet from the received data.
---
--- @param self table The LuaSocket table
--- @return string The next packet, or nil if no packet is available
function LuaSocket.readpacket(self)
end
--- Waits for and returns the next available packet.
---
--- @param self table The LuaSocket table
--- @return string The next packet
function LuaSocket.waitpacket(self)
end
--- Updates the LuaSocket object, handling connection state and sending/receiving data.
---
--- @param self table The LuaSocket table
function LuaSocket.update(self)
end
--- Checks if the LuaSocket object is disconnected.
---
--- @param self table The LuaSocket table
--- @return boolean true if the LuaSocket object is disconnected, false otherwise
function LuaSocket.isdisconnected(self)
end
--- Checks if the LuaSocket object is connected.
---
--- @param self table The LuaSocket table
--- @return boolean true if the LuaSocket object is connected, false otherwise
function LuaSocket.isconnected(self)
end
--- Checks if the LuaSocket object is connecting.
---
--- @param self table The LuaSocket table
--- @return boolean true if the LuaSocket object is connecting, false otherwise
function LuaSocket.isconnecting(self)
end
--- Flushes the send buffer, waiting for all data to be sent.
---
--- @param self table The LuaSocket table
function LuaSocket.flush(self)
end
--- Closes the LuaSocket connection.
---
--- @param self table The LuaSocket table
function LuaSocket.close(self)
end
--- Sends raw data through the LuaSocket connection.
---
--- @param self table The LuaSocket table
--- @param ... string The data to send
function LuaSocket.send_raw(self, ...)
end
--- Sends data through the LuaSocket connection with a length prefix.
---
--- @param self table The LuaSocket table
--- @param ... string The data to send
function LuaSocket.send(self, ...)
end
LuaSocket = {new=function(self, obj)
obj = obj or {}
setmetatable(obj, self)
self.__index = self
obj[true] = false
obj.state = "noconnection"
obj.send_buffer = {}
obj.send_buffer_i = 1
obj.connect_init_time = 0
obj.deadline = 0
obj.timeout = 0
obj.packets = {}
obj.queue = {}
obj.receive_buffer = ""
obj.received_data = ""
obj.transactions = {}
obj.log_enabled = false
obj.maxbuffer = 0
return obj
end, OnAccept=function(self, socket, host, port)
end, OnConnect=function(self, err, host, port)
if err then
self.state = "UnableToConnect"
else
self:__Connected()
end
Msg(self, err)
end, OnDisconnect=function(self, reason)
self.state = "noconnection"
end, OnReceive=function(self, msg)
local start_size = string.len(self.receive_buffer)
self:traffic_log("incoming", msg)
self.receive_buffer = self.receive_buffer .. msg
if string.len(self.receive_buffer) > start_size then
while true do
while string.starts_with(self.receive_buffer, "#") do
if string.len(self.receive_buffer) > 1 then
self.receive_buffer = string.sub(self.receive_buffer, 2) -- ping
else
self.receive_buffer = ""
end
end
local count = string.match(self.receive_buffer, "^(%d+) ")
if count and string.len(self.receive_buffer) >= tonumber(count) + string.len(count) + 1 then -- whole packet received
local packet_start = string.len(count) + 2 -- first byte of packet
local packet_end = packet_start + count - 1 -- last byte of packet
local packet = string.sub(self.receive_buffer, packet_start, packet_end)
table.insert(self.packets, packet)
if string.len(self.receive_buffer) > packet_end then
self.receive_buffer = string.sub(self.receive_buffer, packet_end + 1)
else
self.receive_buffer = ""
end
else
assert(self.receive_buffer == "" or string.match(self.receive_buffer, "^%d")
or string.starts_with(self.receive_buffer, "#"))
break
end
end
end
end, traffic_log=function(self, type, str)
if self.log_enabled then
local filename = type
local f, error = io.open(filename .. ".log", "a")
if f then
f:write(str)
f:close()
else
OutputDebugString(error)
end
end
end, connect=function(self, addr, port, timeout)
if self[true] then
self:__CloseConnection()
else
self[true] = sockNew()
SocketObjs[self[true]] = self
end
self.timeout = timeout or 5000
sockSetOption(self, "timeout", 600000)
self.maxbuffer = sockGetOption(self, "maxbuffer")
self.state = "waitconnect"
local err = sockConnect(self, timeout, addr, port)
self.addr = addr
self.port = port
self.deadline = self.timeout + RealTime()
if not err then
sockProcess(0)
if self.state == "UnableToConnect" and RealTime() - self.deadline > 0 then
self:__CloseConnection()
end
else
if self.state == "UnableToConnect" then
if RealTime() - self.deadline > 0 then
self:__CloseConnection()
end
else
self:__CloseConnection()
end
end
end, readpacket=function(self)
local packet = table.remove(self.packets, 1)
return packet
end, waitpacket=function(self)
while not self:isdisconnected() do
local packet = self:readpacket()
if packet then
return packet
end
self:update()
os.sleep(10)
end
end, update=function(self)
if not self[true] then
return
end
sockProcess(0)
if self.state == "UnableToConnect" then
if RealTime() - self.deadline > 0 then
self:__CloseConnection()
return
else
LuaSocket.connect(self, self.addr, self.port, self.deadline - RealTime())
end
end
if self.state == "connected" then
local send_buffer_i = self.send_buffer_i
local send_buffer = self.send_buffer or {}
while send_buffer[1] and send_buffer == self.send_buffer do
if send_buffer_i == 1 then
while #send_buffer > 1 and #send_buffer[1] + #send_buffer[2] < 2048 do -- concatinate some buffers to form larger piece to minimize the "send" operations
local buff = send_buffer[1] .. send_buffer[2]
assert(buff)
send_buffer[1] = buff
table.remove(send_buffer, 2)
end
end
local err, last_i
if #send_buffer[1] < self.maxbuffer then
err = sockSend(self, send_buffer[1])
last_i = #send_buffer[1]
else
local bytes = #send_buffer[1] - (send_buffer_i - 1)
if bytes > self.maxbuffer then
bytes = self.maxbuffer
end
err = sockSend(self, string.sub(send_buffer[1], send_buffer_i, ((send_buffer_i - 1) + bytes)))
last_i = (send_buffer_i - 1) + bytes
end
if err and err ~= "no data" then
self:__CloseConnection()
return
end
if last_i then
self:traffic_log("outgoing", string.sub(send_buffer[1], send_buffer_i, last_i))
send_buffer_i = last_i + 1
if send_buffer_i > #send_buffer[1] then
send_buffer_i = 1
table.remove(send_buffer, 1)
end
self.send_buffer_i = send_buffer_i
end
end
-- Old Recv was here
end
end, isdisconnected=function(self)
return self.state == "noconnection"
end, isconnected=function(self)
return self.state == "connected"
end, isconnecting=function(self)
return self.state == "waitconnect"
end, flush=function(self)
if not self[true] then
return
end
self:update()
while not self:isdisconnected() and #self.send_buffer > 0 do
os.sleep(10)
self:update()
end
end, close=function(self)
self:__CloseConnection()
end, __CloseConnection=function(self)
self.state = "noconnection"
self.send_buffer_i = 1
self.send_buffer = {}
self.receive_buffer = ""
self.received_data = ""
if self[true] then
sockDisconnect(self)
end
end, __Connected=function(self)
self.state = "connected"
if self.log_enabled then
local f, error = io.open("outgoing.log", "w+")
if f then
f:close()
else
OutputDebugString(error)
end
local f, error = io.open("incoming.log", "w+")
if f then
f:close()
else
OutputDebugString(error)
end
local f, error = io.open("input.log", "w+")
if f then
f:close()
else
OutputDebugString(error)
end
end
end, send_raw=function(self, ...)
local args = {...}
for i = 1, #args do
table.insert(self.send_buffer, args[i])
self:traffic_log("input", args[i])
end
end, send=function(self, ...)
local len = 0
local args = {...}
for i = 1, #args do
len = len + #args[i]
end
table.insert(self.send_buffer, "$" .. len .. "&")
self:send_raw(...)
end}