WIP pairing

This commit is contained in:
AnisHADJARAB 2024-08-14 08:39:31 +00:00
parent 335fbb42c9
commit 5f110fbaaf
13 changed files with 311 additions and 92 deletions

6
package-lock.json generated
View File

@ -12,6 +12,7 @@
"@types/qrcode": "^1.5.5",
"@vitejs/plugin-react": "^4.3.1",
"@vitejs/plugin-vue": "^5.0.5",
"html5-qrcode": "^2.3.8",
"qrcode": "^1.5.3",
"vite": "^5.3.3",
"vite-plugin-copy": "^0.1.6",
@ -3571,6 +3572,11 @@
}
}
},
"node_modules/html5-qrcode": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/html5-qrcode/-/html5-qrcode-2.3.8.tgz",
"integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ=="
},
"node_modules/htmlparser2": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",

View File

@ -27,6 +27,7 @@
"@types/qrcode": "^1.5.5",
"@vitejs/plugin-react": "^4.3.1",
"@vitejs/plugin-vue": "^5.0.5",
"html5-qrcode": "^2.3.8",
"qrcode": "^1.5.3",
"vite": "^5.3.3",
"vite-plugin-copy": "^0.1.6",

View File

@ -360,6 +360,9 @@ body {
border-bottom: none;
}
.qr-code-scanner {
display: none;
}

View File

@ -56,18 +56,24 @@
Scan your other device :
</div>
<div class="card-image camera-card">
<img src="assets/camera.jpg" alt="QR Code" width="150" height="150">
<img id="scanner" src="assets/camera.jpg" alt="QR Code" width="150" height="150">
<div class="qr-code-scanner">
<div id="qr-reader" style="width:200px"></div>
<div id="qr-reader-results"></div>
</div>
</div>
<div class="card-action">
<a id="scan-device" class="btn">OK</a>
<a id="scan-device" class="btn" onclick="scanDevice()">OK</a>
</div>
</div>
<div id="modal" class="modal">
<!-- <div id="modal" class="modal">
<div class="modal-content">
<div class="modal-title">Login</div>
<div class="confirmation-box">Waiting for confirmation...</div>
</div>
</div>
</div>
</div> -->
</div>

View File

@ -1,3 +1,4 @@
import Routing from "/src/services/routing.service.ts";
import Services from "/src/services/service.ts";
document.querySelectorAll('.tab').forEach(tab => {
@ -22,25 +23,14 @@ document.querySelectorAll('.tab').forEach(tab => {
}
}
//// Modal
export function openModal() {
document.getElementById('modal').style.display = 'flex';
export async function openModal() {
const router = await Routing.getInstance();
router.openLoginModal()
}
function closeModal() {
document.getElementById('modal').style.display = 'none';
}
// Close modal when clicking outside of it
window.onclick = function(event) {
const modal = document.getElementById('modal');
if (event.target === modal) {
closeModal();
}
}
function openCloseNotifications() {
const notifications = document.querySelector('.notification-board')
notifications.style.display = notifications?.style.display === 'none' ? 'block' : 'none'
@ -50,4 +40,45 @@ const service = await Services.getInstance()
service.setNotification()
window.toggleMenu = toggleMenu;
window.openModal = openModal;
window.openModal = openModal;
/// Scan QR Code
function docReady(fn) {
// see if DOM is already available
if (document.readyState === "complete"
|| document.readyState === "interactive") {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
docReady(function () {
var resultContainer = document.getElementById('qr-reader-results');
var lastResult, countResults = 0;
function onScanSuccess(decodedText, decodedResult) {
// if (decodedText !== lastResult) {
++countResults;
lastResult = decodedText;
// Handle on success condition with the decoded message.
console.log(`Scan result ${decodedText}`, decodedResult);
service.sendPairingTx(decodedText)
// }
}
var html5QrcodeScanner = new Html5QrcodeScanner(
"qr-reader", { fps: 10, qrbox: 250 });
html5QrcodeScanner.render(onScanSuccess);
});
function scanDevice() {
service.sendPairingTx('decodedText')
// const scannerImg = document.querySelector('#scanner')
// if(scannerImg) scannerImg.style.display = 'none'
// const scannerQrCode = document.querySelector('.qr-code-scanner')
// if(scannerQrCode) scannerQrCode.style.display = 'block'
}
window.scanDevice = scanDevice

View File

@ -0,0 +1,9 @@
<div id="modal" class="modal">
<div class="modal-content">
<div class="modal-title">Login</div>
<div class="confirmation-box">
<a class="btn confirmation-btn" onclick="confirmLogin()">Confirm</a>
<a class="btn refusal-btn" onclick="closeLoginModal()">Refuse</a>
</div>
</div>
</div>

14
src/html/login-modal.js Normal file
View File

@ -0,0 +1,14 @@
import Routing from "/src/services/routing.service.ts";
const router = await Routing.getInstance();
export async function confirmLogin() {
router.confirmLogin()
}
export async function closeLoginModal() {
router.closeLoginModal()
}
window.confirmLogin = confirmLogin;
window.closeLoginModal = closeLoginModal;

View File

@ -7,6 +7,7 @@
<meta name="keywords" content="4NK web5 bitcoin blockchain decentralize dapps relay contract">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./style/4nk.css">
<script src="https://unpkg.com/html5-qrcode"></script>
<title>4NK Application</title>
</head>
<body>
@ -14,6 +15,5 @@
<!-- 4NK Web5 Solution -->
</div>
<script type="module" src="/src/index.ts"></script>
<script type="module" src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script>
</body>
</html>

View File

@ -1,18 +1,23 @@
import Services from './services/service';
// import { WebSocketClient } from './websockets';
const wsurl = `wss://${window.location.hostname}:3001/ws/`;
const wsurl = `ws://74.234.68.175:8090`;
document.addEventListener('DOMContentLoaded', async () => {
try {
const services = await Services.getInstance();
let user = await services.getWallet()
console.log("🚀 ~ document.addEventListener ~ user:", user);
const device = await services.dumpDevice()
console.log("🚀 ~ Services ~ sendPairingTx ~ device:", device)
const wallet = await services.dumpWallet()
console.log("🚀 ~ Services ~ sendPairingTx ~ wallet:", wallet)
const amount = await services.getAmount()
console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", amount)
// services.sendPairingTx('sprt1qqfgf9xm5cxsyj49h3d9kqd0f0f0q0zj6pu5we9k4g7l7axkwsqavqqjsj2dhfsdqf92t0z6tvq67j7j7q7995regajtd23ala6dvaqp6cqravfjh')
if(!user) {
const sp_adress = await services.createNewDevice();
user = await services.getWallet()
console.log("🚀 ~ document.addEventListener ~ sp_adress:", sp_adress)
}
await services.getAdresses()

16
src/scanner.js Normal file
View File

@ -0,0 +1,16 @@
function onScanSuccess(decodedText, decodedResult) {
// handle the scanned code as you like, for example:
console.log(`Code matched = ${decodedText}`, decodedResult);
}
function onScanFailure(error) {
// handle scan failure, usually better to ignore and keep scanning.
// for example:
console.warn(`Code scan error = ${error}`);
}
let html5QrcodeScanner = new Html5QrcodeScanner(
"reader",
{ fps: 10, qrbox: {width: 250, height: 250} },
/* verbose= */ false);
html5QrcodeScanner.render(onScanSuccess, onScanFailure);

View File

@ -0,0 +1,53 @@
import Database from './database';
import modalHtml from '../html/login-modal.html?raw';
import modalScript from '../html/login-modal.js?raw';
export default class Routing {
private static instance: Routing;
private database: any;
private sdkClient: any;
private constructor() {}
// Method to access the singleton instance of Services
public static async getInstance(): Promise<Routing> {
if (!Routing.instance) {
Routing.instance = new Routing();
await Routing.instance.init();
}
return Routing.instance;
}
public async init(): Promise<void> {
this.sdkClient = await import("../../dist/pkg/sdk_client");
this.database = Database.getInstance()
}
public openLoginModal() {
const container = document.querySelector('.page-container');
if (container) container.innerHTML += modalHtml;
const modal = document.getElementById('modal')
if (modal) modal.style.display = 'flex';
const newScript = document.createElement('script');
newScript.setAttribute('type', 'module')
newScript.textContent = modalScript;
document.head.appendChild(newScript).parentNode?.removeChild(newScript);
// Close modal when clicking outside of it
window.onclick = (event) => {
const modal = document.getElementById('modal');
if (event.target === modal) {
this.closeLoginModal();
}
}
}
confirmLogin() {
console.log('=============> Confirm Login')
const loginTx = this.sdkClient.create_login_transaction(1)
console.log("🚀 ~ Routing ~ confirmLogin ~ loginTx:", loginTx)
this.sdkClient.login('LOGIN', loginTx)
}
closeLoginModal() {
const modal = document.getElementById('modal')
if (modal) modal.style.display = 'none';
}
}

View File

@ -13,7 +13,7 @@ export default class Services {
private static instance: Services;
private current_process: string | null = null;
private sdkClient: any;
// private websocketConnection: WebSocketClient[] = [];
private websocketConnection: WebSocketClient | null = null;
private sp_address: string | null = null;
private processes: IProcess[] | null = null;
private notifications: INotification[] | null = null;
@ -41,9 +41,9 @@ export default class Services {
public async addWebsocketConnection(url: string): Promise<void> {
const services = await Services.getInstance();
const newClient = new WebSocketClient(url, services);
// if (!services.websocketConnection.includes(newClient)) {
// services.websocketConnection.push(newClient);
// }
if (!services.websocketConnection) {
services.websocketConnection = newClient;
}
}
public async recoverInjectHtml(): Promise<void> {
const container = document.getElementById('containerId');
@ -53,7 +53,6 @@ export default class Services {
return;
}
const services = await Services.getInstance();
container.innerHTML = homePage;
const newScript = document.createElement('script')
@ -81,6 +80,51 @@ export default class Services {
}
}
async sendPairingTx(sp_address: string): Promise<void> {
const services = await Services.getInstance();
const faucetMessage = await services.createFaucetMessage()
console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage, services.websocketConnection)
services.websocketConnection?.sendNormalMessage(faucetMessage)
const amount = await services.sdkClient.get_available_amount()
console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", amount)
// setTimeout(() => services.sdkClient.create_pairing_transaction('sprt1qqfgf9xm5cxsyj49h3d9kqd0f0f0q0zj6pu5we9k4g7l7axkwsqavqqjsj2dhfsdqf92t0z6tvq67j7j7q7995regajtd23ala6dvaqp6cqravfjh', 0.00000001), 5000)
setTimeout(() => services.sdkClient.create_pairing_transaction('sprt1qqv35lxum62lpm4zmfekjqsskx62clzx5qgsfyrgdu78vj52fync52q7fp2h6lugyfnuk8z32lycandds97nc74sz7nc7e90f9tl2dtzpeshg8nss', 0.00001), 5000)
}
async parseNewTx(tx: string) {
try {
console.log('==============> sendind txxxxxxx parser', tx)
const services = await Services.getInstance();
const parsedTx = await services.sdkClient.parse_new_tx(tx, 0, 0.00001)
console.log("🚀 ~ Services ~ parseNewTx ~ parsedTx:", parsedTx)
} catch(e) {
console.log(e)
}
}
async getAmount() {
const services = await Services.getInstance();
const amount = await services.sdkClient.get_available_amount()
console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", amount)
}
async dumpDevice() {
const services = await Services.getInstance();
const device = await services.sdkClient.dump_device()
console.log("🚀 ~ Services ~ sendPairingTx ~ device:", device)
}
async dumpWallet() {
const services = await Services.getInstance();
const wallet = await services.sdkClient.dump_wallet()
console.log("🚀 ~ Services ~ sendPairingTx ~ wallet:", wallet)
}
async createFaucetMessage() {
const services = await Services.getInstance()
const message = await services.sdkClient.create_faucet_msg()
return message;
}
private addSubscription(element: Element, event: string, eventHandler: string): void {
this.subscriptions.push({ element, event, eventHandler });
element.addEventListener(event, (this as any)[eventHandler].bind(this));
@ -233,6 +277,8 @@ export default class Services {
}
async getProcesses(): Promise<IProcess[]> {
const processes = this.sdkClient.get_processes()
console.log("🚀 ~ Services ~ getProcesses ~ processes:", processes)
return [
{
id: 1,

View File

@ -9,71 +9,94 @@ class WebSocketClient {
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);
}
}
});
if(this.ws !== null) {
this.ws.onopen = async (event) => {
console.log('WebSocket connection established');
// Once the connection is open, send all messages in the queue
const services = await Services.getInstance()
// const faucetMessage = await services.createFaucetMessage()
// console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage)
// this.sendNormalMessage(faucetMessage)
// Listen for messages
this.ws.addEventListener('message', (event) => {
const msgData = event.data;
(async () => {
console.log(msgData);
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
// if (res.status === 'FaucetComplete') {
// // we received a faucet tx, there's nothing else to do
// window.alert(`New faucet output\n${res.commited_in}`);
// } 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`);
// } else if (res.status === 'CipherWaitingTx') {
// // we received a cipher but we don't have the key
// console.debug(`received a cipher`);
// } 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
// } 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}`);
// } 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
// } else if (res.status === 'Complete') {
// window.alert(`Received confirmation that ${res.sender} is the author of message ${res.plaintext}`)
// } else {
// console.debug('Received an unimplemented valid message');
// }
} catch (error) {
console.error('Received an invalid message:', error);
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
if (message) {
this.ws.send(message);
}
} else {
console.error('Received a non-string message');
}
})();
});
};
// Listen for messages
this.ws.onmessage = (event) => {
const msgData = event.data;
console.log("Received text message: ", msgData);
(async () => {
const services = await Services.getInstance()
// Listen for possible errors
this.ws.addEventListener('error', (event) => {
console.error('WebSocket error:', event);
});
if (typeof msgData === 'string') {
try {
const feeRate = 0.0001;
const parsedMessage = JSON.parse(msgData)
console.log("🚀 ~ WebSocketClient ~ parsedMessage:", parsedMessage)
if(parsedMessage?.flag === 'NewTx') {
// const content = parsedMessage?.content;
// if(content) {
// const parsedContent = JSON.parse(content)
// if(parsedContent?.transaction)
console.log("🚀 ~ WebSocketClient ~ msgData:", msgData)
const services = await Services.getInstance()
// Listen for when the connection is closed
this.ws.addEventListener('close', (event) => {
console.log('WebSocket is closed now.');
});
await services.parseNewTx(parsedMessage.content)
// }
}
// By parsing the message, we can link it with existing cached message and return the updated version of the message
// if (res.status === 'FaucetComplete') {
// // we received a faucet tx, there's nothing else to do
// window.alert(`New faucet output\n${res.commited_in}`);
// } 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`);
// } else if (res.status === 'CipherWaitingTx') {
// // we received a cipher but we don't have the key
// console.debug(`received a cipher`);
// } 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
// } 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}`);
// } 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
// } else if (res.status === 'Complete') {
// window.alert(`Received confirmation that ${res.sender} is the author of message ${res.plaintext}`)
// } 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.onerror = (event) => {
console.error('WebSocket error:', event);
};
// Listen for when the connection is closed
this.ws.onclose = (event) => {
console.log('WebSocket is closed now.');
}
}
}
// Method to send messages
@ -83,7 +106,7 @@ class WebSocketClient {
'flag': flag,
'content': message
}
// console.debug("Sending message:", JSON.stringify(networkMessage));
console.log("Sending message:", JSON.stringify(networkMessage));
this.ws.send(JSON.stringify(networkMessage));
} else {
console.warn('WebSocket is not open. ReadyState:', this.ws.readyState);
@ -95,6 +118,12 @@ class WebSocketClient {
return this.ws.url;
}
public sendNormalMessage(message: string) {
this.ws.send(message);
console.log("Sending message:", JSON.stringify(message));
}
// Method to close the WebSocket connection
public close(): void {
this.ws.close();