cleanup preference repo

This commit is contained in:
rubikscraft 2022-06-27 17:16:42 +02:00
parent ba512c2e5b
commit 34eeb11930
No known key found for this signature in database
GPG key ID: 1463EBE9200A5CD4
5 changed files with 41 additions and 30 deletions

View file

@ -2,13 +2,13 @@ import { Injectable, Logger } from '@nestjs/common';
import {
DecodedPref,
PrefValueType,
PrefValueTypeStrings,
PrefValueTypeStrings
} from 'picsur-shared/dist/dto/preferences.dto';
import {
AsyncFailable,
Fail,
Failable,
HasFailed,
HasFailed
} from 'picsur-shared/dist/types';
type Enum = Record<string, string>;
@ -16,7 +16,7 @@ type EnumValue<E> = E[keyof E];
type PrefValueTypeType<E extends Enum> = {
[key in EnumValue<E>]: PrefValueTypeStrings;
};
type KeyValuePref = {
type EncodedPref = {
key: string;
value: string;
};
@ -25,8 +25,13 @@ type KeyValuePref = {
export class PreferenceCommonService {
private readonly logger = new Logger('PreferenceCommonService');
public validateAndUnpackPref<E extends Enum>(
preference: KeyValuePref,
// Preferences values are only validated upon encoding, not decoding
// The preference keys are always validated
// E is either the SysPreference or the UsrPreference enum
// the pref value types is the object containing the type of each key in E
public DecodePref<E extends Enum>(
preference: EncodedPref,
prefType: E,
prefValueTypes: PrefValueTypeType<E>,
): Failable<DecodedPref> {
@ -58,17 +63,17 @@ export class PreferenceCommonService {
return Fail('Invalid preference value');
}
public async validatePref<E extends Enum>(
public async EncodePref<E extends Enum>(
key: string,
value: PrefValueType,
prefType: E,
prefValueTypes: PrefValueTypeType<E>,
): AsyncFailable<KeyValuePref> {
): AsyncFailable<EncodedPref> {
const validatedKey = this.validatePrefKey(key, prefType);
if (HasFailed(validatedKey)) return validatedKey;
const valueType = prefValueTypes[validatedKey];
const validatedValue = this.validateAndPackPrefValue(value, valueType);
const validatedValue = this.encodePrefValue(value, valueType);
if (HasFailed(validatedValue)) return validatedValue;
return {
@ -89,7 +94,7 @@ export class PreferenceCommonService {
return key as V;
}
public validateAndPackPrefValue(
public encodePrefValue(
value: PrefValueType,
expectedType: PrefValueTypeStrings,
): Failable<string> {

View file

@ -5,8 +5,9 @@ import { UsrPreference } from 'picsur-shared/dist/dto/usr-preferences.enum';
import { generateRandomString } from 'picsur-shared/dist/util/random';
import { EarlyJwtConfigService } from '../../config/early/early-jwt.config.service';
// This specific service is used to store default values for system preferences
// This specific service holds the default values for system and user preferences
// It needs to be in a service because the values depend on the environment
// This environment is not loaded outside of services
@Injectable()
export class PreferenceDefaultsService {

View file

@ -36,7 +36,7 @@ export class SysPreferenceService {
value: PrefValueType,
): AsyncFailable<DecodedSysPref> {
// Validate
let sysPreference = await this.validateSysPref(key, value);
let sysPreference = await this.encodeSysPref(key, value);
if (HasFailed(sysPreference)) return sysPreference;
// Set
@ -49,7 +49,6 @@ export class SysPreferenceService {
return Fail(e);
}
// Return
return {
key: sysPreference.key,
value,
@ -63,8 +62,9 @@ export class SysPreferenceService {
let validatedKey = this.prefCommon.validatePrefKey(key, SysPreference);
if (HasFailed(validatedKey)) return validatedKey;
// See the comment in 'mutex-fallback.ts' for why we are using a mutex here
return MutexFallBack(
'fetchSysPrefrence',
`fetchSysPrefrence-${key}`,
async () => {
let existing: ESysPreferenceBackend | null;
try {
@ -84,7 +84,7 @@ export class SysPreferenceService {
}
// Return
return this.prefCommon.validateAndUnpackPref(
return this.prefCommon.DecodePref(
result.data,
SysPreference,
SysPreferenceValueTypes,
@ -106,6 +106,7 @@ export class SysPreferenceService {
return this.getPreferencePinned(key, 'boolean') as AsyncFailable<boolean>;
}
// Get a preference that will be pinned to a specified type
private async getPreferencePinned(
key: string,
type: PrefValueTypeStrings,
@ -137,11 +138,11 @@ export class SysPreferenceService {
return this.setPreference(key, this.defaultsService.sysDefaults[key]());
}
private async validateSysPref(
private async encodeSysPref(
key: string,
value: PrefValueType,
): AsyncFailable<ESysPreferenceBackend> {
const validated = await this.prefCommon.validatePref(
const validated = await this.prefCommon.EncodePref(
key,
value,
SysPreference,

View file

@ -37,7 +37,7 @@ export class UsrPreferenceService {
value: PrefValueType,
): AsyncFailable<DecodedUsrPref> {
// Validate
let usrPreference = await this.validatePref(userid, key, value);
let usrPreference = await this.encodeUsrPref(userid, key, value);
if (HasFailed(usrPreference)) return usrPreference;
// Set
@ -68,6 +68,7 @@ export class UsrPreferenceService {
let validatedKey = this.prefCommon.validatePrefKey(key, UsrPreference);
if (HasFailed(validatedKey)) return validatedKey;
// See the comment in 'mutex-fallback.ts' for why we are using a mutex here
return MutexFallBack(
'fetchUsrPrefrence',
async () => {
@ -89,7 +90,7 @@ export class UsrPreferenceService {
}
// Return
const unpacked = this.prefCommon.validateAndUnpackPref(
const unpacked = this.prefCommon.DecodePref(
result.data,
UsrPreference,
UsrPreferenceValueTypes,
@ -137,6 +138,7 @@ export class UsrPreferenceService {
) as AsyncFailable<boolean>;
}
// Get a preference that will be pinned to a specified type
private async getPreferencePinned(
userid: string,
key: string,
@ -176,12 +178,12 @@ export class UsrPreferenceService {
);
}
private async validatePref(
private async encodeUsrPref(
userid: string,
key: string,
value: PrefValueType,
): AsyncFailable<EUsrPreferenceBackend> {
const validated = await this.prefCommon.validatePref(
const validated = await this.prefCommon.EncodePref(
key,
value,
UsrPreference,

View file

@ -1,11 +1,12 @@
/*
This function is necessary to make sure that a default isnt generated multiple times at the same time.
This function is necessary to make sure that a default isn't generated multiple times at the same time.
Doing that will cause errors.
An example is the jwt secret value, its value is requested aroun 3 times at the same time while starting.
An example is the jwt secret value, it's value is requested around 3 times at the same time while starting.
So when the program was started for the first time, each request returned a different secret.
This function will first try and see if its first function returns a value, if it does, it will return that value.
This function will try and see if its first function returns a value, if it does, it will return that value.
(A Failure object will be seen as a value, only null and undefined are counted as non-values)
If not it will execute a fallback function, which usually is a function that populates a default value.
After that is done it will retry the first function again.
*/
@ -20,21 +21,22 @@ export async function MutexFallBack<
const try_it = await mainFunc();
if (try_it !== undefined && try_it !== null) return try_it;
// Check if a fallback is already running, if so wait on that
if (fallBackMap[key] !== undefined) {
await fallBackMap[key];
// When it is done, try again
return MutexFallBack(key, mainFunc, fallBackFunc);
}
// No fallback is running, start one
const fallBackPromise = fallBackFunc();
// Save the running fallback, and make sure it is cleared when it is done
fallBackMap[key] = fallBackPromise;
fallBackMap[key]
.then(() => {
delete fallBackMap[key];
})
.catch(() => {
delete fallBackMap[key];
});
fallBackMap[key].finally(() => {
delete fallBackMap[key];
});
return fallBackPromise;
}