mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 23:24:52 +09:00
Replace remaining usage of phin (#862)
Replace the remaining places in the codebase using phin with fetch. With the exception of HttpCloser which uses the http/https request method instead.
This commit is contained in:
1 parent
ef0baaa30f
commit
05b6bf8c04
13 files changed
+91
-102
No files matched your search
@@ -56,7 +56,6 @@
|
||||
"jszip": "^3.10.1",
|
||||
"mocha": "^11.7.1",
|
||||
"nyc": "^17.1.0",
|
||||
"phin": "^3.7.1",
|
||||
"typedoc": "^0.28.9",
|
||||
"typescript": "^5.9.2",
|
||||
"yargs": "^18.0.0"
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
"set-blocking": "catalog:",
|
||||
"fs-extra": "catalog:",
|
||||
"winston": "catalog:",
|
||||
"phin": "catalog:",
|
||||
"as-table": "^1.0.55",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from "fs-extra";
|
||||
import asTableModule from "as-table";
|
||||
import events from "events";
|
||||
import phin from "phin";
|
||||
import os from "os";
|
||||
import child_process from "child_process";
|
||||
|
||||
@@ -166,11 +165,8 @@ controllerPluginCommands.add(new lib.Command({
|
||||
handler: async function(args: object, control: Control) {
|
||||
let url = new URL(control.config.get("control.controller_url")!);
|
||||
url.pathname += "api/plugins";
|
||||
let response = await phin<[]>({
|
||||
url,
|
||||
parse: "json",
|
||||
});
|
||||
print(asTable(response.body));
|
||||
let response = await fetch(url);
|
||||
print(asTable(await response.json() as []));
|
||||
},
|
||||
}));
|
||||
controllerPluginCommands.add(new lib.Command({
|
||||
|
||||
@@ -2,7 +2,6 @@ import fs from "fs-extra";
|
||||
import asTableModule from "as-table";
|
||||
import events from "events";
|
||||
import path from "path";
|
||||
import phin from "phin";
|
||||
import os from "os";
|
||||
import child_process from "child_process";
|
||||
import stream from "stream";
|
||||
@@ -330,8 +329,6 @@ instanceSaveCommands.add(new lib.Command({
|
||||
if (!filename.endsWith(".zip")) {
|
||||
throw new lib.CommandError("Save name must end with .zip");
|
||||
}
|
||||
// phin doesn't support streaming requests :(
|
||||
let content = await fs.readFile(args.filepath);
|
||||
|
||||
let instanceId = await lib.resolveInstance(control, args.instance);
|
||||
let url = new URL(control.config.get("control.controller_url")!);
|
||||
@@ -339,29 +336,32 @@ instanceSaveCommands.add(new lib.Command({
|
||||
url.searchParams.append("instance_id", String(instanceId));
|
||||
url.searchParams.append("filename", filename);
|
||||
|
||||
let result = await phin<{ errors?: string[], request_errors?: string[], saves?: string[] }>({
|
||||
url, method: "POST",
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: await fs.createReadStream(args.filepath),
|
||||
duplex: "half",
|
||||
headers: {
|
||||
"X-Access-Token": control.config.get("control.controller_token"),
|
||||
"X-Access-Token": control.config.get("control.controller_token")!,
|
||||
"Content-Type": "application/zip",
|
||||
},
|
||||
data: content,
|
||||
parse: "json",
|
||||
});
|
||||
|
||||
for (let error of result.body.errors || []) {
|
||||
type ResponseType = { errors?: string[], request_errors?: string[], saves?: string[] };
|
||||
const result = await response.json() as ResponseType;
|
||||
|
||||
for (let error of result.errors || []) {
|
||||
logger.error(error);
|
||||
}
|
||||
|
||||
for (let requestError of result.body.request_errors || []) {
|
||||
for (let requestError of result.request_errors || []) {
|
||||
logger.error(requestError);
|
||||
}
|
||||
|
||||
if (result.body.saves && result.body.saves.length) {
|
||||
logger.info(`Successfully uploaded as ${result.body.saves[0]}`);
|
||||
if (result.saves && result.saves.length) {
|
||||
logger.info(`Successfully uploaded as ${result.saves[0]}`);
|
||||
}
|
||||
|
||||
if ((result.body.errors || []).length || (result.body.request_errors || []).length) {
|
||||
if ((result.errors || []).length || (result.request_errors || []).length) {
|
||||
throw new lib.CommandError("Uploading save failed");
|
||||
}
|
||||
},
|
||||
@@ -417,10 +417,10 @@ instanceSaveCommands.add(new lib.Command({
|
||||
|
||||
let url = new URL(control.config.get("control.controller_url")!);
|
||||
url.pathname += `api/stream/${streamId}`;
|
||||
let response = await phin({
|
||||
url, method: "GET",
|
||||
stream: true,
|
||||
});
|
||||
let response = await fetch(url);
|
||||
if (!response.body) {
|
||||
throw new lib.CommandError("Got empty response from server.");
|
||||
}
|
||||
|
||||
let writeStream;
|
||||
let tempFilename = args.save.replace(/(\.zip)?$/, ".tmp.zip");
|
||||
@@ -437,7 +437,7 @@ instanceSaveCommands.add(new lib.Command({
|
||||
}
|
||||
}
|
||||
}
|
||||
response.pipe(writeStream);
|
||||
stream.Readable.fromWeb(response.body).pipe(writeStream);
|
||||
await finished(writeStream);
|
||||
|
||||
let filename = await lib.findUnusedName(".", args.save, ".zip");
|
||||
|
||||
@@ -2,7 +2,6 @@ import fs from "fs-extra";
|
||||
import asTableModule from "as-table";
|
||||
import events from "events";
|
||||
import path from "path";
|
||||
import phin from "phin";
|
||||
import stream from "stream";
|
||||
import util from "util";
|
||||
|
||||
@@ -145,39 +144,38 @@ modCommands.add(new lib.Command({
|
||||
if (!filename.endsWith(".zip")) {
|
||||
throw new lib.CommandError("Mod filename must end with .zip");
|
||||
}
|
||||
// phin doesn't support streaming requests :(
|
||||
let content = await fs.readFile(args.file);
|
||||
|
||||
let url = new URL(control.config.get("control.controller_url")!);
|
||||
url.pathname += "api/upload-mod";
|
||||
url.searchParams.append("filename", filename);
|
||||
|
||||
let result = await phin<
|
||||
{ errors?: [], request_errors?: [], mods: Parameters<typeof lib.ModInfo.fromJSON>[0][]}
|
||||
>({
|
||||
url, method: "POST",
|
||||
let response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: fs.createReadStream(args.file),
|
||||
duplex: "half",
|
||||
headers: {
|
||||
"X-Access-Token": control.config.get("control.controller_token"),
|
||||
"X-Access-Token": control.config.get("control.controller_token")!,
|
||||
"Content-Type": "application/zip",
|
||||
},
|
||||
data: content,
|
||||
parse: "json",
|
||||
});
|
||||
|
||||
for (let error of result.body.errors || []) {
|
||||
type ResponseType = { errors?: [], request_errors?: [], mods: Parameters<typeof lib.ModInfo.fromJSON>[0][]};
|
||||
const result = await response.json() as ResponseType;
|
||||
|
||||
for (let error of result.errors || []) {
|
||||
logger.error(error);
|
||||
}
|
||||
|
||||
for (let requestError of result.body.request_errors || []) {
|
||||
for (let requestError of result.request_errors || []) {
|
||||
logger.error(requestError);
|
||||
}
|
||||
|
||||
if (result.body.mods && result.body.mods.length) {
|
||||
const mod = lib.ModInfo.fromJSON(result.body.mods[0]);
|
||||
if (result.mods && result.mods.length) {
|
||||
const mod = lib.ModInfo.fromJSON(result.mods[0]);
|
||||
logger.info(`Successfully uploaded ${mod.filename}`);
|
||||
}
|
||||
|
||||
if ((result.body.errors || []).length || (result.body.request_errors || []).length) {
|
||||
if ((result.errors || []).length || (result.request_errors || []).length) {
|
||||
throw new lib.CommandError("Uploading mod failed");
|
||||
}
|
||||
},
|
||||
@@ -196,10 +194,10 @@ modCommands.add(new lib.Command({
|
||||
|
||||
let url = new URL(control.config.get("control.controller_url")!);
|
||||
url.pathname += `api/stream/${streamId}`;
|
||||
let response = await phin({
|
||||
url, method: "GET",
|
||||
stream: true,
|
||||
});
|
||||
let response = await fetch(url);
|
||||
if (!response.body) {
|
||||
throw new lib.CommandError("Got empty response from server");
|
||||
}
|
||||
|
||||
let writeStream;
|
||||
let filename = `${args.name}_${args.modVersion}.zip`;
|
||||
@@ -217,7 +215,7 @@ modCommands.add(new lib.Command({
|
||||
}
|
||||
}
|
||||
}
|
||||
response.pipe(writeStream);
|
||||
stream.Readable.fromWeb(response.body).pipe(writeStream);
|
||||
await finished(writeStream);
|
||||
await fs.rename(tempFilename, filename);
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"set-blocking": "catalog:",
|
||||
"fs-extra": "catalog:",
|
||||
"jszip": "catalog:",
|
||||
"phin": "catalog:",
|
||||
"winston": "catalog:",
|
||||
"winston-daily-rotate-file": "catalog:",
|
||||
"jimp": "^0.22.8",
|
||||
|
||||
+18
-20
@@ -3,7 +3,6 @@ import path from "path";
|
||||
import events from "events";
|
||||
import pidusage from "pidusage";
|
||||
import setBlocking from "set-blocking";
|
||||
import phin from "phin";
|
||||
import stream from "stream";
|
||||
import util from "util";
|
||||
|
||||
@@ -585,17 +584,17 @@ export default class Host extends lib.Link {
|
||||
|
||||
let url = new URL(this.config.get("host.controller_url"));
|
||||
url.pathname += `api/stream/${streamId}`;
|
||||
let response = await phin({
|
||||
url, method: "GET",
|
||||
stream: true,
|
||||
});
|
||||
let response = await fetch(url);
|
||||
if (!response.body) {
|
||||
throw new Error(`Empty body downloading stream ${streamId} from controller`);
|
||||
}
|
||||
|
||||
const file = lib.ModInfo.filename(mod.name, mod.version);
|
||||
const filePath = path.join(this.modStore.modsDirectory, file);
|
||||
const tempFilePath = filePath.replace(/(\.zip)?$/, ".tmp.zip");
|
||||
const writeStream = fs.createWriteStream(tempFilePath, { flags: "w" });
|
||||
await events.once(writeStream, "open");
|
||||
response.pipe(writeStream);
|
||||
stream.Readable.fromWeb(response.body).pipe(writeStream);
|
||||
await finished(writeStream);
|
||||
await fs.rename(tempFilePath, filePath);
|
||||
|
||||
@@ -1018,14 +1017,11 @@ export default class Host extends lib.Link {
|
||||
|
||||
let url = new URL(this.config.get("host.controller_url"));
|
||||
url.pathname += `api/stream/${streamId}`;
|
||||
let response = await phin({
|
||||
url, method: "GET",
|
||||
stream: true,
|
||||
});
|
||||
let response = await fetch(url);
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
let content = await lib.readStream(response);
|
||||
throw new lib.RequestError(`Stream returned ${response.statusCode}: ${content.toString()}`);
|
||||
if (response.status !== 200 || !response.body) {
|
||||
let body = Buffer.from(await response.arrayBuffer());
|
||||
throw new lib.RequestError(`Stream returned ${response.status}: ${body.toString()}`);
|
||||
}
|
||||
|
||||
let savesDir = path.join(instance.path, "saves");
|
||||
@@ -1044,7 +1040,7 @@ export default class Host extends lib.Link {
|
||||
}
|
||||
}
|
||||
}
|
||||
response.pipe(writeStream);
|
||||
stream.Readable.fromWeb(response.body).pipe(writeStream);
|
||||
await finished(writeStream);
|
||||
|
||||
name = await lib.findUnusedName(savesDir, name, ".zip");
|
||||
@@ -1059,10 +1055,11 @@ export default class Host extends lib.Link {
|
||||
checkRequestSaveName(name);
|
||||
let instance = this.getRequestInstance(instanceId);
|
||||
|
||||
let content: Buffer;
|
||||
let content = fs.createReadStream(path.join(instance.path, "saves", name));
|
||||
try {
|
||||
// phin doesn't support streaming requests :(
|
||||
content = await fs.readFile(path.join(instance.path, "saves", name));
|
||||
// TODO: Due to a bug in fs-extra the ready event is not emitted here. Replace
|
||||
// "open" with "ready" when fs-extra is replaced with node's fs module.
|
||||
await events.once(content, "open");
|
||||
} catch (err: any) {
|
||||
if (err.code === "ENOENT") {
|
||||
throw new lib.RequestError(`${name} does not exist`);
|
||||
@@ -1072,9 +1069,10 @@ export default class Host extends lib.Link {
|
||||
|
||||
let url = new URL(this.config.get("host.controller_url"));
|
||||
url.pathname += `api/stream/${streamId}`;
|
||||
phin({
|
||||
url, method: "PUT",
|
||||
data: content,
|
||||
fetch(url, {
|
||||
method: "PUT",
|
||||
body: content,
|
||||
duplex: "half",
|
||||
}).catch(err => {
|
||||
logger.error(`Error pushing save to controller:\n${err.stack}`, this.instanceLogMeta(instanceId));
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import pidusage from "pidusage";
|
||||
import phin from "phin";
|
||||
import util from "util";
|
||||
import type { Static } from "@sinclair/typebox";
|
||||
import { exec } from "child_process";
|
||||
@@ -1292,16 +1291,18 @@ end`.replace(/\r?\n/g, " ");
|
||||
let url = new URL(this._host.config.get("host.controller_url"));
|
||||
url.pathname += "api/upload-export";
|
||||
url.searchParams.set("mod_pack_id", String(this.activeModPack.id));
|
||||
let response = await phin({
|
||||
url, method: "PUT",
|
||||
data: content,
|
||||
let response = await fetch(url, {
|
||||
method: "PUT",
|
||||
body: content,
|
||||
duplex: "half",
|
||||
headers: {
|
||||
"Content-Type": "application/zip",
|
||||
"x-access-token": this._host.config.get("host.controller_token"),
|
||||
},
|
||||
});
|
||||
if (response.statusCode !== 200) {
|
||||
throw Error(`Upload failed: ${response.statusCode} ${response.statusMessage}: ${response.body}`);
|
||||
if (response.status !== 200) {
|
||||
const body = Buffer.from(await response.arrayBuffer());
|
||||
throw Error(`Upload failed: ${response.status} ${response.statusText}: ${body.toString()}`);
|
||||
}
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -9,7 +9,7 @@ describe("subspace_storage endpoints", function() {
|
||||
describe("GET /api/inventory", function() {
|
||||
it("should return the controllers current inventory", async function() {
|
||||
let res = await get("/api/inventory");
|
||||
let inventory = res.body;
|
||||
let inventory = await res.json();
|
||||
assert.equal(typeof inventory, "object", "Inventory should be an object");
|
||||
|
||||
return; // XXX Disabled until a suitable test interface is added.
|
||||
|
||||
@@ -33,7 +33,6 @@ catalog:
|
||||
"set-blocking": ^2.0.0
|
||||
"jszip": ^3.10.1
|
||||
"chalk": ^4.1.2
|
||||
"phin": ^3.7.0
|
||||
"ws": ^8.18.1
|
||||
|
||||
catalogMode: strict
|
||||
|
||||
@@ -4,8 +4,7 @@ const fs = require("fs-extra");
|
||||
const http = require("http");
|
||||
const https = require("https");
|
||||
const util = require("util");
|
||||
|
||||
const phin = require("phin");
|
||||
const events = require("node:events");
|
||||
|
||||
const HttpCloser = require("@clusterio/controller/dist/node/src/HttpCloser").default;
|
||||
|
||||
@@ -38,8 +37,16 @@ function serverSuite(proto) {
|
||||
}
|
||||
|
||||
async function get(url, options = {}) {
|
||||
let core = { ...clientOptions, ...(options.core || {}) };
|
||||
return await phin({ ...options, url, core });
|
||||
const request = api.request(url, { ...clientOptions, ...options });
|
||||
request.end();
|
||||
const [response] = await events.once(request, "response");
|
||||
response.body = await new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
response.on("data", chunk => { chunks.push(chunk); });
|
||||
response.on("error", err => { reject(err); });
|
||||
response.on("end", () => { resolve(Buffer.concat(chunks)); });
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
before(async function() {
|
||||
@@ -101,7 +108,7 @@ function serverSuite(proto) {
|
||||
});
|
||||
|
||||
let agent = new api.Agent({ keepAlive: true });
|
||||
let request = catched(get(addr, { core: { agent }}));
|
||||
let request = catched(get(addr, { agent }));
|
||||
await waitForStage1;
|
||||
stage2();
|
||||
await closer.close();
|
||||
@@ -121,7 +128,7 @@ function serverSuite(proto) {
|
||||
});
|
||||
|
||||
let agent = new api.Agent({ keepAlive: true });
|
||||
let request = catched(get(addr, { core: { agent }}));
|
||||
let request = catched(get(addr, { agent }));
|
||||
await waitForStage1;
|
||||
await closer.close();
|
||||
|
||||
@@ -145,7 +152,7 @@ function serverSuite(proto) {
|
||||
let close = catched(closer.close());
|
||||
|
||||
let agent = new api.Agent({ keepAlive: true });
|
||||
await assert.rejects(get(addr, { core: { agent }}), { code: "ECONNREFUSED" });
|
||||
await assert.rejects(get(addr, { agent }), { code: "ECONNREFUSED" });
|
||||
|
||||
let response = await request;
|
||||
assert.equal(response.statusCode, 200, "non-200 response status code");
|
||||
@@ -165,7 +172,7 @@ function serverSuite(proto) {
|
||||
});
|
||||
|
||||
let agent = new api.Agent({ keepAlive: true });
|
||||
let request = catched(get(addr, { core: { agent }}));
|
||||
let request = catched(get(addr, { agent }));
|
||||
await waitForStage1;
|
||||
stage2();
|
||||
await closer.close();
|
||||
@@ -186,8 +193,8 @@ function serverSuite(proto) {
|
||||
});
|
||||
|
||||
let agent = new api.Agent({ keepAlive: true, maxSockets: 1 });
|
||||
let request = catched(get(addr, { core: { agent }}));
|
||||
let droppedRequest = catched(get(addr, { core: { agent }}));
|
||||
let request = catched(get(addr, { agent }));
|
||||
let droppedRequest = catched(get(addr, { agent }));
|
||||
await waitForStage1;
|
||||
stage2();
|
||||
await closer.close();
|
||||
@@ -212,10 +219,7 @@ function serverSuite(proto) {
|
||||
await closer.close(tick*2);
|
||||
stage2();
|
||||
|
||||
// Due to a bug in phin [https://github.com/ethanent/phin/issues/59]
|
||||
// the request Promise never settles.
|
||||
// TODO: uncomment when bug is fixed in phin.
|
||||
// await assert.rejects(request);
|
||||
await assert.rejects(request);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ const fs = require("fs-extra");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const path = require("path");
|
||||
const events = require("events");
|
||||
const phin = require("phin");
|
||||
|
||||
const lib = require("@clusterio/lib");
|
||||
const libBuildMod = require("@clusterio/lib/build_mod");
|
||||
@@ -79,16 +78,15 @@ async function runWithAltHost(callback) {
|
||||
}
|
||||
|
||||
async function uploadSave(instanceId, name, content) {
|
||||
return await phin({
|
||||
url: `https://localhost:4443/api/upload-save?instance_id=${instanceId}&filename=${name}`,
|
||||
const uploadUrl = `https://localhost:4443/api/upload-save?instance_id=${instanceId}&filename=${name}`;
|
||||
return await fetch(uploadUrl, {
|
||||
method: "POST",
|
||||
core: { rejectUnauthorized: false },
|
||||
headers: {
|
||||
"X-Access-Token": controlToken,
|
||||
"Content-Type": "application/zip",
|
||||
"Content-Length": String(content.length),
|
||||
},
|
||||
data: content,
|
||||
body: content,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ const path = require("path");
|
||||
const fs = require("fs-extra");
|
||||
const child_process = require("child_process");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const phin = require("phin");
|
||||
const util = require("util");
|
||||
const events = require("events");
|
||||
|
||||
@@ -148,13 +147,12 @@ function hasFactorio() {
|
||||
}
|
||||
|
||||
async function get(urlPath) {
|
||||
let res = await phin({
|
||||
method: "GET",
|
||||
url: `https://localhost:4443${urlPath}`,
|
||||
core: { rejectUnauthorized: false },
|
||||
});
|
||||
if (res.statusCode !== 200) {
|
||||
throw new Error(`Got response code ${res.statusCode}, content: ${res.body}`);
|
||||
const url = new URL("https://localhost:4443");
|
||||
url.pathname = urlPath;
|
||||
let res = await fetch(url);
|
||||
if (res.status !== 200) {
|
||||
const body = Buffer.from(await res.arrayBuffer());
|
||||
throw new Error(`Got response code ${res.status}, content: ${body.toString()}`);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user