robosats/frontend/src/models/Slot.model.ts

171 lines
5.2 KiB
TypeScript
Raw Normal View History

2023-12-15 15:17:46 +00:00
import { sha256 } from 'js-sha256';
2024-08-15 14:26:04 +00:00
import { Robot, Order, type Federation } from '.';
2024-04-30 14:01:54 +00:00
import { roboidentitiesClient } from '../services/Roboidentities/Web';
2024-08-15 14:26:04 +00:00
import { hexToBase91, validateTokenEntropy } from '../utils';
export interface AuthHeaders {
tokenSHA256: string;
keys: {
pubKey: string;
encPrivKey: string;
};
}
2023-11-21 17:36:59 +00:00
class Slot {
2024-05-01 18:11:20 +00:00
constructor(
token: string,
shortAliases: string[],
robotAttributes: Record<any, any>,
2024-08-15 14:26:04 +00:00
onSlotUpdate: () => void,
2024-05-01 18:11:20 +00:00
) {
2024-08-15 14:26:04 +00:00
this.onSlotUpdate = onSlotUpdate;
2023-11-21 17:36:59 +00:00
this.token = token;
2023-12-15 15:17:46 +00:00
this.hashId = sha256(sha256(this.token));
2024-04-28 12:34:32 +00:00
this.nickname = null;
2024-08-10 15:54:13 +00:00
void roboidentitiesClient.generateRoboname(this.hashId).then((nickname) => {
2024-04-27 21:33:52 +00:00
this.nickname = nickname;
2024-08-15 14:26:04 +00:00
onSlotUpdate();
2024-04-27 21:33:52 +00:00
});
2024-08-10 15:54:13 +00:00
void roboidentitiesClient.generateRobohash(this.hashId, 'small');
void roboidentitiesClient.generateRobohash(this.hashId, 'large');
2023-12-15 15:17:46 +00:00
2024-08-15 14:26:04 +00:00
const { hasEnoughEntropy, bitsEntropy, shannonEntropy } = validateTokenEntropy(token);
const tokenSHA256 = hexToBase91(sha256(token));
this.robots = shortAliases.reduce((acc: Record<string, Robot>, shortAlias: string) => {
2024-08-15 14:26:04 +00:00
acc[shortAlias] = new Robot({
...robotAttributes,
shortAlias,
hasEnoughEntropy,
bitsEntropy,
shannonEntropy,
tokenSHA256,
});
this.updateSlotFromRobot(acc[shortAlias]);
return acc;
}, {});
2023-12-15 15:17:46 +00:00
2023-11-21 17:36:59 +00:00
this.copiedToken = false;
2024-08-15 14:26:04 +00:00
this.onSlotUpdate();
2023-11-21 17:36:59 +00:00
}
token: string | null;
2023-12-15 15:17:46 +00:00
hashId: string | null;
nickname: string | null;
2023-12-02 19:50:07 +00:00
robots: Record<string, Robot>;
2024-08-15 14:26:04 +00:00
activeOrder: Order | null = null;
lastOrder: Order | null = null;
2023-11-21 17:36:59 +00:00
copiedToken: boolean;
2024-08-15 14:26:04 +00:00
onSlotUpdate: () => void;
2023-11-21 17:36:59 +00:00
setCopiedToken = (copied: boolean): void => {
this.copiedToken = copied;
};
2024-08-15 14:26:04 +00:00
// Robots
2023-11-21 17:36:59 +00:00
getRobot = (shortAlias?: string): Robot | null => {
2023-12-22 12:58:59 +00:00
if (shortAlias) {
2023-11-21 17:36:59 +00:00
return this.robots[shortAlias];
2024-08-15 14:26:04 +00:00
} else if (this.activeOrder?.id) {
return this.robots[this.activeOrder.shortAlias];
} else if (this.lastOrder?.id && this.robots[this.lastOrder.shortAlias]) {
return this.robots[this.lastOrder.shortAlias];
2023-11-21 17:36:59 +00:00
} else if (Object.values(this.robots).length > 0) {
return Object.values(this.robots)[0];
}
return null;
};
2024-08-15 14:26:04 +00:00
fetchRobot = async (federation: Federation): Promise<void> => {
Object.values(this.robots).forEach((robot) => {
void robot.fetch(federation).then((robot) => {
this.updateSlotFromRobot(robot);
});
});
};
2023-11-21 17:36:59 +00:00
2024-08-15 14:26:04 +00:00
updateSlotFromRobot = (robot: Robot | null): void => {
if (robot?.lastOrderId && this.lastOrder?.id !== robot?.lastOrderId) {
this.lastOrder = new Order({ id: robot.lastOrderId, shortAlias: robot.shortAlias });
if (this.activeOrder?.id === robot.lastOrderId) {
this.lastOrder = this.activeOrder;
this.activeOrder = null;
2023-11-21 17:36:59 +00:00
}
}
2024-08-15 14:26:04 +00:00
if (robot?.activeOrderId && this.activeOrder?.id !== robot.activeOrderId) {
this.activeOrder = new Order({
id: robot.activeOrderId,
shortAlias: robot.shortAlias,
});
2023-11-21 17:36:59 +00:00
}
2024-08-15 14:26:04 +00:00
this.onSlotUpdate();
};
// Orders
fetchActiveOrder = async (federation: Federation): Promise<void> => {
void this.activeOrder?.fecth(federation, this);
this.updateSlotFromOrder(this.activeOrder);
};
2023-11-21 17:36:59 +00:00
2024-09-10 15:55:29 +00:00
takeOrder = async (federation: Federation, order: Order, takeAmount: string): Promise<Order> => {
await order.take(federation, this, takeAmount);
this.updateSlotFromOrder(order);
return order;
};
2024-08-15 14:26:04 +00:00
makeOrder = async (federation: Federation, attributes: object): Promise<Order> => {
const order = new Order(attributes);
await order.make(federation, this);
this.lastOrder = this.activeOrder;
this.activeOrder = order;
this.onSlotUpdate();
return this.activeOrder;
};
updateSlotFromOrder: (newOrder: Order | null) => void = (newOrder) => {
if (newOrder) {
// FIXME: API responses with bad_request should include also order's status
if (newOrder?.bad_request?.includes('expired')) newOrder.status = 5;
2024-09-10 15:55:29 +00:00
if (newOrder?.bad_request?.includes('collaborativelly')) newOrder.status = 12;
2024-08-15 14:26:04 +00:00
if (
newOrder.id === this.activeOrder?.id &&
newOrder.shortAlias === this.activeOrder?.shortAlias
) {
this.activeOrder?.update(newOrder);
if (this.activeOrder?.bad_request) {
this.lastOrder = this.activeOrder;
this.activeOrder = null;
}
this.onSlotUpdate();
} else if (newOrder?.is_participant && this.lastOrder?.id !== newOrder.id) {
this.activeOrder = newOrder;
this.onSlotUpdate();
}
}
2023-11-21 17:36:59 +00:00
};
2024-08-15 14:26:04 +00:00
syncCoordinator: (federation: Federation, shortAlias: string) => void = (
federation,
shortAlias,
) => {
const defaultRobot = this.getRobot();
if (defaultRobot?.token) {
2024-08-15 14:26:04 +00:00
this.robots[shortAlias] = new Robot({
shortAlias,
hasEnoughEntropy: defaultRobot.hasEnoughEntropy,
bitsEntropy: defaultRobot.bitsEntropy,
shannonEntropy: defaultRobot.shannonEntropy,
token: defaultRobot.token,
pubKey: defaultRobot.pubKey,
encPrivKey: defaultRobot.encPrivKey,
});
2024-08-15 14:26:04 +00:00
void this.robots[shortAlias].fetch(federation);
this.updateSlotFromRobot(this.robots[shortAlias]);
}
};
2023-11-21 17:36:59 +00:00
}
export default Slot;