merge_code

This commit is contained in:
Pascal 2024-11-26 13:47:14 +01:00
commit b50d244d84
9 changed files with 214 additions and 137 deletions

View File

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

View File

@ -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],
}
await 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.');

View File

@ -104,7 +104,6 @@ async function init(): Promise<void> {
await services.restoreDevice(device);
}
await services.restoreProcesses();
await services.restoreMessages();
if (services.isPaired()) {
await navigate('process');
@ -113,7 +112,14 @@ async function init(): Promise<void> {
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 {
await services.connectMember([{sp_addresses: [pairingAddress]}]);
} catch (e) {
console.error('Failed to pair:', e);
}
}, 2000);
}
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) => {
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() {

View File

@ -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<void> {
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<any | null> {
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
}
}

View File

@ -103,6 +103,50 @@ export default class Services {
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> {
const localAddress = this.sdkClient.get_address();
const emptyTxid = '0'.repeat(64);
@ -142,9 +186,10 @@ export default class Services {
}
}
async sendFaucetMessage(message: string): Promise<void> {
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<BigInt> {
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<any> {
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<string | null> {
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 [
{

View File

@ -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 {
await service.connectMember([member]);
// await service.sendPairingTx(addressInput);
} catch (e) {
console.error('onOkButtonClick error:', e);
}
}
export async function generateQRCode(spAddress: string) {

View File

@ -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<void> {
export function sendMessage(flag: AnkFlag, message: string): void {
if (ws.readyState === WebSocket.OPEN) {
const networkMessage = {
flag: flag,