diff --git a/game/engines/default/engine/Module.lua b/game/engines/default/engine/Module.lua index b9824f7e4829c59665a5e11f09903d17e68bc225..ec24a6e6c50615ea74ef1fd918bf77d96fcf0dbe 100644 --- a/game/engines/default/engine/Module.lua +++ b/game/engines/default/engine/Module.lua @@ -232,7 +232,10 @@ function _M:instanciate(mod, name, new_game, no_reboot) table.sort(md5s) local fmd5 = md5.sumhexa(table.concat(md5s)) print("[MODULE LOADER] module MD5", fmd5, "computed in ", core.game.getTime() - t) - local hash_valid, hash_err = profile:checkModuleHash(mod.version_name, fmd5) + local hash_valid, hash_err + if mod.short_name ~= "boot" then + hash_valid, hash_err = profile:checkModuleHash(mod.version_name, fmd5) + end -- If bad hash, switch to dev profile if not hash_valid and not profile.auth then @@ -272,7 +275,7 @@ function _M:instanciate(mod, name, new_game, no_reboot) -- Disable the profile if ungood if mod.short_name ~= "boot" then if not hash_valid then - game.log("#LIGHT_RED#Profile disabled(switching to development profile) due to %s.", hash_err) + game.log("#LIGHT_RED#Profile disabled(switching to development profile) due to %s.", hash_err or "???") end end end diff --git a/game/engines/default/engine/PlayerProfile.lua b/game/engines/default/engine/PlayerProfile.lua index 832e5ab7da6402c480508953f6d6caefd1fa6ac3..8baea00de1cf95dac7bb56bd45a7d16f5c3326c4 100644 --- a/game/engines/default/engine/PlayerProfile.lua +++ b/game/engines/default/engine/PlayerProfile.lua @@ -84,8 +84,6 @@ function _M:init(name) self.login = self.generic.online.login self.pass = self.generic.online.pass self:tryAuth() - self:getConfigs("generic") - self:syncOnline("generic") end end @@ -192,15 +190,24 @@ function _M:saveModuleProfile(name, data, module, nosync) if not nosync then self:setConfigs(module, name, data) end end +function _M:checkFirstRun() + local result = self.generic.firstrun + if not result then + firstrun = { When=os.time() } + self:saveGenericProfile("firstrun", firstrun, false) + end + return result +end + ----------------------------------------------------------------------- -- Events ----------------------------------------------------------------------- function _M:eventAuth(e) if e.ok then - print("===", e.ok) self.auth = e.ok:unserialize() print("[PROFILE] Main thread got authed", self.auth.name, self.auth.email, self.auth.drupid) + self:getConfigs("generic", function(e) self:syncOnline(e.module) end) end end @@ -211,6 +218,33 @@ function _M:eventGetNews(e) end end +function _M:eventGetConfigs(e) + local data = e.data:unserialize() + local module = e.module + if not data then print("[ONLINE PROFILE] get configs") return end + for name, val in pairs(data) do + print("[ONLINE PROFILE] config ", name) + + local field = name + local f, err = loadstring(val) + if not f and err then + print("Error loading profile config: ", err) + else + if module == "generic" then + self.generic[field] = self.generic[field] or {} + self:loadData(f, self.generic[field]) + self:saveGenericProfile(field, self.generic[field], true) + else + self.modules[module] = self.modules[module] or {} + self.modules[module][field] = self.modules[module][field] or {} + self:loadData(f, self.modules[module][field]) + self:saveModuleProfile(field, self.modules[module][field], module, true) + end + end + end + if self.evt_cbs.GetConfigs then self.evt_cbs.GetConfigs(e) self.evt_cbs.GetConfigs = nil end +end + --- Got an event from the profile thread function _M:handleEvent(e) e = e:unserialize() @@ -223,55 +257,10 @@ end -- Online stuff ----------------------------------------------------------------------- -function _M:rpc(data) - -- We can work in asynchronous mode, to not delay the main game execution - if data.async and game and type(game) == "table" and not game.refuse_threads then - data.async = nil - local l = lanes.linda() - - function handler(data) - local http = require "socket.http" - local url = require "socket.url" - require "Json2" - - print("[ONLINE PROFILE] async rpc called", "http://te4.org/lua/profilesrpc.ws/"..data.action) - local body, status = http.request("http://te4.org/lua/profilesrpc.ws/"..data.action, "json="..url.escape(json.encode(data))) - if not body then - l:send("final", nil) - else - local ok, ret = pcall(json.decode, body) - l:send("final", ok and ret or nil) - end - return true - end - - local th = lanes.gen("*", handler)(data) - -- Tell the game to monitor this thread and end it when it's done - game:registerThread(th, l) - - return th, l - else - print("[ONLINE PROFILE] rpc called", "http://te4.org/lua/profilesrpc.ws/"..data.action) - local body, status = http.request("http://te4.org/lua/profilesrpc.ws/"..data.action, "json="..url.escape(json.encode(data))) - if not body then return end - local ok, ret = pcall(json.decode, body) - return ok and ret or nil - end -end - function _M:getNews(callback) print("[ONLINE PROFILE] get news") - core.profile.pushOrder("o='GetNews'") self.evt_cbs.GetNews = callback -end - -function _M:sendError(what, err) - print("[ONLINE PROFILE] sending error") - local popup = Dialog:simplePopup("Sending...", "Sending the error report. Thank you.", nil, true) - popup.__showup = nil - core.display.forceRedraw() - self:rpc{action="SendError", login=self.login, what=what, err=err, module=game.__mod_info.short_name, version=game.__mod_info.version_name} - game:unregisterDialog(popup) + core.profile.pushOrder("o='GetNews'") end function _M:tryAuth() @@ -279,41 +268,28 @@ function _M:tryAuth() core.profile.pushOrder(table.serialize{o="Login", l=self.login, p=self.pass}) end -function _M:getConfigs(module) - if not self.auth then return end - local data = self:rpc{action="GetConfigs", login=self.login, hash=self.auth.hash, module=module} - if not data then print("[ONLINE PROFILE] get configs") return end - for name, val in pairs(data) do - print("[ONLINE PROFILE] config ", name) +function _M:logOut() + core.profile.pushOrder(table.serialize{o="Logoff"}) + profile.generic.online = nil + profile.auth = nil - local field = name - local f, err = loadstring(val) - if not f and err then - print("Error loading profile config: ", err) - else - if module == "generic" then - self.generic[field] = self.generic[field] or {} - self:loadData(f, self.generic[field]) - self:saveGenericProfile(field, self.generic[field], true) - else - self.modules[module] = self.modules[module] or {} - self.modules[module][field] = self.modules[module][field] or {} - self:loadData(f, self.modules[module][field]) - self:saveModuleProfile(field, self.modules[module][field], module, true) - end - end - end + local restore = fs.getWritePath() + fs.setWritePath(engine.homepath) + fs.delete("/profiles/"..self.name.."/generic/online.profile") + if restore then fs.setWritePath(restore) end +end + +function _M:getConfigs(module, cb) + if not self.auth then return end + self.evt_cbs.GetConfigs = cb + core.profile.pushOrder(table.serialize{o="GetConfigs", module=module}) end function _M:setConfigs(module, name, val) if not self.auth then return end if name == "online" then return end - if type(val) ~= "string" then val = serialize(val) end - - local data = self:rpc{async=true, action="SetConfigs", login=self.login, hash=self.auth.hash, module=module, data={[name] = val}} - if not data then return end - print("[ONLINE PROFILE] saved ", module, name, val) + core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=table.serialize{[name] = val}}) end function _M:syncOnline(module) @@ -325,9 +301,46 @@ function _M:syncOnline(module) local data = {} for k, v in pairs(sync) do if k ~= "online" then data[k] = serialize(v) end end - local data = self:rpc{async=true, action="SetConfigs", login=self.login, hash=self.auth.hash, module=module, data=data} - if not data then return end - print("[ONLINE PROFILE] saved ", module) + core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=table.serialize(data)}) +end + +function _M:checkModuleHash(module, md5) + self.hash_valid = false +-- if not self.auth then return nil, "no online profile active" end +-- if config.settings.cheat then return nil, "cheat mode active" end +-- if game and game:isTainted() then return nil, "savefile tainted" end + core.profile.pushOrder(table.serialize{o="CheckModuleHash", module=module, md5=md5}) + + -- Wait anwser, this blocks thegame but cant really be avoided :/ + local stop = false + local ok = false + while not stop do + local evt = core.profile.popEvent() + while evt do + evt = self:handleEvent(evt) -- Bypass game handling, there is none around at this point + if evt.e == "CheckModuleHash" then + ok = evt.ok + stop = true + break + end + evt = core.profile.popEvent() + end + end + + if not ok then return nil, "bad game version" end + print("[ONLINE PROFILE] module hash is valid") + self.hash_valid = true + return true +end + +--[[ +function _M:sendError(what, err) + print("[ONLINE PROFILE] sending error") + local popup = Dialog:simplePopup("Sending...", "Sending the error report. Thank you.", nil, true) + popup.__showup = nil + core.display.forceRedraw() + self:rpc{action="SendError", login=self.login, what=what, err=err, module=game.__mod_info.short_name, version=game.__mod_info.version_name} + game:unregisterDialog(popup) end function _M:newProfile(Login, Name, Password, Email) @@ -351,25 +364,6 @@ function _M:performlogin(login, pass, name, email) end end -function _M:logOut() - profile.generic.online = nil - profile.auth = nil - - local restore = fs.getWritePath() - fs.setWritePath(engine.homepath) - fs.delete("/profiles/"..self.name.."/generic/online.profile") - if restore then fs.setWritePath(restore) end -end - -function _M:checkFirstRun() - local result = self.generic.firstrun - if not result then - firstrun = { When=os.time() } - self:saveGenericProfile("firstrun", firstrun, false) - end - return result -end - function _M:registerNewCharacter(module) if not self.auth or not self.hash_valid then return end local dialog = Dialog:simplePopup("Registering character", "Character is being registered on http://te4.org/") dialog.__showup = nil core.display.forceRedraw() @@ -388,15 +382,4 @@ function _M:registerSaveChardump(module, uuid, title, tags, data) if not data or not data.ok then return end print("[ONLINE PROFILE] saved character ", uuid) end - -function _M:checkModuleHash(module, md5) - self.hash_valid = false - if not self.auth then return nil, "no online profile active" end - if config.settings.cheat then return nil, "cheat mode active" end - if game and game:isTainted() then return nil, "savefile tainted" end - local data = self:rpc{action="CheckModuleHash", login=self.login, hash=self.auth.hash, module=module, md5=md5} - if not data or not data.ok then return nil, "bad game version" end - print("[ONLINE PROFILE] module hash is valid") - self.hash_valid = true - return true -end +]] diff --git a/game/profile-thread/Client.lua b/game/profile-thread/Client.lua index 5455fd96fe6e16697cc949362d58777687f6c2bd..34d4f3c9d159333fcac7f1bf264dfca167cd35ad 100644 --- a/game/profile-thread/Client.lua +++ b/game/profile-thread/Client.lua @@ -101,8 +101,8 @@ end function _M:orderLogin(o) -- Already logged? - if self.auth and self.auth.login == o.login then - print("[PROFILE] reusing login") + if self.auth and self.auth.login == o.l then + print("[PROFILE] reusing login", self.auth.name) cprofile.pushEvent(string.format("e='Auth' ok=%q", table.serialize(self.auth))) else self.user_login = o.l @@ -125,7 +125,37 @@ function _M:orderGetNews(o) end end +function _M:orderGetConfigs(o) + if not self.auth then return end + self:command("GCFS", o.module) + if self:read("200") then + local _, _, size = self.last_line:find("^([0-9]+)") + size = tonumber(size) + if not size or size < 1 then return end + local body = self.sock:receive(size) + cprofile.pushEvent(string.format("e='GetConfigs' module=%q data=%q", o.module, body)) + end +end + +function _M:orderSetConfigs(o) + if not self.auth then return end + self:command("SCFS", o.data:len(), o.module) + if self:read("200") then + self.sock:send(o.data) + end +end + +function _M:orderCheckModuleHash(o) + self:command("CMD5", o.md5, o.module) + if self:read("200") then + cprofile.pushEvent("e='CheckModuleHash' ok=true") + else + cprofile.pushEvent("e='CheckModuleHash' ok=false") + end +end + function _M:handleOrder(o) + if not self.sock then return end o = o:unserialize() if self["order"..o.o] then self["order"..o.o](self, o) end end diff --git a/src/profile.c b/src/profile.c index 0239999fa71d13b9fd32d5fc6e7805a25294ba08..477ad459362bc616230f3a91ffb15e7349c5ea42 100644 --- a/src/profile.c +++ b/src/profile.c @@ -35,6 +35,7 @@ int push_order(lua_State *L) { size_t len; const char *code = luaL_checklstring(L, 1, &len); + printf("[profile order] %s\n", code); profile_queue *q = malloc(sizeof(profile_queue)); char *d = calloc(len, sizeof(char)); @@ -80,6 +81,7 @@ int push_event(lua_State *L) { size_t len; const char *code = luaL_checklstring(L, 1, &len); + printf("[profile event] %s\n", code); profile_queue *q = malloc(sizeof(profile_queue)); char *d = calloc(len, sizeof(char));