This repository has been archived by the owner on Sep 7, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
api.ts
117 lines (110 loc) · 2.88 KB
/
api.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { ApolloClient, NormalizedCacheObject } from '@apollo/client'
import {
createChatTokenMutation,
ChatTokenMutationResult,
ChatTokenVariables,
} from '../../graphql/createChatTokenMutation'
import * as Twilio from 'twilio-chat'
import { Channel } from 'twilio-chat/lib/channel'
import { Either } from 'fp-ts/lib/Either'
import { tryCatch, chain } from 'fp-ts/lib/TaskEither'
import * as TE from 'fp-ts/lib/TaskEither'
import { pipe } from 'fp-ts/lib/pipeable'
import { Option, fromNullable } from 'fp-ts/lib/Option'
import { Paginator } from 'twilio-chat/lib/interfaces/paginator'
type ErrorInfo = {
type: string
message: string
}
const createChatToken = ({
apollo,
deviceId,
token,
}: {
deviceId: string
token: string
apollo: ApolloClient<NormalizedCacheObject>
}) =>
tryCatch<ErrorInfo, string>(
async () =>
apollo
.mutate<ChatTokenMutationResult, ChatTokenVariables>({
mutation: createChatTokenMutation,
variables: { deviceId, token },
})
.then(({ data }) => {
if (!data) {
throw new Error(
'Creating chat token failed! (No response returned.)',
)
}
return data.createChatToken
}),
reason => ({
type: 'IntegrationError',
message: `Creating chat token failed: ${(reason as Error).message}`,
}),
)
const createClient = (chatToken: string) =>
tryCatch<ErrorInfo, Twilio.Client>(
async () => Twilio.Client.create(chatToken),
reason => ({
type: 'IntegrationError',
message: `Creating chat client failed: ${(reason as Error).message}`,
}),
)
const fetchSubscribedChannels = (client: Twilio.Client) =>
tryCatch<ErrorInfo, Paginator<Channel>>(
async () => client.getSubscribedChannels(),
reason => ({
type: 'IntegrationError',
message: `Failed to fetch subscribed channels: ${
(reason as Error).message
}`,
}),
)
const joinChannel = ({
client,
channel,
}: {
client: Twilio.Client
channel: string
}) => () =>
tryCatch<ErrorInfo, Channel>(
async () =>
client.getChannelByUniqueName(channel).then(async c => c.join()),
reason => ({
type: 'IntegrationError',
message: `Failed to join channel "${channel}": ${
(reason as Error).message
}`,
}),
)
const maybeAlreadyJoinedChannel = (context: string) => (
channels: Paginator<Channel>,
): Option<Channel> =>
fromNullable(channels.items.find(({ uniqueName }) => uniqueName === context))
export const connectToChannel = async ({
apollo,
context,
deviceId,
token,
}: {
context: string
deviceId: string
token: string
apollo: ApolloClient<NormalizedCacheObject>
}): Promise<Either<ErrorInfo, Channel>> =>
pipe(
TE.right({ apollo, deviceId, token }),
chain(createChatToken),
chain(createClient),
chain(client =>
pipe(
fetchSubscribedChannels(client),
TE.map(maybeAlreadyJoinedChannel(context)),
TE.map(TE.fromOption<void>(() => undefined)),
chain(TE.orElse(joinChannel({ client, channel: context }))),
),
),
)()