From 44e9a435c49a057e6d6ed9e90ebb21e38ae764c3 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Wed, 25 Jun 2025 08:38:10 +0200 Subject: [PATCH] Add percenteage, refactor sync conditions --- src/components/CoreSyncStatus.tsx | 42 +++-- src/components/Group/Forum/ReadOnlySlate.tsx | 15 +- src/components/Minting/Minting.tsx | 12 +- src/components/Minting/MintingStats.tsx | 8 +- src/encryption/kdf.ts | 170 ++++++++++--------- src/i18n/locales/de/core.json | 4 +- src/i18n/locales/en/core.json | 6 +- src/i18n/locales/es/core.json | 4 +- src/i18n/locales/fr/core.json | 4 +- src/i18n/locales/it/core.json | 4 +- src/i18n/locales/ja/core.json | 4 +- src/i18n/locales/ru/core.json | 4 +- src/i18n/locales/zh/core.json | 4 +- src/qdn/publish/publish.ts | 2 +- 14 files changed, 149 insertions(+), 134 deletions(-) diff --git a/src/components/CoreSyncStatus.tsx b/src/components/CoreSyncStatus.tsx index 8752025..1bf2221 100644 --- a/src/components/CoreSyncStatus.tsx +++ b/src/components/CoreSyncStatus.tsx @@ -25,9 +25,7 @@ export const CoreSyncStatus = () => { useEffect(() => { const getNodeInfos = async () => { try { - setIsUsingGateway( - !!getBaseApiReact()?.includes('ext-node.qortal.link') - ); + setIsUsingGateway(getBaseApiReact()?.includes('ext-node.qortal.link')); const url = `${getBaseApiReact()}/admin/status`; const response = await fetch(url, { method: 'GET', @@ -82,27 +80,27 @@ export const CoreSyncStatus = () => { : ''; let imagePath = syncingImg; - let message = t('core:minting.status.synchronizing', { - postProcess: 'capitalizeFirstChar', - }); + let message: string = ''; - if (isMintingPossible && !isUsingGateway) { - imagePath = syncedMintingImg; - message = `${t(`core:minting.status.${isSynchronizing ? 'synchronizing' : 'synchronized'}`, { postProcess: 'capitalizeFirstChar' })} ${t('core:minting.status.minting')}`; - } else if (isSynchronizing === true && syncPercent === 99) { + if (isUsingGateway) { imagePath = syncingImg; - } else if (isSynchronizing && !isMintingPossible && syncPercent === 100) { - imagePath = syncingImg; - message = `${t('core:minting.status.synchronizing', { postProcess: 'capitalizeFirstChar' })} ${!isUsingGateway ? t('core:minting.status.not_minting') : ''}`; - } else if (!isSynchronizing && !isMintingPossible && syncPercent === 100) { - imagePath = syncedImg; - message = `${t('core:minting.status.synchronized', { postProcess: 'capitalizeFirstChar' })} ${!isUsingGateway ? t('core:minting.status.not_minting') : ''}`; - } else if (isSynchronizing && isMintingPossible && syncPercent === 100) { - imagePath = syncingImg; - message = `${t('core:minting.status.synchronizing', { postProcess: 'capitalizeFirstChar' })} ${!isUsingGateway ? t('core:minting.status.minting') : ''}`; - } else if (!isSynchronizing && isMintingPossible && syncPercent === 100) { - imagePath = syncedMintingImg; - message = `${t('core:minting.status.synchronized', { postProcess: 'capitalizeFirstChar' })} ${!isUsingGateway ? t('core:minting.status.minting') : ''}`; + message = `${t('core:minting.status.no_status')}`; + } else if (isMintingPossible) { + if (isSynchronizing) { + imagePath = syncingImg; + message = `${t(`core:minting.status.synchronizing`, { percent: syncPercent, postProcess: 'capitalizeFirstChar' })} ${t('core:minting.status.minting')}`; + } else { + imagePath = syncedMintingImg; + message = `${t(`core:minting.status.synchronized`, { percent: syncPercent, postProcess: 'capitalizeFirstChar' })} ${t('core:minting.status.minting')}`; + } + } else if (!isMintingPossible) { + if (syncPercent == 100) { + imagePath = syncedImg; + message = `${t(`core:minting.status.synchronized`, { percent: syncPercent, postProcess: 'capitalizeFirstChar' })} ${t('core:minting.status.not_minting')}`; + } else { + imagePath = syncingImg; + message = `${t(`core:minting.status.synchronizing`, { percent: syncPercent, postProcess: 'capitalizeFirstChar' })} ${t('core:minting.status.not_minting')}`; + } } return ( diff --git a/src/components/Group/Forum/ReadOnlySlate.tsx b/src/components/Group/Forum/ReadOnlySlate.tsx index 15e1436..7fc90b1 100644 --- a/src/components/Group/Forum/ReadOnlySlate.tsx +++ b/src/components/Group/Forum/ReadOnlySlate.tsx @@ -96,6 +96,7 @@ interface ReadOnlySlateProps { content: any; mode?: string; } + const ReadOnlySlate: FC = ({ content, mode }) => { const [load, setLoad] = useState(false); const editor = useMemo(() => withReact(createEditor()), []); @@ -103,11 +104,15 @@ const ReadOnlySlate: FC = ({ content, mode }) => { const performUpdate = useCallback(async () => { setLoad(true); - await new Promise((res) => { - setTimeout(() => { - res(); - }, 250); - }); + try { + await new Promise((res) => { + setTimeout(() => { + res(); + }, 250); + }); + } catch (error) { + console.log(error); + } setLoad(false); }, []); useEffect(() => { diff --git a/src/components/Minting/Minting.tsx b/src/components/Minting/Minting.tsx index 2d94344..86d0207 100644 --- a/src/components/Minting/Minting.tsx +++ b/src/components/Minting/Minting.tsx @@ -698,10 +698,14 @@ export const Minting = ({ setIsOpenMinting, myAddress, show }) => { label={t('core:minting.average_blocktime', { postProcess: 'capitalizeEachFirstChar', })} - value={averageBlockTime( - adminInfo, - nodeHeightBlock - ).toFixed(2)} + value={t('core:time.second', { + count: parseFloat( + averageBlockTime(adminInfo, nodeHeightBlock).toFixed( + 2 + ) + ), + postProcess: 'capitalizeEachFirstChar', + })} /> { nodeStatus.isMintingPossible === true && nodeStatus.isSynchronizing === true ) { - // this.cssMinting = 'blue'; return i18n.t('core:minting.status.minting', { postProcess: 'capitalizeFirstChar', }); @@ -376,7 +375,6 @@ export const mintingStatus = (nodeStatus): string => { nodeStatus.isMintingPossible === true && nodeStatus.isSynchronizing === false ) { - // this.cssMinting = 'blue'; return i18n.t('core:minting.status.minting', { postProcess: 'capitalizeFirstChar', }); @@ -384,7 +382,6 @@ export const mintingStatus = (nodeStatus): string => { nodeStatus.isMintingPossible === false && nodeStatus.isSynchronizing === true ) { - // this.cssMinting = 'red'; return i18n.t('core:minting.status.synchronizing', { postProcess: 'capitalizeFirstChar', }) + @@ -396,7 +393,6 @@ export const mintingStatus = (nodeStatus): string => { nodeStatus.isMintingPossible === false && nodeStatus.isSynchronizing === false ) { - // this.cssMinting = 'red'; return i18n.t('core:minting.status.not_minting', { postProcess: 'capitalizeFirstChar', }); diff --git a/src/encryption/kdf.ts b/src/encryption/kdf.ts index 6844d67..5010c0e 100644 --- a/src/encryption/kdf.ts +++ b/src/encryption/kdf.ts @@ -1,100 +1,110 @@ // @ts-nocheck -import {bytes_to_base64 as bytesToBase64, Sha512} from 'asmcrypto.js' -import utils from '../utils/utils' -import { crypto as crypto2 } from '../constants/decryptWallet' +import { bytes_to_base64 as bytesToBase64, Sha512 } from 'asmcrypto.js'; +import utils from '../utils/utils'; +import { crypto as crypto2 } from '../constants/decryptWallet'; import BcryptWorker from './bcryptworker.worker.js?worker'; -const stringtoUTF8Array = (message)=> { - if (typeof message === 'string') { - var s = unescape(encodeURIComponent(message)) // UTF-8 - message = new Uint8Array(s.length) - for (var i = 0; i < s.length; i++) { - message[i] = s.charCodeAt(i) & 0xff - } +const stringtoUTF8Array = (message) => { + if (typeof message === 'string') { + var s = unescape(encodeURIComponent(message)); // UTF-8 + message = new Uint8Array(s.length); + for (var i = 0; i < s.length; i++) { + message[i] = s.charCodeAt(i) & 0xff; } - return message -} - - + } + return message; +}; const bcryptInWorker = (hashBase64, salt) => { return new Promise((resolve, reject) => { - const worker = new BcryptWorker() - worker.onmessage = (e) => { - const { result, error } = e.data; - if (error) { - reject(error); - } else { - resolve(result); - } - worker.terminate(); - }; - worker.onerror = (err) => { - reject(err.message); - worker.terminate(); - }; - worker.postMessage({ hashBase64, salt }); + const worker = new BcryptWorker(); + worker.onmessage = (e) => { + const { result, error } = e.data; + if (error) { + reject(error); + } else { + resolve(result); + } + worker.terminate(); + }; + worker.onerror = (err) => { + reject(err.message); + worker.terminate(); + }; + worker.postMessage({ hashBase64, salt }); }); }; +const stringToUTF8Array = (message) => { + if (typeof message !== 'string') return message; // Assuming you still want to pass through non-string inputs unchanged + const encoder = new TextEncoder(); // TextEncoder defaults to UTF-8 + return encoder.encode(message); +}; -const stringToUTF8Array=(message)=> { - if (typeof message !== 'string') return message; // Assuming you still want to pass through non-string inputs unchanged - const encoder = new TextEncoder(); // TextEncoder defaults to UTF-8 - return encoder.encode(message); -} -const computekdf = async (req)=> { - const { salt, key, nonce, staticSalt, staticBcryptSalt } = req - const combinedBytes = utils.appendBuffer(new Uint8Array([]), stringToUTF8Array(`${staticSalt}${key}${nonce}`)) +const computekdf = async (req) => { + const { salt, key, nonce, staticSalt, staticBcryptSalt } = req; + const combinedBytes = utils.appendBuffer( + new Uint8Array([]), + stringToUTF8Array(`${staticSalt}${key}${nonce}`) + ); - const sha512Hash = new Sha512().process(combinedBytes).finish().result - const sha512HashBase64 = bytesToBase64(sha512Hash) + const sha512Hash = new Sha512().process(combinedBytes).finish().result; + const sha512HashBase64 = bytesToBase64(sha512Hash); - const result = await bcryptInWorker(sha512HashBase64.substring(0, 72), staticBcryptSalt); - return { key, nonce, result } -} + const result = await bcryptInWorker( + sha512HashBase64.substring(0, 72), + staticBcryptSalt + ); + return { key, nonce, result }; +}; export const doInitWorkers = (numberOfWorkers) => { - const workers = [] + const workers = []; - try { - for (let i = 0; i < numberOfWorkers; i++) { - workers.push({}) - } - - } catch (e) { - } - - return workers -} + try { + for (let i = 0; i < numberOfWorkers; i++) { + workers.push({}); + } + } catch (e) {} + + return workers; +}; export const kdf = async (seed, salt, threads) => { - const workers = threads - const salt2 = new Uint8Array(salt) + const workers = threads; + const salt2 = new Uint8Array(salt); - salt = new Uint8Array(salt) - const seedParts = await Promise.all(workers.map((worker, index) => { - const nonce = index - return computekdf({ - key: seed, - salt, - nonce, - staticSalt: crypto2.staticSalt, - staticBcryptSalt: crypto2.staticBcryptSalt - }).then(data => { - let jsonData - try { - jsonData = JSON.parse(data) - data = jsonData - } catch (e) { - // ... - } - // if (seed !== data.key) throw new Error(kst3 + seed + ' !== ' + data.key) - // if (nonce !== data.nonce) throw new Error(kst4) - return data.result - }) - })) - const result = new Sha512().process(stringtoUTF8Array(crypto2.staticSalt + seedParts.reduce((a, c) => a + c))).finish().result - return result -} + salt = new Uint8Array(salt); + const seedParts = await Promise.all( + workers.map((worker, index) => { + const nonce = index; + return computekdf({ + key: seed, + salt, + nonce, + staticSalt: crypto2.staticSalt, + staticBcryptSalt: crypto2.staticBcryptSalt, + }).then((data) => { + let jsonData; + try { + jsonData = JSON.parse(data); + data = jsonData; + } catch (e) { + // ... + } + // if (seed !== data.key) throw new Error(kst3 + seed + ' !== ' + data.key) + // if (nonce !== data.nonce) throw new Error(kst4) + return data.result; + }); + }) + ); + + const result = new Sha512() + .process( + stringtoUTF8Array(crypto2.staticSalt + seedParts.reduce((a, c) => a + c)) + ) + .finish().result; + + return result; +}; diff --git a/src/i18n/locales/de/core.json b/src/i18n/locales/de/core.json index 51eb668..94020dc 100644 --- a/src/i18n/locales/de/core.json +++ b/src/i18n/locales/de/core.json @@ -334,8 +334,8 @@ "minting": "(Prägung)", "not_minting": "(nicht punktieren)", "no_status": "kein Status", - "synchronized": "synchronisiert", - "synchronizing": "Synchronisierung..." + "synchronized": "synchronisiert ({{ percent }}%)", + "synchronizing": "Synchronisierung ({{ percent }}%)..." }, "status_title": "Münzstatus", "tier_share_per_block": "Stufenanteil pro Block", diff --git a/src/i18n/locales/en/core.json b/src/i18n/locales/en/core.json index 1ef7b47..b77d493 100644 --- a/src/i18n/locales/en/core.json +++ b/src/i18n/locales/en/core.json @@ -336,8 +336,8 @@ "minting": "(minting)", "not_minting": "(not minting)", "no_status": "no status", - "synchronized": "synchronized", - "synchronizing": "synchronizing..." + "synchronized": "synchronized ({{ percent }}%)", + "synchronizing": "synchronizing ({{ percent }}%)..." }, "status_title": "minting status", "tier_share_per_block": "tier share per block", @@ -399,6 +399,8 @@ "hour_other": "{{count}} hours", "minute_one": "{{count}} minute", "minute_other": "{{count}} minutes", + "second_one": "{{count}} second", + "second_other": "{{count}} seconds", "time": "time" }, "title": "title", diff --git a/src/i18n/locales/es/core.json b/src/i18n/locales/es/core.json index 2fe2500..d157cf5 100644 --- a/src/i18n/locales/es/core.json +++ b/src/i18n/locales/es/core.json @@ -335,8 +335,8 @@ "minting": "(acuñado)", "not_minting": "(no acuñar)", "no_status": "sin estado", - "synchronized": "sincronizado", - "synchronizing": "sincronización..." + "synchronized": "sincronizado ({{ percent }}%)", + "synchronizing": "sincronización ({{ percent }}%)..." }, "status_title": "estado de acuñación", "tier_share_per_block": "porción del nivel por bloque", diff --git a/src/i18n/locales/fr/core.json b/src/i18n/locales/fr/core.json index de469e4..8c28c23 100644 --- a/src/i18n/locales/fr/core.json +++ b/src/i18n/locales/fr/core.json @@ -335,8 +335,8 @@ "minting": "(Frappe)", "not_minting": "(pas de la frappe)", "no_status": "pas de statut", - "synchronized": "synchronisé", - "synchronizing": "synchronisation..." + "synchronized": "synchronisé ({{ percent }}%)", + "synchronizing": "synchronisation ({{ percent }}%)..." }, "status_title": "statut de frappe", "tier_share_per_block": "part du niveau par bloc", diff --git a/src/i18n/locales/it/core.json b/src/i18n/locales/it/core.json index 8010bdc..678bdaa 100644 --- a/src/i18n/locales/it/core.json +++ b/src/i18n/locales/it/core.json @@ -334,8 +334,8 @@ "minting": "(minting)", "not_minting": "(non minting)", "no_status": "nessun stato", - "synchronized": "sincronizzato", - "synchronizing": "sincronizzazione..." + "synchronized": "sincronizzato ({{ percent }}%)", + "synchronizing": "sincronizzazione ({{ percent }}%)..." }, "status_title": "stato minting", "tier_share_per_block": "quota della fascia per blocco", diff --git a/src/i18n/locales/ja/core.json b/src/i18n/locales/ja/core.json index e58e29a..06ca85f 100644 --- a/src/i18n/locales/ja/core.json +++ b/src/i18n/locales/ja/core.json @@ -335,8 +335,8 @@ "minting": "(鋳造)", "not_minting": "(造りではありません)", "no_status": "ステータスなし", - "synchronized": "同期", - "synchronizing": "同期..." + "synchronized": "同期 ({{ percent }}%)", + "synchronizing": "同期 ({{ percent }}%)..." }, "status_title": "ミントステータス", "tier_share_per_block": "ブロックごとのティアシェア", diff --git a/src/i18n/locales/ru/core.json b/src/i18n/locales/ru/core.json index 07d4331..0272068 100644 --- a/src/i18n/locales/ru/core.json +++ b/src/i18n/locales/ru/core.json @@ -335,8 +335,8 @@ "minting": "(добыча)", "not_minting": "(не шахта)", "no_status": "нет статуса", - "synchronized": "синхронизированный", - "synchronizing": "синхронизация..." + "synchronized": "синхронизированный ({{ percent }}%)", + "synchronizing": "синхронизация ({{ percent }}%)..." }, "status_title": "Статус майтинга", "tier_share_per_block": "доля уровня за блок", diff --git a/src/i18n/locales/zh/core.json b/src/i18n/locales/zh/core.json index 52e0c2e..7f80d55 100644 --- a/src/i18n/locales/zh/core.json +++ b/src/i18n/locales/zh/core.json @@ -335,8 +335,8 @@ "minting": "(铸造)", "not_minting": "(不是铸造)", "no_status": "没有状态", - "synchronized": "同步", - "synchronizing": "同步..." + "synchronized": "同步 ({{ percent }}%)", + "synchronizing": "同步 ({{ percent }}%)..." }, "status_title": "铸造状态", "tier_share_per_block": "每个区块的等级份额", diff --git a/src/qdn/publish/publish.ts b/src/qdn/publish/publish.ts index 82f3dc1..31b6d65 100644 --- a/src/qdn/publish/publish.ts +++ b/src/qdn/publish/publish.ts @@ -71,7 +71,7 @@ async function uploadChunkWithRetry(endpoint, formData, index, maxRetries = 3) { if (attempt >= maxRetries) { throw new Error(`Chunk ${index} failed after ${maxRetries} attempts`); } - // Wait 10 seconds before next retry + // Wait 25 seconds before next retry await new Promise((res) => setTimeout(res, 25_000)); } }