Added dependency injection

This commit is contained in:
peter
2020-01-22 00:58:12 +01:00
parent 030908376b
commit e4a6972884
27 changed files with 1769 additions and 208 deletions
+9 -4
View File
@@ -1,8 +1,10 @@
import { ConfigLoader } from "loadson";
import { Inject, Module } from "../../Injector/ServiceDecorator";
import { GuildManagerFeatureIfc, GuildManagerIfc } from "./RPCInterface";
import { FrontworkAdmin } from "../../Admin/Admin";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { _Rank, Rank } from "../../Types/Types";
import { ConfigLoader } from "loadson";
import { GuildManagerIfc, GuildManagerFeatureIfc } from "./RPCInterface";
import { IAdmin } from "../../Admin/Interface";
export type Guild = {
name: string
@@ -10,11 +12,14 @@ export type Guild = {
description: string
}
@Module()
export class GuildManager
implements FrontworkComponent<GuildManagerIfc, GuildManagerFeatureIfc>{
name = "GuildManager" as "GuildManager";
admin: FrontworkAdmin
@Inject(IAdmin)
private admin
guild: ConfigLoader<Guild>
@@ -56,7 +61,7 @@ implements FrontworkComponent<GuildManagerIfc, GuildManagerFeatureIfc>{
getTableDefinitions = () => []
headCount = async () => await Promise.all(
['ADMIN', ..._Rank].map(async r => {
_Rank.map(async r => {
const res = await this.admin.knex
.select('*')
.from('users')
+18 -10
View File
@@ -1,16 +1,17 @@
import { TableDefinitionExporter } from "../../Types/Interfaces";
import { TableDefiniton, _Rank } from "../../Types/Types";
import { FrontworkAdmin } from "../../Admin/Admin";
import { T1 } from "../../Types/Items";
import { RPC } from "rpclibrary";
import { Inject, Module } from "../../Injector/ServiceDecorator";
import { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { RPC, RPCInterface } from "rpclibrary";
import { ItemManagerIfc, ItemManagerFeatureIfc } from "./RPCInterface";
import { TableDefinitionExporter } from "../../Types/Interfaces";
import { FrontworkAdmin } from "../../Admin/Admin";
import { TableDefiniton } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface";
const fetch = require('node-fetch')
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
export type Item = {
id?:number
name:string
@@ -20,12 +21,14 @@ export type Item = {
hidden:boolean
}
@Module()
export class ItemManager
implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefinitionExporter{
admin:FrontworkAdmin
name = "ItemManager" as "ItemManager";
@Inject(IAdmin)
private admin: FrontworkAdmin
exportRPCs(): RPC<any, any>[]{
return [{
name: 'getItems',
@@ -90,7 +93,11 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
return <number>count[0]['count(*)']
}
initialize = async() => {
private initialized = false
initialize = async () => {
if(!this.initialized)
this.initialized = true
const allItems = [...T1]
const countCache = await this.countItems()
if(countCache != allItems.length){
@@ -100,6 +107,7 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
.knex('items')
.insert(items)
}catch(e){
console.log(e)
console.info("Skipping item insertion")
}
}
+6 -3
View File
@@ -1,7 +1,10 @@
import { Raid, Signup, User } from "../../Types/Types";
import { RPCInterface } from "rpclibrary";
import { Raid, Signup, User } from "../../Types/Types"
export type RaidManagerIfc = RPCInterface
export type RaidManagerIfc = {
RaidManager:{
getRaids: () => Promise<Raid[]>
}
}
export type RaidManagerFeatureIfc = {
manageRaid: {
+17 -11
View File
@@ -1,14 +1,22 @@
import { TableDefiniton, User, _Rank, Raid, Signup } from "../../Types/Types";
import { FrontworkAdmin } from "../../Admin/Admin";
import { Inject, Module } from "../../Injector/ServiceDecorator";
import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { RaidManagerFeatureIfc, RaidManagerIfc } from "./RPCInterface";
import { FrontworkAdmin } from "../../Admin/Admin";
import { TableDefiniton, Signup, Raid, User } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface";
@Module()
export class RaidManager
implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
name = "RaidManager" as "RaidManager";
admin: FrontworkAdmin
exportRPCs = () => []
@Inject(IAdmin)
private admin: FrontworkAdmin
exportRPCs = () => [{
name: 'getRaids' as 'getRaids',
call: this.getRaids
},]
exportRPCFeatures() {
return [{
@@ -26,9 +34,6 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
},{
name: 'signup' as 'signup',
exportRPCs: () => [{
name: 'getRaids' as 'getRaids',
call: this.getRaids
},{
name: 'getSingups' as 'getSingups',
call: this.getSignups
},{
@@ -52,9 +57,10 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
},{
name: 'signups',
tableBuilder: (table) => {
table.integer('raid_id').primary()
table.primary(['raid_id', 'user_id'])
table.integer('raid_id')
table.foreign('raid_id').references('id').inTable('raids')
table.integer('user_id').primary()
table.integer('user_id')
table.foreign('user_id').references('id').inTable('users')
}
}
@@ -77,7 +83,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
})
.delete()
getRaids = async () => await this.admin.knex
getRaids = async () : Promise<Raid[]> => await this.admin.knex
.select('*')
.from('raids')
@@ -0,0 +1,96 @@
import { RPCInterface } from "rpclibrary";
import { Inject, Module } from "../../Injector/ServiceDecorator";
import { TableDefiniton, Character } from "../../Types/Types";
import { CharacterManagerIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { FrontworkAdmin } from "../../Admin/Admin";
import { LoginManager } from "./LoginManager";
import { getSpecTableData, SpecT } from "../../Types/PlayerSpecs";
import { IAdmin } from "../../Admin/Interface";
@Module()
export class CharacterManager
implements FrontworkComponent<CharacterManagerIfc, RPCInterface>{
name = "CharacterManager" as "CharacterManager";
@Inject(IAdmin)
private admin: IAdmin
private loginManager : LoginManager
exportRPCs = () => [
{
name: 'getSpecId' as 'getSpecId',
call: this.getSpecId
}
]
exportRPCFeatures = () => [
{
name: "createCharacter",
exportRPCs: () => [
{
name: 'createCharacter',
call: this.createCharacter
}
]
}
]
getTableDefinitions = (): TableDefiniton[] => [
{
name: 'characters',
tableBuilder: (table) => {
table.increments("id").primary()
table.string("name").notNullable().unique()
table.integer("specid").notNullable()
table.foreign("specid").references("specs.id")
table.integer("userid").notNullable()
table.foreign("userid").references("users.id")
}
},{
name: 'specs',
tableBuilder: (table) => {
table.increments("id")
table.string('class')
table.string('name')
table.unique(['class', 'name'])
}
}
]
private initialized = false
initialize = async () => {
if(!this.initialized)
this.initialized = true
//initialize spec table
await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
}
createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
try{
await this.admin.knex('characters').insert(character)
const char : Character = await this.admin.knex.select('*').from('characters').where(character).first()
return char
}catch(e){
console.log(e);
}
throw new Error('Unable to create character')
}
getCharacters = async() : Promise<Character[]> => {
return this.admin.knex.select('*').from('characters')
}
getSpecId = async <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => await this.admin.knex
.from('specs')
.select('id')
.where({
class: clazz,
name: name
}).first().then(spec => spec.id)
}
+78 -51
View File
@@ -1,10 +1,15 @@
import { RPCServer, Socket } from "rpclibrary";
import { TableDefiniton, AnyRPCExporter, User, RPCPermission, Token, Auth, Rank, FrontcraftFeatureIfc, _Rank } from "../../Types/Types";
import { Inject, Module } from "../../Injector/ServiceDecorator";
import { FrontworkAdmin } from "../../Admin/Admin";
import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { getSpecTableData } from "../../Types/PlayerSpecs"
import { GuildManager } from "../Guild/GuildManager";
import { ItemManager } from "../Item/ItemManager";
import { RaidManager } from "../Raid/RaidManager";
import { CharacterManager } from "./CharacterManager";
import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
import { FrontworkComponent } from "../../Types/FrontworkComponent";
import { Rank, User, Auth, _Rank, TableDefiniton, RPCPermission, FrontcraftFeatureIfc, AnyRPCExporter, Token } from "../../Types/Types";
import { IAdmin } from "../../Admin/Interface";
const uuid = require('uuid/v4')
const ONE_WEEK = 604800000
@@ -15,21 +20,35 @@ type Serverstate = {
allowed: string[]
}
@Module()
export class LoginManager
implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
name = "Authenticator" as "Authenticator";
admin:FrontworkAdmin
@Inject(IAdmin)
private admin: FrontworkAdmin
@Inject(GuildManager)
private guild : GuildManager
@Inject(ItemManager)
private item : ItemManager
@Inject(RaidManager)
private raid : RaidManager
@Inject(CharacterManager)
private character : CharacterManager
exporters :any[] = []
rankServers : {[rank in Rank] : Serverstate}
userLogins : {[username in string] : {
user: User
connections: {[port in number]: Socket}
auth: Auth
}} = {}
constructor(
private exporters: PrivilegedRPCExporter[]
){}
exportRPCs = () => [
{
name: 'login' as 'login',
@@ -43,21 +62,14 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
},{
name: 'checkToken' as 'checkToken',
call: async (tokenValue : string, rank: Rank) => this.checkToken(tokenValue, rank)
},{
name: 'createUser' as 'createUser',
call: this.createUser
}
]
onSetAdmin(admin:FrontworkAdmin){
this.exporters.forEach(e => e['admin'] = admin)
}
exportRPCFeatures = () => [
{
name: 'createUser' as 'createUser',
exportRPCs: () => [{
name: 'createUser' as 'createUser',
call: this.createUser
}]
},{
name: 'modifyPermissions' as 'modifyPermissions',
exportRPCs: () => [{
name: 'getPermissions' as 'getPermissions',
@@ -79,36 +91,26 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
table.string("pwhash").notNullable()
table.string("rank").notNullable()
table.string("email").nullable().unique()
}
},{
name: 'characters',
tableBuilder: (table) => {
table.increments("id").primary()
table.string("name").notNullable().unique()
table.integer("specid").notNullable()
table.foreign("specid").references("specs.id")
table.integer("userid").notNullable()
table.foreign("userid").references("users.id")
table.boolean("locked").defaultTo(true)
}
},{
name: 'rpcpermissions',
tableBuilder: (table) => {
table.string("name").primary().notNullable()
table.boolean("ADMIN").defaultTo(true).notNullable()
_Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
}
},{
name: 'specs',
tableBuilder: (table) => {
table.increments("id")
table.string('class')
table.string('name')
_Rank.forEach(r => {
if(r === 'ADMIN')
table.boolean(r).defaultTo(true).notNullable()
else
table.boolean(r).defaultTo(false).notNullable()
})
}
}
,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
]
initialize = async () => {
this.exporters = [this.guild, this.item, this.raid, this.character]
//set up permissions
await Promise.all(
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
@@ -117,12 +119,6 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
}catch(e){}
})))
//initialize managed exporters
await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
//initialize spec table
await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
//start rankServers
const rankServers : any = {}
@@ -138,7 +134,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
}
this.rankServers = rankServers
setInterval(this.checkExpiredSessions, 600_000)
setInterval(this.checkExpiredSessions, 600_000)
}
checkExpiredSessions = () => {
@@ -151,8 +147,14 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
}
checkConnection = async (socket: Socket) => {
let data : Auth | false = false
let data : any = false
let tries = 0
while(!data){
tries ++
if(tries === 5){
socket.destroy()
return
}
data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
}
this.userLogins[data.user.name].connections[socket.port] = socket
@@ -181,20 +183,40 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
}
getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
return [
let rpcs = [
...this.exportRPCFeatures(),
...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank))
]
const bits = await Promise.all(rpcs.map(async (feature) => {
const allowed = await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank)
return allowed
}))
return rpcs.filter(entry => bits.shift())
}
createUser = async(user:User): Promise<User> => {
if(user.rank === 'ADMIN'){
const admins = await this.admin.knex
.select("*")
.from('users')
.where({rank: 'ADMIN'})
if(admins.length > 0){
return {} as User
}
user.locked = false
}
await this.admin.knex('users')
.insert(user)
const users = await this.admin.knex
.select("*")
.from('users')
.where(user)
return users[0]
}
@@ -238,7 +260,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
port: this.rankServers[user.rank].port
}
this.userLogins[user.name] = {connections: {}, auth: userAuth}
this.userLogins[user.name] = {connections: {}, auth: userAuth, user:user}
this.rankServers[user.rank].allowed.push(token.value)
return userAuth
@@ -247,8 +269,13 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
throw new Error('login failed')
}
getUserRecordByToken(tokenValue: string){
const maybeRecord = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
return maybeRecord?maybeRecord:undefined
}
getAuth = async (tokenValue:string) : Promise<Auth> => {
const maybeAuth = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
const maybeAuth = this.getUserRecordByToken(tokenValue)
if(maybeAuth)
return maybeAuth.auth
+16 -4
View File
@@ -1,4 +1,5 @@
import { Token, Auth, User, RPCPermission, Rank } from "../../Types/Types"
import { Auth, Rank, User, RPCPermission, Character } from "../../Types/Types"
import { SpecT } from "../../Types/PlayerSpecs"
export type LoginManagerIfc = {
Authenticator: {
@@ -6,15 +7,26 @@ export type LoginManagerIfc = {
logout: (username: string, tokenValue :string) => Promise<void>
getAuth: (tokenValue: string) => Promise<Auth>
checkToken: (token: string, rank: Rank) => Promise<boolean>
createUser: (user:User) => Promise<User>
}
}
export type LoginManagerFeatureIfc = {
createUser: {
createUser: (user:User) => Promise<User>
}
modifyPermissions: {
setPermission: (perm: RPCPermission) => Promise<void>
getPermissions: () => Promise<RPCPermission[]>
}
}
export type CharacterManagerIfc = {
CharacterManager: {
getSpecId : <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => Promise<number>
getCharacters : () => Promise<Character[]>
}
}
export type CharacterManagerFeatureIfc = {
createCharacter: {
createCharacter: (usertoken: string, char : Character) => Promise<Character>
}
}