-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(server): runtime setting support
- Loading branch information
Showing
7 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
packages/backend/server/migrations/20240115072744_runtime_setting/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
-- CreateTable | ||
CREATE TABLE "application_settings" ( | ||
"key" VARCHAR(36) NOT NULL, | ||
"value" TEXT NOT NULL, | ||
|
||
CONSTRAINT "application_settings_pkey" PRIMARY KEY ("key") | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Injectable, Provider } from '@nestjs/common'; | ||
|
||
import { Config } from '../config'; | ||
|
||
export interface RuntimeConfigs { | ||
enablePayment: boolean; | ||
defaultPasswordLogin: boolean; | ||
} | ||
|
||
export type RuntimeConfigKey = keyof RuntimeConfigs; | ||
export type RuntimeConfig<T extends RuntimeConfigKey> = RuntimeConfigs[T]; | ||
|
||
@Injectable() | ||
export class DefaultRuntimeConfigs implements RuntimeConfigs { | ||
enablePayment = true; | ||
enableQuota = true; | ||
defaultPasswordLogin = false; | ||
} | ||
|
||
export class SelfHostDefaultRuntimeConfigs extends DefaultRuntimeConfigs { | ||
override enablePayment = false; | ||
override enableQuota = false; | ||
override defaultPasswordLogin = true; | ||
} | ||
|
||
export const DefaultRuntimeConfigsProvider: Provider = { | ||
provide: DefaultRuntimeConfigs, | ||
useFactory: (config: Config) => { | ||
if (config.flavor === 'selfhosted') { | ||
return new SelfHostDefaultRuntimeConfigs(); | ||
} else { | ||
return new DefaultRuntimeConfigs(); | ||
} | ||
}, | ||
inject: [Config], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Global, Module } from '@nestjs/common'; | ||
|
||
import { DefaultRuntimeConfigsProvider } from './def'; | ||
import { Runtime } from './service'; | ||
|
||
@Global() | ||
@Module({ | ||
providers: [Runtime, DefaultRuntimeConfigsProvider], | ||
exports: [Runtime], | ||
}) | ||
export class RuntimeSettingModule {} | ||
export { Runtime }; |
107 changes: 107 additions & 0 deletions
107
packages/backend/server/src/fundamentals/runtime/service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { PrismaClient } from '@prisma/client'; | ||
|
||
import { Cache } from '../cache'; | ||
import { Config } from '../config'; | ||
import { | ||
DefaultRuntimeConfigs, | ||
type RuntimeConfig, | ||
type RuntimeConfigKey, | ||
} from './def'; | ||
|
||
/** | ||
* runtime.get(k) | ||
* runtime.set(k, v) | ||
* runtime.update(k, (v) => { | ||
* | ||
* }) | ||
*/ | ||
export class Runtime { | ||
constructor( | ||
public readonly config: Config, | ||
private readonly db: PrismaClient, | ||
private readonly cache: Cache, | ||
private readonly defaultConfigs: DefaultRuntimeConfigs | ||
) {} | ||
|
||
async get<K extends RuntimeConfigKey, V extends RuntimeConfig<K>>( | ||
k: K | ||
): Promise<V> { | ||
const cached = await this.loadCache<K, V>(k); | ||
|
||
if (cached) { | ||
return cached; | ||
} | ||
|
||
const dbValue = await this.loadDb<K, V>(k); | ||
|
||
if (!dbValue) { | ||
throw new Error(`Runtime config ${k} not found`); | ||
} | ||
|
||
await this.setCache(k, dbValue); | ||
|
||
return dbValue; | ||
} | ||
|
||
async set<K extends RuntimeConfigKey, V extends RuntimeConfig<K>>( | ||
k: K, | ||
v: V | ||
) { | ||
await this.db.applicationSetting.upsert({ | ||
where: { | ||
key: k, | ||
}, | ||
create: { | ||
key: k, | ||
value: JSON.stringify(v), | ||
}, | ||
update: { | ||
value: JSON.stringify(v), | ||
}, | ||
}); | ||
|
||
await this.setCache(k, v); | ||
} | ||
|
||
async update<K extends RuntimeConfigKey, V extends RuntimeConfig<K>>( | ||
k: K, | ||
modifier: (v: V) => V | Promise<V> | ||
) { | ||
const data = await this.loadDb<K, V>(k); | ||
|
||
const updated = await modifier(data); | ||
|
||
await this.set(k, updated); | ||
|
||
return updated; | ||
} | ||
|
||
async loadDb<K extends RuntimeConfigKey, V extends RuntimeConfig<K>>( | ||
k: K | ||
): Promise<V> { | ||
const v = await this.db.applicationSetting.findUnique({ | ||
where: { | ||
key: k, | ||
}, | ||
}); | ||
|
||
if (v) { | ||
return JSON.parse(v.value); | ||
} else { | ||
return this.defaultConfigs[k] as V; | ||
} | ||
} | ||
|
||
async loadCache<K extends RuntimeConfigKey, V extends RuntimeConfig<K>>( | ||
k: K | ||
): Promise<V | undefined> { | ||
return this.cache.get<V>(`runtime:${k}`); | ||
} | ||
|
||
async setCache<K extends RuntimeConfigKey, V extends RuntimeConfig<K>>( | ||
k: K, | ||
v: V | ||
): Promise<boolean> { | ||
return this.cache.set<V>(k, v, { ttl: 60 * 1000 }); | ||
} | ||
} |