Hi @AliSci , Can you please try installing those packages
npm install crypto
and npm install crypto-browserify
And then add this to you webpack.config:
crypto: require.resolve("crypto-browserify"),
, under fallback.
That was the fix in my case.
Hi @AliSci , Can you please try installing those packages
npm install crypto
and npm install crypto-browserify
And then add this to you webpack.config:
crypto: require.resolve("crypto-browserify"),
, under fallback.
That was the fix in my case.
Hi @AliSci , I think @ilbert will provide a more detailed and even more correct and precise response, but for the mean time I’ll just share what I think is the issue here. Please try to revisit Step 4: on the medium tutorial, specifically the part of removing .ic-assets.json5
file, if you have already removed it, try removing the the dist directory and redeploy. Or you can try to modify the .ic-assets.json5 file by adding this ws://127.0.0.1:8080/
at the Content-Security-Policy
line at connect-src 'self'
like this connect-src 'self' https://icp0.io https://*.icp0.io ws://127.0.0.1:8080/
. If you have 2 assets.json5, do this in both of them, and redeploy.
Also, for quick testing locally, I think you might be able to temporarily avoid this issue by using npm start instead using this local replica url, you might want to try that as well.
As for the Uncaught ReferenceError: IDL is not defined
error, I’m not really sure what could be going wrong there without seeing the code.
@iamenochchirima you explained the Content-Security-Policy
solution correctly!
Regarding this error, instead:
you just need to import IDL from @dfinity/candid to solve it:
import { IDL } from "@dfinity/candid";
The tutorial is not so clear on this point, we’re updating it.
By the way, we’ve published the packages on the registries :
Motoko CDK will soon be published on mops.
Please expect frequent (minor) updates in the next weeks.
And we’ve opened a Discord server for everything related to IC WebSockets, see you also there!
Check this out guys!
@ilbert
Oh my gosh it works now>>> thank you so much guys.
One last thing please
I want to make and update method like this
#[update]
fn send_message(text: String) {
...
}
which take a string and just send a message how can I achieve that?
To send a message from the canister to a connected client (you must know its principal), you can simply use the ws_send
method! In your case:
#[update]
fn send_message(text: String) -> ic_websocket_cdk::CanisterWsSendResult {
let msg_bytes = candid::encode_one(&text).unwrap();
// here you need to get the client's principal to which you want to send the message to
// the client must be connected to the canister via WebSocket
let client_principal = ...;
ic_websocket_cdk::ws_send(client_principal, msg_bytes)
}
We also did something similar for the canister that we use in the integration tests, to programmatically make the canister send a bunch of messages to a connected client:
ok so u mean in the frontend I should
const authClient = await AuthClient.create();
const client_principal = authClient.princpal();
// then call my actor
await websocket_backend.send_message(client_principal,message);
You should record the client’s principal once it connects to the canister and the on_open callback is fired, like we do in the test canister in the gateway repo:
This way, you can map the connected clients’ principals with some data/identifiers you use in your canister, so that you can look for them later to know their principal and properly call the ic_websocket_cdk::ws_send method.
What is your use case here? Who is supposed to call the send_message
update method? If it’s the client itself, it doesn’t make sense because the flow becomes:
send_message
with its principal to make the canister send a messageIf you instead want to send a message from the client to the canister, you should use the send
method of the IcWebSocket JS instance (see the example for reference), like you would do in a traditional websocket application.
ws.onmessage = async (event) => {
console.log("Received message:", event.data);
// serialize the message with candid before sending it
const messageToSend = IDL.encode([AppMessageIdl], [
{
text: event.data.text + "-pong test message here",
}
]);
ws.send(new Uint8Array(messageToSend));
};
I got the event.data
in form of array instead of text ? How can I parse that?
also I can do channel messages? right? because I want to a send a message to a group of people not just one person .
One more issue when I send a message it send fine , but when i send another message to the same client_principal
again it shows
"client with principal yqohg-fuhxk-4j44w-rzoqt-ma5qb-fio7j-5mk26-am4ql-crjqw-z23uj-mae doesn't have an open connection"'
As we do in the example, you can do it by simply using the IDL.decode function:
const receivedMessage = IDL.decode([AppMessageIdl], event.data)[0] as unknown as AppMessage;
From the next minor release, you won’t have to do it anymore as we’ll handle serialization and deserialization automatically for you in the JS client.
As of right now, you can’t have channels in IC WebSocket. But you can easily handle them by creating custom maps group_id
→ client_principal
and adding clients accordingly when the on_open
callback is fired. Then, when you want to send a message to a group of client, you can simply iterate on the map entries and invoke the ws_send
for each client_principal
. Does this help?
This is a weird error. Can you please paste here the piece of code that generates it and the full logs?
I’m expecting that on the client side there are some logs (most likely errors) that should tell you why the IC WebSocket connection has been closed.
We also send messages in batches to the same client in our integration tests, without getting any error:
Bro thank you so much I achieved my milestone now. I will also make a video tutorial for that to help other people.
That’s great @AliSci! Let’s also have a chat together if you like! Feel free to book a session on my calendar: IC WebSocket | Luca Bertelli | Cal.com.