From b28c1b2f24cfd1b7e4be8b6683e50a1c22464bbb Mon Sep 17 00:00:00 2001 From: Ryan Date: Thu, 15 Jun 2017 21:47:26 -0400 Subject: [PATCH] Updated to 2.0.0 Adds the feature of broadcasting a server locally on your network --- net/aft.lua | 155 +++++++++++++++++++++++++++++++++++++---------- net/chatting.lua | 1 - net/email.lua | 3 +- net/identity.lua | 73 +++++++++++++++------- net/inbox.lua | 53 +++++++++++++++- net/init.lua | 138 +++++++++++++++++++++++++++++++++-------- net/logging.lua | 2 +- net/settings.lua | 8 +-- net/version.lua | 38 ++++++++++-- 9 files changed, 377 insertions(+), 94 deletions(-) diff --git a/net/aft.lua b/net/aft.lua index c99636a..0ce6c59 100644 --- a/net/aft.lua +++ b/net/aft.lua @@ -45,7 +45,7 @@ function net.aft:init() -- calling this initilizes the library and binds it to t s.cachable=10 -- 10 MBs s.OnDataRecieved(function(self,data,cid,ip,port) -- when the server recieves data this method is triggered local cmd,arg1,arg2=data:match("!aft! (%S+) (%S+) (%S+)") ---~ print(cmd,arg1,arg2) + --print(cmd,arg1,arg2) if cmd=="PIECE" then local FID,piecenum=arg1,tonumber(arg2) local pp=piecenum-1 @@ -67,18 +67,21 @@ function net.aft:init() -- calling this initilizes the library and binds it to t end end end + local ddata local unpackedDATA=net.aft.transfers[cid][FID].sink:sub((pp*net.aft.pieceSize)+1,(pp+1)*net.aft.pieceSize) - local unpackedDATA1=unpackedDATA:sub(1,384) - local unpackedDATA2=unpackedDATA:sub(385) - local packedDATA="" ---~ if self.autoNormalization==false then -- if we already handled normalization in the main data packet then don't redo - packedDATA=net.normalize(unpackedDATA1)..net.normalize(unpackedDATA2) ---~ end - local hash=""--string.rep("0",64)--bin.new(unpackedDATA):getHash2(64) + local num=#unpackedDATA + if num<384 then + ddata="!aft! TRANS "..piecenum.." "..FID.." | "..net.normalize(unpackedDATA) + else + local unpackedDATA1=unpackedDATA:sub(1,384) + local unpackedDATA2=unpackedDATA:sub(385) + local packedDATA=net.normalize(unpackedDATA1)..net.normalize(unpackedDATA2) + ddata="!aft! TRANS "..piecenum.." "..FID.." | "..packedDATA + end net.aft.transfers[cid][FID].resendAlarm.piecenum=piecenum - net.aft.transfers[cid][FID].resendAlarm.hash=hash + net.aft.transfers[cid][FID].resendAlarm.hash="" -- not needed anymore net.aft.transfers[cid][FID].resendAlarm.packedDATA=packedDATA - local ddata="!aft! TRANS "..piecenum.." "..FID.." | "..packedDATA + -- SAFE if self.allowSmallFileCaching then net.aft.cache[net.aft.transfers[cid][FID].name][piecenum]=ddata end @@ -88,6 +91,55 @@ function net.aft:init() -- calling this initilizes the library and binds it to t self:send(ip,"!aft! DOWNLOAD INVALID_FID NIL NIL NIL",port) print("ERROR 102") end + elseif cmd=="UPLOAD" then -- here we set up the spot for file writing + local FID,filename=arg1:match("(.-)|(.+)") + local struct={ + FID=FID, + filename=filename, + numpieces=tonumber(arg2) or -1 + } + if struct.numpieces==-1 then -- error handling catch it all :) + self:send(ip,"!aft! UPLOAD UPLOAD_REFUSED INVALID_NUMBER_OF_PIECES | |",port) + return + end + self.OnUploadRequest:Fire(struct,cid,ip,port) + if not(struct.deny) then -- block request or allow it + -- If we are allowed to lets do this + if not(net.aft.transfers.DOWNLOADS) then + net.aft.transfers.DOWNLOADS={} + end + if not(net.aft.transfers.DOWNLOADS[FID]) then + net.aft.transfers.DOWNLOADS[FID]={} + end + bin.new(""):tofile(struct.filename) + net.aft.transfers.DOWNLOADS[struct.FID].sink=struct.sink or bin.stream(struct.filename,false) + net.aft.transfers.DOWNLOADS[struct.FID].currentPiece=1 + net.aft.transfers.DOWNLOADS[struct.FID].numPieces=tonumber(arg2) + --we got that setup... Lets Request a piece now! + self:send(ip,"!aft! PIECE 1 "..FID.." | |",port) -- request piece # 1 + else + self:send(ip,"!aft! UPLOAD UPLOAD_REFUSED "..(struct.reason or "UNSPECIFIED_ERROR").." | |",port) + end + elseif cmd=="TRANS" then + local FID,piece=arg1:match("(.-)|(.+)") + local piece=tonumber(piece) or -1 + if pieces==-1 then -- error handling catch it all :) + self:send(ip,"!aft! UPLOAD UPLOAD_CANCLED PIECE_DATA_MALFORMED | |",port) + return + end + if #arg2<512 then + net.aft.transfers.DOWNLOADS[FID].sink:tackE(net.denormalize(arg2)) + else + net.aft.transfers.DOWNLOADS[FID].sink:tackE(net.denormalize(arg2:sub(1,512))..net.denormalize(arg2:sub(513))) + end + -- request the next piece + if piece==net.aft.transfers.DOWNLOADS[FID].numPieces then + -- We are done! + self:send(ip,"!aft! DONE "..FID.." | | |",port) + net.aft.transfers.DOWNLOADS[FID].sink:close() -- close the file + else + self:send(ip,"!aft! PIECE "..piece+1 .." "..FID.." | |",port) + end elseif cmd=="REQUEST" then local filename=arg1 local struct={ @@ -139,10 +191,10 @@ function net.aft:init() -- calling this initilizes the library and binds it to t c.OnTransferStarted=multi:newConnection() c.OnTransferCompleted=multi:newConnection() c.OnFileRequestFailed=multi:newConnection() -- create an aft event - --c.OnFileUploadFailed=multi:newConnection() -- not yet must ensure oneway works well first + c.OnFileUploadFailed=multi:newConnection() -- not yet must ensure oneway works well first c.OnDataRecieved(function(self,data) -- when the client recieves data this method is triggered local cmd,pieces,FID,arg1,arg2=data:match("!aft! (%S+) (%S+) (%S+) (%S+) (%S+)") ---~ print(cmd,pieces,FID,arg1,arg2) + --print(cmd,pieces,FID,arg1,arg2) if cmd=="START" then-- FID filename #pieces local struct={ FID=FID, @@ -171,10 +223,34 @@ function net.aft:init() -- calling this initilizes the library and binds it to t net.aft.transfers[FID].piecesRecieved=0 net.aft.transfers[FID].numpieces=tonumber(pieces) c:requestPiece(FID,1) + elseif cmd=="DONE" then + local FID=pieces + print(net.aft.transfers.UPLOADS[FID].name.." has Finished Uploading!") + self.OnTransferCompleted:Fire(self,net.aft.transfers[FID].name,"U") + net.aft.transfers[FID]=nil -- clean up + elseif cmd=="PIECE" then -- Server is asking for a piece to some file + local pieces=tonumber(pieces) + local pp=pieces-1 + local unpackedDATA=net.aft.transfers.UPLOADS[FID].sink:sub((pp*net.aft.pieceSize)+1,(pp+1)*net.aft.pieceSize) + local num=#unpackedDATA + if num<384 then + self:send("!aft! TRANS "..FID.."|"..pieces.." "..net.normalize(unpackedDATA)) + else + local unpackedDATA1=unpackedDATA:sub(1,384) + local unpackedDATA2=unpackedDATA:sub(385) + local packedDATA=net.normalize(unpackedDATA1)..net.normalize(unpackedDATA2) + self:send("!aft! TRANS "..FID.."|"..pieces.." "..packedDATA) + end elseif cmd=="TRANS" then-- self,data,FID,piecenum,hash if self.autoNormalization==false then -- if we already handled normalization in the main data packet then don't redo + local ddata + if #arg2<512 then + ddata=net.denormalize(arg2) + else + ddata=net.denormalize(arg2:sub(1,512))..net.denormalize(arg2:sub(513)) + end struct={ - data=net.denormalize(arg2:sub(1,512))..net.denormalize(arg2:sub(513)), + data=ddata, FID=FID, piecenum=tonumber(pieces), numpieces=net.aft.transfers[FID].numpieces, @@ -194,28 +270,24 @@ function net.aft:init() -- calling this initilizes the library and binds it to t net.aft.transfers[FID].currentPiece=tonumber(pieces) self.OnPieceRecieved:Fire(self,struct) local data,FID,piecenum,hash=struct.data,struct.FID,struct.piecenum,struct.hash - if --[[bin.new(data):getHash2(64)==hash]] true then - net.aft.transfers[FID].sink:tackE(data) - net.aft.transfers[FID].piecesRecieved=net.aft.transfers[FID].piecesRecieved+1 - if net.aft.transfers[FID].numpieces<=net.aft.transfers[FID].piecesRecieved then - print(net.aft.transfers[FID].name.." has finished downloading!") - net.aft.transfers[FID].sink:close() - self:send("!aft! COMPLETE "..FID.." NIL") -- for clean up purposes - self.OnTransferCompleted:Fire(self,net.aft.transfers[FID].name) - else - self:requestPiece(FID,piecenum+1) -- get next piece - end + net.aft.transfers[FID].sink:tackE(data) + net.aft.transfers[FID].piecesRecieved=net.aft.transfers[FID].piecesRecieved+1 + if net.aft.transfers[FID].numpieces==net.aft.transfers[FID].piecesRecieved then + print(net.aft.transfers[FID].name.." has finished downloading!") + net.aft.transfers[FID].sink:close() + self:send("!aft! COMPLETE "..FID.." NIL") -- for clean up purposes + self.OnTransferCompleted:Fire(self,net.aft.transfers[FID].name) else - print("Hash Bad! Requesting Again!") - self:requestPiece(FID,piecenum) + self:requestPiece(FID,piecenum+1) -- get next piece end - elseif cmd=="ERROR" then + elseif cmd=="DOWNLOAD" then local msg=FID - if pieces=="DOWNLOAD" then - print("Download Error!",msg) - else - print("UPLOAD Error!",msg) - end + self.OnFileRequestFailed:Fire(msg) + print("Download Error!",msg) + elseif cmd=="UPLOAD" then + local msg=FID + self.OnFileUploadFailed:Fire(msg) + print("Upload Error!",msg) end end,"aft") function c:requestFile(filename,sink) -- sinks data through a bin-stream sink if the filename you want otherwise the filename is used instead @@ -224,6 +296,25 @@ function net.aft:init() -- calling this initilizes the library and binds it to t net.aft.sinks[filename]=sink end end + function c:requestUpload(filename) + if io.fileExists(filename) then + local FID=bin.new(filename):getRandomHash(16) -- We need this, but its not as important for client as it is for servers + local file=bin.stream(filename) + if not net.aft.transfers.UPLOADS then + net.aft.transfers.UPLOADS={} + end + if not net.aft.transfers.UPLOADS[FID] then + net.aft.transfers.UPLOADS[FID]={} + end + net.aft.transfers.UPLOADS[FID].sink=file -- client file management is much simpler since we only have to worry about 1 reciever/sender + net.aft.transfers.UPLOADS[FID].name=filename + net.aft.transfers.UPLOADS[FID].size=file:getSize() + net.aft.transfers.UPLOADS[FID].pieces=math.ceil(net.aft.transfers.UPLOADS[FID].size/net.aft.pieceSize) + self:send("!aft! UPLOAD "..FID.."|"..filename.." "..net.aft.transfers.UPLOADS[FID].pieces)-- Lets send the FID we will be using and the number of pieces the server should look out for + else + self.OnFileUploadFailed:Fire("File specified not found! "..filename.." does not exist!") + end + end function c:requestPiece(FID,piecenum) self:send("!aft! PIECE "..FID.." "..piecenum) end diff --git a/net/chatting.lua b/net/chatting.lua index eb1e8ef..b2ab8d5 100644 --- a/net/chatting.lua +++ b/net/chatting.lua @@ -20,7 +20,6 @@ function net.chatting:init() -- calling this initilizes the library and binds it s.OnUserLoggedIn(function(user,cid,ip,port,dTable) dTable=loadstring("return "..dTable)() local USERID=bin.new(user):getHash(32) - print(USERID) net.chatting.users[USERID]={dTable.nick,cid,ip,port,dTable} -- add users that log in to the userlist net.chatting.users[ip]=USERID -- add users that log in to the userlist local users={} diff --git a/net/email.lua b/net/email.lua index dbea43a..1f46368 100644 --- a/net/email.lua +++ b/net/email.lua @@ -1,7 +1,8 @@ require("net.identity") net:registerModule("email",{1,0,0}) +-- needs rewriting, where it uses the identity module and can send an email. EX: server:email(user,subject,body) smtp = require 'socket.smtp' -ssl = require 'ssl' +ssl = require 'ssl' -- server side only so noworries for love2d users function net.email.init(from,user,pass) net.OnServerCreated:connect(function(s) diff --git a/net/identity.lua b/net/identity.lua index 85f37f3..c16aa43 100644 --- a/net/identity.lua +++ b/net/identity.lua @@ -5,12 +5,13 @@ Adds net.identity:init() ]] -net:registerModule("identity",{2,0,1})--1.0.1 Note: Added eaiser ways to get user data using only cid +net:registerModule("identity",{2,1,0})--1.0.1 Note: Added eaiser ways to get user data using only cid function net.hash(text,n) n=n or 16 return bin.new(text.."jgmhktyf"):getHash(n) end net.identity.UIDS={} +net.identity.UIDS.ids={} function net.identity:init() -- calling this initilizes the library and binds it to the servers and clients created --Server Stuff net.OnServerCreated(function(s) @@ -24,27 +25,43 @@ function net.identity:init() -- calling this initilizes the library and binds it local nick,dTable=userdata:match("%S-|%S-|(%S-)|(.+)") return nick,loadstring("return "..(dTable or "{}"))() end + function s:modifyUserData(user,oldpass,pass,nick,dTable) + if self:_isRegistered(user) then + local userdata=bin.load(self.userFolder..net.hash(user)..".dat") + local args={} + local _pass,_nick,_dTable=userdata:match("%S-|(%S-)|(%S-)|(.+)") + if oldpass~=_pass then + args.invalidPass=true + pass=_pass + end + if not nick then nick=_nick args.invalidNick=true end + table.merge(_dTable or {}, dTable or {}) + bin.new(string.format("%s|%s|%s|%s\n",user,pass,nick,dTable)):tofile(self.userFolder..net.hash(user)..".dat") + else + return false + end + end function s:getUserCred(user) local userdata=bin.load(self.userFolder..net.hash(user)..".dat") return userdata:match("%S-|(%S-)|") end - function s:getUSERID(cid) -- Quality of life functions + function s:getUSERID(cid) return (net.identity.UIDS[cid] or "User Not Logged In!") end - function s:getUsername(cid) -- Quality of life functions + function s:getUsername(cid) return self:userLoggedIn(cid) end - function s:getNickname(cid) -- Quality of life functions + function s:getNickname(cid) return self.loggedIn[self:getUsername(cid)].nick end - function s:getdTable(cid) -- Quality of life functions + function s:getdTable(cid) return self.loggedIn[self:getUsername(cid)] end - function s:getUserData(cid) -- Quality of life functions + function s:getUserDat(cid) return self:getUserDataHandle(self:getUsername(cid)) end - function s:nickTaken(nick) - -- + function s:getNickFromUSERID(USERID) + return bin.load(self.userFolder..net.hash(user)..".dat"):match("%S-|%S-|(%S-)|") end function s:userLoggedIn(cid) for i,v in pairs(self.loggedIn) do @@ -60,20 +77,20 @@ function net.identity:init() -- calling this initilizes the library and binds it end self.userFolder=loc end - s:setDataLocation("USERS") + s:setDataLocation("USERS/") function s:logoutUser(user) net.identity.UIDS.ids[user.UID]=nil self.loggedIn[user]=nil end function s:loginUser(user,cid) - net.identity.UIDS[cid]=bin.new(user):getHash(32) + net.identity.UIDS[cid]=net.hash(user) local nick,dTable=self:getUserData(user) self.loggedIn[user]={} table.merge(self.loggedIn[user],dTable or {}) self.loggedIn[user].cid=cid self.loggedIn[user].nick=nick self.loggedIn[user].UID=net.resolveID(net.identity.UIDS) - return self:getUserDataHandle(user) + return self.loggedIn[user] end function s:getUserDataHandle(user) return self.loggedIn[user] @@ -110,10 +127,6 @@ function net.identity:init() -- calling this initilizes the library and binds it self:send(ip,"!identity! REGISTERREFUSED <-|Nickname too short|->",port) return end - if not self.allowDuplicateNicks and self:nickTaken(nick) then - self:send(ip,"!identity! REGISTERREFUSED <-|Nickname already taken|->",port) - return - end for i=1,#rets do if rets[i][1]==false then print("Server refused to accept registration request!") @@ -121,14 +134,29 @@ function net.identity:init() -- calling this initilizes the library and binds it return end end - bin.new(string.format("%s|%s|%s|%s\n",user,pass,nick,dTable)):tofile(self.userFolder..net.hash(user)..".dat") - self:send(ip,"!identity! REGISTEREDGOOD <-|"..user.."|->",port) - if not allowDuplicateNicks then - if not self.dupnickfilemanager then - self.dupnickfilemanager=bin.stream("Nicks.dat",false) + multi:newFunction(function(func) -- anom func, allows for fancy multitasking + local dupnickfilemanager=bin.stream(self.userFolder.."Nicks.dat",false) + local isValid=func:newCondition(function() return t~=nil end) + local tab={} + local t=dupnickfilemanager:getBlock("s") + if self.allowDuplicateNicks==false then + while func:condition(isValid) do + tab[#tab]=t + if t==nick then + self:send(ip,"!identity! REGISTERREFUSED <-|Duplicate Nicks are not allowed|->",port) + dupnickfilemanager:close() + return + end + end + t=dupnickfilemanager:getBlock("s") end - self.dupnickfilemanager:addBlock(nick) - end + dupnickfilemanager:addBlock(nick.."|"..bin.new(user):getHash(32)) + dupnickfilemanager:close() + bin.new(string.format("%s|%s|%s|%s\n",user,pass,nick,dTable)):tofile(self.userFolder..net.hash(user)..".dat") + self:send(ip,"!identity! REGISTEREDGOOD <-|"..user.."|->",port) + func=nil -- we dont want 1000s+ of these anom functions lying around + return + end)()-- lets call the function end return elseif cmd=="login" then @@ -138,7 +166,6 @@ function net.identity:init() -- calling this initilizes the library and binds it self:send(ip,"!identity! LOGINBAD <-|nil|->",port) return end - print(pass,_pass) if pass==_pass then if self:userLoggedIn(cid) then self.OnAlreadyLoggedIn:Fire(self,user,cid,ip,port) diff --git a/net/inbox.lua b/net/inbox.lua index 70aba82..d76f37c 100644 --- a/net/inbox.lua +++ b/net/inbox.lua @@ -1,12 +1,47 @@ require("net.identity") +require("net.aft") +require("net.users") +require("net.db") net:registerModule("inbox",{1,0,0}) --self.OnUserLoggedIn:Fire(user,cid,ip,port,bin.ToStr(handle)) --allows the storing of messages that the user can recieve and view whenever. Allows user to also send messeges to users that are even offline! --requires an account setup and nick name to be set at account creation +if not io.dirExists("INBOX") then + io.mkDir("INBOX") +end +net.inbox.dbfmt=db.format([=[ +[INBOX]{ + string MSG 0x800 -- contents of the message +} +[MAIL]{ + string NAME 0x20 -- username + string UID 0x10 -- User ID + string NICK 0x20 -- Nickname + number[3] DATE -- list of numbers + table INBO INBOX -- Inbox +} +]=]) net.OnServerCreated:connect(function(s) + s.OnUserLoggedIn(function(user,cid,ip,port,dTable) + if not io.dirExists("INBOX/"..self:getUSERID(cid)) then -- Make sure inbox stuff is set up + io.mkDir("INBOX/"..self:getUSERID(cid)) + bin.new():tofile("info.dat") + end + end) s.OnDataRecieved(function(self,data,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP) if self:userLoggedIn(cid) then -- If the user is logged in we do the tests - -- + local cmd,arg1,arg2=data:match("!inbox! (%S+) (%S+) (%S+)") + if cmd=="SEND" then + -- + elseif cmd=="LIST" then + -- + elseif cmd=="OPEN" then + -- + elseif cmd=="DELETE" then + -- + elseif cmd=="CLEAR" then + -- + end else return end @@ -16,4 +51,20 @@ net.OnClientCreated:connect(function(c) c.OnDataRecieved(function(self,data) -- end,"inbox") + function c:sendMessage(USERID,msg) -- USERID who, msg being sent. Server handles time stamps + self:send("!inbox! SEND "..USERID.." "..msg) + end + function c:checkInbox() -- returns list of msgIDs + self:send("!inbox! LIST NIL NIL") + end + function c:checkMsg(msgId) + self:send("!inbox! OPEN "..msgId.." NIL") -- server sends back msg content as a file + end + function c:deleteMessage(msgID) + self:send("!inbox! DELETE "..msgId.." NIL") + end + function c:clearInbox() + self:send("!inbox! CLEAR NIL NIL") + end + -- end) diff --git a/net/init.lua b/net/init.lua index eb77472..21f3db9 100644 --- a/net/init.lua +++ b/net/init.lua @@ -1,12 +1,38 @@ +--[[ + 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) + 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 socket=require("socket") +http=require("socket.http") mime=require("mime") net={} -net.Version={1,5,0} -net._VERSION="1.5.0" +net.Version={2,0,0} -- This will probably stay this version for quite a while... The modules on the otherhand will be more inconsistant +net._VERSION="2.0.0" net.OnServerCreated=multi:newConnection() net.OnClientCreated=multi:newConnection() net.loadedModules={} @@ -19,6 +45,19 @@ 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.org/") + return data:match("600;\">(%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!") @@ -60,6 +99,30 @@ 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 + 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 -- UDP Stuff function net:newServer(port,servercode) local c={} @@ -83,6 +146,15 @@ function net:newServer(port,servercode) function c:banIP(ip) table.insert(self.bannedIPs,cid) end + c.broad=socket.udp() + c.hostip=net.getLocalIP() + function c:broadcast(name) + local loop=multi:newTLoop(function(dt,loop) + 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,1) + end function c:send(ip,data,port,cid) if self.autoNormalization then data=net.normalize(data) @@ -154,7 +226,7 @@ function net:newServer(port,servercode) data=net.denormalize(data) end if data:sub(1,4)=="pong" then - print("Recieved pong from: "..data:sub(5,-1)) + --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) @@ -177,8 +249,8 @@ function net:newServer(port,servercode) self.udp:sendto("Make sure your server code is correct!", ip, port) end elseif data:sub(1,2)=="C!" then - local hook=data:match("!(.-)!") - self.OnDataRecieved:getConnection(hook):Fire(hook,data:sub(11,-1),data:sub(3,10),ip,port) + 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 @@ -216,7 +288,7 @@ function net:newServer(port,servercode) c.connectiontest=multi:newAlarm(30) c.connectiontest.link=c c.connectiontest:OnRing(function(alarm) - print("pinging clients!") + --print("pinging clients!") alarm.link:sendAll("ping") alarm:Reset() end) @@ -231,8 +303,8 @@ function net:newClient(host,port,servercode,nonluaServer) local c={} c.ip=assert(socket.dns.toip(host)) c.udp=assert(socket.udp()) - c.udp:setpeername(c.ip, port) c.udp:settimeout(0) + c.udp:setpeername(c.ip, port) c.cid="NIL" c.lastPing=0 c.Type="udp" @@ -352,6 +424,16 @@ function net:newTCPServer(port) c.updaterRate=1 c.autoNormalization=false c.updates={} + c.links={} + c.broad=socket.udp() + c.hostip=net.getLocalIP() + function c:broadcast(name) + local loop=multi:newTLoop(function(dt,loop) + 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,1) + end function c:setUpdateRate(n) self.updaterRate=n end @@ -377,6 +459,12 @@ function net:newTCPServer(port) 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 @@ -427,6 +515,7 @@ function net:newTCPServer(port) end end self.Link.OnClientClosed:Fire(self.Link,"Client Closed Connection!",self.client,self.client,ip) + self.Link.links[self.client]=nil -- lets clean up self:Destroy() end if data then @@ -438,7 +527,7 @@ function net:newTCPServer(port) return end local hook=data:match("!(.-)!") - self.Link.OnDataRecieved:getConnection(hook):Fire(self.Link,data,self.client,self.client,ip) + self.Link.OnDataRecieved:getConnection(hook):Fire(self.Link,data,self.client,self.client,ip,self) if data:sub(1,2)=="L!" then cList=data local list={} @@ -455,6 +544,7 @@ function net:newTCPServer(port) function updater:setReceiveMode(mode) self.rMode=mode end + self.links[client]=updater end end c.OnClientsModulesList=multi:newConnection() @@ -491,7 +581,6 @@ function net:newTCPClient(host,port) self.sMode=mode end function c:send(data) - if not self.tcp then return end if self.autoNormalization then data=net.normalize(data) end @@ -509,7 +598,6 @@ function net:newTCPClient(host,port) end end function c:sendRaw(data) - if not self.tcp then return end if self.autoNormalization then data=net.normalize(data) end @@ -542,21 +630,21 @@ function net:newTCPClient(host,port) self.OnDataRecieved:getConnection(hook):Fire(self,data) end end - c.reconnect=multi:newFunction(function(func,self) - self.tcp=socket.connect(self.ip,self.port) - if self.tcp==nil then - print("Can't connect to the server: No response from server!") - func:hold(3) - self:reconnect() - func=nil - return - end - self.OnConnectionRegained:Fire(self) - self.tcp:settimeout(0) - --self.tcp:setoption('tcp-nodelay', true) - self.tcp:setoption('keepalive', true) - func=nil - 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!") + func:hold(3) + self:reconnect() + return + 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) diff --git a/net/logging.lua b/net/logging.lua index bd05eb0..be82728 100644 --- a/net/logging.lua +++ b/net/logging.lua @@ -1,6 +1,6 @@ net.OnServerCreated:connect(function(s) print("The logging Module has been loaded onto the server!") - s.OnDataRecieved:connect(function(self,data,cid,ip,port) + s.OnDataRecieved:fConnect(function(self,data,cid,ip,port) log(tostring(ip)..":"..tostring(port),"Server-log.log") log(data,"Server-log.log") end) diff --git a/net/settings.lua b/net/settings.lua index bd5df06..de9c190 100644 --- a/net/settings.lua +++ b/net/settings.lua @@ -11,7 +11,7 @@ function net.settings:init() -- calling this initilizes the library and binds it --Server Stuff net.OnServerCreated:connect(function(s) print("The Settings Module has been loaded onto the server!") - s.OnDataRecieved:connect(function(self,data,cid,ip,port) -- when the server recieves data this method is triggered + s.OnDataRecieved(function(self,data,cid,ip,port) -- when the server recieves data this method is triggered local namespace,args=data:match("!settings! (%s+) (.+)") local args if namespace then @@ -23,7 +23,7 @@ function net.settings:init() -- calling this initilizes the library and binds it end end end - end) + end,"settings") function s:regSetting(namespace,settings) if not net.settings.config[namespace] then net.settings.config[namespace]={} @@ -35,9 +35,9 @@ function net.settings:init() -- calling this initilizes the library and binds it end) --Client Stuff net.OnClientCreated:connect(function(c) - c.OnDataRecieved:connect(function(self,data) -- when the client recieves data this method is triggered + c.OnDataRecieved:(function(self,data) -- when the client recieves data this method is triggered --First Lets make sure we are getting Setting data - end) + end,"setings") function sendSetting(namespace,args) self:send("!settings! "..namespace.." "..args) end diff --git a/net/version.lua b/net/version.lua index e818c91..258bb4b 100644 --- a/net/version.lua +++ b/net/version.lua @@ -1,17 +1,43 @@ +require("net") +require("net.aft") net:registerModule("version",{1,0,0}) -- allows communication of versions for modules +net.version.HOSTS={ + ["Lua"]=1, + ["LuaJIT"]=1, + ["Love2d"]=2, -- Yes love2d uses luaJIT, but the filesystem works a bit differently + ["Corona"]=3, +} +net.version.OS={ + ["Windows"]=1, + ["Unix"]=2, + ["RPI"]=3, +} +--net.version.EOL="\60\69\110\100\45\79\102\45\70\105\108\101\45\84\114\97\110\115\102\101\114\62" net.OnServerCreated:connect(function(s) s.OnDataRecieved(function(self,data,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP) - -- + local cmd,arg1,arg2=data:match("!version! ") end,"version") s.OnClientConnected(function(self,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP) - s:pollClientModules(IP_OR_HANDLE,PORT_OR_IP) - end) - s.OnClientsModulesList(function(list,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP) - -- + multi:newFunction(function(func) -- anom func, allows for fancy multitasking + multi:newFunction(function(self) + local range=self:newRange() + for i in range(1,#self.loadedModules) do + local mod=self.loadedModules[i] + self:send(IP_OR_HANDLE,"!version! CHECK "..mod.." NIL",PORT_OR_IP) -- sends command to client to return the version of the module + end + end)() + func=nil -- we dont want 1000s+ of these anom functions lying around + end)()-- lets call the function + self:send(IP_OR_HANDLE,"!version! HOST NIL NIL",PORT_OR_IP) end) end) net.OnClientCreated:connect(function(c) c.OnDataRecieved(function(self,data) - -- + local cmd,module,arg1=data:match("!version! (%S+) (%S+) (%S+)") + if cmd=="CHECK" then + self:send("!version! VER "..self.loadedModules[module].." "..net.getModuleVersion(module)) + elseif cmd=="UPDATE" then + -- + end end,"version") end)