enum LOG { NONE, ERROR, INFO, CRAZY_VERBOSE }; function onInitialized() { this.trigger("created"); } function onCreated() { this.join("func_http"); // options this.server = "http://gsync.graalcenter.org/era/gsync.php"; // change this to your server this.key = "REPLACE_ME"; this.verbosity = LOG.ERROR; this.maxFilesPerRequest = 1000; this.maxSendSize = 1048576 * 1; this.folders = { "weapons", "scripts", "npcs" }; // temp //this.sync(); } public function sync() { report(LOG.INFO, "Starting sync"); // build list of files and their mod times report(LOG.INFO, "Building list of files and mod times"); this.fileList = ""; this.testedFiles = 0; this.foldersToLoad = this.folders; this.scheduleEvent(0.1, "onBuildFileList"); } function onBuildFileList() { if (this.filesToLoad.size() > 0) { temp.maxLoop = min(this.maxlooplimit, this.filesToLoad.size()); for (temp.i = 0; temp.i < temp.maxLoop; temp.i ++) { temp.file = this.filesToLoad[0]; this.filesToLoad.delete(0); temp.path = this.currentFolder @ "/" @ temp.file; if (temp.path.ends(".arc")) { continue; // don't send GBall archives } if (temp.path.index(@ "npclocalnpc") > (- 1)) { continue; // don't do local NPCs } if (temp.path == "npcs/npcgsync.txt") { continue; // don't backup myself } if (fileExists(temp.path)) { this.fileList @= temp.path @ "\t" @ getFileModTime(temp.path) @ "\n"; this.testedFiles ++; } } report(LOG.CRAZY_VERBOSE, "Building sync list: " @ this.currentFolder @ "/*"); } else if (this.foldersToLoad.size() > 0) { this.currentFolder = this.foldersToLoad[0]; this.filesToLoad.loadFolder(this.currentFolder @ "/*", true); this.foldersToLoad.delete(0); } else { // all done return this.finishSync(); } this.scheduleEvent(0.1, "onBuildFileList"); } function finishSync() { report(LOG.INFO, "Built list of files and mod times"); // send list of files & mod times to the server report(LOG.INFO, "Sending list of files and mod times to server (" @ this.testedFiles @ ")"); temp.data = { {"filelist", this.fileList} }; temp.returnData = this.send("filelist", temp.data, "needed"); if (temp.returnData == null) { return report(LOG.ERROR, "Didn't receive acceptable response from server"); } this.neededFiles = temp.returnData; report(LOG.INFO, "Server responded with needed files (" @ this.neededFiles.size() @ ")"); report(LOG.INFO, "Starting sending files to server"); this.scheduleEvent(0.1, "onSendFiles"); } function onSendFiles() { if (this.neededFiles.size() > 0) { // send server all the files it wants temp.maxLoop = min(this.maxFilesPerRequest, this.neededFiles.size()); temp.data = null; temp.includedFiles = ""; temp.i = 0; temp.dataLength = 0; for (temp.i = 0; temp.i < temp.maxLoop; temp.i ++) { temp.neededFile = this.neededFiles[0]; temp.fileLength = fileSize(temp.neededFile); temp.dataLength += temp.fileLength; if (temp.dataLength > this.maxSendSize) { temp.dataLength -= temp.fileLength; if (temp.fileLength > this.maxSendSize) { this.neededFiles.delete(0); report(LOG.ERROR, "Not sending file " @ temp.neededFile @ " because it's over the max send size."); } break; } this.neededFiles.delete(0); temp.contents.loadString(temp.neededFile); temp.data.add({"file-" @ md5(temp.neededFile), temp.contents}); temp.data.add({"filem-" @ md5(temp.neededFile), getFileModTime(temp.neededFile)}); temp.includedFiles @= temp.neededFile @ "\n"; } temp.data.add({"files", temp.includedFiles}); report(LOG.CRAZY_VERBOSE, "Sending server " @ temp.i @ " files (about " @ temp.dataLength @ " bytes) (" @ this.neededFiles.size() @ " files left)"); temp.returnData = this.send("store", temp.data, "status"); if (temp.returnData == null) { return report(LOG.ERROR, "Didn't receive acceptable response from server"); } } else { return report(LOG.INFO, "Sync complete"); } this.scheduleEvent(0.1, "onSendFiles"); } function send(temp.action, temp.data, temp.needed) { temp.data.add({"action", temp.action}); temp.data.add({"key", this.key}); temp.json = new TStaticVar("GSyncResponse" @ int(timevar2 * 100)); temp.response = this.post(this.server, temp.data); parseJSON(temp.json, temp.response); if (temp.json.status != null) { report(LOG.CRAZY_VERBOSE, "Parsed JSON successfully in server's response to " @ temp.action); if (temp.json.status == "ok") { temp.responseSingle = temp.json.(@ temp.needed); temp.json.destroy(); return temp.responseSingle; } else if (temp.json.status == "error") { report(LOG.ERROR, "Received error from server for " @ temp.action @ ": " @ temp.json.error); } else { report(LOG.ERROR, "Received unexpected status code '" @ temp.json.status @ "' in response to " @ temp.action); } } else { report(LOG.ERROR, "Unable to parse JSON in server's response to " @ temp.action); } temp.json.destroy(); } function report(temp.logLevel, temp.msg) { if (this.verbosity >= temp.logLevel) { echo("gsync: " @ temp.msg); } }