fusion_sosthene_ok

This commit is contained in:
Pascal 2024-11-25 12:36:12 +01:00
commit 86373b2eca
9 changed files with 214 additions and 137 deletions

View File

@ -34,4 +34,4 @@
<div id="emoji-display-2"></div> <div id="emoji-display-2"></div>
<button id="okButton" style="display: none">OK</button> <button id="okButton" style="display: none">OK</button>
</div> </div>
</div> </div>

View File

@ -55,7 +55,15 @@ async function onScanSuccess(decodedText: any, decodedResult: any) {
html5QrcodeScanner.clear(); html5QrcodeScanner.clear();
const service = await Services.getInstance(); const service = await Services.getInstance();
// Call the sendPairingTx function with the extracted sp_address // Call the sendPairingTx function with the extracted sp_address
await service.sendPairingTx(spAddress); try {
const member = {
sp_addresses: [spAddress],
}
service.connectMember([member]);
// await service.sendPairingTx(spAddress);
} catch (e) {
console.error('Failed to pair:', e);
}
} else { } else {
console.error('The scanned URL does not contain the sp_address parameter.'); console.error('The scanned URL does not contain the sp_address parameter.');
alert('Invalid QR code: sp_address parameter missing.'); alert('Invalid QR code: sp_address parameter missing.');

View File

@ -104,7 +104,6 @@ async function init(): Promise<void> {
await services.restoreDevice(device); await services.restoreDevice(device);
} }
await services.restoreProcesses(); await services.restoreProcesses();
await services.restoreMessages();
if (services.isPaired()) { if (services.isPaired()) {
await navigate('process'); await navigate('process');
@ -113,7 +112,14 @@ async function init(): Promise<void> {
const urlParams = new URLSearchParams(queryString); const urlParams = new URLSearchParams(queryString);
const pairingAddress = urlParams.get('sp_address'); const pairingAddress = urlParams.get('sp_address');
if (pairingAddress) { if (pairingAddress) {
setTimeout(async () => await services.sendPairingTx(pairingAddress), 2000); setTimeout(async () => {
// await services.sendPairingTx(pairingAddress)
try {
services.connectMember([{sp_addresses: [pairingAddress]}]);
} catch (e) {
console.error('Failed to pair:', e);
}
}, 2000);
} }
await navigate('home'); await navigate('home');
} }

View File

@ -0,0 +1,20 @@
const addResourcesToCache = async (resources) => {
const cache = await caches.open("v1");
await cache.addAll(resources);
};
self.addEventListener("install", (event) => {
event.waitUntil(
addResourcesToCache([
"/",
"/index.html",
"/style.css",
"/app.js",
"/image-list.js",
"/star-wars-logo.jpg",
"/gallery/bountyHunters.jpg",
"/gallery/myLittleVader.jpg",
"/gallery/snowTroopers.jpg",
]),
);
});

View File

@ -1,5 +1,3 @@
import Database from '../services/database.service';
self.addEventListener('install', (event) => { self.addEventListener('install', (event) => {
event.waitUntil(self.skipWaiting()); // Activate worker immediately event.waitUntil(self.skipWaiting()); // Activate worker immediately
}); });
@ -11,7 +9,6 @@ self.addEventListener('activate', (event) => {
// Event listener for messages from clients // Event listener for messages from clients
self.addEventListener('message', async (event) => { self.addEventListener('message', async (event) => {
const data = event.data; const data = event.data;
const db = await Database.getInstance();
if (data.type === 'ADD_OBJECT') { if (data.type === 'ADD_OBJECT') {
try { try {
@ -19,26 +16,18 @@ self.addEventListener('message', async (event) => {
const db = await openDatabase(); const db = await openDatabase();
const tx = db.transaction(storeName, 'readwrite'); const tx = db.transaction(storeName, 'readwrite');
const store = tx.objectStore(storeName); const store = tx.objectStore(storeName);
await store.put(object);
event.ports[0].postMessage({ status: 'success', message: 'Object added or replaced successfully' }); if (key) {
await store.put(object, key);
} else {
await store.put(object);
}
event.ports[0].postMessage({ status: 'success', message: '' });
} catch (error) { } catch (error) {
event.ports[0].postMessage({ status: 'error', message: error.message }); event.ports[0].postMessage({ status: 'error', message: error.message });
} }
} }
if (data.type === 'GET_OBJECT') {
const { storeName, key } = data.payload;
const db = await openDatabase();
const tx = db.transaction(storeName, 'readonly');
const store = tx.objectStore(storeName);
const result = await new Promise((resolve, reject) => {
const getRequest = store.get(key);
getRequest.onsuccess = (event) => resolve(getRequest.result);
getRequest.onerror = (event) => reject(getRequest.error);
});
event.ports[0].postMessage({ type: 'GET_OBJECT_RESULT', payload: result });
}
}); });
async function openDatabase() { async function openDatabase() {

View File

@ -17,9 +17,14 @@ class Database {
options: { keyPath: 'id' }, options: { keyPath: 'id' },
indices: [], indices: [],
}, },
AnkMessages: { AnkSharedSecrets: {
name: 'messages', name: 'shared_secrets',
options: { keyPath: 'id' }, options: { keyPath: 'key' },
indices: [],
},
AnkUnconfirmedSecrets: {
name: 'unconfirmed_secrets',
options: { autoIncrement: true },
indices: [], indices: [],
}, },
AnkProcessData: { AnkProcessData: {
@ -139,31 +144,52 @@ class Database {
console.log('Received response from service worker (GET_OBJECT):', event.data); console.log('Received response from service worker (GET_OBJECT):', event.data);
}; };
public addObject(payload: { storeName: string; object: any; key: any }) { public addObject(payload: { storeName: string; object: any; key: any }): Promise<void> {
if (this.serviceWorkerRegistration?.active) { return new Promise((resolve, reject) => {
const messageChannel = this.createMessageChannel(this.handleAddObjectResponse); // Check if the service worker is active
this.serviceWorkerRegistration.active.postMessage( if (!this.serviceWorkerRegistration?.active) {
{ reject(new Error('Service worker is not active'));
type: 'ADD_OBJECT', return;
payload, }
},
[messageChannel.port2], // Create a message channel for communication
); const messageChannel = new MessageChannel();
}
// Handle the response from the service worker
messageChannel.port1.onmessage = (event) => {
if (event.data.status === 'success') {
resolve();
} else {
const error = event.data.message;
reject(new Error(error || 'Unknown error occurred while adding object'));
}
};
// Send the add object request to the service worker
try {
this.serviceWorkerRegistration.active.postMessage(
{
type: 'ADD_OBJECT',
payload,
},
[messageChannel.port2],
);
} catch (error) {
reject(new Error(`Failed to send message to service worker: ${error}`));
}
});
} }
public getObject(storeName: string, key: string) { public async getObject(storeName: string, key: string): Promise<any | null> {
if (this.serviceWorkerRegistration?.active) { const db = await this.getDb();
const messageChannel = this.createMessageChannel(this.handleGetObjectResponse); const tx = db.transaction(storeName, 'readonly');
const store = tx.objectStore(storeName);
this.serviceWorkerRegistration.active.postMessage( const result = await new Promise((resolve, reject) => {
{ const getRequest = store.get(key);
type: 'GET_OBJECT', getRequest.onsuccess = () => resolve(getRequest.result);
payload: { storeName, key }, getRequest.onerror = () => reject(getRequest.error);
}, });
[messageChannel.port2], return result
);
}
} }
} }

View File

@ -103,6 +103,50 @@ export default class Services {
return apiReturn; return apiReturn;
} }
public async connectMember(members: Member[]): Promise<void> {
if (members.length === 0) {
throw new Error('Trying to connect to empty members list');
}
const members_str = members.map(member => JSON.stringify(member));
const waitForAmount = async (): Promise<BigInt> => {
let attempts = 3;
while (attempts > 0) {
const amount = this.getAmount();
if (amount !== 0n) {
return amount;
}
attempts--;
if (attempts > 0) {
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for 1 second
}
}
throw new Error('Amount is still 0 after 3 attempts');
};
let availableAmt = this.getAmount();
if (availableAmt === 0n) {
const faucetMsg = this.createFaucetMessage();
this.sendFaucetMessage(faucetMsg);
try {
availableAmt = await waitForAmount();
} catch (e) {
console.error('Failed to retrieve amount:', e);
throw e; // Rethrow the error if needed
}
}
try {
const apiReturn = this.sdkClient.create_connect_transaction(members_str, 1);
await this.handleApiReturn(apiReturn);
} catch (e) {
console.error('Failed to connect:', e);
}
}
public async sendPairingTx(spAddress: string): Promise<void> { public async sendPairingTx(spAddress: string): Promise<void> {
const localAddress = this.sdkClient.get_address(); const localAddress = this.sdkClient.get_address();
const emptyTxid = '0'.repeat(64); const emptyTxid = '0'.repeat(64);
@ -142,9 +186,10 @@ export default class Services {
} }
} }
async sendFaucetMessage(message: string): Promise<void> { sendFaucetMessage(message: string): void {
await sendMessage('Faucet', message); sendMessage('Faucet', message);
} }
async parseCipher(message: string) { async parseCipher(message: string) {
try { try {
console.log('parsing new cipher'); console.log('parsing new cipher');
@ -159,7 +204,7 @@ export default class Services {
async parseNewTx(tx: string) { async parseNewTx(tx: string) {
try { try {
const parsedTx = await this.sdkClient.parse_new_tx(tx, 0, 0.0001); const parsedTx = await this.sdkClient.parse_new_tx(tx, 0);
if (parsedTx) { if (parsedTx) {
console.log('🚀 ~ Services ~ parseNewTx ~ parsedTx:', parsedTx); console.log('🚀 ~ Services ~ parseNewTx ~ parsedTx:', parsedTx);
try { try {
@ -176,8 +221,33 @@ export default class Services {
} }
private async handleApiReturn(apiReturn: ApiReturn) { private async handleApiReturn(apiReturn: ApiReturn) {
if (apiReturn.ciphers_to_send && apiReturn.ciphers_to_send.length) { if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) {
await this.sendCipherMessages(apiReturn.ciphers_to_send); await this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send));
}
if (apiReturn.secrets) {
const unconfirmedSecrets = apiReturn.secrets.unconfirmed_secrets;
const confirmedSecrets = apiReturn.secrets.shared_secrets;
console.log('confirmedSecrets:', confirmedSecrets);
const db = await Database.getInstance();
for (const secret of unconfirmedSecrets) {
db.addObject({
storeName: 'unconfirmed_secrets',
object: secret,
key: null,
});
}
const entries = Object.entries(confirmedSecrets).map(([key, value]) => ({ key, value }));
for (const entry of entries) {
console.log('entry:', entry);
db.addObject({
storeName: 'shared_secrets',
object: entry,
key: null,
});
}
} }
setTimeout(async () => { setTimeout(async () => {
@ -207,27 +277,17 @@ export default class Services {
} }
} }
if (apiReturn.updated_cached_msg && apiReturn.updated_cached_msg.length) {
apiReturn.updated_cached_msg.forEach(async (msg, index) => {
// console.debug(`CachedMessage ${index}:`, msg);
// Save the message to local storage
localStorage.setItem(msg.id.toString(), JSON.stringify(msg));
const db = await Database.getInstance();
db.addObject({
storeName: 'messages',
object: { id: msg.id.toString(), msg },
key: msg.id.toString(),
});
});
}
if (apiReturn.commit_to_send) { if (apiReturn.commit_to_send) {
const commit = apiReturn.commit_to_send; const commit = apiReturn.commit_to_send;
await this.sendCommitMessage(JSON.stringify(commit)); await this.sendCommitMessage(JSON.stringify(commit));
} }
if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) { if (apiReturn.decrypted_pcds && apiReturn.decrypted_pcds.length != 0) {
await this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send)); // TODO
}
if (apiReturn.ciphers_to_send && apiReturn.ciphers_to_send.length != 0) {
await this.sendCipherMessages(apiReturn.ciphers_to_send);
} }
}, 0); }, 0);
} }
@ -281,8 +341,8 @@ export default class Services {
} }
} }
async getAmount(): Promise<BigInt> { public getAmount(): BigInt {
const amount = await this.sdkClient.get_available_amount(); const amount = this.sdkClient.get_available_amount();
return amount; return amount;
} }
@ -297,18 +357,30 @@ export default class Services {
async saveDevice(device: any): Promise<any> { async saveDevice(device: any): Promise<any> {
const db = await Database.getInstance(); const db = await Database.getInstance();
db.addObject({ try {
storeName: 'wallet', await db.addObject({
object: { pre_id: '1', device }, storeName: 'wallet',
key: '1', object: { pre_id: '1', device },
}); key: null,
localStorage.setItem('wallet', device); });
} catch (e) {
console.error(e);
}
} }
async getDevice(): Promise<string | null> { async getDevice(): Promise<string | null> {
const db = await Database.getInstance(); const db = await Database.getInstance();
db.getObject('wallet', '1'); try {
return localStorage.getItem('wallet'); const dbRes = await db.getObject('wallet', '1');
if (dbRes) {
const wallet = dbRes['device'];
return wallet;
} else {
return null;
}
} catch (e) {
throw new Error(`Failed to retrieve device from db: ${e}`);
}
} }
async dumpWallet() { async dumpWallet() {
@ -317,8 +389,8 @@ export default class Services {
return wallet; return wallet;
} }
async createFaucetMessage() { public createFaucetMessage() {
const message = await this.sdkClient.create_faucet_msg(); const message = this.sdkClient.create_faucet_msg();
console.log('🚀 ~ Services ~ createFaucetMessage ~ message:', message); console.log('🚀 ~ Services ~ createFaucetMessage ~ message:', message);
return message; return message;
} }
@ -447,38 +519,6 @@ export default class Services {
return hexObjects; return hexObjects;
} }
private getCachedMessages(): string[] {
const u32KeyRegex = /^\d+$/;
const U32_MAX = 4294967295;
const messages: string[] = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (!key) {
return messages;
}
if (u32KeyRegex.test(key)) {
const num = parseInt(key, 10);
if (num < 0 || num > U32_MAX) {
console.warn(`Key ${key} is outside the u32 range and will be ignored.`);
continue;
}
const value = localStorage.getItem(key);
if (!value) {
console.warn(`No value found for key: ${key}`);
continue;
}
messages.push(value);
}
}
return messages;
}
public async restoreProcesses() { public async restoreProcesses() {
const processesCache = this.getProcessesCache(); const processesCache = this.getProcessesCache();
console.log('🚀 ~ Services ~ restoreProcesses ~ processesCache:', processesCache); console.log('🚀 ~ Services ~ restoreProcesses ~ processesCache:', processesCache);
@ -495,19 +535,6 @@ export default class Services {
} }
} }
public async restoreMessages() {
const cachedMessages = this.getCachedMessages();
console.log('🚀 ~ Services ~ restoreMessages ~ chachedMessages:', cachedMessages);
if (cachedMessages && cachedMessages.length != 0) {
try {
await this.sdkClient.set_message_cache(cachedMessages);
} catch (e) {
console.error('Services ~ restoreMessages ~ Error:', e);
}
}
}
getNotifications(): INotification[] { getNotifications(): INotification[] {
return [ return [
{ {

View File

@ -148,7 +148,15 @@ export function initAddressInput() {
async function onOkButtonClick() { async function onOkButtonClick() {
const service = await Services.getInstance(); const service = await Services.getInstance();
const addressInput = (document.getElementById('addressInput') as HTMLInputElement).value; const addressInput = (document.getElementById('addressInput') as HTMLInputElement).value;
await service.sendPairingTx(addressInput); const member = {
sp_addresses: [addressInput],
}
try {
service.connectMember([member]);
// await service.sendPairingTx(addressInput);
} catch (e) {
console.error('onOkButtonClick error:', e);
}
} }
export async function generateQRCode(spAddress: string) { export async function generateQRCode(spAddress: string) {

View File

@ -3,21 +3,13 @@ import Services from './services/service';
let ws: WebSocket; let ws: WebSocket;
let messageQueue: string[] = []; let messageQueue: string[] = [];
let services: Services;
export async function initWebsocket(url: string) { export async function initWebsocket(url: string) {
ws = new WebSocket(url); ws = new WebSocket(url);
services = await Services.getInstance();
if (ws !== null) { if (ws !== null) {
ws.onopen = async (event) => { ws.onopen = async (event) => {
console.log('WebSocket connection established'); console.log('WebSocket connection established');
const amount = await services.getAmount();
if (amount === 0n) {
const faucetMsg = await services.createFaucetMessage();
await services.sendFaucetMessage(faucetMsg);
}
while (messageQueue.length > 0) { while (messageQueue.length > 0) {
const message = messageQueue.shift(); const message = messageQueue.shift();
if (message) { if (message) {
@ -36,6 +28,7 @@ export async function initWebsocket(url: string) {
try { try {
const feeRate = 0.0001; const feeRate = 0.0001;
const parsedMessage = JSON.parse(msgData); const parsedMessage = JSON.parse(msgData);
const services = await Services.getInstance();
switch (parsedMessage.flag) { switch (parsedMessage.flag) {
case 'NewTx': case 'NewTx':
await services.parseNewTx(parsedMessage.content); await services.parseNewTx(parsedMessage.content);
@ -66,7 +59,7 @@ export async function initWebsocket(url: string) {
} }
// Method to send messages // Method to send messages
export async function sendMessage(flag: AnkFlag, message: string): Promise<void> { export function sendMessage(flag: AnkFlag, message: string): void {
if (ws.readyState === WebSocket.OPEN) { if (ws.readyState === WebSocket.OPEN) {
const networkMessage = { const networkMessage = {
flag: flag, flag: flag,