@openocean.finance/widget-sdk
Version:
OpenOcean Any-to-Any Cross-Chain-Swap SDK
189 lines • 7.18 kB
JavaScript
import { executionState } from './executionState.js';
import { getProcessMessage } from './processMessages.js';
/**
* Manages status updates of a route and provides various functions for tracking processes
* @param {string} routeId The route dd this StatusManger belongs to.
* @returns {StatusManager} An instance of StatusManager.
*/
export class StatusManager {
routeId;
shouldUpdate = true;
constructor(routeId) {
this.routeId = routeId;
}
/**
* Initializes the execution object of a Step.
* @param step The current step in execution
* @returns The initialized execution object for this step and a function to update this step
*/
initExecutionObject = (step) => {
if (!step.execution) {
step.execution = {
status: 'PENDING',
process: [],
startedAt: Date.now(),
};
this.updateStepInRoute(step);
}
// Change status to PENDING after resuming from FAILED
if (step.execution.status === 'FAILED') {
step.execution.startedAt = Date.now();
step.execution.status = 'PENDING';
this.updateStepInRoute(step);
}
return step.execution;
};
/**
* Updates the execution object of a Step.
* @param step The current step in execution
* @param status The status for the execution
* @param execution Optional. Information about received tokens
* @returns The step with the updated execution object
*/
updateExecution(step, status, execution) {
if (!step.execution) {
throw Error("Can't update empty execution.");
}
step.execution.status = status;
if (status === 'DONE') {
step.execution.doneAt = Date.now();
}
if (execution) {
step.execution = {
...step.execution,
...execution,
};
}
this.updateStepInRoute(step);
return step;
}
/**
* Finds a process of the specified type in the step's execution
* @param step The step to search in
* @param type The process type to find
* @param status Optional status to update the process with if found
* @returns The found process or undefined if not found
*/
findProcess(step, type, status) {
if (!step.execution?.process) {
throw new Error("Execution hasn't been initialized.");
}
const process = step.execution.process.find((p) => p.type === type);
if (process && status && process.status !== status) {
process.status = status;
this.updateStepInRoute(step);
}
return process;
}
/**
* Create and push a new process into the execution.
* @param step The step that should contain the new process.
* @param type Type of the process. Used to identify already existing processes.
* @param chainId Chain Id of the process.
* @param status By default created procces is set to the STARTED status. We can override new process with the needed status.
* @returns Returns process.
*/
findOrCreateProcess = ({ step, type, chainId, status, startedAt, }) => {
const process = this.findProcess(step, type, status);
if (process) {
return process;
}
const newProcess = {
type: type,
startedAt: startedAt ?? Date.now(),
message: getProcessMessage(type, status ?? 'STARTED'),
status: status ?? 'STARTED',
chainId: chainId,
};
step.execution.process.push(newProcess);
this.updateStepInRoute(step);
return newProcess;
};
/**
* Update a process object.
* @param step The step where the process should be updated
* @param type The process type to update
* @param status The status the process gets.
* @param [params] Additional parameters to append to the process.
* @returns The update process
*/
updateProcess = (step, type, status, params) => {
if (!step.execution) {
throw new Error("Can't update an empty step execution.");
}
const currentProcess = this.findProcess(step, type);
if (!currentProcess) {
throw new Error("Can't find a process for the given type.");
}
switch (status) {
case 'CANCELLED':
currentProcess.doneAt = Date.now();
break;
case 'FAILED':
currentProcess.doneAt = Date.now();
step.execution.status = 'FAILED';
break;
case 'DONE':
currentProcess.doneAt = Date.now();
break;
case 'PENDING':
step.execution.status = 'PENDING';
currentProcess.pendingAt = Date.now();
break;
case 'ACTION_REQUIRED':
step.execution.status = 'ACTION_REQUIRED';
currentProcess.actionRequiredAt = Date.now();
break;
default:
break;
}
currentProcess.status = status;
currentProcess.message = getProcessMessage(type, status);
// set extra parameters or overwritte the standard params set in the switch statement
if (params) {
for (const [key, value] of Object.entries(params)) {
currentProcess[key] = value;
}
}
// Sort processes, the ones with DONE status go first
step.execution.process = [
...step.execution.process.filter((process) => process.status === 'DONE'),
...step.execution.process.filter((process) => process.status !== 'DONE'),
];
this.updateStepInRoute(step); // updates the step in the route
return currentProcess;
};
/**
* Remove a process from the execution
* @param step The step where the process should be removed from
* @param type The process type to remove
*/
removeProcess = (step, type) => {
if (!step.execution) {
throw new Error("Execution hasn't been initialized.");
}
const index = step.execution.process.findIndex((p) => p.type === type);
step.execution.process.splice(index, 1);
this.updateStepInRoute(step);
};
updateStepInRoute = (step) => {
if (!this.shouldUpdate) {
return step;
}
const data = executionState.get(this.routeId);
if (!data) {
throw new Error('Execution data not found.');
}
const stepIndex = data.route.steps.findIndex((routeStep) => routeStep.id === step.id);
if (stepIndex === -1) {
throw new Error("Couldn't find a step to update.");
}
data.route.steps[stepIndex] = { ...data.route.steps[stepIndex], ...step };
data.executionOptions?.updateRouteHook?.(data.route);
return data.route.steps[stepIndex];
};
allowUpdates(value) {
this.shouldUpdate = value;
}
}
//# sourceMappingURL=StatusManager.js.map