From 448f71a07cc79d591b11e40dad2047aade6ebce4 Mon Sep 17 00:00:00 2001 From: tsuki Date: Fri, 1 Aug 2025 19:07:03 +0800 Subject: [PATCH] WS --- app/page.tsx | 19 +++++++++++++++ lib/apollo-client.ts | 21 +++++++++++++++-- package-lock.json | 55 ++++++++++++++++++++++++++++++++++++-------- package.json | 3 ++- 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index e9282ab..1f2aec4 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -20,6 +20,17 @@ import { cn } from '@/lib/utils'; import { useTimeline } from '@/hooks/use-timeline'; import { useEffect } from 'react' import { useRadarTile } from '@/hooks/use-radartile' +import { gql, useSubscription } from '@apollo/client' + +const SUBSCRIPTION_QUERY = gql` + subscription { + statusUpdates { + id + message + status + } + } +` export default function Page() { @@ -30,6 +41,14 @@ export default function Page() { const { setTime } = useTimeline() const { imgBitmap, fetchRadarTile } = useRadarTile({}) + const { data, loading, error } = useSubscription(SUBSCRIPTION_QUERY) + + useEffect(() => { + if (data) { + console.log(data.statusUpdates) + } + }, [data]) + return ( diff --git a/lib/apollo-client.ts b/lib/apollo-client.ts index 7de875d..b6578a0 100644 --- a/lib/apollo-client.ts +++ b/lib/apollo-client.ts @@ -1,5 +1,9 @@ -import { ApolloClient, InMemoryCache, createHttpLink, from } from '@apollo/client'; +import { ApolloClient, InMemoryCache, createHttpLink, from, split } from '@apollo/client'; +import { getMainDefinition } from '@apollo/client/utilities'; import { setContext } from '@apollo/client/link/context'; +import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; +import { createClient } from 'graphql-ws'; + const TOKEN_KEY = 'auth_token'; @@ -7,6 +11,10 @@ const httpLink = createHttpLink({ uri: "http://127.0.0.1:3050/graphql", }); +const wsLink = new GraphQLWsLink(createClient({ + url: "ws://127.0.0.1:3050/ws", +})); + const authLink = setContext((_, { headers }) => { // 从 localStorage 获取 token const token = typeof window !== 'undefined' ? localStorage.getItem(TOKEN_KEY) : null; @@ -29,9 +37,18 @@ const authLink = setContext((_, { headers }) => { }; }); +const link = split( + ({ query }) => { + const def = getMainDefinition(query); + return def.kind === 'OperationDefinition' && def.operation === 'subscription'; + }, + wsLink, // 如果是 subscription,则走 ws + from([authLink, httpLink]) +); + export const createApolloClient = () => { return new ApolloClient({ - link: from([authLink, httpLink]), + link, cache: new InMemoryCache(), }); }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c37bda5..930f809 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@21st-extension/react": "^0.5.14", "@21st-extension/toolbar-next": "^0.5.14", - "@apollo/client": "^3.13.8", + "@apollo/client": "^3.13.9", "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", @@ -40,6 +40,7 @@ "dnd-kit": "^0.0.2", "framer-motion": "^12.23.6", "graphql": "^16.11.0", + "graphql-ws": "^6.0.6", "lucide-react": "^0.525.0", "maplibre-gl": "^5.6.1", "next": "15.4.1", @@ -140,9 +141,9 @@ } }, "node_modules/@apollo/client": { - "version": "3.13.8", - "resolved": "http://mirrors.cloud.tencent.com/npm/@apollo/client/-/client-3.13.8.tgz", - "integrity": "sha512-YM9lQpm0VfVco4DSyKooHS/fDTiKQcCHfxr7i3iL6a0kP/jNO5+4NFK6vtRDxaYisd5BrwOZHLJpPBnvRVpKPg==", + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.13.9.tgz", + "integrity": "sha512-RStSzQfL1XwL6/NWd7W8avhGQYTgPCtJ+qHkkTTSj9Upp3VVm6Oppv81YWdXG1FgEpDPW4hvCrTUELdcC4inCQ==", "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", @@ -3564,7 +3565,7 @@ }, "node_modules/graphql": { "version": "16.11.0", - "resolved": "http://mirrors.cloud.tencent.com/npm/graphql/-/graphql-16.11.0.tgz", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", "license": "MIT", "engines": { @@ -3586,6 +3587,36 @@ "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/graphql-ws": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.6.tgz", + "integrity": "sha512-zgfER9s+ftkGKUZgc0xbx8T7/HMO4AV5/YuYiFc+AtgcO5T0v8AxYYNQ+ltzuzDZgNkYJaFspm5MMYLjQzrkmw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@fastify/websocket": "^10 || ^11", + "crossws": "~0.3", + "graphql": "^15.10.1 || ^16", + "uWebSockets.js": "^20", + "ws": "^8" + }, + "peerDependenciesMeta": { + "@fastify/websocket": { + "optional": true + }, + "crossws": { + "optional": true + }, + "uWebSockets.js": { + "optional": true + }, + "ws": { + "optional": true + } + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -5599,9 +5630,9 @@ } }, "@apollo/client": { - "version": "3.13.8", - "resolved": "http://mirrors.cloud.tencent.com/npm/@apollo/client/-/client-3.13.8.tgz", - "integrity": "sha512-YM9lQpm0VfVco4DSyKooHS/fDTiKQcCHfxr7i3iL6a0kP/jNO5+4NFK6vtRDxaYisd5BrwOZHLJpPBnvRVpKPg==", + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.13.9.tgz", + "integrity": "sha512-RStSzQfL1XwL6/NWd7W8avhGQYTgPCtJ+qHkkTTSj9Upp3VVm6Oppv81YWdXG1FgEpDPW4hvCrTUELdcC4inCQ==", "requires": { "@graphql-typed-document-node/core": "^3.1.1", "@wry/caches": "^1.0.0", @@ -7705,7 +7736,7 @@ }, "graphql": { "version": "16.11.0", - "resolved": "http://mirrors.cloud.tencent.com/npm/graphql/-/graphql-16.11.0.tgz", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==" }, "graphql-tag": { @@ -7716,6 +7747,12 @@ "tslib": "^2.1.0" } }, + "graphql-ws": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.6.tgz", + "integrity": "sha512-zgfER9s+ftkGKUZgc0xbx8T7/HMO4AV5/YuYiFc+AtgcO5T0v8AxYYNQ+ltzuzDZgNkYJaFspm5MMYLjQzrkmw==", + "requires": {} + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", diff --git a/package.json b/package.json index 0ceb249..7ca64fe 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "dependencies": { "@21st-extension/react": "^0.5.14", "@21st-extension/toolbar-next": "^0.5.14", - "@apollo/client": "^3.13.8", + "@apollo/client": "^3.13.9", "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", @@ -41,6 +41,7 @@ "dnd-kit": "^0.0.2", "framer-motion": "^12.23.6", "graphql": "^16.11.0", + "graphql-ws": "^6.0.6", "lucide-react": "^0.525.0", "maplibre-gl": "^5.6.1", "next": "15.4.1",