Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2afef5d0fe | |||
| 0efb553d7c | |||
| eb6c7ba651 | |||
| 50a6cf88f4 | |||
|
|
b7636e977d | ||
|
|
fbd63a9aea | ||
| e2503cf103 | |||
| 808c73cf93 | |||
| 36ae77e98a | |||
| a7ce660e3b | |||
| 4a5b9433f5 | |||
| 9d5a7b559c | |||
| b98058f84e | |||
| 97578e5073 | |||
| b4a8ec0360 | |||
| 1760935658 | |||
| c61ee0537d | |||
| 8f8fd31e64 | |||
| 7633e87ab9 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
|||||||
|
# lua-env
|
||||||
|
luajit/*
|
||||||
|
|
||||||
# Compiled Lua sources
|
# Compiled Lua sources
|
||||||
luac.out
|
luac.out
|
||||||
|
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "multi"]
|
||||||
|
path = multi
|
||||||
|
url = https://github.com/rayaman/multi.git
|
||||||
184
README.html
184
README.html
File diff suppressed because one or more lines are too long
16
README.md
16
README.md
@ -1,10 +1,8 @@
|
|||||||
# net (2.0.1)
|
# net (5.0.0) Total Rewrite
|
||||||
Updated from 2.0.0 to 2.0.1
|
|
||||||
Added:
|
|
||||||
- Examples
|
|
||||||
- Support for latest multi version
|
|
||||||
- Updated readme
|
|
||||||
|
|
||||||
|
This readme needs to be rewritten, that will happen when all planned features are added to v5
|
||||||
|
|
||||||
|
I've returned to this project. Mainly to create a way to test my multi-tasking library. Notable features, create server/client connections that work async. Added wrapper for http and https request (multi, luasocket and luasec required) to work in coroutines without needing a lua-core modifacation.
|
||||||
|
|
||||||
# Discord
|
# Discord
|
||||||
For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries</br>
|
For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries</br>
|
||||||
@ -26,12 +24,12 @@ A simple and powerful way to make servers and clients
|
|||||||
- [ ] Improve 'stable' modules
|
- [ ] Improve 'stable' modules
|
||||||
- [ ] AUDP - advance udp. Ensures packets arrive and handles late packets.
|
- [ ] AUDP - advance udp. Ensures packets arrive and handles late packets.
|
||||||
- [ ] P2P - peer to peer (Server to set up initial connection)
|
- [ ] P2P - peer to peer (Server to set up initial connection)
|
||||||
- [ ] Relay - offput server load (locally)
|
- [ ] Threading (requires lanes which is installed when multi is installed)
|
||||||
- [ ] Threading - Simple threading ~~(UDP/AUDP Only)~~ Thanks to an updated multi library we can thread with ease
|
|
||||||
- [ ] Priority handling
|
- [ ] Priority handling
|
||||||
|
|
||||||
# Note
|
# Note
|
||||||
You will see a bunch of files inside of the net folder. All that is stable is the init.lua and sft.lua file. Everything else is a work in progress. Plus I am planning on rewritting all of the modules to take advantage of the new threading features that are found in the new multi updates. PRogress on this will be made soon. I have just been away from my PC for a while.
|
You will see a bunch of files inside of the net folder. All that is stable is the init.lua and sft.lua file. Everything else is a work in progress. Plus I am planning on rewritting all of the modules to take advantage of the new threading features that are found in the new multi updates. PRogress on this will be made soon. I have just been away from my PC for a while.
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
server.lua
|
server.lua
|
||||||
```lua
|
```lua
|
||||||
@ -39,7 +37,7 @@ require("bin") -- this library needs a lot of work it has a bunch of old useless
|
|||||||
require("multi") -- you need this to handle multiple connections and such
|
require("multi") -- you need this to handle multiple connections and such
|
||||||
require("net") -- That requires the main library
|
require("net") -- That requires the main library
|
||||||
server=net:newTCPServer(12345) -- create a server that listens on port 12345
|
server=net:newTCPServer(12345) -- create a server that listens on port 12345
|
||||||
server.OnDataRecieved(function(self,data,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP,UPDATER_OR_NIL) -- a bit confusing, but dont worry you will hardly ever need more then the first 5 arguments, unless you are writing modules!
|
server.OnDataRecieved(function(self, data, CID, IP, PORT) -- a bit confusing, but dont worry you will hardly ever need more then the first 5 arguments, unless you are writing modules!
|
||||||
if data=="Hello!" then
|
if data=="Hello!" then
|
||||||
print("Got response from client sending back data!")
|
print("Got response from client sending back data!")
|
||||||
self:send(IP_OR_HANDLE,"Hello Client!",PORT_OR_IP) -- doing it like this makes this code work for both udp and tcp
|
self:send(IP_OR_HANDLE,"Hello Client!",PORT_OR_IP) -- doing it like this makes this code work for both udp and tcp
|
||||||
|
|||||||
46
client.lua
46
client.lua
@ -1,17 +1,29 @@
|
|||||||
package.path="?/init.lua;"..package.path
|
package.path = "./?/init.lua;./?.lua;"..package.path
|
||||||
local multi = require("multi")
|
local net = require("lnet.tcp")
|
||||||
local net = require("net")
|
local multi, thread = require("multi"):init()
|
||||||
client = net:newTCPClient("localhost",12345)
|
--
|
||||||
client:enableBinaryMode()
|
-- local http = require("lnet.http")
|
||||||
local file = bin.new()
|
-- local http_ = require("socket.http")
|
||||||
client.OnDataRecieved(function(self,data)
|
|
||||||
if data == "END" then
|
local https = require("lnet.https")
|
||||||
file:tofile("test2.mp3")
|
|
||||||
print("File transfered!")
|
-- multi:newThread("Timer",function()
|
||||||
else
|
-- while true do
|
||||||
file:tackE(data)
|
-- thread.sleep(8)
|
||||||
end
|
-- print("...")
|
||||||
end)
|
-- end
|
||||||
client.OnClientReady:holdUT() -- waits until the client is ready... You can also connect to this event as well and have code do stuff too
|
-- end)
|
||||||
client:send("Hello Server!")
|
-- download("http://212.183.159.230/5MB.zip","test1.bin")
|
||||||
multi:mainloop()
|
-- download("http://212.183.159.230/50MB.zip","test2.bin").OnError(print)
|
||||||
|
|
||||||
|
print(https.request("https://erowall.com/wallpapers/large/32757.jpg"))
|
||||||
|
|
||||||
|
-- local client = net.newCastedClient("Test")--net:newTCPClient("localhost",12345)
|
||||||
|
|
||||||
|
-- client:send("Test!")
|
||||||
|
|
||||||
|
-- client.OnDataRecieved(function(c,data)
|
||||||
|
-- print("Response: ",data)
|
||||||
|
-- end)
|
||||||
|
|
||||||
|
--multi:mainloop()
|
||||||
|
|||||||
35
lnet/base/client.lua
Normal file
35
lnet/base/client.lua
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local client = {}
|
||||||
|
client.__index = client
|
||||||
|
client.updaterRate = 1
|
||||||
|
client.sMode = "*l"
|
||||||
|
client.rMode = "*l"
|
||||||
|
function client:init(type)
|
||||||
|
self.Type = type
|
||||||
|
self.OnDataRecieved = multi:newConnection()
|
||||||
|
self.OnServerNotAvailable = multi:newConnection()
|
||||||
|
self.OnClientReady = multi:newConnection()
|
||||||
|
self.OnClientDisconnected = multi:newConnection()
|
||||||
|
self.OnConnectionRegained = multi:newConnection()
|
||||||
|
self.OnPreSend = multi:newConnection()
|
||||||
|
self.OnPreRecieved = multi:newConnection()
|
||||||
|
self.OnError = multi:newConnection()
|
||||||
|
self.process = multi:newProcessor()
|
||||||
|
self.process.Start()
|
||||||
|
end
|
||||||
|
function client:send(data)
|
||||||
|
-- Override this function
|
||||||
|
end
|
||||||
|
function client:close()
|
||||||
|
-- Override this function
|
||||||
|
end
|
||||||
|
function client:setUpdateRate(n)
|
||||||
|
self.updaterRate = n
|
||||||
|
end
|
||||||
|
function client:setReceiveMode(mode)
|
||||||
|
self.rMode = mode
|
||||||
|
end
|
||||||
|
function client:setSendMode(mode)
|
||||||
|
self.sMode = mode
|
||||||
|
end
|
||||||
|
return client
|
||||||
87
lnet/base/server.lua
Normal file
87
lnet/base/server.lua
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local socket = require("socket")
|
||||||
|
local net = require("lnet")
|
||||||
|
local server = {}
|
||||||
|
local bCaster = 0
|
||||||
|
server.__index = server
|
||||||
|
server.updaterRate = 1
|
||||||
|
server.rMode = "*l"
|
||||||
|
server.sMode = "*l"
|
||||||
|
function server:init(type)
|
||||||
|
self.Type = type
|
||||||
|
self.OnClientsModulesList = multi:newConnection()
|
||||||
|
self.OnPreRecieved = multi:newConnection()
|
||||||
|
self.OnDataRecieved = multi:newConnection()
|
||||||
|
self.OnClientClosed = multi:newConnection()
|
||||||
|
self.OnClientConnected = multi:newConnection()
|
||||||
|
self.OnPreSend = multi:newConnection()
|
||||||
|
self.idleRate = 5
|
||||||
|
self.clientHandlers = {}
|
||||||
|
self.bannedCIDs = {}
|
||||||
|
self.bannedIPs = {}
|
||||||
|
self.broad = socket.udp()
|
||||||
|
self.localIP = net.getLocalIP()
|
||||||
|
self.ips = {}
|
||||||
|
self.links = {}
|
||||||
|
self.cids = {}
|
||||||
|
self.process = multi:newProcessor()
|
||||||
|
self.process.Start()
|
||||||
|
end
|
||||||
|
function server:setIdleRate(minutes)
|
||||||
|
self.idleRate = minutes
|
||||||
|
end
|
||||||
|
function server:setUpdateRate(n)
|
||||||
|
self.updaterRate = n
|
||||||
|
end
|
||||||
|
function server:banCID(cid)
|
||||||
|
table.insert(self.bannedCIDs,cid)
|
||||||
|
end
|
||||||
|
function server:banIP(ip)
|
||||||
|
table.insert(self.bannedIPs)
|
||||||
|
end
|
||||||
|
function server:setRecieveMode(mode)
|
||||||
|
self.rMode = mode
|
||||||
|
end
|
||||||
|
function server:setSendMode(mode)
|
||||||
|
self.sMode = mode
|
||||||
|
end
|
||||||
|
function server:broadcast(name)
|
||||||
|
if not self.isBroadcasting then
|
||||||
|
bCaster = bCaster + 1
|
||||||
|
self.isBroadcasting = true
|
||||||
|
self.process:newThread("Broadcast Handler<"..bCaster..">",function()
|
||||||
|
while true do
|
||||||
|
thread.yield()
|
||||||
|
self.broad:setoption("broadcast",true)
|
||||||
|
self.broad:sendto(table.concat({name,self.Type,self.localIP},"|")..":"..self.port, "255.255.255.255", 11111)
|
||||||
|
-- Send to localhost as well
|
||||||
|
self.broad:sendto(table.concat({name,self.Type,self.localIP},"|")..":"..self.port, self.localIP, 11111)
|
||||||
|
self.broad:setoption("broadcast", false)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function server:send(cid,data)
|
||||||
|
-- Override this
|
||||||
|
end
|
||||||
|
function server:getCid(ip,port)
|
||||||
|
if self.cids[ip .. port] then
|
||||||
|
return self.cids[ip .. port]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function server:sendAll(data)
|
||||||
|
for i,v in pairs(self.cids) do
|
||||||
|
self:send(data,cid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function server:sendAllBut(data,cid)
|
||||||
|
for i,v in pairs(self.cids) do
|
||||||
|
if v~=cid then
|
||||||
|
self:send(data,cid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function server:clientRegistered(cid)
|
||||||
|
return self.cids[cid]
|
||||||
|
end
|
||||||
|
return server
|
||||||
372
lnet/http.lua
Normal file
372
lnet/http.lua
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- HTTP/1.1 client support for the Lua language.
|
||||||
|
-- LuaSocket toolkit.
|
||||||
|
-- Author: Diego Nehab
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- Declare module and import dependencies
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
local net = require("lnet")
|
||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local socket = require("socket")
|
||||||
|
local url = require("socket.url")
|
||||||
|
local ltn12 = require("ltn12")
|
||||||
|
local mime = require("mime")
|
||||||
|
local string = require("string")
|
||||||
|
local headers = require("socket.headers")
|
||||||
|
local base = _G
|
||||||
|
local table = require("table")
|
||||||
|
net.http = {}
|
||||||
|
local _M = net.http
|
||||||
|
local default_block_size = 1024
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- Program constants
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- connection timeout in seconds
|
||||||
|
TIMEOUT = 60
|
||||||
|
-- default port for document retrieval
|
||||||
|
_M.PORT = 80
|
||||||
|
-- user agent field sent in request
|
||||||
|
_M.USERAGENT = socket._VERSION
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- Reads MIME headers from a connection, unfolding where needed
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
local function receiveheaders(sock, headers)
|
||||||
|
local line, name, value, err
|
||||||
|
headers = headers or {}
|
||||||
|
-- get first line
|
||||||
|
line, err = sock:receive()
|
||||||
|
if err then return nil, err end
|
||||||
|
-- headers go until a blank line is found
|
||||||
|
while line ~= "" do
|
||||||
|
-- get field-name and value
|
||||||
|
name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
|
||||||
|
if not (name and value) then return nil, "malformed reponse headers" end
|
||||||
|
name = string.lower(name)
|
||||||
|
-- get next line (value might be folded)
|
||||||
|
line, err = sock:receive()
|
||||||
|
if err then return nil, err end
|
||||||
|
-- unfold any folded values
|
||||||
|
while string.find(line, "^%s") do
|
||||||
|
value = value .. line
|
||||||
|
line = sock:receive()
|
||||||
|
if err then return nil, err end
|
||||||
|
end
|
||||||
|
-- save pair in table
|
||||||
|
if headers[name] then headers[name] = headers[name] .. ", " .. value
|
||||||
|
else headers[name] = value end
|
||||||
|
end
|
||||||
|
return headers
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- Extra sources and sinks
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
socket.sourcet["http-chunked"] = function(sock, headers)
|
||||||
|
return base.setmetatable({
|
||||||
|
getfd = function() return sock:getfd() end,
|
||||||
|
dirty = function() return sock:dirty() end
|
||||||
|
}, {
|
||||||
|
__call = function()
|
||||||
|
-- get chunk size, skip extention
|
||||||
|
local line, err = sock:receive()
|
||||||
|
if err then return nil, err end
|
||||||
|
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
|
||||||
|
if not size then return nil, "invalid chunk size" end
|
||||||
|
-- was it the last chunk?
|
||||||
|
if size > 0 then
|
||||||
|
-- if not, get chunk and skip terminating CRLF
|
||||||
|
local chunk, err, part = sock:receive(size)
|
||||||
|
if chunk then sock:receive() end
|
||||||
|
return chunk, err
|
||||||
|
else
|
||||||
|
-- if it was, read trailers into headers table
|
||||||
|
headers, err = receiveheaders(sock, headers)
|
||||||
|
if not headers then return nil, err end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
socket.sinkt["http-chunked"] = function(sock)
|
||||||
|
return base.setmetatable({
|
||||||
|
getfd = function() return sock:getfd() end,
|
||||||
|
dirty = function() return sock:dirty() end
|
||||||
|
}, {
|
||||||
|
__call = function(self, chunk, err)
|
||||||
|
if not chunk then return sock:send("0\r\n\r\n") end
|
||||||
|
local size = string.format("%X\r\n", string.len(chunk))
|
||||||
|
return sock:send(size .. chunk .. "\r\n")
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- Low level HTTP API
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
local metat = { __index = {} }
|
||||||
|
|
||||||
|
function _M.open(host, port, create)
|
||||||
|
-- create socket with user connect function, or with default
|
||||||
|
local c = socket.try((create or socket.tcp)())
|
||||||
|
local h = base.setmetatable({ c = c }, metat)
|
||||||
|
-- create finalized try
|
||||||
|
h.try = socket.newtry(function() h:close() end)
|
||||||
|
-- set timeout before connecting
|
||||||
|
h.try(c:settimeout(_M.TIMEOUT))
|
||||||
|
h.try(c:connect(host, port or _M.PORT))
|
||||||
|
-- here everything worked
|
||||||
|
return h
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:sendrequestline(method, uri)
|
||||||
|
local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
|
||||||
|
return self.try(self.c:send(reqline))
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:sendheaders(tosend)
|
||||||
|
local canonic = headers.canonic
|
||||||
|
local h = "\r\n"
|
||||||
|
for f, v in base.pairs(tosend) do
|
||||||
|
h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h
|
||||||
|
end
|
||||||
|
self.try(self.c:send(h))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:sendbody(headers, source, step)
|
||||||
|
source = source or ltn12.source.empty()
|
||||||
|
step = step or ltn12.pump.step
|
||||||
|
-- if we don't know the size in advance, send chunked and hope for the best
|
||||||
|
local mode = "http-chunked"
|
||||||
|
if headers["content-length"] then mode = "keep-open" end
|
||||||
|
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:receivestatusline()
|
||||||
|
local status = self.try(self.c:receive(5))
|
||||||
|
-- identify HTTP/0.9 responses, which do not contain a status line
|
||||||
|
-- this is just a heuristic, but is what the RFC recommends
|
||||||
|
if status ~= "HTTP/" then return nil, status end
|
||||||
|
-- otherwise proceed reading a status line
|
||||||
|
status = self.try(self.c:receive("*l", status))
|
||||||
|
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
|
||||||
|
return self.try(base.tonumber(code), status)
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:receiveheaders()
|
||||||
|
return self.try(receiveheaders(self.c))
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:receivebody(headers, sink, step)
|
||||||
|
sink = sink or ltn12.sink.null()
|
||||||
|
step = step or ltn12.pump.step
|
||||||
|
local length = base.tonumber(headers["content-length"])
|
||||||
|
local t = headers["transfer-encoding"] -- shortcut
|
||||||
|
local mode = "default" -- connection close
|
||||||
|
if t and t ~= "identity" then mode = "http-chunked"
|
||||||
|
elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
|
||||||
|
local ret,lp
|
||||||
|
lp = length%default_block_size
|
||||||
|
for i=1,math.floor(length/default_block_size) do
|
||||||
|
thread.yield()
|
||||||
|
ret = self.try(ltn12.pump.step(socket.source(mode, self.c, default_block_size), sink, step))
|
||||||
|
thread.pushStatus(i,math.floor(length/default_block_size))
|
||||||
|
end
|
||||||
|
if lp~=0 then
|
||||||
|
ret = self.try(ltn12.pump.step(socket.source(mode, self.c, lp), sink, step))
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:receive09body(status, sink, step)
|
||||||
|
local source = ltn12.source.rewind(socket.source("until-closed", self.c))
|
||||||
|
source(status)
|
||||||
|
return self.try(ltn12.pump.all(source, sink, step))
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:close()
|
||||||
|
return self.c:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- High level HTTP API
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
local function adjusturi(reqt)
|
||||||
|
local u = reqt
|
||||||
|
-- if there is a proxy, we need the full url. otherwise, just a part.
|
||||||
|
if not reqt.proxy and not PROXY then
|
||||||
|
u = {
|
||||||
|
path = socket.try(reqt.path, "invalid path 'nil'"),
|
||||||
|
params = reqt.params,
|
||||||
|
query = reqt.query,
|
||||||
|
fragment = reqt.fragment
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return url.build(u)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function adjustproxy(reqt)
|
||||||
|
local proxy = reqt.proxy or PROXY
|
||||||
|
if proxy then
|
||||||
|
proxy = url.parse(proxy)
|
||||||
|
return proxy.host, proxy.port or 3128
|
||||||
|
else
|
||||||
|
return reqt.host, reqt.port
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function adjustheaders(reqt)
|
||||||
|
-- default headers
|
||||||
|
local lower = {
|
||||||
|
["user-agent"] = _M.USERAGENT,
|
||||||
|
["host"] = reqt.host,
|
||||||
|
["connection"] = "close, TE",
|
||||||
|
["te"] = "trailers"
|
||||||
|
}
|
||||||
|
-- if we have authentication information, pass it along
|
||||||
|
if reqt.user and reqt.password then
|
||||||
|
lower["authorization"] =
|
||||||
|
"Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
|
||||||
|
end
|
||||||
|
-- override with user headers
|
||||||
|
for i,v in base.pairs(reqt.headers or lower) do
|
||||||
|
lower[string.lower(i)] = v
|
||||||
|
end
|
||||||
|
return lower
|
||||||
|
end
|
||||||
|
|
||||||
|
-- default url parts
|
||||||
|
local default = {
|
||||||
|
host = "",
|
||||||
|
port = _M.PORT,
|
||||||
|
path ="/",
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
local function adjustrequest(reqt)
|
||||||
|
-- parse url if provided
|
||||||
|
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
||||||
|
-- explicit components override url
|
||||||
|
for i,v in base.pairs(reqt) do nreqt[i] = v end
|
||||||
|
if nreqt.port == "" then nreqt.port = 80 end
|
||||||
|
socket.try(nreqt.host and nreqt.host ~= "",
|
||||||
|
"invalid host '" .. base.tostring(nreqt.host) .. "'")
|
||||||
|
-- compute uri if user hasn't overriden
|
||||||
|
nreqt.uri = reqt.uri or adjusturi(nreqt)
|
||||||
|
-- ajust host and port if there is a proxy
|
||||||
|
nreqt.host, nreqt.port = adjustproxy(nreqt)
|
||||||
|
-- adjust headers in request
|
||||||
|
nreqt.headers = adjustheaders(nreqt)
|
||||||
|
return nreqt
|
||||||
|
end
|
||||||
|
|
||||||
|
local function shouldredirect(reqt, code, headers)
|
||||||
|
return headers.location and
|
||||||
|
string.gsub(headers.location, "%s", "") ~= "" and
|
||||||
|
(reqt.redirect ~= false) and
|
||||||
|
(code == 301 or code == 302 or code == 303 or code == 307) and
|
||||||
|
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
||||||
|
and (not reqt.nredirects or reqt.nredirects < 5)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function shouldreceivebody(reqt, code)
|
||||||
|
if reqt.method == "HEAD" then return nil end
|
||||||
|
if code == 204 or code == 304 then return nil end
|
||||||
|
if code >= 100 and code < 200 then return nil end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- forward declarations
|
||||||
|
local trequest, tredirect
|
||||||
|
|
||||||
|
--[[local]] function tredirect(reqt, location)
|
||||||
|
local result, code, headers, status = trequest {
|
||||||
|
-- the RFC says the redirect URL has to be absolute, but some
|
||||||
|
-- servers do not respect that
|
||||||
|
url = url.absolute(reqt.url, location),
|
||||||
|
source = reqt.source,
|
||||||
|
sink = reqt.sink,
|
||||||
|
headers = reqt.headers,
|
||||||
|
proxy = reqt.proxy,
|
||||||
|
nredirects = (reqt.nredirects or 0) + 1,
|
||||||
|
create = reqt.create
|
||||||
|
}
|
||||||
|
-- pass location header back as a hint we redirected
|
||||||
|
headers = headers or {}
|
||||||
|
headers.location = headers.location or location
|
||||||
|
return result, code, headers, status
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We don't need to protect this function the thread:newFunction wrapper handles errors for us
|
||||||
|
function trequest(reqt)
|
||||||
|
-- we loop until we get what we want, or
|
||||||
|
-- until we are sure there is no way to get it
|
||||||
|
local nreqt = adjustrequest(reqt)
|
||||||
|
local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
|
||||||
|
-- send request line and headers
|
||||||
|
h:sendrequestline(nreqt.method, nreqt.uri)
|
||||||
|
h:sendheaders(nreqt.headers)
|
||||||
|
-- if there is a body, send it
|
||||||
|
if nreqt.source then
|
||||||
|
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
|
||||||
|
end
|
||||||
|
local code, status = h:receivestatusline()
|
||||||
|
-- if it is an HTTP/0.9 server, simply get the body and we are done
|
||||||
|
if not code then
|
||||||
|
h:receive09body(status, nreqt.sink, nreqt.step)
|
||||||
|
return 1, 200
|
||||||
|
end
|
||||||
|
local headers
|
||||||
|
-- ignore any 100-continue messages
|
||||||
|
while code == 100 do
|
||||||
|
headers = h:receiveheaders()
|
||||||
|
code, status = h:receivestatusline()
|
||||||
|
end
|
||||||
|
headers = h:receiveheaders()
|
||||||
|
-- at this point we should have a honest reply from the server
|
||||||
|
-- we can't redirect if we already used the source, so we report the error
|
||||||
|
if shouldredirect(nreqt, code, headers) and not nreqt.source then
|
||||||
|
h:close()
|
||||||
|
return tredirect(reqt, headers.location)
|
||||||
|
end
|
||||||
|
-- here we are finally done
|
||||||
|
if shouldreceivebody(nreqt, code) then
|
||||||
|
h:receivebody(headers, nreqt.sink, nreqt.step)
|
||||||
|
end
|
||||||
|
h:close()
|
||||||
|
return 1, code, headers, status
|
||||||
|
end
|
||||||
|
|
||||||
|
local function srequest(u, b)
|
||||||
|
local t = {}
|
||||||
|
local reqt = {
|
||||||
|
url = u,
|
||||||
|
sink = ltn12.sink.table(t)
|
||||||
|
}
|
||||||
|
if b then
|
||||||
|
reqt.source = ltn12.source.string(b)
|
||||||
|
reqt.headers = {
|
||||||
|
["content-length"] = string.len(b),
|
||||||
|
["content-type"] = "application/x-www-form-urlencoded"
|
||||||
|
}
|
||||||
|
reqt.method = "POST"
|
||||||
|
end
|
||||||
|
local code, headers, status = socket.skip(1, trequest(reqt))
|
||||||
|
local data = table.concat(t)
|
||||||
|
if #data>0 then
|
||||||
|
return data, code, headers, status
|
||||||
|
else
|
||||||
|
return nil, code, headers, status
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
_M.request = thread:newFunction(function(reqt, body)
|
||||||
|
if base.type(reqt) == "string" then return srequest(reqt, body)
|
||||||
|
else return trequest(reqt) end
|
||||||
|
end,true)
|
||||||
|
|
||||||
|
return _M
|
||||||
146
lnet/https.lua
Normal file
146
lnet/https.lua
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- LuaSec 1.0.1
|
||||||
|
-- Copyright (C) 2009-2021 PUC-Rio
|
||||||
|
--
|
||||||
|
-- Author: Pablo Musa
|
||||||
|
-- Author: Tomas Guisasola
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local socket = require("socket")
|
||||||
|
local ssl = require("ssl")
|
||||||
|
local ltn12 = require("ltn12")
|
||||||
|
local http = require("lnet.http")
|
||||||
|
local url = require("socket.url")
|
||||||
|
|
||||||
|
local try = socket.try
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Module
|
||||||
|
--
|
||||||
|
local _M = {
|
||||||
|
_VERSION = "1.0.1",
|
||||||
|
_COPYRIGHT = "LuaSec 1.0.1 - Copyright (C) 2009-2021 PUC-Rio",
|
||||||
|
PORT = 443,
|
||||||
|
TIMEOUT = 60
|
||||||
|
}
|
||||||
|
|
||||||
|
-- TLS configuration
|
||||||
|
local cfg = {
|
||||||
|
protocol = "any",
|
||||||
|
options = {"all", "no_sslv2", "no_sslv3", "no_tlsv1"},
|
||||||
|
verify = "none",
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
-- Auxiliar Functions
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Insert default HTTPS port.
|
||||||
|
local function default_https_port(u)
|
||||||
|
return url.build(url.parse(u, {port = _M.PORT}))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert an URL to a table according to Luasocket needs.
|
||||||
|
local function urlstring_totable(url, body, result_table)
|
||||||
|
url = {
|
||||||
|
url = default_https_port(url),
|
||||||
|
method = body and "POST" or "GET",
|
||||||
|
sink = ltn12.sink.table(result_table)
|
||||||
|
}
|
||||||
|
if body then
|
||||||
|
url.source = ltn12.source.string(body)
|
||||||
|
url.headers = {
|
||||||
|
["content-length"] = #body,
|
||||||
|
["content-type"] = "application/x-www-form-urlencoded",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return url
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Forward calls to the real connection object.
|
||||||
|
local function reg(conn)
|
||||||
|
local mt = getmetatable(conn.sock).__index
|
||||||
|
for name, method in pairs(mt) do
|
||||||
|
if type(method) == "function" then
|
||||||
|
conn[name] = function (self, ...)
|
||||||
|
return method(self.sock, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return a function which performs the SSL/TLS connection.
|
||||||
|
local function tcp(params)
|
||||||
|
params = params or {}
|
||||||
|
-- Default settings
|
||||||
|
for k, v in pairs(cfg) do
|
||||||
|
params[k] = params[k] or v
|
||||||
|
end
|
||||||
|
-- Force client mode
|
||||||
|
params.mode = "client"
|
||||||
|
-- 'create' function for LuaSocket
|
||||||
|
return function ()
|
||||||
|
local conn = {}
|
||||||
|
conn.sock = try(socket.tcp())
|
||||||
|
local st = getmetatable(conn.sock).__index.settimeout
|
||||||
|
function conn:settimeout(...)
|
||||||
|
return st(self.sock, _M.TIMEOUT)
|
||||||
|
end
|
||||||
|
-- Replace TCP's connection function
|
||||||
|
function conn:connect(host, port)
|
||||||
|
try(self.sock:connect(host, port))
|
||||||
|
self.sock = try(ssl.wrap(self.sock, params))
|
||||||
|
self.sock:sni(host)
|
||||||
|
self.sock:settimeout(_M.TIMEOUT)
|
||||||
|
try(self.sock:dohandshake())
|
||||||
|
reg(self, getmetatable(self.sock))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return conn
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
-- Main Function
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Make a HTTP request over secure connection. This function receives
|
||||||
|
-- the same parameters of LuaSocket's HTTP module (except 'proxy' and
|
||||||
|
-- 'redirect') plus LuaSec parameters.
|
||||||
|
--
|
||||||
|
-- @param url mandatory (string or table)
|
||||||
|
-- @param body optional (string)
|
||||||
|
-- @return (string if url == string or 1), code, headers, status
|
||||||
|
--
|
||||||
|
local function request(url, body)
|
||||||
|
local result_table = {}
|
||||||
|
local stringrequest = type(url) == "string"
|
||||||
|
if stringrequest then
|
||||||
|
url = urlstring_totable(url, body, result_table)
|
||||||
|
else
|
||||||
|
url.url = default_https_port(url.url)
|
||||||
|
end
|
||||||
|
if http.PROXY or url.proxy then
|
||||||
|
return nil, "proxy not supported"
|
||||||
|
elseif url.redirect then
|
||||||
|
return nil, "redirect not supported"
|
||||||
|
elseif url.create then
|
||||||
|
return nil, "create function not permitted"
|
||||||
|
end
|
||||||
|
-- New 'create' function to establish a secure connection
|
||||||
|
url.create = tcp(url)
|
||||||
|
local res, code, headers, status = http.request(url)
|
||||||
|
if res and stringrequest then
|
||||||
|
return table.concat(result_table), code, headers, status
|
||||||
|
end
|
||||||
|
return res, code, headers, status
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Export module
|
||||||
|
--
|
||||||
|
|
||||||
|
_M.request = request
|
||||||
|
_M.tcp = tcp
|
||||||
|
|
||||||
|
return _M
|
||||||
195
lnet/init.lua
Normal file
195
lnet/init.lua
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
--[[
|
||||||
|
UPCOMMING ADDITIONS
|
||||||
|
AUDP - advance udp. Ensures packets arrive and handles late packets.
|
||||||
|
P2P - peer to peer (Server to set up initial connection)
|
||||||
|
Relay - offput server load (locally)
|
||||||
|
Threading - Simple threading ~~(UDP/AUDP Only)~~ Thanks to an updated multi library we can thread with ease
|
||||||
|
Priority handling
|
||||||
|
]]
|
||||||
|
--[[
|
||||||
|
TODO: Finish stuff for Priority handling
|
||||||
|
]]
|
||||||
|
function table.merge(t1, t2)
|
||||||
|
for k, v in pairs(t2) do
|
||||||
|
if type(v) == "table" then
|
||||||
|
if type(t1[k] or false) == "table" then
|
||||||
|
table.merge(t1[k] or {}, t2[k] or {})
|
||||||
|
else
|
||||||
|
t1[k] = v
|
||||||
|
end
|
||||||
|
else
|
||||||
|
t1[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return t1
|
||||||
|
end
|
||||||
|
function string.trim(s)
|
||||||
|
local from = s:match "^%s*()"
|
||||||
|
return from > #s and "" or s:match(".*%S", from)
|
||||||
|
end
|
||||||
|
local guid = {}
|
||||||
|
local char = {}
|
||||||
|
for i = 48, 57 do
|
||||||
|
char[#char + 1] = string.char(i)
|
||||||
|
end
|
||||||
|
for i = 65, 90 do
|
||||||
|
char[#char + 1] = string.char(i)
|
||||||
|
end
|
||||||
|
for i = 97, 122 do
|
||||||
|
char[#char + 1] = string.char(i)
|
||||||
|
end
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
local multi, thread = require("multi").init()
|
||||||
|
local socket = require("socket")
|
||||||
|
local http = require("socket.http")
|
||||||
|
--ssl=require("ssl")
|
||||||
|
--https=require("ssl.https")
|
||||||
|
local net = {}
|
||||||
|
net.Version = {5, 0, 0} -- This will probably stay this version for quite a while... The modules on the otherhand will change more often
|
||||||
|
net._VERSION = "5.0.0"
|
||||||
|
net.ClientCache = {}
|
||||||
|
net.OnServerCreated = multi:newConnection()
|
||||||
|
net.OnClientCreated = multi:newConnection()
|
||||||
|
net.loadedModules = {}
|
||||||
|
net.OnCastedClientInfo = multi:newConnection()
|
||||||
|
net.autoInit = true
|
||||||
|
net.ConnectionDriver = {}
|
||||||
|
net.BroadcastDriver = {}
|
||||||
|
math.randomseed(math.ceil(os.time()+(os.clock()*1000)))
|
||||||
|
local isHyphen = {[9] = 1, [14] = 1, [19] = 1, [24] = 1}
|
||||||
|
net.generateGUID = function(t)
|
||||||
|
local pass = {}
|
||||||
|
local a = 0
|
||||||
|
local x = ""
|
||||||
|
for i in string.format("%x",os.time()+math.ceil(os.time()+os.clock()*1000)):gmatch(".") do
|
||||||
|
table.insert(pass,i)
|
||||||
|
end
|
||||||
|
for z = 9, 36 do
|
||||||
|
if isHyphen[z] then
|
||||||
|
x = "-"
|
||||||
|
else
|
||||||
|
a = math.random(1, #char)
|
||||||
|
x = char[a]
|
||||||
|
end
|
||||||
|
table.insert(pass, x)
|
||||||
|
if t == z then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
z = nil
|
||||||
|
return tostring(table.concat(pass))
|
||||||
|
end
|
||||||
|
function net.normalize(input)
|
||||||
|
local enc = mime.b64(input)
|
||||||
|
return enc
|
||||||
|
end
|
||||||
|
function net.denormalize(input)
|
||||||
|
local unenc = mime.unb64(input)
|
||||||
|
return unenc
|
||||||
|
end
|
||||||
|
function net.getLocalIP()
|
||||||
|
local someRandomIP = "192.168.1.122"
|
||||||
|
local someRandomPort = "3102"
|
||||||
|
local mySocket = socket.udp()
|
||||||
|
mySocket:setpeername(someRandomIP, someRandomPort)
|
||||||
|
local dat = (mySocket:getsockname())
|
||||||
|
mySocket:close()
|
||||||
|
return dat
|
||||||
|
end
|
||||||
|
function net.getExternalIP()
|
||||||
|
local data = http.request("http://www.myipnumber.com/my-ip-address.asp")
|
||||||
|
return data:match("(%d+%.%d+%.%d+%.%d+)")
|
||||||
|
end
|
||||||
|
function net.registerModule(mod, version)
|
||||||
|
if net[mod] then
|
||||||
|
error("Module by the name: " .. mod .. " has already been registered! Remember some modules are internal and use certain names!")
|
||||||
|
end
|
||||||
|
table.insert(net.loadedModules, mod)
|
||||||
|
net[mod] = {}
|
||||||
|
if version then
|
||||||
|
net[mod].Version = version
|
||||||
|
net[mod]._VERSION = table.concat(version,".")
|
||||||
|
else
|
||||||
|
net[mod].Version = {1, 0, 0}
|
||||||
|
net[mod]._VERSION = {1, 0, 0}
|
||||||
|
end
|
||||||
|
return {Version = version, _VERSION = table.concat(version,".")}
|
||||||
|
end
|
||||||
|
function net.getModuleVersion(ext)
|
||||||
|
if not ext then
|
||||||
|
return string.format("%d.%d.%d", net.Version[1], net.Version[2], net.Version[3])
|
||||||
|
end
|
||||||
|
return string.format("%d.%d.%d", net[ext].Version[1], net[ext].Version[2], net[ext].Version[3])
|
||||||
|
end
|
||||||
|
function net.resolveID(obj)
|
||||||
|
local num = math.random(10000000, 99999999)
|
||||||
|
if obj[tostring(num)] then
|
||||||
|
return net.resolveID(obj)
|
||||||
|
end
|
||||||
|
obj.ids[tostring(num)] = true
|
||||||
|
return tostring(num)
|
||||||
|
end
|
||||||
|
function net.inList(list, dat)
|
||||||
|
for i, v in pairs(list) do
|
||||||
|
if v == dat then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
function net.setTrigger(funcW, funcE)
|
||||||
|
multi:newTrigger(func)
|
||||||
|
end
|
||||||
|
net.registerModule("net", net.Version)
|
||||||
|
-- Client broadcast
|
||||||
|
function net.newCastedClient(name) -- connects to the broadcasted server
|
||||||
|
local listen = socket.udp() -- make a new socket
|
||||||
|
listen:setsockname(net.getLocalIP(), 11111)
|
||||||
|
listen:settimeout(0)
|
||||||
|
local timer = multi:newTimer()
|
||||||
|
while true do
|
||||||
|
local data, ip, port = listen:receivefrom()
|
||||||
|
if timer:Get() > 3 then
|
||||||
|
error("Timeout! Server by the name: " .. name .. " has not been found!")
|
||||||
|
end
|
||||||
|
if data then
|
||||||
|
local n, tp, ip, port = data:match("(%S-)|(%S-)|(%S-):(%d+)")
|
||||||
|
if n:match(name) then
|
||||||
|
if tp == "tcp" then
|
||||||
|
return net.newTCPClient(ip, tonumber(port))
|
||||||
|
else
|
||||||
|
return net.newClient(ip, tonumber(port))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function net.newCastedClients(name) -- connects to the broadcasted server
|
||||||
|
local listen = socket.udp() -- make a new socket
|
||||||
|
listen:setsockname(net.getLocalIP(), 11111)
|
||||||
|
listen:settimeout(0)
|
||||||
|
multi:newThread("net.castedTask",function()
|
||||||
|
while true do
|
||||||
|
thread.skip(24)
|
||||||
|
local data, ip, port = listen:receivefrom()
|
||||||
|
if data then
|
||||||
|
local n, tp, ip, port = data:match("(%S-)|(%S-)|(%S-):(%d+)")
|
||||||
|
if n:match(name) and not net.ClientCache[n] then
|
||||||
|
local capture = n:match(name)
|
||||||
|
local client = {}
|
||||||
|
if tp == "tcp" then
|
||||||
|
client = net:newTCPClient(ip, tonumber(port))
|
||||||
|
else
|
||||||
|
client = net:newUDPClient(ip, tonumber(port))
|
||||||
|
end
|
||||||
|
net.ClientCache[n] = client
|
||||||
|
net.OnCastedClientInfo:Fire(client, n, ip, port)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return net
|
||||||
135
lnet/tcp/init.lua
Normal file
135
lnet/tcp/init.lua
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
local net = require("lnet")
|
||||||
|
local clientbase = require("lnet.base.client")
|
||||||
|
local serverbase = require("lnet.base.server")
|
||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local socket = require("socket")
|
||||||
|
local tcpcount = 0
|
||||||
|
net.newTCPServer = thread:newFunction(function(port)
|
||||||
|
local c = {}
|
||||||
|
setmetatable(c,serverbase)
|
||||||
|
c:init("tcp")
|
||||||
|
c.tcp = assert(socket.bind("*", port or 0))
|
||||||
|
c.tcp:settimeout(0)
|
||||||
|
c.ip, c.port = c.tcp:getsockname()
|
||||||
|
if port and port == 0 then
|
||||||
|
_, c.port = c.tcp:getsockname()
|
||||||
|
end
|
||||||
|
function c:send(cid,data)
|
||||||
|
local dat = {data = data, cid = cid}
|
||||||
|
self.OnPreSend:Fire(dat)
|
||||||
|
if self.sMode == "*l" then
|
||||||
|
cid:send(data .. "\n")
|
||||||
|
else
|
||||||
|
cid:send(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
tcpcount = tcpcount + 1
|
||||||
|
c.updateThread = c.process:newThread("TCPServer Thread<"..tcpcount..">",function()
|
||||||
|
while true do
|
||||||
|
thread.skip(c.updaterRate)
|
||||||
|
local client = c.tcp:accept(c.rMode)
|
||||||
|
if client then
|
||||||
|
print("Got Client!")
|
||||||
|
table.insert(c.ips, client)
|
||||||
|
client:settimeout(0)
|
||||||
|
client:setoption("keepalive", true)
|
||||||
|
ip, port = client:getpeername()
|
||||||
|
if ip and port then
|
||||||
|
c.OnClientConnected:Fire(c, client, ip, port)
|
||||||
|
-- We need to cache the client handler so we can work with it
|
||||||
|
c.clientHandlers[client] = multi:newThread("ServerClientHandler<".. tostring(client):match(": (.+)") ..">",function()
|
||||||
|
local cli = client
|
||||||
|
while true do
|
||||||
|
thread.yield()
|
||||||
|
local data, err, dat, len
|
||||||
|
data, err = thread.hold(function()
|
||||||
|
data, err = cli:receive(c.rMode)
|
||||||
|
if data then print(data) end
|
||||||
|
if data~=nil and err then
|
||||||
|
print(err)
|
||||||
|
return multi.NIL, err
|
||||||
|
end
|
||||||
|
return data
|
||||||
|
end)
|
||||||
|
if err == "closed" then
|
||||||
|
for i = 1, #c.ips do
|
||||||
|
if c.ips[i] == cli then
|
||||||
|
table.remove(c.ips, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
c.OnClientClosed:Fire(c, "Client Closed Connection!", cli, ip)
|
||||||
|
c.links[cli] = nil -- lets clean up
|
||||||
|
thread.kill()
|
||||||
|
end
|
||||||
|
if data then
|
||||||
|
if net.inList(c.bannedIPs, ip) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
c.OnDataRecieved:Fire(c, data, cli, ip, port)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end).OnError(function(...)
|
||||||
|
print(...)
|
||||||
|
end)
|
||||||
|
net.OnServerCreated:Fire(c)
|
||||||
|
return c
|
||||||
|
end,true)
|
||||||
|
|
||||||
|
net.newTCPClient = thread:newFunction(function(host, port)
|
||||||
|
local c = {}
|
||||||
|
setmetatable(c,clientbase)
|
||||||
|
c:init("tcp")
|
||||||
|
c.ip = assert(socket.dns.toip(host))
|
||||||
|
c.tcp = socket.connect(c.ip,port)
|
||||||
|
c.tcp:settimeout(0)
|
||||||
|
c.tcp:setoption("keepalive",true)
|
||||||
|
function c:send(data)
|
||||||
|
if self.sMode == "*l" then
|
||||||
|
data = data .. "\n"
|
||||||
|
end
|
||||||
|
print("Sending:",data)
|
||||||
|
local dat = {data = data}
|
||||||
|
self.OnPreSend:Fire(dat)
|
||||||
|
local ind, err = self.tcp:send(dat.data)
|
||||||
|
print(ind,err)
|
||||||
|
print("Data Sent!")
|
||||||
|
if err == "closed" then
|
||||||
|
self.OnClientDisconnected:Fire(self,err)
|
||||||
|
elseif err == "timeout" then
|
||||||
|
self.OnClientDisconnected:Fire(self,err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
c.updateThread = c.process:newThread("TCPClient Thread<"..tcpcount..">",function()
|
||||||
|
while true do
|
||||||
|
thread.skip(c.updaterRate)
|
||||||
|
local data = thread.hold(function()
|
||||||
|
local d,err = c.tcp:receive(c.rMode)
|
||||||
|
if not(d) then
|
||||||
|
if err == "closed" then
|
||||||
|
c.OnClientDisconnected:Fire(c,err)
|
||||||
|
elseif err == "timeout" then
|
||||||
|
c.OnClientDisconnected:Fire(c,err)
|
||||||
|
else
|
||||||
|
print(err)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return d
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
if data then
|
||||||
|
local dat = {data = data}
|
||||||
|
c.OnPreRecieved:Fire(dat)
|
||||||
|
c.OnDataRecieved:Fire(c,dat.data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end).OnError(function(...)
|
||||||
|
print(...)
|
||||||
|
end)
|
||||||
|
net.OnClientCreated:Fire(c)
|
||||||
|
return c
|
||||||
|
end,true)
|
||||||
|
return net
|
||||||
102
lnet/udp/init.lua
Normal file
102
lnet/udp/init.lua
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
local net = require("lnet")
|
||||||
|
local clientbase = require("lnet.base.client")
|
||||||
|
local serverbase = require("lnet.base.server")
|
||||||
|
local multi, thread = require("multi"):init()
|
||||||
|
local CID = {}
|
||||||
|
CID.__index = cid
|
||||||
|
local udpcount = 0
|
||||||
|
CID.ip = "0.0.0.0"
|
||||||
|
CID.port = 0
|
||||||
|
net.newUDPServer = thread:newFunction(function(port)
|
||||||
|
local c = {}
|
||||||
|
setmetatable(c,serverbase)
|
||||||
|
c:init("udp")
|
||||||
|
c.udp = assert(socket.udp())
|
||||||
|
c.udp:settimeout(0)
|
||||||
|
c.udp:setsockname("*",port)
|
||||||
|
local inactivity = {}
|
||||||
|
if port == 0 then
|
||||||
|
_,c.port = c.udp:getsockname()
|
||||||
|
else
|
||||||
|
c.port = port
|
||||||
|
end
|
||||||
|
udpcount = udpcount + 1
|
||||||
|
function c:send(cid,data)
|
||||||
|
local dat = {data = data, cid = cid}
|
||||||
|
self.OnPreSend:Fire(dat)
|
||||||
|
self.udp:sendto(dat.data,dat.cid.ip,dat.cid.port)
|
||||||
|
end
|
||||||
|
c.updateThread = c.process:newThread("UDPServer Thread<"..udpcount..">",function()
|
||||||
|
-- Every now and then we are going to check to see if a client has been inactive
|
||||||
|
local sideJob = thread:newFunction(function()
|
||||||
|
thread.sleep(60*c.idleRate)
|
||||||
|
for i,v in pairs(c.cids) do
|
||||||
|
thread.skip(1)
|
||||||
|
if os.clock() - v.activity >= 60*c.idleRate then
|
||||||
|
c.OnClientClosed:Fire(v)
|
||||||
|
c.cids[i] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end)
|
||||||
|
while true do
|
||||||
|
thread.skip(c.updaterRate)
|
||||||
|
local data, ip, port = c.udp:receivefrom()
|
||||||
|
sideJob().connect(function(yes)
|
||||||
|
if yes then
|
||||||
|
sideJob:Resume()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
sideJob:Pause()
|
||||||
|
if data then
|
||||||
|
local cid = c:getCid(ip,port)
|
||||||
|
if not cid then
|
||||||
|
local cd = {}
|
||||||
|
setmetatable(cd,CID)
|
||||||
|
cd.ip = ip
|
||||||
|
cd.port = port
|
||||||
|
cd.activity = os.clock()
|
||||||
|
c.cids[ip .. port] = cd
|
||||||
|
cid = cd
|
||||||
|
c.OnClientConnected:Fire(c, cd, ip, port)
|
||||||
|
end
|
||||||
|
cid.activity = os.clock()
|
||||||
|
local dat = {data = data,cid = cid}
|
||||||
|
c.OnPreRecieved:Fire(dat)
|
||||||
|
c.OnDataRecieved:Fire(c,dat.data,dat.cid,cid.ip,cid.port)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end).OnError(function(...)
|
||||||
|
print(...)
|
||||||
|
end)
|
||||||
|
net.OnServerCreated:Fire(c)
|
||||||
|
return c
|
||||||
|
end,true)
|
||||||
|
net.newUDPClient = thread:newFunction(function(host, port)
|
||||||
|
local c = {}
|
||||||
|
setmetatable(c,clientbase)
|
||||||
|
c:init("udp")
|
||||||
|
c.ip = assert(socket.dns.toip(host))
|
||||||
|
c.udp = assert(socket.udp())
|
||||||
|
c.udp:settimeout(0)
|
||||||
|
c.udp:setpeername(c.ip,port)
|
||||||
|
function c:send(data)
|
||||||
|
local dat = {data = data}
|
||||||
|
self.OnPreSend:Fire(dat)
|
||||||
|
self.udp:send(dat.data)
|
||||||
|
end
|
||||||
|
c.updateThread = c.process:newThread("UDPServer Thread<"..udpcount..">",function()
|
||||||
|
while true do
|
||||||
|
thread.skip(c.updaterRate)
|
||||||
|
local data = thread.hold(function()
|
||||||
|
return c.udp:receive()
|
||||||
|
end)
|
||||||
|
local dat = {data = data}
|
||||||
|
c.OnPreRecieved:Fire(dat)
|
||||||
|
c.OnDataRecieved:Fire(c,dat.data)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
net.OnClientCreated:Fire(c)
|
||||||
|
return c
|
||||||
|
end,true)
|
||||||
|
return net
|
||||||
1
multi
Submodule
1
multi
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d36204c87f5c63a4e6f7510040e495bbab3de2d1
|
||||||
893
net/init.lua
893
net/init.lua
@ -1,893 +0,0 @@
|
|||||||
--[[
|
|
||||||
UPCOMMING ADDITIONS
|
|
||||||
AUDP - advance udp. Ensures packets arrive and handles late packets.
|
|
||||||
P2P - peer to peer (Server to set up initial connection)
|
|
||||||
Relay - offput server load (locally)
|
|
||||||
Threading - Simple threading ~~(UDP/AUDP Only)~~ Thanks to an updated multi library we can thread with ease
|
|
||||||
Priority handling
|
|
||||||
]]
|
|
||||||
--[[
|
|
||||||
TODO: Finish stuff for Priority handling
|
|
||||||
]]
|
|
||||||
function table.merge(t1, t2)
|
|
||||||
for k,v in pairs(t2) do
|
|
||||||
if type(v) == 'table' then
|
|
||||||
if type(t1[k] or false) == 'table' then
|
|
||||||
table.merge(t1[k] or {}, t2[k] or {})
|
|
||||||
else
|
|
||||||
t1[k] = v
|
|
||||||
end
|
|
||||||
else
|
|
||||||
t1[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return t1
|
|
||||||
end
|
|
||||||
function string.trim(s)
|
|
||||||
local from = s:match"^%s*()"
|
|
||||||
return from > #s and "" or s:match(".*%S", from)
|
|
||||||
end
|
|
||||||
local guid = {}
|
|
||||||
local char = {}
|
|
||||||
for i = 48,57 do
|
|
||||||
char[#char+1]=string.char(i)
|
|
||||||
end
|
|
||||||
for i = 65,90 do
|
|
||||||
char[#char+1]=string.char(i)
|
|
||||||
end
|
|
||||||
for i = 97,122 do
|
|
||||||
char[#char+1]=string.char(i)
|
|
||||||
end
|
|
||||||
local isHyphen = {[9]=1,[14]=1,[19]=1,[24]=1}
|
|
||||||
math.randomseed(os.time())
|
|
||||||
local multi = require("multi")
|
|
||||||
local socket=require("socket")
|
|
||||||
local http=require("socket.http")
|
|
||||||
local mime=require("mime")
|
|
||||||
--ssl=require("ssl")
|
|
||||||
--https=require("ssl.https")
|
|
||||||
local net={}
|
|
||||||
net.Version={3,0,0} -- This will probably stay this version for quite a while... The modules on the otherhand will be more inconsistant
|
|
||||||
net._VERSION="3.0.0"
|
|
||||||
net.ClientCache = {}
|
|
||||||
net.OnServerCreated=multi:newConnection()
|
|
||||||
net.OnClientCreated=multi:newConnection()
|
|
||||||
net.loadedModules={}
|
|
||||||
net.OnCastedClientInfo=multi:newConnection()
|
|
||||||
net.autoInit=true
|
|
||||||
net.ConnectionDriver = {}
|
|
||||||
net.BroadcastDriver = {}
|
|
||||||
net.generateGUID = function(t)
|
|
||||||
local pass = {}
|
|
||||||
local a=0
|
|
||||||
local x=""
|
|
||||||
for z = 1,36 do
|
|
||||||
if isHyphen[z] then
|
|
||||||
x='-'
|
|
||||||
else
|
|
||||||
a = math.random(1,#char)
|
|
||||||
x = char[a]
|
|
||||||
end
|
|
||||||
table.insert(pass, x)
|
|
||||||
if t == z then break end
|
|
||||||
end
|
|
||||||
z = nil
|
|
||||||
return tostring(table.concat(pass))
|
|
||||||
end
|
|
||||||
function net.normalize(input)
|
|
||||||
local enc=mime.b64(input)
|
|
||||||
return enc
|
|
||||||
end
|
|
||||||
function net.denormalize(input)
|
|
||||||
local unenc=mime.unb64(input)
|
|
||||||
return unenc
|
|
||||||
end
|
|
||||||
function net.getLocalIP()
|
|
||||||
local someRandomIP = "192.168.1.122"
|
|
||||||
local someRandomPort = "3102"
|
|
||||||
local mySocket = socket.udp()
|
|
||||||
mySocket:setpeername(someRandomIP,someRandomPort)
|
|
||||||
local dat = (mySocket:getsockname())
|
|
||||||
mySocket:close()
|
|
||||||
return dat
|
|
||||||
end
|
|
||||||
function net.getExternalIP()
|
|
||||||
local data=http.request("http://whatismyip.host")
|
|
||||||
return data:match("(%d+.%d+.%d+.%d+)")
|
|
||||||
end
|
|
||||||
function net:registerModule(mod,version)
|
|
||||||
if net[mod] then
|
|
||||||
error("Module by the name: "..mod.." has already been registered! Remember some modules are internal and use certain names!")
|
|
||||||
end
|
|
||||||
table.insert(self.loadedModules,mod)
|
|
||||||
net[mod]={}
|
|
||||||
if version then
|
|
||||||
net[mod].Version=version
|
|
||||||
net[mod]._VERSION=version[1].."."..version[2].."."..version[3]
|
|
||||||
else
|
|
||||||
net[mod].Version={1,0,0}
|
|
||||||
net[mod]._VERSION={1,0,0}
|
|
||||||
end
|
|
||||||
return {Version=version,_VERSION=version[1].."."..version[2].."."..version[3]}
|
|
||||||
end
|
|
||||||
function net.getModuleVersion(ext)
|
|
||||||
if not ext then
|
|
||||||
return string.format("%d.%d.%d",net.Version[1],net.Version[2],net.Version[3])
|
|
||||||
end
|
|
||||||
return string.format("%d.%d.%d",net[ext].Version[1],net[ext].Version[2],net[ext].Version[3])
|
|
||||||
end
|
|
||||||
function net.resolveID(obj)
|
|
||||||
local num=math.random(10000000,99999999)
|
|
||||||
if obj[tostring(num)] then
|
|
||||||
return net.resolveID(obj)
|
|
||||||
end
|
|
||||||
obj.ids[tostring(num)]=true
|
|
||||||
return tostring(num)
|
|
||||||
end
|
|
||||||
function net.inList(list,dat)
|
|
||||||
for i,v in pairs(list) do
|
|
||||||
if v==dat then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
function net.setTrigger(funcW,funcE)
|
|
||||||
multi:newTrigger(func)
|
|
||||||
end
|
|
||||||
net:registerModule("net",net.Version)
|
|
||||||
-- Client broadcast
|
|
||||||
function net:newCastedClient(name) -- connects to the broadcasted server
|
|
||||||
local listen = socket.udp() -- make a new socket
|
|
||||||
listen:setsockname(net.getLocalIP(), 11111)
|
|
||||||
listen:settimeout(0)
|
|
||||||
local timer=multi:newTimer()
|
|
||||||
while true do
|
|
||||||
local data, ip, port = listen:receivefrom()
|
|
||||||
if timer:Get()>3 then
|
|
||||||
error("Timeout! Server by the name: "..name.." has not been found!")
|
|
||||||
end
|
|
||||||
if data then
|
|
||||||
print("found!",data)
|
|
||||||
local n,tp,ip,port=data:match("(%S-)|(%S-)|(%S-):(%d+)")
|
|
||||||
if n:match(name) then
|
|
||||||
print("Found Server!",n,tp,ip,port)
|
|
||||||
if tp=="tcp" then
|
|
||||||
return net:newTCPClient(ip,tonumber(port))
|
|
||||||
else
|
|
||||||
return net:newClient(ip,tonumber(port))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function net:newCastedClients(name) -- connects to the broadcasted server
|
|
||||||
local listen = socket.udp() -- make a new socket
|
|
||||||
listen:setsockname(net.getLocalIP(), 11111)
|
|
||||||
listen:settimeout(0)
|
|
||||||
multi:newTLoop(function(self)
|
|
||||||
local data, ip, port = listen:receivefrom()
|
|
||||||
if data then
|
|
||||||
local n,tp,ip,port=data:match("(%S-)|(%S-)|(%S-):(%d+)")
|
|
||||||
if n:match(name) and not net.ClientCache[n] then
|
|
||||||
local capture = n:match(name)
|
|
||||||
local client = {}
|
|
||||||
if tp=="tcp" then
|
|
||||||
client=net:newTCPClient(ip,tonumber(port))
|
|
||||||
else
|
|
||||||
client=net:newUDPClient(ip,tonumber(port))
|
|
||||||
end
|
|
||||||
net.ClientCache[n]=client
|
|
||||||
net.OnCastedClientInfo:Fire(client,n,ip,port)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,.1):setName("net.castedTask")
|
|
||||||
end
|
|
||||||
-- UDP Stuff
|
|
||||||
function net:newUDPServer(port,servercode,nonluaServer)
|
|
||||||
local c={}
|
|
||||||
c.udp=assert(socket.udp())
|
|
||||||
c.udp:settimeout(0)
|
|
||||||
c.udp:setsockname("*", port)
|
|
||||||
c.ips={}
|
|
||||||
c.Type="udp"
|
|
||||||
if port == 0 then
|
|
||||||
_, c.port = c.udp:getsockname()
|
|
||||||
end
|
|
||||||
c.ids={}
|
|
||||||
c.servercode=servercode
|
|
||||||
c.bannedIPs={}
|
|
||||||
c.bannedCIDs={}
|
|
||||||
c.autoNormalization=false
|
|
||||||
function c:setUpdateRate(n)
|
|
||||||
print("Not needed in a udp server!")
|
|
||||||
end
|
|
||||||
function c:banCID(cid)
|
|
||||||
table.insert(self.bannedCIDs,cid)
|
|
||||||
end
|
|
||||||
function c:banIP(ip)
|
|
||||||
table.insert(self.bannedIPs,cid)
|
|
||||||
end
|
|
||||||
c.broad=socket.udp()
|
|
||||||
c.hostip=net.getLocalIP()
|
|
||||||
function c:broadcast(name)
|
|
||||||
table.insert(net.BroadcastDriver,function(loop,dt)
|
|
||||||
self.broad:setoption('broadcast',true)
|
|
||||||
self.broad:sendto(name.."|"..self.Type.."|"..self.hostip..":"..self.port, "255.255.255.255", 11111)
|
|
||||||
self.broad:setoption('broadcast',false)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
function c:send(ip,data,port,cid)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
if self.servercode then
|
|
||||||
cid=cid or self:CIDFrom(ip,port)
|
|
||||||
if not self.ips[cid] then
|
|
||||||
print("Can't determine cid from client... sending the client a new one!")
|
|
||||||
local cid=net.resolveID(self)
|
|
||||||
print("Sending unique cid to client: "..cid)
|
|
||||||
self.ips[cid]={ip,port,0,self.servercode==nil}
|
|
||||||
print(ip)
|
|
||||||
self.udp:sendto("I!"..cid,ip,port)
|
|
||||||
if self.servercode then
|
|
||||||
self.udp:sendto("S!",ip,port)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if net.inList(self.bannedIPs,ip) or net.inList(self.bannedCIDs,cid) then
|
|
||||||
self.udp:sendto("BANNED CLIENT", ip, port or self.port)
|
|
||||||
elseif self.ips[cid][4] then
|
|
||||||
self.udp:sendto(data, ip, port or self.port)
|
|
||||||
elseif self.ips[cid][4]==false then
|
|
||||||
self.udp:sendto("Make sure your server code is correct!", ip, port)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.udp:sendto(data, ip, port or self.port)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:pollClientModules(ip,port)
|
|
||||||
self:send(ip,"L!",port)
|
|
||||||
end
|
|
||||||
function c:CIDFrom(ip,port)
|
|
||||||
for i,v in pairs(self.ips) do
|
|
||||||
if(ip==v[1] and v[2]==port) then
|
|
||||||
return i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:sendAll(data)
|
|
||||||
for i,v in pairs(self.ips) do
|
|
||||||
self:send(v[1],data,v[2],i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:sendAllBut(data,cid)
|
|
||||||
for i,v in pairs(self.ips) do
|
|
||||||
if i~=cid then
|
|
||||||
self:send(v[1],data,v[2],i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:clientRegistered(cid)
|
|
||||||
return self.ips[cid]
|
|
||||||
end
|
|
||||||
function c:clientLoggedIn(cid)
|
|
||||||
if not self.clientRegistered(cid) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
return self.ips[cid][4]
|
|
||||||
end
|
|
||||||
function c:update()
|
|
||||||
local data,ip,port=self.udp:receivefrom()
|
|
||||||
if net.inList(self.bannedIPs,ip) or net.inList(self.bannedCIDs,cid) then
|
|
||||||
print("We will ignore data from a banned client!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if data then
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.denormalize(data)
|
|
||||||
end
|
|
||||||
if data:sub(1,4)=="pong" then
|
|
||||||
--print("Recieved pong from: "..data:sub(5,-1))
|
|
||||||
self.ips[data:sub(5,-1)][3]=os.clock()
|
|
||||||
elseif data:sub(1,2)=="S!" then
|
|
||||||
local cid=self:CIDFrom(ip,port)
|
|
||||||
if data:sub(3,-1)==self.servercode then
|
|
||||||
print("Servercode Accepted: "..self.servercode)
|
|
||||||
if self.ips[cid] then
|
|
||||||
self.ips[cid][4]=true
|
|
||||||
else
|
|
||||||
print("Server can't keep up! CID: "..cid.." has been skipped! Sending new CID to the client!")
|
|
||||||
local cid=net.resolveID(self)
|
|
||||||
print("Sending unique cid to client: "..cid)
|
|
||||||
self.ips[cid]={ip,port,0,self.servercode==nil}
|
|
||||||
print(ip)
|
|
||||||
self.udp:sendto("I!"..cid,ip,port)
|
|
||||||
if self.servercode then
|
|
||||||
self.udp:sendto("S!",ip,port)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.udp:sendto("Make sure your server code is correct!", ip, port)
|
|
||||||
end
|
|
||||||
elseif data:sub(1,2)=="C!" then
|
|
||||||
local hook=(data:sub(11,-1)):match("!(.-)!")
|
|
||||||
self.OnDataRecieved:getConnection(hook):Fire(self,data:sub(11,-1),data:sub(3,10),ip,port)
|
|
||||||
elseif data:sub(1,2)=="E!" then
|
|
||||||
self.ips[data:sub(3,10)]=nil
|
|
||||||
obj.ids[data:sub(3,10)]=false
|
|
||||||
self.OnClientClosed:Fire(self,"Client Closed Connection!",data:sub(3,10),ip,port)
|
|
||||||
elseif data=="I!" then
|
|
||||||
local cid=net.resolveID(self)
|
|
||||||
print("Sending unique cid to client: "..cid)
|
|
||||||
self.ips[cid]={ip,port,os.clock(),self.servercode==nil}
|
|
||||||
print(ip)
|
|
||||||
self.udp:sendto("I!"..cid,ip,port)
|
|
||||||
if self.servercode then
|
|
||||||
self.udp:sendto("S!",ip,port)
|
|
||||||
end
|
|
||||||
self.OnClientConnected:Fire(self,cid,ip,port)
|
|
||||||
elseif data:sub(1,2)=="L!" then
|
|
||||||
cid,cList=data:sub(3,10),data:sub(11,-1)
|
|
||||||
local list={}
|
|
||||||
for m,v in cList:gmatch("(%S-):(%S-)|") do
|
|
||||||
list[m]=v
|
|
||||||
end
|
|
||||||
self.OnClientsModulesList:Fire(list,cid,ip,port)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for cid,dat in pairs(self.ips) do
|
|
||||||
if not((os.clock()-dat[3])<65) then
|
|
||||||
self.ips[cid]=nil
|
|
||||||
self.OnClientClosed:Fire(self,"Client lost Connection: ping timeout",cid,ip,port)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
c.OnClientsModulesList=multi:newConnection()
|
|
||||||
c.OnDataRecieved=multi:newConnection()
|
|
||||||
c.OnClientClosed=multi:newConnection()
|
|
||||||
c.OnClientConnected=multi:newConnection()
|
|
||||||
c.connectiontest=multi:newAlarm(30):setName("net.pingOutTask")
|
|
||||||
c.connectiontest.link=c
|
|
||||||
c.connectiontest:OnRing(function(alarm)
|
|
||||||
alarm.link:sendAll("ping")
|
|
||||||
alarm:Reset()
|
|
||||||
end)
|
|
||||||
table.insert(net.ConnectionDriver,c)
|
|
||||||
net.OnServerCreated:Fire(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
local pingManager = {}
|
|
||||||
function net:newUDPClient(host,port,servercode,nonluaServer)
|
|
||||||
local c={}
|
|
||||||
c.ip=assert(socket.dns.toip(host))
|
|
||||||
c.udp=assert(socket.udp())
|
|
||||||
c.udp:settimeout(0)
|
|
||||||
c.udp:setpeername(c.ip, port)
|
|
||||||
c.cid="NIL"
|
|
||||||
c.lastPing=0
|
|
||||||
c.Type="udp"
|
|
||||||
c.servercode=servercode
|
|
||||||
c.autoReconnect=true
|
|
||||||
c.autoNormalization=false
|
|
||||||
function c:pollPing(n)
|
|
||||||
return not((os.clock()-self.lastPing)<(n or 60))
|
|
||||||
end
|
|
||||||
function c:send(data)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
self.udp:send("C!"..self.cid..data)
|
|
||||||
end
|
|
||||||
function c:sendRaw(data)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
self.udp:send(data)
|
|
||||||
end
|
|
||||||
function c:getCID()
|
|
||||||
if self:IDAssigned() then
|
|
||||||
return self.cid
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:close()
|
|
||||||
self:send("E!")
|
|
||||||
end
|
|
||||||
function c:IDAssigned()
|
|
||||||
return self.cid~="NIL"
|
|
||||||
end
|
|
||||||
function c:update()
|
|
||||||
local data=self.udp:receive()
|
|
||||||
if data then
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.denormalize(data)
|
|
||||||
end
|
|
||||||
if data:sub(1,2)=="I!" then
|
|
||||||
self.cid=data:sub(3,-1)
|
|
||||||
self.OnClientReady:Fire(self)
|
|
||||||
elseif data=="S!" then
|
|
||||||
self.udp:send("S!"..(self.servercode or ""))
|
|
||||||
elseif data=="L!" then
|
|
||||||
local mods=""
|
|
||||||
local m=""
|
|
||||||
for i=1,#net.loadedModules do
|
|
||||||
m=net.loadedModules[i]
|
|
||||||
mods=mods..m..":"..net.getModuleVersion(m).."|"
|
|
||||||
end
|
|
||||||
self.udp:send("L!"..self.cid..mods)
|
|
||||||
elseif data=="ping" then
|
|
||||||
self.lastPing=os.clock()
|
|
||||||
self.OnPingRecieved:Fire(self)
|
|
||||||
self.udp:send("pong"..self.cid)
|
|
||||||
else
|
|
||||||
local hook=data:match("!(.-)!")
|
|
||||||
self.OnDataRecieved:getConnection(hook):Fire(self,data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:reconnect()
|
|
||||||
if not nonluaServer then
|
|
||||||
self.cid="NIL"
|
|
||||||
c.udp:send("I!")
|
|
||||||
end
|
|
||||||
self.pingEvent:Resume()
|
|
||||||
self.OnConnectionRegained:Fire(self)
|
|
||||||
end
|
|
||||||
c.pingEvent=multi:newEvent(function(self) return self.link:pollPing() end)
|
|
||||||
c.pingEvent:OnEvent(function(self)
|
|
||||||
if self.link.autoReconnect then
|
|
||||||
self.link.OnServerNotAvailable:Fire("Connection to server lost: ping timeout! Attempting to reconnect...")
|
|
||||||
self.link.OnClientDisconnected:Fire(self,"closed")
|
|
||||||
self.link:reconnect()
|
|
||||||
else
|
|
||||||
self.link.OnServerNotAvailable:Fire("Connection to server lost: ping timeout!")
|
|
||||||
self.link.OnClientDisconnected:Fire(self,"closed")
|
|
||||||
end
|
|
||||||
self:Pause()
|
|
||||||
end):setName("net.pingInTask")
|
|
||||||
c.pingEvent.link=c
|
|
||||||
c.OnPingRecieved=multi:newConnection()
|
|
||||||
c.OnDataRecieved=multi:newConnection()
|
|
||||||
c.OnServerNotAvailable=multi:newConnection()
|
|
||||||
c.OnClientReady=multi:newConnection()
|
|
||||||
c.OnClientDisconnected=multi:newConnection()
|
|
||||||
c.OnConnectionRegained=multi:newConnection()
|
|
||||||
c.notConnected=multi:newFunction(function(self)
|
|
||||||
multi:newAlarm(3):OnRing(function(alarm)
|
|
||||||
if self.link:IDAssigned()==false then
|
|
||||||
self.link.OnServerNotAvailable:Fire("Can't connect to the server: no response from server")
|
|
||||||
end
|
|
||||||
alarm:Destroy()
|
|
||||||
end):setName("net.clientTimeout")
|
|
||||||
end)
|
|
||||||
c.notConnected.link=c
|
|
||||||
if not nonluaServer then
|
|
||||||
c.udp:send("I!")
|
|
||||||
end
|
|
||||||
table.insert(net.ConnectionDriver,c)
|
|
||||||
multi.nextStep(function() c.notConnected() end)
|
|
||||||
net.OnClientCreated:Fire(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
multi:newThread(function()
|
|
||||||
|
|
||||||
end)
|
|
||||||
--TCP Stuff
|
|
||||||
function net:newTCPClientObject(fd)
|
|
||||||
local c = {}
|
|
||||||
local client
|
|
||||||
c.Type="tcp-ClientObj"
|
|
||||||
c.rMode="*l"
|
|
||||||
c.sMode="*l"
|
|
||||||
function c:packMsg(data)
|
|
||||||
local temp = bin.new()
|
|
||||||
temp:addBlock(#data,self.numspace,"n")
|
|
||||||
temp:addBlock(data)
|
|
||||||
return temp:getData()
|
|
||||||
end
|
|
||||||
function c:enableBinaryMode()
|
|
||||||
self.rMode = "b"
|
|
||||||
self.sMode = "b"
|
|
||||||
end
|
|
||||||
if fd then
|
|
||||||
client=socket.tcp()
|
|
||||||
client:setfd(fd)
|
|
||||||
_,port = client:getsockname()
|
|
||||||
c.handle = client
|
|
||||||
else
|
|
||||||
error("You need to enter a fd in order to be able to create a tcp client object like this!")
|
|
||||||
end
|
|
||||||
function c:setUpdateRate(n)
|
|
||||||
self.updaterRate=n
|
|
||||||
end
|
|
||||||
function c:setReceiveMode(mode)
|
|
||||||
self.rMode=mode
|
|
||||||
end
|
|
||||||
function c:setSendMode(mode)
|
|
||||||
self.rMode=mode
|
|
||||||
end
|
|
||||||
function c:send(data)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
if self.sMode=="*l" then
|
|
||||||
self.handle:send(data.."\n")
|
|
||||||
elseif self.sMode=="b" then
|
|
||||||
self.handle:send(self:packMsg(data))
|
|
||||||
else
|
|
||||||
self.handle:send(data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
multi:newThread("ServerClientHandler",function()
|
|
||||||
while true do
|
|
||||||
thread.skip(1)
|
|
||||||
local data, err, dat, len
|
|
||||||
if self.rMode == "b" then
|
|
||||||
thread.hold(function()
|
|
||||||
dat = client:receive(self.numspace)
|
|
||||||
return dat
|
|
||||||
end)
|
|
||||||
len = bin.new(dat):getBlock("n",self.numspace)
|
|
||||||
data, err = client:receive(len)
|
|
||||||
else
|
|
||||||
data, err = client:receive(self.rMode)
|
|
||||||
end
|
|
||||||
if err=="closed" then
|
|
||||||
for i=1,#self.ips do
|
|
||||||
if self.ips[i]==client then
|
|
||||||
table.remove(self.ips,i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.OnClientClosed:Fire(self,"Client Closed Connection!",client,client,ip)
|
|
||||||
self.links[client]=nil -- lets clean up
|
|
||||||
self:Destroy()
|
|
||||||
end
|
|
||||||
if data then
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.denormalize(data)
|
|
||||||
end
|
|
||||||
if net.inList(self.bannedIPs,ip) then
|
|
||||||
print("We will ingore data from a banned client!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local hook=data:match("!(.-)!")
|
|
||||||
self.OnDataRecieved:getConnection(hook):Fire(self,data,client,client,ip,self)
|
|
||||||
if data:sub(1,2)=="L!" then
|
|
||||||
cList=data
|
|
||||||
local list={}
|
|
||||||
for m,v in cList:gmatch("(%S-):(%S-)|") do
|
|
||||||
list[m]=v
|
|
||||||
end
|
|
||||||
self.OnClientsModulesList:Fire(list,client,client,ip)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
c.OnClientsModulesList=multi:newConnection()
|
|
||||||
c.OnDataRecieved=multi:newConnection()
|
|
||||||
c.OnClientClosed=multi:newConnection()
|
|
||||||
c.OnClientConnected=multi:newConnection()
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
function net:newTCPServer(port)
|
|
||||||
local c={}
|
|
||||||
local port = port or 0
|
|
||||||
c.tcp=assert(socket.bind("*", port))
|
|
||||||
c.tcp:settimeout(0)
|
|
||||||
c.ip,c.port=c.tcp:getsockname()
|
|
||||||
c.ips={}
|
|
||||||
if port == 0 then
|
|
||||||
_, c.port = c.tcp:getsockname()
|
|
||||||
end
|
|
||||||
c.ids={}
|
|
||||||
c.bannedIPs={}
|
|
||||||
c.Type="tcp"
|
|
||||||
c.rMode="*l"
|
|
||||||
c.sMode="*l"
|
|
||||||
c.updaterRate=1
|
|
||||||
c.autoNormalization=false
|
|
||||||
c.updates={}
|
|
||||||
c.links={}
|
|
||||||
c.numspace = 4
|
|
||||||
c.broad=socket.udp()
|
|
||||||
c.hostip=net.getLocalIP()
|
|
||||||
function c:packMsg(data)
|
|
||||||
local temp = bin.new()
|
|
||||||
temp:addBlock(#data,self.numspace,"n")
|
|
||||||
temp:addBlock(data)
|
|
||||||
return temp:getData()
|
|
||||||
end
|
|
||||||
function c:enableBinaryMode()
|
|
||||||
self.rMode = "b"
|
|
||||||
self.sMode = "b"
|
|
||||||
end
|
|
||||||
function c:broadcast(name)
|
|
||||||
table.insert(net.BroadcastDriver,function(loop,dt)
|
|
||||||
self.broad:setoption('broadcast',true)
|
|
||||||
self.broad:sendto(name.."|"..self.Type.."|"..self.hostip..":"..self.port, "255.255.255.255", 11111)
|
|
||||||
self.broad:setoption('broadcast',false)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
function c:setUpdateRate(n)
|
|
||||||
self.updaterRate=n
|
|
||||||
end
|
|
||||||
function c:setReceiveMode(mode)
|
|
||||||
self.rMode=mode
|
|
||||||
end
|
|
||||||
function c:setSendMode(mode)
|
|
||||||
self.rMode=mode
|
|
||||||
end
|
|
||||||
function c:banCID(cid)
|
|
||||||
print("Function not supported on a tcp server!")
|
|
||||||
end
|
|
||||||
function c:banIP(ip)
|
|
||||||
table.insert(self.bannedIPs,cid)
|
|
||||||
end
|
|
||||||
function c:send(handle,data)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
if self.sMode=="*l" then
|
|
||||||
handle:send(data.."\n")
|
|
||||||
elseif self.sMode=="b" then
|
|
||||||
handle:send(self:packMsg(data))
|
|
||||||
else
|
|
||||||
handle:send(data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:sendAllData(handle,data)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
handle:send(data)
|
|
||||||
end
|
|
||||||
function c:pollClientModules(ip,port)
|
|
||||||
self:send(ip,"L!",port)
|
|
||||||
end
|
|
||||||
function c:CIDFrom(ip,port)
|
|
||||||
print("Method not supported when using a TCP Server!")
|
|
||||||
return "CIDs in TCP work differently!"
|
|
||||||
end
|
|
||||||
function c:sendAll(data)
|
|
||||||
for i,v in pairs(self.ips) do
|
|
||||||
self:send(v,data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:sendAllBut(data,cid)
|
|
||||||
for i,v in pairs(self.ips) do
|
|
||||||
if not(cid==i) then
|
|
||||||
self:send(v,data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:clientRegistered(cid)
|
|
||||||
return self.ips[cid]
|
|
||||||
end
|
|
||||||
function c:clientLoggedIn(cid)
|
|
||||||
return self.ips[cid]
|
|
||||||
end
|
|
||||||
function c:getUpdater(cid)
|
|
||||||
return self.updates[cid]
|
|
||||||
end
|
|
||||||
function c:update()
|
|
||||||
local client = self.tcp:accept(self.rMode)
|
|
||||||
if not client then return end
|
|
||||||
table.insert(self.ips,client)
|
|
||||||
client:settimeout(0)
|
|
||||||
--client:setoption('tcp-nodelay', true)
|
|
||||||
client:setoption('keepalive', true)
|
|
||||||
ip,port=client:getpeername()
|
|
||||||
if ip and port then
|
|
||||||
print("Got connection from: ",ip,port)
|
|
||||||
-- local updater=multi:newUpdater(skip):setName("net.tcpClientObj")
|
|
||||||
-- self.updates[client]=updater
|
|
||||||
self.OnClientConnected:Fire(self,client,client,ip)
|
|
||||||
--updater:OnUpdate(function(self)
|
|
||||||
multi:newThread("ServerClientHandler",function()
|
|
||||||
while true do
|
|
||||||
thread.skip(1)
|
|
||||||
local data, err, dat, len
|
|
||||||
if self.rMode == "b" then
|
|
||||||
thread.hold(function()
|
|
||||||
dat = client:receive(self.numspace)
|
|
||||||
return dat
|
|
||||||
end)
|
|
||||||
len = bin.new(dat):getBlock("n",self.numspace)
|
|
||||||
data, err = client:receive(len)
|
|
||||||
else
|
|
||||||
data, err = client:receive(self.rMode)
|
|
||||||
end
|
|
||||||
if err=="closed" then
|
|
||||||
for i=1,#self.ips do
|
|
||||||
if self.ips[i]==client then
|
|
||||||
table.remove(self.ips,i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.OnClientClosed:Fire(self,"Client Closed Connection!",client,client,ip)
|
|
||||||
self.links[client]=nil -- lets clean up
|
|
||||||
self:Destroy()
|
|
||||||
thread.kill()
|
|
||||||
end
|
|
||||||
if data then
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.denormalize(data)
|
|
||||||
end
|
|
||||||
if net.inList(self.bannedIPs,ip) then
|
|
||||||
print("We will ingore data from a banned client!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local hook=data:match("!(.-)!")
|
|
||||||
self.OnDataRecieved:getConnection(hook):Fire(self,data,client,client,ip,self)
|
|
||||||
if data:sub(1,2)=="L!" then
|
|
||||||
cList=data
|
|
||||||
local list={}
|
|
||||||
for m,v in cList:gmatch("(%S-):(%S-)|") do
|
|
||||||
list[m]=v
|
|
||||||
end
|
|
||||||
self.OnClientsModulesList:Fire(list,client,client,ip)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
-- updater:SetSkip(self.updaterRate)
|
|
||||||
-- updater.client=client
|
|
||||||
-- updater.Link=self
|
|
||||||
-- function updater:setReceiveMode(mode)
|
|
||||||
-- self.rMode=mode
|
|
||||||
-- end
|
|
||||||
-- self.links[client]=updater
|
|
||||||
end
|
|
||||||
end
|
|
||||||
c.OnClientsModulesList=multi:newConnection()
|
|
||||||
c.OnDataRecieved=multi:newConnection()
|
|
||||||
c.OnClientClosed=multi:newConnection()
|
|
||||||
c.OnClientConnected=multi:newConnection()
|
|
||||||
table.insert(net.ConnectionDriver,c)
|
|
||||||
net.OnServerCreated:Fire(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
function net:newTCPClient(host,port)
|
|
||||||
local c={}
|
|
||||||
c.ip=assert(socket.dns.toip(host))
|
|
||||||
c.tcp=socket.connect(c.ip,port)
|
|
||||||
if not c.tcp then
|
|
||||||
print("Can't connect to the server: no response from server")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
c.tcp:settimeout(0)
|
|
||||||
--c.tcp:setoption('tcp-nodelay', true)
|
|
||||||
c.tcp:setoption('keepalive', true)
|
|
||||||
c.Type="tcp"
|
|
||||||
c.autoReconnect=true
|
|
||||||
c.rMode="*l"
|
|
||||||
c.sMode="*l"
|
|
||||||
c.autoNormalization=false
|
|
||||||
c.numspace = 4
|
|
||||||
function c:enableBinaryMode()
|
|
||||||
self.rMode = "b"
|
|
||||||
self.sMode = "b"
|
|
||||||
end
|
|
||||||
function c:setReceiveMode(mode)
|
|
||||||
self.rMode=mode
|
|
||||||
end
|
|
||||||
function c:setSendMode(mode)
|
|
||||||
self.sMode=mode
|
|
||||||
end
|
|
||||||
function c:packMsg(data)
|
|
||||||
local temp = bin.new()
|
|
||||||
temp:addBlock(#data,self.numspace)
|
|
||||||
temp:addBlock(data)
|
|
||||||
return temp:getData()
|
|
||||||
end
|
|
||||||
function c:send(data)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
if self.sMode=="*l" then
|
|
||||||
ind,err=self.tcp:send(data.."\n")
|
|
||||||
elseif self.sMode=="b" then
|
|
||||||
ind,err=self.tcp:send(self:packMsg(data))
|
|
||||||
else
|
|
||||||
ind,err=self.tcp:send(data)
|
|
||||||
end
|
|
||||||
if err=="closed" then
|
|
||||||
self.OnClientDisconnected:Fire(self,err)
|
|
||||||
elseif err=="timeout" then
|
|
||||||
self.OnClientDisconnected:Fire(self,err)
|
|
||||||
elseif err then
|
|
||||||
print(err)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:sendRaw(data)
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.normalize(data)
|
|
||||||
end
|
|
||||||
self.tcp:send(data)
|
|
||||||
end
|
|
||||||
function c:getCID()
|
|
||||||
return "No Cid on a tcp client!"
|
|
||||||
end
|
|
||||||
function c:close()
|
|
||||||
self.tcp:close()
|
|
||||||
end
|
|
||||||
function c:IDAssigned()
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
function c:update()
|
|
||||||
if not self.tcp then return end
|
|
||||||
local data,err,dat
|
|
||||||
if self.rMode == "b" then
|
|
||||||
thread.hold(function()
|
|
||||||
dat = self.tcp:receive(self.numspace)
|
|
||||||
return dat
|
|
||||||
end)
|
|
||||||
len = bin.new(dat):getBlock("n",self.numspace)
|
|
||||||
data, err = self.tcp:receive(len)
|
|
||||||
else
|
|
||||||
data,err = self.tcp:receive()
|
|
||||||
end
|
|
||||||
if err=="closed" then
|
|
||||||
self.OnClientDisconnected:Fire(self,err)
|
|
||||||
elseif err=="timeout" then
|
|
||||||
self.OnClientDisconnected:Fire(self,err)
|
|
||||||
elseif err then
|
|
||||||
print(err)
|
|
||||||
end
|
|
||||||
if data then
|
|
||||||
if self.autoNormalization then
|
|
||||||
data=net.denormalize(data)
|
|
||||||
end
|
|
||||||
local hook=data:match("!(.-)!")
|
|
||||||
self.OnDataRecieved:getConnection(hook):Fire(self,data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function c:reconnect()
|
|
||||||
multi:newFunction(function(func)
|
|
||||||
self.tcp=socket.connect(self.ip,self.port)
|
|
||||||
if self.tcp==nil then
|
|
||||||
print("Can't connect to the server: No response from server!")
|
|
||||||
multi:newAlarm(3):OnRing(function(alarm)
|
|
||||||
self:reconnect()
|
|
||||||
alarm:Destroy()
|
|
||||||
return
|
|
||||||
end):setName("net.timeoutTask")
|
|
||||||
end
|
|
||||||
self.OnConnectionRegained:Fire(self)
|
|
||||||
self.tcp:settimeout(0)
|
|
||||||
--self.tcp:setoption('tcp-nodelay', true)
|
|
||||||
self.tcp:setoption('keepalive', true)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
c.event=multi:newEvent(function(event)
|
|
||||||
return event.link:IDAssigned()
|
|
||||||
end):OnEvent(function(event)
|
|
||||||
event.link.OnClientReady:Fire(event.link)
|
|
||||||
event:Destroy()
|
|
||||||
end)
|
|
||||||
c.event:setName("net.handshakeTask")
|
|
||||||
c.event.link=c
|
|
||||||
c.OnClientReady=multi:newConnection()
|
|
||||||
c.OnClientDisconnected=multi:newConnection()
|
|
||||||
c.OnDataRecieved=multi:newConnection()
|
|
||||||
c.OnConnectionRegained=multi:newConnection()
|
|
||||||
table.insert(net.ConnectionDriver,c)
|
|
||||||
net.OnClientCreated:Fire(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
net.timer = multi:newTimer():Start()
|
|
||||||
multi:newThread("ClientServerHandler",function()
|
|
||||||
while true do
|
|
||||||
thread.skip()
|
|
||||||
for i=1,#net.ConnectionDriver do
|
|
||||||
thread.skip()
|
|
||||||
net.ConnectionDriver[i]:update()
|
|
||||||
end
|
|
||||||
if net.timer:Get()>=1 then
|
|
||||||
for i=1,#net.BroadcastDriver do
|
|
||||||
net.BroadcastDriver[i]()
|
|
||||||
end
|
|
||||||
net.timer:Reset()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
return net
|
|
||||||
@ -18,7 +18,7 @@ net.OnServerCreated:connect(function(s)
|
|||||||
local cmd,arg1,arg2=data:match("!version! ")
|
local cmd,arg1,arg2=data:match("!version! ")
|
||||||
end,"version")
|
end,"version")
|
||||||
s.OnClientConnected(function(self,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP)
|
s.OnClientConnected(function(self,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP)
|
||||||
multi:newFunction(function(func) -- anom func, allows for fancy multitasking
|
multi:newFunction(function(func) -- anon func, allows for fancy multitasking
|
||||||
multi:newFunction(function(self)
|
multi:newFunction(function(self)
|
||||||
local range=self:newRange()
|
local range=self:newRange()
|
||||||
for i in range(1,#self.loadedModules) do
|
for i in range(1,#self.loadedModules) do
|
||||||
|
|||||||
32
rockspec/lnet-5.0-0.rockspec
Normal file
32
rockspec/lnet-5.0-0.rockspec
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package = "llnet"
|
||||||
|
version = "5.0-0"
|
||||||
|
source = {
|
||||||
|
url = "git://github.com/rayaman/lnet.git",
|
||||||
|
tag = "lnet-v5",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "Lua lnetworking library that wraps around lua-socket to make lnetworking easy.",
|
||||||
|
detailed = [[
|
||||||
|
This library uses the multi library. The new multitasking library and this one are now co-Dependant if using the lnetworkManager integration for lnetwork parallelism. This has an event driven approach for lnetworking which allows one to easily work async with the data.
|
||||||
|
]],
|
||||||
|
homepage = "https://github.com/rayaman/lnet",
|
||||||
|
license = "MIT"
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"luasocket",
|
||||||
|
"luasec",
|
||||||
|
"multi",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = {
|
||||||
|
["lnet.init"] = "lnet/init.lua",
|
||||||
|
["lnet.tcp.init"] = "lnet/tcp/init.lua",
|
||||||
|
["lnet.udp.init"] = "lnet/udp/init.lua",
|
||||||
|
["lnet.base.client"] = "lnet/base/client.lua",
|
||||||
|
["lnet.base.server"] = "lnet/base/server.lua",
|
||||||
|
["lnet.http"] = "lnet/http.lua",
|
||||||
|
["lnet.https"] = "lnet/https.lua"
|
||||||
|
}
|
||||||
|
}
|
||||||
27
server.lua
27
server.lua
@ -1,20 +1,11 @@
|
|||||||
package.path="?/init.lua;"..package.path
|
package.path = "./?/init.lua;./?.lua;"..package.path
|
||||||
local multi = require("multi")
|
local net = require("lnet.tcp")
|
||||||
local net = require("net")
|
local multi, thread = require("multi"):init()
|
||||||
local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
|
server = net.newTCPServer(12345)
|
||||||
server = net:newTCPServer(12345)
|
server:broadcast("Test")
|
||||||
server:enableBinaryMode()
|
print("Server has been broadcasted!")
|
||||||
print("Server hosted on "..net.getExternalIP().." listening on port: 12345")
|
server.OnDataRecieved(function(serv, data,cid)
|
||||||
server.OnDataRecieved(function(self,data,cid,ip,port)
|
print("Response: ",data)
|
||||||
print(data)
|
server:send(cid,"Hello!")
|
||||||
local file = bin.load("test.mp3")
|
|
||||||
local dat = file:read(1024)
|
|
||||||
while dat do
|
|
||||||
thread.sleep(.002)
|
|
||||||
self:send(ip,dat,port,cid)
|
|
||||||
dat = file:read(1024)
|
|
||||||
end
|
|
||||||
self:send(ip,dat or "",port,cid)
|
|
||||||
self:send(ip,"END",port,cid)
|
|
||||||
end)
|
end)
|
||||||
multi:mainloop()
|
multi:mainloop()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user