Compare commits
2 Commits
4f6b573100
...
a37fd81052
Author | SHA1 | Date | |
---|---|---|---|
a37fd81052 | |||
26175ce357 |
@ -1,6 +1,7 @@
|
|||||||
import { LoggerMasterOptions, LoggerClientOptions } from '@navy.gif/logger';
|
import { LoggerMasterOptions, LoggerClientOptions } from '@navy.gif/logger';
|
||||||
import { ServerOptions } from './Server.js';
|
import { ServerOptions } from './Server.js';
|
||||||
import { DatabaseOptions, DiscordOptions } from './Other.js';
|
import { DatabaseOptions, DiscordOptions } from './Other.js';
|
||||||
|
import { BrokerOptions } from '@navy.gif/wrappers';
|
||||||
|
|
||||||
type Env = {
|
type Env = {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
@ -25,5 +26,6 @@ export type ControllerOptions = {
|
|||||||
discord: DiscordOptions,
|
discord: DiscordOptions,
|
||||||
databases: DatabaseOptions,
|
databases: DatabaseOptions,
|
||||||
env: Env,
|
env: Env,
|
||||||
srcDir: string
|
srcDir: string,
|
||||||
|
rabbitConfig: BrokerOptions
|
||||||
}
|
}
|
11
@types/Flags.ts
Normal file
11
@types/Flags.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export type FlagType = string | number | boolean | number[] | null
|
||||||
|
export type FlagEnv = 'test' | 'prod'
|
||||||
|
export type FlagConsumer = 'client' | 'server' | 'api'
|
||||||
|
|
||||||
|
export type FlagData<T = FlagType> = {
|
||||||
|
_id?: string,
|
||||||
|
name: string,
|
||||||
|
env: FlagEnv,
|
||||||
|
consumer: FlagConsumer,
|
||||||
|
value: T
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { AbstractUser } from "../src/server/interfaces/index.js";
|
import { AbstractUser } from "../src/server/interfaces/index.js";
|
||||||
import { LoggerClientOptions } from '@navy.gif/logger';
|
import { LoggerClientOptions } from '@navy.gif/logger';
|
||||||
import { MariaOptions, MongoOptions, ObjectId } from '@navy.gif/wrappers';
|
import { BrokerOptions, MariaOptions, MongoOptions, ObjectId } from '@navy.gif/wrappers';
|
||||||
import { Request as ExpressRequest, Response as ExpressResponse, NextFunction } from "express";
|
import { Request as ExpressRequest, Response as ExpressResponse, NextFunction } from "express";
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import { UploadedFile } from "express-fileupload";
|
import { UploadedFile } from "express-fileupload";
|
||||||
@ -51,7 +51,8 @@ export type ServerOptions = {
|
|||||||
discord: {
|
discord: {
|
||||||
scope?: string[],
|
scope?: string[],
|
||||||
version?: number
|
version?: number
|
||||||
}
|
},
|
||||||
|
rabbitConfig: BrokerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Permissions = {
|
export type Permissions = {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"@navy.gif/commandparser": "^1.4.5",
|
"@navy.gif/commandparser": "^1.4.5",
|
||||||
"@navy.gif/logger": "^2.3.3",
|
"@navy.gif/logger": "^2.3.3",
|
||||||
"@navy.gif/passport-discord": "^0.2.2-b",
|
"@navy.gif/passport-discord": "^0.2.2-b",
|
||||||
"@navy.gif/wrappers": "^1.3.13",
|
"@navy.gif/wrappers": "^1.3.14",
|
||||||
"@types/cors": "^2.8.13",
|
"@types/cors": "^2.8.13",
|
||||||
"@types/express-fileupload": "^1.4.1",
|
"@types/express-fileupload": "^1.4.1",
|
||||||
"@types/express-session": "^1.17.7",
|
"@types/express-session": "^1.17.7",
|
||||||
|
@ -18,6 +18,7 @@ import { ControllerOptions } from '../../@types/Controller.js';
|
|||||||
import BaseCommand from './BaseCommand.js';
|
import BaseCommand from './BaseCommand.js';
|
||||||
import { IPCMessage } from '../../@types/Other.js';
|
import { IPCMessage } from '../../@types/Other.js';
|
||||||
import { ServerOptions } from '../../@types/Server.js';
|
import { ServerOptions } from '../../@types/Server.js';
|
||||||
|
import { BrokerOptions } from '@navy.gif/wrappers';
|
||||||
|
|
||||||
class Controller extends EventEmitter {
|
class Controller extends EventEmitter {
|
||||||
|
|
||||||
@ -97,7 +98,8 @@ class Controller extends EventEmitter {
|
|||||||
serverOptions = {} as ServerOptions,
|
serverOptions = {} as ServerOptions,
|
||||||
logger = {},
|
logger = {},
|
||||||
discord = {},
|
discord = {},
|
||||||
databases = {}
|
databases = {},
|
||||||
|
rabbitConfig = {} as BrokerOptions
|
||||||
} = this.#_options;
|
} = this.#_options;
|
||||||
this.#_logger.info(`Spawning ${shardCount} shards`);
|
this.#_logger.info(`Spawning ${shardCount} shards`);
|
||||||
|
|
||||||
@ -129,7 +131,7 @@ class Controller extends EventEmitter {
|
|||||||
for (let i = 0; i < shardCount; i++) {
|
for (let i = 0; i < shardCount; i++) {
|
||||||
const shard = new Shard(this, i, {
|
const shard = new Shard(this, i, {
|
||||||
serverOptions: {
|
serverOptions: {
|
||||||
...serverOptions, logger, discord, databases
|
...serverOptions, logger, discord, databases, rabbitConfig
|
||||||
},
|
},
|
||||||
...shardOptions,
|
...shardOptions,
|
||||||
env: this.#_options.env,
|
env: this.#_options.env,
|
||||||
|
@ -2,6 +2,7 @@ import { OptionType, ArgsResult } from '@navy.gif/commandparser';
|
|||||||
import BaseCommand from '../BaseCommand.js';
|
import BaseCommand from '../BaseCommand.js';
|
||||||
import Controller from '../Controller.js';
|
import Controller from '../Controller.js';
|
||||||
import { IPCMessage, SignupCode } from '../../../@types/Other.js';
|
import { IPCMessage, SignupCode } from '../../../@types/Other.js';
|
||||||
|
import Util from '../../util/Util.js';
|
||||||
|
|
||||||
class CreateCommand extends BaseCommand {
|
class CreateCommand extends BaseCommand {
|
||||||
|
|
||||||
@ -19,20 +20,62 @@ class CreateCommand extends BaseCommand {
|
|||||||
valueOptional: true,
|
valueOptional: true,
|
||||||
defaultValue: 1
|
defaultValue: 1
|
||||||
}]
|
}]
|
||||||
|
}, {
|
||||||
|
name: 'account',
|
||||||
|
type: OptionType.SUB_COMMAND,
|
||||||
|
options: [{
|
||||||
|
name: 'name',
|
||||||
|
type: OptionType.STRING,
|
||||||
|
}, {
|
||||||
|
name: 'password',
|
||||||
|
type: OptionType.STRING
|
||||||
|
}]
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute ({ subcommand, args }: {subcommand: string, args: ArgsResult}) {
|
async execute ({ subcommand, args }: {subcommand: string, args: ArgsResult}) {
|
||||||
|
|
||||||
|
if (subcommand === 'registration-code')
|
||||||
|
return this.#code(args);
|
||||||
|
else if (subcommand === 'account')
|
||||||
|
return this.#account(args);
|
||||||
|
return 'Unknown subcommand';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async #account (args: ArgsResult) {
|
||||||
|
const { name, password } = args;
|
||||||
|
let accountName = 'admin';
|
||||||
|
let accountPass = Util.randomString();
|
||||||
|
if (name)
|
||||||
|
accountName = name.value as string;
|
||||||
|
if (password)
|
||||||
|
accountPass = password.value as string;
|
||||||
|
|
||||||
|
const shard = this.controller.shards.random();
|
||||||
|
if (!shard)
|
||||||
|
return 'No available shard';
|
||||||
|
|
||||||
|
const msg = {
|
||||||
|
type: 'account-create',
|
||||||
|
accountName,
|
||||||
|
accountPass
|
||||||
|
};
|
||||||
|
const response = await shard.send(msg, true) as IPCMessage;
|
||||||
|
if (response.success)
|
||||||
|
return `Account ${accountName} created with password ${accountPass}`;
|
||||||
|
return `Failed to create account:\n${response.message}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #code (args: ArgsResult) {
|
||||||
const amount = args.amount?.value || 1;
|
const amount = args.amount?.value || 1;
|
||||||
const shard = this.controller.shards.random();
|
const shard = this.controller.shards.random();
|
||||||
if (!shard)
|
if (!shard)
|
||||||
return `No available shard`;
|
return `No available shard`;
|
||||||
|
|
||||||
const msg: IPCMessage = { amount };
|
const msg: IPCMessage = { amount, type: 'reqregcode' };
|
||||||
if (subcommand === 'registration-code')
|
|
||||||
msg.type = 'reqregcode';
|
|
||||||
|
|
||||||
const response = await shard.send(msg, true);
|
const response = await shard.send(msg, true);
|
||||||
if (!response)
|
if (!response)
|
||||||
@ -44,7 +87,6 @@ class CreateCommand extends BaseCommand {
|
|||||||
out += `${invite.code}\n`;
|
out += `${invite.code}\n`;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import MongoStore from 'connect-mongo';
|
|||||||
// Own
|
// Own
|
||||||
import { LogFunction, LoggerClient } from '@navy.gif/logger';
|
import { LogFunction, LoggerClient } from '@navy.gif/logger';
|
||||||
import DiscordStrategy from '@navy.gif/passport-discord';
|
import DiscordStrategy from '@navy.gif/passport-discord';
|
||||||
import { MariaDB, MongoDB } from '@navy.gif/wrappers';
|
import { MariaDB, MessageBroker, MongoDB } from '@navy.gif/wrappers';
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
import { Util } from '../util/index.js';
|
import { Util } from '../util/index.js';
|
||||||
@ -37,6 +37,7 @@ class Server extends EventEmitter {
|
|||||||
|
|
||||||
#_name: string;
|
#_name: string;
|
||||||
#_userDatabase: UserDatabaseInterface;
|
#_userDatabase: UserDatabaseInterface;
|
||||||
|
#_messageBroker: MessageBroker;
|
||||||
#_options: ServerOptions;
|
#_options: ServerOptions;
|
||||||
#_shardId: number;
|
#_shardId: number;
|
||||||
#_ready: boolean;
|
#_ready: boolean;
|
||||||
@ -68,8 +69,10 @@ class Server extends EventEmitter {
|
|||||||
MONGO_PORT, MONGO_PASS, MONGO_DB, MONGO_AUTH_DB,
|
MONGO_PORT, MONGO_PASS, MONGO_DB, MONGO_AUTH_DB,
|
||||||
NODE_ENV, SECRET, CRYPTO_SECRET, CRYPTO_SALT,
|
NODE_ENV, SECRET, CRYPTO_SECRET, CRYPTO_SALT,
|
||||||
MONGO_MEMORY_URI, MONGO_MEMORY_HOST, MONGO_MEMORY_USER, MONGO_MEMORY_PORT,
|
MONGO_MEMORY_URI, MONGO_MEMORY_HOST, MONGO_MEMORY_USER, MONGO_MEMORY_PORT,
|
||||||
MONGO_MEMORY_PASS, MONGO_MEMORY_DB, MONGO_MEMORY_AUTH_DB } = process.env as {[key: string]: string};
|
MONGO_MEMORY_PASS, MONGO_MEMORY_DB, MONGO_MEMORY_AUTH_DB,
|
||||||
const { http: httpOpts, databases, name } = options;
|
RABBIT_HOST, RABBIT_USER, RABBIT_PASS, RABBIT_VHOST, RABBIT_PORT
|
||||||
|
} = process.env as { [key: string]: string };
|
||||||
|
const { http: httpOpts, databases, name, rabbitConfig } = options;
|
||||||
|
|
||||||
// This key never leaves memory and is exclusively used on the server, the salt can stay static
|
// This key never leaves memory and is exclusively used on the server, the salt can stay static
|
||||||
const encryption = Util.createEncryptionKey(CRYPTO_SECRET as string, CRYPTO_SALT as string);
|
const encryption = Util.createEncryptionKey(CRYPTO_SECRET as string, CRYPTO_SALT as string);
|
||||||
@ -140,6 +143,15 @@ class Server extends EventEmitter {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.#_userDatabase = new UserDatabase(this, this.#_mongodb);
|
this.#_userDatabase = new UserDatabase(this, this.#_mongodb);
|
||||||
|
|
||||||
|
this.#_messageBroker = new MessageBroker(this, {
|
||||||
|
...rabbitConfig,
|
||||||
|
host: RABBIT_HOST,
|
||||||
|
user: RABBIT_USER,
|
||||||
|
pass: RABBIT_PASS,
|
||||||
|
vhost: RABBIT_VHOST,
|
||||||
|
port: parseInt(RABBIT_PORT)
|
||||||
|
});
|
||||||
|
|
||||||
// Provider needs to implement getKey(key) and setKey(key, value)
|
// Provider needs to implement getKey(key) and setKey(key, value)
|
||||||
// Distributed memory storage, using mongo in this case, but this could be redis or whatever
|
// Distributed memory storage, using mongo in this case, but this could be redis or whatever
|
||||||
@ -219,6 +231,8 @@ class Server extends EventEmitter {
|
|||||||
|
|
||||||
await this.#_userDatabase.init();
|
await this.#_userDatabase.init();
|
||||||
|
|
||||||
|
await this.#_messageBroker.init();
|
||||||
|
|
||||||
this.#logger.info('Loading endpoints');
|
this.#logger.info('Loading endpoints');
|
||||||
await this.#_registry.loadEndpoints();
|
await this.#_registry.loadEndpoints();
|
||||||
this.#logger.debug(this.#_registry.print);
|
this.#logger.debug(this.#_registry.print);
|
||||||
@ -275,6 +289,7 @@ class Server extends EventEmitter {
|
|||||||
await this.#_mongodb.close();
|
await this.#_mongodb.close();
|
||||||
await this.#_mariadb.close();
|
await this.#_mariadb.close();
|
||||||
await this.#_memoryStoreProvider.close();
|
await this.#_memoryStoreProvider.close();
|
||||||
|
await this.#_messageBroker.close();
|
||||||
this.#logger.status('DB shutdowns complete.');
|
this.#logger.status('DB shutdowns complete.');
|
||||||
|
|
||||||
this.#logger.status('Server shutdown complete.');
|
this.#logger.status('Server shutdown complete.');
|
||||||
@ -302,6 +317,17 @@ class Server extends EventEmitter {
|
|||||||
codes.push(code);
|
codes.push(code);
|
||||||
}
|
}
|
||||||
process.send({ _id: msg._id, codes });
|
process.send({ _id: msg._id, codes });
|
||||||
|
} else if (msg.type === 'account-create') {
|
||||||
|
const name = msg.accountName as string;
|
||||||
|
const pass = msg.accountPass as string;
|
||||||
|
this.#logger.info(`Creating account ${name}`);
|
||||||
|
try {
|
||||||
|
await this.users.createUser(name, pass);
|
||||||
|
process.send({ _id: msg._id, success: true });
|
||||||
|
} catch (err) {
|
||||||
|
const error = err as Error;
|
||||||
|
process.send({ _id: msg._id, success: false, message: error.message });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,6 +412,10 @@ class Server extends EventEmitter {
|
|||||||
return this.#_mariadb;
|
return this.#_mariadb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get messageBroker () {
|
||||||
|
return this.#_messageBroker;
|
||||||
|
}
|
||||||
|
|
||||||
get users () {
|
get users () {
|
||||||
return this.#_userDatabase;
|
return this.#_userDatabase;
|
||||||
}
|
}
|
||||||
|
107
src/server/components/FlagManager.ts
Normal file
107
src/server/components/FlagManager.ts
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { MongoDB, ObjectId } from "@navy.gif/wrappers";
|
||||||
|
import Server from "../Server.js";
|
||||||
|
import Flag from "../structures/Flag.js";
|
||||||
|
import { FlagConsumer, FlagData, FlagEnv } from "../../../@types/Flags.js";
|
||||||
|
import { Collection } from "@discordjs/collection";
|
||||||
|
import { LoggerClient } from "@navy.gif/logger";
|
||||||
|
|
||||||
|
type FlagQuery = {
|
||||||
|
id?: string,
|
||||||
|
name?: string,
|
||||||
|
env?: FlagEnv,
|
||||||
|
consumer?: FlagConsumer
|
||||||
|
}
|
||||||
|
|
||||||
|
class FlagManager {
|
||||||
|
|
||||||
|
#server: Server;
|
||||||
|
#mongo: MongoDB;
|
||||||
|
#collectionName = 'flags';
|
||||||
|
#flags: Collection<string, Flag>;
|
||||||
|
#broker;
|
||||||
|
#logger: LoggerClient;
|
||||||
|
|
||||||
|
constructor (server: Server) {
|
||||||
|
this.#server = server;
|
||||||
|
this.#mongo = server.mongodb;
|
||||||
|
this.#logger = server.createLogger(this);
|
||||||
|
this.#flags = new Collection();
|
||||||
|
this.#broker = server.messageBroker;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init () {
|
||||||
|
|
||||||
|
const data = await this.#mongo.find<FlagData>(this.#collectionName, {});
|
||||||
|
for (const flagData of data) {
|
||||||
|
flagData._id = flagData._id.toString();
|
||||||
|
const flag = new Flag(this, flagData);
|
||||||
|
this.#flags.set(flag.id, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#broker.subscribe('flagUpdates', this.#flagUpdate.bind(this));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async #flagUpdate (incoming: { origin: number, flag: FlagData }) {
|
||||||
|
const { flag: data, origin } = incoming;
|
||||||
|
if (origin === this.#server.shardId)
|
||||||
|
return;
|
||||||
|
this.#logger.info(`Incoming flag update for ${data.name}`);
|
||||||
|
const flag = this.#flags.get(data._id as string);
|
||||||
|
if (!flag) {
|
||||||
|
if (!data._id)
|
||||||
|
throw new Error(`Missing flag id? ${data.name}`);
|
||||||
|
this.#flags.set(data._id, new Flag(this, data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flag.value = data.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFlags ({ id, name, env, consumer }: FlagQuery): Flag[] {
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
const flag = this.#flags.get(id);
|
||||||
|
if (!flag)
|
||||||
|
return [];
|
||||||
|
return [ flag ];
|
||||||
|
}
|
||||||
|
|
||||||
|
let filtered = this.#flags;
|
||||||
|
if (name)
|
||||||
|
filtered = filtered.filter(flag => flag.name === name);
|
||||||
|
if (env)
|
||||||
|
filtered = filtered.filter(flag => flag.env === env);
|
||||||
|
if (consumer)
|
||||||
|
filtered = filtered.filter(flag => flag.consumer === consumer);
|
||||||
|
|
||||||
|
return [ ...filtered.values() ];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async createFlag (data: FlagData) {
|
||||||
|
|
||||||
|
const existing = await this.#mongo.findOne(this.#collectionName, { name: data.name, env: data.env, consumer: data.consumer });
|
||||||
|
if (existing)
|
||||||
|
throw new Error(`A flag with the given parameters already exists`);
|
||||||
|
|
||||||
|
data._id = (new ObjectId()).toString();
|
||||||
|
const flag = new Flag(this, data);
|
||||||
|
await this.#mongo.insertOne(this.#collectionName, flag.json);
|
||||||
|
this.#flags.set(flag.id, flag);
|
||||||
|
this.#broker.publish('flagUpdates', { origin: this.#server.shardId, flag: flag.json });
|
||||||
|
return flag;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateFlag (flag: Flag): Promise<void> {
|
||||||
|
|
||||||
|
const json = flag.json as { _id?: string };
|
||||||
|
delete json._id;
|
||||||
|
await this.#mongo.updateOne(this.#collectionName, { _id: flag.id }, json, true);
|
||||||
|
this.#broker.publish('flagUpdates', { origin: this.#server.shardId, flag: flag.json });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FlagManager;
|
@ -61,7 +61,7 @@ class UserDatabase implements UserDatabaseInterface {
|
|||||||
|
|
||||||
async init () {
|
async init () {
|
||||||
for (const coll of [ this.#_userCollection, this.#_appCollection, this.#_roleCollection ])
|
for (const coll of [ this.#_userCollection, this.#_appCollection, this.#_roleCollection ])
|
||||||
await this.#db.ensureIndex(coll, [ 'name' ]);
|
await this.#db.ensureIndex(coll, [ 'name' ], { unique: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchUsers (page: number, amount = 10, query = {}): Promise<User[]> {
|
async fetchUsers (page: number, amount = 10, query = {}): Promise<User[]> {
|
||||||
|
162
src/server/structures/Flag.ts
Normal file
162
src/server/structures/Flag.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import { FlagConsumer, FlagData, FlagEnv, FlagType } from "../../../@types/Flags.js";
|
||||||
|
import FlagManager from "../components/FlagManager.js";
|
||||||
|
|
||||||
|
// const BITS = {
|
||||||
|
// Client: (1 << 0),
|
||||||
|
// Server: (1 << 1),
|
||||||
|
// Test: (1 << 2),
|
||||||
|
// Prod: (1 << 3)
|
||||||
|
// };
|
||||||
|
|
||||||
|
const CONSUMERS = [ 'client', 'server', 'api' ];
|
||||||
|
const ENVS = [ 'test', 'prod' ];
|
||||||
|
|
||||||
|
class Flag {
|
||||||
|
|
||||||
|
#manager: FlagManager;
|
||||||
|
|
||||||
|
#_id: string;
|
||||||
|
#_name: string;
|
||||||
|
|
||||||
|
#_env: FlagEnv;
|
||||||
|
#_consumer: FlagConsumer;
|
||||||
|
|
||||||
|
#_value: FlagType;
|
||||||
|
#_type: string;
|
||||||
|
|
||||||
|
constructor (manager: FlagManager, data: FlagData) {
|
||||||
|
this.#manager = manager;
|
||||||
|
|
||||||
|
if (!data._id)
|
||||||
|
throw new Error('Missing Id');
|
||||||
|
if (!data.name)
|
||||||
|
throw new Error('Missing name');
|
||||||
|
|
||||||
|
if (!data.consumer)
|
||||||
|
throw new Error('Missing consumer');
|
||||||
|
if (!CONSUMERS.includes(data.consumer))
|
||||||
|
throw new Error('Bad consumer');
|
||||||
|
|
||||||
|
if (!data.env)
|
||||||
|
throw new Error('Missing env');
|
||||||
|
if (!ENVS.includes(data.env))
|
||||||
|
throw new Error('Bad env');
|
||||||
|
|
||||||
|
if (!('value' in data))
|
||||||
|
throw new Error('Missing value');
|
||||||
|
|
||||||
|
this.#_id = data._id;
|
||||||
|
this.#_env = data.env;
|
||||||
|
this.#_consumer = data.consumer;
|
||||||
|
this.#_name = data.name;
|
||||||
|
this.#_value = data.value;
|
||||||
|
this.#_type = Flag.resolveType(data.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
save (): Promise<void> {
|
||||||
|
return this.#manager.updateFlag(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
return this.#_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id () {
|
||||||
|
return this.#_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get type () {
|
||||||
|
return this.#_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
get value () {
|
||||||
|
return this.#_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value (val) {
|
||||||
|
this.#_value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
get env () {
|
||||||
|
return this.#_env;
|
||||||
|
}
|
||||||
|
|
||||||
|
get consumer () {
|
||||||
|
return this.#_consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
get json () {
|
||||||
|
return {
|
||||||
|
_id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
value: this.value,
|
||||||
|
env: this.env,
|
||||||
|
consumer: this.consumer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// get client () {
|
||||||
|
// return (this.#env & BITS.Client) === BITS.Client;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// set client (val: boolean) {
|
||||||
|
// if (val)
|
||||||
|
// this.#env |= BITS.Client;
|
||||||
|
// else
|
||||||
|
// this.#env &= ~BITS.Client;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get server () {
|
||||||
|
// return (this.#env & BITS.Server) === BITS.Server;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// set server (val: boolean) {
|
||||||
|
// if (val)
|
||||||
|
// this.#env |= BITS.Server;
|
||||||
|
// else
|
||||||
|
// this.#env &= ~BITS.Server;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get test () {
|
||||||
|
// return (this.#env & BITS.Test) === BITS.Test;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// set test (val: boolean) {
|
||||||
|
// if (val)
|
||||||
|
// this.#env |= BITS.Test;
|
||||||
|
// else
|
||||||
|
// this.#env &= ~BITS.Test;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get prod () {
|
||||||
|
// return (this.#env & BITS.Prod) === BITS.Prod;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// set prod (val: boolean) {
|
||||||
|
// if (val)
|
||||||
|
// this.#env |= BITS.Prod;
|
||||||
|
// else
|
||||||
|
// this.#env &= ~BITS.Prod;
|
||||||
|
// }
|
||||||
|
|
||||||
|
static resolveType (value: unknown) {
|
||||||
|
if (!value)
|
||||||
|
throw new Error('Missing value');
|
||||||
|
|
||||||
|
let type = '';
|
||||||
|
const nativeType = typeof value;
|
||||||
|
if (nativeType === 'object') {
|
||||||
|
type = value.constructor.name;
|
||||||
|
if (value instanceof Array) {
|
||||||
|
const compositeType = typeof value[0];
|
||||||
|
type += `<${compositeType}>`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = nativeType;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Flag;
|
10
yarn.lock
10
yarn.lock
@ -1773,15 +1773,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@navy.gif/wrappers@npm:^1.3.13":
|
"@navy.gif/wrappers@npm:^1.3.14":
|
||||||
version: 1.3.13
|
version: 1.3.14
|
||||||
resolution: "@navy.gif/wrappers@npm:1.3.13"
|
resolution: "@navy.gif/wrappers@npm:1.3.14"
|
||||||
dependencies:
|
dependencies:
|
||||||
amqp-connection-manager: ^4.1.12
|
amqp-connection-manager: ^4.1.12
|
||||||
amqplib: ^0.10.3
|
amqplib: ^0.10.3
|
||||||
mongodb: ^5.2.0
|
mongodb: ^5.2.0
|
||||||
mysql: ^2.18.1
|
mysql: ^2.18.1
|
||||||
checksum: e3328375a8ca4ce6995dcc777b91dece35d92edad1046e6c728226de99a5e524b992fb6f2cb78dd7a266488f5c87294478088c5c0726304ca6b0f3ce56f8668c
|
checksum: 0b9d102b34bdb7f423955f0202bf908aca5b6355621feb00ca2466b60e20f87c5e74953e05a3c5932ff2ee6f508940ec694862b7b93bc2c3ecd8937f25878209
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -7038,7 +7038,7 @@ __metadata:
|
|||||||
"@navy.gif/commandparser": ^1.4.5
|
"@navy.gif/commandparser": ^1.4.5
|
||||||
"@navy.gif/logger": ^2.3.3
|
"@navy.gif/logger": ^2.3.3
|
||||||
"@navy.gif/passport-discord": ^0.2.2-b
|
"@navy.gif/passport-discord": ^0.2.2-b
|
||||||
"@navy.gif/wrappers": ^1.3.13
|
"@navy.gif/wrappers": ^1.3.14
|
||||||
"@types/cors": ^2.8.13
|
"@types/cors": ^2.8.13
|
||||||
"@types/express-fileupload": ^1.4.1
|
"@types/express-fileupload": ^1.4.1
|
||||||
"@types/express-session": ^1.17.7
|
"@types/express-session": ^1.17.7
|
||||||
|
Loading…
Reference in New Issue
Block a user