MCPcopy Create free account
hub / github.com/tiann/hapi / open

Function open

hub/src/web/server.ts:84–138  ·  view source on GitHub ↗
(clientWs: ServerWebSocket<unknown>)

Source from the content-addressed store, hash-verified

82
83 return {
84 open(clientWs: ServerWebSocket<unknown>) {
85 const data = clientWs.data as {
86 _geminiProxy: boolean
87 apiKey: string
88 language?: string
89 voiceName?: string
90 systemInstruction?: string
91 affectiveDialog?: boolean
92 }
93 const upstreamUrl = `${process.env.GEMINI_LIVE_WS_URL || GEMINI_WS_BASE}?key=${encodeURIComponent(data.apiKey)}`
94 const pending: Array<string | ArrayBuffer | Uint8Array> = []
95 pendingMap.set(clientWs, pending)
96 pendingBytesMap.set(clientWs, 0)
97
98 const upstream = new WebSocket(upstreamUrl)
99 upstreamMap.set(clientWs, upstream)
100
101 upstream.onopen = () => {
102 // Hub-owned setup only — never forward client setup (prevents generic Gemini proxy abuse).
103 // Do NOT flush pending here: wait for Google's setupComplete before forwarding client frames.
104 upstream.send(JSON.stringify(buildGeminiLiveSetupMessage(
105 data.language,
106 data.voiceName,
107 data.systemInstruction,
108 { affectiveDialog: data.affectiveDialog }
109 )))
110 }
111 upstream.onmessage = (event) => {
112 try {
113 if (clientWs.readyState === 1) {
114 clientWs.send(typeof event.data === 'string' ? event.data : new Uint8Array(event.data as ArrayBuffer))
115 }
116 } catch { /* client gone */ }
117 // Flush queued client frames only after Google acknowledges setup.
118 const pending = pendingMap.get(clientWs)
119 if (pending && isGeminiSetupCompleteFrame(event.data as string | ArrayBuffer)) {
120 pendingMap.delete(clientWs)
121 pendingBytesMap.delete(clientWs)
122 for (const queued of pending) {
123 try { upstream.send(queued) } catch { /* upstream gone */ }
124 }
125 }
126 }
127 upstream.onerror = () => {
128 pendingMap.delete(clientWs)
129 pendingBytesMap.delete(clientWs)
130 try { clientWs.close(1011, 'Upstream error') } catch { /* */ }
131 }
132 upstream.onclose = (event) => {
133 pendingMap.delete(clientWs)
134 pendingBytesMap.delete(clientWs)
135 try { clientWs.close(toClientCloseCode(event.code), event.reason || 'Upstream closed') } catch { /* client gone */ }
136 upstreamMap.delete(clientWs)
137 }
138 },
139 message(clientWs: ServerWebSocket<unknown>, message: string | ArrayBuffer | Uint8Array) {
140 if (isGeminiSetupFrame(message)) {
141 try { clientWs.close(1008, 'Client-provided Gemini setup is not allowed') } catch { /* */ }

Callers 2

updateSettingsFunction · 0.50
acquireRunnerLockFunction · 0.50

Calls 7

getMethod · 0.80
openMethod · 0.80
toClientCloseCodeFunction · 0.70
sendMethod · 0.65
closeMethod · 0.65

Tested by

no test coverage detected