You've already forked AstralRinth
693a371d61
* start new server settings tabs * update properties tab to match design * better stying in general tab * feat: add suffix input for hostname field * implement tables for allocations and DNS records * add tags for dns record type * small gap adjustment * polish advanced page * adjust properties page hierarchy * fix searching properties, empty state and projection radius appearing * pnpm prepr * update copy to match designs * fix suffix input component * style fixes and match heading size * small fix * fix search allocations placeholder * adjust table styles * move all installation settings helper text to below input * update icon to use overflow menu buttons * fix modal to be consistent * open advanced properties when search * remove other and custom properties, and update styles * remove hide/show all java versions * handle mc 26 * refactor: move server settings pages into /ui and add app ServerSettingsModal * hook up server pages for app * add server page header to app * hook up server settings modal * use large size * fix card box shadow style * fix hostname input for app * fix app/website card containers * implement external tabs for billing and admin billing * fix save banner fixed to parent instead of page body * remove unused prop to FriendsList causing warning in app * fix client-only not available for app * fix bottom cut off * wire node auth * implement full copy buttons * dedup copy button tailwind styles * fix hover class not working in @apply * fix spacing * fix error validation styles * apply consistent styles and spacing * feat: update hosting server card (#5609) * fix type errors * fix some stylesheets not imported for storybook * add server listing stories * add fix for frontend stylesheet imports * remove props. * convert copy code to use tailwind * update server listing component styles * update server info label styles * start status/player count info label, more style updates and fixes * add new server card buttons * hook up server cards and implement updated styles * hook up on download button * fix tauri throwing error when api returns 204 No Content * hook up purchase server modal in app * fix upgrading state loading icon * pnpm prepr * filter out servers past 30 days after cancellation * do not apply opacity on lock or spiner icons * fix disabled server icon background * update pending change stage * handle known suspension states * refactor: reduce code duplication for server listing * update disabled state text color * fix loading icon color * clean up copy * fix disabled opacity for server card * update server listing files kept to be countdown * implement resubscribe modal * implement proper provisioning state for resubscribe * fix duplicate attribute and pnpm prepr * feat: add shared UI package auth DI * feat: update purchase server flow (#5714) * implement server list empty state component * fix stories and adjust spacing * implement select plan design refresh * implement auth for empty server list * use refs instead of reactive * pnpm prepr * fix auth usage for empty servers list * move app auth provider setup to src/providers/setup * pnpm prepr * fix max height * style fix * fix getCreds no auth is blocking api client * implement servers guest plan modal and signin which redirects back to modal's next step * refactor guest plan select logic into provider * implement sign in or create account popup * remove force empty serverList * add download button for suspended mod and generic * add handling for when user logs out * QA pass style fixes * more consistent page styles * fix duplicate export * refactor: remove all fallback stuff from resubscribe modal * implement shared download latest backup util * i18n pass * pnpm prepr * fix region being selected if ping failed * pnpm prepr * feat: servers in app finalization (#5744) * feat: start on shared console implementation into logs and overview pages * fix: terminal gap issues * feat: swap word wrap for full screen * fix: stats cards alignment * fix: stats * feat: fix console clear + remove copy * fix: lint * fix: use reset not clear * feat: shared server header & overview page for app and website (#5736) * feat: implement shared server header for app and website * feat: implement wrapped overview page with shared composable and hook it up * pnpm prepr * fix: bugs * qa: cleanup * feat: root.vue shared layout * feat: delete old options pages + fix discovery frontend * fix: discovery * fix: misc style/layout issues * fix page padding * fix: modal height jankiness * feat: implement server install content in app and server setup modal with DI * fix: spacing * remove servers in app feature flag * Revert "remove servers in app feature flag" This reverts commit 86e284c4bdd6fa42c3c8fbaf1efbec41f4d1c6d2. * fix: qa * feat: remove legacy components from apps/frontend/src/components/ui/servers --------- Co-authored-by: Calum H. (IMB11) <contact@cal.engineer> * qa pass (#5738) * fix: qa * feat: qa * fix: server icon fetch fails due to global node auth race condition overriding each other * fix: lint * fix: server icon upload/sync and centralize logic * fix: server settings modal not closing for server reset * fix: better server sorting * feat: copy address in server listing card * fix: notification panel in modal and when overlapping with action bar * fix: empty server list empty state flashing when refresh, fixed by adding isReady auth flag * feat: use floating action bar for save banner * fix: saving state in save bar * fix: edit server icon styling * fix: confirm modal to have consistent buttons * feat: loading animation for server panel + caching improvements for app * pnpm prepr * feat: search page deduplication (#5754) * fix: action bar behind modal * fix: remove warning modal for stopping * fix: server cards states * we hate webkit we hate webkit * fix: update allocation creation to not use modal * fix: properties tab spacing and styles * feat: add files tab copy * fix: advanced properties icon * fix: remove back to all servers link * feat: add files tab link in copy * fix: server header styles to be consistent with instance * fix: add header icons back * feat: update instance settings icon to be consistent * fix: icon container * feat: upload state persistence across tabs * fix: server labels text wrapping * fix: use surface-5 border * fix: loading spinner showing with onboarding below * feat: new server button shows purchase modal in website * fix: billing page not showing quarterly interval * fix: server downgrade not showing updated subscription notification * fix: server settings invalidate saved state and remove server context provider since its already provided in the page * pnpm prepr * add stripe publishable key to app build * feat: console highlighting * fix: rename servers title to modrinth hosting * feat: search fix * fix: qa/styles * fix: ip click active and remove power dont ask again * fix: qa * feat: highlighting fix console * fix: disable conflicts action * fix: error dismiss bug * feat: modal clarification * fix: files perms issue * fix: lint * feat: modal fix * enable show uptime * fix: add loading state to edit server icon * fix: notification panel take in has sidebar from settings * fix: consistency pass on app settings * fix: consistency pass on instance settings * pnpm prepr * fix: nagivate to billing button in app to go to website * fix: stripe return url in app causing app to open modrinth.com in tauri * refactor: better show polling UI code * fix: new server polling comparison to use server ids instead of length * fix: buttonstyled story * fix: button styling * fix: content.vue regression * feat: project url redirects * fix: breadcrumbs * fix: purchase with newly added card * fix: console ordering problems * fix: app-frontend missing env config and staging environment * fix: log syncing for instances and server panel accidentally * fix: QA issues * fix: server page loading state * fix: stats card logic * fix: lint * fix: qa * fix: console height padding * fix: terminal padding + loading indicator * feat: update medal server listing styling * fix: no upgrade button for medal server listing in app * fix: go to overview instead of content tab after onboarding * fix: qa * fix: teleport modals to body * fix: logs tab + qa * fix: local storage for user preferences * fix: qa loading indic * feat: considitonal debug and trace * fix: jump to top on install bug * feat: swap out server hard drive icon to server stack icon * feat: servers in app feature flag default true * fix: highlight row ufll * fix: webkit thing onto a tag * fix: input field * fix: clear fix * fix: lint * fix: fmt * feat: improve share modal and bring it back for sharing log * pnpm prepr * fix: menu overflowing * feat: remove servers in app feature flag * fix: server stat charts no longer showing color * fix: library nav no primary state * fix: better modal height and width * fix: highlighting bugs * fix: empty states * fix: delay import to fix overview page slow load on MacOS * fix: medal server listing too bright on light mode * fix: admon analysis + fix logs * fix: bug * fix: clear purchase intent from sign-in after closing modal * performance: improve server manage stats loading by splitting reactivity * fix: deploy + admon + disable highlighting * fix: clippy --------- Co-authored-by: tdgao <mr.trumgao@gmail.com> Co-authored-by: Truman Gao <106889354+tdgao@users.noreply.github.com> * feat: temp wrangler * fix: lint * fix: logs upload * fix: console empty state and admon regressions * fix: fields * feat: log deleting + prefetch for Logs.vue * feat: move delete before share * feat: clear endpoint * feat: we ball! --------- Co-authored-by: Calum H. <calum@modrinth.com> Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
444 lines
12 KiB
TypeScript
444 lines
12 KiB
TypeScript
import {
|
|
type Archon,
|
|
clearNodeAuthState,
|
|
setNodeAuthState,
|
|
type UploadState,
|
|
} from '@modrinth/api-client'
|
|
import type { Stats } from '@modrinth/utils'
|
|
import type { ComputedRef, Ref } from 'vue'
|
|
import { computed, reactive, ref, watch } from 'vue'
|
|
|
|
import type { FileOperation } from '../layouts/shared/files-tab/types'
|
|
import { injectModrinthClient, provideModrinthServerContext } from '../providers'
|
|
import type { BusyReason } from '../providers/server-context'
|
|
import { defineMessage } from './i18n'
|
|
import { useModrinthServersConsole } from './server-console'
|
|
|
|
type ReadableRef<T> = Ref<T> | ComputedRef<T>
|
|
type SocketUnsubscriber = () => void
|
|
|
|
type ConnectSocketOptions = {
|
|
force?: boolean
|
|
extraSubscriptions?: (targetServerId: string) => SocketUnsubscriber[]
|
|
}
|
|
|
|
type UseServerManageCoreRuntimeOptions = {
|
|
serverId: ReadableRef<string>
|
|
worldId: ReadableRef<string | null>
|
|
server: ReadableRef<Archon.Servers.v0.Server | null | undefined>
|
|
isSyncingContent: ReadableRef<boolean>
|
|
markBackupCancelled?: (backupId: string) => void
|
|
includeBackupBusyReasons?: boolean
|
|
setDisconnectedOnAuthIncorrect?: boolean
|
|
syncUptimeFromState?: boolean
|
|
incrementUptimeLocally?: boolean
|
|
eventGuard?: () => boolean
|
|
onStateEvent?: (data: Archon.Websocket.v0.WSStateEvent) => void
|
|
}
|
|
|
|
const createInitialStats = (): Stats => ({
|
|
current: {
|
|
cpu_percent: 0,
|
|
ram_usage_bytes: 0,
|
|
ram_total_bytes: 1,
|
|
storage_usage_bytes: 0,
|
|
storage_total_bytes: 0,
|
|
},
|
|
past: {
|
|
cpu_percent: 0,
|
|
ram_usage_bytes: 0,
|
|
ram_total_bytes: 1,
|
|
storage_usage_bytes: 0,
|
|
storage_total_bytes: 0,
|
|
},
|
|
graph: {
|
|
cpu: [],
|
|
ram: [],
|
|
},
|
|
})
|
|
|
|
const appendGraphData = (dataArray: number[], newValue: number): number[] => {
|
|
const updated = [...dataArray, newValue]
|
|
if (updated.length > 10) updated.shift()
|
|
return updated
|
|
}
|
|
|
|
const mapPowerStateFromStateEvent = (
|
|
data: Archon.Websocket.v0.WSStateEvent,
|
|
): Archon.Websocket.v0.PowerState => {
|
|
const powerMap: Record<Archon.Websocket.v0.FlattenedPowerState, Archon.Websocket.v0.PowerState> =
|
|
{
|
|
not_ready: 'stopped',
|
|
starting: 'starting',
|
|
running: 'running',
|
|
stopping: 'stopping',
|
|
idle:
|
|
data.was_oom || (data.exit_code != null && data.exit_code !== 0) ? 'crashed' : 'stopped',
|
|
}
|
|
return powerMap[data.power_variant]
|
|
}
|
|
|
|
export function useServerManageCoreRuntime(options: UseServerManageCoreRuntimeOptions) {
|
|
const client = injectModrinthClient()
|
|
const modrinthServersConsole = useModrinthServersConsole()
|
|
|
|
const shouldProcessEvent = () => (options.eventGuard ? options.eventGuard() : true)
|
|
|
|
const isConnected = ref(false)
|
|
const isWsAuthIncorrect = ref(false)
|
|
const serverPowerState = ref<Archon.Websocket.v0.PowerState>('stopped')
|
|
const powerStateDetails = ref<{ oom_killed?: boolean; exit_code?: number }>()
|
|
const isServerRunning = computed(() => serverPowerState.value === 'running')
|
|
const stats = ref<Stats>(createInitialStats())
|
|
const uptimeSeconds = ref(0)
|
|
const backupsState = reactive(new Map())
|
|
const fsAuth = ref<{ url: string; token: string } | null>(null)
|
|
const fsOps = ref<Archon.Websocket.v0.FilesystemOperation[]>([])
|
|
const fsQueuedOps = ref<Archon.Websocket.v0.QueuedFilesystemOp[]>([])
|
|
const connectedSocketServerId = ref<string | null>(null)
|
|
const socketUnsubscribers = ref<SocketUnsubscriber[]>([])
|
|
const cpuData = ref<number[]>([])
|
|
const ramData = ref<number[]>([])
|
|
|
|
let uptimeIntervalId: ReturnType<typeof setInterval> | null = null
|
|
|
|
const markBackupCancelled =
|
|
options.markBackupCancelled ??
|
|
((backupId: string) => {
|
|
backupsState.delete(backupId)
|
|
})
|
|
|
|
const busyReasons = computed<BusyReason[]>(() => {
|
|
const reasons: BusyReason[] = []
|
|
if (options.server.value?.status === 'installing') {
|
|
reasons.push({
|
|
reason: defineMessage({
|
|
id: 'servers.busy.installing',
|
|
defaultMessage: 'Server is installing',
|
|
}),
|
|
})
|
|
}
|
|
if (options.isSyncingContent.value) {
|
|
reasons.push({
|
|
reason: defineMessage({
|
|
id: 'servers.busy.syncing-content',
|
|
defaultMessage: 'Content sync in progress',
|
|
}),
|
|
})
|
|
}
|
|
if (options.includeBackupBusyReasons) {
|
|
for (const entry of backupsState.values()) {
|
|
if (entry.create?.state === 'ongoing') {
|
|
reasons.push({
|
|
reason: defineMessage({
|
|
id: 'servers.busy.backup-creating',
|
|
defaultMessage: 'Backup creation in progress',
|
|
}),
|
|
})
|
|
break
|
|
}
|
|
if (entry.restore?.state === 'ongoing') {
|
|
reasons.push({
|
|
reason: defineMessage({
|
|
id: 'servers.busy.backup-restoring',
|
|
defaultMessage: 'Backup restore in progress',
|
|
}),
|
|
})
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return reasons
|
|
})
|
|
|
|
const stopUptimeTicker = () => {
|
|
if (uptimeIntervalId) {
|
|
clearInterval(uptimeIntervalId)
|
|
uptimeIntervalId = null
|
|
}
|
|
}
|
|
|
|
const startUptimeTicker = () => {
|
|
if (!options.incrementUptimeLocally || uptimeIntervalId) return
|
|
uptimeIntervalId = setInterval(() => {
|
|
uptimeSeconds.value += 1
|
|
}, 1000)
|
|
}
|
|
|
|
const updateStats = (currentStats: Stats['current']) => {
|
|
if (!shouldProcessEvent()) return
|
|
if (!isConnected.value) isConnected.value = true
|
|
cpuData.value = appendGraphData(cpuData.value, currentStats.cpu_percent)
|
|
ramData.value = appendGraphData(
|
|
ramData.value,
|
|
Math.floor((currentStats.ram_usage_bytes / currentStats.ram_total_bytes) * 100),
|
|
)
|
|
stats.value = {
|
|
current: currentStats,
|
|
past: { ...stats.value.current },
|
|
graph: {
|
|
cpu: cpuData.value,
|
|
ram: ramData.value,
|
|
},
|
|
}
|
|
}
|
|
|
|
const updatePowerState = (
|
|
state: Archon.Websocket.v0.PowerState,
|
|
details?: { oom_killed?: boolean; exit_code?: number },
|
|
) => {
|
|
if (!shouldProcessEvent()) return
|
|
serverPowerState.value = state
|
|
powerStateDetails.value = state === 'crashed' ? details : undefined
|
|
if (state === 'stopped' || state === 'crashed') {
|
|
stopUptimeTicker()
|
|
uptimeSeconds.value = 0
|
|
}
|
|
}
|
|
|
|
const handleLog = (data: Archon.Websocket.v0.WSLogEvent) => {
|
|
if (!shouldProcessEvent()) return
|
|
modrinthServersConsole.addLegacyLog(data.message)
|
|
}
|
|
|
|
const handleLog4j = (data: Archon.Websocket.v0.WSLog4jEvent) => {
|
|
if (!shouldProcessEvent()) return
|
|
modrinthServersConsole.addLog4jEvent(data)
|
|
}
|
|
|
|
const handleStats = (data: Archon.Websocket.v0.WSStatsEvent) => {
|
|
updateStats({
|
|
cpu_percent: data.cpu_percent,
|
|
ram_usage_bytes: data.ram_usage_bytes,
|
|
ram_total_bytes: data.ram_total_bytes,
|
|
storage_usage_bytes: data.storage_usage_bytes,
|
|
storage_total_bytes: data.storage_total_bytes,
|
|
})
|
|
}
|
|
|
|
const handlePowerState = (data: Archon.Websocket.v0.WSPowerStateEvent) => {
|
|
if (data.state === 'crashed') {
|
|
updatePowerState(data.state, {
|
|
oom_killed: data.oom_killed,
|
|
exit_code: data.exit_code,
|
|
})
|
|
} else {
|
|
updatePowerState(data.state)
|
|
}
|
|
}
|
|
|
|
const handleState = (data: Archon.Websocket.v0.WSStateEvent) => {
|
|
if (!shouldProcessEvent()) return
|
|
options.onStateEvent?.(data)
|
|
updatePowerState(mapPowerStateFromStateEvent(data), {
|
|
exit_code: data.exit_code ?? undefined,
|
|
oom_killed: data.was_oom,
|
|
})
|
|
|
|
if (options.syncUptimeFromState && data.uptime > 0) {
|
|
stopUptimeTicker()
|
|
uptimeSeconds.value = data.uptime
|
|
startUptimeTicker()
|
|
}
|
|
}
|
|
|
|
const handleUptime = (data: Archon.Websocket.v0.WSUptimeEvent) => {
|
|
if (!shouldProcessEvent()) return
|
|
stopUptimeTicker()
|
|
uptimeSeconds.value = data.uptime
|
|
startUptimeTicker()
|
|
}
|
|
|
|
const handleAuthIncorrect = () => {
|
|
if (!shouldProcessEvent()) return
|
|
isWsAuthIncorrect.value = true
|
|
if (options.setDisconnectedOnAuthIncorrect) {
|
|
isConnected.value = false
|
|
}
|
|
}
|
|
|
|
const handleAuthOk = () => {
|
|
if (!shouldProcessEvent()) return
|
|
isWsAuthIncorrect.value = false
|
|
isConnected.value = true
|
|
}
|
|
|
|
const clearSocketListeners = () => {
|
|
for (const unsub of socketUnsubscribers.value) unsub()
|
|
socketUnsubscribers.value = []
|
|
}
|
|
|
|
const disconnectSocket = (targetServerId?: string) => {
|
|
if (!targetServerId && !connectedSocketServerId.value) return
|
|
|
|
clearSocketListeners()
|
|
|
|
if (targetServerId) {
|
|
client.archon.sockets.disconnect(targetServerId)
|
|
}
|
|
|
|
stopUptimeTicker()
|
|
connectedSocketServerId.value = null
|
|
isConnected.value = false
|
|
isWsAuthIncorrect.value = false
|
|
serverPowerState.value = 'stopped'
|
|
powerStateDetails.value = undefined
|
|
uptimeSeconds.value = 0
|
|
}
|
|
|
|
const connectSocket = async (
|
|
targetServerId: string,
|
|
connectOptions: ConnectSocketOptions = {},
|
|
): Promise<boolean> => {
|
|
if (
|
|
connectedSocketServerId.value === targetServerId &&
|
|
(isConnected.value || isWsAuthIncorrect.value)
|
|
) {
|
|
return true
|
|
}
|
|
|
|
disconnectSocket(connectedSocketServerId.value ?? undefined)
|
|
|
|
try {
|
|
const safeConnectOptions = connectOptions.force ? { force: true } : undefined
|
|
await client.archon.sockets.safeConnect(targetServerId, safeConnectOptions)
|
|
connectedSocketServerId.value = targetServerId
|
|
isConnected.value = true
|
|
isWsAuthIncorrect.value = false
|
|
|
|
modrinthServersConsole.clear()
|
|
|
|
const baseSubscriptions: SocketUnsubscriber[] = [
|
|
client.archon.sockets.on(targetServerId, 'log', handleLog),
|
|
client.archon.sockets.on(targetServerId, 'log4j', handleLog4j),
|
|
client.archon.sockets.on(targetServerId, 'stats', handleStats),
|
|
client.archon.sockets.on(targetServerId, 'state', handleState),
|
|
client.archon.sockets.on(targetServerId, 'power-state', handlePowerState),
|
|
client.archon.sockets.on(targetServerId, 'uptime', handleUptime),
|
|
client.archon.sockets.on(targetServerId, 'auth-incorrect', handleAuthIncorrect),
|
|
client.archon.sockets.on(targetServerId, 'auth-ok', handleAuthOk),
|
|
]
|
|
const extraSubscriptions = connectOptions.extraSubscriptions?.(targetServerId) ?? []
|
|
socketUnsubscribers.value = [...baseSubscriptions, ...extraSubscriptions]
|
|
return true
|
|
} catch (error) {
|
|
console.error('[hosting/manage] Failed to connect server socket:', error)
|
|
isConnected.value = false
|
|
return false
|
|
}
|
|
}
|
|
|
|
const uploadState = ref<UploadState>({
|
|
isUploading: false,
|
|
currentFileName: null,
|
|
currentFileProgress: 0,
|
|
uploadedBytes: 0,
|
|
totalBytes: 0,
|
|
completedFiles: 0,
|
|
totalFiles: 0,
|
|
})
|
|
const cancelUpload = ref<(() => void) | null>(null)
|
|
|
|
type QueuedOpWithState = Archon.Websocket.v0.QueuedFilesystemOp & { state: 'queued' }
|
|
const dismissedOpIds = ref<Set<string>>(new Set())
|
|
|
|
const activeOperations = computed<FileOperation[]>(() => [
|
|
...fsQueuedOps.value.map((x) => ({ ...x, state: 'queued' }) satisfies QueuedOpWithState),
|
|
...(fsOps.value.filter((op) => !op.id || !dismissedOpIds.value.has(op.id)) as FileOperation[]),
|
|
])
|
|
|
|
async function dismissOperation(opId: string, action: 'dismiss' | 'cancel') {
|
|
if (action === 'dismiss') {
|
|
dismissedOpIds.value = new Set([...dismissedOpIds.value, opId])
|
|
}
|
|
try {
|
|
await client.kyros.files_v0.modifyOperation(opId, action)
|
|
} catch (error) {
|
|
if (action === 'dismiss') return
|
|
console.error(`Failed to ${action} operation:`, error)
|
|
}
|
|
}
|
|
|
|
watch(
|
|
() => fsOps.value,
|
|
(newOps) => {
|
|
for (const op of newOps) {
|
|
if (op.state === 'done' && op.id && !dismissedOpIds.value.has(op.id)) {
|
|
setTimeout(() => {
|
|
dismissOperation(op.id!, 'dismiss')
|
|
}, 3000)
|
|
}
|
|
}
|
|
},
|
|
{ deep: true },
|
|
)
|
|
|
|
const refreshFsAuth = async () => {
|
|
if (!options.serverId.value) {
|
|
fsAuth.value = null
|
|
return
|
|
}
|
|
fsAuth.value = await client.archon.servers_v0.getFilesystemAuth(options.serverId.value)
|
|
}
|
|
|
|
provideModrinthServerContext({
|
|
get serverId() {
|
|
return options.serverId.value
|
|
},
|
|
worldId: options.worldId as Ref<string | null>,
|
|
server: options.server as Ref<Archon.Servers.v0.Server>,
|
|
isConnected,
|
|
isWsAuthIncorrect,
|
|
powerState: serverPowerState,
|
|
powerStateDetails,
|
|
isServerRunning,
|
|
stats,
|
|
uptimeSeconds,
|
|
backupsState,
|
|
markBackupCancelled,
|
|
isSyncingContent: options.isSyncingContent as Ref<boolean>,
|
|
busyReasons,
|
|
fsAuth,
|
|
fsOps,
|
|
fsQueuedOps,
|
|
refreshFsAuth,
|
|
uploadState,
|
|
cancelUpload,
|
|
activeOperations,
|
|
dismissOperation,
|
|
})
|
|
|
|
setNodeAuthState(() => fsAuth.value, refreshFsAuth)
|
|
|
|
const cleanupCoreRuntime = (targetServerId?: string) => {
|
|
disconnectSocket(targetServerId ?? connectedSocketServerId.value ?? undefined)
|
|
clearNodeAuthState()
|
|
}
|
|
|
|
return {
|
|
activeOperations,
|
|
backupsState,
|
|
busyReasons,
|
|
cancelUpload,
|
|
cleanupCoreRuntime,
|
|
connectSocket,
|
|
connectedSocketServerId,
|
|
cpuData,
|
|
disconnectSocket,
|
|
dismissOperation,
|
|
fsAuth,
|
|
fsOps,
|
|
fsQueuedOps,
|
|
isConnected,
|
|
isServerRunning,
|
|
isWsAuthIncorrect,
|
|
powerStateDetails,
|
|
ramData,
|
|
refreshFsAuth,
|
|
serverPowerState,
|
|
stats,
|
|
uptimeSeconds,
|
|
uploadState,
|
|
}
|
|
}
|