mirror of
https://github.com/unraid/api.git
synced 2026-01-06 00:30:22 -06:00
refactor: callback finished refreshServerState
This commit is contained in:
@@ -3,6 +3,7 @@ import { defineStore } from 'pinia';
|
||||
import { addPreventClose, removePreventClose } from '~/composables/preventClose';
|
||||
import { useAccountStore } from '~/store/account';
|
||||
import { useInstallKeyStore } from '~/store/installKey';
|
||||
import { useServerStore } from '~/store/server';
|
||||
import { useCallbackStoreGeneric, type ExternalPayload, type ExternalKeyActions, type QueryPayloads } from '~/store/callback';
|
||||
|
||||
export const useCallbackActionsStore = defineStore(
|
||||
@@ -10,6 +11,7 @@ export const useCallbackActionsStore = defineStore(
|
||||
() => {
|
||||
const accountStore = useAccountStore();
|
||||
const installKeyStore = useInstallKeyStore();
|
||||
const serverStore = useServerStore();
|
||||
|
||||
type CallbackStatus = 'error' | 'loading' | 'ready' | 'success';
|
||||
const callbackStatus = ref<CallbackStatus>('ready');
|
||||
@@ -43,6 +45,8 @@ export const useCallbackActionsStore = defineStore(
|
||||
}
|
||||
// all actions have run
|
||||
if (array.length === (index + 1)) {
|
||||
/** @todo refresh server state until we have new data */
|
||||
await serverStore.refreshServerState();
|
||||
// callbackStatus.value = 'done';
|
||||
if (array.length > 1) {
|
||||
// if we have more than 1 action it means there was a key install and an account action so both need to be successful
|
||||
|
||||
@@ -70,35 +70,3 @@ export const SERVER_STATE_QUERY = graphql(/* GraphQL */`
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_CONFIG_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Config {
|
||||
config {
|
||||
...FragmentConfig
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_OWNER_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Owner {
|
||||
owner {
|
||||
...FragmentOwner
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_REGISTRATION_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Registration {
|
||||
registration {
|
||||
...FragmentRegistration
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const SERVER_VARS_SUBSCRIPTION = graphql(/* GraphQL */`
|
||||
subscription Vars {
|
||||
vars {
|
||||
...FragmentVars
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
130
store/server.ts
130
store/server.ts
@@ -2,6 +2,7 @@
|
||||
* @todo Check OS and Connect Plugin versions against latest via API every session
|
||||
*/
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import {
|
||||
ArrowRightOnRectangleIcon,
|
||||
CogIcon,
|
||||
@@ -10,8 +11,10 @@ import {
|
||||
KeyIcon,
|
||||
QuestionMarkCircleIcon
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import { useQuery, useSubscription } from '@vue/apollo-composable';
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
import { useTimeoutPoll } from '@vueuse/core';
|
||||
|
||||
import { WebguiState } from '~/composables/services/webgui';
|
||||
import { SETTINGS_MANAGMENT_ACCESS } from '~/helpers/urls';
|
||||
import { useAccountStore } from '~/store/account';
|
||||
import { useErrorsStore, type Error } from '~/store/errors';
|
||||
@@ -31,18 +34,7 @@ import type {
|
||||
ServerconnectPluginInstalled,
|
||||
} from '~/types/server';
|
||||
|
||||
import {
|
||||
SERVER_STATE_QUERY,
|
||||
SERVER_VARS_FRAGMENT,
|
||||
SERVER_VARS_SUBSCRIPTION,
|
||||
SERVER_OWNER_FRAGMENT,
|
||||
SERVER_OWNER_SUBSCRIPTION,
|
||||
SERVER_CONFIG_FRAGMENT,
|
||||
SERVER_CONFIG_SUBSCRIPTION,
|
||||
SERVER_REGISTRATION_FRAGMENT,
|
||||
SERVER_REGISTRATION_SUBSCRIPTION,
|
||||
} from './server.fragment';
|
||||
import { useFragment } from '~/composables/gql/fragment-masking';
|
||||
import { SERVER_STATE_QUERY } from './server.fragment';
|
||||
/**
|
||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||
* @see https://github.com/vuejs/pinia/discussions/1085
|
||||
@@ -93,6 +85,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
const username = ref<string>(''); // @todo potentially move to a user store
|
||||
const wanFQDN = ref<string>('');
|
||||
|
||||
const apiServerStateRefresh = ref<any>(null);
|
||||
/**
|
||||
* Getters
|
||||
*/
|
||||
@@ -693,89 +686,98 @@ export const useServerStore = defineStore('server', () => {
|
||||
};
|
||||
|
||||
const fetchServerFromApi = () => {
|
||||
const { result: resultServerState } = useQuery(SERVER_STATE_QUERY);
|
||||
const { result: resultServerState, refetch: refetchServerState } = useQuery(SERVER_STATE_QUERY, null, {
|
||||
pollInterval: 2500,
|
||||
fetchPolicy: 'no-cache',
|
||||
});
|
||||
const serverState = computed(() => resultServerState.value ?? null);
|
||||
apiServerStateRefresh.value = refetchServerState;
|
||||
watch(serverState, value => {
|
||||
console.debug('[watch.serverState]', value);
|
||||
console.debug('[watch:serverState]', value);
|
||||
if (value) {
|
||||
const mutatedServerStateResult = mutateServerStateFromApi(value);
|
||||
setServer(mutatedServerStateResult);
|
||||
}
|
||||
});
|
||||
|
||||
const { result: resultServerVars } = useSubscription(SERVER_VARS_SUBSCRIPTION);
|
||||
const serverVars = computed(() => useFragment(SERVER_VARS_FRAGMENT, resultServerVars.value));
|
||||
watch(serverVars, value => {
|
||||
console.debug('[watch.serverVars]', value);
|
||||
// if (value) {
|
||||
// }
|
||||
});
|
||||
|
||||
// const { result: resultServerOwner } = useSubscription(SERVER_OWNER_SUBSCRIPTION);
|
||||
// const serverOwner = computed(() => resultServerOwner.value ?? null);
|
||||
// watch(serverOwner, value => {
|
||||
// console.debug('[watch.resultServerOwner]', value);
|
||||
// // if (value) {
|
||||
// // }
|
||||
// });
|
||||
|
||||
// const { result: resultServerConfig } = useSubscription(SERVER_CONFIG_SUBSCRIPTION);
|
||||
// const serverConfig = computed(() => resultServerConfig.value ?? null);
|
||||
// watch(serverConfig, value => {
|
||||
// console.debug('[watch.resultServerConfig]', value);
|
||||
// // if (value) {
|
||||
// // }
|
||||
// });
|
||||
|
||||
// const { result: resultServerRegistration } = useSubscription(SERVER_REGISTRATION_SUBSCRIPTION);
|
||||
// const serverRegistration = computed(() => resultServerRegistration.value ?? null);
|
||||
// watch(serverRegistration, value => {
|
||||
// console.debug('[watch.resultServerRegistration]', value);
|
||||
// // if (value) {
|
||||
// // }
|
||||
// });
|
||||
};
|
||||
|
||||
watch(apiKey, (newVal, oldVal) => {
|
||||
console.debug('[watch.apiKey]', newVal, oldVal);
|
||||
if (oldVal) {
|
||||
// stop old client
|
||||
console.debug('[watch.apiKey] no apiKey, stop old client');
|
||||
const phpServerStateRefresh = async () => {
|
||||
console.debug('[phpServerStateRefresh] start');
|
||||
try {
|
||||
const stateResponse: Server = await WebguiState
|
||||
.get()
|
||||
.json();
|
||||
console.debug('[phpServerStateRefresh] stateResponse', stateResponse);
|
||||
setServer(stateResponse);
|
||||
return stateResponse;
|
||||
} catch (error) {
|
||||
console.error('[phpServerStateRefresh] error', error);
|
||||
}
|
||||
/** @todo abstract validation checks */
|
||||
if (newVal && newVal.length === 64 && newVal.startsWith('unupc_')) {
|
||||
// start new client
|
||||
console.debug('[watch.apiKey] start new client');
|
||||
unraidApiStore.createApolloClient(newVal);
|
||||
};
|
||||
|
||||
let refreshCount = 0;
|
||||
const refreshLimit = 10;
|
||||
const refreshedServerState = ref(false);
|
||||
const refreshServerState = async () => {
|
||||
refreshCount++;
|
||||
console.debug('[refreshServerState] start', { refreshCount });
|
||||
const registeredBeforeRefresh = registered.value;
|
||||
const stateBeforeRefresh = state.value;
|
||||
|
||||
const responseNewState = apiServerStateRefresh.value
|
||||
? await apiServerStateRefresh.value()
|
||||
: await phpServerStateRefresh();
|
||||
console.debug(`[refreshServerState] responseNewState`, responseNewState);
|
||||
|
||||
const newState = apiServerStateRefresh.value && responseNewState?.data ? responseNewState.data : responseNewState;
|
||||
console.debug(`[refreshServerState] newState`, newState);
|
||||
|
||||
const registrationStatusChanged = registeredBeforeRefresh !== newState.registered;
|
||||
const stateChanged = stateBeforeRefresh !== newState.state;
|
||||
|
||||
if (registrationStatusChanged || stateChanged) {
|
||||
console.debug('[refreshServerState] change detected, stop refreshing', { registrationStatusChanged, stateChanged });
|
||||
refreshedServerState.value = true;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (refreshCount >= refreshLimit) {
|
||||
console.debug('[refreshServerState] refresh limit reached, stop refreshing');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.debug('[refreshServerState] no change, fetch again in 250ms…', { registrationStatusChanged, stateChanged });
|
||||
setTimeout(() => {
|
||||
return refreshServerState();
|
||||
}, 250);
|
||||
};
|
||||
|
||||
watch(theme, (newVal) => {
|
||||
if (newVal) themeStore.setTheme(newVal);
|
||||
});
|
||||
|
||||
watch(stateDataError, (newVal, oldVal) => {
|
||||
console.debug('[watch.stateDataError]', newVal, oldVal);
|
||||
console.debug('[watch:stateDataError]', newVal, oldVal);
|
||||
if (oldVal && oldVal.ref) errorsStore.removeErrorByRef(oldVal.ref);
|
||||
if (newVal) errorsStore.setError(newVal);
|
||||
});
|
||||
watch(invalidApiKey, (newVal, oldVal) => {
|
||||
console.debug('[watch.invalidApiKey]', newVal, oldVal);
|
||||
console.debug('[watch:invalidApiKey]', newVal, oldVal);
|
||||
if (oldVal && oldVal.ref) errorsStore.removeErrorByRef(oldVal.ref);
|
||||
if (newVal) errorsStore.setError(newVal);
|
||||
});
|
||||
watch(tooManyDevices, (newVal, oldVal) => {
|
||||
console.debug('[watch.tooManyDevices]', newVal, oldVal);
|
||||
console.debug('[watch:tooManyDevices]', newVal, oldVal);
|
||||
if (oldVal && oldVal.ref) errorsStore.removeErrorByRef(oldVal.ref);
|
||||
if (newVal) errorsStore.setError(newVal);
|
||||
});
|
||||
watch(pluginInstallFailed, (newVal, oldVal) => {
|
||||
console.debug('[watch.pluginInstallFailed]', newVal, oldVal);
|
||||
console.debug('[watch:pluginInstallFailed]', newVal, oldVal);
|
||||
if (oldVal && oldVal.ref) errorsStore.removeErrorByRef(oldVal.ref);
|
||||
if (newVal) errorsStore.setError(newVal);
|
||||
});
|
||||
watch(deprecatedUnraidSSL, (newVal, oldVal) => {
|
||||
console.debug('[watch.deprecatedUnraidSSL]', newVal, oldVal);
|
||||
console.debug('[watch:deprecatedUnraidSSL]', newVal, oldVal);
|
||||
if (oldVal && oldVal.ref) errorsStore.removeErrorByRef(oldVal.ref);
|
||||
if (newVal) errorsStore.setError(newVal);
|
||||
});
|
||||
@@ -802,6 +804,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
theme,
|
||||
uptime,
|
||||
username,
|
||||
refreshedServerState,
|
||||
// getters
|
||||
authAction,
|
||||
deprecatedUnraidSSL,
|
||||
@@ -820,5 +823,6 @@ export const useServerStore = defineStore('server', () => {
|
||||
// actions
|
||||
setServer,
|
||||
fetchServerFromApi,
|
||||
refreshServerState,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import { logErrorMessages } from '@vue/apollo-util'
|
||||
import { createClient } from 'graphql-ws';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
import { useAccountStore } from '~/store/account';
|
||||
import { useErrorsStore } from '~/store/errors';
|
||||
import { useServerStore } from '~/store/server';
|
||||
/**
|
||||
@@ -28,18 +29,26 @@ console.debug('[useUnraidApiStore] wsEndpoint', wsEndpoint.toString());
|
||||
|
||||
export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
console.debug('[useUnraidApiStore]');
|
||||
const accountStore = useAccountStore();
|
||||
const errorsStore = useErrorsStore();
|
||||
const serverStore = useServerStore();
|
||||
|
||||
const unraidApiClient = ref<ApolloClient<any>>();
|
||||
|
||||
const registeredWithValidApiKey = computed(() => {
|
||||
const { registered, invalidApiKey } = serverStore;
|
||||
return registered && !invalidApiKey;
|
||||
});
|
||||
|
||||
/**
|
||||
* Automatically called when an apiKey is set in the serverStore
|
||||
*/
|
||||
const createApolloClient = (apiKey: string) => {
|
||||
console.debug('[useUnraidApiStore.createApolloClient]');
|
||||
|
||||
const headers = { 'x-api-key': apiKey };
|
||||
const createApolloClient = () => {
|
||||
console.debug('[useUnraidApiStore.createApolloClient]', serverStore.apiKey);
|
||||
if (accountStore.accountActionType === 'signOut') {
|
||||
return console.debug('[useUnraidApiStore.createApolloClient] sign out imminent, skipping createApolloClient');
|
||||
}
|
||||
const headers = { 'x-api-key': serverStore.apiKey };
|
||||
|
||||
const httpLink = new createHttpLink({
|
||||
uri: httpEndpoint.toString(),
|
||||
@@ -103,8 +112,32 @@ export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
console.debug('[useUnraidApiStore.createApolloClient] 🏁 CREATED');
|
||||
};
|
||||
|
||||
const closeUnraidApiClient = async () => {
|
||||
console.debug('[useUnraidApiStore.closeUnraidApiClient] STARTED');
|
||||
if (!unraidApiClient.value) return console.debug('[useUnraidApiStore.closeUnraidApiClient] unraidApiClient not set');
|
||||
if (unraidApiClient.value) {
|
||||
await unraidApiClient.value.clearStore();
|
||||
unraidApiClient.value.stop();
|
||||
// (wsLink.value as any).subscriptionClient.close(); // needed if we start using subscriptions
|
||||
}
|
||||
unraidApiClient.value = undefined;
|
||||
console.debug('[useUnraidApiStore.closeUnraidApiClient] DONE');
|
||||
};
|
||||
|
||||
watch(registeredWithValidApiKey, (newVal, oldVal) => {
|
||||
console.debug('[watch:registeredWithValidApiKey]', newVal, oldVal);
|
||||
if (oldVal) {
|
||||
console.debug('[watch:registeredWithValidApiKey] no apiKey, stop unraid-api client');
|
||||
closeUnraidApiClient();
|
||||
}
|
||||
if (newVal) {
|
||||
console.debug('[watch:registeredWithValidApiKey] new apiKey, start unraid-api client');
|
||||
createApolloClient();
|
||||
}
|
||||
});
|
||||
|
||||
watch(unraidApiClient, (newVal, oldVal) => {
|
||||
console.debug('[watch.unraidApiStore.unraidApiClient]', { newVal, oldVal });
|
||||
console.debug('[watch:unraidApiStore.unraidApiClient]', { newVal, oldVal });
|
||||
if (newVal && !oldVal) { // first time
|
||||
serverStore.fetchServerFromApi();
|
||||
}
|
||||
@@ -113,5 +146,6 @@ export const useUnraidApiStore = defineStore('unraidApi', () => {
|
||||
return {
|
||||
unraidApiClient,
|
||||
createApolloClient,
|
||||
closeUnraidApiClient,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user