196 lines
5.4 KiB
Lua
196 lines
5.4 KiB
Lua
local sendCHN=love.thread.getChannel('HTTP_inputChannel')
|
|
local recvCHN=love.thread.getChannel('HTTP_outputChannel')
|
|
|
|
local threads={}
|
|
local threadCount=0
|
|
local threadCode=[[
|
|
local id=...
|
|
|
|
local http=require'socket.http'
|
|
local ltn12=require'ltn12'
|
|
|
|
local sendCHN=love.thread.getChannel('HTTP_inputChannel')
|
|
local recvCHN=love.thread.getChannel('HTTP_outputChannel')
|
|
local sleep=require'love.timer'.sleep
|
|
|
|
while true do
|
|
-- local arg=sendCHN:demand()
|
|
-- Warning: workaround for love.js
|
|
while sendCHN:getCount()==0 do sleep(.0626) end
|
|
local arg=sendCHN:pop()
|
|
|
|
if arg._destroy then
|
|
recvCHN:push{
|
|
destroy=true,
|
|
id=id,
|
|
}
|
|
break
|
|
end
|
|
|
|
-- print("\n------SEND------") for k,v in next,arg do print(k,v) end
|
|
local data={}
|
|
local _,code,detail=http.request{
|
|
method=arg.method,
|
|
url=arg.url,
|
|
headers=arg.headers,
|
|
source=ltn12.source.string(arg.body),
|
|
|
|
sink=ltn12.sink.table(data),
|
|
}
|
|
|
|
local result={
|
|
pool=arg.pool,
|
|
poolPtr=arg.poolPtr,
|
|
code=code,
|
|
body=table.concat(data),
|
|
detail=detail,
|
|
}
|
|
-- print("\n------RECV------") for k,v in next,result do print(k,v) end
|
|
recvCHN:push(result)
|
|
end
|
|
]]
|
|
|
|
local msgPool=setmetatable({},{
|
|
__index=function(self,k)
|
|
self[k]={}
|
|
return self[k]
|
|
end
|
|
})
|
|
|
|
local HTTP={
|
|
_msgCount=0,
|
|
_trigTime=0,
|
|
_trigInterval=.26,
|
|
_host=false,
|
|
}
|
|
|
|
local function addThread(num)
|
|
for i=1,26 do
|
|
if num<=0 then break end
|
|
if not threads[i] then
|
|
threads[i]=love.thread.newThread(threadCode)
|
|
threads[i]:start(i)
|
|
threadCount=threadCount+1
|
|
num=num-1
|
|
end
|
|
end
|
|
end
|
|
|
|
function HTTP.request(arg)
|
|
arg.method=arg.method or arg.body and 'POST' or 'GET'
|
|
if arg.url then
|
|
assert(type(arg.url)=='string',"Field 'url' need string, get "..type(arg.url))
|
|
if arg.url:sub(1,7)~='http://' then arg.url='http://'..arg.url end
|
|
else
|
|
arg.url=HTTP._host or error("Need url=<string> or set default host with HTTP.setHost")
|
|
end
|
|
if arg.path then
|
|
assert(type(arg.path)=='string',"Field 'path' need string, get "..type(arg.path))
|
|
arg.url=arg.url..arg.path
|
|
end
|
|
assert(arg.headers==nil or type(arg.headers)=='table',"Field 'headers' need table, get "..type(arg.headers))
|
|
|
|
if arg.body~=nil then
|
|
assert(type(arg.body)=='table',"Field 'body' need table, get "..type(arg.body))
|
|
arg.body=JSON.encode(arg.body)
|
|
if not arg.headers then arg.headers={} end
|
|
TABLE.cover({
|
|
['Content-Type']="application/json",
|
|
['Content-Length']=#arg.body,
|
|
},arg.headers)
|
|
end
|
|
|
|
if arg.pool==nil then arg.pool='_default' end
|
|
arg.poolPtr=tostring(msgPool[arg.pool])
|
|
|
|
sendCHN:push(arg)
|
|
end
|
|
|
|
function HTTP.reset()
|
|
for i=1,#threads do
|
|
threads[i]:release()
|
|
threads[i]=false
|
|
end
|
|
TABLE.clear(msgPool)
|
|
sendCHN:clear()
|
|
recvCHN:clear()
|
|
addThread(threadCount)
|
|
end
|
|
function HTTP.setThreadCount(n)
|
|
assert(type(n)=='number' and n>=1 and n<=26 and n%1==0,"function HTTP.setThreadCount(n): n must be integer from 1 to 26")
|
|
if n>threadCount then
|
|
addThread(n-threadCount)
|
|
else
|
|
for _=n+1,threadCount do
|
|
sendCHN:push{_destroy=true}
|
|
end
|
|
end
|
|
end
|
|
function HTTP.getThreadCount()
|
|
return threadCount
|
|
end
|
|
function HTTP.setInterval(interval)
|
|
if interval<=0 then interval=1e99 end
|
|
assert(type(interval)=='number',"Interval must be number")
|
|
HTTP._trigInterval=interval
|
|
end
|
|
function HTTP.clearPool(pool)
|
|
if pool==nil then pool='_default' end
|
|
assert(type(pool)=='string',"Pool must be nil or string")
|
|
HTTP._msgCount=HTTP._msgCount-#msgPool[pool]
|
|
msgPool[pool]={}
|
|
end
|
|
function HTTP.deletePool(pool)
|
|
assert(type(pool)=='string',"Pool must be nil or string")
|
|
assert(pool~='_default',"Cannot delete _default pool. What are you doing?")
|
|
HTTP._msgCount=HTTP._msgCount-#msgPool[pool]
|
|
msgPool[pool]=nil
|
|
end
|
|
function HTTP.pollMsg(pool)
|
|
if not (type(pool)=='nil' or type(pool)=='string') then error("Pool must be nil or string") end
|
|
HTTP.update()
|
|
local p=msgPool[pool or '_default']
|
|
if #p>0 then
|
|
HTTP._msgCount=HTTP._msgCount-1
|
|
return table.remove(p)
|
|
end
|
|
end
|
|
function HTTP.setHost(host)
|
|
assert(type(host)=='string',"Host must be string")
|
|
if host:sub(1,7)~='http://' then host='http://'..host end
|
|
HTTP._host=host
|
|
end
|
|
|
|
function HTTP.update(dt)
|
|
if dt then
|
|
HTTP._trigTime=HTTP._trigTime+dt
|
|
if HTTP._trigTime>HTTP._trigInterval then
|
|
HTTP._trigTime=HTTP._trigTime%HTTP._trigInterval
|
|
else
|
|
return
|
|
end
|
|
end
|
|
while recvCHN:getCount()>0 do
|
|
local m=recvCHN:pop()
|
|
if m.destroy then
|
|
threads[m.id]:release()
|
|
threads[m.id]=false
|
|
elseif tostring(msgPool[m.pool])==m.poolPtr then -- If pool were cleared, discard this datapack
|
|
table.insert(msgPool[m.pool],{
|
|
code=m.code,
|
|
body=m.body,
|
|
detail=m.detail,
|
|
})
|
|
HTTP._msgCount=HTTP._msgCount+1
|
|
end
|
|
end
|
|
end
|
|
|
|
setmetatable(HTTP,{__call=function(self,arg)
|
|
return self.request(arg)
|
|
end,__metatable=true})
|
|
|
|
HTTP.reset()
|
|
|
|
return HTTP
|