@rpgjs/vite 5.0.0-alpha.33 → 5.0.0-alpha.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +114 -42
- package/dist/index.js.map +1 -1
- package/dist/server-plugin.d.ts +9 -8
- package/package.json +6 -6
- package/src/server-plugin.ts +134 -49
package/dist/index.js
CHANGED
|
@@ -8253,10 +8253,8 @@ class PartyConnection {
|
|
|
8253
8253
|
this.messageQueue = [];
|
|
8254
8254
|
this.isProcessingQueue = false;
|
|
8255
8255
|
this.sequenceCounter = 0;
|
|
8256
|
-
this.lastSendTime = 0;
|
|
8257
|
-
this.outgoingFlushTimeout = null;
|
|
8258
8256
|
this.incomingQueue = [];
|
|
8259
|
-
this.
|
|
8257
|
+
this.isProcessingIncomingQueue = false;
|
|
8260
8258
|
this.id = id || this.generateId();
|
|
8261
8259
|
this.uri = uri || "";
|
|
8262
8260
|
}
|
|
@@ -8320,22 +8318,12 @@ class PartyConnection {
|
|
|
8320
8318
|
}
|
|
8321
8319
|
}
|
|
8322
8320
|
/**
|
|
8323
|
-
* Processes the outgoing queue
|
|
8324
|
-
*
|
|
8325
|
-
*
|
|
8326
|
-
*
|
|
8321
|
+
* Processes the outgoing queue in order.
|
|
8322
|
+
*
|
|
8323
|
+
* Each message receives its own fixed latency (if enabled), while preserving
|
|
8324
|
+
* original spacing and order.
|
|
8327
8325
|
*/
|
|
8328
8326
|
async processMessageQueue() {
|
|
8329
|
-
if (this.messageQueue.length === 0) return;
|
|
8330
|
-
const shouldBatchWithLatency = PartyConnection.latencyEnabled && PartyConnection.latencyMs > 0;
|
|
8331
|
-
if (shouldBatchWithLatency) {
|
|
8332
|
-
if (this.outgoingFlushTimeout) return;
|
|
8333
|
-
this.outgoingFlushTimeout = setTimeout(async () => {
|
|
8334
|
-
this.outgoingFlushTimeout = null;
|
|
8335
|
-
await this.flushSendQueue();
|
|
8336
|
-
}, PartyConnection.latencyMs);
|
|
8337
|
-
return;
|
|
8338
|
-
}
|
|
8339
8327
|
await this.flushSendQueue();
|
|
8340
8328
|
}
|
|
8341
8329
|
/**
|
|
@@ -8346,6 +8334,9 @@ class PartyConnection {
|
|
|
8346
8334
|
this.isProcessingQueue = true;
|
|
8347
8335
|
while (this.messageQueue.length > 0) {
|
|
8348
8336
|
const queueItem = this.messageQueue.shift();
|
|
8337
|
+
if (this.shouldApplyLatency(queueItem.message)) {
|
|
8338
|
+
await this.waitUntil(queueItem.timestamp + PartyConnection.latencyMs);
|
|
8339
|
+
}
|
|
8349
8340
|
if (PartyConnection.bandwidthEnabled && PartyConnection.bandwidthKbps > 0) {
|
|
8350
8341
|
if (!PartyConnection.bandwidthFilter || queueItem.message.includes(PartyConnection.bandwidthFilter)) {
|
|
8351
8342
|
const messageSizeBits = queueItem.message.length * 8;
|
|
@@ -8360,6 +8351,22 @@ class PartyConnection {
|
|
|
8360
8351
|
}
|
|
8361
8352
|
this.isProcessingQueue = false;
|
|
8362
8353
|
}
|
|
8354
|
+
shouldApplyLatency(message) {
|
|
8355
|
+
if (!PartyConnection.latencyEnabled || PartyConnection.latencyMs <= 0) {
|
|
8356
|
+
return false;
|
|
8357
|
+
}
|
|
8358
|
+
if (!PartyConnection.latencyFilter) {
|
|
8359
|
+
return true;
|
|
8360
|
+
}
|
|
8361
|
+
return message.includes(PartyConnection.latencyFilter);
|
|
8362
|
+
}
|
|
8363
|
+
async waitUntil(targetTimestamp) {
|
|
8364
|
+
const delayMs = targetTimestamp - Date.now();
|
|
8365
|
+
if (delayMs <= 0) {
|
|
8366
|
+
return;
|
|
8367
|
+
}
|
|
8368
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
8369
|
+
}
|
|
8363
8370
|
/**
|
|
8364
8371
|
* Closes the WebSocket connection
|
|
8365
8372
|
*/
|
|
@@ -8386,9 +8393,9 @@ class PartyConnection {
|
|
|
8386
8393
|
}
|
|
8387
8394
|
/**
|
|
8388
8395
|
* Buffers incoming messages to simulate TCP latency on reception.
|
|
8389
|
-
*
|
|
8390
|
-
*
|
|
8391
|
-
*
|
|
8396
|
+
*
|
|
8397
|
+
* Messages are processed in strict order. Each message keeps its own fixed
|
|
8398
|
+
* latency delay relative to the moment it arrived.
|
|
8392
8399
|
*
|
|
8393
8400
|
* @param {string} message - Raw incoming message
|
|
8394
8401
|
* @param {(messages: string[]) => Promise<void>} processor - Async batch processor
|
|
@@ -8399,19 +8406,32 @@ class PartyConnection {
|
|
|
8399
8406
|
* })
|
|
8400
8407
|
*/
|
|
8401
8408
|
bufferIncoming(message, processor) {
|
|
8402
|
-
this.incomingQueue.push(
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
this.
|
|
8409
|
+
this.incomingQueue.push({
|
|
8410
|
+
message,
|
|
8411
|
+
timestamp: Date.now(),
|
|
8412
|
+
processor
|
|
8413
|
+
});
|
|
8414
|
+
if (!this.isProcessingIncomingQueue) {
|
|
8415
|
+
void this.processIncomingQueue();
|
|
8416
|
+
}
|
|
8417
|
+
}
|
|
8418
|
+
async processIncomingQueue() {
|
|
8419
|
+
if (this.isProcessingIncomingQueue) {
|
|
8420
|
+
return;
|
|
8421
|
+
}
|
|
8422
|
+
this.isProcessingIncomingQueue = true;
|
|
8423
|
+
while (this.incomingQueue.length > 0) {
|
|
8424
|
+
const item = this.incomingQueue.shift();
|
|
8425
|
+
if (this.shouldApplyLatency(item.message)) {
|
|
8426
|
+
await this.waitUntil(item.timestamp + PartyConnection.latencyMs);
|
|
8427
|
+
}
|
|
8409
8428
|
try {
|
|
8410
|
-
await processor(
|
|
8429
|
+
await item.processor([item.message]);
|
|
8411
8430
|
} catch (err) {
|
|
8412
|
-
console.error("Error processing incoming
|
|
8431
|
+
console.error("Error processing incoming message:", err);
|
|
8413
8432
|
}
|
|
8414
|
-
}
|
|
8433
|
+
}
|
|
8434
|
+
this.isProcessingIncomingQueue = false;
|
|
8415
8435
|
}
|
|
8416
8436
|
/**
|
|
8417
8437
|
* Configures packet loss simulation settings
|
|
@@ -8632,12 +8652,15 @@ async function importWebSocketServer() {
|
|
|
8632
8652
|
}
|
|
8633
8653
|
}
|
|
8634
8654
|
async function updateMap(roomId, rpgServer) {
|
|
8655
|
+
if (!roomId.startsWith("map-")) {
|
|
8656
|
+
return;
|
|
8657
|
+
}
|
|
8635
8658
|
try {
|
|
8636
8659
|
const mapId = roomId.startsWith("map-") ? roomId.slice(4) : roomId;
|
|
8637
8660
|
const defaultMapPayload = {
|
|
8638
8661
|
id: mapId,
|
|
8639
|
-
width:
|
|
8640
|
-
height:
|
|
8662
|
+
width: 0,
|
|
8663
|
+
height: 0,
|
|
8641
8664
|
events: []
|
|
8642
8665
|
};
|
|
8643
8666
|
const req = {
|
|
@@ -8786,22 +8809,71 @@ function serverPlugin(serverModule) {
|
|
|
8786
8809
|
}
|
|
8787
8810
|
server.middlewares.use("/parties", async (req, res, next) => {
|
|
8788
8811
|
try {
|
|
8789
|
-
|
|
8790
|
-
|
|
8812
|
+
const host = req.headers.host || "localhost";
|
|
8813
|
+
const incomingUrl = req.url || "/";
|
|
8814
|
+
const parsedUrl = new URL(incomingUrl, `http://${host}`);
|
|
8815
|
+
const normalizedPath = parsedUrl.pathname.startsWith("/parties") ? parsedUrl.pathname : `/parties${parsedUrl.pathname.startsWith("/") ? parsedUrl.pathname : `/${parsedUrl.pathname}`}`;
|
|
8816
|
+
const pathParts = normalizedPath.split("/").filter(Boolean);
|
|
8817
|
+
if (pathParts[0] !== "parties" || pathParts[1] !== "main" || pathParts.length < 4) {
|
|
8818
|
+
next();
|
|
8819
|
+
return;
|
|
8820
|
+
}
|
|
8821
|
+
const roomId = pathParts[2];
|
|
8822
|
+
const requestPath = `/${pathParts.slice(3).join("/")}`;
|
|
8823
|
+
const { room, rpgServer } = await ensureRoomAndServer(roomId);
|
|
8824
|
+
room.context.parties = buildPartiesContext();
|
|
8825
|
+
const bodyText = await new Promise((resolve, reject) => {
|
|
8826
|
+
const chunks = [];
|
|
8827
|
+
req.on("data", (chunk) => {
|
|
8828
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
8829
|
+
});
|
|
8830
|
+
req.on("end", () => {
|
|
8831
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
8832
|
+
});
|
|
8833
|
+
req.on("error", reject);
|
|
8834
|
+
});
|
|
8835
|
+
const requestHeaders = new Headers();
|
|
8836
|
+
Object.entries(req.headers).forEach(([key, value]) => {
|
|
8837
|
+
if (Array.isArray(value)) {
|
|
8838
|
+
if (value[0] !== void 0) requestHeaders.set(key, value[0]);
|
|
8839
|
+
return;
|
|
8840
|
+
}
|
|
8841
|
+
if (typeof value === "string") {
|
|
8842
|
+
requestHeaders.set(key, value);
|
|
8843
|
+
}
|
|
8844
|
+
});
|
|
8845
|
+
const requestLike = {
|
|
8846
|
+
url: `http://${host}/parties/main/${roomId}${requestPath}${parsedUrl.search}`,
|
|
8847
|
+
method: (req.method || "GET").toUpperCase(),
|
|
8848
|
+
headers: requestHeaders,
|
|
8849
|
+
json: async () => {
|
|
8850
|
+
if (!bodyText) return void 0;
|
|
8851
|
+
return JSON.parse(bodyText);
|
|
8852
|
+
},
|
|
8853
|
+
text: async () => bodyText
|
|
8854
|
+
};
|
|
8855
|
+
const result = await rpgServer.onRequest(requestLike);
|
|
8856
|
+
if (result instanceof Response) {
|
|
8857
|
+
res.statusCode = result.status;
|
|
8858
|
+
result.headers.forEach((value, key) => {
|
|
8859
|
+
res.setHeader(key, value);
|
|
8860
|
+
});
|
|
8861
|
+
res.end(await result.text());
|
|
8862
|
+
return;
|
|
8863
|
+
}
|
|
8864
|
+
if (typeof result === "string") {
|
|
8791
8865
|
res.statusCode = 200;
|
|
8792
|
-
res.setHeader("Content-Type", "
|
|
8793
|
-
res.end(
|
|
8794
|
-
JSON.stringify({
|
|
8795
|
-
message: "RPG-JS server is running",
|
|
8796
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
8797
|
-
})
|
|
8798
|
-
);
|
|
8866
|
+
res.setHeader("Content-Type", "text/plain");
|
|
8867
|
+
res.end(result);
|
|
8799
8868
|
return;
|
|
8800
8869
|
}
|
|
8801
|
-
|
|
8870
|
+
res.statusCode = 200;
|
|
8871
|
+
res.setHeader("Content-Type", "application/json");
|
|
8872
|
+
res.end(JSON.stringify(result ?? {}));
|
|
8802
8873
|
} catch (error) {
|
|
8803
8874
|
console.error("Error handling RPG-JS request:", error);
|
|
8804
8875
|
res.statusCode = 500;
|
|
8876
|
+
res.setHeader("Content-Type", "application/json");
|
|
8805
8877
|
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
8806
8878
|
}
|
|
8807
8879
|
});
|