-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathsocket.ts
More file actions
111 lines (93 loc) · 3.01 KB
/
socket.ts
File metadata and controls
111 lines (93 loc) · 3.01 KB
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
import { getSocketPath } from './utils';
declare const amb: any;
interface AmbExt {
from_user: string;
processed_by_glide: boolean;
sys_id: string;
}
interface AmbGlideChanges {
[key: string]: { display_value: string; value: string };
}
interface AmbData {
action: 'entry' | 'change' | 'exit';
record?: AmbGlideChanges;
sys_id: string; // target record
table_name: string;
operation: 'insert' | 'update' | 'delete';
changes: string[] /* NOTE: does not include sys fields (e.g. sys_updated_on) */;
sent_by?: number;
display_value: string; // Display value of the DB record
}
interface AmbSocketChangeObj {
channel: string;
data: AmbData;
ext: AmbExt;
}
interface AmbCallback {
(payload: AmbSocketChangeObj): void;
}
interface AmbChannel {
getCallback(): AmbCallback;
getID(): string;
resubscribe(): AmbChannel;
subscribe(callback: AmbCallback): AmbChannel;
unsubscribe(): AmbChannel;
getName(): string;
}
interface SNSocketUnsubscribe {
(): void;
}
interface SNSocketParams {
table: string;
filter: string;
callback: AmbCallback;
}
interface SocketCache {
[key: string]: AmbChannel;
}
/** Hold reference to channel for unsubscribing */
const cache: SocketCache = {};
function getClient() {
if (amb) {
return amb.getClient();
}
console.error(`Failed to subscribe websocket channel.
The amb scripts are loaded separately from this library via the ServiceNow instance.
Perhaps include the /scripts/glide-amb-client-bundle.min.js in your UI Page and retry.`);
}
function getChannel(client: any, path: string): AmbChannel {
return client.getChannel(path);
}
function getCacheKey(params: SNSocketParams): string {
const { table, filter } = params;
return `${table}_${filter}`;
}
function subscribeToClient(client: any, params: SNSocketParams): SNSocketUnsubscribe {
const { callback } = params;
const path = getSocketPath(params);
const channel = getChannel(client, path);
const key = getCacheKey(params);
channel.subscribe(callback);
cache[key] = channel;
return () => {
delete cache[key];
channel.unsubscribe();
};
}
function noop() {}
/**
* Subscribe and respond to changes on a table which match a given filter
* @param {Object} params - Arguments required for initializing a websocket subscription
* @param {string} params.table - The name of target table
* @param {string} params.filter - The query to watch. Corresponds to sysparm_query in the system
* @param {string} params.callback - The callback to fire on notification from Websocket
* @returns {function} - Returns an unsubscribe function which takes no arguments. Allows one to deregister the socket subscription
*/
async function subscribe(params: SNSocketParams): Promise<SNSocketUnsubscribe> {
const client = getClient();
const key = getCacheKey(params);
const shouldSubscribe = client && !cache[key];
/* If amb is not loaded, return a noop function */
return shouldSubscribe ? subscribeToClient(client, params) : noop;
}
export { subscribe, SNSocketParams };