feat(server): runtime service config (#7644)

This commit is contained in:
liuyi
2024-07-30 14:58:24 +08:00
committed by GitHub
parent 67248316bd
commit fcf0ecbaa2
8 changed files with 136 additions and 10 deletions
@@ -12,6 +12,7 @@ AFFiNE.ENV_MAP = {
MAILER_PASSWORD: 'mailer.auth.pass', MAILER_PASSWORD: 'mailer.auth.pass',
MAILER_SENDER: 'mailer.from.address', MAILER_SENDER: 'mailer.from.address',
MAILER_SECURE: ['mailer.secure', 'boolean'], MAILER_SECURE: ['mailer.secure', 'boolean'],
DATABASE_URL: 'database.datasourceUrl',
OAUTH_GOOGLE_CLIENT_ID: 'plugins.oauth.providers.google.clientId', OAUTH_GOOGLE_CLIENT_ID: 'plugins.oauth.providers.google.clientId',
OAUTH_GOOGLE_CLIENT_SECRET: 'plugins.oauth.providers.google.clientSecret', OAUTH_GOOGLE_CLIENT_SECRET: 'plugins.oauth.providers.google.clientSecret',
OAUTH_GITHUB_CLIENT_ID: 'plugins.oauth.providers.github.clientId', OAUTH_GITHUB_CLIENT_ID: 'plugins.oauth.providers.github.clientId',
@@ -2,10 +2,18 @@ import './config';
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { ServerConfigResolver, ServerRuntimeConfigResolver } from './resolver'; import {
ServerConfigResolver,
ServerRuntimeConfigResolver,
ServerServiceConfigResolver,
} from './resolver';
@Module({ @Module({
providers: [ServerConfigResolver, ServerRuntimeConfigResolver], providers: [
ServerConfigResolver,
ServerRuntimeConfigResolver,
ServerServiceConfigResolver,
],
}) })
export class ServerConfigModule {} export class ServerConfigModule {}
export { ADD_ENABLED_FEATURES, ServerConfigType } from './resolver'; export { ADD_ENABLED_FEATURES, ServerConfigType } from './resolver';
@@ -175,11 +175,42 @@ export class ServerConfigResolver {
} }
} }
@ObjectType()
class ServerServiceConfig {
@Field()
name!: string;
@Field(() => GraphQLJSONObject)
config!: any;
}
interface ServerServeConfig {
https: boolean;
host: string;
port: number;
externalUrl: string;
}
interface ServerMailerConfig {
host?: string | null;
port?: number | null;
secure?: boolean | null;
service?: string | null;
sender?: string | null;
}
interface ServerDatabaseConfig {
host: string;
port: number;
user?: string | null;
database: string;
}
@Admin()
@Resolver(() => ServerRuntimeConfigType) @Resolver(() => ServerRuntimeConfigType)
export class ServerRuntimeConfigResolver { export class ServerRuntimeConfigResolver {
constructor(private readonly config: Config) {} constructor(private readonly config: Config) {}
@Admin()
@Query(() => [ServerRuntimeConfigType], { @Query(() => [ServerRuntimeConfigType], {
description: 'get all server runtime configurable settings', description: 'get all server runtime configurable settings',
}) })
@@ -187,7 +218,6 @@ export class ServerRuntimeConfigResolver {
return this.config.runtime.list(); return this.config.runtime.list();
} }
@Admin()
@Mutation(() => ServerRuntimeConfigType, { @Mutation(() => ServerRuntimeConfigType, {
description: 'update server runtime configurable setting', description: 'update server runtime configurable setting',
}) })
@@ -198,7 +228,6 @@ export class ServerRuntimeConfigResolver {
return await this.config.runtime.set(id as any, value); return await this.config.runtime.set(id as any, value);
} }
@Admin()
@Mutation(() => [ServerRuntimeConfigType], { @Mutation(() => [ServerRuntimeConfigType], {
description: 'update multiple server runtime configurable settings', description: 'update multiple server runtime configurable settings',
}) })
@@ -213,3 +242,57 @@ export class ServerRuntimeConfigResolver {
return results; return results;
} }
} }
@Admin()
@Resolver(() => ServerServiceConfig)
export class ServerServiceConfigResolver {
constructor(private readonly config: Config) {}
@Query(() => [ServerServiceConfig])
serverServiceConfigs() {
return [
{
name: 'server',
config: this.serve(),
},
{
name: 'mailer',
config: this.mail(),
},
{
name: 'database',
config: this.database(),
},
];
}
serve(): ServerServeConfig {
return this.config.server;
}
mail(): ServerMailerConfig {
const sender =
typeof this.config.mailer.from === 'string'
? this.config.mailer.from
: this.config.mailer.from?.address;
return {
host: this.config.mailer.host,
port: this.config.mailer.port,
secure: this.config.mailer.secure,
service: this.config.mailer.service,
sender,
};
}
database(): ServerDatabaseConfig {
const url = new URL(this.config.database.datasourceUrl);
return {
host: url.hostname,
port: Number(url.port),
user: url.username,
database: url.pathname.slice(1) ?? url.username,
};
}
}
@@ -0,0 +1,17 @@
import type { Prisma } from '@prisma/client';
import { defineStartupConfig, ModuleConfig } from '../config';
interface PrismaStartupConfiguration extends Prisma.PrismaClientOptions {
datasourceUrl: string;
}
declare module '../config' {
interface AppConfig {
database: ModuleConfig<PrismaStartupConfiguration>;
}
}
defineStartupConfig('database', {
datasourceUrl: '',
});
@@ -1,18 +1,22 @@
import './config';
import { Global, Module, Provider } from '@nestjs/common'; import { Global, Module, Provider } from '@nestjs/common';
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
import { Config } from '../config';
import { PrismaService } from './service'; import { PrismaService } from './service';
// only `PrismaClient` can be injected // only `PrismaClient` can be injected
const clientProvider: Provider = { const clientProvider: Provider = {
provide: PrismaClient, provide: PrismaClient,
useFactory: () => { useFactory: (config: Config) => {
if (PrismaService.INSTANCE) { if (PrismaService.INSTANCE) {
return PrismaService.INSTANCE; return PrismaService.INSTANCE;
} }
return new PrismaService(); return new PrismaService(config.database);
}, },
inject: [Config],
}; };
@Global() @Global()
@@ -1,6 +1,6 @@
import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common'; import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client'; import { Prisma, PrismaClient } from '@prisma/client';
@Injectable() @Injectable()
export class PrismaService export class PrismaService
@@ -9,8 +9,8 @@ export class PrismaService
{ {
static INSTANCE: PrismaService | null = null; static INSTANCE: PrismaService | null = null;
constructor() { constructor(opts: Prisma.PrismaClientOptions) {
super(); super(opts);
PrismaService.INSTANCE = this; PrismaService.INSTANCE = this;
} }
+6
View File
@@ -541,6 +541,7 @@ type Query {
"""get all server runtime configurable settings""" """get all server runtime configurable settings"""
serverRuntimeConfig: [ServerRuntimeConfigType!]! serverRuntimeConfig: [ServerRuntimeConfigType!]!
serverServiceConfigs: [ServerServiceConfig!]!
"""Get user by email""" """Get user by email"""
user(email: String!): UserOrLimitedUser user(email: String!): UserOrLimitedUser
@@ -663,6 +664,11 @@ type ServerRuntimeConfigType {
value: JSON! value: JSON!
} }
type ServerServiceConfig {
config: JSONObject!
name: String!
}
type SubscriptionAlreadyExistsDataType { type SubscriptionAlreadyExistsDataType {
plan: String! plan: String!
} }
+7
View File
@@ -798,6 +798,7 @@ export interface Query {
serverConfig: ServerConfigType; serverConfig: ServerConfigType;
/** get all server runtime configurable settings */ /** get all server runtime configurable settings */
serverRuntimeConfig: Array<ServerRuntimeConfigType>; serverRuntimeConfig: Array<ServerRuntimeConfigType>;
serverServiceConfigs: Array<ServerServiceConfig>;
/** Get user by email */ /** Get user by email */
user: Maybe<UserOrLimitedUser>; user: Maybe<UserOrLimitedUser>;
/** Get user by id */ /** Get user by id */
@@ -952,6 +953,12 @@ export interface ServerRuntimeConfigType {
value: Scalars['JSON']['output']; value: Scalars['JSON']['output'];
} }
export interface ServerServiceConfig {
__typename?: 'ServerServiceConfig';
config: Scalars['JSONObject']['output'];
name: Scalars['String']['output'];
}
export interface SubscriptionAlreadyExistsDataType { export interface SubscriptionAlreadyExistsDataType {
__typename?: 'SubscriptionAlreadyExistsDataType'; __typename?: 'SubscriptionAlreadyExistsDataType';
plan: Scalars['String']['output']; plan: Scalars['String']['output'];