Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit 498ce3f

Browse files
author
Noah Hanjun Lee
authored
feat: change the interface of event stream (#107)
* Change the interface of the event stream * Fix handling events with renewed interface
1 parent 3b499a2 commit 498ce3f

File tree

16 files changed

+238
-110
lines changed

16 files changed

+238
-110
lines changed

internal/server/api/v1/stream/stream.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,9 @@ L:
8585
})
8686
w.Flush()
8787
case e := <-events:
88-
var data interface{}
89-
if e.Kind == event.KindDeployment {
90-
data = e.Edges.Deployment
91-
} else if e.Kind == event.KindApproval {
92-
data = e.Edges.Approval
93-
}
94-
9588
c.Render(-1, sse.Event{
96-
Event: e.Kind.String(),
97-
Data: data,
89+
Event: "event",
90+
Data: e,
9891
})
9992
w.Flush()
10093
s.log.Debug("server sent event.", zap.Int("event_id", e.ID), zap.String("debug_id", debugID))

internal/server/slack/notification.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (s *Slack) notifyApprovalEvent(ctx context.Context, e *ent.Event) {
8888
return
8989
}
9090

91-
d := e.Edges.Deployment
91+
d := a.Edges.Deployment
9292
if err := d.CheckEagerLoading(); err != nil {
9393
s.log.Error("The eager loading of deployment has failed.")
9494
return

openapi.yml

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,6 @@ servers:
66
- url: http://localhost/api/v1
77
- url: https://gitploy.jp.ngrok.io/api/v1
88
paths:
9-
/sync:
10-
post:
11-
tags:
12-
- Sync
13-
summary: Synchronize with SCM.
14-
responses:
15-
'200':
16-
description: OK
17-
'401':
18-
$ref: '#/components/responses/401Unauthorized'
19-
'402':
20-
$ref: '#/components/responses/402PaymentRequired'
21-
'500':
22-
$ref: '#/components/responses/500InternalError'
239
/license:
2410
get:
2511
tags:
@@ -1244,6 +1230,77 @@ paths:
12441230
$ref: '#/components/responses/402PaymentRequired'
12451231
'500':
12461232
$ref: '#/components/responses/500InternalError'
1233+
/stream/events:
1234+
get:
1235+
tags:
1236+
- Event
1237+
summary: Subscribes streaming event
1238+
responses:
1239+
'200':
1240+
description: Returns events for deployments and approvals
1241+
content:
1242+
text/event-stream:
1243+
schema:
1244+
type: array
1245+
format: chunked
1246+
items:
1247+
type: object
1248+
format: text
1249+
required:
1250+
- id
1251+
- event
1252+
- data
1253+
properties:
1254+
id:
1255+
type: integer
1256+
event:
1257+
type: string
1258+
data:
1259+
type: object
1260+
format: json
1261+
required:
1262+
- id
1263+
- kind
1264+
- type
1265+
- created_at
1266+
- edges
1267+
properties:
1268+
id:
1269+
type: integer
1270+
kind:
1271+
type: string
1272+
enum:
1273+
- deployment
1274+
- approval
1275+
type:
1276+
type: string
1277+
enum:
1278+
- created
1279+
- updated
1280+
- removed
1281+
created_at:
1282+
type: string
1283+
edges:
1284+
type: object
1285+
properties:
1286+
deployment:
1287+
$ref: '#/components/schemas/Deployment'
1288+
approval:
1289+
$ref: '#/components/schemas/Approval'
1290+
/sync:
1291+
post:
1292+
tags:
1293+
- Sync
1294+
summary: Synchronize with SCM.
1295+
responses:
1296+
'200':
1297+
description: OK
1298+
'401':
1299+
$ref: '#/components/responses/401Unauthorized'
1300+
'402':
1301+
$ref: '#/components/responses/402PaymentRequired'
1302+
'500':
1303+
$ref: '#/components/responses/500InternalError'
12471304
security:
12481305
- BearerAuth: []
12491306
- OAuth2:

ui/src/apis/approval.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
HttpUnprocessableEntityError
1515
} from '../models'
1616

17-
interface ApprovalData {
17+
export interface ApprovalData {
1818
id: number,
1919
status: string
2020
created_at: string

ui/src/apis/events.ts

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,79 @@
11
import { instance } from './setting'
22

3-
import { mapDataToDeployment } from "./deployment"
4-
import { mapDataToApproval } from "./approval"
5-
import { Deployment, Approval } from "../models"
3+
import { DeploymentData, mapDataToDeployment } from "./deployment"
4+
import { ApprovalData, mapDataToApproval } from "./approval"
5+
import { Deployment, Approval, Event, EventKindEnum, EventTypeEnum } from "../models"
66

7-
export const subscribeDeploymentEvent = (cb: (e: Deployment) => void): EventSource => {
8-
const eventName = "deployment"
7+
interface EventData {
8+
id: number
9+
kind: string
10+
type: string
11+
deleted_entity_id: number
12+
edges: {
13+
deployment?: DeploymentData
14+
approval?: ApprovalData
15+
}
16+
}
917

10-
const sse = new EventSource(`${instance}/api/v1/stream/events`, {
11-
withCredentials: true,
12-
})
18+
const mapDataToEvent = (data: EventData): Event => {
19+
let kind: EventKindEnum
20+
let type: EventTypeEnum
21+
let deployment: Deployment | undefined
22+
let approval: Approval | undefined
1323

14-
sse.addEventListener(eventName, (e: any) => {
15-
const data = JSON.parse(e.data)
16-
cb(mapDataToDeployment(data))
17-
})
24+
switch (data.kind) {
25+
case "deployment":
26+
kind = EventKindEnum.Deployment
27+
break
28+
case "approval":
29+
kind = EventKindEnum.Approval
30+
break
31+
default:
32+
kind = EventKindEnum.Deployment
33+
}
1834

19-
return sse
20-
}
35+
switch (data.type) {
36+
case "created":
37+
type = EventTypeEnum.Created
38+
break
39+
case "updated":
40+
type = EventTypeEnum.Updated
41+
break
42+
case "deleted":
43+
type = EventTypeEnum.Deleted
44+
break
45+
default:
46+
type = EventTypeEnum.Created
47+
}
48+
49+
if (data.edges.deployment) {
50+
deployment = mapDataToDeployment(data.edges.deployment)
51+
}
2152

22-
export const subscribeApprovalEvent = (cb: (e: Approval) => void): EventSource => {
23-
const eventName = "approval"
53+
if (data.edges.approval) {
54+
approval = mapDataToApproval(data.edges.approval)
55+
}
2456

57+
return {
58+
id: data.id,
59+
kind,
60+
type,
61+
deletedEntityId: data.deleted_entity_id,
62+
deployment,
63+
approval
64+
}
65+
}
66+
67+
export const subscribeEvents = (cb: (event: Event) => void): EventSource => {
2568
const sse = new EventSource(`${instance}/api/v1/stream/events`, {
2669
withCredentials: true,
2770
})
2871

29-
sse.addEventListener(eventName, (e: any) => {
72+
sse.addEventListener("event", (e: any) => {
3073
const data = JSON.parse(e.data)
31-
cb(mapDataToApproval(data))
74+
const event = mapDataToEvent(data)
75+
76+
cb(event)
3277
})
3378

3479
return sse

ui/src/apis/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
setApprovalDeclined
3535
} from "./approval"
3636
import { getLicense } from "./license"
37-
import { subscribeDeploymentEvent, subscribeApprovalEvent } from "./events"
37+
import { subscribeEvents } from "./events"
3838

3939
export {
4040
sync,
@@ -75,6 +75,5 @@ export {
7575
setApprovalApproved,
7676
setApprovalDeclined,
7777
getLicense,
78-
subscribeDeploymentEvent,
79-
subscribeApprovalEvent
78+
subscribeEvents
8079
}

ui/src/models/Event.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Deployment from "./Deployment"
2+
import Approval from "./Approval"
3+
4+
export default interface Event {
5+
id: number
6+
kind: EventKindEnum
7+
type: EventTypeEnum
8+
deployment?: Deployment
9+
approval?: Approval
10+
deletedEntityId: number
11+
}
12+
13+
export enum EventKindEnum {
14+
Deployment = "deployment",
15+
Approval = "approval"
16+
}
17+
18+
export enum EventTypeEnum {
19+
Created = "created",
20+
Updated = "updated",
21+
Deleted = "deleted"
22+
}

ui/src/models/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Tag from "./Tag"
1212
import User, { ChatUser, RateLimit } from "./User"
1313
import Approval, { ApprovalStatus } from "./Approval"
1414
import License from "./License"
15+
import Event, {EventKindEnum, EventTypeEnum} from "./Event"
1516
import {
1617
HttpRequestError,
1718
HttpInternalServerError,
@@ -40,6 +41,7 @@ export type {
4041
RateLimit,
4142
Approval,
4243
License,
44+
Event
4345
}
4446

4547
export {
@@ -55,4 +57,6 @@ export {
5557
StatusState,
5658
RequestStatus,
5759
ApprovalStatus,
60+
EventKindEnum,
61+
EventTypeEnum
5862
}

ui/src/redux/deployment.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Deployment,
88
Commit,
99
Approval,
10+
Event,
1011
RequestStatus,
1112
HttpNotFoundError,
1213
HttpForbiddenError,
@@ -252,14 +253,14 @@ export const deploymentSlice = createSlice({
252253
setNumber: (state, action: PayloadAction<number>) => {
253254
state.number = action.payload
254255
},
255-
handleDeploymentEvent: (state, action: PayloadAction<Deployment>) => {
256+
handleDeploymentEvent: (state, action: PayloadAction<Event>) => {
256257
const event = action.payload
257258

258-
if (event.id !== state.deployment?.id) {
259+
if (event.deployment?.id !== state.deployment?.id) {
259260
return
260261
}
261262

262-
state.deployment = event
263+
state.deployment = event.deployment
263264
}
264265
},
265266
extraReducers: builder => {

ui/src/redux/home.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
22

3-
import { Repo, RequestStatus, Deployment } from '../models'
3+
import {
4+
Repo,
5+
RequestStatus,
6+
Event,
7+
EventTypeEnum
8+
} from '../models'
49
import * as apis from '../apis'
510

611
export const perPage = 30
@@ -68,26 +73,25 @@ export const homeSlice = createSlice({
6873
decreasePage: (state) => {
6974
state.page = state.page - 1
7075
},
71-
handleDeploymentEvent: (state, action: PayloadAction<Deployment>) => {
76+
handleDeploymentEvent: (state, action: PayloadAction<Event>) => {
7277
const event = action.payload
7378

7479
state.repos = state.repos.map((repo) => {
75-
if (event.repo?.id !== repo.id) {
80+
if (event.deployment?.repo?.id !== repo.id) {
7681
return repo
7782
}
7883

7984
if (!repo.deployments) {
8085
repo.deployments = []
8186
}
8287

83-
// Unshift a new deployment when the event is create.
84-
if (event.createdAt.getTime() === event.updatedAt.getTime()) {
85-
repo.deployments.unshift(event)
88+
if (event.type === EventTypeEnum.Created) {
89+
repo.deployments.unshift(event.deployment)
8690
return repo
8791
}
8892

8993
repo.deployments = repo.deployments.map((deployment) => {
90-
return (deployment.id === event.id)? event : deployment
94+
return (event.deployment?.id === deployment.id )? event.deployment : deployment
9195
})
9296
return repo
9397
})

0 commit comments

Comments
 (0)