Skip to content

Commit 4ba284b

Browse files
committed
feat: using subscription for deploy completed event
1 parent 43e55c0 commit 4ba284b

File tree

13 files changed

+89
-32
lines changed

13 files changed

+89
-32
lines changed

apps/book-server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@fastify/cookie": "^9.3.1",
2828
"@fastify/cors": "^8.3.0",
2929
"@fastify/mongodb": "^8.0.0",
30+
"@fastify/websocket": "^10.0.1",
3031
"@graphql-tools/utils": "^10.2.1",
3132
"@packages/commonjs": "workspace:*",
3233
"@packages/database": "workspace:*",

apps/book-server/src/common/plugins/global/corsPlugin.mts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import cors from '@fastify/cors'
44
import { ForbiddenError } from '@errors/ForbiddenError.mjs'
55
import { ENV } from '@env'
66

7-
const corsPlugin: FastifyPluginAsync = async (fastify) => {
8-
const corsWhitelist: RegExp[] = [
7+
export const getWhiteList = (): RegExp[] => {
8+
const whiteList: RegExp[] = [
99
/^https:\/\/velog.io$/,
1010
/^https:\/\/(.*).velog.io$/,
1111
/^https:\/\/(.*\.velog\.io)$/,
@@ -14,13 +14,19 @@ const corsPlugin: FastifyPluginAsync = async (fastify) => {
1414
]
1515

1616
if (ENV.appEnv === 'development') {
17-
corsWhitelist.push(/^http:\/\/localhost/)
17+
whiteList.push(/^http:\/\/localhost/)
1818
}
1919

20+
return whiteList
21+
}
22+
23+
const corsPlugin: FastifyPluginAsync = async (fastify) => {
24+
const corsWhiteList = getWhiteList()
25+
2026
await fastify.register(cors, {
2127
credentials: true,
2228
origin: (origin, callback) => {
23-
if (!origin || corsWhitelist.some((re) => re.test(origin))) {
29+
if (!origin || corsWhiteList.some((re) => re.test(origin))) {
2430
callback(null, true)
2531
} else {
2632
callback(new ForbiddenError('Not allow origin'), false)

apps/book-server/src/common/plugins/global/mercuriusPlugin.mts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { MqService } from '@lib/mq/MqService.mjs'
99
import { GraphQLContextBase } from '@interfaces/graphql.mjs'
1010
import { ENV } from '@env'
1111
import { schemaTransforms } from '@graphql/transformer/index.mjs'
12+
import { getWhiteList } from './corsPlugin.mjs'
1213

1314
const mercuriusPlugin: FastifyPluginAsync = async (fastify) => {
1415
const mqService = container.resolve(MqService)
@@ -21,12 +22,11 @@ const mercuriusPlugin: FastifyPluginAsync = async (fastify) => {
2122
subscription: {
2223
emitter: mqService.emitter,
2324
verifyClient: (info, next) => {
24-
// if (info.req.headers['x-fastify-header'] !== 'fastify is awesome !') {
25-
// return next(false) // the connection is not allowed
26-
// }
27-
28-
next(false)
29-
// next(true) // the connection is allowed
25+
const whiteList = getWhiteList()
26+
if (info.origin && !whiteList.some((re) => re.test(info.origin))) {
27+
return next(false)
28+
}
29+
next(true) // the connection is allowed
3030
},
3131
},
3232
context: (request, reply): GraphQLContextBase => {

apps/book-server/src/graphql/Book.gql

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type Mutation {
1919
type Subscription {
2020
buildInstalled(input: BookUrlSlugInput!): SubScriptionPayload @auth
2121
buildCompleted(input: BookUrlSlugInput!): SubScriptionPayload @auth
22-
deployCompleted(input: BookUrlSlugInput!): SubScriptionPayload @auth
22+
deployCompleted(input: BookUrlSlugInput!): DeployCompletedPayload
2323
}
2424

2525
input BookIdInput {
@@ -34,14 +34,19 @@ type SubScriptionPayload {
3434
message: String!
3535
}
3636

37+
type DeployCompletedPayload {
38+
message: String!
39+
published_url: String!
40+
}
41+
3742
type BuildResult {
3843
result: Boolean!
3944
message: String
4045
}
4146

4247
type DeployResult {
48+
message: String!
4349
published_url: String
44-
message: String
4550
}
4651

4752
input IsDeployInput {

apps/book-server/src/graphql/generated.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ export type DeletePageInput = {
6565
page_url_slug: Scalars['String']['input']
6666
}
6767

68+
export type DeployCompletedPayload = {
69+
message: Scalars['String']['output']
70+
published_url: Scalars['String']['output']
71+
}
72+
6873
export type DeployResult = {
6974
message?: Maybe<Scalars['String']['output']>
7075
published_url?: Maybe<Scalars['String']['output']>
@@ -173,7 +178,7 @@ export type SubScriptionPayload = {
173178
export type Subscription = {
174179
buildCompleted?: Maybe<SubScriptionPayload>
175180
buildInstalled?: Maybe<SubScriptionPayload>
176-
deployCompleted?: Maybe<SubScriptionPayload>
181+
deployCompleted?: Maybe<DeployCompletedPayload>
177182
}
178183

179184
export type SubscriptionBuildCompletedArgs = {
@@ -296,6 +301,7 @@ export type ResolversTypes = {
296301
CreatePageInput: CreatePageInput
297302
Date: ResolverTypeWrapper<Scalars['Date']['output']>
298303
DeletePageInput: DeletePageInput
304+
DeployCompletedPayload: ResolverTypeWrapper<DeployCompletedPayload>
299305
DeployResult: ResolverTypeWrapper<DeployResult>
300306
GetPageInput: GetPageInput
301307
GetPagesInput: GetPagesInput
@@ -327,6 +333,7 @@ export type ResolversParentTypes = {
327333
CreatePageInput: CreatePageInput
328334
Date: Scalars['Date']['output']
329335
DeletePageInput: DeletePageInput
336+
DeployCompletedPayload: DeployCompletedPayload
330337
DeployResult: DeployResult
331338
GetPageInput: GetPageInput
332339
GetPagesInput: GetPagesInput
@@ -381,6 +388,16 @@ export interface DateScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes
381388
name: 'Date'
382389
}
383390

391+
export type DeployCompletedPayloadResolvers<
392+
ContextType = GraphQLContext,
393+
ParentType extends
394+
ResolversParentTypes['DeployCompletedPayload'] = ResolversParentTypes['DeployCompletedPayload'],
395+
> = {
396+
message?: Resolver<ResolversTypes['String'], ParentType, ContextType>
397+
published_url?: Resolver<ResolversTypes['String'], ParentType, ContextType>
398+
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>
399+
}
400+
384401
export type DeployResultResolvers<
385402
ContextType = GraphQLContext,
386403
ParentType extends ResolversParentTypes['DeployResult'] = ResolversParentTypes['DeployResult'],
@@ -521,7 +538,7 @@ export type SubscriptionResolvers<
521538
RequireFields<SubscriptionBuildInstalledArgs, 'input'>
522539
>
523540
deployCompleted?: SubscriptionResolver<
524-
Maybe<ResolversTypes['SubScriptionPayload']>,
541+
Maybe<ResolversTypes['DeployCompletedPayload']>,
525542
'deployCompleted',
526543
ParentType,
527544
ContextType,
@@ -549,6 +566,7 @@ export type Resolvers<ContextType = GraphQLContext> = {
549566
Book?: BookResolvers<ContextType>
550567
BuildResult?: BuildResultResolvers<ContextType>
551568
Date?: GraphQLScalarType
569+
DeployCompletedPayload?: DeployCompletedPayloadResolvers<ContextType>
552570
DeployResult?: DeployResultResolvers<ContextType>
553571
JSON?: GraphQLScalarType
554572
Mutation?: MutationResolvers<ContextType>

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ export class MqService {
3232

3333
public topicGenerator<T extends SubscriptionResolverKey>(type: T): (args: any) => string {
3434
const map: TopicMap = {
35-
buildCompleted: (bookId: string) => `BOOK_BUILD:completed:${bookId}`,
36-
buildInstalled: (bookId: string) => `BOOK_BUILD:installed:${bookId}`,
37-
deployCompleted: (bookId: string) => `BOOK_DEPLOY:completed:${bookId}`,
35+
buildCompleted: (bookUrlSlug: string) => `BOOK_BUILD:completed:${bookUrlSlug}`,
36+
buildInstalled: (bookUrlSlug: string) => `BOOK_BUILD:installed:${bookUrlSlug}`,
37+
deployCompleted: (bookUrlSlug: string) => `BOOK_DEPLOY:completed:${bookUrlSlug}`,
3838
}
3939
const generator = map[type]
4040
if (!generator) {
@@ -53,7 +53,7 @@ export class MqService {
5353

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

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export class BookBuildService implements Service {
9898
const stdout = await this.installDependencies('npm install', dest)
9999
if (stdout) {
100100
this.mq.publish({
101-
topicParameter: book.id,
101+
topicParameter: book.url_slug,
102102
payload: {
103103
buildInstalled: {
104104
message: stdout,
@@ -137,7 +137,7 @@ export class BookBuildService implements Service {
137137
const buildStdout = await this.buildTsToJs(dest)
138138
if (buildStdout) {
139139
this.mq.publish({
140-
topicParameter: book.id,
140+
topicParameter: book.url_slug,
141141
payload: {
142142
buildCompleted: { message: buildStdout },
143143
},

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ export class BookDeployService implements Service {
115115
})
116116
})
117117

118+
console.log('published_urlpublished_url', published_url)
118119
this.mq.publish({
119-
topicParameter: book.id,
120+
topicParameter: book.url_slug,
120121
payload: {
121122
deployCompleted: {
122123
message: 'Deploy completed',

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ query isDeploy($input: IsDeployInput!) {
1414
isDeploy(input: $input)
1515
}
1616

17-
subscription DeployCompleted($input: BookUrlSlugInput!) {
17+
subscription deployCompleted($input: BookUrlSlugInput!) {
1818
deployCompleted(input: $input) {
1919
message
20+
published_url
2021
}
2122
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ export type DeletePageInput = {
6565
page_url_slug: Scalars['String']['input']
6666
}
6767

68+
export type DeployCompletedPayload = {
69+
message: Scalars['String']['output']
70+
published_url: Scalars['String']['output']
71+
}
72+
6873
export type DeployResult = {
6974
message: Maybe<Scalars['String']['output']>
7075
published_url: Maybe<Scalars['String']['output']>
@@ -173,7 +178,7 @@ export type SubScriptionPayload = {
173178
export type Subscription = {
174179
buildCompleted: Maybe<SubScriptionPayload>
175180
buildInstalled: Maybe<SubScriptionPayload>
176-
deployCompleted: Maybe<SubScriptionPayload>
181+
deployCompleted: Maybe<DeployCompletedPayload>
177182
}
178183

179184
export type SubscriptionBuildCompletedArgs = {
@@ -226,7 +231,9 @@ export type DeployCompletedSubscriptionVariables = Exact<{
226231
input: BookUrlSlugInput
227232
}>
228233

229-
export type DeployCompletedSubscription = { deployCompleted: { message: string } | null }
234+
export type DeployCompletedSubscription = {
235+
deployCompleted: { message: string; published_url: string } | null
236+
}
230237

231238
export type GetPagesQueryVariables = Exact<{
232239
input: GetPagesInput
@@ -392,9 +399,10 @@ useIsDeployQuery.fetcher = (variables: IsDeployQueryVariables, options?: Request
392399
fetcher<IsDeployQuery, IsDeployQueryVariables>(IsDeployDocument, variables, options)
393400

394401
export const DeployCompletedDocument = `
395-
subscription DeployCompleted($input: BookUrlSlugInput!) {
402+
subscription deployCompleted($input: BookUrlSlugInput!) {
396403
deployCompleted(input: $input) {
397404
message
405+
published_url
398406
}
399407
}
400408
`

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useEffect, useState } from 'react'
88
import { BookMetadata, generateBookMetadata, Pages } from '@/lib/generateBookMetadata'
99
import {
1010
DeployCompletedDocument,
11+
DeployCompletedPayload,
1112
useBuildMutation,
1213
useCreatePageMutation,
1314
useDeletePageMutation,
@@ -56,13 +57,23 @@ function MarkdownEditorLayout({ children, mdxText }: Props) {
5657
},
5758
})
5859

59-
const deployCompleted = useSubscription({
60+
const [deployCompleted] = useSubscription<DeployCompletedPayload>({
6061
query: DeployCompletedDocument,
6162
variables: { input: { book_url_slug: bookUrlSlug } },
6263
})
6364

65+
// 재접속시에 deploy 결과 확인
6466
useEffect(() => {
67+
if (!deployCompleted.data) return
6568
console.log(deployCompleted)
69+
const { message, published_url } = deployCompleted.data
70+
if (published_url) {
71+
console.log('published_url in client', published_url)
72+
const event = new CustomEvent(markdownCustomEventName.deployEndEvent, {
73+
detail: { publishedUrl: published_url },
74+
})
75+
window.dispatchEvent(event)
76+
}
6677
}, [deployCompleted])
6778

6879
const { data: isDeployData } = useIsDeployQuery({

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@ const wsClient = createWSClient({
1010
url: `ws://${ENV.graphqlBookServerHost.replace(/^http(s)?:\/\//, '')}/graphql`,
1111
})
1212

13-
export const urqlClient = createClient({
13+
const urqlClient = createClient({
1414
url: `${ENV.graphqlBookServerHost}/graphql`,
1515
exchanges: [
1616
cacheExchange,
1717
fetchExchange,
1818
subscriptionExchange({
19-
forwardSubscription: (operation) => ({
20-
subscribe: (sink) => ({
21-
unsubscribe: wsClient.subscribe(operation as SubscribePayload, sink),
22-
}),
19+
forwardSubscription: (request) => ({
20+
subscribe: (sink) => {
21+
const input = { ...request, query: request.query || '' }
22+
return {
23+
unsubscribe: wsClient.subscribe(input, sink),
24+
}
25+
},
2326
}),
2427
}),
2528
],
@@ -29,4 +32,4 @@ function UrqlProvider({ children }: Props) {
2932
return <Provider value={urqlClient}>{children}</Provider>
3033
}
3134

32-
export default UrqlProvider
35+
export default UrqlProvider

pnpm-lock.yaml

Lines changed: 3 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)