Add files via upload
This commit is contained in:
parent
555f9de5f7
commit
b5590af9bd
797
client/Libs/Utils.lua
Normal file
797
client/Libs/Utils.lua
Normal file
@ -0,0 +1,797 @@
|
||||
-- os Additions
|
||||
function os.getSystemBit()
|
||||
if (os.getenv('PROCESSOR_ARCHITEW6432')=='AMD64' or os.getenv('PROCESSOR_ARCHITECTURE')=='AMD64') then
|
||||
return 64
|
||||
else
|
||||
return 32
|
||||
end
|
||||
end
|
||||
function os.sleep(n)
|
||||
if not n then n=0 end
|
||||
local t0 = os.clock()
|
||||
while os.clock() - t0 <= n do end
|
||||
end
|
||||
function os.pause(msg)
|
||||
if msg ~= nil then
|
||||
print(msg)
|
||||
end
|
||||
io.read()
|
||||
end
|
||||
function os.batCmd(cmd)
|
||||
io.mkFile('temp.bat',cmd)
|
||||
local temp = os.execute([[temp.bat]])
|
||||
io.delFile('temp.bat')
|
||||
return temp
|
||||
end
|
||||
function os._getOS()
|
||||
if package.config:sub(1,1)=='\\' then
|
||||
return 'windows'
|
||||
else
|
||||
return 'unix'
|
||||
end
|
||||
end
|
||||
function os.getOS(t)
|
||||
if not t then
|
||||
return os._getOS()
|
||||
end
|
||||
if os._getOS()=='unix' then
|
||||
fh,err = io.popen('uname -o 2>/dev/null','r')
|
||||
if fh then
|
||||
osname = fh:read()
|
||||
end
|
||||
if osname then return osname end
|
||||
end
|
||||
local winver='Unknown Version'
|
||||
local a,b,c=os.capture('ver'):match('(%d+).(%d+).(%d+)')
|
||||
local win=a..'.'..b..'.'..c
|
||||
if type(t)=='string' then
|
||||
win=t
|
||||
end
|
||||
if win=='4.00.950' then
|
||||
winver='95'
|
||||
elseif win=='4.00.1111' then
|
||||
winver='95 OSR2'
|
||||
elseif win=='4.00.1381' then
|
||||
winver='NT 4.0'
|
||||
elseif win=='4.10.1998' then
|
||||
winver='98'
|
||||
elseif win=='4.10.2222' then
|
||||
winver='98 SE'
|
||||
elseif win=='4.90.3000' then
|
||||
winver='ME'
|
||||
elseif win=='5.00.2195' then
|
||||
winver='2000'
|
||||
elseif win=='5.1.2600' then
|
||||
winver='XP'
|
||||
elseif win=='5.2.3790' then
|
||||
winver='Server 2003'
|
||||
elseif win=='6.0.6000' then
|
||||
winver='Vista/Windows Server 2008'
|
||||
elseif win=='6.0.6002' then
|
||||
winver='Vista SP2'
|
||||
elseif win=='6.1.7600' then
|
||||
winver='7/Windows Server 2008 R2'
|
||||
elseif win=='6.1.7601' then
|
||||
winver='7 SP1/Windows Server 2008 R2 SP1'
|
||||
elseif win=='6.2.9200' then
|
||||
winver='8/Windows Server 2012'
|
||||
elseif win=='6.3.9600' then
|
||||
winver='8.1/Windows Server 2012'
|
||||
elseif win=='6.4.9841' then
|
||||
winver='10 Technical Preview 1'
|
||||
elseif win=='6.4.9860' then
|
||||
winver='10 Technical Preview 2'
|
||||
elseif win=='6.4.9879' then
|
||||
winver='10 Technical Preview 3'
|
||||
elseif win=='10.0.9926' then
|
||||
winver='10 Technical Preview 4'
|
||||
end
|
||||
return 'Windows '..winver
|
||||
end
|
||||
function os.getLuaArch()
|
||||
return (#tostring({})-7)*4
|
||||
end
|
||||
if os.getOS()=='windows' then
|
||||
function os.sleep(n)
|
||||
if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
|
||||
end
|
||||
else
|
||||
function os.sleep(n)
|
||||
os.execute('sleep ' .. tonumber(n))
|
||||
end
|
||||
end
|
||||
function os.capture(cmd, raw)
|
||||
local f = assert(io.popen(cmd, 'r'))
|
||||
local s = assert(f:read('*a'))
|
||||
f:close()
|
||||
if raw then return s end
|
||||
s = string.gsub(s, '^%s+', '')
|
||||
s = string.gsub(s, '%s+$', '')
|
||||
s = string.gsub(s, '[\n\r]+', ' ')
|
||||
return s
|
||||
end
|
||||
function os.getCurrentUser()
|
||||
return os.getenv('$USER') or os.getenv('USERNAME')
|
||||
end
|
||||
-- string Additions
|
||||
function string.trim(s)
|
||||
local from = s:match"^%s*()"
|
||||
return from > #s and "" or s:match(".*%S", from)
|
||||
end
|
||||
function string.random(n)
|
||||
local str = ''
|
||||
strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||
for i=1,n do
|
||||
h = math.random(1,#strings)
|
||||
str = str..''..strings[h]
|
||||
end
|
||||
return str
|
||||
end
|
||||
function string.linesToTable(s)
|
||||
local t = {}
|
||||
local i = 0
|
||||
while true do
|
||||
i = string.find(s, '\n', i+1)
|
||||
if i == nil then return t end
|
||||
table.insert(t, i)
|
||||
end
|
||||
end
|
||||
function string.lines(str)
|
||||
local t = {}
|
||||
local function helper(line) table.insert(t, line) return '' end
|
||||
helper((str:gsub('(.-)\r?\n', helper)))
|
||||
return t
|
||||
end
|
||||
function string.split(str, pat)
|
||||
local t = {} -- NOTE: use {n = 0} in Lua-5.0
|
||||
local fpat = '(.-)' .. pat
|
||||
local last_end = 1
|
||||
local s, e, cap = str:find(fpat, 1)
|
||||
while s do
|
||||
if s ~= 1 or cap ~= '' then
|
||||
table.insert(t,cap)
|
||||
end
|
||||
last_end = e+1
|
||||
s, e, cap = str:find(fpat, last_end)
|
||||
end
|
||||
if last_end <= #str then
|
||||
cap = str:sub(last_end)
|
||||
table.insert(t, cap)
|
||||
end
|
||||
return t
|
||||
end
|
||||
function string.shuffle(inputStr)
|
||||
math.randomseed(os.time());
|
||||
local outputStr = '';
|
||||
local strLength = string.len(inputStr);
|
||||
while (strLength ~=0) do
|
||||
local pos = math.random(strLength);
|
||||
outputStr = outputStr..string.sub(inputStr,pos,pos);
|
||||
inputStr = inputStr:sub(1, pos-1) .. inputStr:sub(pos+1);
|
||||
strLength = string.len(inputStr);
|
||||
end
|
||||
return outputStr;
|
||||
end
|
||||
function string.genKeys(chars,a,f,s,GG)
|
||||
if GG then
|
||||
chars=string.rep(chars,a)
|
||||
end
|
||||
if s then
|
||||
chars=string.shuffle(chars)
|
||||
end
|
||||
b=#chars
|
||||
if a==0 then return end
|
||||
local taken = {} local slots = {}
|
||||
for i=1,a do slots[i]=0 end
|
||||
for i=1,b do taken[i]=false end
|
||||
local index = 1
|
||||
local tab={}
|
||||
for i=1,#chars do
|
||||
table.insert(tab,chars:sub(i,i))
|
||||
end
|
||||
while index > 0 do repeat
|
||||
repeat slots[index] = slots[index] + 1
|
||||
until slots[index] > b or not taken[slots[index]]
|
||||
if slots[index] > b then
|
||||
slots[index] = 0
|
||||
index = index - 1
|
||||
if index > 0 then
|
||||
taken[slots[index]] = false
|
||||
end
|
||||
break
|
||||
else
|
||||
taken[slots[index]] = true
|
||||
end
|
||||
if index == a then
|
||||
local tt={}
|
||||
for i=1,a do
|
||||
table.insert(tt,tab[slots[i]])
|
||||
end
|
||||
f(table.concat(tt))
|
||||
taken[slots[index]] = false
|
||||
break
|
||||
end
|
||||
index = index + 1
|
||||
until true end
|
||||
end
|
||||
-- io Additions
|
||||
function io.getInput(msg)
|
||||
if msg ~= nil then
|
||||
io.write(msg)
|
||||
end
|
||||
return io.read()
|
||||
end
|
||||
function io.scanDir(directory)
|
||||
directory=directory or io.getDir()
|
||||
local i, t, popen = 0, {}, io.popen
|
||||
if os.getOS()=='unix' then
|
||||
for filename in popen('ls -a \''..directory..'\''):lines() do
|
||||
i = i + 1
|
||||
t[i] = filename
|
||||
end
|
||||
else
|
||||
for filename in popen('dir \''..directory..'\' /b'):lines() do
|
||||
i = i + 1
|
||||
t[i] = filename
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
function io.buildFromTree(tbl, indent,folder)
|
||||
if not indent then indent = 0 end
|
||||
if not folder then folder = '' end
|
||||
for k, v in pairs(tbl) do
|
||||
formatting = string.rep(' ', indent) .. k .. ':'
|
||||
if type(v) == 'table' then
|
||||
if not(io.dirExists(folder..string.sub(formatting,1,-2))) then
|
||||
io.mkDir(folder..string.sub(formatting,1,-2))
|
||||
end
|
||||
io.buildFromTree(v,0,folder..string.sub(formatting,1,-2)..'\\')
|
||||
else
|
||||
a=string.find(tostring(v),':',1,true)
|
||||
if a then
|
||||
file=string.sub(tostring(v),1,a-1)
|
||||
data=string.sub(tostring(v),a+1)
|
||||
io.mkFile(folder..file,data,'wb')
|
||||
else
|
||||
io.mkFile(folder..v,'','wb')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function io.cpFile(path,topath)
|
||||
if os.getOS()=='unix' then
|
||||
os.execute('cp '..file1..' '..file2)
|
||||
else
|
||||
os.execute('Copy '..path..' '..topath)
|
||||
end
|
||||
end
|
||||
function io.delDir(directoryname)
|
||||
if os.getOS()=='unix' then
|
||||
os.execute('rm -rf '..directoryname)
|
||||
else
|
||||
os.execute('rmdir '..directoryname..' /s /q')
|
||||
end
|
||||
end
|
||||
function io.delFile(path)
|
||||
os.remove(path)
|
||||
end
|
||||
function io.mkDir(dirname)
|
||||
os.execute('mkdir "' .. dirname..'"')
|
||||
end
|
||||
function io.mkFile(filename,data,tp)
|
||||
if not(tp) then tp='wb' end
|
||||
if not(data) then data='' end
|
||||
file = io.open(filename, tp)
|
||||
if file==nil then return end
|
||||
file:write(data)
|
||||
file:close()
|
||||
end
|
||||
function io.movFile(path,topath)
|
||||
io.cpFile(path,topath)
|
||||
io.delFile(path)
|
||||
end
|
||||
function io.listFiles(dir)
|
||||
if not(dir) then dir='' end
|
||||
local f = io.popen('dir \''..dir..'\'')
|
||||
if f then
|
||||
return f:read('*a')
|
||||
else
|
||||
print('failed to read')
|
||||
end
|
||||
end
|
||||
function io.getDir(dir)
|
||||
if not dir then return io.getWorkingDir() end
|
||||
if os.getOS()=='unix' then
|
||||
return os.capture('cd '..dir..' ; cd')
|
||||
else
|
||||
return os.capture('cd '..dir..' & cd')
|
||||
end
|
||||
end
|
||||
function io.getWorkingDir()
|
||||
return io.popen'cd':read'*l'
|
||||
end
|
||||
function io.fileExists(path)
|
||||
g=io.open(path or '','r')
|
||||
if path =='' then
|
||||
p='empty path'
|
||||
return nil
|
||||
end
|
||||
if g~=nil and true or false then
|
||||
p=(g~=nil and true or false)
|
||||
end
|
||||
if g~=nil then
|
||||
io.close(g)
|
||||
else
|
||||
return false
|
||||
end
|
||||
return p
|
||||
end
|
||||
function io.fileCheck(file_name)
|
||||
if not file_name then print('No path inputed') return false end
|
||||
local file_found=io.open(file_name, 'r')
|
||||
if file_found==nil then
|
||||
file_found=false
|
||||
else
|
||||
file_found=true
|
||||
end
|
||||
return file_found
|
||||
end
|
||||
function io.dirExists(strFolderName)
|
||||
strFolderName = strFolderName or io.getDir()
|
||||
local fileHandle, strError = io.open(strFolderName..'\\*.*','r')
|
||||
if fileHandle ~= nil then
|
||||
io.close(fileHandle)
|
||||
return true
|
||||
else
|
||||
if string.match(strError,'No such file or directory') then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
function io.getAllItems(dir)
|
||||
local t=os.capture("cd \""..dir.."\" & dir /a-d | find",true):lines()
|
||||
return t
|
||||
end
|
||||
function io.listItems(dir)
|
||||
if io.dirExists(dir) then
|
||||
temp=io.listFiles(dir) -- current directory if blank
|
||||
if io.getDir(dir)=='C:\\\n' then
|
||||
a,b=string.find(temp,'C:\\',1,true)
|
||||
a=a+2
|
||||
else
|
||||
a,b=string.find(temp,'..',1,true)
|
||||
end
|
||||
temp=string.sub(temp,a+2)
|
||||
list=string.linesToTable(temp)
|
||||
temp=string.sub(temp,1,list[#list-2])
|
||||
slist=string.lines(temp)
|
||||
table.remove(slist,1)
|
||||
table.remove(slist,#slist)
|
||||
temp={}
|
||||
temp2={}
|
||||
for i=1,#slist do
|
||||
table.insert(temp,string.sub(slist[i],40,-1))
|
||||
end
|
||||
return temp
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
function io.getDirectories(dir,l)
|
||||
if dir then
|
||||
dir=dir..'\\'
|
||||
else
|
||||
dir=''
|
||||
end
|
||||
local temp2=io.scanDir(dir)
|
||||
for i=#temp2,1,-1 do
|
||||
if io.fileExists(dir..temp2[i]) then
|
||||
table.remove(temp2,i)
|
||||
elseif l then
|
||||
temp2[i]=dir..temp2[i]
|
||||
end
|
||||
end
|
||||
return temp2
|
||||
end
|
||||
function io.getFiles(dir,l)
|
||||
if dir then
|
||||
dir=dir..'\\'
|
||||
else
|
||||
dir=''
|
||||
end
|
||||
local temp2=io.scanDir(dir)
|
||||
for i=#temp2,1,-1 do
|
||||
if io.dirExists(dir..temp2[i]) then
|
||||
table.remove(temp2,i)
|
||||
elseif l then
|
||||
temp2[i]=dir..temp2[i]
|
||||
end
|
||||
end
|
||||
return temp2
|
||||
end
|
||||
function io.getFullName(name)
|
||||
local temp=name or arg[0]
|
||||
if string.find(temp,'\\',1,true) or string.find(temp,'/',1,true) then
|
||||
temp=string.reverse(temp)
|
||||
a,b=string.find(temp,'\\',1,true)
|
||||
if not(a) or not(b) then
|
||||
a,b=string.find(temp,'/',1,true)
|
||||
end
|
||||
return string.reverse(string.sub(temp,1,b-1))
|
||||
end
|
||||
return temp
|
||||
end
|
||||
function io.getName(file)
|
||||
local name=io.getFullName(file)
|
||||
name=string.reverse(name)
|
||||
a,b=string.find(name,'.',1,true)
|
||||
name=string.sub(name,a+1,-1)
|
||||
return string.reverse(name)
|
||||
end
|
||||
function io.readFile(file)
|
||||
local f = io.open(file, 'rb')
|
||||
local content = f:read('*all')
|
||||
f:close()
|
||||
return content
|
||||
end
|
||||
function io.getExtension(file)
|
||||
local file=io.getFullName(file)
|
||||
file=string.reverse(file)
|
||||
local a,b=string.find(file,'.',0,true)
|
||||
local temp=string.sub(file,1,b)
|
||||
return string.reverse(temp)
|
||||
end
|
||||
function io.pathToTable(path)
|
||||
local p=io.splitPath(path)
|
||||
local temp={}
|
||||
temp[p[1]]={}
|
||||
local last=temp[p[1]]
|
||||
for i=2,#p do
|
||||
snd=last
|
||||
last[p[i]]={}
|
||||
last=last[p[i]]
|
||||
end
|
||||
return temp,last,snd
|
||||
end
|
||||
function io.splitPath(str)
|
||||
return string.split(str,'[\\/]+')
|
||||
end
|
||||
|
||||
function io.parseDir(dir,t)
|
||||
io.tempFiles={}
|
||||
function _p(dir)
|
||||
local dirs=io.getDirectories(dir,true)
|
||||
local files=io.getFiles(dir,true)
|
||||
for i=1,#files do
|
||||
p,l,s=io.pathToTable(files[i])
|
||||
if t then
|
||||
s[io.getFullName(files[i])]=io.readFile(files[i])
|
||||
else
|
||||
s[io.getFullName(files[i])]=io.open(files[i],'r+')
|
||||
end
|
||||
table.merge(io.tempFiles,p)
|
||||
end
|
||||
for i=1,#dirs do
|
||||
table.merge(io.tempFiles,io.pathToTable(dirs[i]))
|
||||
_p(dirs[i],t)
|
||||
end
|
||||
end
|
||||
_p(dir)
|
||||
return io.tempFiles
|
||||
end
|
||||
function io.parsedir(dir,f)
|
||||
io.tempFiles={}
|
||||
function _p(dir,f)
|
||||
local dirs=io.getDirectories(dir,true)
|
||||
local files=io.getFiles(dir,true)
|
||||
for i=1,#files do
|
||||
if not f then
|
||||
table.insert(io.tempFiles,files[i])
|
||||
else
|
||||
f(files[i])
|
||||
end
|
||||
end
|
||||
for i=1,#dirs do
|
||||
_p(dirs[i],f)
|
||||
end
|
||||
end
|
||||
_p(dir,f)
|
||||
return io.tempFiles
|
||||
end
|
||||
function io.driveReady(drive)
|
||||
drive=drive:upper()
|
||||
if not(drive:find(':',1,true)) then
|
||||
drive=drive..':'
|
||||
end
|
||||
drives=io.getDrives()
|
||||
for i=1,#drives do
|
||||
if drives[i]==drive then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function io.getDrives()
|
||||
if os.getOS()=='windows' then
|
||||
local temp={}
|
||||
local t1=os.capture('wmic logicaldisk where drivetype=2 get deviceid, volumename',true)
|
||||
local t2=os.capture('wmic logicaldisk where drivetype=3 get deviceid, volumename',true)
|
||||
for drive,d2 in t1:gmatch('(.:)%s-(%w+)') do
|
||||
if #d2>1 then
|
||||
table.insert(temp,drive)
|
||||
end
|
||||
end
|
||||
for drive in t2:gmatch('(.:)') do
|
||||
table.insert(temp,drive)
|
||||
end
|
||||
return temp
|
||||
end
|
||||
error('Command is windows only!')
|
||||
end
|
||||
-- table Additions
|
||||
function table.dump(t,indent)
|
||||
local names = {}
|
||||
if not indent then indent = '' end
|
||||
for n,g in pairs(t) do
|
||||
table.insert(names,n)
|
||||
end
|
||||
table.sort(names)
|
||||
for i,n in pairs(names) do
|
||||
local v = t[n]
|
||||
if type(v) == 'table' then
|
||||
if(v==t) then
|
||||
print(indent..tostring(n)..': <-')
|
||||
else
|
||||
print(indent..tostring(n)..':')
|
||||
table.dump(v,indent..' ')
|
||||
end
|
||||
else
|
||||
if type(v) == 'function' then
|
||||
print(indent..tostring(n)..'()')
|
||||
else
|
||||
print(indent..tostring(n)..': '..tostring(v))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function table.alphanumsort(o)
|
||||
local function padnum(d) local dec, n = string.match(d, '(%.?)0*(.+)')
|
||||
return #dec > 0 and ('%.12f'):format(d) or ('%s%03d%s'):format(dec, #n, n)
|
||||
end
|
||||
table.sort(o, function(a,b) return tostring(a):gsub('%.?%d+',padnum)..('%3d'):format(#b)< tostring(b):gsub('%.?%d+',padnum)..('%3d'):format(#a) end)
|
||||
return o
|
||||
end
|
||||
function table.foreach(t,f)
|
||||
for i,v in pairs(t) do
|
||||
f(v)
|
||||
end
|
||||
end
|
||||
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 table.print(tbl, indent)
|
||||
if not indent then indent = 0 end
|
||||
for k, v in pairs(tbl) do
|
||||
formatting = string.rep(' ', indent) .. k .. ': '
|
||||
if type(v) == 'table' then
|
||||
print(formatting)
|
||||
table.print(v, indent+1)
|
||||
else
|
||||
print(formatting .. tostring(v))
|
||||
end
|
||||
end
|
||||
end
|
||||
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 table.clear(t)
|
||||
for k in pairs (t) do
|
||||
t[k] = nil
|
||||
end
|
||||
end
|
||||
function table.copy(t)
|
||||
function deepcopy(orig)
|
||||
local orig_type = type(orig)
|
||||
local copy
|
||||
if orig_type == 'table' then
|
||||
copy = {}
|
||||
for orig_key, orig_value in next, orig, nil do
|
||||
copy[deepcopy(orig_key)] = deepcopy(orig_value)
|
||||
end
|
||||
setmetatable(copy, deepcopy(getmetatable(orig)))
|
||||
else -- number, string, boolean, etc
|
||||
copy = orig
|
||||
end
|
||||
return copy
|
||||
end
|
||||
return deepcopy(t)
|
||||
end
|
||||
function table.swap(tab,i1,i2)
|
||||
tab[i1],tab[i2]=tab[i2],tab[i1]
|
||||
end
|
||||
function table.append(t1, ...)
|
||||
t1,t2= t1 or {},{...}
|
||||
for k,v in pairs(t2) do
|
||||
t1[#t1+1]=t2[k]
|
||||
end
|
||||
return t1
|
||||
end
|
||||
function table.compare(t1, t2,d)
|
||||
if d then
|
||||
return table.deepCompare(t1,t2)
|
||||
end
|
||||
--if #t1 ~= #t2 then return false end
|
||||
if #t2>#t1 then
|
||||
for i=1,#t2 do
|
||||
if t1[i] ~= t2[i] then
|
||||
return false,t2[i]
|
||||
end
|
||||
end
|
||||
else
|
||||
for i=1,#t1 do
|
||||
if t1[i] ~= t2[i] then
|
||||
return false,t2[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
function table.deepCompare(t1,t2)
|
||||
if t1==t2 then return true end
|
||||
if (type(t1)~='table') then return false end
|
||||
local mt1 = getmetatable(t1)
|
||||
local mt2 = getmetatable(t2)
|
||||
if( not table.deepCompare(mt1,mt2) ) then return false end
|
||||
for k1,v1 in pairs(t1) do
|
||||
local v2 = t2[k1]
|
||||
if( not table.deepCompare(v1,v2) ) then return false end
|
||||
end
|
||||
for k2,v2 in pairs(t2) do
|
||||
local v1 = t1[k2]
|
||||
if( not table.deepCompare(v1,v2) ) then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
function table.has(t,_v)
|
||||
for i,v in pairs(t) do
|
||||
if v==_v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function table.reverse(tab)
|
||||
local size = #tab
|
||||
local newTable = {}
|
||||
for i,v in ipairs (tab) do
|
||||
newTable[size-i] = v
|
||||
end
|
||||
for i=1,#newTable do
|
||||
tab[i]=newTable[i]
|
||||
end
|
||||
end
|
||||
-- Math Additions
|
||||
local Y = function(g) local a = function(f) return f(f) end return a(function(f) return g(function(x) local c=f(f) return c(x) end) end) end
|
||||
local F = function(f) return function(n)if n == 0 then return 1 else return n*f(n-1) end end end
|
||||
math.factorial = Y(F)
|
||||
math.fib={}
|
||||
math.fib.fibL={}
|
||||
setmetatable(math.fib,{__call=function(self,n)
|
||||
if n<=2 then
|
||||
return 1
|
||||
else
|
||||
if self.fibL[n] then
|
||||
return self.fibL[n]
|
||||
else
|
||||
local t=math.fib(n-1)+math.fib(n-2)
|
||||
self.fibL[n]=t
|
||||
return t
|
||||
end
|
||||
end
|
||||
end})
|
||||
local floor,insert = math.floor, table.insert
|
||||
function math.basen(n,b)
|
||||
n = floor(n)
|
||||
if not b or b == 10 then return tostring(n) end
|
||||
local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
local t = {}
|
||||
local sign = ''
|
||||
if n < 0 then
|
||||
sign = '-'
|
||||
n = -n
|
||||
end
|
||||
repeat
|
||||
local d = (n % b) + 1
|
||||
n = floor(n / b)
|
||||
insert(t, 1, digits:sub(d,d))
|
||||
until n == 0
|
||||
return sign .. table.concat(t,'')
|
||||
end
|
||||
function math.convbase(n,b,tb)
|
||||
return math.basen(tonumber(tostring(n),b),tb)
|
||||
end
|
||||
if BigNum then
|
||||
function BigNum.mod(a,b)
|
||||
return a-((a/b)*b)
|
||||
end
|
||||
local floor,insert = math.floor, table.insert
|
||||
function math.basen(n,b)
|
||||
n = BigNum.new(n)
|
||||
if not b or b == 10 then return tostring(n) end
|
||||
local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
local t = {}
|
||||
local sign = ''
|
||||
if n < BigNum.new(0) then
|
||||
sign = '-'
|
||||
n = -n
|
||||
end
|
||||
repeat
|
||||
local d = BigNum.mod(n , b) + 1
|
||||
n = n/b
|
||||
d=tonumber(tostring(d))
|
||||
insert(t, 1, digits:sub(d,d))
|
||||
until tonumber(tostring(n)) == 0
|
||||
return sign .. table.concat(t,'')
|
||||
end
|
||||
function math.to10(n,b)
|
||||
local num=tostring(n)
|
||||
local sum=BigNum.new()
|
||||
local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
for i=1,#num do
|
||||
local v=digits:find(num:sub(i,i),1,true)
|
||||
sum=sum+BigNum.new(tonumber(v)-1)*BigNum.pow(BigNum.new(b),BigNum.new(#num-i))
|
||||
end
|
||||
return sum
|
||||
end
|
||||
function math.convbase(n,b,tb)
|
||||
return math.basen(math.to10(n,b),tb)
|
||||
end
|
||||
end
|
||||
function math.numfix(n,x)
|
||||
local str=tostring(n)
|
||||
if #str<x then
|
||||
str=('0'):rep(x-#str)..str
|
||||
end
|
||||
return str
|
||||
end
|
||||
-- Misc Additions
|
||||
function smartPrint(...)
|
||||
local args={...}
|
||||
for i=1,#args do
|
||||
if type(args[i])=='table' then
|
||||
table.print(args[i])
|
||||
else
|
||||
print(args[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
function totable(v)
|
||||
if type(v)=='table' then return v end
|
||||
return {v}
|
||||
end
|
||||
print(math.factorial(2))
|
||||
@ -1,3 +1,4 @@
|
||||
MY_Name="" -- Will be set at a later time
|
||||
-- This is a comment
|
||||
--This is the test client code!
|
||||
require("Libs/Library") -- One of the defualt libraies that i load... Not needed for this project
|
||||
@ -10,25 +11,96 @@ require("net") -- Loads the networking library
|
||||
require("net.chatting")
|
||||
client=net:newTCPClient("localhost",12345) -- Connects to the server
|
||||
if type(client)=="boolean" then error("Please run the server file first!") end
|
||||
client.OnChatRecieved(function(user,msg) -- hook to grab chat data
|
||||
mainapp.chatFrame.text=mainapp.chatFrame.text..user..": "..msg.."\n"
|
||||
client.OnChatRecieved(function(user,msg,isself) -- hook to grab chat data
|
||||
Chat:AddChatBubble(user,msg,isself)
|
||||
end)
|
||||
gui.enableAutoWindowScaling(true) -- allows mobile support. Not needed for PC use
|
||||
--gui.enableAutoWindowScaling(true) -- allows mobile support. Not needed for PC use
|
||||
nameframe=gui:newFrame("",0,0,200,100)
|
||||
nameframe.Color=Color.Lighten(Color.Brown,.15)
|
||||
nameframe:setRoundness(15,15,360)
|
||||
nameframe:centerX()
|
||||
nameframe:centerY()
|
||||
namer=nameframe:newTextBox("Please enter a name to use!",0,0,180,30)
|
||||
namer:centerX()
|
||||
namer:centerY()
|
||||
namer.Color=Color.tan
|
||||
namer.ClearOnFocus=true
|
||||
namer:setRoundness(5,5,360)
|
||||
namer:OnEnter(function(self,txt)
|
||||
MY_Name=txt:gsub("%s","_")
|
||||
InitEngine()
|
||||
nameframe:Destroy()
|
||||
gui.ff:Destroy()
|
||||
end)
|
||||
gui.ff.C1=45
|
||||
gui.ff.C2=193
|
||||
gui.ff.C3=92
|
||||
gui.ff.C1m=-1
|
||||
gui.ff.C2m=1
|
||||
gui.ff.C3m=-1
|
||||
gui.ff.Color=Color.Blue
|
||||
func=multi:newFunction(function(l,self) -- not needed just adds color change when chosing a name
|
||||
l:hold(.05)
|
||||
self.C1=self.C1+(({1,2,3})[math.random(1,3)]*self.C1m)
|
||||
self.C2=self.C2+(({1,2,3})[math.random(1,3)]*self.C2m)
|
||||
self.C3=self.C3+(({1,2,3})[math.random(1,3)]*self.C3m)
|
||||
if self.C1>255 then self.C1=254 self.C1m=-1 end
|
||||
if self.C2>255 then self.C2=254 self.C2m=-1 end
|
||||
if self.C3>255 then self.C3=254 self.C3m=-1 end
|
||||
if self.C1<0 then self.C1=1 self.C1m=1 end
|
||||
if self.C2<0 then self.C2=1 self.C2m=1 end
|
||||
if self.C3<0 then self.C3=1 self.C3m=1 end
|
||||
self.Color=Color.new(self.C1,self.C2,self.C3)
|
||||
end)
|
||||
function love.wheelmoved(x, y) -- handle scrolling
|
||||
if mainapp then else return end
|
||||
if y > 0 then
|
||||
Chat.bubbles:SetDualDim(nil,Chat.bubbles.y+10)
|
||||
elseif y < 0 then
|
||||
Chat.bubbles:SetDualDim(nil,Chat.bubbles.y-50)
|
||||
end
|
||||
if Chat.bubbles.offset.pos.y>0 then
|
||||
Chat.bubbles.offset.pos.y=0
|
||||
end
|
||||
print(Chat.bubbles.offset.pos.y)
|
||||
end
|
||||
gui.ff:OnUpdate(func)
|
||||
function InitEngine()
|
||||
mainapp=gui:newFrame("",0,0,0,0,0,0,1,1) -- creates a frame that takes up the enitre window
|
||||
mainapp.header=mainapp:newTextLabel("Chat Program",0,0,0,20,0,0,1) -- creates the header for the app
|
||||
mainapp.header.Tween=-3 -- moves the text up by a factor of 3 pixels
|
||||
mainapp.Color=Color.Lighten(Color.Brown,.25)
|
||||
mainapp.BorderSize=0
|
||||
mainapp.header=mainapp:newTextLabel("Now chatting as: "..MY_Name,1,-10,-2,30,0,0,1) -- creates the header for the app
|
||||
mainapp.header:setRoundness(15,15,360)
|
||||
mainapp.header.Tween=7 -- moves the text up by a factor of 3 pixels
|
||||
mainapp.header.Color=Color.Lighten(Color.Blue,.25) -- Sets the Color of the header object to light blue
|
||||
mainapp.chatFrame=mainapp:newTextLabel("",0,20,0,-20,0,0,1,1) -- creates the chat frame where users can see the text that is sent
|
||||
mainapp.chatFrame.Color=Color.Lighten(Color.Brown,.15) -- Color stuff
|
||||
mainapp.chatFrame.Tween=-3 -- text positioning
|
||||
mainapp.chatFrame.TextFormat="left" -- changes the text format to left hand side of screen
|
||||
mainapp.chatFrame=mainapp:newFrame("",0,21,0,-20,0,0,1,1) -- creates the chat frame where users can see the text that is sent
|
||||
mainapp.chatFrame.Color=Color.Lighten(Color.Brown,.25) -- Color stuff
|
||||
mainapp.chatFrame.ClipDescendants=true
|
||||
mainapp.chatFrame.bubbles=mainapp.chatFrame:newFrame("",0,0,0,0,0,0,1)
|
||||
mainapp.chatFrame.bubbles.Visibility=0
|
||||
Chat=mainapp.chatFrame
|
||||
Chat.lastBubbleHeight=0
|
||||
function Chat:AddChatBubble(user,txt,isself)
|
||||
local msg=user..": "..txt
|
||||
local bubble=self.bubbles:newTextLabel(msg,0,self.lastBubbleHeight+5,math.floor(mainapp.width/2),(math.ceil(#msg/24)*12)+5)
|
||||
bubble.TextFormat="left"
|
||||
bubble.XTween=2
|
||||
bubble.Tween=-4
|
||||
bubble:setRoundness(5,5,360)
|
||||
if isself then
|
||||
bubble:anchorRight(1)
|
||||
end
|
||||
self.lastBubbleHeight=self.lastBubbleHeight+(math.ceil(#msg/24)*12)+13
|
||||
if self.lastBubbleHeight>mainapp.height-60 then
|
||||
self.bubbles.offset.pos.y=-(self.lastBubbleHeight-(mainapp.height-60))
|
||||
end
|
||||
end
|
||||
mainapp.textbox=mainapp:newTextBox("",5,-35,-10,30,0,1,1) -- creates a textbox that allows the user to be able to send messages
|
||||
mainapp.textbox.TextFormat="left" -- sets the format to left hand side of screen
|
||||
mainapp.textbox.Color=Color.tan
|
||||
mainapp.textbox:setRoundness(5,5,360)
|
||||
mainapp.textbox:OnEnter(function(self,txt) -- handles the send event
|
||||
client:sendChat("NAMENOSPACE",txt) -- sends the data to the server
|
||||
client:sendChat(MY_Name,txt) -- sends the data to the server
|
||||
self.text=""
|
||||
self.Color=Color.tan
|
||||
end)
|
||||
@ -38,5 +110,4 @@ function InitEngine()
|
||||
mainapp.textbox.ClearOnFocus=true
|
||||
mainapp.textbox.XTween=2
|
||||
mainapp.textbox.Tween=2 -- positions the text in the text box
|
||||
--This displays the chatting frame and allows connection to the server... Look at server.lua to see the servers code
|
||||
end
|
||||
|
||||
@ -21,7 +21,14 @@ function net.chatting:init() -- calling this initilizes the library and binds it
|
||||
msg=msg
|
||||
}
|
||||
self.OnChatRecieved:Fire(struct) -- trigger the chat event
|
||||
self:sendAll("!chatting! "..struct.user.." '"..struct.msg.."'")
|
||||
for i,v in pairs(self.ips) do
|
||||
if ip==v then
|
||||
print("Self: "..struct.user)
|
||||
self:send(v,"!chatting! 1 "..struct.user.." '"..struct.msg.."'")
|
||||
else
|
||||
self:send(v,"!chatting! 0 "..struct.user.." '"..struct.msg.."'")
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
s.rooms={}
|
||||
@ -34,10 +41,11 @@ function net.chatting:init() -- calling this initilizes the library and binds it
|
||||
net.OnClientCreated:connect(function(c)
|
||||
c.OnDataRecieved:connect(function(self,data) -- when the client recieves data this method is triggered
|
||||
--First Lets make sure we are getting chatting data
|
||||
local user,msg = data:match("!chatting! (%S-) '(.+)'")
|
||||
local isself, user,msg = data:match("!chatting! (%d) (%S-) '(.+)'")
|
||||
if user and msg then
|
||||
--This is the client so our job here is done
|
||||
self.OnChatRecieved:Fire(user,msg) -- trigger the chat event
|
||||
print(isself)
|
||||
self.OnChatRecieved:Fire(user,msg,({["1"]=true, ["0"]=false})[isself]) -- trigger the chat event
|
||||
end
|
||||
end)
|
||||
function c:sendChat(user,msg)
|
||||
|
||||
53
client/net/email.lua
Normal file
53
client/net/email.lua
Normal file
@ -0,0 +1,53 @@
|
||||
require("net.identity")
|
||||
net:registerModule("email",{1,0,0})
|
||||
smtp = require 'socket.smtp'
|
||||
ssl = require 'ssl'
|
||||
|
||||
function net.email.init(from,user,pass)
|
||||
net.OnServerCreated:connect(function(s)
|
||||
s.from=from
|
||||
s.user=user
|
||||
s.pass=pass
|
||||
function s:sendMessage(subject, body, dTable)
|
||||
local msg = {
|
||||
headers = {
|
||||
from = '<'..dTable.email..'>'
|
||||
to = dTable.nick..' <'..dTable.email..'>',
|
||||
subject = subject
|
||||
},
|
||||
body = body
|
||||
}
|
||||
local ok, err = smtp.send {
|
||||
from = '<'..self.from..'>',
|
||||
rcpt = '<'..dTable.email..'>',
|
||||
source = smtp.message(msg),
|
||||
user = self.user,
|
||||
password = self.pass,
|
||||
server = 'smtp.gmail.com',
|
||||
port = 465,
|
||||
create = net.sslCreate
|
||||
}
|
||||
if not ok then
|
||||
print("Mail send failed", err) -- better error handling required
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
function net.sslCreate()
|
||||
local sock = socket.tcp()
|
||||
return setmetatable({
|
||||
connect = function(_, host, port)
|
||||
local r, e = sock:connect(host, port)
|
||||
if not r then return r, e end
|
||||
sock = ssl.wrap(sock, {mode='client', protocol='tlsv1'})
|
||||
return sock:dohandshake()
|
||||
end
|
||||
}, {
|
||||
__index = function(t,n)
|
||||
return function(_, ...)
|
||||
return sock[n](sock, ...)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
192
client/net/identity.lua
Normal file
192
client/net/identity.lua
Normal file
@ -0,0 +1,192 @@
|
||||
require("net")
|
||||
--General Stuff
|
||||
--[[ What this module does!
|
||||
Adds
|
||||
net.identity:init()
|
||||
|
||||
]]
|
||||
net:registerModule("identity",{1,0,0})
|
||||
function net.hash(text,n)
|
||||
n=n or 16
|
||||
return bin.new(text.."jgmhktyf"):getHash(n)
|
||||
end
|
||||
function net.identity:init() -- calling this initilizes the library and binds it to the servers and clients created
|
||||
--Server Stuff
|
||||
net.OnServerCreated:connect(function(s)
|
||||
s.userFolder="./"
|
||||
print("The identity Module has been loaded onto the server!")
|
||||
function s:_isRegistered(user)
|
||||
return io.fileExists(self.userFolder..net.hash(user)..".dat")
|
||||
end
|
||||
function s:getUserData(user)
|
||||
local userdata=bin.load(self.userFolder..net.hash(user)..".dat")
|
||||
local nick,dTable=userdata:match("%S-|%S-|(%S-)|(.+)")
|
||||
return nick,loadstring("return "..(dTable or "{}"))()
|
||||
end
|
||||
function s:getUserCred(user)
|
||||
local userdata=bin.load(self.userFolder..net.hash(user)..".dat")
|
||||
return userdata:match("%S-|(%S-)|")
|
||||
end
|
||||
function s:userLoggedIn(cid)
|
||||
for i,v in pairs(self.loggedIn) do
|
||||
if v.cid==cid then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function s:setDataLocation(loc)
|
||||
self.userFolder=loc
|
||||
end
|
||||
function s:loginUserOut(user)
|
||||
self.loggedIn[user]=nil
|
||||
end
|
||||
function s:loginUserIn(user,cid)
|
||||
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
|
||||
return self:getUserDataHandle(user)
|
||||
end
|
||||
function s:getUserDataHandle(user)
|
||||
return self.loggedIn[user]
|
||||
end
|
||||
function s:syncUserData(user,ip,port)
|
||||
local handle=self:getUserDataHandle(user)
|
||||
self:send(ip,"!identity! SYNC <-|"..bin.ToStr(handle).."|->",port)
|
||||
end
|
||||
s.loggedIn={}
|
||||
s.OnUserRegistered=multi:newConnection()
|
||||
s.OnUserLoggedIn=multi:newConnection()
|
||||
s.OnUserLoggerOut=multi:newConnection()
|
||||
s.OnAlreadyLoggedIn=multi:newConnection()
|
||||
s.OnPasswordForgotten=multi:newConnection()
|
||||
s.OnDataRecieved:connect(function(self,data,cid,ip,port) -- when the server recieves data this method is triggered
|
||||
local cmd,arg1,arg2,arg3,arg4 = data:match("!identity! (%S-) '(.-)' '(.-)' '(.-)' <%-|(.+)|%->")
|
||||
if cmd=="register" then
|
||||
local user,pass,nick,dTable = arg1,arg2,arg3,arg4
|
||||
if self:_isRegistered(user) then
|
||||
self:send(ip,"!identity! REGISTERED <-|"..user.."|->",port)
|
||||
else
|
||||
if not(self.userFolder:sub(-1,-1)=="/" or self.userFolder:sub(-1,-1)=="\\") then
|
||||
self.userFolder=self.userFolder.."/"
|
||||
end
|
||||
local rets=self.OnUserRegistered:Fire(user,pass,nick,loadstring("return "..(dTable or "{}"))())
|
||||
for i=1,#rets do
|
||||
if rets[i][1]==false then
|
||||
print("Server refused to accept registration request!")
|
||||
self:send(ip,"!identity! REGISTERREFUSED <-|NIL|->",port)
|
||||
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)
|
||||
end
|
||||
return
|
||||
elseif cmd=="login" then
|
||||
local user,pass = arg1,arg2
|
||||
local _pass=s:getUserCred(user)
|
||||
if not(self:_isRegistered(user)) then
|
||||
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)
|
||||
self:send(ip,"!identity! ALREADYLOGGEDIN <-|nil|->",port)
|
||||
return
|
||||
end
|
||||
local handle=self:loginUserIn(user,cid) -- binds the cid to username
|
||||
self:send(ip,"!identity! LOGINGOOD <-|"..bin.ToStr(handle).."|->",port)
|
||||
self.OnUserLoggedIn:Fire(user,cid,ip,port)
|
||||
return
|
||||
else
|
||||
self:send(ip,"!identity! LOGINBAD <-|nil|->",port)
|
||||
return
|
||||
end
|
||||
elseif cmd=="logout" then
|
||||
self:loginUserOut(user)
|
||||
self.OnClientClosed:Fire(self,"User logged out!",cid,ip,port)
|
||||
elseif cmd=="sync" then
|
||||
local dTable = loadstring("return "..(arg4 or "{}"))()
|
||||
local handle = self:getUserDataHandle(self:userLoggedIn(cid))
|
||||
table.merge(handle,dTable)
|
||||
elseif cmd=="pass" then
|
||||
local user=arg1
|
||||
if self:_isRegistered(user) then
|
||||
self.OnPasswordForgotten:Fire(arg1,cid)
|
||||
self:send(ip,"!identity! PASSREQUESTHANDLED <-|NONE|->",port)
|
||||
else
|
||||
self:send(ip,"!identity! NOUSER <-|"..user.."|->",port)
|
||||
end
|
||||
end
|
||||
end)
|
||||
s.OnClientClosed:connect(function(self,reason,cid,ip,port)
|
||||
self.OnUserLoggerOut:Fire(self,self:userLoggedIn(cid),cid,reason)
|
||||
end)
|
||||
end)
|
||||
--Client Stuff
|
||||
net.OnClientCreated:connect(function(c)
|
||||
c.userdata={}
|
||||
c.OnUserLoggedIn=multi:newConnection()
|
||||
c.OnBadLogin=multi:newConnection()
|
||||
c.OnUserAlreadyRegistered=multi:newConnection()
|
||||
c.OnUserAlreadyLoggedIn=multi:newConnection()
|
||||
c.OnUserRegistered=multi:newConnection()
|
||||
c.OnNoUserWithName=multi:newConnection()
|
||||
c.OnPasswordRequest=multi:newConnection()
|
||||
c.OnUserRegisterRefused=multi:newConnection()
|
||||
function c:logout()
|
||||
self:send("!identity! logout 'NONE' 'NONE' 'NONE' <-|nil|->")
|
||||
end
|
||||
c.OnDataRecieved:connect(function(self,data) -- when the client recieves data this method is triggered
|
||||
local cmd,arg1 = data:match("!identity! (%S-) <%-|(.+)|%->")
|
||||
if cmd=="REGISTERED" then
|
||||
self.OnUserAlreadyRegistered:Fire(self,arg1)
|
||||
elseif cmd=="REGISTEREDGOOD" then
|
||||
self.OnUserRegistered:Fire(self,arg1)
|
||||
elseif cmd=="REGISTERREFUSED" then
|
||||
self.OnUserRegisterRefused:Fire(self,arg1)
|
||||
elseif cmd=="ALREADYLOGGEDIN" then
|
||||
self.OnUserAlreadyLoggedIn:Fire(self,arg1)
|
||||
elseif cmd=="LOGINBAD" then
|
||||
self.OnBadLogin:Fire(self)
|
||||
elseif cmd=="LOGINGOOD" then
|
||||
local dTable=loadstring("return "..(arg1 or "{}"))()
|
||||
table.merge(self.userdata,dTable)
|
||||
self.OnUserLoggedIn:Fire(self,self.userdata)
|
||||
elseif cmd=="SYNC" then
|
||||
local dTable=loadstring("return "..(arg1 or "{}"))()
|
||||
table.merge(self.userdata,dTable)
|
||||
elseif cmd=="NOUSER" then
|
||||
self.OnNoUserWithName:Fire(self,arg1)
|
||||
elseif cmd=="PASSREQUESTHANDLED" then
|
||||
self.OnPasswordRequest:Fire(self)
|
||||
end
|
||||
end)
|
||||
function c:syncUserData()
|
||||
self:send(string.format("!identity! sync 'NONE' 'NONE' 'NONE' <-|%s|->",bin.ToStr(dTable)))
|
||||
end
|
||||
function c:forgotPass(user)
|
||||
self:send(string.format("!identity! pass '%s' 'NONE' 'NONE' <-|nil|->",user))
|
||||
end
|
||||
function c:getUserDataHandle()
|
||||
return self.userdata
|
||||
end
|
||||
function c:logIn(user,pass)
|
||||
self:send(string.format("!identity! login '%s' '%s' 'NONE' <-|nil|->",user,net.hash(pass)))
|
||||
end
|
||||
function c:register(user,pass,nick,dTable)
|
||||
if dTable then
|
||||
self:send(string.format("!identity! register '%s' '%s' '%s' <-|%s|->",user,net.hash(pass),nick,bin.ToStr(dTable)))
|
||||
else
|
||||
self:send(string.format("!identity! register '%s' '%s' '%s' <-|nil|->",user,net.hash(pass),nick))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
if net.autoInit then
|
||||
net.identity:init()
|
||||
end
|
||||
483
client/net/init.lua
Normal file
483
client/net/init.lua
Normal file
@ -0,0 +1,483 @@
|
||||
function string.trim(s)
|
||||
local from = s:match"^%s*()"
|
||||
return from > #s and "" or s:match(".*%S", from)
|
||||
end
|
||||
socket=require("socket")
|
||||
net={}
|
||||
net.Version={1,0,0}
|
||||
net.OnServerCreated=multi:newConnection()
|
||||
net.OnClientCreated=multi:newConnection()
|
||||
net.loadedModules={}
|
||||
net.autoInit=true
|
||||
function net:registerModule(mod,version)
|
||||
table.insert(self.loadedModules,mod)
|
||||
net[mod]={}
|
||||
if version then
|
||||
net[mod].Version=version
|
||||
else
|
||||
net[mod].Version={1,0,0}
|
||||
end
|
||||
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
|
||||
-- UDP Stuff
|
||||
function net:newServer(port,servercode)
|
||||
local c={}
|
||||
c.udp=assert(socket.udp())
|
||||
c.udp:settimeout(0)
|
||||
c.udp:setsockname("*", port)
|
||||
c.ips={}
|
||||
c.Type="udp"
|
||||
c.port=port
|
||||
c.ids={}
|
||||
c.servercode=servercode
|
||||
c.bannedIPs={}
|
||||
c.bannedCIDs={}
|
||||
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
|
||||
function c:send(ip,data,port,cid)
|
||||
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 ingore data from a banned client!")
|
||||
return
|
||||
end
|
||||
if data then
|
||||
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
|
||||
self.OnDataRecieved: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
|
||||
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.OnPongRecieved=multi:newConnection()
|
||||
c.OnClientClosed=multi:newConnection()
|
||||
c.connectiontest=multi:newAlarm(30)
|
||||
c.connectiontest.link=c
|
||||
c.connectiontest:OnRing(function(alarm)
|
||||
print("pinging clients!")
|
||||
alarm.link:sendAll("ping")
|
||||
alarm:Reset()
|
||||
end)
|
||||
multi:newLoop(function()
|
||||
c:update()
|
||||
end)
|
||||
net.OnServerCreated:Fire(c)
|
||||
return c
|
||||
end
|
||||
|
||||
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.cid="NIL"
|
||||
c.lastPing=0
|
||||
c.Type="udp"
|
||||
c.servercode=servercode
|
||||
c.autoReconnect=true
|
||||
function c:pollPing(n)
|
||||
return not((os.clock()-self.lastPing)<(n or 60))
|
||||
end
|
||||
function c:send(data)
|
||||
self.udp:send("C!"..self.cid..data)
|
||||
end
|
||||
function c:sendRaw(data)
|
||||
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 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
|
||||
self.OnDataRecieved:Fire(self,data)
|
||||
end
|
||||
end
|
||||
end
|
||||
function c:reconnect()
|
||||
if not nonluaServer then
|
||||
self.cid="NIL"
|
||||
c.udp:send("I!")
|
||||
end
|
||||
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:reconnect()
|
||||
else
|
||||
self.link.OnServerNotAvailable:Fire("Connection to server lost: ping timeout!")
|
||||
end
|
||||
end)
|
||||
c.pingEvent.link=c
|
||||
c.OnPingRecieved=multi:newConnection()
|
||||
c.OnDataRecieved=multi:newConnection()
|
||||
c.OnServerNotAvailable=multi:newConnection()
|
||||
c.OnClientReady=multi:newConnection()
|
||||
c.notConnected=multi:newFunction(function(self)
|
||||
self:hold(3)
|
||||
if self.link:IDAssigned()==false then
|
||||
self.link.OnServerNotAvailable:Fire("Can't connect to the server: no response from server")
|
||||
end
|
||||
end)
|
||||
c.notConnected.link=c
|
||||
if not nonluaServer then
|
||||
c.udp:send("I!")
|
||||
end
|
||||
multi:newLoop(function()
|
||||
c:update()
|
||||
end)
|
||||
multi:newJob(function() c.notConnected() end)
|
||||
net.OnClientCreated:Fire(c)
|
||||
return c
|
||||
end
|
||||
--TCP Stuff
|
||||
function net:newTCPServer(port)
|
||||
local c={}
|
||||
c.tcp=assert(socket.bind("*", port))
|
||||
c.tcp:settimeout(0)
|
||||
c.ip,c.port=c.tcp:getsockname()
|
||||
c.ips={}
|
||||
c.port=port
|
||||
c.ids={}
|
||||
c.bannedIPs={}
|
||||
c.Type="tcp"
|
||||
c.rMode="*l"
|
||||
c.sMode="*l"
|
||||
c.updaterRate=1
|
||||
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.sMode=="*l" then
|
||||
handle:send(data.."\n")
|
||||
else
|
||||
handle:send(data)
|
||||
end
|
||||
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: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)
|
||||
updater:OnUpdate(function(self)
|
||||
local data, err = self.client:receive(self.Link.rMode)
|
||||
if err=="closed" then
|
||||
for i=1,#self.Link.ips do
|
||||
if self.Link.ips[i]==self.client then
|
||||
table.remove(self.Link.ips,i)
|
||||
end
|
||||
end
|
||||
self.Link.OnClientClosed:Fire(self.Link,"Client Closed Connection!",self.client,self.client,ip)
|
||||
self:Destroy()
|
||||
end
|
||||
if data then
|
||||
if net.inList(self.Link.bannedIPs,ip) then
|
||||
print("We will ingore data from a banned client!")
|
||||
return
|
||||
end
|
||||
self.Link.OnDataRecieved:Fire(self.Link,data,self.client,self.client,ip)
|
||||
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.Link.OnClientsModulesList:Fire(list,self.client,self.client,ip)
|
||||
end
|
||||
end
|
||||
end)
|
||||
updater:setSkip(self.updaterRate)
|
||||
updater.client=client
|
||||
updater.Link=self
|
||||
end
|
||||
end
|
||||
c.OnClientsModulesList=multi:newConnection()
|
||||
c.OnDataRecieved=multi:newConnection()
|
||||
c.OnClientClosed=multi:newConnection()
|
||||
multi:newLoop(function()
|
||||
c:update()
|
||||
end)
|
||||
net.OnServerCreated:Fire(c)
|
||||
return c
|
||||
end
|
||||
|
||||
function net:newTCPClient(host,port)
|
||||
local c={}
|
||||
c.ip=assert(socket.dns.toip(host))
|
||||
c.port=post
|
||||
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"
|
||||
function c:setReceiveMode(mode)
|
||||
self.rMode=mode
|
||||
end
|
||||
function c:setSendMode(mode)
|
||||
self.sMode=mode
|
||||
end
|
||||
function c:send(data)
|
||||
if self.sMode=="*l" then
|
||||
self.tcp:send(data.."\n")
|
||||
else
|
||||
self.tcp:send(data)
|
||||
end
|
||||
end
|
||||
function c:sendRaw(data)
|
||||
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()
|
||||
local data=self.tcp:receive()
|
||||
if data then
|
||||
self.OnDataRecieved:Fire(self,data)
|
||||
end
|
||||
end
|
||||
function c:reconnect()
|
||||
self.ip=assert(socket.dns.toip(host))
|
||||
self.tcp=socket.connect(self.ip,self.port)
|
||||
if not self.tcp then
|
||||
print("Can't connect to the server: no response from server")
|
||||
return
|
||||
end
|
||||
self.tcp:settimeout(0)
|
||||
self.tcp:setoption('tcp-nodelay', true)
|
||||
self.tcp:setoption('keepalive', true)
|
||||
end
|
||||
c.event=multi:newEvent(function(event)
|
||||
return event.link:IDAssigned()
|
||||
end)
|
||||
c.event:OnEvent(function(event)
|
||||
event.link.OnClientReady:Fire(event.link)
|
||||
end)
|
||||
c.event.link=c
|
||||
c.OnClientReady=multi:newConnection()
|
||||
c.OnDataRecieved=multi:newConnection()
|
||||
multi:newLoop(function()
|
||||
c:update()
|
||||
end)
|
||||
net.OnClientCreated:Fire(c)
|
||||
return c
|
||||
end
|
||||
179
client/net/sft.lua
Normal file
179
client/net/sft.lua
Normal file
@ -0,0 +1,179 @@
|
||||
require("net")
|
||||
--General Stuff
|
||||
--[[ What this module does!
|
||||
Adds
|
||||
|
||||
]]
|
||||
function io.fileExists(path)
|
||||
g=io.open(path or '','r')
|
||||
if path =='' then
|
||||
p='empty path'
|
||||
return nil
|
||||
end
|
||||
if g~=nil and true or false then
|
||||
p=(g~=nil and true or false)
|
||||
end
|
||||
if g~=nil then
|
||||
io.close(g)
|
||||
else
|
||||
return false
|
||||
end
|
||||
return p
|
||||
end
|
||||
net:registerModule("sft",{1,0,0})
|
||||
function net.sft:init() -- calling this initilizes the library and binds it to the servers and clients created
|
||||
--Server Stuff
|
||||
net.OnServerCreated:connect(function(s)
|
||||
print("The sft(Simple File Transfer) Module has been loaded onto the server!")
|
||||
if s.Type~="tcp" then
|
||||
print("It is recomended that you use tcp to transfer files!")
|
||||
end
|
||||
s.transfers={}
|
||||
s.OnUploadRequest=multi:newConnection() -- create a sft event
|
||||
s.OnFileUploaded=multi:newConnection() -- create a sft event
|
||||
s.OnDownloadRequest=multi:newConnection()
|
||||
s.OnDataRecieved:connect(function(self,data,cid,ip,port) -- when the server recieves data this method is triggered
|
||||
--First Lets make sure we are getting sft data
|
||||
--filename,dat=data:match("!sft! (%S-) (%S+)")
|
||||
local cmd,arg1,arg2=data:match("!sft! (%S-) (%S-) (.+)")
|
||||
if cmd=="tstart" then
|
||||
local rets=self.OnUploadRequest:Fire(self,cid,ip,port)
|
||||
for i=1,#rets do
|
||||
if rets[i][1]==false then
|
||||
print("Server refused to accept upload request!")
|
||||
self:send(ip,"!sft! CANTUPLOAD NIL NIL",port)
|
||||
return
|
||||
end
|
||||
end
|
||||
local ID,streamable=arg1:match("(.+)|(.+)")
|
||||
local file,hash=arg2:match("(.+)|(.+)")
|
||||
if streamable~="NIL" then
|
||||
self.transfers[ID]={bin.stream(streamable,false),hash,file}
|
||||
else
|
||||
self.transfers[ID]={bin.new(""),hash,file}
|
||||
end
|
||||
return
|
||||
elseif cmd=="transfer" then
|
||||
if self.transfers[arg1]~=nil then
|
||||
self.transfers[arg1][1]:tackE(bin.fromhex(arg2))
|
||||
--print(self.transfers[arg1][1]:getSize())
|
||||
end
|
||||
return
|
||||
elseif cmd=="tend" then
|
||||
if self.transfers[arg1]~=nil then
|
||||
if self.transfers[arg1][1]:getHash(32)==self.transfers[arg1][2] then
|
||||
self.OnFileUploaded:Fire(self,self.transfers[arg1][1],self.transfers[arg1][3],"Hash Good!")
|
||||
else
|
||||
print("Hash Error!")
|
||||
self.OnFileUploaded:Fire(self,self.transfers[arg1][1],self.transfers[arg1][3],"Hash Bad!")
|
||||
end
|
||||
self.transfers[arg1]=nil
|
||||
end
|
||||
return
|
||||
end
|
||||
local filename=cmd
|
||||
local dat=arg1
|
||||
if filename==nil then return end
|
||||
local rets=self.OnDownloadRequest:Fire(self,cid,ip,port)
|
||||
for i=1,#rets do
|
||||
if rets[i][1]==false then
|
||||
print("Server refused to accept download request!")
|
||||
self:send(ip,"!sft! CANTREQUEST NIL NIL",port)
|
||||
return
|
||||
end
|
||||
end
|
||||
if io.fileExists(filename) then
|
||||
--Lets first load the file
|
||||
local file=bin.stream(filename,false)
|
||||
local size=file:getSize()
|
||||
local pieceSize=512
|
||||
local pieces=math.ceil(size/pieceSize)
|
||||
local step=multi:newStep(1,pieces)
|
||||
step.TransferID=tostring(math.random(1000,9999))
|
||||
step.sender=self
|
||||
step.ip=ip
|
||||
step.port=port
|
||||
step.pieceSize=pieceSize
|
||||
step:OnStart(function(self)
|
||||
self.sender:send(self.ip,"!sft! TSTART "..self.TransferID.."|"..dat.." "..filename.."|"..file:getHash(32),self.port)
|
||||
end)
|
||||
step:OnStep(function(pos,self)
|
||||
self:hold(.01)
|
||||
self.sender:send(self.ip,"!sft! TRANSFER "..self.TransferID.." "..bin.tohex(file:sub(((self.pieceSize*pos)+1)-self.pieceSize,self.pieceSize*pos)),self.port)
|
||||
end)
|
||||
step:OnEnd(function(self)
|
||||
self.sender:send(self.ip,"!sft! TEND "..self.TransferID.." NIL",self.port)
|
||||
end)
|
||||
else
|
||||
self:send(ip,"!sft! CANTREQUEST NIL NIL",port)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
--Client Stuff
|
||||
net.OnClientCreated:connect(function(c)
|
||||
c.transfers={}
|
||||
c.OnTransferStarted=multi:newConnection() -- create a sft event
|
||||
c.OnTransferFinished=multi:newConnection() -- create a sft event
|
||||
c.OnFileRequestFailed=multi:newConnection() -- create a sft event
|
||||
c.OnFileUploadFailed=multi:newConnection() -- create a sft event
|
||||
c.OnDataRecieved:connect(function(self,data) -- when the client recieves data this method is triggered
|
||||
--First Lets make sure we are getting sft data
|
||||
local cmd,arg1,arg2=data:match("!sft! (%S-) (%S-) (.+)")
|
||||
if cmd=="TSTART" then
|
||||
local ID,streamable=arg1:match("(.+)|(.+)")
|
||||
local file,hash=arg2:match("(.+)|(.+)")
|
||||
if streamable~="NIL" then
|
||||
self.transfers[ID]={bin.stream(streamable,false),hash,file}
|
||||
else
|
||||
self.transfers[ID]={bin.new(""),hash,file}
|
||||
end
|
||||
self.OnTransferStarted:Fire(self)
|
||||
elseif cmd=="TRANSFER" then
|
||||
self.transfers[arg1][1]:tackE(bin.fromhex(arg2))
|
||||
elseif cmd=="TEND" then
|
||||
if self.transfers[arg1][1]:getHash(32)==self.transfers[arg1][2] then
|
||||
self.OnTransferFinished:Fire(self,self.transfers[arg1][1],self.transfers[arg1][3],"Hash Good!")
|
||||
else
|
||||
print("Hash Error!")
|
||||
self.OnTransferFinished:Fire(self,self.transfers[arg1][1],self.transfers[arg1][3],"Hash Bad!")
|
||||
end
|
||||
self.transfers[arg1]=nil
|
||||
elseif cmd=="CANTREQUEST" then
|
||||
self.OnFileRequestFailed:Fire(self,"Could not request the file for some reason!")
|
||||
elseif cmd=="CANTUPLOAD" then
|
||||
self.OnFileUploadFailed:Fire(self,"Could not upload the file for some reason!")
|
||||
end
|
||||
end)
|
||||
function c:uploadFile(filename)
|
||||
if io.fileExists(filename) then
|
||||
local file=bin.stream(filename,false)
|
||||
local size=file:getSize()
|
||||
local pieceSize=512
|
||||
local pieces=math.ceil(size/pieceSize)
|
||||
local step=multi:newStep(1,pieces)
|
||||
step.TransferID=tostring(math.random(1000,9999))
|
||||
step.sender=self
|
||||
step.pieceSize=pieceSize
|
||||
step:OnStart(function(self)
|
||||
self.sender:send("!sft! tstart "..self.TransferID.."|NIL "..filename.."|"..file:getHash(32))
|
||||
end)
|
||||
step:OnStep(function(pos,self)
|
||||
self:hold(.01)
|
||||
self.sender:send("!sft! transfer "..self.TransferID.." "..bin.tohex(file:sub(((self.pieceSize*pos)+1)-self.pieceSize,self.pieceSize*pos)))
|
||||
end)
|
||||
step:OnEnd(function(self)
|
||||
print("Request done!")
|
||||
self.sender:send("!sft! tend "..self.TransferID.." NIL")
|
||||
end)
|
||||
else
|
||||
self.OnFileUploadFailed:Fire(self,filename,"File does not exist!")
|
||||
end
|
||||
end
|
||||
function c:requestFile(filename)
|
||||
self:send("!sft! "..filename.." NIL NIL NIL")
|
||||
end
|
||||
end)
|
||||
end
|
||||
if net.autoInit then
|
||||
net.sft.init()
|
||||
end
|
||||
BIN
client/them.png
Normal file
BIN
client/them.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
client/you.png
Normal file
BIN
client/you.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Loading…
x
Reference in New Issue
Block a user