I tried to store the client_key from on_open but in fact on_open is never used.
Goal I want to send_app_message(key.clone(), msg); a message to the user to niffy them that their friend request has been excpeted. Also, the message should be send to spesfic user (channel) and others should not be able to access it.
can I also use caller() instead of client_key?
This is something that shouldn’t happen. Every time a new client connects, the on_open callback is called by the CDK on the canister. If this doesn’t happen, it means that the connection is still not fully established. This appears to be a bug, that we also have encountered and that we’re fixing. As a temporary workaround, reinstalling the canister should fix it (but you’re going to loose all the canister data, so be careful!).
We’re working on a more robust protocol for the IC WebSocket, that we’ll release soon. We’ll also update the tutorial accordingly. With this update, you’ll be able to use the client’s principal instead of that client_key. So, to answer your question:
No, you can’t with the current version. What you can do for now is to create a map client principal → client_key in order to find the right client_key to pass to the send_app_message function.
If you call the ws_send passing a specific client_key, the underlying IC WebSocket protocol takes care of delivering it to the right client and only that one.
P.S.: I’ve reached you out in DM if you want to have a call together, so that we can help you out better.
@AliSci we’ve updated the tutorial with the new versions (commit hashes) of both the JS SDK and the Rust CDK that should fix the bug. Reporting them here also:
You have to serialize the message to a Candid bytes array before sending it. This will change in the next release.
To serialize the message, you can use the candid::encode_one function, like we do in the ic_websocket_example:
let msg_bytes = encode_one(&msg).unwrap()
if let Err(e) = ws_send(client_key, msg_bytes) {
println!("Could not send message: {}", e);
}
To make things simpler, you can define an implementation for your AppMessage struct, like:
Please note that you’ll have to serialize/deserialize the message also on the frontend. Have a look at the idl.ts file of the ic_websocket_example:
Again, in the next version both the serialization and deserialization of your messages will be handled automatically by the SDKs, so that you don’t have to care about it.
Are you using the candid crate or the re-exports from the id_cdk crate?
In the latter case, please switch to the candid crate.
In the former case, which version of the candid crate are you using? The IC WebSocket CDK is using the version 0.9.3, so I’d suggest you to use the same version for your canister.
use ic_cdk_macros::*;
use handlers::{on_close, on_message, on_open};
use ic_websocket_cdk::{
CanisterWsCloseArguments, CanisterWsCloseResult, CanisterWsGetMessagesArguments,
CanisterWsGetMessagesResult, CanisterWsMessageArguments, CanisterWsMessageResult,
CanisterWsOpenArguments, CanisterWsOpenResult, CanisterWsRegisterArguments,
CanisterWsRegisterResult, WsHandlers,
};
use candid::candid_method;
mod handlers;
// Paste here the principal of the gateway obtained when running the gateway
pub const GATEWAY_PRINCIPAL: &str = "<gateway-principal>";
#[init]
fn init() {
let handlers = WsHandlers {
on_open: Some(on_open),
on_message: Some(on_message),
on_close: Some(on_close),
};
ic_websocket_cdk::init(handlers, GATEWAY_PRINCIPAL);
}
#[post_upgrade]
fn post_upgrade() {
let handlers = WsHandlers {
on_open: Some(on_open),
on_message: Some(on_message),
on_close: Some(on_close),
};
ic_websocket_cdk::init(handlers, GATEWAY_PRINCIPAL);
}
// method called by the client SDK when instantiating a new IcWebSocket
#[update]
#[candid_method(update)]
fn ws_register(args: CanisterWsRegisterArguments) -> CanisterWsRegisterResult {
ic_websocket_cdk::ws_register(args)
}
// method called by the WS Gateway after receiving FirstMessage from the client
#[update]
#[candid_method(update)]
fn ws_open(args: CanisterWsOpenArguments) -> CanisterWsOpenResult {
ic_websocket_cdk::ws_open(args)
}
// method called by the Ws Gateway when closing the IcWebSocket connection
#[update]
#[candid_method(update)]
fn ws_close(args: CanisterWsCloseArguments) -> CanisterWsCloseResult {
ic_websocket_cdk::ws_close(args)
}
// method called by the frontend SDK to send a message to the canister
#[update]
#[candid_method(update)]
fn ws_message(args: CanisterWsMessageArguments) -> CanisterWsMessageResult {
ic_websocket_cdk::ws_message(args)
}
// method called by the WS Gateway to get messages for all the clients it serves
#[query]
#[candid_method(query)]
fn ws_get_messages(args: CanisterWsGetMessagesArguments) -> CanisterWsGetMessagesResult {
ic_websocket_cdk::ws_get_messages(args)
}
[package]
name = "ic_websocket_example_backend"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
[dependencies]
ic-websocket-cdk = { git = "https://github.com/omnia-network/ic-websocket-cdk-rs", rev = "a1d05625f96faa12cad484afcdd01ddad39bb28c", version = "0.1.0" }
serde_cbor = "0.11.2"
dotenv = "0.15.0"
lazy_static = "1.4"
serde = "1.0.176"
candid = "0.9.3"
ic-cdk = "0.9.2"
ic-cdk-macros = "0.7.0"
ic-cdk-timers = "0.2.0"
@AliSci is your code publicly available? Or is there a way I can see it? I think this way I can help you better.
Please also keep in mind that we’ll release the next version of the protocol (and so the SDKs and the Gateway) by the end of September and all these bugs should be solved. Thanks for your patience
We’re slowly rolling out the new version with the new protocol, we’ve shut down the temporary gatewayv1 and updated the gateway at wss://gateway.icws.io with the latest version.
Error: Failed while trying to deploy canisters.
Caused by: Failed while trying to deploy canisters.
Failed to build all canisters.
Failed while trying to build all canisters.
The post-build step failed for canister 'bd3sg-teaaa-aaaaa-qaaba-cai' (ic_websocket_example_2_frontend) with an embedded error: Failed to build frontend for network 'local'.: The command '"npm" "run" "build"' failed with exit status 'exit status: 1'.
Stdout:
> ic_websocket_example_2_frontend@0.2.0 prebuild
> dfx generate
> ic_websocket_example_2_frontend@0.2.0 build
> webpack
asset index.js 1.61 MiB [compared for emit] (name: index) 1 related asset
asset .ic-assets.json5 5.4 KiB [compared for emit] [from: src/ic_websocket_example_2_frontend/src/.ic-assets.json5] [copied]
asset index.html 707 bytes [compared for emit]
runtime modules 1.25 KiB 6 modules
javascript modules 1.25 MiB
modules by path ./node_modules/ 1.25 MiB 209 modules
modules by path ./src/ 3.96 KiB 3 modules
optional modules 30 bytes [optional] 2 modules
+ 3 modules
json modules 161 KiB
./node_modules/bip39/src/wordlists/czech.json 18.6 KiB [optional] [built] [code generated]
./node_modules/bip39/src/wordlists/chinese_simplified.json 8.01 KiB [optional] [built] [code generated]
./node_modules/bip39/src/wordlists/chinese_traditional.json 8.01 KiB [optional] [built] [code generated]
./node_modules/bip39/src/wordlists/korean.json 17.7 KiB [optional] [built] [code generated]
./node_modules/bip39/src/wordlists/french.json 20 KiB [optional] [built] [code generated]
+ 6 modules
ERROR in ./node_modules/@dfinity/identity-secp256k1/lib/cjs/hdkey.js 14:17-34
Module not found: Error: Can't resolve 'crypto' in '/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/@dfinity/identity-secp256k1/lib/cjs'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }'
- install 'crypto-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "crypto": false }
resolve 'crypto' in '/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/@dfinity/identity-secp256k1/lib/cjs'
Parsed request is a module
using description file: /Users/ahmed/Desktop/ic_websocket_example_2/node_modules/@dfinity/identity-secp256k1/package.json (relative path: ./lib/cjs)
Field 'browser' doesn't contain a valid alias configuration
resolve as module
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/@dfinity/identity-secp256k1/lib/cjs/node_modules doesn't exist or is not a directory
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/@dfinity/identity-secp256k1/lib/node_modules doesn't exist or is not a directory
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/@dfinity/identity-secp256k1/node_modules doesn't exist or is not a directory
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/@dfinity/node_modules doesn't exist or is not a directory
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/node_modules doesn't exist or is not a directory
looking for modules in /Users/ahmed/Desktop/ic_websocket_example_2/node_modules
single file module
using description file: /Users/ahmed/Desktop/ic_websocket_example_2/package.json (relative path: ./node_modules/crypto)
no extension
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/crypto doesn't exist
.js
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/crypto.js doesn't exist
.ts
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/crypto.ts doesn't exist
.jsx
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/crypto.jsx doesn't exist
.tsx
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/crypto.tsx doesn't exist
/Users/ahmed/Desktop/ic_websocket_example_2/node_modules/crypto doesn't exist
/Users/ahmed/Desktop/node_modules doesn't exist or is not a directory
looking for modules in /Users/ahmed/node_modules
single file module
using description file: /Users/ahmed/package.json (relative path: ./node_modules/crypto)
no extension
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/node_modules/crypto doesn't exist
.js
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/node_modules/crypto.js doesn't exist
.ts
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/node_modules/crypto.ts doesn't exist
.jsx
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/node_modules/crypto.jsx doesn't exist
.tsx
Field 'browser' doesn't contain a valid alias configuration
/Users/ahmed/node_modules/crypto.tsx doesn't exist
/Users/ahmed/node_modules/crypto doesn't exist
/Users/node_modules doesn't exist or is not a directory
/node_modules doesn't exist or is not a directory
@ ./node_modules/@dfinity/identity-secp256k1/lib/cjs/secp256k1.js 10:32-50
@ ./node_modules/@dfinity/identity-secp256k1/lib/cjs/index.js 17:13-35
@ ./node_modules/ic-websocket-js/lib/esm/identity.js 1:0-67 3:11-40
@ ./node_modules/ic-websocket-js/lib/esm/index.js 5:0-27 5:0-27
@ ./src/ic_websocket_example_2_frontend/src/index.js 2:0-68 7:15-26 9:14-36
webpack 5.88.2 compiled with 1 error in 1000 ms
Stderr:
Generating type declarations for canister ic_websocket_example_2_frontend:
src/declarations/ic_websocket_example_2_frontend/ic_websocket_example_2_frontend.did.d.ts
src/declarations/ic_websocket_example_2_frontend/ic_websocket_example_2_frontend.did.js
src/declarations/ic_websocket_example_2_frontend/ic_websocket_example_2_frontend.did
Generating type declarations for canister ic_websocket_example_2_backend:
src/declarations/ic_websocket_example_2_backend/ic_websocket_example_2_backend.did.d.ts
src/declarations/ic_websocket_example_2_backend/ic_websocket_example_2_backend.did.js
src/ic_websocket_example_2_backend/ic_websocket_example_2_backend.did
Ok when U publish on ic-websocket-js on npm I will use it then I really wish to keep trying but I can’t afford this. However, thank you so much for your help and for the websocket package really great job.