Zoltan
04/13/2023, 11:22 AMnew WebSocket()
using the unique ID from the message.
First I tried Service Bindings but that doesn't seem to support WebSockets yet.
Then I tried this new WebSocket()
connection but was getting 404 instead of 101 without hitting DO at all, after some trial and error and getting 1024 from a dummy fetch request, I found that CF doesn't allow connecting two Workers within the same account.
So then I opened another account and set up the DO there. This worked but I would need to duplicate half my infrastructure to this second account in order to have all the Service Bindings and KV stores. This is less than ideal.
Now, I'm trying to set up a simple WebSocket proxy on this 2nd account. ie.: Client -> Single WS (Account 1) -> Proxy (Account 2) -> DO WS (Account 1) -> Client
My understanding is that this should just work by CF magic passing around the request but the WS keeps disconnecting right after connecting without any errors. I tested a simple fetch on the proxy and that worked.
So I tried setting up a manual proxy where I listen for messages from the ws pair and pass it along to the DO, this seem to establish a persisting connection but nothing happens with the messaging. Not getting any errors just silently failing.
I would appreciate any insights or suggestions.Zoltan
04/13/2023, 11:42 AMexport default {
fetch: async (request: Request, env: Environment, context: ExecutionContext) => {
const url = new URL(request.url)
const doUrl = new URL('wss://' + env.DO_BASE + url.pathname)
const upgradeHeader = request.headers.get('Upgrade')
if (!upgradeHeader || upgradeHeader !== 'websocket') {
return new Response('Expected Upgrade: websocket', { status: 426 })
}
const [client, server] = Object.values(new WebSocketPair())
server.accept()
const doWS = new WebSocket(pollenUrl)
doWS.addEventListener('open', () => {
console.log('open DO ws')
})
doWS.addEventListener('message', (e: MessageEvent) => {
console.log('message DO ws', e.data)
server.readyState === 1 && server.send(e.data)
})
doWS.addEventListener('close', () => {
console.log('close DO ws')
})
doWS.addEventListener('error', error => {
console.error('error DO ws', JSON.stringify(error))
})
server.addEventListener('open', event => {
console.log('open proxy ws')
})
server.addEventListener('message', async e => {
doWS.readyState === 1 && doWS.send(e.data)
})
server.addEventListener('error', error => {
console.error('error proxy ws', JSON.stringify(error))
})
server.addEventListener('close', () => {
console.log('close proxy ws')
})
return new Response(null, {
status: 101,
webSocket: client
})
}
} as ExportedHandler<Environment>
Even though it seems to connect it logs 'close proxy ws'
right after it logged 'open DO ws'
. Even though the proxy says it disconnected, the worker in Account 1 doesn't seem to say it disconnected or errored.
None of the console logs in message handlers seem to trigger.Zoltan
04/14/2023, 5:38 PM[miniflare]
values were overwriten with --wrangler-config
but not the others not).
Now I have "single client facing WS" + "multiple DO" in a single Worker in Account 1 and the simple proxy Worker in Account 2.
Here is the proxy code:
export default {
fetch: async (request: Request, env: Environment, context: ExecutionContext) => {
const upgradeHeader = request.headers.get('Upgrade')
if (!upgradeHeader || upgradeHeader !== 'websocket') {
return new Response('Expected Upgrade: websocket', { status: 426 })
}
const sockets = new Map<string, WebSocket>()
const [client, server] = Object.values(new WebSocketPair())
server.accept()
server.addEventListener('message', async event => {
const doID = event.data.doID
if (!sockets.has(doID)) {
const url = new URL(request.url)
const doUrl = new URL(env.DO_BASE + url.pathname)
doUrl.protocol = doUrl.protocol.replace('http', 'ws')
const doWS = new WebSocket(doUrl)
sockets.set(doID, doWS)
doWS.addEventListener('open', () => doWS.send(event.data))
doWS.addEventListener('message', (event: MessageEvent) => {
server.readyState === 1 && server.send(event.data)
})
doWS.addEventListener('close', () => sockets.delete(doID))
doWS.addEventListener('error', error => console.error('Durable WS', JSON.stringify(error)))
} else {
sockets.get(doID)?.readyState === 1 && sockets.get(doID)?.send(event.data)
}
})
server.addEventListener('error', error => console.error('Proxy WS', JSON.stringify(error)))
return new Response(null, { status: 101, webSocket: client })
}
} as ExportedHandler<Environment>