mirror of
https://github.com/AzuraCast/AzuraCast.git
synced 2024-06-14 21:26:37 +00:00
Make auto-refreshing async calls a common function that stops intervals on an exception.
This commit is contained in:
parent
5de23588f5
commit
dd13a5a91e
|
@ -228,7 +228,7 @@
|
|||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
import useHasDatatable, {DataTableTemplateRef} from "~/functions/useHasDatatable";
|
||||
import DataTable, { DataTableField } from "~/components/Common/DataTable.vue";
|
||||
import DataTable, {DataTableField} from "~/components/Common/DataTable.vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import CardPage from "~/components/Common/CardPage.vue";
|
||||
import {useLuxon} from "~/vendor/luxon";
|
||||
|
@ -237,12 +237,12 @@ import {useAxios} from "~/vendor/axios";
|
|||
import {useNotify} from "~/functions/useNotify";
|
||||
import Tabs from "~/components/Common/Tabs.vue";
|
||||
import Tab from "~/components/Common/Tab.vue";
|
||||
import {useIntervalFn} from "@vueuse/core";
|
||||
import {getApiUrl} from "~/router.ts";
|
||||
import useRefreshableAsyncState from "~/functions/useRefreshableAsyncState.ts";
|
||||
import Loading from "~/components/Common/Loading.vue";
|
||||
import {IconRefresh} from "~/components/Common/icons.ts";
|
||||
import Icon from "~/components/Common/Icon.vue";
|
||||
import useAutoRefreshingAsyncState from "~/functions/useAutoRefreshingAsyncState.ts";
|
||||
|
||||
const listSyncTasksUrl = getApiUrl('/admin/debug/sync-tasks');
|
||||
const listQueueTotalsUrl = getApiUrl('/admin/debug/queues');
|
||||
|
@ -252,14 +252,20 @@ const clearQueuesUrl = getApiUrl('/admin/debug/clear-queue');
|
|||
|
||||
const {axios} = useAxios();
|
||||
|
||||
const {state: syncTasks, isLoading: syncTasksLoading, execute: resetSyncTasks} = useRefreshableAsyncState(
|
||||
const {state: syncTasks, isLoading: syncTasksLoading, execute: resetSyncTasks} = useAutoRefreshingAsyncState(
|
||||
() => axios.get(listSyncTasksUrl.value).then(r => r.data),
|
||||
[],
|
||||
{
|
||||
timeout: 60000
|
||||
}
|
||||
);
|
||||
|
||||
const {state: queueTotals, isLoading: queueTotalsLoading, execute: resetQueueTotals} = useRefreshableAsyncState(
|
||||
const {state: queueTotals, isLoading: queueTotalsLoading, execute: resetQueueTotals} = useAutoRefreshingAsyncState(
|
||||
() => axios.get(listQueueTotalsUrl.value).then(r => r.data),
|
||||
[],
|
||||
{
|
||||
timeout: 60000
|
||||
}
|
||||
);
|
||||
|
||||
const {state: stations, isLoading: stationsLoading} = useRefreshableAsyncState(
|
||||
|
@ -267,14 +273,6 @@ const {state: stations, isLoading: stationsLoading} = useRefreshableAsyncState(
|
|||
[],
|
||||
);
|
||||
|
||||
useIntervalFn(
|
||||
() => {
|
||||
resetSyncTasks();
|
||||
resetQueueTotals();
|
||||
},
|
||||
60000
|
||||
);
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
const {timestampToRelative} = useLuxon();
|
||||
|
||||
|
|
|
@ -93,7 +93,6 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import Icon from '~/components/Common/Icon.vue';
|
||||
import {computed} from "vue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
import {getApiUrl} from "~/router";
|
||||
import {useAdminMenu} from "~/components/Admin/menu";
|
||||
|
@ -102,9 +101,8 @@ import MemoryStatsPanel from "~/components/Admin/Index/MemoryStatsPanel.vue";
|
|||
import DiskUsagePanel from "~/components/Admin/Index/DiskUsagePanel.vue";
|
||||
import ServicesPanel from "~/components/Admin/Index/ServicesPanel.vue";
|
||||
import NetworkStatsPanel from "~/components/Admin/Index/NetworkStatsPanel.vue";
|
||||
import useRefreshableAsyncState from "~/functions/useRefreshableAsyncState.ts";
|
||||
import {useIntervalFn} from "@vueuse/core";
|
||||
import Loading from "~/components/Common/Loading.vue";
|
||||
import useAutoRefreshingAsyncState from "~/functions/useAutoRefreshingAsyncState.ts";
|
||||
|
||||
const statsUrl = getApiUrl('/admin/server/stats');
|
||||
|
||||
|
@ -112,7 +110,7 @@ const menuItems = useAdminMenu();
|
|||
|
||||
const {axiosSilent} = useAxios();
|
||||
|
||||
const {state: stats, isLoading, execute: reloadStats} = useRefreshableAsyncState(
|
||||
const {state: stats, isLoading} = useAutoRefreshingAsyncState(
|
||||
() => axiosSilent.get(statsUrl.value).then(r => r.data),
|
||||
{
|
||||
cpu: {
|
||||
|
@ -154,14 +152,8 @@ const {state: stats, isLoading, execute: reloadStats} = useRefreshableAsyncState
|
|||
network: []
|
||||
},
|
||||
{
|
||||
shallow: true
|
||||
shallow: true,
|
||||
timeout: 5000
|
||||
}
|
||||
);
|
||||
|
||||
useIntervalFn(
|
||||
() => {
|
||||
reloadStats()
|
||||
},
|
||||
computed(() => (!document.hidden) ? 5000 : 10000)
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -51,30 +51,22 @@ import RunningBadge from "~/components/Common/Badges/RunningBadge.vue";
|
|||
import {getApiUrl} from "~/router.ts";
|
||||
import {useAxios} from "~/vendor/axios.ts";
|
||||
import {useNotify} from "~/functions/useNotify";
|
||||
import useRefreshableAsyncState from "~/functions/useRefreshableAsyncState.ts";
|
||||
import {useIntervalFn} from "@vueuse/core";
|
||||
import {computed} from "vue";
|
||||
import Loading from "~/components/Common/Loading.vue";
|
||||
import useAutoRefreshingAsyncState from "~/functions/useAutoRefreshingAsyncState.ts";
|
||||
|
||||
const servicesUrl = getApiUrl('/admin/services');
|
||||
|
||||
const {axios, axiosSilent} = useAxios();
|
||||
|
||||
const {state: services, isLoading, execute: reloadServices} = useRefreshableAsyncState(
|
||||
const {state: services, isLoading} = useAutoRefreshingAsyncState(
|
||||
() => axiosSilent.get(servicesUrl.value).then(r => r.data),
|
||||
[],
|
||||
{
|
||||
timeout: 5000,
|
||||
shallow: true
|
||||
}
|
||||
);
|
||||
|
||||
useIntervalFn(
|
||||
() => {
|
||||
reloadServices()
|
||||
},
|
||||
computed(() => (!document.hidden) ? 5000 : 15000)
|
||||
);
|
||||
|
||||
const {notifySuccess} = useNotify();
|
||||
|
||||
const doRestart = (serviceUrl) => {
|
||||
|
|
|
@ -276,9 +276,8 @@ import Icon from '~/components/Common/Icon.vue';
|
|||
import PlayButton from "~/components/Common/PlayButton.vue";
|
||||
import AlbumArt from "~/components/Common/AlbumArt.vue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
import {useAsyncState, useIntervalFn} from "@vueuse/core";
|
||||
import {useAsyncState} from "@vueuse/core";
|
||||
import {computed, ref} from "vue";
|
||||
import useRefreshableAsyncState from "~/functions/useRefreshableAsyncState";
|
||||
import DashboardCharts from "~/components/DashboardCharts.vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import Loading from "~/components/Common/Loading.vue";
|
||||
|
@ -290,6 +289,7 @@ import useOptionalStorage from "~/functions/useOptionalStorage";
|
|||
import {IconAccountCircle, IconHeadphones, IconInfo, IconSettings, IconWarning} from "~/components/Common/icons";
|
||||
import UserInfoPanel from "~/components/Account/UserInfoPanel.vue";
|
||||
import {getApiUrl} from "~/router.ts";
|
||||
import useAutoRefreshingAsyncState from "~/functions/useAutoRefreshingAsyncState.ts";
|
||||
|
||||
const props = defineProps({
|
||||
profileUrl: {
|
||||
|
@ -339,14 +339,12 @@ const {state: notifications, isLoading: notificationsLoading} = useAsyncState(
|
|||
[]
|
||||
);
|
||||
|
||||
const {state: stations, isLoading: stationsLoading, execute: reloadStations} = useRefreshableAsyncState(
|
||||
const {state: stations, isLoading: stationsLoading} = useAutoRefreshingAsyncState(
|
||||
() => axiosSilent.get(stationsUrl.value).then((r) => r.data),
|
||||
[],
|
||||
);
|
||||
|
||||
useIntervalFn(
|
||||
reloadStations,
|
||||
computed(() => (!document.hidden) ? 15000 : 30000)
|
||||
{
|
||||
timeout: 15000
|
||||
}
|
||||
);
|
||||
|
||||
const $lightbox = ref<LightboxTemplateRef>(null);
|
||||
|
|
|
@ -90,11 +90,10 @@ import publicPagesPanelProps from "./publicPagesPanelProps";
|
|||
import requestsPanelProps from "./requestsPanelProps";
|
||||
import streamersPanelProps from "./streamersPanelProps";
|
||||
import {pickProps} from "~/functions/pickProps";
|
||||
import useRefreshableAsyncState from "~/functions/useRefreshableAsyncState";
|
||||
import {useIntervalFn} from "@vueuse/core";
|
||||
import {useSweetAlert} from "~/vendor/sweetalert";
|
||||
import {useNotify} from "~/functions/useNotify";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import useAutoRefreshingAsyncState from "~/functions/useAutoRefreshingAsyncState.ts";
|
||||
|
||||
const props = defineProps({
|
||||
...backendPanelProps,
|
||||
|
@ -129,7 +128,7 @@ const hasActiveBackend = computed(() => {
|
|||
|
||||
const {axios, axiosSilent} = useAxios();
|
||||
|
||||
const {state: profileInfo, execute: reloadProfile} = useRefreshableAsyncState(
|
||||
const {state: profileInfo} = useAutoRefreshingAsyncState(
|
||||
() => axiosSilent.get(props.profileApiUri).then((r) => r.data),
|
||||
{
|
||||
station: {
|
||||
|
@ -142,14 +141,12 @@ const {state: profileInfo, execute: reloadProfile} = useRefreshableAsyncState(
|
|||
needs_restart: false
|
||||
},
|
||||
schedule: []
|
||||
},
|
||||
{
|
||||
timeout: 15000
|
||||
}
|
||||
);
|
||||
|
||||
useIntervalFn(
|
||||
reloadProfile,
|
||||
computed(() => (!document.hidden) ? 15000 : 30000)
|
||||
);
|
||||
|
||||
const {showAlert} = useSweetAlert();
|
||||
const {notify} = useNotify();
|
||||
const {$gettext} = useTranslate();
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
style="line-height: 1;"
|
||||
>
|
||||
{{ np.playing_next.song.title }}<br>
|
||||
<small>{{ np.playing_next.song.artist }}</small>
|
||||
<small class="text-muted">{{ np.playing_next.song.artist }}</small>
|
||||
</h6>
|
||||
</div>
|
||||
<div v-else>
|
||||
|
|
63
frontend/src/functions/useAutoRefreshingAsyncState.ts
Normal file
63
frontend/src/functions/useAutoRefreshingAsyncState.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
import useRefreshableAsyncState from "~/functions/useRefreshableAsyncState.ts";
|
||||
import {Pausable, UseAsyncStateOptions, UseAsyncStateReturn, useIntervalFn} from "@vueuse/core";
|
||||
import {computed} from "vue";
|
||||
|
||||
interface AutoRefreshingAsyncStateOptions<Shallow extends boolean, D = any>
|
||||
extends UseAsyncStateOptions<Shallow, D> {
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
interface AutoRefreshingAsyncStateReturn<Data, Params extends any[], Shallow extends boolean>
|
||||
extends UseAsyncStateReturn<Data, Params, Shallow>, Pausable {
|
||||
}
|
||||
|
||||
export default function useAutoRefreshingAsyncState<Data, Params extends any[] = [], Shallow extends boolean = true>(
|
||||
promise: Promise<Data> | ((...args: Params) => Promise<Data>),
|
||||
initialState: Data,
|
||||
options: AutoRefreshingAsyncStateOptions<Shallow, Data> = {}
|
||||
): AutoRefreshingAsyncStateReturn<Data, Params, Shallow> {
|
||||
const {
|
||||
timeout = 15000
|
||||
} = options ?? {}
|
||||
|
||||
const {
|
||||
state,
|
||||
isReady,
|
||||
isLoading,
|
||||
error,
|
||||
execute
|
||||
} = useRefreshableAsyncState(
|
||||
promise,
|
||||
initialState,
|
||||
{
|
||||
throwError: true,
|
||||
...options
|
||||
}
|
||||
);
|
||||
|
||||
const intervalDelay = computed(() =>
|
||||
(!document.hidden) ? timeout : (timeout * 2)
|
||||
);
|
||||
|
||||
const {isActive, pause, resume} = useIntervalFn(
|
||||
async () => {
|
||||
try {
|
||||
await execute();
|
||||
} catch (e) {
|
||||
pause();
|
||||
}
|
||||
},
|
||||
intervalDelay
|
||||
);
|
||||
|
||||
return {
|
||||
state,
|
||||
isReady,
|
||||
isLoading,
|
||||
error,
|
||||
execute,
|
||||
isActive,
|
||||
pause,
|
||||
resume
|
||||
};
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import {useAsyncState} from "@vueuse/core";
|
||||
import {useAsyncState, UseAsyncStateOptions, UseAsyncStateReturn} from "@vueuse/core";
|
||||
import syncOnce from "~/functions/syncOnce";
|
||||
import {Ref} from "vue";
|
||||
|
||||
/**
|
||||
* Just like useAsyncState, except with settings changed:
|
||||
|
@ -8,12 +9,18 @@ import syncOnce from "~/functions/syncOnce";
|
|||
*
|
||||
* @see useAsyncState
|
||||
*/
|
||||
export default function useRefreshableAsyncState(
|
||||
promise,
|
||||
initialState,
|
||||
options = {}
|
||||
) {
|
||||
const {state, isLoading: allIsLoading, execute} = useAsyncState(
|
||||
export default function useRefreshableAsyncState<Data, Params extends any[] = [], Shallow extends boolean = true>(
|
||||
promise: Promise<Data> | ((...args: Params) => Promise<Data>),
|
||||
initialState: Data,
|
||||
options: UseAsyncStateOptions<Shallow, Data> = {}
|
||||
): UseAsyncStateReturn<Data, Params, Shallow> {
|
||||
const {
|
||||
state,
|
||||
isReady,
|
||||
isLoading: allIsLoading,
|
||||
error,
|
||||
execute
|
||||
} = useAsyncState(
|
||||
promise,
|
||||
initialState,
|
||||
{
|
||||
|
@ -22,11 +29,13 @@ export default function useRefreshableAsyncState(
|
|||
}
|
||||
);
|
||||
|
||||
const isLoading = syncOnce(allIsLoading);
|
||||
const isLoading: Ref<boolean> = syncOnce(allIsLoading);
|
||||
|
||||
return {
|
||||
state,
|
||||
isReady,
|
||||
isLoading,
|
||||
error,
|
||||
execute
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user