Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local Tag="hdata"
- -- HELPERS -------------------------------------------------------------
- local tostring=tostring
- local setmetatable=setmetatable
- local hook=hook
- local table=table
- local pairs=pairs
- local type=type
- local string=string
- local HTTPGet=HTTPGet
- local class do -- http://lua-users.org/wiki/SimpleLuaClasses
- -- class.lua
- -- Compatible with Lua 5.1 (not 5.0).
- class = function(base, init)
- local c = {} -- a new class instance
- if not init and type(base) == 'function' then
- init = base
- base = nil
- elseif type(base) == 'table' then
- -- our new class is a shallow copy of the base class!
- for i,v in pairs(base) do
- c[i] = v
- end
- c._base = base
- end
- -- the class will be the metatable for all its objects,
- -- and they will look up their methods in it.
- c.__index = c
- -- expose a constructor which can be called by <classname>(<args>)
- local mt = {}
- mt.__call = function(class_tbl, ...)
- local obj = {}
- setmetatable(obj,c)
- if init then
- init(obj,...)
- else
- -- make sure that any stuff from the base class is initialized!
- if base and base.init then
- base.init(obj, ...)
- end
- end
- return obj
- end
- c.init = init
- c.is_a = function(self, klass)
- local m = getmetatable(self)
- while m do
- if m == klass then return true end
- m = m._base
- end
- return false
- end
- setmetatable(c, mt)
- return c
- end
- end -- http://lua-users.org/wiki/SimpleLuaClasses
- --[[TEST
- local _class = class(function(a,name)
- a.name = name
- end)
- --_class.__newindex=function(a,b,c) print("asserttest","newindex",type(a),type(b),type(c)) rawset(a,b,c) end
- _class.__tostring=function(s)return s.name end
- local name="test"
- local _=_class(name)
- assert(tostring(_)==name)
- _.testkey="testvalue"
- _=nil
- _class=nil
- --]]--ETEST
- local insert=table.insert
- local remove=table.remove
- local Empty=table.Empty
- local function unescape (str)
- str = string.gsub (str, "+", " ")
- str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end)
- str = string.gsub (str, "\r\n", "\n")
- return str
- end
- local function escape (str)
- str = string.gsub (str, "\n", "\r\n")
- str = string.gsub (str, "([^0-9a-zA-Z ])", -- locale independent
- function (c) return string.format ("%%%02X", string.byte(c)) end)
- str = string.gsub (str, " ", "+")
- return str
- end
- -------------------------------------------------------------
- -------------------------------------------------------------
- -------------------------------------------------------------
- local FIFO do -- STACK IMPLEMENTATION
- FIFO=class()
- function FIFO:__tostring() return "< Stack "..tostring(self:len()).." >" end
- -- Pop
- function FIFO:pop()
- return remove( self , self.lilo and #self or 1 )
- end
- -- push
- function FIFO.push(a,b)
- insert( a , b )
- return a
- end
- function FIFO:len()
- return #self
- end
- function FIFO:length()
- return #self
- end
- function FIFO:clear()
- return Empty( self )
- end
- end -- STACK IMPLEMENTATION
- --[[TEST
- local _=FIFO()
- assert(_:push("a")==_)
- assert(_:push("b")==_)
- assert(_:pop()=="a")
- print("asserttest",_)
- assert(_:pop()=="b")
- assert(!_:pop())
- _=nil
- --]]--ETEST
- local thinks do -- THINK IMPLEMENTATION
- local Now=SysTime
- thinks=class(function(self,add_shutdown_hook)
- if add_shutdown_hook==true then
- print("adding shutdown hook for",self)
- hook.Add('Shutdown',self,function()
- print(self,"shutting down with thinking")
- if not self or not self.ThinkForever then return end
- print(self,"Finishing thinking")
- self:ThinkForever(10)
- end)
- end
- end)
- meta.name="Think Queue"
- function thinks:__tostring() return "< ".."Thinks".." - "..table.Count(self).." thinks >" end
- function thinks:Add(obj,thinkfunc)
- self[obj]=thinkfunc or true
- if not hook:GetTable().Think[Tag] then
- --dprint("Adding think")
- hook.Add('Think',Tag,function() self:Think() end)
- end
- end
- function thinks:Remove(obj)
- if self[obj] then
- self[obj]=nil
- return true
- end
- return false
- end
- function thinks:Exec( thinkfunc,obj )
- local bOk, strReturn = pcall( thinkfunc,obj )
- if !bOk then
- ErrorNoHalt( "Think failure:"+strReturn )
- end
- end
- function thinks:Think()
- local done=true
- for obj,thinkfunc in pairs(self) do
- done=false
- self:Exec( thinkfunc,obj )
- end
- if done then
- --dprint("Removing thinking")
- hook.Remove('Think',Tag)
- end
- end
- function thinks:ThinkForever(timeout)
- -- optimization
- if table.Count(self) == 0 then return end
- local started=Now()
- local done=false
- if !timeout then error"no timeout specified" end
- while not done do
- done=true
- for obj,thinkfunc in pairs(self) do
- done=false
- self:Exec( thinkfunc,obj )
- end
- if (Now()-started) < timeout then
- ErrorNoHalt(tostring(self).." exceeded timeout ("..timeout.." seconds), killed!\n")
- break
- end
- end
- if done then
- print(self,"Emptied queue")
- end
- end
- end -- THINK IMPLEMENTATION
- --[[TEST
- local _=thinks()
- local boo=false
- _:Add("!",function() boo=true _:Remove("!") end)
- _:Add("_",function() end)
- _:Think()_:Think()_:Think()_:Think()_:Think()
- assert(boo==true)
- print("asserttest",_)
- assert(_:Remove("_")==true)
- print("asserttest",_)
- _:Think()
- --]]--ETEST
- local thinks=thinks(true)
- local HTTPQueryObject do -- HTTP QUERY OBJECT HELPERS
- HTTPQueryObject=class()
- function HTTPQueryObject:__tostring()
- return "< ".."HTTPQueryObject".." - Timeout "..tostring(self:GetTimeout() or 0).." - Started "..tostring(self:GetStarted()).." >"
- end
- AccessorFunc(HTTPQueryObject,"__headers","Header",FORCE_STRING)
- AccessorFunc(HTTPQueryObject,"__callback","Callback")
- AccessorFunc(HTTPQueryObject,"__timeout","Timeout",FORCE_NUMBER)
- AccessorFunc(HTTPQueryObject,"__started","Started",FORCE_BOOL)
- end -- HTTP QUERY OBJECT HELPERS
- --[[TEST
- local _=HTTPQueryObject()
- _:SetStarted(true)
- assert(_:GetStarted()==true)
- print("asserttest",_)
- assert(tostring(_)!="")
- _=nil
- --]]--ETEST
- local queryqueue do -- QUERY QUEUE IMPLEMENTATION
- queryqueue = class(function( tbl, host )
- local http = tbl:GetHTTPGet()
- assert(http:Finished()==false)
- tbl:__sethost(host or "http://gmod.iriz.org:20090")
- tbl.stack=FIFO()
- return tbl
- end)
- function queryqueue:__tostring()
- return "< ".."Query Object".." >"
- end
- function queryqueue:GetProcess()
- return self.__proc
- end
- function queryqueue:SetProcess(proc)
- self.__proc = proc
- end
- function queryqueue:GetHTTPGet(new)
- if new or not self.__HTTPGet then
- self.__HTTPGet=HTTPGet()
- end
- return self.__HTTPGet
- end
- -- not finished if not even started!!
- function queryqueue:HTTPIsFinished()
- return self:GetHTTPGet():Finished()
- end
- function queryqueue:GetCurrentData( raw )
- local buf = self:GetHTTPGet():GetBuffer()
- local len = self:GetHTTPGet():DownloadSize()
- -- http.Get does this for some reason...
- local data = raw and buf or buf:gsub( "\r\n","\n")
- return data,len
- end
- function queryqueue:Download(host,header)
- if header and header:len() > 0 then -- hack
- header="Accept: */*\n"..header
- else
- header = ""
- end
- self:GetHTTPGet():Download(host,header)
- end
- function queryqueue:Process(proc)
- local started = proc:GetStarted()
- if not started then
- proc:SetStarted(true)
- self:GetHTTPGet(true) -- We need to reset it :\
- --dprint("Started processing new",proc,"to",self:gethost())
- --proc:GetTimeout()
- self:Download( self:gethost(), proc:GetHeader())
- end
- if proc:GetStarted() and self:HTTPIsFinished() then
- local proc = self:GetProcess()
- self:SetProcess( nil )
- local callback = proc:GetCallback()
- if not callback then
- --dprint("processed",proc,"without callbacks?")
- return
- end
- local buf,len=self:GetCurrentData()
- local ok, ret = pcall( callback, buf, len )
- if not ok then
- ErrorNoHalt( meta.name.." callback error: "+ret+"\n" )
- end
- end
- end
- function queryqueue:Think()
- local proc=self:GetProcess()
- if proc then
- self:Process(proc)
- return
- end
- if self:GetProcess() then return end
- local newdata=self.stack:pop()
- if newdata then
- --print("grabbing new process",newdata)
- self:SetProcess( newdata )
- return
- end
- --dprint("stopped thinking",self)
- thinks:Remove(self)
- end
- function queryqueue:Wake()
- if self.stack:len() > 0 then
- --dprint("waking up")
- thinks:Add(self,self.Think)
- end
- end
- function queryqueue:query(header,callback,timeout)
- local proc = HTTPQueryObject()
- if header then
- proc:SetHeader(header)
- end
- if callback then
- proc:SetCallback(callback)
- end
- if timeout then
- proc:SetTimeout(timeout)
- end
- self.stack:push(proc)
- self:Wake()
- end
- function queryqueue:gethost()
- return self.def_host
- end
- function queryqueue:__sethost(host)
- self.def_host = host
- end
- function queryqueue:GetQueueLength()
- return self.stack:len()
- end
- end -- QUERY QUEUE IMPLEMENTATION
- --[[TEST
- local host="http://iriz.org"
- _G._=queryqueue(host)
- local _=_G._
- assert(_:HTTPIsFinished()==false)
- _:query(nil,function(a,b)print("callback:",a:len()) assert(a:len()>0) end,0)
- _:query(nil,function(a,b)print("callback:",a:len()) assert(a:len()>0) end,0)
- assert(_:GetQueueLength()==2)
- print("host:",_:gethost())
- assert(_:gethost()==host)
- --]]--ETEST
- local hyperdata do -- HYPERDATA IMPLEMENTATION
- hyperdata=class(function(tbl,host)
- tbl.httpqueue=queryqueue(host or "http://gmod.iriz.org:20090") or "HURR??"
- --dprint("New",self)
- return tbl
- end)
- function hyperdata:__tostring()
- return "< ".."Hyperdata".." - "..tostring(self:gethost()).." >"
- end
- function hyperdata:gethost()
- return self:GetQueryQueue():gethost()
- end
- function hyperdata:test(callback)
- http.Get(self:gethost(),"",function(_,b)
- callback(b>0)
- end)
- end
- function hyperdata:GetQueryQueue()
- return self.httpqueue
- end
- function hyperdata:GetTaskCount()
- return self.httpqueue:GetQueueLength()
- end
- function hyperdata:request_kv(keyvalues,callback)
- if !keyvalues then error"need juice" end
- local payload=""
- local first=true
- for k,v in pairs(keyvalues) do
- --dprint"ADDING SHIT"
- local str=(first and "" or "\n")..escape(tostring(k))..": "..escape(tostring(v))
- first=false
- payload=payload..str
- end
- self:GetQueryQueue():query(payload,callback,0)
- end
- end -- HYPERDATA IMPLEMENTATION
- /*
- local _=hyperdata("http://iriz.org:20090")
- --_:test(function(works)
- -- assert(works)
- _:request_kv(
- { type="test",
- Data=data,
- },function(str,len)
- local binary=str:find("\0",1,true)
- print("Backend response ("..len.."): '"..tostring(binary and "binary data" or str).."'")
- if binary then
- file.Write("bintest_recv.txt",str)
- if data!=str then
- for i=1,#data do
- if data[i]!=str[i] then
- print("DATA DIFF AT POS "..i,string.byte(data[i]),string.byte(str[i]))
- print("diffbytes:","'"..data[i].."'","'"..str[i].."'")
- break
- end
- end
- else
- print"data is the same :o"
- end
- end
- end)
- --end)*/
- /*
- _G.hcoins=hyperdata("http://iriz.org:20090")
- local coins=_G.hcoins
- function coins:GetCoins(steamid64,callback)
- local steamid64=steamid64
- coins:request_kv(
- { type="getcoins",
- sid64=steamid64,
- },function(str,len)
- if len==0 then
- callback(false,"no reply")
- end
- if str:sub(1,6)!="COINS=" then
- if str:find("NOTFOUND",1,true) then
- callback(-1,steamid64)
- end
- callback(false,str)
- return
- end
- local coins=tonumber(str:match("COINS%=(%d+)"))
- if !coins then
- callback(false,"bad coin reply:"..str)
- end
- callback(coins,steamid64)
- end)
- end
- function coins:SetCoins(steamid64,newcoins,callback)
- local steamid64=steamid64
- local newcoins=tonumber(newcoins)
- coins:request_kv(
- { type="setcoins",
- sid64=steamid64,
- coins=tostring(newcoins)
- },function(str,len)
- if len==0 then
- callback(false,"no reply")
- end
- if str:sub(1,8)!="SETCOINS" then
- callback(false,str)
- else
- callback(true,steamid64,newcoins)
- end
- end)
- end
- Say("setting coins to 5555555")
- coins:SetCoins("0",5555555,function(coins,a)Say(type(coins),coins,a)end)
- coins:GetCoins("0",function(coins)Say(type(coins),coins)end)
- */
- local playing_time=class(hyperdata,function(c,host)
- hyperdata.init(c,host)
- end)
- function playing_time:GetPlayingTimeDB(ident,callback)
- local cb=callback
- local function callback(a,b,c)
- if not a then
- print("Error while retrieveing playing time for ident ",b,c)
- end
- cb(a,b,c)
- end
- self:request_kv(
- { type = "playingtime",
- id = ident,
- },
- function(str,len)
- if len==0 then callback(false,ident,"no reply") end
- if str:find("time")!=1 then
- if str:find("NOTFOUND",1,true)==1 then
- callback(0,ident)
- end
- callback(false,ident,str)
- return
- end
- local time=tonumber(str:match("time%=(%d+)"))
- if !time then
- callback(false,ident,"bad time reply:"..str)
- end
- callback(time,ident)
- end)
- end
- function playing_time:AddPlayingTimeDB(ident,added_time_seconds,callback)
- local cb=callback
- local function callback(a,b,c)
- if not a then
- print("Error while retrieveing playing time for ident ",b,c)
- end
- cb(a,b,c)
- end
- self:request_kv({ type = "playingtime",
- id = ident,
- add=added_time_seconds
- },
- function(str,len)
- if len==0 then callback(false,"no reply") end
- if str:find("SET",1,true)!=1 then
- callback(false,ident,str)
- else
- callback(true,ident,added_time_seconds)
- end
- end)
- end
- -- get a new connection. After all players aren't depending on each others with their coins..
- local function PlayingTimeDBConnection()
- return playing_time("http://gmod.iriz.org:20090")
- end
- local Now=SysTime
- local function InitPlayingTime(pl)
- print("InitPlayingTime",pl)
- pl.ptimedb = PlayingTimeDBConnection()
- pl.ptime_offset=Now()
- pl.ptime_can_update=false
- pl.db_playing_time=0
- pl.ptimedb:GetPlayingTimeDB(tostring(pl:UniqueID()),function(time)
- if not IsValid(pl) then return end
- if time then
- print("Got playing time for",pl,"=",time)
- pl.ptime_can_update=true
- pl.db_playing_time=time
- end
- end)
- end
- local ITER_CONTINUE=true
- for k,pl in pairs(player.GetHumans()) do
- InitPlayingTime(pl)
- end
- local function UpdatePlayer( pl )
- if not pl.ptimedb then
- InitPlayingTime( pl )
- return
- end
- if not pl.ptime_can_update then
- --print("!ptime_can_update",pl)
- return ITER_CONTINUE
- end
- if pl.ptimedb:GetTaskCount()>1 then print("locked",pl,pl.ptimedb:GetTaskCount()) return end
- local accumulated=Now()-pl.ptime_offset
- local accumulated=math.floor( accumulated ) -- we don't transfer floats, just full integers
- if accumulated <1 then
- --print("Not enough accumulated",pl,"acc:",accumulated)
- return
- end
- pl.ptime_can_update=false
- pl.ptime_offset=pl.ptime_offset+accumulated
- pl.db_playing_time = pl.db_playing_time + accumulated
- print("Updating ",pl,"accu:",accumulated,"in db:",pl.db_playing_time)
- pl.ptimedb:AddPlayingTimeDB( tostring(pl:UniqueID()), accumulated, function(success)
- if not IsValid(pl) then return end
- pl.ptime_can_update=true
- if success then
- else
- print("reverting accumulation for",pl,", set failed")
- pl.ptime_offset=pl.ptime_offset - accumulated
- pl.db_playing_time = pl.db_playing_time - accumulated
- end
- end)
- end
- function _R.Player.GetPlayingTime()
- return self.db_playing_time+Now()-ptime_offset
- end
- local id=0
- local IteratePlayers = function()
- local ply
- local i=0
- while true do
- i=i+1 if i > #player.GetHumans() then break end
- local plys=#player.GetHumans()
- if plys == 0 then return end
- id=id + 1
- id =id>plys and 1 or id
- ply=player.GetHumans()[id]
- local ret = UpdatePlayer(ply)
- if ret!=ITER_CONTINUE then break end
- end
- end
- timer.Create('PlayingTime',0,0,IteratePlayers)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement