From 426b5170d356c7f82d2e0c1e7d2543ed6229985b Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Wed, 16 Oct 2024 21:27:44 +0700 Subject: [PATCH 01/18] feat: worker file --- .../assets/js/catalyst_compression.js | 88 ++++++------------- .../assets/js/catalyst_compression_worker.js | 85 ++++++++++++++++++ 2 files changed, 112 insertions(+), 61 deletions(-) create mode 100644 catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index 065791c5e01..68757ef39ad 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -1,70 +1,36 @@ -const brotli = await import("https://unpkg.com/brotli-wasm@3.0.0/index.web.js?module").then(m => m.default); -const zstd = await import("https://unpkg.com/@oneidentity/zstd-js@1.0.3/wasm/index.js?module"); - -// Initializes the zstd module, must be called before it can be used. -await zstd.ZstdInit(); - -/// Compresses hex bytes using brotli compression algorithm and returns compressed hex bytes. -function _brotliCompress(bytesHex) { - const bytes = _hexStringToUint8Array(bytesHex); - const compressedBytes = brotli.compress(bytes); - return _uint8ArrayToHexString(compressedBytes); -} - -/// Decompresses hex bytes using brotli compression algorithm and returns decompressed hex bytes. -function _brotliDecompress(bytesHex) { - const bytes = _hexStringToUint8Array(bytesHex); - const decompressedBytes = brotli.decompress(bytes); - return _uint8ArrayToHexString(decompressedBytes); -} - -/// Compresses hex bytes using zstd compression algorithm and returns compressed hex bytes. -function _zstdCompress(bytesHex) { - const bytes = _hexStringToUint8Array(bytesHex); - const compressedBytes = zstd.ZstdSimple.compress(bytes); - return _uint8ArrayToHexString(compressedBytes); -} - -/// Decompresses hex bytes using zstd compression algorithm and returns decompressed hex bytes. -function _zstdDecompress(bytesHex) { - const bytes = _hexStringToUint8Array(bytesHex); - const decompressedBytes = zstd.ZstdSimple.decompress(bytes); - return _uint8ArrayToHexString(decompressedBytes); -} - -// Converts a hex string into a byte array. -function _hexStringToUint8Array(hexString) { - // Ensure the hex string length is even - if (hexString.length % 2 !== 0) { - throw new Error('Invalid hex string'); - } - - // Create a Uint8Array - const byteArray = new Uint8Array(hexString.length / 2); - - // Parse the hex string into byte values - for (let i = 0; i < hexString.length; i += 2) { - byteArray[i / 2] = parseInt(hexString.substr(i, 2), 16); +function runCompressionInWorker(fnName) { + return (data) => { + return new Promise((resolve, reject) => { + const compressionWorker = new Worker('/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js'); + + compressionWorker.onmessage = (event) => { + const { result, initialized, error } = event.data; + if (initialized) { + compressionWorker.postMessage({ action: fnName, bytesHex: data }); + } else if (result) { + resolve(result); + compressionWorker.terminate() + } else { + reject(error || null); + compressionWorker.terminate() + } + }; + + compressionWorker.onerror = (error) => { + reject(error); + compressionWorker.terminate() + }; + }); } - - return byteArray; -} - -// Converts a byte array into a hex string. -function _uint8ArrayToHexString(uint8Array) { - return Array.from(uint8Array) - .map(byte => byte.toString(16).padStart(2, '0')) - .join(''); } - // A namespace containing the JS functions that // can be executed from dart side const catalyst_compression = { - brotliCompress: _brotliCompress, - brotliDecompress: _brotliDecompress, - zstdCompress: _zstdCompress, - zstdDecompress: _zstdDecompress, + brotliCompress: runCompressionInWorker("brotliCompress"), + brotliDecompress: runCompressionInWorker("brotliDecompress"), + zstdCompress: runCompressionInWorker("zstdCompress"), + zstdDecompress: runCompressionInWorker("zstdDecompress"), } // Expose catalyst compression as globally accessible diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js new file mode 100644 index 00000000000..5443bc0f78a --- /dev/null +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js @@ -0,0 +1,85 @@ +Promise.all([ + import('https://unpkg.com/brotli-wasm@3.0.0/index.web.js?module').then(m => m.default), + import('https://unpkg.com/@oneidentity/zstd-js@1.0.3/wasm/index.js?module') +]).then(async ([brotli, zstd]) => { + // Initializes the zstd module, must be called before it can be used. + await zstd.ZstdInit(); + + /// Compresses hex bytes using brotli compression algorithm and returns compressed hex bytes. + function _brotliCompress(bytesHex) { + const bytes = _hexStringToUint8Array(bytesHex); + const compressedBytes = brotli.compress(bytes); + return _uint8ArrayToHexString(compressedBytes); + } + + /// Decompresses hex bytes using brotli compression algorithm and returns decompressed hex bytes. + function _brotliDecompress(bytesHex) { + const bytes = _hexStringToUint8Array(bytesHex); + const decompressedBytes = brotli.decompress(bytes); + return _uint8ArrayToHexString(decompressedBytes); + } + + /// Compresses hex bytes using zstd compression algorithm and returns compressed hex bytes. + function _zstdCompress(bytesHex) { + const bytes = _hexStringToUint8Array(bytesHex); + const compressedBytes = zstd.ZstdSimple.compress(bytes); + return _uint8ArrayToHexString(compressedBytes); + } + + /// Decompresses hex bytes using zstd compression algorithm and returns decompressed hex bytes. + function _zstdDecompress(bytesHex) { + const bytes = _hexStringToUint8Array(bytesHex); + const decompressedBytes = zstd.ZstdSimple.decompress(bytes); + return _uint8ArrayToHexString(decompressedBytes); + } + + // Converts a hex string into a byte array. + function _hexStringToUint8Array(hexString) { + // Ensure the hex string length is even + if (hexString.length % 2 !== 0) { + throw new Error('Invalid hex string'); + } + + // Create a Uint8Array + const byteArray = new Uint8Array(hexString.length / 2); + + // Parse the hex string into byte values + for (let i = 0; i < hexString.length; i += 2) { + byteArray[i / 2] = parseInt(hexString.substr(i, 2), 16); + } + + return byteArray; + } + + // Converts a byte array into a hex string. + function _uint8ArrayToHexString(uint8Array) { + return Array.from(uint8Array) + .map(byte => byte.toString(16).padStart(2, '0')) + .join(''); + } + + const catalyst_compression = { + brotliCompress: _brotliCompress, + brotliDecompress: _brotliDecompress, + zstdCompress: _zstdCompress, + zstdDecompress: _zstdDecompress, + }; + + self.onmessage = (event) => { + const { action, bytesHex } = event.data; + if (catalyst_compression[action]) { + try { + const result = catalyst_compression[action](bytesHex); + self.postMessage({ result }); + } catch (error) { + self.postMessage({ error: error.message }); + } + } else { + self.postMessage({ error: 'Unknown action' }); + } + }; + + self.postMessage({ initialized: true }); +}).catch(error => { + self.postMessage({ error: `Failed to load modules: ${error.message}` }); +}) \ No newline at end of file From b683e3bd72afa352d4c12a1375cfa7291895d83b Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Wed, 16 Oct 2024 21:50:23 +0700 Subject: [PATCH 02/18] chore: change affacted functions to future --- .../registration_transaction_builder.dart | 2 +- .../example/lib/sign_and_submit_rbac_tx.dart | 10 +++-- .../lib/src/rbac/x509_metadata_envelope.dart | 34 +++++++++-------- .../catalyst_compression/example/main.dart | 10 ++--- .../lib/src/catalyst_compressor.dart | 4 +- .../interop/catalyst_compression_interop.dart | 37 +++++++++++-------- 6 files changed, 54 insertions(+), 43 deletions(-) diff --git a/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_transaction_builder.dart b/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_transaction_builder.dart index 63850d0bcd5..e551c64204c 100644 --- a/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_transaction_builder.dart +++ b/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_transaction_builder.dart @@ -60,7 +60,7 @@ final class RegistrationTransactionBuilder { return _buildUnsignedRbacTx( auxiliaryData: AuxiliaryData.fromCbor( - x509Envelope.toCbor(serializer: (e) => e.toCbor()), + await x509Envelope.toCbor(serializer: (e) => e.toCbor()), ), ); } diff --git a/catalyst_voices_packages/catalyst_cardano/catalyst_cardano/example/lib/sign_and_submit_rbac_tx.dart b/catalyst_voices_packages/catalyst_cardano/catalyst_cardano/example/lib/sign_and_submit_rbac_tx.dart index ac34dc1ab64..6a32f9453b6 100644 --- a/catalyst_voices_packages/catalyst_cardano/catalyst_cardano/example/lib/sign_and_submit_rbac_tx.dart +++ b/catalyst_voices_packages/catalyst_cardano/catalyst_cardano/example/lib/sign_and_submit_rbac_tx.dart @@ -34,7 +34,7 @@ Future _signAndSubmitRbacTx({ ); final auxiliaryData = AuxiliaryData.fromCbor( - x509Envelope.toCbor(serializer: (e) => e.toCbor()), + await x509Envelope.toCbor(serializer: (e) => e.toCbor()), ); final unsignedTx = _buildUnsignedRbacTx( @@ -122,7 +122,9 @@ Future> _buildMetadataEnvelope({ print('unsigned x509 envelope:'); print( - hex.encode(cbor.encode(x509Envelope.toCbor(serializer: (e) => e.toCbor()))), + hex.encode( + cbor.encode(await x509Envelope.toCbor(serializer: (e) => e.toCbor())), + ), ); final signedX509Envelope = await x509Envelope.sign( @@ -133,7 +135,9 @@ Future> _buildMetadataEnvelope({ print('signed x509 envelope:'); print( hex.encode( - cbor.encode(signedX509Envelope.toCbor(serializer: (e) => e.toCbor())), + cbor.encode( + await signedX509Envelope.toCbor(serializer: (e) => e.toCbor()), + ), ), ); diff --git a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart index d9275fdb8c1..9e14f9f2857 100644 --- a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart +++ b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart @@ -129,16 +129,16 @@ final class X509MetadataEnvelope extends Equatable { /// /// The [deserializer] in most cases is going /// to be [RegistrationData.fromCbor]. - factory X509MetadataEnvelope.fromCbor( + static Future> fromCbor( CborValue value, { required ChunkedDataDeserializer deserializer, - }) { + }) async { final metadata = value as CborMap; final envelope = metadata[const CborSmallInt(509)]! as CborMap; final purpose = envelope[const CborSmallInt(0)]! as CborBytes; final txInputsHash = envelope[const CborSmallInt(1)]!; final previousTransactionId = envelope[const CborSmallInt(2)]; - final chunkedData = _deserializeChunkedData(envelope); + final chunkedData = await _deserializeChunkedData(envelope); final validationSignature = envelope[const CborSmallInt(99)]!; return X509MetadataEnvelope( @@ -155,10 +155,12 @@ final class X509MetadataEnvelope extends Equatable { /// Serializes the type as cbor. /// /// The [serializer] in most cases is going to be [RegistrationData.toCbor]. - CborValue toCbor({required ChunkedDataSerializer serializer}) { + Future toCbor({ + required ChunkedDataSerializer serializer, + }) async { final chunkedData = this.chunkedData; final metadata = chunkedData != null - ? _serializeChunkedData(serializer(chunkedData)) + ? await _serializeChunkedData(serializer(chunkedData)) : null; return CborMap({ @@ -182,7 +184,7 @@ final class X509MetadataEnvelope extends Equatable { required Ed25519PrivateKey privateKey, required ChunkedDataSerializer serializer, }) async { - final bytes = cbor.encode(toCbor(serializer: serializer)); + final bytes = cbor.encode(await toCbor(serializer: serializer)); final signature = await privateKey.sign(bytes); return withValidationSignature(signature); } @@ -197,7 +199,7 @@ final class X509MetadataEnvelope extends Equatable { required ChunkedDataSerializer serializer, }) async { final envelope = withValidationSignature(Ed25519Signature.seeded(0)); - final bytes = cbor.encode(envelope.toCbor(serializer: serializer)); + final bytes = cbor.encode(await envelope.toCbor(serializer: serializer)); return signature.verify(bytes, publicKey: publicKey); } @@ -215,7 +217,7 @@ final class X509MetadataEnvelope extends Equatable { ); } - static CborValue? _deserializeChunkedData(CborMap map) { + static Future _deserializeChunkedData(CborMap map) async { final rawCbor = map[const CborSmallInt(10)] as CborList?; if (rawCbor != null) { final bytes = _unchunkCborBytes(rawCbor); @@ -226,7 +228,7 @@ final class X509MetadataEnvelope extends Equatable { if (brotliCbor != null) { final bytes = _unchunkCborBytes(brotliCbor); final uncompressedBytes = - CatalystCompression.instance.brotli.decompress(bytes); + await CatalystCompression.instance.brotli.decompress(bytes); return cbor.decode(uncompressedBytes); } @@ -234,19 +236,19 @@ final class X509MetadataEnvelope extends Equatable { if (zstdCbor != null) { final bytes = _unchunkCborBytes(zstdCbor); final uncompressedBytes = - CatalystCompression.instance.zstd.decompress(bytes); + await CatalystCompression.instance.zstd.decompress(bytes); return cbor.decode(uncompressedBytes); } return null; } - static MapEntry _serializeChunkedData( + static Future> _serializeChunkedData( CborValue value, - ) { + ) async { final rawBytes = cbor.encode(value); - final brotliBytes = _compressBrotli(rawBytes); - final zstdBytes = _compressZstd(rawBytes); + final brotliBytes = await _compressBrotli(rawBytes); + final zstdBytes = await _compressZstd(rawBytes); final bytesByKey = { 10: rawBytes, @@ -266,7 +268,7 @@ final class X509MetadataEnvelope extends Equatable { ); } - static List? _compressBrotli(List bytes) { + static Future?> _compressBrotli(List bytes) async { try { return CatalystCompression.instance.brotli.compress(bytes); } on CompressionNotSupportedException { @@ -274,7 +276,7 @@ final class X509MetadataEnvelope extends Equatable { } } - static List? _compressZstd(List bytes) { + static Future?> _compressZstd(List bytes) async { try { return CatalystCompression.instance.zstd.compress(bytes); } on CompressionNotSupportedException { diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression/example/main.dart b/catalyst_voices_packages/catalyst_compression/catalyst_compression/example/main.dart index 22697d19e98..2a102c3732b 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression/example/main.dart +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression/example/main.dart @@ -42,13 +42,13 @@ E61E8EE7D77E9F7F9804E03EBC31B458 ''' .replaceAll('\n', ''); -void main() { +Future main() async { final rawBytes = hex.decode(derCertHex); // brotli final brotli = CatalystCompression.instance.brotli; - final brotliCompressed = brotli.compress(rawBytes); - final brotliDecompressed = brotli.decompress(brotliCompressed); + final brotliCompressed = await brotli.compress(rawBytes); + final brotliDecompressed = await brotli.decompress(brotliCompressed); assert( listEquals(rawBytes, brotliDecompressed), @@ -57,8 +57,8 @@ void main() { // zstd final zstd = CatalystCompression.instance.zstd; - final zstdCompressed = zstd.compress(rawBytes); - final zstdDecompressed = zstd.decompress(zstdCompressed); + final zstdCompressed = await zstd.compress(rawBytes); + final zstdDecompressed = await zstd.decompress(zstdCompressed); assert( listEquals(rawBytes, zstdDecompressed), diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_platform_interface/lib/src/catalyst_compressor.dart b/catalyst_voices_packages/catalyst_compression/catalyst_compression_platform_interface/lib/src/catalyst_compressor.dart index c64ff341dec..34908e27f89 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_platform_interface/lib/src/catalyst_compressor.dart +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_platform_interface/lib/src/catalyst_compressor.dart @@ -7,13 +7,13 @@ abstract class CatalystCompressor { /// /// Compressing and then decompressing the [bytes] /// should yield the original [bytes]. - List compress(List bytes); + Future> compress(List bytes); /// Returns the list of decompressed [bytes]. /// /// Compressing and then decompressing the [bytes] /// should yield the original [bytes]. - List decompress(List bytes); + Future> decompress(List bytes); } /// Exception thrown when [CatalystCompressor.compress] can't compress diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart index 0c5e8d84cf2..2ddf2830b1d 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart @@ -2,6 +2,7 @@ library catalyst_compression_interop; import 'dart:js_interop'; +import 'dart:js_util'; import 'package:catalyst_compression_platform_interface/catalyst_compression_platform_interface.dart'; import 'package:convert/convert.dart'; @@ -11,28 +12,28 @@ import 'package:convert/convert.dart'; /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external JSString brotliCompress(JSString bytes); +external Object brotliCompress(JSString bytes); /// Decompresses the [bytes] using brotli algorithm. /// /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external JSString brotliDecompress(JSString bytes); +external Object brotliDecompress(JSString bytes); /// Compresses the [bytes] using zstd algorithm. /// /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external JSString zstdCompress(JSString bytes); +external Object zstdCompress(JSString bytes); /// Decompresses the [bytes] using zstd algorithm. /// /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external JSString zstdDecompress(JSString bytes); +external Object zstdDecompress(JSString bytes); /// The JS implementation of brotli compressor. class JSBrotliCompressor implements CatalystCompressor { @@ -40,15 +41,17 @@ class JSBrotliCompressor implements CatalystCompressor { const JSBrotliCompressor(); @override - List compress(List bytes) { - final data = brotliCompress(hex.encode(bytes).toJS).toDart; - return hex.decode(data); + Future> compress(List bytes) async { + final data = + await promiseToFuture(brotliCompress(hex.encode(bytes).toJS)); + return hex.decode(data.toDart); } @override - List decompress(List bytes) { - final data = brotliDecompress(hex.encode(bytes).toJS).toDart; - return hex.decode(data); + Future> decompress(List bytes) async { + final data = + await promiseToFuture(brotliDecompress(hex.encode(bytes).toJS)); + return hex.decode(data.toDart); } } @@ -65,20 +68,22 @@ class JSZstdCompressor implements CatalystCompressor { const JSZstdCompressor(); @override - List compress(List bytes) { + Future> compress(List bytes) async { if (bytes.length < _minLength) { throw CompressionNotSupportedException( 'Bytes too short, actual: ${bytes.length}, required: $_minLength', ); } - final data = zstdCompress(hex.encode(bytes).toJS).toDart; - return hex.decode(data); + final data = + await promiseToFuture(zstdCompress(hex.encode(bytes).toJS)); + return hex.decode(data.toDart); } @override - List decompress(List bytes) { - final data = zstdDecompress(hex.encode(bytes).toJS).toDart; - return hex.decode(data); + Future> decompress(List bytes) async { + final data = + await promiseToFuture(zstdDecompress(hex.encode(bytes).toJS)); + return hex.decode(data.toDart); } } From 30dc858bd528606c64d05bb3708563c1ffd6fb72 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Thu, 17 Oct 2024 01:24:43 +0700 Subject: [PATCH 03/18] feat: unique calling ids --- .../catalyst_compression/README.md | 10 +-- .../assets/js/catalyst_compression.js | 68 +++++++++++++++---- .../assets/js/catalyst_compression_worker.js | 8 +-- .../interop/catalyst_compression_interop.dart | 8 +-- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression/README.md b/catalyst_voices_packages/catalyst_compression/catalyst_compression/README.md index 68965ff97a8..d5c0683c0f4 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression/README.md +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression/README.md @@ -85,13 +85,13 @@ E61E8EE7D77E9F7F9804E03EBC31B458 ''' .replaceAll('\n', ''); -void main() { +Future main() async { final rawBytes = hex.decode(derCertHex); // brotli final brotli = CatalystCompression.instance.brotli; - final brotliCompressed = brotli.compress(rawBytes); - final brotliDecompressed = brotli.decompress(brotliCompressed); + final brotliCompressed = await brotli.compress(rawBytes); + final brotliDecompressed = await brotli.decompress(brotliCompressed); assert( listEquals(rawBytes, brotliDecompressed), @@ -100,8 +100,8 @@ void main() { // zstd final zstd = CatalystCompression.instance.zstd; - final zstdCompressed = zstd.compress(rawBytes); - final zstdDecompressed = zstd.decompress(zstdCompressed); + final zstdCompressed = await zstd.compress(rawBytes); + final zstdDecompressed = await zstd.decompress(zstdCompressed); assert( listEquals(rawBytes, zstdDecompressed), diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index 68757ef39ad..fbde165ede0 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -1,25 +1,69 @@ +// initialize a web worker for compression works. +// this is a persistent worker, will last for life of the app. +const compressionWorker = new Worker('/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js'); + +const processingIdsPool = new Set(); + +// A simple id generator function. The generated id must be unique across all the processing ids. +function generateId() { + let id + do { + const timestamp = Date.now().toString(36); + const randomNum = Math.random().toString(36).substring(2, 8); + id = `${timestamp}-${randomNum}`; + } while (processingIdsPool.has(id)); + processingIdsPool.add(id); + + return id; +} + +function removeWorkerListener(onMessage, onError) { + compressionWorker.removeEventListener("message", onMessage); + compressionWorker.removeEventListener("error", onError); +} + +// A function to create a compression function according to its name. function runCompressionInWorker(fnName) { return (data) => { return new Promise((resolve, reject) => { - const compressionWorker = new Worker('/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js'); - - compressionWorker.onmessage = (event) => { - const { result, initialized, error } = event.data; - if (initialized) { - compressionWorker.postMessage({ action: fnName, bytesHex: data }); - } else if (result) { + const id = generateId(); + + const handleMessage = (event) => { + const { + id: responseId, + result, + error, + initialized + } = event.data; + + // skip the initialized completion event, + // and the id that is not itself. + if (initialized || responseId !== id) { + return; + } + + if (result) { resolve(result); - compressionWorker.terminate() } else { reject(error || null); - compressionWorker.terminate() } + + processingIdsPool.delete(id); + + removeWorkerListener(handleMessage, handleError); }; - - compressionWorker.onerror = (error) => { + const handleError = (error) => { reject(error); - compressionWorker.terminate() + + processingIdsPool.clear(); + + removeWorkerListener(handleMessage, handleError); }; + + compressionWorker.addEventListener("message", handleMessage); + compressionWorker.addEventListener("error", handleError); + + compressionWorker.postMessage({ id, action: fnName, bytesHex: data }); }); } } diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js index 5443bc0f78a..c5ab236b703 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js @@ -66,16 +66,16 @@ Promise.all([ }; self.onmessage = (event) => { - const { action, bytesHex } = event.data; + const { id, action, bytesHex } = event.data; if (catalyst_compression[action]) { try { const result = catalyst_compression[action](bytesHex); - self.postMessage({ result }); + self.postMessage({ id, result }); } catch (error) { - self.postMessage({ error: error.message }); + self.postMessage({ id, error: error.message }); } } else { - self.postMessage({ error: 'Unknown action' }); + self.postMessage({ id, error: 'Unknown action' }); } }; diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart index 2ddf2830b1d..40ecf6ae01f 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart @@ -12,28 +12,28 @@ import 'package:convert/convert.dart'; /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external Object brotliCompress(JSString bytes); +external JSPromise brotliCompress(JSString bytes); /// Decompresses the [bytes] using brotli algorithm. /// /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external Object brotliDecompress(JSString bytes); +external JSPromise brotliDecompress(JSString bytes); /// Compresses the [bytes] using zstd algorithm. /// /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external Object zstdCompress(JSString bytes); +external JSPromise zstdCompress(JSString bytes); /// Decompresses the [bytes] using zstd algorithm. /// /// The bytes are transferred as hex string due to /// raw bytes not being supported by the js_interop. @JS() -external Object zstdDecompress(JSString bytes); +external JSPromise zstdDecompress(JSString bytes); /// The JS implementation of brotli compressor. class JSBrotliCompressor implements CatalystCompressor { From a663a40c5cf002c9cef0a01fc42fc2f0c1eb214e Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Thu, 17 Oct 2024 01:31:47 +0700 Subject: [PATCH 04/18] chore: interop --- .../interop/catalyst_compression_interop.dart | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart index 40ecf6ae01f..eaa41e22424 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart @@ -42,15 +42,17 @@ class JSBrotliCompressor implements CatalystCompressor { @override Future> compress(List bytes) async { - final data = - await promiseToFuture(brotliCompress(hex.encode(bytes).toJS)); + final data = await promiseToFuture( + brotliCompress(hex.encode(bytes).toJS), + ); return hex.decode(data.toDart); } @override Future> decompress(List bytes) async { - final data = - await promiseToFuture(brotliDecompress(hex.encode(bytes).toJS)); + final data = await promiseToFuture( + brotliDecompress(hex.encode(bytes).toJS), + ); return hex.decode(data.toDart); } } @@ -75,15 +77,17 @@ class JSZstdCompressor implements CatalystCompressor { ); } - final data = - await promiseToFuture(zstdCompress(hex.encode(bytes).toJS)); + final data = await promiseToFuture( + zstdCompress(hex.encode(bytes).toJS), + ); return hex.decode(data.toDart); } @override Future> decompress(List bytes) async { - final data = - await promiseToFuture(zstdDecompress(hex.encode(bytes).toJS)); + final data = await promiseToFuture( + zstdDecompress(hex.encode(bytes).toJS), + ); return hex.decode(data.toDart); } } From f9895132f88722f5d603a3168b6f75dc8c09d202 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Thu, 17 Oct 2024 02:33:44 +0700 Subject: [PATCH 05/18] fix: asset loading path --- .../catalyst_compression_web/assets/js/catalyst_compression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index fbde165ede0..c84a23ca9f6 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -1,6 +1,6 @@ // initialize a web worker for compression works. // this is a persistent worker, will last for life of the app. -const compressionWorker = new Worker('/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js'); +const compressionWorker = new Worker('/assets/packages/catalyst_compression_web/assets/js/catalyst_compression_worker.js'); const processingIdsPool = new Set(); From 740df05c8d7f2dddc3c11bbcd7242b3d133ae239 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Thu, 17 Oct 2024 02:58:46 +0700 Subject: [PATCH 06/18] chore: worker initial message event --- .../assets/js/catalyst_compression.js | 13 +++++-------- .../assets/js/catalyst_compression_worker.js | 8 ++++++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index c84a23ca9f6..bb44d9d5cc2 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -17,11 +17,6 @@ function generateId() { return id; } -function removeWorkerListener(onMessage, onError) { - compressionWorker.removeEventListener("message", onMessage); - compressionWorker.removeEventListener("error", onError); -} - // A function to create a compression function according to its name. function runCompressionInWorker(fnName) { return (data) => { @@ -36,7 +31,7 @@ function runCompressionInWorker(fnName) { initialized } = event.data; - // skip the initialized completion event, + // skip the initializing completion event, // and the id that is not itself. if (initialized || responseId !== id) { return; @@ -50,14 +45,16 @@ function runCompressionInWorker(fnName) { processingIdsPool.delete(id); - removeWorkerListener(handleMessage, handleError); + compressionWorker.removeEventListener("message", handleMessage); + compressionWorker.removeEventListener("error", handleError); }; const handleError = (error) => { reject(error); processingIdsPool.clear(); - removeWorkerListener(handleMessage, handleError); + compressionWorker.removeEventListener("message", handleMessage); + compressionWorker.removeEventListener("error", handleError); }; compressionWorker.addEventListener("message", handleMessage); diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js index c5ab236b703..7de73de5f9d 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression_worker.js @@ -1,3 +1,9 @@ +// initial message handler from the main thread. +self.onmessage = (event) => { + const { id } = event.data; + self.postMessage({ id, error: 'Worker is not ready' }); +}; + Promise.all([ import('https://unpkg.com/brotli-wasm@3.0.0/index.web.js?module').then(m => m.default), import('https://unpkg.com/@oneidentity/zstd-js@1.0.3/wasm/index.js?module') @@ -65,6 +71,7 @@ Promise.all([ zstdDecompress: _zstdDecompress, }; + // replace the initial handler with the actual handler. self.onmessage = (event) => { const { id, action, bytesHex } = event.data; if (catalyst_compression[action]) { @@ -79,6 +86,7 @@ Promise.all([ } }; + // send an event to notify the main thread that the worker is ready. self.postMessage({ initialized: true }); }).catch(error => { self.postMessage({ error: `Failed to load modules: ${error.message}` }); From 293524373a76b7c7331fbc849820e0ea5b34ced3 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Thu, 17 Oct 2024 03:19:58 +0700 Subject: [PATCH 07/18] refactor: compression web --- .../assets/js/catalyst_compression.js | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index bb44d9d5cc2..06c7d6ac390 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -17,48 +17,55 @@ function generateId() { return id; } +function registerWorkerEventHandler(worker, handleMessage, handleError) { + const wrappedHandleMessage = (event) => handleMessage(event, complete); + const wrappedHandleError = (error) => handleError(error, complete); + + function complete() { + worker.removeEventListener("message", wrappedHandleMessage); + worker.removeEventListener("error", wrappedHandleError) + } + + worker.addEventListener("message", wrappedHandleMessage) + worker.addEventListener("error", wrappedHandleError) +} + // A function to create a compression function according to its name. function runCompressionInWorker(fnName) { return (data) => { return new Promise((resolve, reject) => { const id = generateId(); - const handleMessage = (event) => { - const { - id: responseId, - result, - error, - initialized - } = event.data; - - // skip the initializing completion event, - // and the id that is not itself. - if (initialized || responseId !== id) { - return; + registerWorkerEventHandler( + compressionWorker, + (event, complete) => { + const { + id: responseId, + result, + error, + initialized + } = event.data; + + // skip the initializing completion event, + // and the id that is not itself. + if (initialized || responseId !== id) { + return; + } + + if (result) { + complete(resolve(result)); + } else { + complete(reject(error || 'Unexpected error')); + } + + processingIdsPool.delete(id); + }, + (error, complete) => { + complete(reject(error)); + + processingIdsPool.clear(); } - - if (result) { - resolve(result); - } else { - reject(error || null); - } - - processingIdsPool.delete(id); - - compressionWorker.removeEventListener("message", handleMessage); - compressionWorker.removeEventListener("error", handleError); - }; - const handleError = (error) => { - reject(error); - - processingIdsPool.clear(); - - compressionWorker.removeEventListener("message", handleMessage); - compressionWorker.removeEventListener("error", handleError); - }; - - compressionWorker.addEventListener("message", handleMessage); - compressionWorker.addEventListener("error", handleError); + ); compressionWorker.postMessage({ id, action: fnName, bytesHex: data }); }); From f87028f3128ba0c5c1b55bc6a613493fc9f19dbd Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Thu, 17 Oct 2024 12:55:53 +0700 Subject: [PATCH 08/18] chore: complete calling function --- .../assets/js/catalyst_compression.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index 06c7d6ac390..4a1c1f4eedf 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -53,17 +53,19 @@ function runCompressionInWorker(fnName) { } if (result) { - complete(resolve(result)); + resolve(result); } else { - complete(reject(error || 'Unexpected error')); + reject(error || 'Unexpected error'); } processingIdsPool.delete(id); + complete(); }, (error, complete) => { - complete(reject(error)); + reject(error); processingIdsPool.clear(); + complete(); } ); From 00010d0722e737293259fb53ee7eb2017c58f89e Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Thu, 17 Oct 2024 17:50:37 +0700 Subject: [PATCH 09/18] fix: worker loading path --- .../catalyst_compression_web/assets/js/catalyst_compression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index 4a1c1f4eedf..1aa7d18d6cc 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -1,6 +1,6 @@ // initialize a web worker for compression works. // this is a persistent worker, will last for life of the app. -const compressionWorker = new Worker('/assets/packages/catalyst_compression_web/assets/js/catalyst_compression_worker.js'); +const compressionWorker = new Worker(new URL('./catalyst_compression_worker.js', import.meta.url)); const processingIdsPool = new Set(); From bb106e606a04018b79cfa3c66cc9c340b924b04e Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj <38898766+apskhem@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:25:37 +0700 Subject: [PATCH 10/18] fix: await in try/catch Co-authored-by: Dominik Toton <166132265+dtscalac@users.noreply.github.com> --- .../lib/src/rbac/x509_metadata_envelope.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart index 9e14f9f2857..82abc71488c 100644 --- a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart +++ b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart @@ -270,7 +270,7 @@ final class X509MetadataEnvelope extends Equatable { static Future?> _compressBrotli(List bytes) async { try { - return CatalystCompression.instance.brotli.compress(bytes); + return await CatalystCompression.instance.brotli.compress(bytes); } on CompressionNotSupportedException { return null; } From e25f18305ea58f5ac288fe80c212532d3ca08433 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj <38898766+apskhem@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:53:17 +0700 Subject: [PATCH 11/18] fix: await in try/catch for zstd Co-authored-by: Dominik Toton <166132265+dtscalac@users.noreply.github.com> --- .../lib/src/rbac/x509_metadata_envelope.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart index 82abc71488c..22c7ca0ed4a 100644 --- a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart +++ b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/rbac/x509_metadata_envelope.dart @@ -278,7 +278,7 @@ final class X509MetadataEnvelope extends Equatable { static Future?> _compressZstd(List bytes) async { try { - return CatalystCompression.instance.zstd.compress(bytes); + return await CatalystCompression.instance.zstd.compress(bytes); } on CompressionNotSupportedException { return null; } From 73f8f541fc2c7fe0efb2c87f10f61779d913506a Mon Sep 17 00:00:00 2001 From: Dominik Toton Date: Fri, 18 Oct 2024 10:24:36 +0200 Subject: [PATCH 12/18] chore: annotate code parts that require optimization --- .../lib/src/keychain/key_derivation.dart | 3 +++ .../catalyst_cardano_serialization/lib/src/signature.dart | 3 +++ 2 files changed, 6 insertions(+) diff --git a/catalyst_voices/packages/catalyst_voices_services/lib/src/keychain/key_derivation.dart b/catalyst_voices/packages/catalyst_voices_services/lib/src/keychain/key_derivation.dart index 53ec2f37d9b..017301be517 100644 --- a/catalyst_voices/packages/catalyst_voices_services/lib/src/keychain/key_derivation.dart +++ b/catalyst_voices/packages/catalyst_voices_services/lib/src/keychain/key_derivation.dart @@ -7,6 +7,9 @@ final class KeyDerivation { /// Derives an [Ed25519KeyPair] from a [seedPhrase] and [path]. /// /// Example [path]: m/0'/2147483647' + /// + // TODO(dtscalac): this takes around 2.5s to execute, optimize it + // or move to a JS web worker. Future deriveKeyPair({ required SeedPhrase seedPhrase, required String path, diff --git a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart index bee9f452d85..d27e4d64b0a 100644 --- a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart +++ b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart @@ -116,6 +116,9 @@ extension type Ed25519PrivateKey._(List bytes) { String toHex() => hex.encode(bytes); /// Signs the [message] with the private key and returns the signature. + /// + /// TODO(dtscalac): it takes 200-300ms to execute, optimize it + /// or move to a JS web worker Future sign(List message) async { final algorithm = Ed25519(); final keyPair = await algorithm.newKeyPairFromSeed(bytes); From 0313924a9419ea84944d58aa313c3df099cf0748 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj <38898766+apskhem@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:47:42 +0700 Subject: [PATCH 13/18] chore: minor comment Co-authored-by: Dominik Toton <166132265+dtscalac@users.noreply.github.com> --- .../assets/js/catalyst_compression.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index 1aa7d18d6cc..34dc5233847 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -1,5 +1,5 @@ -// initialize a web worker for compression works. -// this is a persistent worker, will last for life of the app. +// Initialize a web worker for compression works. +// This is a persistent worker, will last for life of the app. const compressionWorker = new Worker(new URL('./catalyst_compression_worker.js', import.meta.url)); const processingIdsPool = new Set(); From db0b0302cefdf7c78e0932028241bab730602e07 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Fri, 18 Oct 2024 15:54:22 +0700 Subject: [PATCH 14/18] refactor: random string to number counter --- .../assets/js/catalyst_compression.js | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index 34dc5233847..91b2523a8a8 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -2,19 +2,16 @@ // This is a persistent worker, will last for life of the app. const compressionWorker = new Worker(new URL('./catalyst_compression_worker.js', import.meta.url)); -const processingIdsPool = new Set(); +let idCounter = 0; // A simple id generator function. The generated id must be unique across all the processing ids. function generateId() { - let id - do { - const timestamp = Date.now().toString(36); - const randomNum = Math.random().toString(36).substring(2, 8); - id = `${timestamp}-${randomNum}`; - } while (processingIdsPool.has(id)); - processingIdsPool.add(id); + const thisId = idCounter; + const nextId = idCounter + 1; - return id; + idCounter = nextId >= Number.MAX_SAFE_INTEGER ? 0 : nextId; + + return thisId; } function registerWorkerEventHandler(worker, handleMessage, handleError) { @@ -23,11 +20,11 @@ function registerWorkerEventHandler(worker, handleMessage, handleError) { function complete() { worker.removeEventListener("message", wrappedHandleMessage); - worker.removeEventListener("error", wrappedHandleError) + worker.removeEventListener("error", wrappedHandleError); } - worker.addEventListener("message", wrappedHandleMessage) - worker.addEventListener("error", wrappedHandleError) + worker.addEventListener("message", wrappedHandleMessage); + worker.addEventListener("error", wrappedHandleError); } // A function to create a compression function according to its name. @@ -57,14 +54,12 @@ function runCompressionInWorker(fnName) { } else { reject(error || 'Unexpected error'); } - - processingIdsPool.delete(id); + complete(); }, (error, complete) => { reject(error); - - processingIdsPool.clear(); + complete(); } ); @@ -81,9 +76,9 @@ const catalyst_compression = { brotliDecompress: runCompressionInWorker("brotliDecompress"), zstdCompress: runCompressionInWorker("zstdCompress"), zstdDecompress: runCompressionInWorker("zstdDecompress"), -} +}; // Expose catalyst compression as globally accessible // so that we can call it via catalyst_compression.function_name() from // other scripts or dart without needing to care about module imports -window.catalyst_compression = catalyst_compression; \ No newline at end of file +window.catalyst_compression = catalyst_compression; From c01c9db7c79af4f41df28e5db3d349278be64ad5 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Fri, 18 Oct 2024 15:54:54 +0700 Subject: [PATCH 15/18] chore: minor comment --- .../catalyst_compression_web/assets/js/catalyst_compression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js index 91b2523a8a8..b4749753718 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/assets/js/catalyst_compression.js @@ -4,7 +4,7 @@ const compressionWorker = new Worker(new URL('./catalyst_compression_worker.js', let idCounter = 0; -// A simple id generator function. The generated id must be unique across all the processing ids. +// A simple id generator function. function generateId() { const thisId = idCounter; const nextId = idCounter + 1; From 85c95b33457ea81cbc582ba63b68bf375581aa46 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Fri, 18 Oct 2024 15:58:37 +0700 Subject: [PATCH 16/18] chore: simplify promise to future --- .../interop/catalyst_compression_interop.dart | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart index eaa41e22424..c912e779688 100644 --- a/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart +++ b/catalyst_voices_packages/catalyst_compression/catalyst_compression_web/lib/src/interop/catalyst_compression_interop.dart @@ -2,7 +2,6 @@ library catalyst_compression_interop; import 'dart:js_interop'; -import 'dart:js_util'; import 'package:catalyst_compression_platform_interface/catalyst_compression_platform_interface.dart'; import 'package:convert/convert.dart'; @@ -42,17 +41,13 @@ class JSBrotliCompressor implements CatalystCompressor { @override Future> compress(List bytes) async { - final data = await promiseToFuture( - brotliCompress(hex.encode(bytes).toJS), - ); + final data = await brotliCompress(hex.encode(bytes).toJS).toDart; return hex.decode(data.toDart); } @override Future> decompress(List bytes) async { - final data = await promiseToFuture( - brotliDecompress(hex.encode(bytes).toJS), - ); + final data = await brotliDecompress(hex.encode(bytes).toJS).toDart; return hex.decode(data.toDart); } } @@ -77,17 +72,13 @@ class JSZstdCompressor implements CatalystCompressor { ); } - final data = await promiseToFuture( - zstdCompress(hex.encode(bytes).toJS), - ); + final data = await zstdCompress(hex.encode(bytes).toJS).toDart; return hex.decode(data.toDart); } @override Future> decompress(List bytes) async { - final data = await promiseToFuture( - zstdDecompress(hex.encode(bytes).toJS), - ); + final data = await zstdDecompress(hex.encode(bytes).toJS).toDart; return hex.decode(data.toDart); } } From 3ebcce47cf11f8cefb2fcd12eb3e9ce4b9c93c09 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Fri, 18 Oct 2024 16:14:50 +0700 Subject: [PATCH 17/18] chore: todo comment --- .../catalyst_cardano_serialization/lib/src/signature.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart index d27e4d64b0a..4c2ebf43d17 100644 --- a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart +++ b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart @@ -116,9 +116,9 @@ extension type Ed25519PrivateKey._(List bytes) { String toHex() => hex.encode(bytes); /// Signs the [message] with the private key and returns the signature. - /// - /// TODO(dtscalac): it takes 200-300ms to execute, optimize it - /// or move to a JS web worker + // + // TODO(dtscalac): it takes 200-300ms to execute, optimize it + // or move to a JS web worker Future sign(List message) async { final algorithm = Ed25519(); final keyPair = await algorithm.newKeyPairFromSeed(bytes); From 193bd35e2593de5de5b17969dbecf5968f0e1578 Mon Sep 17 00:00:00 2001 From: Apisit Ritreungroj Date: Fri, 18 Oct 2024 16:18:32 +0700 Subject: [PATCH 18/18] chore: fmt --- .../catalyst_cardano_serialization/lib/src/signature.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart index 4c2ebf43d17..a29064f0a73 100644 --- a/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart +++ b/catalyst_voices_packages/catalyst_cardano_serialization/lib/src/signature.dart @@ -116,7 +116,7 @@ extension type Ed25519PrivateKey._(List bytes) { String toHex() => hex.encode(bytes); /// Signs the [message] with the private key and returns the signature. - // + // // TODO(dtscalac): it takes 200-300ms to execute, optimize it // or move to a JS web worker Future sign(List message) async {