mirror of
https://github.com/unraid/api.git
synced 2026-05-09 08:41:12 -05:00
feat: working
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
18.19.1
|
||||
v22.10.0
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
###########################################################
|
||||
# Development/Build Image
|
||||
###########################################################
|
||||
FROM node:18.19.1-bookworm-slim As development
|
||||
FROM node:22-bookworm-slim As development
|
||||
|
||||
# Install build tools and dependencies
|
||||
RUN apt-get update -y && apt-get install -y \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[api]
|
||||
version="3.11.0+04f7b636"
|
||||
version="THIS_WILL_BE_REPLACED_WHEN_BUILT"
|
||||
extraOrigins="https://google.com,https://test.com"
|
||||
[local]
|
||||
[notifier]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[api]
|
||||
version="3.11.0+04f7b636"
|
||||
version="THIS_WILL_BE_REPLACED_WHEN_BUILT"
|
||||
extraOrigins="https://google.com,https://test.com"
|
||||
[local]
|
||||
[notifier]
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@
|
||||
"install:unraid": "./scripts/install-in-unraid.sh",
|
||||
"start:plugin": "INTROSPECTION=true LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug",
|
||||
"start:plugin-verbose": "LOG_CONTEXT=true LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug",
|
||||
"start:tsx": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace DOTENV_CONFIG_PATH=./.env.staging tsx -r dotenv/config src/cli.ts start --debug",
|
||||
"start:tsx": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace DOTENV_CONFIG_PATH=./.env.development tsx -r dotenv/config src/cli.ts start --debug",
|
||||
"start:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs start --debug'",
|
||||
"restart:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs restart --debug'",
|
||||
"stop:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs stop --debug'",
|
||||
|
||||
+9
-4
@@ -4,8 +4,13 @@ import { am } from 'am';
|
||||
import { main } from '@app/cli/index';
|
||||
import { internalLogger } from '@app/core/log';
|
||||
|
||||
void am(main, (error: unknown) => {
|
||||
internalLogger.fatal((error as Error).message);
|
||||
// Ensure process is exited
|
||||
try {
|
||||
await main();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
internalLogger.error({
|
||||
message: 'Failed to start unraid-api',
|
||||
error,
|
||||
});
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -13,14 +13,10 @@ import {
|
||||
type getServersQuery,
|
||||
type getCloudQuery,
|
||||
} from '../../graphql/generated/api/operations';
|
||||
import {
|
||||
type ApolloQueryResult,
|
||||
type ApolloClient,
|
||||
type NormalizedCacheObject,
|
||||
} from '@apollo/client/core/core.cjs';
|
||||
import { MinigraphStatus } from '@app/graphql/generated/api/types';
|
||||
import { API_VERSION } from '@app/environment';
|
||||
import { loadStateFiles } from '@app/store/modules/emhttp';
|
||||
import { ApolloClient, ApolloQueryResult, NormalizedCacheObject } from '@apollo/client/core';
|
||||
|
||||
type CloudQueryResult = NonNullable<
|
||||
ApolloQueryResult<getCloudQuery>['data']['cloud']
|
||||
|
||||
@@ -12,7 +12,6 @@ import { API_VERSION } from '@app/environment';
|
||||
*/
|
||||
export const start = async () => {
|
||||
// Set process title
|
||||
|
||||
process.title = 'unraid-api';
|
||||
const runningProcesses = await getAllUnraidApiPids();
|
||||
if (runningProcesses.length > 0) {
|
||||
@@ -24,8 +23,6 @@ export const start = async () => {
|
||||
// Start API
|
||||
cliLogger.info('Starting unraid-api@v%s', API_VERSION);
|
||||
|
||||
// If we're in debug mode or we're NOT
|
||||
console.log(mainOptions);
|
||||
// in debug but ARE in the child process
|
||||
if (mainOptions.debug || process.env._DAEMONIZE_PROCESS) {
|
||||
// Log when the API exits
|
||||
@@ -52,10 +49,10 @@ export const start = async () => {
|
||||
logToSyslog('✔️ UNRAID API started successfully!');
|
||||
}
|
||||
|
||||
console.log(mainOptions);
|
||||
await import ('@app/index.ts');
|
||||
|
||||
await import ('@app/index.ts');
|
||||
if (!mainOptions.debug) {
|
||||
console.log('Daemonizing process. %s %o', process.execPath, process.argv);
|
||||
if ('_DAEMONIZE_PROCESS' in process.env) {
|
||||
// In the child, clean up the tracking environment variable
|
||||
delete process.env._DAEMONIZE_PROCESS;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { gql, QueryOptions } from "@apollo/client/core";
|
||||
|
||||
interface ParsedQuery {
|
||||
query?: string;
|
||||
variables?: Record<string, string>;
|
||||
}
|
||||
|
||||
export const parseGraphQLQuery = (body: string): QueryOptions => {
|
||||
try {
|
||||
const parsedBody: ParsedQuery = JSON.parse(body);
|
||||
if (
|
||||
parsedBody.query &&
|
||||
parsedBody.variables &&
|
||||
typeof parsedBody.variables === 'object'
|
||||
) {
|
||||
return {
|
||||
query: gql(parsedBody.query),
|
||||
variables: parsedBody.variables,
|
||||
};
|
||||
}
|
||||
throw new Error('Invalid Body');
|
||||
} catch (error) {
|
||||
throw new Error('Invalid Body Provided');
|
||||
}
|
||||
};
|
||||
@@ -2,8 +2,8 @@ import { join } from 'path';
|
||||
import { loadFilesSync } from '@graphql-tools/load-files';
|
||||
import { mergeTypeDefs } from '@graphql-tools/merge';
|
||||
|
||||
const files = loadFilesSync(join(import.meta.dirname, '../src/graphql/schema/types'), {
|
||||
const files = loadFilesSync(join(import.meta.dirname, './types'), {
|
||||
extensions: ['graphql'],
|
||||
});
|
||||
|
||||
export const typeDefs = mergeTypeDefs(files);
|
||||
export const typeDefs = mergeTypeDefs(files);
|
||||
+58
-62
@@ -1,7 +1,6 @@
|
||||
import 'reflect-metadata';
|
||||
import 'global-agent/bootstrap';
|
||||
|
||||
import { am } from 'am';
|
||||
import http from 'http';
|
||||
import https from 'https';
|
||||
import CacheableLookup from 'cacheable-lookup';
|
||||
@@ -31,90 +30,87 @@ import { setupLogRotation } from '@app/core/logrotate/setup-logrotate';
|
||||
import { WebSocket } from 'ws';
|
||||
import * as env from '@app/environment';
|
||||
|
||||
let server: NestFastifyApplication<RawServerDefault>;
|
||||
let server: NestFastifyApplication<RawServerDefault> | null = null;
|
||||
|
||||
const unlinkUnixPort = () => {
|
||||
if (isNaN(parseInt(PORT, 10))) {
|
||||
if (fileExistsSync(PORT)) unlinkSync(PORT);
|
||||
}
|
||||
};
|
||||
// Boot app
|
||||
void am(
|
||||
async () => {
|
||||
environment.IS_MAIN_PROCESS = true;
|
||||
try {
|
||||
environment.IS_MAIN_PROCESS = true;
|
||||
|
||||
logger.debug('ENV %o', env);
|
||||
logger.debug('ENV %o', env);
|
||||
|
||||
const cacheable = new CacheableLookup();
|
||||
const cacheable = new CacheableLookup();
|
||||
|
||||
Object.assign(global, { WebSocket });
|
||||
// Ensure all DNS lookups are cached for their TTL
|
||||
cacheable.install(http.globalAgent);
|
||||
cacheable.install(https.globalAgent);
|
||||
|
||||
Object.assign(global, { WebSocket });
|
||||
// Ensure all DNS lookups are cached for their TTL
|
||||
cacheable.install(http.globalAgent);
|
||||
cacheable.install(https.globalAgent);
|
||||
// Start file <-> store sync
|
||||
// Must occur before config is loaded to ensure that the handler can fix broken configs
|
||||
await startStoreSync();
|
||||
|
||||
// Start file <-> store sync
|
||||
// Must occur before config is loaded to ensure that the handler can fix broken configs
|
||||
await startStoreSync();
|
||||
await setupLogRotation();
|
||||
|
||||
await setupLogRotation();
|
||||
// Load my servers config file into store
|
||||
await store.dispatch(loadConfigFile());
|
||||
|
||||
// Load my servers config file into store
|
||||
await store.dispatch(loadConfigFile());
|
||||
// Load emhttp state into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
|
||||
// Load emhttp state into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
// Load initial registration key into store
|
||||
await store.dispatch(loadRegistrationKey());
|
||||
|
||||
// Load initial registration key into store
|
||||
await store.dispatch(loadRegistrationKey());
|
||||
// Load my dynamix config file into store
|
||||
await store.dispatch(loadDynamixConfigFile());
|
||||
|
||||
// Load my dynamix config file into store
|
||||
await store.dispatch(loadDynamixConfigFile());
|
||||
// Start listening to file updates
|
||||
StateManager.getInstance();
|
||||
|
||||
// Start listening to file updates
|
||||
StateManager.getInstance();
|
||||
// Start listening to key file changes
|
||||
setupRegistrationKeyWatch();
|
||||
|
||||
// Start listening to key file changes
|
||||
setupRegistrationKeyWatch();
|
||||
// Start listening to docker events
|
||||
setupVarRunWatch();
|
||||
|
||||
// Start listening to docker events
|
||||
setupVarRunWatch();
|
||||
// Start listening to dynamix config file changes
|
||||
setupDynamixConfigWatch();
|
||||
|
||||
// Start listening to dynamix config file changes
|
||||
setupDynamixConfigWatch();
|
||||
// Disabled until we need the access token to work
|
||||
// TokenRefresh.init();
|
||||
|
||||
// Disabled until we need the access token to work
|
||||
// TokenRefresh.init();
|
||||
// If port is unix socket, delete old socket before starting http server
|
||||
unlinkUnixPort();
|
||||
|
||||
// If port is unix socket, delete old socket before starting http server
|
||||
// Start webserver
|
||||
server = await bootstrapNestServer();
|
||||
PingTimeoutJobs.init();
|
||||
|
||||
startMiddlewareListeners();
|
||||
|
||||
await validateApiKeyIfPresent();
|
||||
|
||||
// On process exit stop HTTP server - this says it supports async but it doesnt seem to
|
||||
exitHook(() => {
|
||||
server?.close?.();
|
||||
// If port is unix socket, delete socket before exiting
|
||||
unlinkUnixPort();
|
||||
|
||||
// Start webserver
|
||||
server = await bootstrapNestServer();
|
||||
PingTimeoutJobs.init();
|
||||
|
||||
startMiddlewareListeners();
|
||||
|
||||
await validateApiKeyIfPresent();
|
||||
|
||||
// On process exit stop HTTP server - this says it supports async but it doesnt seem to
|
||||
exitHook(() => {
|
||||
server?.close?.();
|
||||
// If port is unix socket, delete socket before exiting
|
||||
unlinkUnixPort();
|
||||
|
||||
shutdownApiEvent();
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
},
|
||||
async (error: NodeJS.ErrnoException) => {
|
||||
logger.error('API-GLOBAL-ERROR %s %s', error.message, error.stack);
|
||||
if (server) {
|
||||
await server?.close?.();
|
||||
}
|
||||
shutdownApiEvent();
|
||||
// Kill application
|
||||
process.exit(1);
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
logger.error('API-ERROR %s %s', error.message, error.stack);
|
||||
}
|
||||
);
|
||||
if (server) {
|
||||
await server?.close?.();
|
||||
}
|
||||
shutdownApiEvent();
|
||||
// Kill application
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
ApolloClient,
|
||||
InMemoryCache,
|
||||
type NormalizedCacheObject,
|
||||
} from '@apollo/client/core/core.cjs';
|
||||
} from '@apollo/client/core';
|
||||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
||||
import { MinigraphStatus } from '@app/graphql/generated/api/types';
|
||||
import { API_VERSION } from '@app/environment';
|
||||
|
||||
+2
-1
@@ -38,6 +38,7 @@
|
||||
], /* List of folders to include type definitions from. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
|
||||
"resolveJsonModule": false
|
||||
"resolveJsonModule": false,
|
||||
"allowImportingTsExtensions": true
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,3 @@
|
||||
import type {
|
||||
split as SplitType,
|
||||
ApolloClient as ApolloClientType,
|
||||
NormalizedCacheObject,
|
||||
} from "@apollo/client";
|
||||
|
||||
import {
|
||||
from,
|
||||
ApolloClient,
|
||||
@@ -85,7 +79,7 @@ const retryLink = new RetryLink({
|
||||
},
|
||||
});
|
||||
|
||||
const splitLinks = (split as typeof SplitType)(
|
||||
const splitLinks = split(
|
||||
({ query }) => {
|
||||
const definition = getMainDefinition(query);
|
||||
return (
|
||||
@@ -103,7 +97,7 @@ const splitLinks = (split as typeof SplitType)(
|
||||
*/
|
||||
const additiveLink = from([errorLink, retryLink, splitLinks]);
|
||||
|
||||
const client: ApolloClientType<NormalizedCacheObject> = new ApolloClient({
|
||||
const client = new ApolloClient({
|
||||
link: additiveLink,
|
||||
cache: createApolloCache(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user