convex
Version:
Client for the Convex Cloud
152 lines (151 loc) • 4.97 kB
JavaScript
"use strict";
import { jsonToConvex } from "../../values/index.js";
import { logToConsole } from "../logging.js";
export class RequestManager {
constructor() {
this.inflightRequests = /* @__PURE__ */ new Map();
this.requestsOlderThanRestart = /* @__PURE__ */ new Set();
}
request(message, sent) {
const result = new Promise((resolve) => {
const status = sent ? "Requested" : "NotSent";
this.inflightRequests.set(message.requestId, {
message,
status: { status, requestedAt: /* @__PURE__ */ new Date(), onResult: resolve }
});
});
return result;
}
/**
* Update the state after receiving a response.
*
* @returns A RequestId if the request is complete and its optimistic update
* can be dropped, null otherwise.
*/
onResponse(response) {
const requestInfo = this.inflightRequests.get(response.requestId);
if (requestInfo === void 0) {
return null;
}
if (requestInfo.status.status === "Completed") {
return null;
}
const udfType = requestInfo.message.type === "Mutation" ? "mutation" : "action";
const udfPath = requestInfo.message.udfPath;
for (const line of response.logLines) {
logToConsole("info", udfType, udfPath, line);
}
const status = requestInfo.status;
let onResolve;
if (response.success) {
onResolve = () => status.onResult({
success: true,
logLines: response.logLines,
value: jsonToConvex(response.result)
});
} else {
const errorMessage = response.result;
const { errorData } = response;
logToConsole("error", udfType, udfPath, errorMessage);
onResolve = () => status.onResult({
success: false,
errorMessage,
errorData: errorData !== void 0 ? jsonToConvex(errorData) : void 0,
logLines: response.logLines
});
}
if (response.type === "ActionResponse" || !response.success) {
onResolve();
this.inflightRequests.delete(response.requestId);
this.requestsOlderThanRestart.delete(response.requestId);
return response.requestId;
}
requestInfo.status = {
status: "Completed",
ts: response.ts,
onResolve
};
return null;
}
// Remove and returns completed requests.
removeCompleted(ts) {
const completeRequests = /* @__PURE__ */ new Set();
for (const [requestId, requestInfo] of this.inflightRequests.entries()) {
const status = requestInfo.status;
if (status.status === "Completed" && status.ts.lessThanOrEqual(ts)) {
status.onResolve();
completeRequests.add(requestId);
this.inflightRequests.delete(requestId);
this.requestsOlderThanRestart.delete(requestId);
}
}
return completeRequests;
}
restart() {
this.requestsOlderThanRestart = new Set(this.inflightRequests.keys());
const allMessages = [];
for (const [requestId, value] of this.inflightRequests) {
if (value.status.status === "NotSent") {
value.status.status = "Requested";
allMessages.push(value.message);
continue;
}
if (value.message.type === "Mutation") {
allMessages.push(value.message);
} else {
this.inflightRequests.delete(requestId);
this.requestsOlderThanRestart.delete(requestId);
if (value.status.status === "Completed") {
throw new Error("Action should never be in 'Completed' state");
}
value.status.onResult({
success: false,
errorMessage: "Connection lost while action was in flight",
logLines: []
});
}
}
return allMessages;
}
/**
* @returns true if there are any requests that have been requested but have
* not be completed yet.
*/
hasIncompleteRequests() {
for (const requestInfo of this.inflightRequests.values()) {
if (requestInfo.status.status === "Requested") {
return true;
}
}
return false;
}
/**
* @returns true if there are any inflight requests, including ones that have
* completed on the server, but have not been applied.
*/
hasInflightRequests() {
return this.inflightRequests.size > 0;
}
/**
* @returns true if there are any inflight requests, that have been hanging around
* since prior to the most recent restart.
*/
hasSyncedPastLastReconnect() {
return this.requestsOlderThanRestart.size === 0;
}
timeOfOldestInflightRequest() {
if (this.inflightRequests.size === 0) {
return null;
}
let oldestInflightRequest = Date.now();
for (const request of this.inflightRequests.values()) {
if (request.status.status !== "Completed") {
if (request.status.requestedAt.getTime() < oldestInflightRequest) {
oldestInflightRequest = request.status.requestedAt.getTime();
}
}
}
return new Date(oldestInflightRequest);
}
}
//# sourceMappingURL=request_manager.js.map