H
Hono3mo ago
Mik

Where Can I found WS api documentation ?

Hello I would like to know if it's possible to fill "origin" in the WS event. Or find a way to add identity information about the sender. Or get ip address of the sender. Where Can I find ws API documentation Hono documentation ?
13 Replies
Aditya Mathur
Aditya Mathur3mo ago
Do you want to get this information when starting the connection or on each message?
Mik
MikOP3mo ago
ideally I would like to have it on opening and on message. For now, I had an identifier in each messages, and I keep track of the opened socket in an array, updating this array on a close or an open event. I need that last thing for broadcasting. something like that:
var cons = [];
const app = new Hono().get(
"/ws",
upgradeWebSocket(() => {
return {
onOpen: (event, ws) => {
cons.push(ws);
console.log(`new client, ${cons.length} clients connected`);
},
onClose: (event, ws) => {
cons = cons.filter((ws) => ws.readyState !== 3);
console.log(`client removed, ${cons.length} clients connected`);
},
onMessage: (event) => {
const { eventType, source, data } = JSON.parse(event.data);
console.log(`${eventType} from ${source}`);
for (const ws of cons) {
if (ws.readyState === 1) ws.send(event.data);
}
},
};
}),
);
var cons = [];
const app = new Hono().get(
"/ws",
upgradeWebSocket(() => {
return {
onOpen: (event, ws) => {
cons.push(ws);
console.log(`new client, ${cons.length} clients connected`);
},
onClose: (event, ws) => {
cons = cons.filter((ws) => ws.readyState !== 3);
console.log(`client removed, ${cons.length} clients connected`);
},
onMessage: (event) => {
const { eventType, source, data } = JSON.parse(event.data);
console.log(`${eventType} from ${source}`);
for (const ws of cons) {
if (ws.readyState === 1) ws.send(event.data);
}
},
};
}),
);
in fact I realized that “ws” passed to each handler call was an instance specific to each client Is there anything I've missed that makes this possible?
Aditya Mathur
Aditya Mathur3mo ago
You do have the context object in upgradeWebSocket, so you can access all the information regarding the req
Mik
MikOP3mo ago
If I console log the context I don't see req and If I try to read it I get an error. This is what I tried:
const cons = [];
const app = new Hono().get(
"/ws",
upgradeWebSocket((c) => {
return {
onOpen: (event, ws) => {
console.log(c);
cons.push(ws);
console.log(`new client, ${cons.length} clients connected`);
},
onClose: (event, ws) => {
cons.sort((a, b) => a.readyState - b.readyState);
while (cons.length && cons.at(-1).readyState === 3) cons.pop();
console.log(`client removed, ${cons.length} clients connected`);
},
onMessage: (event) => {
console.log(c.req);
const { eventType, source, data } = JSON.parse(event.data);
console.log(`${eventType} from ${source}`);
for (const ws of cons) {
if (ws.readyState === 1) ws.send(event.data);
}
},
};
}),
);
const cons = [];
const app = new Hono().get(
"/ws",
upgradeWebSocket((c) => {
return {
onOpen: (event, ws) => {
console.log(c);
cons.push(ws);
console.log(`new client, ${cons.length} clients connected`);
},
onClose: (event, ws) => {
cons.sort((a, b) => a.readyState - b.readyState);
while (cons.length && cons.at(-1).readyState === 3) cons.pop();
console.log(`client removed, ${cons.length} clients connected`);
},
onMessage: (event) => {
console.log(c.req);
const { eventType, source, data } = JSON.parse(event.data);
console.log(`${eventType} from ${source}`);
for (const ws of cons) {
if (ws.readyState === 1) ws.send(event.data);
}
},
};
}),
);
And what I get :
Context {
env: ServeHandlerInfo {},
finalized: false,
error: undefined,
render: [Function: render],
setLayout: [Function: setLayout],
getLayout: [Function: getLayout],
setRenderer: [Function: setRenderer],
header: [Function: header],
status: [Function: status],
set: [Function: set],
get: [Function: get],
newResponse: [Function: newResponse],
body: [Function: body],
text: [Function: text],
json: [Function: json],
html: [Function: html],
redirect: [Function: redirect],
notFound: [Function: notFound]
}
new client, 1 clients connected
[Internal Formatting Error] AssertionError: Assertion failed.
at assert (ext:deno_console/01_console.js:184:11)
at getKeys (ext:deno_console/01_console.js:1268:7)
at formatRaw (ext:deno_console/01_console.js:745:14)
at formatValue (ext:deno_console/01_console.js:529:10)
at inspect (ext:deno_console/01_console.js:3417:10)
at Request.[Deno.privateCustomInspect] (ext:deno_fetch/23_request.js:514:12)
at formatValue (ext:deno_console/01_console.js:471:48)
at formatProperty (ext:deno_console/01_console.js:1612:11)
at formatRaw (ext:deno_console/01_console.js:931:9)
at formatValue (ext:deno_console/01_console.js:529:10)
new-offer from bar-1
Context {
env: ServeHandlerInfo {},
finalized: false,
error: undefined,
render: [Function: render],
setLayout: [Function: setLayout],
getLayout: [Function: getLayout],
setRenderer: [Function: setRenderer],
header: [Function: header],
status: [Function: status],
set: [Function: set],
get: [Function: get],
newResponse: [Function: newResponse],
body: [Function: body],
text: [Function: text],
json: [Function: json],
html: [Function: html],
redirect: [Function: redirect],
notFound: [Function: notFound]
}
new client, 1 clients connected
[Internal Formatting Error] AssertionError: Assertion failed.
at assert (ext:deno_console/01_console.js:184:11)
at getKeys (ext:deno_console/01_console.js:1268:7)
at formatRaw (ext:deno_console/01_console.js:745:14)
at formatValue (ext:deno_console/01_console.js:529:10)
at inspect (ext:deno_console/01_console.js:3417:10)
at Request.[Deno.privateCustomInspect] (ext:deno_fetch/23_request.js:514:12)
at formatValue (ext:deno_console/01_console.js:471:48)
at formatProperty (ext:deno_console/01_console.js:1612:11)
at formatRaw (ext:deno_console/01_console.js:931:9)
at formatValue (ext:deno_console/01_console.js:529:10)
new-offer from bar-1
Maybe I could try the set/get in order too put a specific id on each ws, however...
Mik
MikOP3mo ago
yet req is mentioned in the doc ... I don't understand... https://hono.dev/docs/api/context#req
Context - Hono
Ultrafast web framework for Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Node.js, and others. Fast, but not only fast.
Aditya Mathur
Aditya Mathur3mo ago
Seems to be working on my end, I am using worker's runtime. Can you share a reproduction?
No description
Aditya Mathur
Aditya Mathur3mo ago
import { Hono } from "hono";
import { upgradeWebSocket } from "hono/cloudflare-workers";

const app = new Hono();

app.get(
"/ws",
upgradeWebSocket((c) => {
console.log(c.req);
return {
onMessage(event, ws) {
console.log(c.req.header());
console.log(`Message from client: ${event.data}`);
ws.send("Hello from server!");
},
onClose: () => {
console.log("Connection closed");
},
};
})
);

export default app;
import { Hono } from "hono";
import { upgradeWebSocket } from "hono/cloudflare-workers";

const app = new Hono();

app.get(
"/ws",
upgradeWebSocket((c) => {
console.log(c.req);
return {
onMessage(event, ws) {
console.log(c.req.header());
console.log(`Message from client: ${event.data}`);
ws.send("Hello from server!");
},
onClose: () => {
console.log("Connection closed");
},
};
})
);

export default app;
Mik
MikOP3mo ago
ah ok I see, it works like this but not from the onMessage handler apparently If you want to reproduce :
import { Hono } from "hono";
import { upgradeWebSocket } from "hono/deno";

var cons = [];
const app = new Hono().get(
"/ws",
upgradeWebSocket((c) => {
console.log(c.req);
return {
onOpen: (event, ws) => {
cons.push(ws);
console.log(`new client, ${cons.length} clients connected`);
},
onClose: (event, ws) => {
console.log(c.req);
cons = cons.filter((ws) => ws.readyState !== 3);
console.log(`client removed, ${cons.length} clients connected`);
},
onMessage: (event) => {
const { eventType, source, data } = JSON.parse(event.data);
console.log(`${eventType} from ${source}`);
for (const ws of cons) {
if (ws.readyState === 1) ws.send(event.data);
}
},
};
}),
);

Deno.serve(app.fetch);
import { Hono } from "hono";
import { upgradeWebSocket } from "hono/deno";

var cons = [];
const app = new Hono().get(
"/ws",
upgradeWebSocket((c) => {
console.log(c.req);
return {
onOpen: (event, ws) => {
cons.push(ws);
console.log(`new client, ${cons.length} clients connected`);
},
onClose: (event, ws) => {
console.log(c.req);
cons = cons.filter((ws) => ws.readyState !== 3);
console.log(`client removed, ${cons.length} clients connected`);
},
onMessage: (event) => {
const { eventType, source, data } = JSON.parse(event.data);
console.log(`${eventType} from ${source}`);
for (const ws of cons) {
if (ws.readyState === 1) ws.send(event.data);
}
},
};
}),
);

Deno.serve(app.fetch);
console.log(c.req) throw en error when called from "onClose" handler I don't know if it's expected... Anyway there is no information about the remote. I'm not even sure it's possible with websockets. unless a referrer field is added to the headers I don't really need it that much anyway...
Mik
MikOP3mo ago
anyway if you need to reproduce the code is here https://codeberg.org/Mik000/nammu-web-api/src/branch/master/broker/broker.ts but i guess it's just not possible with ws
Aditya Mathur
Aditya Mathur3mo ago
Maybe this could be related to deno, can you try this with workers? You can refer to my code as an example if you are not familiar with workers, the API is similar
Mik
MikOP3mo ago
Ok I will do it Hello @Aditya Mathur . Just had a look to workers. As I understand it's related to cloudflare and for serverless application . But it turns out that the clients of the broker relies on a sqlite backend which is incompatible with a serverless application, I am afraid .
Mik
MikOP3mo ago
the "clients" use the broker here https://codeberg.org/Mik000/nammu-web-api/src/commit/cb3c60999e6eec54001b6b3959686f06b6fd3f86/server.ts#L108 and in other places in the future. (each time one of them handles a successful POST to be exact)
Mik
MikOP3mo ago
That said I could use cloudflare just for the broker and Durable Objects for persistence. But it takes me a bit away from what I wanted to do in the first place. (Anyway run serverless function on cloudflare looks very interesting, so thank you to give me the opportunity to dig this subject)
Want results from more Discord servers?
Add your server