mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
4 files changed
+78
-4
No files matched your search
@@ -259,6 +259,11 @@ async function getStream(req, res) {
|
||||
}
|
||||
|
||||
|
||||
const zipMimes = [
|
||||
"application/zip",
|
||||
"application/x-zip-compressed",
|
||||
];
|
||||
|
||||
async function uploadSave(req, res) {
|
||||
try {
|
||||
res.locals.user.checkPermission("core.instance.save.upload");
|
||||
@@ -319,7 +324,7 @@ async function uploadSave(req, res) {
|
||||
requestErrors.push("instance_id must come before files uploaded");
|
||||
}
|
||||
|
||||
if (fileMime !== "application/zip") {
|
||||
if (!zipMimes.includes(fileMime)) {
|
||||
requestErrors.push("invalid file Content-Type");
|
||||
}
|
||||
|
||||
@@ -350,7 +355,7 @@ async function uploadSave(req, res) {
|
||||
req.pipe(busboy);
|
||||
});
|
||||
|
||||
} else if (mimeType === "application/zip") {
|
||||
} else if (zipMimes.includes(mimeType)) {
|
||||
let filename = req.query.filename;
|
||||
if (typeof filename !== "string") {
|
||||
requestErrors.push("Missing or invalid filename parameter");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import { Button, Popconfirm, Space, Table, Tooltip, Upload } from "antd";
|
||||
import { Button, List, Popconfirm, Progress, Space, Table, Tooltip, Upload } from "antd";
|
||||
import CaretLeftOutlined from "@ant-design/icons/CaretLeftOutlined";
|
||||
import LeftOutlined from "@ant-design/icons/LeftOutlined";
|
||||
|
||||
@@ -27,6 +27,7 @@ export default function SavesList(props) {
|
||||
let control = useContext(ControlContext);
|
||||
let saves = useSaves(props.instance.id);
|
||||
let [starting, setStarting] = useState(false);
|
||||
let [uploadingFiles, setUploadingFiles] = useState([]);
|
||||
|
||||
const saveTable = <Table
|
||||
size="small"
|
||||
@@ -107,6 +108,38 @@ export default function SavesList(props) {
|
||||
}}
|
||||
/>;
|
||||
|
||||
function onChange(changeEvent) {
|
||||
if (["done", "error"].includes(changeEvent.file.status)) {
|
||||
if (changeEvent.file.status === "error") {
|
||||
notifyErrorHandler("Error uploading file")(changeEvent.file.error);
|
||||
}
|
||||
|
||||
let newUploadingFiles = [...uploadingFiles];
|
||||
let index = newUploadingFiles.findIndex(f => f.uid === changeEvent.file.uid);
|
||||
if (index !== -1) {
|
||||
newUploadingFiles.splice(index, 1);
|
||||
setUploadingFiles(newUploadingFiles);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let file = {
|
||||
uid: changeEvent.file.uid,
|
||||
name: changeEvent.file.name,
|
||||
percent: changeEvent.file.percent,
|
||||
status: changeEvent.file.status,
|
||||
};
|
||||
|
||||
let newUploadingFiles = [...uploadingFiles];
|
||||
let index = newUploadingFiles.findIndex(f => f.uid === changeEvent.file.uid);
|
||||
if (index !== -1) {
|
||||
newUploadingFiles[index] = file;
|
||||
} else {
|
||||
newUploadingFiles.push(file);
|
||||
}
|
||||
setUploadingFiles(newUploadingFiles);
|
||||
}
|
||||
|
||||
let uploadProps = {
|
||||
name: "file",
|
||||
accept: ".zip",
|
||||
@@ -118,7 +151,7 @@ export default function SavesList(props) {
|
||||
},
|
||||
showUploadList: false,
|
||||
action: `${webRoot}api/upload-save`,
|
||||
// TODO: show progress to user.
|
||||
onChange,
|
||||
};
|
||||
|
||||
return <div>
|
||||
@@ -131,5 +164,15 @@ export default function SavesList(props) {
|
||||
<Upload.Dragger className="save-list-dragger" openFileDialogOnClick={false} {...uploadProps}>
|
||||
{saveTable}
|
||||
</Upload.Dragger>
|
||||
{uploadingFiles.length ? <List>
|
||||
{uploadingFiles.map(file => <List.Item key={file.uid}>
|
||||
{file.name}
|
||||
<Progress
|
||||
percent={file.percent}
|
||||
format={percent => `${Math.floor(percent)}%`}
|
||||
status={file.status === "error" ? "exception" : "normal"}
|
||||
/>
|
||||
</List.Item>)}
|
||||
</List> : null}
|
||||
</div>;
|
||||
}
|
||||
@@ -65,6 +65,12 @@ describe("Integration of Clusterio", function() {
|
||||
describe("clusterioslave", function() {
|
||||
describe("slaveUpdateEventHandler()", function() {
|
||||
it("should trigger when a new slave is added", async function() {
|
||||
// On windows there's currently no way to automate graceful shutdown of the slave
|
||||
// process as CTRL+C is some weird terminal thing and SIGINT isn't a thing.
|
||||
if (process.platform === "win32") {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
slowTest(this);
|
||||
getControl().slaveUpdates = [];
|
||||
let config = "alt-slave-config.json";
|
||||
|
||||
@@ -325,5 +325,25 @@ describe("master/src/routes", function() {
|
||||
assert.deepEqual(JSON.parse(response.body), { saves: ["test.zip"] });
|
||||
assert.equal(response.statusCode, 200);
|
||||
});
|
||||
it("should complete a valid transfer with non-standerd mime type", async function() {
|
||||
master.forwardRequestToInstance = async (request, data) => {
|
||||
let stream = await phin({
|
||||
url: `http://localhost:${port}/api/stream/${data.stream_id}`,
|
||||
});
|
||||
assert.equal(stream.body.toString(), "totally a zip file");
|
||||
return { save: data.filename };
|
||||
};
|
||||
let response;
|
||||
response = await phin({
|
||||
url: `http://localhost:${port}/api/upload-save?instance_id=123&filename=test.zip`, method: "POST",
|
||||
headers: {
|
||||
"X-Access-Token": testToken,
|
||||
"Content-Type": "application/x-zip-compressed",
|
||||
},
|
||||
data: "totally a zip file",
|
||||
});
|
||||
assert.deepEqual(JSON.parse(response.body), { saves: ["test.zip"] });
|
||||
assert.equal(response.statusCode, 200);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user