forked from galaxyproject/galaxy
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathresourceWatcher.ts
More file actions
139 lines (125 loc) · 4.31 KB
/
resourceWatcher.ts
File metadata and controls
139 lines (125 loc) · 4.31 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { readonly, ref } from "vue";
export type WatchResourceHandler<T = unknown> = (app?: T) => Promise<void>;
export interface WatchOptions {
/**
* Polling interval in milliseconds when the app is active (in the current tab).
*/
shortPollingInterval?: number;
/**
* Polling interval in milliseconds when the app is in the background (not in the current tab).
*/
longPollingInterval?: number;
/**
* If true, the resource is watched in the background even when the app is not active (in the current tab).
*/
enableBackgroundPolling?: boolean;
}
const DEFAULT_WATCH_OPTIONS: WatchOptions = {
shortPollingInterval: 3000,
longPollingInterval: 10000,
enableBackgroundPolling: true,
};
/**
* Creates a composable that watches a resource by polling the server continuously.
* By default, the polling interval is 'short' when the app is active (in the current tab) and 'long'
* when the app is in the background (not in the current tab).
* You can also completely disable background polling by setting `enableBackgroundPolling` to false in the options.
* @param watchHandler The handler function that watches the resource by querying the server.
* @param options Options to customize the polling interval.
* @returns An object with functions to start/stop watching and check the current watching state.
*/
export function useResourceWatcher<T = unknown>(
watchHandler: WatchResourceHandler,
options: WatchOptions = DEFAULT_WATCH_OPTIONS,
) {
const { shortPollingInterval, longPollingInterval, enableBackgroundPolling } = {
...DEFAULT_WATCH_OPTIONS,
...options,
};
let currentPollingInterval = shortPollingInterval;
let watchTimeout: NodeJS.Timeout | null = null;
let isEventSetup = false;
const isWatchingResource = ref<boolean>(false);
/**
* Starts watching the resource by polling the server continuously.
*/
function startWatchingResource(app?: T) {
stopWatcher();
isWatchingResource.value = true;
tryWatchResource(app);
}
/**
* Stops continuously watching the resource.
*/
function stopWatchingResource() {
stopWatcher();
}
/**
* Starts watching the resource if it is not already being watched.
*/
function startWatchingResourceIfNeeded() {
if (!isWatchingResource.value) {
startWatchingResource();
}
}
/**
* Stops watching the resource if it is currently being watched.
*/
function stopWatchingResourceIfNeeded() {
if (isWatchingResource.value) {
stopWatchingResource();
}
}
function stopWatcher() {
isWatchingResource.value = false;
if (watchTimeout) {
clearTimeout(watchTimeout);
watchTimeout = null;
}
}
async function tryWatchResource(app?: T) {
try {
await watchHandler(app);
} catch (error) {
console.warn(error);
} finally {
if (currentPollingInterval && isWatchingResource.value) {
watchTimeout = setTimeout(() => {
tryWatchResource(app);
}, currentPollingInterval);
}
}
}
function setupVisibilityListeners() {
if (!isEventSetup) {
isEventSetup = true;
document.addEventListener("visibilitychange", updateThrottle);
}
}
function updateThrottle() {
if (document.visibilityState === "visible") {
currentPollingInterval = shortPollingInterval;
startWatchingResourceIfNeeded();
} else {
currentPollingInterval = enableBackgroundPolling ? longPollingInterval : undefined;
}
}
setupVisibilityListeners();
return {
/**
* Starts watching the resource by polling the server continuously.
* @param app Optional parameter to pass to the watch handler.
*/
startWatchingResource,
/**
* Stops continuously watching the resource.
*/
stopWatchingResource,
startWatchingResourceIfNeeded,
stopWatchingResourceIfNeeded,
/**
* Reactive boolean ref indicating whether the resource watcher is currently active.
*/
isWatchingResource: readonly(isWatchingResource),
};
}