From 6a6ef2216f83d5efaa894083cce7140e1cec7189 Mon Sep 17 00:00:00 2001 From: tech-shrimp Date: Wed, 1 Jan 2025 18:13:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++ worker.js | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 README.md create mode 100644 worker.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..f5fbae9 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Gemini API 的cloudflare worker 代理 + +使用cloudflare worker 将Gemini 2.0 免费的原生多模态API代理到国内
+ +## 使用方法 +将 [`worker.js`](worker.js)内容拷贝到 https://workers.cloudflare.com/playground +然后点击部署按钮 + +## 作者 +技术爬爬虾,分享好玩实用软件DIY的科技博主,全网同名。 diff --git a/worker.js b/worker.js new file mode 100644 index 0000000..3ca3fbf --- /dev/null +++ b/worker.js @@ -0,0 +1,121 @@ +export default { + async fetch(request, env, ctx) { + if (request.headers.get("Upgrade") !== "websocket") { + return new Response("Expected WebSocket connection", { status: 400 }); + } + + const url = new URL(request.url); + const pathAndQuery = url.pathname + url.search; + const targetUrl = `wss://generativelanguage.googleapis.com${pathAndQuery}`; + + console.log('Target URL:', targetUrl); + + const [client, proxy] = new WebSocketPair(); + proxy.accept(); + + // 用于存储在连接建立前收到的消息 + let pendingMessages = []; + + const connectPromise = new Promise((resolve, reject) => { + const targetWebSocket = new WebSocket(targetUrl); + + console.log('Initial targetWebSocket readyState:', targetWebSocket.readyState); + + targetWebSocket.addEventListener("open", () => { + console.log('Connected to target server'); + console.log('targetWebSocket readyState after open:', targetWebSocket.readyState); + + // 连接建立后,发送所有待处理的消息 + console.log(`Processing ${pendingMessages.length} pending messages`); + for (const message of pendingMessages) { + try { + targetWebSocket.send(message); + console.log('Sent pending message:', message.slice(0, 100)); + } catch (error) { + console.error('Error sending pending message:', error); + } + } + pendingMessages = []; // 清空待处理消息队列 + resolve(targetWebSocket); + }); + + proxy.addEventListener("message", async (event) => { + console.log('Received message from client:', { + dataPreview: typeof event.data === 'string' ? event.data.slice(0, 200) : 'Binary data', + dataType: typeof event.data, + timestamp: new Date().toISOString() + }); + + if (targetWebSocket.readyState === WebSocket.OPEN) { + try { + targetWebSocket.send(event.data); + console.log('Successfully sent message to gemini'); + } catch (error) { + console.error('Error sending to gemini:', error); + } + } else { + // 如果连接还未建立,将消息加入待处理队列 + console.log('Connection not ready, queueing message'); + pendingMessages.push(event.data); + } + }); + + targetWebSocket.addEventListener("message", (event) => { + console.log('Received message from gemini:', { + dataPreview: typeof event.data === 'string' ? event.data.slice(0, 200) : 'Binary data', + dataType: typeof event.data, + timestamp: new Date().toISOString() + }); + + try { + if (proxy.readyState === WebSocket.OPEN) { + proxy.send(event.data); + console.log('Successfully forwarded message to client'); + } + } catch (error) { + console.error('Error forwarding to client:', error); + } + }); + + targetWebSocket.addEventListener("close", (event) => { + console.log('Gemini connection closed:', { + code: event.code, + reason: event.reason || 'No reason provided', + wasClean: event.wasClean, + timestamp: new Date().toISOString(), + readyState: targetWebSocket.readyState + }); + if (proxy.readyState === WebSocket.OPEN) { + proxy.close(event.code, event.reason); + } + }); + + proxy.addEventListener("close", (event) => { + console.log('Client connection closed:', { + code: event.code, + reason: event.reason || 'No reason provided', + wasClean: event.wasClean, + timestamp: new Date().toISOString() + }); + if (targetWebSocket.readyState === WebSocket.OPEN) { + targetWebSocket.close(event.code, event.reason); + } + }); + + targetWebSocket.addEventListener("error", (error) => { + console.error('Gemini WebSocket error:', { + error: error.message || 'Unknown error', + timestamp: new Date().toISOString(), + readyState: targetWebSocket.readyState + }); + }); + }); + + ctx.waitUntil(connectPromise); + + return new Response(null, { + status: 101, + webSocket: client, + }); + }, + }; \ No newline at end of file