ci: docker_tag=ext - Fix WASM compilation for web target
Some checks failed
Build and Push Docker image (ext) / docker (push) Failing after 3m44s
Some checks failed
Build and Push Docker image (ext) / docker (push) Failing after 3m44s
- Recompile sdk_client WASM with --target web for ES modules - Update Dockerfile to build WASM in web target instead of bundler - Modify index.html to initialize WASM before router - Update service.ts and router.ts to use ES module imports - Fix 'module is not defined' error in browser
This commit is contained in:
parent
5da295be1a
commit
01b1b50d6b
35
Dockerfile
35
Dockerfile
@ -1,13 +1,46 @@
|
||||
# syntax=docker/dockerfile:1.4
|
||||
|
||||
# Stage 1: Build WASM for web target
|
||||
FROM rust:1.82-alpine AS wasm-builder
|
||||
WORKDIR /build
|
||||
|
||||
# Install dependencies for WASM compilation
|
||||
RUN apk update && apk add --no-cache git openssh-client curl nodejs npm build-base pkgconfig clang llvm musl-dev
|
||||
|
||||
# Install wasm-bindgen-cli
|
||||
RUN cargo install wasm-bindgen-cli --version 0.2.103 --locked && rustup target add wasm32-unknown-unknown
|
||||
|
||||
# Setup SSH for git clone
|
||||
RUN mkdir -p /root/.ssh && ssh-keyscan git.4nkweb.com >> /root/.ssh/known_hosts
|
||||
|
||||
# Copy project files
|
||||
COPY . ihm_client/
|
||||
|
||||
# Clone and build sdk_client for web target
|
||||
RUN --mount=type=ssh git clone -b dev ssh://git@git.4nkweb.com/4nk/sdk_client.git
|
||||
WORKDIR /build/sdk_client
|
||||
|
||||
# Build WASM for web target (ES modules)
|
||||
RUN cargo build --target wasm32-unknown-unknown --profile dev && \
|
||||
wasm-bindgen target/wasm32-unknown-unknown/debug/sdk_client.wasm \
|
||||
--out-dir /build/ihm_client/pkg \
|
||||
--typescript \
|
||||
--target web \
|
||||
--debug
|
||||
|
||||
# Stage 2: Final application
|
||||
FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Installation des dépendances nécessaires
|
||||
RUN apk update && apk add --no-cache git nginx
|
||||
|
||||
# Copie du projet (incluant pkg pré-compilé)
|
||||
# Copy project files
|
||||
COPY . .
|
||||
|
||||
# Copy the web-compiled WASM package
|
||||
COPY --from=wasm-builder /build/ihm_client/pkg ./pkg
|
||||
|
||||
# Installation des dépendances Node.js
|
||||
RUN npm install
|
||||
|
||||
|
18
index.html
18
index.html
@ -17,9 +17,23 @@
|
||||
</div>
|
||||
<!-- <script type="module" src="/src/index.ts"></script> -->
|
||||
<script type="module">
|
||||
import { init } from '/src/router.ts';
|
||||
// Initialize WASM first
|
||||
import init, * as sdk from './pkg/sdk_client.js';
|
||||
|
||||
// Initialize the application
|
||||
import { init as initRouter } from '/src/router.ts';
|
||||
|
||||
(async () => {
|
||||
await init();
|
||||
try {
|
||||
// Initialize WASM
|
||||
await init();
|
||||
console.log('WASM initialized successfully');
|
||||
|
||||
// Initialize the router
|
||||
await initRouter();
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize application:', error);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
@ -10,7 +10,7 @@ import { prepareAndSendPairingTx } from './utils/sp-address.utils';
|
||||
import ModalService from './services/modal.service';
|
||||
import { MessageType } from './models/process.model';
|
||||
import { splitPrivateData, isValid32ByteHex } from './utils/service.utils';
|
||||
import { MerkleProofResult } from 'pkg/sdk_client';
|
||||
import { MerkleProofResult } from 'pkg/sdk_client.js';
|
||||
|
||||
const routes: { [key: string]: string } = {
|
||||
home: '/src/pages/home/home.html',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { INotification } from '~/models/notification.model';
|
||||
import { IProcess } from '~/models/process.model';
|
||||
import { initWebsocket, sendMessage } from '../websockets';
|
||||
import { ApiReturn, Device, HandshakeMessage, Member, MerkleProofResult, NewTxMessage, OutPointProcessMap, Process, ProcessState, RoleDefinition, SecretsStore, UserDiff } from '../../pkg/sdk_client';
|
||||
import { ApiReturn, Device, HandshakeMessage, Member, MerkleProofResult, NewTxMessage, OutPointProcessMap, Process, ProcessState, RoleDefinition, SecretsStore, UserDiff } from '../../pkg/sdk_client.js';
|
||||
import ModalService from './modal.service';
|
||||
import Database from './database.service';
|
||||
import { navigate } from '../router';
|
||||
@ -58,7 +58,8 @@ export default class Services {
|
||||
|
||||
public async init(): Promise<void> {
|
||||
this.notifications = this.getNotifications();
|
||||
this.sdkClient = await import('../../pkg/sdk_client');
|
||||
// SDK is now imported as ES module at the top of the file
|
||||
this.sdkClient = await import('../../pkg/sdk_client.js');
|
||||
this.sdkClient.setup();
|
||||
for (const wsurl of Object.values(BOOTSTRAPURL)) {
|
||||
this.updateRelay(wsurl, '');
|
||||
@ -87,7 +88,7 @@ export default class Services {
|
||||
*/
|
||||
public async connectAllRelays(): Promise<void> {
|
||||
const connectedUrls: string[] = [];
|
||||
|
||||
|
||||
// Connect to all relays
|
||||
for (const wsurl of Object.keys(this.relayAddresses)) {
|
||||
try {
|
||||
@ -99,7 +100,7 @@ export default class Services {
|
||||
console.error(`Failed to connect to ${wsurl}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Wait for at least one handshake message if we have connections
|
||||
if (connectedUrls.length > 0) {
|
||||
await this.waitForHandshakeMessage();
|
||||
@ -381,18 +382,18 @@ export default class Services {
|
||||
roles: Record<string, RoleDefinition>,
|
||||
): Promise<ApiReturn> {
|
||||
let relayAddress = this.getAllRelays()[0]?.spAddress;
|
||||
|
||||
|
||||
if (!relayAddress || relayAddress === '') {
|
||||
console.log('No relay address found, connecting to relays...');
|
||||
await this.connectAllRelays();
|
||||
|
||||
|
||||
// After connectAllRelays completes, relay addresses should be updated
|
||||
relayAddress = this.getAllRelays()[0]?.spAddress;
|
||||
if (!relayAddress || relayAddress === '') {
|
||||
throw new Error('No relay address available after connecting to relays');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const feeRate = 1;
|
||||
|
||||
// We can't encode files as the rest because Uint8Array is not valid json
|
||||
@ -400,12 +401,12 @@ export default class Services {
|
||||
// TODO encoding of relatively large binaries (=> 1M) is a bit long now and blocking
|
||||
const privateSplitData = this.splitData(privateData);
|
||||
const publicSplitData = this.splitData(publicData);
|
||||
const encodedPrivateData = {
|
||||
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
||||
const encodedPrivateData = {
|
||||
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
||||
...this.sdkClient.encode_binary(privateSplitData.binaryData)
|
||||
};
|
||||
const encodedPublicData = {
|
||||
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
||||
const encodedPublicData = {
|
||||
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
||||
...this.sdkClient.encode_binary(publicSplitData.binaryData)
|
||||
};
|
||||
|
||||
@ -413,10 +414,10 @@ export default class Services {
|
||||
console.log('encoded data:', encodedPublicData);
|
||||
|
||||
const result = this.sdkClient.create_new_process (
|
||||
encodedPrivateData,
|
||||
encodedPrivateData,
|
||||
roles,
|
||||
encodedPublicData,
|
||||
relayAddress,
|
||||
relayAddress,
|
||||
feeRate,
|
||||
this.getAllMembers()
|
||||
);
|
||||
@ -440,12 +441,12 @@ export default class Services {
|
||||
}
|
||||
const privateSplitData = this.splitData(privateData);
|
||||
const publicSplitData = this.splitData(publicData);
|
||||
const encodedPrivateData = {
|
||||
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
||||
const encodedPrivateData = {
|
||||
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
||||
...this.sdkClient.encode_binary(privateSplitData.binaryData)
|
||||
};
|
||||
const encodedPublicData = {
|
||||
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
||||
const encodedPublicData = {
|
||||
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
||||
...this.sdkClient.encode_binary(publicSplitData.binaryData)
|
||||
};
|
||||
try {
|
||||
@ -569,7 +570,7 @@ export default class Services {
|
||||
}
|
||||
|
||||
async parseNewTx(newTxMsg: string) {
|
||||
const parsedMsg: NewTxMessage = JSON.parse(newTxMsg);
|
||||
const parsedMsg: NewTxMessage = JSON.parse(newTxMsg);
|
||||
if (parsedMsg.error !== null) {
|
||||
console.error('Received error in new tx message:', parsedMsg.error);
|
||||
return;
|
||||
@ -864,7 +865,7 @@ export default class Services {
|
||||
try {
|
||||
const device = await this.getDeviceFromDatabase();
|
||||
if (device) {
|
||||
const pairedMember = device['paired_member'];
|
||||
const pairedMember = device['paired_member'];
|
||||
return pairedMember.sp_addresses;
|
||||
} else {
|
||||
return null;
|
||||
@ -1051,7 +1052,7 @@ export default class Services {
|
||||
} catch (e) {
|
||||
console.error(`Failed to save data to db: ${e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async getBlobFromDb(hash: string): Promise<Blob | null> {
|
||||
const db = await Database.getInstance();
|
||||
@ -1178,7 +1179,7 @@ export default class Services {
|
||||
});
|
||||
}
|
||||
|
||||
// Now we can transfer them to memory
|
||||
// Now we can transfer them to memory
|
||||
await this.restoreSecretsFromDB();
|
||||
}
|
||||
|
||||
@ -1219,7 +1220,7 @@ export default class Services {
|
||||
if (!key) {
|
||||
const roles = state.roles;
|
||||
let hasAccess = false;
|
||||
// If we're not supposed to have access to this attribute, ignore
|
||||
// If we're not supposed to have access to this attribute, ignore
|
||||
for (const role of Object.values(roles)) {
|
||||
for (const rule of Object.values(role.validation_rules)) {
|
||||
if (rule.fields.includes(attribute)) {
|
||||
@ -1241,7 +1242,7 @@ export default class Services {
|
||||
const maxRetries = 5;
|
||||
const retryDelay = 500; // delay in milliseconds
|
||||
let retries = 0;
|
||||
|
||||
|
||||
while ((!hash || !key) && retries < maxRetries) {
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
// Re-read hash and key after waiting
|
||||
@ -1274,7 +1275,7 @@ export default class Services {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1316,7 +1317,7 @@ export default class Services {
|
||||
await this.resetDevice();
|
||||
|
||||
await this.saveDeviceInDatabase(device);
|
||||
|
||||
|
||||
this.restoreDevice(device);
|
||||
|
||||
// TODO restore secrets and processes from file
|
||||
@ -1495,7 +1496,7 @@ export default class Services {
|
||||
private async waitForHandshakeMessage(timeoutMs: number = 10000): Promise<void> {
|
||||
const startTime = Date.now();
|
||||
const pollInterval = 100; // Check every 100ms
|
||||
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const checkForHandshake = () => {
|
||||
// Check if we have any members or any relays (indicating handshake was received)
|
||||
@ -1504,17 +1505,17 @@ export default class Services {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check timeout
|
||||
if (Date.now() - startTime >= timeoutMs) {
|
||||
reject(new Error(`No handshake message received after ${timeoutMs}ms timeout`));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Continue polling
|
||||
setTimeout(checkForHandshake, pollInterval);
|
||||
};
|
||||
|
||||
|
||||
checkForHandshake();
|
||||
});
|
||||
}
|
||||
@ -1565,7 +1566,7 @@ export default class Services {
|
||||
this.sendCommitMessage(JSON.stringify(content));
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
|
||||
public getRoles(process: Process): Record<string, RoleDefinition> | null {
|
||||
const lastCommitedState = this.getLastCommitedState(process);
|
||||
if (lastCommitedState && lastCommitedState.roles && Object.keys(lastCommitedState.roles).length != 0) {
|
||||
@ -1745,7 +1746,7 @@ export default class Services {
|
||||
return process.states[index + 1];
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
public isPairingProcess(roles: Record<string, RoleDefinition>): boolean {
|
||||
|
Loading…
x
Reference in New Issue
Block a user