Skip to content

Commit 43e55c0

Browse files
committed
WIP: connection websocket
1 parent 628233a commit 43e55c0

File tree

11 files changed

+172
-3
lines changed

11 files changed

+172
-3
lines changed

apps/book-server/src/lib/mq/MqService.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export class MqService {
5353

5454
type SubscriptionResolverKey = keyof SubscriptionResolvers
5555
type Payload = {
56-
[K in SubscriptionResolverKey]?: { message: string }
56+
[K in SubscriptionResolverKey]?: { message: string } & { [k in string]: any }
5757
}
5858
type TopicMap = {
5959
[K in SubscriptionResolverKey]: (args: any) => string

apps/book-server/src/services/BookDeployService/index.mts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ConfilctError } from '@errors/ConfilctError.mjs'
1212
import { DeployResult } from '@graphql/generated.js'
1313
import { MongoService } from '@lib/mongo/MongoService.mjs'
1414
import { RedisService } from '@lib/redis/RedisService.mjs'
15+
import { MqService } from '@lib/mq/MqService.mjs'
1516

1617
interface Service {
1718
deploy: (bookId: string, signedWriterId?: string) => Promise<DeployResult>
@@ -23,6 +24,7 @@ export class BookDeployService implements Service {
2324
private readonly mongo: MongoService,
2425
private readonly awsS3: AwsS3Service,
2526
private readonly redis: RedisService,
27+
private readonly mq: MqService,
2628
private readonly writerService: WriterService,
2729
private readonly bookService: BookService,
2830
) {}
@@ -113,6 +115,16 @@ export class BookDeployService implements Service {
113115
})
114116
})
115117

118+
this.mq.publish({
119+
topicParameter: book.id,
120+
payload: {
121+
deployCompleted: {
122+
message: 'Deploy completed',
123+
published_url,
124+
},
125+
},
126+
})
127+
116128
return {
117129
published_url,
118130
}

apps/book-web/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"graphql": "^16.7.1",
2626
"graphql-request": "^6.1.0",
2727
"graphql-tag": "^2.12.6",
28+
"graphql-ws": "^5.16.0",
2829
"gray-matter": "^4.0.3",
2930
"next": "14.2.3",
3031
"react": "^18",
@@ -37,7 +38,9 @@
3738
"remark-reading-time": "^2.0.1",
3839
"shiki": "^0.14.3",
3940
"unified": "^10.1.2",
41+
"urql": "^4.1.0",
4042
"vscode-oniguruma": "^2.0.1",
43+
"wonka": "^6.3.4",
4144
"zod": "^3.23.7"
4245
},
4346
"devDependencies": {

apps/book-web/src/graphql/bookServer/book.gql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,9 @@ mutation build($input: BookUrlSlugInput!) {
1313
query isDeploy($input: IsDeployInput!) {
1414
isDeploy(input: $input)
1515
}
16+
17+
subscription DeployCompleted($input: BookUrlSlugInput!) {
18+
deployCompleted(input: $input) {
19+
message
20+
}
21+
}

apps/book-web/src/graphql/bookServer/generated/bookServer.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ export type IsDeployQueryVariables = Exact<{
222222

223223
export type IsDeployQuery = { isDeploy: boolean }
224224

225+
export type DeployCompletedSubscriptionVariables = Exact<{
226+
input: BookUrlSlugInput
227+
}>
228+
229+
export type DeployCompletedSubscription = { deployCompleted: { message: string } | null }
230+
225231
export type GetPagesQueryVariables = Exact<{
226232
input: GetPagesInput
227233
}>
@@ -385,6 +391,13 @@ useSuspenseIsDeployQuery.getKey = (variables: IsDeployQueryVariables) => [
385391
useIsDeployQuery.fetcher = (variables: IsDeployQueryVariables, options?: RequestInit['headers']) =>
386392
fetcher<IsDeployQuery, IsDeployQueryVariables>(IsDeployDocument, variables, options)
387393

394+
export const DeployCompletedDocument = `
395+
subscription DeployCompleted($input: BookUrlSlugInput!) {
396+
deployCompleted(input: $input) {
397+
message
398+
}
399+
}
400+
`
388401
export const GetPagesDocument = `
389402
query getPages($input: GetPagesInput!) {
390403
pages(input: $input) {

apps/book-web/src/graphql/bookServer/helpers/bookServerFetcher.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { ENV } from '@/env'
22
import graphqlFetch from '@/lib/graphqlFetch'
3+
import { pipe, subscribe } from 'wonka'
4+
import { urqlClient } from './bookServerUrlql'
5+
import { AnyVariables } from 'urql'
36

47
export function fetcher<TData, TVariables extends Record<string, any>>(
58
query: string,
@@ -19,3 +22,20 @@ export function fetcher<TData, TVariables extends Record<string, any>>(
1922
return data as Awaited<TData>
2023
}
2124
}
25+
export function subscriptionFetcher<TData, TVariables extends AnyVariables>(
26+
query: string,
27+
variables: TVariables,
28+
) {
29+
return new Promise<TData>((resolve) => {
30+
const subscription = pipe(
31+
urqlClient.subscription<TData, TVariables>(query, variables),
32+
subscribe((result) => {
33+
if (result.data) {
34+
resolve(result.data)
35+
}
36+
}),
37+
)
38+
39+
return () => subscription.unsubscribe()
40+
})
41+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { createClient, subscriptionExchange, cacheExchange, fetchExchange } from 'urql'
2+
import { createClient as createWSClient, SubscribePayload } from 'graphql-ws'
3+
import { ENV } from '@/env'
4+
5+
const wsClient = createWSClient({
6+
url: `ws://${ENV.graphqlBookServerHost.replace(/^http(s)?:\/\//, '')}/graphql`,
7+
})
8+
9+
export const urqlClient = createClient({
10+
url: `${ENV.graphqlBookServerHost}/graphql`,
11+
exchanges: [
12+
cacheExchange,
13+
fetchExchange,
14+
subscriptionExchange({
15+
forwardSubscription: (operation) => ({
16+
subscribe: (sink) => ({
17+
unsubscribe: wsClient.subscribe(operation as SubscribePayload, sink),
18+
}),
19+
}),
20+
}),
21+
],
22+
})

apps/book-web/src/layouts/MarkdownEditorLayout/MarkdownEditorLayout.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { themeConfig } from './context'
77
import { useEffect, useState } from 'react'
88
import { BookMetadata, generateBookMetadata, Pages } from '@/lib/generateBookMetadata'
99
import {
10+
DeployCompletedDocument,
1011
useBuildMutation,
1112
useCreatePageMutation,
1213
useDeletePageMutation,
@@ -18,6 +19,7 @@ import {
1819
useUpdatePageMutation,
1920
} from '@/graphql/bookServer/generated/bookServer'
2021
import { useUrlSlug } from '@/hooks/useUrlSlug'
22+
import { useSubscription } from 'urql'
2123

2224
type Props = {
2325
children?: React.ReactNode
@@ -54,6 +56,15 @@ function MarkdownEditorLayout({ children, mdxText }: Props) {
5456
},
5557
})
5658

59+
const deployCompleted = useSubscription({
60+
query: DeployCompletedDocument,
61+
variables: { input: { book_url_slug: bookUrlSlug } },
62+
})
63+
64+
useEffect(() => {
65+
console.log(deployCompleted)
66+
}, [deployCompleted])
67+
5768
const { data: isDeployData } = useIsDeployQuery({
5869
input: {
5970
book_url_slug: bookUrlSlug,
@@ -230,7 +241,6 @@ function MarkdownEditorLayout({ children, mdxText }: Props) {
230241
}
231242

232243
const timeoutId = setTimeout(dispatchDeployEvent, 200)
233-
234244
return () => {
235245
clearTimeout(timeoutId)
236246
}

apps/book-web/src/provider/CoreProvider.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ReactQueryProvider from './ReactQueryProvider'
2+
import UrqlProvider from './UrqlProvider'
23

34
type Props = {
45
children: React.ReactNode
@@ -7,7 +8,9 @@ type Props = {
78
function CoreProvider({ children }: Props) {
89
return (
910
<>
10-
<ReactQueryProvider>{children}</ReactQueryProvider>
11+
<ReactQueryProvider>
12+
<UrqlProvider>{children}</UrqlProvider>
13+
</ReactQueryProvider>
1114
</>
1215
)
1316
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { createClient, subscriptionExchange, cacheExchange, fetchExchange, Provider } from 'urql'
2+
import { createClient as createWSClient, SubscribePayload } from 'graphql-ws'
3+
import { ENV } from '@/env'
4+
5+
type Props = {
6+
children: React.ReactNode
7+
}
8+
9+
const wsClient = createWSClient({
10+
url: `ws://${ENV.graphqlBookServerHost.replace(/^http(s)?:\/\//, '')}/graphql`,
11+
})
12+
13+
export const urqlClient = createClient({
14+
url: `${ENV.graphqlBookServerHost}/graphql`,
15+
exchanges: [
16+
cacheExchange,
17+
fetchExchange,
18+
subscriptionExchange({
19+
forwardSubscription: (operation) => ({
20+
subscribe: (sink) => ({
21+
unsubscribe: wsClient.subscribe(operation as SubscribePayload, sink),
22+
}),
23+
}),
24+
}),
25+
],
26+
})
27+
28+
function UrqlProvider({ children }: Props) {
29+
return <Provider value={urqlClient}>{children}</Provider>
30+
}
31+
32+
export default UrqlProvider

pnpm-lock.yaml

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)