diff --git a/src/pages/home/home.html b/src/pages/home/home.html
index 84676b6..842dd76 100755
--- a/src/pages/home/home.html
+++ b/src/pages/home/home.html
@@ -34,4 +34,4 @@
-
+
\ No newline at end of file
diff --git a/src/pages/home/home.ts b/src/pages/home/home.ts
index fb6c9a3..f2d9bad 100755
--- a/src/pages/home/home.ts
+++ b/src/pages/home/home.ts
@@ -55,7 +55,15 @@ async function onScanSuccess(decodedText: any, decodedResult: any) {
html5QrcodeScanner.clear();
const service = await Services.getInstance();
// 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 {
console.error('The scanned URL does not contain the sp_address parameter.');
alert('Invalid QR code: sp_address parameter missing.');
diff --git a/src/router.ts b/src/router.ts
index 5f809e7..729fc1b 100755
--- a/src/router.ts
+++ b/src/router.ts
@@ -104,7 +104,6 @@ async function init(): Promise {
await services.restoreDevice(device);
}
await services.restoreProcesses();
- await services.restoreMessages();
if (services.isPaired()) {
await navigate('process');
@@ -113,7 +112,14 @@ async function init(): Promise {
const urlParams = new URLSearchParams(queryString);
const pairingAddress = urlParams.get('sp_address');
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');
}
diff --git a/src/service-workers/cache.worker.js b/src/service-workers/cache.worker.js
new file mode 100644
index 0000000..42e720c
--- /dev/null
+++ b/src/service-workers/cache.worker.js
@@ -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",
+ ]),
+ );
+ });
\ No newline at end of file
diff --git a/src/service-workers/database.worker.js b/src/service-workers/database.worker.js
index fa75692..78cc01c 100755
--- a/src/service-workers/database.worker.js
+++ b/src/service-workers/database.worker.js
@@ -1,5 +1,3 @@
-import Database from '../services/database.service';
-
self.addEventListener('install', (event) => {
event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
@@ -11,7 +9,6 @@ self.addEventListener('activate', (event) => {
// Event listener for messages from clients
self.addEventListener('message', async (event) => {
const data = event.data;
- const db = await Database.getInstance();
if (data.type === 'ADD_OBJECT') {
try {
@@ -19,26 +16,18 @@ self.addEventListener('message', async (event) => {
const db = await openDatabase();
const tx = db.transaction(storeName, 'readwrite');
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) {
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() {
diff --git a/src/services/database.service.ts b/src/services/database.service.ts
index 5749806..53225b7 100755
--- a/src/services/database.service.ts
+++ b/src/services/database.service.ts
@@ -17,9 +17,14 @@ class Database {
options: { keyPath: 'id' },
indices: [],
},
- AnkMessages: {
- name: 'messages',
- options: { keyPath: 'id' },
+ AnkSharedSecrets: {
+ name: 'shared_secrets',
+ options: { keyPath: 'key' },
+ indices: [],
+ },
+ AnkUnconfirmedSecrets: {
+ name: 'unconfirmed_secrets',
+ options: { autoIncrement: true },
indices: [],
},
AnkProcessData: {
@@ -139,31 +144,52 @@ class Database {
console.log('Received response from service worker (GET_OBJECT):', event.data);
};
- public addObject(payload: { storeName: string; object: any; key: any }) {
- if (this.serviceWorkerRegistration?.active) {
- const messageChannel = this.createMessageChannel(this.handleAddObjectResponse);
- this.serviceWorkerRegistration.active.postMessage(
- {
- type: 'ADD_OBJECT',
- payload,
- },
- [messageChannel.port2],
- );
- }
+ public addObject(payload: { storeName: string; object: any; key: any }): Promise {
+ return new Promise((resolve, reject) => {
+ // Check if the service worker is active
+ if (!this.serviceWorkerRegistration?.active) {
+ reject(new Error('Service worker is not active'));
+ return;
+ }
+
+ // 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) {
- if (this.serviceWorkerRegistration?.active) {
- const messageChannel = this.createMessageChannel(this.handleGetObjectResponse);
-
- this.serviceWorkerRegistration.active.postMessage(
- {
- type: 'GET_OBJECT',
- payload: { storeName, key },
- },
- [messageChannel.port2],
- );
- }
+ public async getObject(storeName: string, key: string): Promise {
+ const db = await this.getDb();
+ 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 = () => resolve(getRequest.result);
+ getRequest.onerror = () => reject(getRequest.error);
+ });
+ return result
}
}
diff --git a/src/services/service.ts b/src/services/service.ts
index fbbb8db..706ef73 100755
--- a/src/services/service.ts
+++ b/src/services/service.ts
@@ -103,6 +103,50 @@ export default class Services {
return apiReturn;
}
+ public async connectMember(members: Member[]): Promise {
+ 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 => {
+ 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 {
const localAddress = this.sdkClient.get_address();
const emptyTxid = '0'.repeat(64);
@@ -142,9 +186,10 @@ export default class Services {
}
}
- async sendFaucetMessage(message: string): Promise {
- await sendMessage('Faucet', message);
+ sendFaucetMessage(message: string): void {
+ sendMessage('Faucet', message);
}
+
async parseCipher(message: string) {
try {
console.log('parsing new cipher');
@@ -159,7 +204,7 @@ export default class Services {
async parseNewTx(tx: string) {
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) {
console.log('🚀 ~ Services ~ parseNewTx ~ parsedTx:', parsedTx);
try {
@@ -176,8 +221,33 @@ export default class Services {
}
private async handleApiReturn(apiReturn: ApiReturn) {
- if (apiReturn.ciphers_to_send && apiReturn.ciphers_to_send.length) {
- await this.sendCipherMessages(apiReturn.ciphers_to_send);
+ if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) {
+ 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 () => {
@@ -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) {
const commit = apiReturn.commit_to_send;
await this.sendCommitMessage(JSON.stringify(commit));
}
- if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) {
- await this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send));
+ if (apiReturn.decrypted_pcds && apiReturn.decrypted_pcds.length != 0) {
+ // TODO
+ }
+
+ if (apiReturn.ciphers_to_send && apiReturn.ciphers_to_send.length != 0) {
+ await this.sendCipherMessages(apiReturn.ciphers_to_send);
}
}, 0);
}
@@ -281,8 +341,8 @@ export default class Services {
}
}
- async getAmount(): Promise {
- const amount = await this.sdkClient.get_available_amount();
+ public getAmount(): BigInt {
+ const amount = this.sdkClient.get_available_amount();
return amount;
}
@@ -297,18 +357,30 @@ export default class Services {
async saveDevice(device: any): Promise {
const db = await Database.getInstance();
- db.addObject({
- storeName: 'wallet',
- object: { pre_id: '1', device },
- key: '1',
- });
- localStorage.setItem('wallet', device);
+ try {
+ await db.addObject({
+ storeName: 'wallet',
+ object: { pre_id: '1', device },
+ key: null,
+ });
+ } catch (e) {
+ console.error(e);
+ }
}
async getDevice(): Promise {
const db = await Database.getInstance();
- db.getObject('wallet', '1');
- return localStorage.getItem('wallet');
+ try {
+ 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() {
@@ -317,8 +389,8 @@ export default class Services {
return wallet;
}
- async createFaucetMessage() {
- const message = await this.sdkClient.create_faucet_msg();
+ public createFaucetMessage() {
+ const message = this.sdkClient.create_faucet_msg();
console.log('🚀 ~ Services ~ createFaucetMessage ~ message:', message);
return message;
}
@@ -447,38 +519,6 @@ export default class Services {
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() {
const processesCache = this.getProcessesCache();
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[] {
return [
{
diff --git a/src/utils/sp-address.utils.ts b/src/utils/sp-address.utils.ts
index e05471a..93b5b4d 100755
--- a/src/utils/sp-address.utils.ts
+++ b/src/utils/sp-address.utils.ts
@@ -148,7 +148,15 @@ export function initAddressInput() {
async function onOkButtonClick() {
const service = await Services.getInstance();
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) {
diff --git a/src/websockets.ts b/src/websockets.ts
index db5460c..175ffca 100755
--- a/src/websockets.ts
+++ b/src/websockets.ts
@@ -3,21 +3,13 @@ import Services from './services/service';
let ws: WebSocket;
let messageQueue: string[] = [];
-let services: Services;
export async function initWebsocket(url: string) {
ws = new WebSocket(url);
- services = await Services.getInstance();
if (ws !== null) {
ws.onopen = async (event) => {
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) {
const message = messageQueue.shift();
if (message) {
@@ -36,6 +28,7 @@ export async function initWebsocket(url: string) {
try {
const feeRate = 0.0001;
const parsedMessage = JSON.parse(msgData);
+ const services = await Services.getInstance();
switch (parsedMessage.flag) {
case 'NewTx':
await services.parseNewTx(parsedMessage.content);
@@ -66,7 +59,7 @@ export async function initWebsocket(url: string) {
}
// Method to send messages
-export async function sendMessage(flag: AnkFlag, message: string): Promise {
+export function sendMessage(flag: AnkFlag, message: string): void {
if (ws.readyState === WebSocket.OPEN) {
const networkMessage = {
flag: flag,