@kshema/communications-client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +23 -0
- package/src/core/AcsSessionManager.ts +82 -0
- package/src/core/AcsSupport.ts +236 -0
- package/src/core/EventEmitter.ts +49 -0
- package/src/core/types.ts +44 -0
- package/src/hooks/useCall.ts +57 -0
- package/src/hooks/usePresence.ts +29 -0
- package/src/hooks/useSocket.ts +38 -0
- package/src/index.ts +19 -0
- package/src/native/NativeAcsBridge.ts +34 -0
- package/src/native/RemoteControlSession.ts +74 -0
- package/src/native/SupportCallSession.ts +80 -0
- package/src/screens/ActiveCallScreen.tsx +54 -0
- package/src/screens/CallHistoryScreen.tsx +41 -0
- package/src/screens/IncomingCallScreen.tsx +51 -0
- package/src/screens/ScreenShareScreen.tsx +28 -0
- package/src/services/CallingService.ts +68 -0
- package/src/services/NotificationService.ts +58 -0
- package/src/services/PresenceService.ts +58 -0
- package/src/services/RecordingService.ts +50 -0
- package/src/services/RemoteControlService.ts +64 -0
- package/src/services/TokenService.ts +47 -0
- package/src/sockets/socket.ts +31 -0
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kshema/communications-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@azure/communication-common": "^2.5.0",
|
|
8
|
+
"@react-native-async-storage/async-storage": "^3.1.1",
|
|
9
|
+
"axios": "^1.20.0",
|
|
10
|
+
"react-native-permissions": "^5.6.2",
|
|
11
|
+
"react-native-webrtc": "^124.0.8",
|
|
12
|
+
"socket.io-client": "^4.8.3"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"react": ">=18.0.0",
|
|
16
|
+
"react-native": ">=0.76.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/react": "^19.3.0",
|
|
20
|
+
"@types/react-native": "^0.72.8",
|
|
21
|
+
"typescript": "^5.9.2"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import AsyncStorage from
|
|
2
|
+
"@react-native-async-storage/async-storage";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AcsEvents,
|
|
6
|
+
SessionData,
|
|
7
|
+
} from "./types";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
eventEmitter,
|
|
11
|
+
} from "./EventEmitter";
|
|
12
|
+
|
|
13
|
+
const STORAGE_KEY =
|
|
14
|
+
"@acs_session";
|
|
15
|
+
|
|
16
|
+
class AcsSessionManager {
|
|
17
|
+
|
|
18
|
+
async save(
|
|
19
|
+
session: SessionData
|
|
20
|
+
) {
|
|
21
|
+
|
|
22
|
+
await AsyncStorage.setItem(
|
|
23
|
+
STORAGE_KEY,
|
|
24
|
+
JSON.stringify(session)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
eventEmitter.emit(
|
|
28
|
+
AcsEvents.SESSION_CREATED,
|
|
29
|
+
session
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async get() {
|
|
34
|
+
|
|
35
|
+
const value =
|
|
36
|
+
await AsyncStorage.getItem(
|
|
37
|
+
STORAGE_KEY
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (!value) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return JSON.parse(
|
|
45
|
+
value
|
|
46
|
+
) as SessionData;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async clear() {
|
|
50
|
+
|
|
51
|
+
await AsyncStorage.removeItem(
|
|
52
|
+
STORAGE_KEY
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
eventEmitter.emit(
|
|
56
|
+
AcsEvents.SESSION_CLEARED
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async isExpired() {
|
|
61
|
+
|
|
62
|
+
const session =
|
|
63
|
+
await this.get();
|
|
64
|
+
|
|
65
|
+
if (!session) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const now =
|
|
70
|
+
new Date().getTime();
|
|
71
|
+
|
|
72
|
+
const expiry =
|
|
73
|
+
new Date(
|
|
74
|
+
session.expiresOn
|
|
75
|
+
).getTime();
|
|
76
|
+
|
|
77
|
+
return now >= expiry;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const sessionManager =
|
|
82
|
+
new AcsSessionManager();
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AcsConfig,
|
|
3
|
+
AcsEvents,
|
|
4
|
+
} from "./types";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
sessionManager,
|
|
8
|
+
} from "./AcsSessionManager";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
eventEmitter,
|
|
12
|
+
} from "./EventEmitter";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
TokenService,
|
|
16
|
+
} from "../services/TokenService";
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
PresenceService,
|
|
20
|
+
} from "../services/PresenceService";
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
CallingService,
|
|
24
|
+
} from "../services/CallingService";
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
NotificationService,
|
|
28
|
+
} from "../services/NotificationService";
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
RecordingService,
|
|
32
|
+
} from "../services/RecordingService";
|
|
33
|
+
|
|
34
|
+
import {
|
|
35
|
+
RemoteControlService,
|
|
36
|
+
} from "../services/RemoteControlService";
|
|
37
|
+
|
|
38
|
+
import {
|
|
39
|
+
socketManager,
|
|
40
|
+
} from "../sockets/socket";
|
|
41
|
+
|
|
42
|
+
export class AcsSupport {
|
|
43
|
+
|
|
44
|
+
private tokenService: TokenService;
|
|
45
|
+
|
|
46
|
+
public presence!: PresenceService;
|
|
47
|
+
|
|
48
|
+
public calling!: CallingService;
|
|
49
|
+
|
|
50
|
+
public notifications!: NotificationService;
|
|
51
|
+
|
|
52
|
+
public recordings!: RecordingService;
|
|
53
|
+
|
|
54
|
+
public remoteControl!: RemoteControlService;
|
|
55
|
+
|
|
56
|
+
constructor(
|
|
57
|
+
private config: AcsConfig
|
|
58
|
+
) {
|
|
59
|
+
this.tokenService =
|
|
60
|
+
new TokenService(config);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async initialize() {
|
|
64
|
+
|
|
65
|
+
let session =
|
|
66
|
+
await sessionManager.get();
|
|
67
|
+
|
|
68
|
+
if (!session) {
|
|
69
|
+
|
|
70
|
+
const token =
|
|
71
|
+
await this.tokenService
|
|
72
|
+
.generateToken();
|
|
73
|
+
|
|
74
|
+
session = {
|
|
75
|
+
acsUserId:
|
|
76
|
+
token.acsUserId,
|
|
77
|
+
|
|
78
|
+
acsToken:
|
|
79
|
+
token.token,
|
|
80
|
+
|
|
81
|
+
expiresOn:
|
|
82
|
+
token.expiresOn,
|
|
83
|
+
|
|
84
|
+
userId:
|
|
85
|
+
token.userId,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
await sessionManager.save(
|
|
89
|
+
session
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
eventEmitter.emit(
|
|
93
|
+
AcsEvents.SESSION_CREATED,
|
|
94
|
+
session
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const expired =
|
|
99
|
+
await sessionManager.isExpired();
|
|
100
|
+
|
|
101
|
+
if (expired) {
|
|
102
|
+
|
|
103
|
+
eventEmitter.emit(
|
|
104
|
+
AcsEvents.SESSION_EXPIRED
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const token =
|
|
108
|
+
await this.tokenService
|
|
109
|
+
.generateToken();
|
|
110
|
+
|
|
111
|
+
session = {
|
|
112
|
+
acsUserId:
|
|
113
|
+
token.acsUserId,
|
|
114
|
+
|
|
115
|
+
acsToken:
|
|
116
|
+
token.token,
|
|
117
|
+
|
|
118
|
+
expiresOn:
|
|
119
|
+
token.expiresOn,
|
|
120
|
+
|
|
121
|
+
userId:
|
|
122
|
+
token.userId,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
await sessionManager.save(
|
|
126
|
+
session
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
eventEmitter.emit(
|
|
130
|
+
AcsEvents.TOKEN_REFRESHED,
|
|
131
|
+
session
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Initialize Services
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
this.presence =
|
|
140
|
+
new PresenceService(
|
|
141
|
+
this.config.apiBaseUrl,
|
|
142
|
+
this.config.jwtToken
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
this.calling =
|
|
146
|
+
new CallingService(
|
|
147
|
+
this.config.apiBaseUrl,
|
|
148
|
+
this.config.jwtToken
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
this.notifications =
|
|
152
|
+
new NotificationService();
|
|
153
|
+
|
|
154
|
+
this.recordings =
|
|
155
|
+
new RecordingService(
|
|
156
|
+
this.config.apiBaseUrl,
|
|
157
|
+
this.config.jwtToken
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
this.remoteControl =
|
|
161
|
+
new RemoteControlService();
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Connect Socket.IO
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
if (this.config.socketUrl) {
|
|
168
|
+
|
|
169
|
+
socketManager.connect(
|
|
170
|
+
this.config.socketUrl,
|
|
171
|
+
this.config.jwtToken
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Start Heartbeat
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
this.startHeartbeat();
|
|
180
|
+
|
|
181
|
+
return session;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private startHeartbeat() {
|
|
185
|
+
|
|
186
|
+
setInterval(async () => {
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
|
|
190
|
+
await this.presence.heartbeat();
|
|
191
|
+
|
|
192
|
+
} catch (error) {
|
|
193
|
+
|
|
194
|
+
console.error(
|
|
195
|
+
"Presence heartbeat failed",
|
|
196
|
+
error
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
}, 30000);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async getSession() {
|
|
204
|
+
|
|
205
|
+
return sessionManager.get();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async logout() {
|
|
209
|
+
|
|
210
|
+
socketManager.disconnect();
|
|
211
|
+
|
|
212
|
+
await sessionManager.clear();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
on(
|
|
216
|
+
event: string,
|
|
217
|
+
callback: (...args: any[]) => void
|
|
218
|
+
) {
|
|
219
|
+
|
|
220
|
+
eventEmitter.on(
|
|
221
|
+
event,
|
|
222
|
+
callback
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
off(
|
|
227
|
+
event: string,
|
|
228
|
+
callback: (...args: any[]) => void
|
|
229
|
+
) {
|
|
230
|
+
|
|
231
|
+
eventEmitter.off(
|
|
232
|
+
event,
|
|
233
|
+
callback
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type EventCallback = (
|
|
2
|
+
payload?: any
|
|
3
|
+
) => void;
|
|
4
|
+
|
|
5
|
+
class EventEmitter {
|
|
6
|
+
private listeners:
|
|
7
|
+
Record<string, EventCallback[]> = {};
|
|
8
|
+
|
|
9
|
+
on(
|
|
10
|
+
event: string,
|
|
11
|
+
callback: EventCallback
|
|
12
|
+
) {
|
|
13
|
+
if (!this.listeners[event]) {
|
|
14
|
+
this.listeners[event] = [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
this.listeners[event].push(
|
|
18
|
+
callback
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
emit(
|
|
23
|
+
event: string,
|
|
24
|
+
payload?: any
|
|
25
|
+
) {
|
|
26
|
+
const callbacks =
|
|
27
|
+
this.listeners[event] || [];
|
|
28
|
+
|
|
29
|
+
callbacks.forEach(cb =>
|
|
30
|
+
cb(payload)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
off(
|
|
35
|
+
event: string,
|
|
36
|
+
callback: EventCallback
|
|
37
|
+
) {
|
|
38
|
+
const callbacks =
|
|
39
|
+
this.listeners[event] || [];
|
|
40
|
+
|
|
41
|
+
this.listeners[event] =
|
|
42
|
+
callbacks.filter(
|
|
43
|
+
listener => listener !== callback
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const eventEmitter =
|
|
49
|
+
new EventEmitter();
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface AcsTokenResponse {
|
|
2
|
+
source: "new" | "cached" | "refreshed";
|
|
3
|
+
|
|
4
|
+
userId: string;
|
|
5
|
+
|
|
6
|
+
username?: string;
|
|
7
|
+
|
|
8
|
+
displayName?: string;
|
|
9
|
+
|
|
10
|
+
acsUserId: string;
|
|
11
|
+
|
|
12
|
+
token: string;
|
|
13
|
+
|
|
14
|
+
expiresOn: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface AcsConfig {
|
|
18
|
+
|
|
19
|
+
apiBaseUrl: string;
|
|
20
|
+
|
|
21
|
+
jwtToken: string;
|
|
22
|
+
|
|
23
|
+
socketUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface SessionData {
|
|
27
|
+
acsUserId: string;
|
|
28
|
+
|
|
29
|
+
acsToken: string;
|
|
30
|
+
|
|
31
|
+
expiresOn: string;
|
|
32
|
+
|
|
33
|
+
userId: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export enum AcsEvents {
|
|
37
|
+
TOKEN_REFRESHED = "TOKEN_REFRESHED",
|
|
38
|
+
|
|
39
|
+
SESSION_CREATED = "SESSION_CREATED",
|
|
40
|
+
|
|
41
|
+
SESSION_EXPIRED = "SESSION_EXPIRED",
|
|
42
|
+
|
|
43
|
+
SESSION_CLEARED = "SESSION_CLEARED",
|
|
44
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
export const useCall = (
|
|
4
|
+
support: any
|
|
5
|
+
) => {
|
|
6
|
+
|
|
7
|
+
const [call,
|
|
8
|
+
setCall] =
|
|
9
|
+
useState<any>(null);
|
|
10
|
+
|
|
11
|
+
const createCall =
|
|
12
|
+
async () => {
|
|
13
|
+
|
|
14
|
+
const response =
|
|
15
|
+
await support
|
|
16
|
+
.calling
|
|
17
|
+
.createCall();
|
|
18
|
+
|
|
19
|
+
setCall(
|
|
20
|
+
response.data.call
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
return response;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const acceptCall =
|
|
27
|
+
async (callId: string) => {
|
|
28
|
+
|
|
29
|
+
return support
|
|
30
|
+
.calling
|
|
31
|
+
.acceptCall(callId);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const rejectCall =
|
|
35
|
+
async (callId: string) => {
|
|
36
|
+
|
|
37
|
+
return support
|
|
38
|
+
.calling
|
|
39
|
+
.rejectCall(callId);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const endCall =
|
|
43
|
+
async (callId: string) => {
|
|
44
|
+
|
|
45
|
+
return support
|
|
46
|
+
.calling
|
|
47
|
+
.endCall(callId);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
call,
|
|
52
|
+
createCall,
|
|
53
|
+
acceptCall,
|
|
54
|
+
rejectCall,
|
|
55
|
+
endCall,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
export const usePresence = (
|
|
4
|
+
support: any
|
|
5
|
+
) => {
|
|
6
|
+
const [agents, setAgents] =
|
|
7
|
+
useState([]);
|
|
8
|
+
|
|
9
|
+
const loadAgents =
|
|
10
|
+
async () => {
|
|
11
|
+
const response =
|
|
12
|
+
await support
|
|
13
|
+
.presence
|
|
14
|
+
.getAvailableAgents();
|
|
15
|
+
|
|
16
|
+
setAgents(
|
|
17
|
+
response.data || []
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
loadAgents();
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
agents,
|
|
27
|
+
refresh: loadAgents,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
export const useSocket = (
|
|
4
|
+
support: any,
|
|
5
|
+
handlers: {
|
|
6
|
+
onIncomingCall?: (
|
|
7
|
+
call: any
|
|
8
|
+
) => void;
|
|
9
|
+
|
|
10
|
+
onCallAccepted?: (
|
|
11
|
+
call: any
|
|
12
|
+
) => void;
|
|
13
|
+
|
|
14
|
+
onCallEnded?: (
|
|
15
|
+
call: any
|
|
16
|
+
) => void;
|
|
17
|
+
}
|
|
18
|
+
) => {
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
|
|
22
|
+
support.notifications
|
|
23
|
+
.listenIncomingCall(
|
|
24
|
+
handlers.onIncomingCall
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
support.notifications
|
|
28
|
+
.listenCallAccepted(
|
|
29
|
+
handlers.onCallAccepted
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
support.notifications
|
|
33
|
+
.listenCallEnded(
|
|
34
|
+
handlers.onCallEnded
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
}, []);
|
|
38
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from "./core/AcsSupport";
|
|
2
|
+
export * from "./core/AcsSessionManager";
|
|
3
|
+
export * from "./core/EventEmitter";
|
|
4
|
+
export * from "./core/types";
|
|
5
|
+
|
|
6
|
+
export * from "./services/PresenceService";
|
|
7
|
+
export * from "./services/CallingService";
|
|
8
|
+
export * from "./services/NotificationService";
|
|
9
|
+
export * from "./services/RecordingService";
|
|
10
|
+
export * from "./services/RemoteControlService";
|
|
11
|
+
|
|
12
|
+
export * from "./hooks/useCall";
|
|
13
|
+
export * from "./hooks/usePresence";
|
|
14
|
+
export * from "./hooks/useSocket";
|
|
15
|
+
|
|
16
|
+
export * from "./screens/IncomingCallScreen";
|
|
17
|
+
export * from "./screens/ActiveCallScreen";
|
|
18
|
+
export * from "./screens/ScreenShareScreen";
|
|
19
|
+
export * from "./screens/CallHistoryScreen";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NativeModules } from "react-native";
|
|
2
|
+
|
|
3
|
+
export interface NativeAcsModule {
|
|
4
|
+
initialize(token: string): Promise<void>;
|
|
5
|
+
|
|
6
|
+
joinCall(groupId: string): Promise<void>;
|
|
7
|
+
|
|
8
|
+
leaveCall(): Promise<void>;
|
|
9
|
+
|
|
10
|
+
mute(): Promise<void>;
|
|
11
|
+
|
|
12
|
+
unmute(): Promise<void>;
|
|
13
|
+
|
|
14
|
+
startVideo(): Promise<void>;
|
|
15
|
+
|
|
16
|
+
stopVideo(): Promise<void>;
|
|
17
|
+
|
|
18
|
+
startScreenShare(): Promise<void>;
|
|
19
|
+
|
|
20
|
+
stopScreenShare(): Promise<void>;
|
|
21
|
+
|
|
22
|
+
startRecording(): Promise<void>;
|
|
23
|
+
|
|
24
|
+
stopRecording(): Promise<void>;
|
|
25
|
+
|
|
26
|
+
requestRemoteControl(): Promise<void>;
|
|
27
|
+
|
|
28
|
+
approveRemoteControl(): Promise<void>;
|
|
29
|
+
|
|
30
|
+
denyRemoteControl(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const NativeAcsBridge =
|
|
34
|
+
NativeModules.KshemaAcsSupport as NativeAcsModule;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NativeAcsBridge }
|
|
2
|
+
from "./NativeAcsBridge";
|
|
3
|
+
|
|
4
|
+
export class RemoteControlSession {
|
|
5
|
+
|
|
6
|
+
async requestControl() {
|
|
7
|
+
|
|
8
|
+
await NativeAcsBridge.requestRemoteControl();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async approveControl() {
|
|
12
|
+
|
|
13
|
+
await NativeAcsBridge.approveRemoteControl();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async denyControl() {
|
|
17
|
+
|
|
18
|
+
await NativeAcsBridge.denyRemoteControl();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pointerMove(
|
|
22
|
+
x: number,
|
|
23
|
+
y: number
|
|
24
|
+
) {
|
|
25
|
+
|
|
26
|
+
console.log(
|
|
27
|
+
"POINTER_MOVE",
|
|
28
|
+
x,
|
|
29
|
+
y
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
click(
|
|
34
|
+
x: number,
|
|
35
|
+
y: number
|
|
36
|
+
) {
|
|
37
|
+
|
|
38
|
+
console.log(
|
|
39
|
+
"CLICK",
|
|
40
|
+
x,
|
|
41
|
+
y
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
scroll(
|
|
46
|
+
delta: number
|
|
47
|
+
) {
|
|
48
|
+
|
|
49
|
+
console.log(
|
|
50
|
+
"SCROLL",
|
|
51
|
+
delta
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
keyboardInput(
|
|
56
|
+
text: string
|
|
57
|
+
) {
|
|
58
|
+
|
|
59
|
+
console.log(
|
|
60
|
+
"KEYBOARD_INPUT",
|
|
61
|
+
text
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
revokeConsent() {
|
|
66
|
+
|
|
67
|
+
console.log(
|
|
68
|
+
"CONSENT_REVOKED"
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const remoteControlSession =
|
|
74
|
+
new RemoteControlSession();
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { NativeAcsBridge } from "./NativeAcsBridge";
|
|
2
|
+
|
|
3
|
+
export class SupportCallSession {
|
|
4
|
+
|
|
5
|
+
private callId?: string;
|
|
6
|
+
|
|
7
|
+
private groupId?: string;
|
|
8
|
+
|
|
9
|
+
async initialize(
|
|
10
|
+
acsToken: string
|
|
11
|
+
) {
|
|
12
|
+
|
|
13
|
+
await NativeAcsBridge.initialize(
|
|
14
|
+
acsToken
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async joinCall(
|
|
19
|
+
groupId: string
|
|
20
|
+
) {
|
|
21
|
+
|
|
22
|
+
this.groupId = groupId;
|
|
23
|
+
|
|
24
|
+
await NativeAcsBridge.joinCall(
|
|
25
|
+
groupId
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async leaveCall() {
|
|
30
|
+
|
|
31
|
+
await NativeAcsBridge.leaveCall();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async mute() {
|
|
35
|
+
|
|
36
|
+
await NativeAcsBridge.mute();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async unmute() {
|
|
40
|
+
|
|
41
|
+
await NativeAcsBridge.unmute();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async startVideo() {
|
|
45
|
+
|
|
46
|
+
await NativeAcsBridge.startVideo();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async stopVideo() {
|
|
50
|
+
|
|
51
|
+
await NativeAcsBridge.stopVideo();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async startScreenShare() {
|
|
55
|
+
|
|
56
|
+
await NativeAcsBridge.startScreenShare();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async stopScreenShare() {
|
|
60
|
+
|
|
61
|
+
await NativeAcsBridge.stopScreenShare();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async startRecording() {
|
|
65
|
+
|
|
66
|
+
await NativeAcsBridge.startRecording();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async stopRecording() {
|
|
70
|
+
|
|
71
|
+
await NativeAcsBridge.stopRecording();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getGroupId() {
|
|
75
|
+
return this.groupId;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const supportCallSession =
|
|
80
|
+
new SupportCallSession();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
View,
|
|
5
|
+
Button,
|
|
6
|
+
} from "react-native";
|
|
7
|
+
|
|
8
|
+
export default function
|
|
9
|
+
ActiveCallScreen({
|
|
10
|
+
onMute,
|
|
11
|
+
onUnmute,
|
|
12
|
+
onEnd,
|
|
13
|
+
onVideoOn,
|
|
14
|
+
onVideoOff,
|
|
15
|
+
onShareScreen,
|
|
16
|
+
}: any) {
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<View>
|
|
20
|
+
|
|
21
|
+
<Button
|
|
22
|
+
title="Mute"
|
|
23
|
+
onPress={onMute}
|
|
24
|
+
/>
|
|
25
|
+
|
|
26
|
+
<Button
|
|
27
|
+
title="Unmute"
|
|
28
|
+
onPress={onUnmute}
|
|
29
|
+
/>
|
|
30
|
+
|
|
31
|
+
<Button
|
|
32
|
+
title="Video On"
|
|
33
|
+
onPress={onVideoOn}
|
|
34
|
+
/>
|
|
35
|
+
|
|
36
|
+
<Button
|
|
37
|
+
title="Video Off"
|
|
38
|
+
onPress={onVideoOff}
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
<Button
|
|
42
|
+
title="Share Screen"
|
|
43
|
+
onPress={
|
|
44
|
+
onShareScreen
|
|
45
|
+
}
|
|
46
|
+
/>
|
|
47
|
+
|
|
48
|
+
<Button
|
|
49
|
+
title="End Call"
|
|
50
|
+
onPress={onEnd}
|
|
51
|
+
/>
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
FlatList,
|
|
5
|
+
Text,
|
|
6
|
+
View,
|
|
7
|
+
} from "react-native";
|
|
8
|
+
|
|
9
|
+
export default function
|
|
10
|
+
CallHistoryScreen({
|
|
11
|
+
calls,
|
|
12
|
+
}: any) {
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<FlatList
|
|
16
|
+
data={calls}
|
|
17
|
+
keyExtractor={item =>
|
|
18
|
+
item.id
|
|
19
|
+
}
|
|
20
|
+
renderItem={({
|
|
21
|
+
item,
|
|
22
|
+
}) => (
|
|
23
|
+
<View>
|
|
24
|
+
|
|
25
|
+
<Text>
|
|
26
|
+
{item.customerName}
|
|
27
|
+
</Text>
|
|
28
|
+
|
|
29
|
+
<Text>
|
|
30
|
+
{item.status}
|
|
31
|
+
</Text>
|
|
32
|
+
|
|
33
|
+
<Text>
|
|
34
|
+
{item.createdAt}
|
|
35
|
+
</Text>
|
|
36
|
+
|
|
37
|
+
</View>
|
|
38
|
+
)}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
View,
|
|
5
|
+
Text,
|
|
6
|
+
Button,
|
|
7
|
+
} from "react-native";
|
|
8
|
+
|
|
9
|
+
export default function
|
|
10
|
+
IncomingCallScreen({
|
|
11
|
+
call,
|
|
12
|
+
onAccept,
|
|
13
|
+
onReject,
|
|
14
|
+
}: any) {
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<View
|
|
18
|
+
style={{
|
|
19
|
+
flex: 1,
|
|
20
|
+
justifyContent:
|
|
21
|
+
"center",
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
<Text>
|
|
25
|
+
Incoming Call
|
|
26
|
+
</Text>
|
|
27
|
+
|
|
28
|
+
<Text>
|
|
29
|
+
{call?.customerName}
|
|
30
|
+
</Text>
|
|
31
|
+
|
|
32
|
+
<Button
|
|
33
|
+
title="Accept"
|
|
34
|
+
onPress={() =>
|
|
35
|
+
onAccept(
|
|
36
|
+
call.id
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
<Button
|
|
42
|
+
title="Reject"
|
|
43
|
+
onPress={() =>
|
|
44
|
+
onReject(
|
|
45
|
+
call.id
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
/>
|
|
49
|
+
</View>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
View,
|
|
5
|
+
Text,
|
|
6
|
+
Button,
|
|
7
|
+
} from "react-native";
|
|
8
|
+
|
|
9
|
+
export default function
|
|
10
|
+
ScreenShareScreen({
|
|
11
|
+
onStop,
|
|
12
|
+
}: any) {
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<View>
|
|
16
|
+
|
|
17
|
+
<Text>
|
|
18
|
+
Screen Sharing Active
|
|
19
|
+
</Text>
|
|
20
|
+
|
|
21
|
+
<Button
|
|
22
|
+
title="Stop Sharing"
|
|
23
|
+
onPress={onStop}
|
|
24
|
+
/>
|
|
25
|
+
|
|
26
|
+
</View>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
export class CallingService {
|
|
4
|
+
constructor(
|
|
5
|
+
private apiBaseUrl: string,
|
|
6
|
+
private jwtToken: string
|
|
7
|
+
) {}
|
|
8
|
+
|
|
9
|
+
async createCall() {
|
|
10
|
+
const response = await axios.post(
|
|
11
|
+
`${this.apiBaseUrl}/api/v1/calls`,
|
|
12
|
+
{},
|
|
13
|
+
{
|
|
14
|
+
headers: {
|
|
15
|
+
Authorization:
|
|
16
|
+
`Bearer ${this.jwtToken}`,
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return response.data;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async acceptCall(callId: string) {
|
|
25
|
+
const response = await axios.post(
|
|
26
|
+
`${this.apiBaseUrl}/api/v1/calls/${callId}/accept`,
|
|
27
|
+
{},
|
|
28
|
+
{
|
|
29
|
+
headers: {
|
|
30
|
+
Authorization:
|
|
31
|
+
`Bearer ${this.jwtToken}`,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return response.data;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async rejectCall(callId: string) {
|
|
40
|
+
const response = await axios.post(
|
|
41
|
+
`${this.apiBaseUrl}/api/v1/calls/${callId}/reject`,
|
|
42
|
+
{},
|
|
43
|
+
{
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization:
|
|
46
|
+
`Bearer ${this.jwtToken}`,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return response.data;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async endCall(callId: string) {
|
|
55
|
+
const response = await axios.post(
|
|
56
|
+
`${this.apiBaseUrl}/api/v1/calls/${callId}/end`,
|
|
57
|
+
{},
|
|
58
|
+
{
|
|
59
|
+
headers: {
|
|
60
|
+
Authorization:
|
|
61
|
+
`Bearer ${this.jwtToken}`,
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return response.data;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { socketManager } from "../sockets/socket";
|
|
2
|
+
|
|
3
|
+
export class NotificationService {
|
|
4
|
+
listenIncomingCall(
|
|
5
|
+
callback: (payload: any) => void
|
|
6
|
+
) {
|
|
7
|
+
socketManager
|
|
8
|
+
.getSocket()
|
|
9
|
+
?.on(
|
|
10
|
+
"INCOMING_CALL",
|
|
11
|
+
callback
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
listenCallAccepted(
|
|
16
|
+
callback: (payload: any) => void
|
|
17
|
+
) {
|
|
18
|
+
socketManager
|
|
19
|
+
.getSocket()
|
|
20
|
+
?.on(
|
|
21
|
+
"CALL_ACCEPTED",
|
|
22
|
+
callback
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
listenCallRejected(
|
|
27
|
+
callback: (payload: any) => void
|
|
28
|
+
) {
|
|
29
|
+
socketManager
|
|
30
|
+
.getSocket()
|
|
31
|
+
?.on(
|
|
32
|
+
"CALL_REJECTED",
|
|
33
|
+
callback
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
listenCallTaken(
|
|
38
|
+
callback: (payload: any) => void
|
|
39
|
+
) {
|
|
40
|
+
socketManager
|
|
41
|
+
.getSocket()
|
|
42
|
+
?.on(
|
|
43
|
+
"CALL_TAKEN",
|
|
44
|
+
callback
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
listenCallEnded(
|
|
49
|
+
callback: (payload: any) => void
|
|
50
|
+
) {
|
|
51
|
+
socketManager
|
|
52
|
+
.getSocket()
|
|
53
|
+
?.on(
|
|
54
|
+
"CALL_ENDED",
|
|
55
|
+
callback
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
export class PresenceService {
|
|
4
|
+
constructor(
|
|
5
|
+
private apiBaseUrl: string,
|
|
6
|
+
private jwtToken: string
|
|
7
|
+
) {}
|
|
8
|
+
|
|
9
|
+
async heartbeat() {
|
|
10
|
+
const response = await axios.post(
|
|
11
|
+
`${this.apiBaseUrl}/api/v1/presence/heartbeat`,
|
|
12
|
+
{},
|
|
13
|
+
{
|
|
14
|
+
headers: {
|
|
15
|
+
Authorization:
|
|
16
|
+
`Bearer ${this.jwtToken}`,
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return response.data;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async updateStatus(
|
|
25
|
+
status:
|
|
26
|
+
| "Available"
|
|
27
|
+
| "Busy"
|
|
28
|
+
| "Away"
|
|
29
|
+
| "Offline"
|
|
30
|
+
) {
|
|
31
|
+
const response = await axios.put(
|
|
32
|
+
`${this.apiBaseUrl}/api/v1/presence/status`,
|
|
33
|
+
{ status },
|
|
34
|
+
{
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization:
|
|
37
|
+
`Bearer ${this.jwtToken}`,
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return response.data;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getAvailableAgents() {
|
|
46
|
+
const response = await axios.get(
|
|
47
|
+
`${this.apiBaseUrl}/api/v1/presence/agents`,
|
|
48
|
+
{
|
|
49
|
+
headers: {
|
|
50
|
+
Authorization:
|
|
51
|
+
`Bearer ${this.jwtToken}`,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return response.data;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
export class RecordingService {
|
|
4
|
+
constructor(
|
|
5
|
+
private apiBaseUrl: string,
|
|
6
|
+
private jwtToken: string
|
|
7
|
+
) {}
|
|
8
|
+
|
|
9
|
+
async startRecording(
|
|
10
|
+
callId: string
|
|
11
|
+
) {
|
|
12
|
+
return axios.post(
|
|
13
|
+
`${this.apiBaseUrl}/api/v1/recordings/start`,
|
|
14
|
+
{ callId },
|
|
15
|
+
{
|
|
16
|
+
headers: {
|
|
17
|
+
Authorization:
|
|
18
|
+
`Bearer ${this.jwtToken}`,
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async stopRecording(
|
|
25
|
+
recordingId: string
|
|
26
|
+
) {
|
|
27
|
+
return axios.post(
|
|
28
|
+
`${this.apiBaseUrl}/api/v1/recordings/stop`,
|
|
29
|
+
{ recordingId },
|
|
30
|
+
{
|
|
31
|
+
headers: {
|
|
32
|
+
Authorization:
|
|
33
|
+
`Bearer ${this.jwtToken}`,
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async getHistory() {
|
|
40
|
+
return axios.get(
|
|
41
|
+
`${this.apiBaseUrl}/api/v1/recordings`,
|
|
42
|
+
{
|
|
43
|
+
headers: {
|
|
44
|
+
Authorization:
|
|
45
|
+
`Bearer ${this.jwtToken}`,
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export class RemoteControlService {
|
|
2
|
+
|
|
3
|
+
requestControl() {
|
|
4
|
+
console.log(
|
|
5
|
+
"CONTROL_REQUEST"
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
approveControl() {
|
|
10
|
+
console.log(
|
|
11
|
+
"CONTROL_APPROVED"
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
denyControl() {
|
|
16
|
+
console.log(
|
|
17
|
+
"CONTROL_DENIED"
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
endControl() {
|
|
22
|
+
console.log(
|
|
23
|
+
"CONTROL_ENDED"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pointerMove(
|
|
28
|
+
x: number,
|
|
29
|
+
y: number
|
|
30
|
+
) {
|
|
31
|
+
console.log(
|
|
32
|
+
"POINTER_MOVE",
|
|
33
|
+
x,
|
|
34
|
+
y
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
click(
|
|
39
|
+
x: number,
|
|
40
|
+
y: number
|
|
41
|
+
) {
|
|
42
|
+
console.log(
|
|
43
|
+
"CLICK",
|
|
44
|
+
x,
|
|
45
|
+
y
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
scroll(
|
|
50
|
+
delta: number
|
|
51
|
+
) {
|
|
52
|
+
console.log(
|
|
53
|
+
"SCROLL",
|
|
54
|
+
delta
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
keyInput(text: string) {
|
|
59
|
+
console.log(
|
|
60
|
+
"KEY_INPUT",
|
|
61
|
+
text
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AcsConfig,
|
|
5
|
+
AcsTokenResponse,
|
|
6
|
+
} from "../core/types";
|
|
7
|
+
|
|
8
|
+
export class TokenService {
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
private config: AcsConfig
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async generateToken() {
|
|
15
|
+
|
|
16
|
+
const response =
|
|
17
|
+
await axios.post(
|
|
18
|
+
`${this.config.apiBaseUrl}/api/v1/acs/token`,
|
|
19
|
+
{},
|
|
20
|
+
{
|
|
21
|
+
headers: {
|
|
22
|
+
Authorization:
|
|
23
|
+
`Bearer ${this.config.jwtToken}`,
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return response.data
|
|
29
|
+
.data as AcsTokenResponse;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async checkTokenStatus() {
|
|
33
|
+
|
|
34
|
+
const response =
|
|
35
|
+
await axios.get(
|
|
36
|
+
`${this.config.apiBaseUrl}/api/v1/acs/token/status`,
|
|
37
|
+
{
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization:
|
|
40
|
+
`Bearer ${this.config.jwtToken}`,
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return response.data.data;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { io, Socket } from "socket.io-client";
|
|
2
|
+
|
|
3
|
+
class SocketManager {
|
|
4
|
+
private socket: Socket | null = null;
|
|
5
|
+
|
|
6
|
+
connect(url: string, jwtToken: string) {
|
|
7
|
+
if (this.socket?.connected) {
|
|
8
|
+
return this.socket;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.socket = io(url, {
|
|
12
|
+
transports: ["websocket"],
|
|
13
|
+
auth: {
|
|
14
|
+
token: jwtToken,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return this.socket;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getSocket() {
|
|
22
|
+
return this.socket;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
disconnect() {
|
|
26
|
+
this.socket?.disconnect();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const socketManager =
|
|
31
|
+
new SocketManager();
|