diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2025-04-23 22:19:24 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2025-04-23 22:19:24 -0400 |
| commit | 713afd0b4963460cc37b3767c6b542c8c828d227 (patch) | |
| tree | 5156b6874cdd3cde684b4719d5e8fe1500b47612 /ui/lib | |
| parent | 1ebe642ebe7c9ba72eb1713ec21f0cd03949a47f (diff) | |
| parent | 4d6cc62f0c9bb5d50720c83fb1ecbd0889d2acd3 (diff) | |
Retry boot every five seconds.
Merged in spite of misgivings. This method will loop over the request until it completes, even if the user moves to a view where the response is no longer relevant.
Diffstat (limited to 'ui/lib')
| -rw-r--r-- | ui/lib/apiServer.js | 61 | ||||
| -rw-r--r-- | ui/lib/retry.js | 21 | ||||
| -rw-r--r-- | ui/lib/session.svelte.js | 24 |
3 files changed, 79 insertions, 27 deletions
diff --git a/ui/lib/apiServer.js b/ui/lib/apiServer.js index 0b51883..cad8997 100644 --- a/ui/lib/apiServer.js +++ b/ui/lib/apiServer.js @@ -1,56 +1,59 @@ import axios from 'axios'; +import * as r from './retry.js'; +import { timedDelay } from './retry.js'; + export const apiServer = axios.create({ - baseURL: '/api/', - validateStatus: () => true + baseURL: '/api/' }); export async function boot() { - return apiServer.get('/boot'); + return apiServer.get('/boot').catch(responseError); } export async function setup(name, password) { - return apiServer.post('/setup', { name, password }); + return await apiServer.post('/setup', { name, password }).catch(responseError); } export async function logIn(name, password) { - return apiServer.post('/auth/login', { name, password }); + return await apiServer.post('/auth/login', { name, password }).catch(responseError); } export async function logOut() { - return apiServer.post('/auth/logout', {}); + return await apiServer.post('/auth/logout', {}).catch(responseError); } export async function changePassword(password, to) { - return apiServer.post('/password', { password, to }); + return await apiServer.post('/password', { password, to }).catch(responseError); } export async function createChannel(name) { - return apiServer.post('/channels', { name }); + return await apiServer.post('/channels', { name }).catch(responseError); } export async function postToChannel(channelId, body) { - return apiServer.post(`/channels/${channelId}`, { body }); + return await apiServer.post(`/channels/${channelId}`, { body }).catch(responseError); } export async function deleteMessage(messageId) { - return apiServer.delete(`/messages/${messageId}`, {}); + return await apiServer.delete(`/messages/${messageId}`, {}).catch(responseError); } export async function createInvite() { - return apiServer.post(`/invite`, {}); + return await apiServer.post(`/invite`, {}).catch(responseError); } export async function getInvite(inviteId) { - return apiServer.get(`/invite/${inviteId}`); + return await apiServer.get(`/invite/${inviteId}`).catch(responseError); } export async function acceptInvite(inviteId, name, password) { - const data = { - name, - password - }; - return apiServer.post(`/invite/${inviteId}`, data); + return apiServer + .post(`/invite/${inviteId}`, { + name, + password + }) + .catch(responseError); } export function subscribeToEvents(resumePoint) { @@ -62,3 +65,27 @@ export function subscribeToEvents(resumePoint) { }); return new EventSource(eventsUrl); } + +export class LoggedOut extends Error {} + +export class SetupRequired extends Error {} + +export async function retry(op) { + return await r.retry(op, isRetryable, r.timedDelay(5000)); +} + +function responseError(err) { + if (err.response) { + switch (err.response.status) { + case 401: + throw new LoggedOut(); + case 503: + throw new SetupRequired(); + } + } + throw err; +} + +function isRetryable(err) { + return !!err.request; +} diff --git a/ui/lib/retry.js b/ui/lib/retry.js new file mode 100644 index 0000000..a2cff65 --- /dev/null +++ b/ui/lib/retry.js @@ -0,0 +1,21 @@ +export async function retry(callback, shouldRetry, delay) { + while (true) { + try { + return await callback(); + } catch (err) { + if (shouldRetry(err)) { + await delay(); + } else { + throw err; + } + } + } +} + +export function timedDelay(millis) { + return async () => await sleep(millis); +} + +function sleep(millis) { + return new Promise((resolve) => setTimeout(resolve, millis)); +} diff --git a/ui/lib/session.svelte.js b/ui/lib/session.svelte.js index b953d9c..21a391d 100644 --- a/ui/lib/session.svelte.js +++ b/ui/lib/session.svelte.js @@ -94,16 +94,20 @@ class Session { } async function bootOrNavigate(navigateTo) { - const response = await api.boot(); - switch (response.status) { - case 401: - await navigateTo('/login'); - break; - case 503: - await navigateTo('/setup'); - break; - case 200: - return response.data; + try { + const response = await api.retry(async () => await api.boot()); + return response.data; + } catch (err) { + switch (true) { + case err instanceof api.LoggedOut: + await navigateTo('/login'); + break; + case err instanceof api.SetupRequired: + await navigateTo('/setup'); + break; + default: + throw err; + } } } |
