DwarfNinja
DwarfNinja
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
// durable_customer_id.ts
import {DurableObject} from "cloudflare:workers";
import { Hono } from 'hono'
import {Env} from "hono";

export class DurableCustomerId extends DurableObject {
state: DurableObjectState;
app: Hono = new Hono();
sockets: Set<WebSocket>;

constructor(state: DurableObjectState, env: Env) {
super(state, env);
this.state = state;
this.sockets = new Set<WebSocket>();
const websockets = this.ctx.getWebSockets();

for (const ws of websockets) {
this.sockets.add(ws);
}

this.app.post('/mollie-payment-webhook', async (context, env) => {
const payload = await context.req.text();
console.log('Received webhook data:', payload);

const customerId = payload.split('=')[1]

for (const socket of this.sockets) {
console.log('Websocket Data Sent:', payload);
socket.send(customerId);
}

return context.text('Webhook received', 200);
});

this.app.get('/mollie-payment-websocket', (context) => {
const { 0: client, 1: server } = new WebSocketPair();

server.accept();

this.sockets.add(server);
console.log('New WebSocket client connected');

for (const socket of this.sockets) {
socket.send(" I'm Connected");
}

server.addEventListener('message', (event) => {
console.log('Message from client:', event.data);
});

server.addEventListener('close', () => {
this.sockets.delete(server);
console.log('WebSocket client disconnected');
});

return new Response(null, {
status: 101,
webSocket: client,
});
});
}
async fetch(request: Request) {
return this.app.fetch(request)
}
}
// durable_customer_id.ts
import {DurableObject} from "cloudflare:workers";
import { Hono } from 'hono'
import {Env} from "hono";

export class DurableCustomerId extends DurableObject {
state: DurableObjectState;
app: Hono = new Hono();
sockets: Set<WebSocket>;

constructor(state: DurableObjectState, env: Env) {
super(state, env);
this.state = state;
this.sockets = new Set<WebSocket>();
const websockets = this.ctx.getWebSockets();

for (const ws of websockets) {
this.sockets.add(ws);
}

this.app.post('/mollie-payment-webhook', async (context, env) => {
const payload = await context.req.text();
console.log('Received webhook data:', payload);

const customerId = payload.split('=')[1]

for (const socket of this.sockets) {
console.log('Websocket Data Sent:', payload);
socket.send(customerId);
}

return context.text('Webhook received', 200);
});

this.app.get('/mollie-payment-websocket', (context) => {
const { 0: client, 1: server } = new WebSocketPair();

server.accept();

this.sockets.add(server);
console.log('New WebSocket client connected');

for (const socket of this.sockets) {
socket.send(" I'm Connected");
}

server.addEventListener('message', (event) => {
console.log('Message from client:', event.data);
});

server.addEventListener('close', () => {
this.sockets.delete(server);
console.log('WebSocket client disconnected');
});

return new Response(null, {
status: 101,
webSocket: client,
});
});
}
async fetch(request: Request) {
return this.app.fetch(request)
}
}
12 replies
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
Alright, I migrated the connections to the Durable Object and I currently have the following, but I somehow can't get my client to receive any message. Cloudflare logs show the socket is closed right after opening. What's the issue here?
// index.ts
app.post('/mollie-payment-webhook', async (context, env) => {
const id = context.env.DURABLE_CUSTOMER_ID.idFromName("customer_id");
const stub = context.env.DURABLE_CUSTOMER_ID.get(id);

await stub.fetch(context.req.raw);

return context.text('Webhook received', 200);
});

app.get(
'/mollie-payment-websocket',
upgradeWebSocket(async (context) => {
const id = context.env.DURABLE_CUSTOMER_ID.idFromName("customer_id");
const stub = context.env.DURABLE_CUSTOMER_ID.get(id);

return stub.fetch(context.req.raw);
})
);
// index.ts
app.post('/mollie-payment-webhook', async (context, env) => {
const id = context.env.DURABLE_CUSTOMER_ID.idFromName("customer_id");
const stub = context.env.DURABLE_CUSTOMER_ID.get(id);

await stub.fetch(context.req.raw);

return context.text('Webhook received', 200);
});

app.get(
'/mollie-payment-websocket',
upgradeWebSocket(async (context) => {
const id = context.env.DURABLE_CUSTOMER_ID.idFromName("customer_id");
const stub = context.env.DURABLE_CUSTOMER_ID.get(id);

return stub.fetch(context.req.raw);
})
);
12 replies
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
May I ask why it is better for the DO to handle the connection? How would I migratie the functionality into the DO? Can I just pretty much copy paste the app.post and app.get code? (ps. im using hono) Thank you in advance!
12 replies
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
EDIT SOLVED ✅: Got it to work by using Durable Object Storage to store the received webhook data during the /mollie-webhook call and later retrieve it in /mollie-payment-sse. I assume it's due to that the Durable Object is destroyed after it is used in /mollie-webhook which means it loses it's state, but I'll need someone to confirm that.
12 replies
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
//durable-webhook.ts
import { DurableObject } from "cloudflare:workers";
import {Env} from "hono";

export class DurableWebhook extends DurableObject {
webhookData: string | null = null;

constructor(state: DurableObjectState, env: Env) {
super(state, env);
}

// Stores incoming webhook data
async storeWebhookData(webhookData: string): Promise<string> {
this.webhookData = webhookData;
return "Webhook data stored";
}

// Returns the stored webhook data (if any)
async getWebhookData(): Promise<string | null> {
return this.webhookData;
}

// Clears the stored webhook data
async clearWebhookData(): Promise<void> {
this.webhookData = null;
}
}
//durable-webhook.ts
import { DurableObject } from "cloudflare:workers";
import {Env} from "hono";

export class DurableWebhook extends DurableObject {
webhookData: string | null = null;

constructor(state: DurableObjectState, env: Env) {
super(state, env);
}

// Stores incoming webhook data
async storeWebhookData(webhookData: string): Promise<string> {
this.webhookData = webhookData;
return "Webhook data stored";
}

// Returns the stored webhook data (if any)
async getWebhookData(): Promise<string | null> {
return this.webhookData;
}

// Clears the stored webhook data
async clearWebhookData(): Promise<void> {
this.webhookData = null;
}
}
12 replies
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
@Leo & @Hard@Work thank you for your responses. You have one me over and I started with Durable Objects today. Im trying to learn how they work and currently got this implementation. The problem im now facing is is that the webhookdata is null when retrieved in the stream. Stub WebhookData: null What am I missing here? Is the Durable Object disposed in between /mollie-webhook and /mollie-payment-sse? Thanks in advance!
//index.ts
app.post('/mollie-webhook', async (context, env) => {
const payload = await context.req.text()
console.log('Received webhook data:', payload)

const id = context.env.DURABLE_WEBHOOK.idFromName("durable_webhook");
const stub = context.env.DURABLE_WEBHOOK.get(id);

const rpcResponse = await stub.storeWebhookData(payload);
console.log(rpcResponse);

return context.text('Webhook received')
})

app.get('/mollie-payment-sse', async (c) => {

return streamSSE(c, async (stream: SSEStreamingApi) => {
const id = c.env.DURABLE_WEBHOOK.idFromName("durable_webhook");
const stub = c.env.DURABLE_WEBHOOK.get(id);

while (true) {
await stream.sleep(1000);

const webhookData = await stub.getWebhookData();
console.log(`Stub WebhookData: ${webhookData}`);

if (webhookData) {
await stream.writeSSE({
event: "new-payment-update",
data: webhookData
});

await stub.clearWebhookData();
}
}
});
});
//index.ts
app.post('/mollie-webhook', async (context, env) => {
const payload = await context.req.text()
console.log('Received webhook data:', payload)

const id = context.env.DURABLE_WEBHOOK.idFromName("durable_webhook");
const stub = context.env.DURABLE_WEBHOOK.get(id);

const rpcResponse = await stub.storeWebhookData(payload);
console.log(rpcResponse);

return context.text('Webhook received')
})

app.get('/mollie-payment-sse', async (c) => {

return streamSSE(c, async (stream: SSEStreamingApi) => {
const id = c.env.DURABLE_WEBHOOK.idFromName("durable_webhook");
const stub = c.env.DURABLE_WEBHOOK.get(id);

while (true) {
await stream.sleep(1000);

const webhookData = await stub.getWebhookData();
console.log(`Stub WebhookData: ${webhookData}`);

if (webhookData) {
await stream.writeSSE({
event: "new-payment-update",
data: webhookData
});

await stub.clearWebhookData();
}
}
});
});
12 replies
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
For the current scope of the project yes, while it seems the're should be an alternative or is Durable Objects the only solution?
12 replies
CDCloudflare Developers
Created by DwarfNinja on 2/19/2025 in #workers-help
Receiving webhook in a worker and sending it to the frontend?
@Leo As mentioned I'd rather use an alternative if possible as it seems that purchasing Workers Pro seems overkill for this problem? Do you have any other suggestions?
12 replies