mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
Automatically upload export to master server
Upload the created export data zip file to a new /api/upload-export endpoint on the master server which unpacks it into the appropriate directory on the master.
This commit is contained in:
1 parent
f3d4cfdcf5
commit
36cf14074e
5 files changed
+62
-4
No files matched your search
@@ -306,6 +306,7 @@ async function exportLocale(server, modVersions, modOrder, languageCode) {
|
||||
*
|
||||
* @param {module:lib/factorio.FactorioServer} server -
|
||||
* The server to export the data from.
|
||||
* @returns {JSZip} zip file with exported data.
|
||||
* @memberof module:lib/factorio
|
||||
*/
|
||||
async function exportData(server) {
|
||||
@@ -347,8 +348,7 @@ async function exportData(server) {
|
||||
zip.file("export/item-spritesheet.png", await iconSheet.getBufferAsync(Jimp.MIME_PNG));
|
||||
zip.file("export/item-metadata.json", JSON.stringify([...itemData.entries()]));
|
||||
zip.file("export/locale.json", JSON.stringify([...locale.entries()]));
|
||||
let content = await zip.generateAsync({ type: "nodebuffer" });
|
||||
await fs.outputFile("temp/export.zip", content);
|
||||
return zip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ const setBlocking = require("set-blocking");
|
||||
const events = require("events");
|
||||
const yargs = require("yargs");
|
||||
const WebSocket = require("ws");
|
||||
const JSZip = require("jszip");
|
||||
const version = require("./package").version;
|
||||
|
||||
// ugly globals
|
||||
@@ -174,6 +175,45 @@ async function getMetrics(req, res, next) {
|
||||
}
|
||||
app.get('/metrics', (req, res, next) => getMetrics(req, res, next).catch(next));
|
||||
|
||||
// Handle an uploaded export package.
|
||||
async function uploadExport(req, res, next) {
|
||||
endpointHitCounter.labels(req.route.path).inc();
|
||||
if (req.get("Content-Type") !== "application/zip") {
|
||||
res.sendStatus(415);
|
||||
return;
|
||||
}
|
||||
|
||||
let data = [];
|
||||
for await (let chunk of req) {
|
||||
data.push(chunk);
|
||||
}
|
||||
data = Buffer.concat(data);
|
||||
let zip = await JSZip.loadAsync(data);
|
||||
delete data;
|
||||
|
||||
// This is hardcoded to prevent path expansion attacks
|
||||
let exportFiles = [
|
||||
"export/item-spritesheet.png",
|
||||
"export/item-metadata.json",
|
||||
"export/locale.json",
|
||||
];
|
||||
|
||||
for (let filePath of exportFiles) {
|
||||
let file = zip.file(filePath);
|
||||
if (!file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = path.posix.basename(filePath);
|
||||
await fs.outputFile(path.join("static", "export", name), await file.async("nodebuffer"));
|
||||
}
|
||||
|
||||
res.sendStatus(200);
|
||||
}
|
||||
app.put("/api/upload-export",
|
||||
authenticate.middleware,
|
||||
(req, res, next) => uploadExport(req, res, next).catch(next)
|
||||
);
|
||||
|
||||
const masterConnectedClientsCount = new prometheus.Gauge(
|
||||
'clusterio_master_connected_clients_count', "How many clients are currently connected to this master server",
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"needle": "^2.4.0",
|
||||
"node-factorio-api": "^0.3.8",
|
||||
"node-forge": "^0.7.1",
|
||||
"phin": "^3.4.1",
|
||||
"pidusage": "^2.0.18",
|
||||
"rcon-client": "^4.2.0",
|
||||
"request": "^2.83.0",
|
||||
|
||||
@@ -16,6 +16,7 @@ const yargs = require("yargs");
|
||||
const events = require("events");
|
||||
const pidusage = require("pidusage");
|
||||
const setBlocking = require("set-blocking");
|
||||
const phin = require("phin");
|
||||
const version = require("./package").version;
|
||||
|
||||
// internal libraries
|
||||
@@ -446,7 +447,23 @@ class Instance extends link.Link{
|
||||
|
||||
console.log("Exporting data .....");
|
||||
await symlinkMods(this, "sharedMods", console);
|
||||
await factorio.exportData(this.server);
|
||||
let zip = await factorio.exportData(this.server);
|
||||
|
||||
let content = await zip.generateAsync({ type: "nodebuffer" });
|
||||
let url = new URL(this._slave.config.get("slave.master_url"));
|
||||
url.pathname += "api/upload-export";
|
||||
let response = await phin({
|
||||
url, method: "PUT",
|
||||
data: content,
|
||||
core: { rejectUnauthorized: false },
|
||||
headers: {
|
||||
"Content-Type": "application/zip",
|
||||
"x-access-token": this._slave.config.get("slave.master_token"),
|
||||
},
|
||||
});
|
||||
if (response.statusCode !== 200) {
|
||||
throw Error(`Upload failed: ${response.statusCode} ${response.statusMessage}: ${response.body}`)
|
||||
}
|
||||
|
||||
} finally {
|
||||
this.notifyExit();
|
||||
|
||||
@@ -62,7 +62,7 @@ describe("Integration of Clusterio", function() {
|
||||
it("exports the data", async function() {
|
||||
slowTest(this);
|
||||
await exec(`node clusterctl --config ${controlConfigPath} export-data --instance test`);
|
||||
assert(await fs.exists(path.join("temp", "export.zip")), "Export was not created");
|
||||
assert(await fs.exists(path.join("static", "export", "locale.json")), "Export was not created");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user