118 lines
5.6 KiB
TypeScript
118 lines
5.6 KiB
TypeScript
import Services from "./services";
|
|
import { AnkFlag, AnkNetworkMsg, CachedMessage } from "../dist/pkg/sdk_client";
|
|
|
|
class WebSocketClient {
|
|
private ws: WebSocket;
|
|
private messageQueue: string[] = [];
|
|
|
|
constructor(url: string, private services: Services) {
|
|
this.ws = new WebSocket(url);
|
|
|
|
this.ws.addEventListener('open', (event) => {
|
|
console.log('WebSocket connection established');
|
|
// Once the connection is open, send all messages in the queue
|
|
while (this.messageQueue.length > 0) {
|
|
const message = this.messageQueue.shift();
|
|
if (message) {
|
|
this.ws.send(message);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Listen for messages
|
|
this.ws.addEventListener('message', (event) => {
|
|
const msgData = event.data;
|
|
|
|
(async () => {
|
|
if (typeof(msgData) === 'string') {
|
|
console.log("Received text message: "+msgData);
|
|
try {
|
|
const feeRate = 1;
|
|
// By parsing the message, we can link it with existing cached message and return the updated version of the message
|
|
let res: CachedMessage = await services.parseNetworkMessage(msgData, feeRate);
|
|
console.debug(res);
|
|
if (res.status === 'FaucetComplete') {
|
|
// we received a faucet tx, there's nothing else to do
|
|
window.alert(`New faucet output\n${res.commited_in}`);
|
|
await services.updateMessages(res);
|
|
await services.updateOwnedOutputsForUser();
|
|
} else if (res.status === 'TxWaitingCipher') {
|
|
// we received a tx but we don't have the cipher
|
|
console.debug(`received notification in output ${res.commited_in}, waiting for cipher message`);
|
|
await services.updateMessages(res);
|
|
await services.updateOwnedOutputsForUser();
|
|
} else if (res.status === 'CipherWaitingTx') {
|
|
// we received a cipher but we don't have the key
|
|
console.debug(`received a cipher`);
|
|
await services.updateMessages(res);
|
|
} else if (res.status === 'SentWaitingConfirmation') {
|
|
// We are sender and we're waiting for the challenge that will confirm recipient got the transaction and the message
|
|
await services.updateMessages(res);
|
|
await services.updateOwnedOutputsForUser();
|
|
} else if (res.status === 'MustSpendConfirmation') {
|
|
// we received a challenge for a notification we made
|
|
// that means we can stop rebroadcasting the tx and we must spend the challenge to confirm
|
|
window.alert(`Spending ${res.confirmed_by} to prove our identity`);
|
|
console.debug(`sending confirm message to ${res.recipient}`);
|
|
await services.updateMessages(res);
|
|
await services.answer_confirmation_message(res);
|
|
} else if (res.status === 'ReceivedMustConfirm') {
|
|
// we found a notification and decrypted the cipher
|
|
window.alert(`Received message from ${res.sender}\n${res.plaintext}`);
|
|
// we must spend the commited_in output to sender
|
|
await services.updateMessages(res);
|
|
await services.confirm_sender_address(res);
|
|
} else if (res.status === 'Complete') {
|
|
window.alert(`Received confirmation that ${res.sender} is the author of message ${res.plaintext}`)
|
|
await services.updateMessages(res);
|
|
await services.updateOwnedOutputsForUser();
|
|
} else {
|
|
console.debug('Received an unimplemented valid message');
|
|
}
|
|
} catch (error) {
|
|
console.error('Received an invalid message:', error);
|
|
}
|
|
} else {
|
|
console.error('Received a non-string message');
|
|
}
|
|
})();
|
|
});
|
|
|
|
// Listen for possible errors
|
|
this.ws.addEventListener('error', (event) => {
|
|
console.error('WebSocket error:', event);
|
|
});
|
|
|
|
// Listen for when the connection is closed
|
|
this.ws.addEventListener('close', (event) => {
|
|
console.log('WebSocket is closed now.');
|
|
});
|
|
}
|
|
|
|
// Method to send messages
|
|
public sendMessage(flag: AnkFlag, message: string): void {
|
|
if (this.ws.readyState === WebSocket.OPEN) {
|
|
const networkMessage: AnkNetworkMsg = {
|
|
'flag': flag,
|
|
'content': message
|
|
}
|
|
// console.debug("Sending message:", JSON.stringify(networkMessage));
|
|
this.ws.send(JSON.stringify(networkMessage));
|
|
} else {
|
|
console.warn('WebSocket is not open. ReadyState:', this.ws.readyState);
|
|
this.messageQueue.push(message);
|
|
}
|
|
}
|
|
|
|
public getUrl(): string {
|
|
return this.ws.url;
|
|
}
|
|
|
|
// Method to close the WebSocket connection
|
|
public close(): void {
|
|
this.ws.close();
|
|
}
|
|
}
|
|
|
|
export { WebSocketClient };
|