<commit_before>import { 
  ModelManager, 
  ModelManagerConfig 
} from 'mzen';
import { 
  ServerRemoteObject
} from './remote-object';
import { 
  ServerApiConfig
} from './api-config';
import ServerAcl from './acl';
import ServerAclRoleAssessor from './acl/role-assessor';
import Http = require('http');
import express = require('express');
import path = require('path');

export interface ServerConfig
{
  path?: string;
  port?: number;
  appDir?: string;
  model?: ModelManagerConfig; 
  [key: string]: any; // Any custom config options
}

export class Server
{
  modelManager: ModelManager;
  config: ServerConfig;
  apiConfigs: Array<ServerApiConfig>;
  app: express.Application;
  server: Http.Server;
  router: express.Router;
  aclRoleAssessor: {[key: string]: any};
  logger: any;
  initialisers: {
    [key: string]: any[]
  };
  initialised: boolean;
  
  constructor(options?: ServerConfig, modelManager?: ModelManager)
  {
    this.config = options ? options : {};
    this.config.path = this.config.path ? this.config.path : '/api';
    this.config.port = this.config.port ? this.config.port : 3838;
    // Default appDir directory is the same directory as the executed script
    this.config.appDir = this.config.appDir ? path.resolve(this.config.appDir) : '';
    
    this.modelManager = modelManager 
      ? modelManager 
      : new ModelManager(this.config.model ? this.config.model : undefined);

    this.apiConfigs = [];
    this.app = express();
    this.server = null;
    this.router = express.Router();
    this.aclRoleAssessor = {};
    this.logger = console;
    this.initialisers = {};
    this.initialised = false;
  }
  
  setLogger(logger)
  {
    this.logger = logger;
    this.modelManager.setLogger(logger);
    return this;
  }

  async init()
  {
    if (!this.initialised) {
      await this.runInitialisers();
      await this.runInitialisers('00-init');

      await this.modelManager.init();
      await this.runInitialisers('01-model-initialised');

      await this.runInitialisers('02-resources-loaded');

      this.registerEndpoints();
      await this.runInitialisers('03-endpoints-registered');

      this.app.use(this.config.path, this.router);
      await this.runInitialisers('04-router-mounted');

      this.app.use((err, req, res, next) => {
        this.logger.error({err, req, res});
        res.status(500).send('Something broke!');
        next();
      });

      await this.runInitialisers('99-final');

      this.initialised = true;
    }
  }

  async runInitialisers(stage?:string)
  {
    stage = stage ? stage : 'default';
    if (this.initialisers[stage]) {
      this.initialisers[stage].forEach(async initFunction => {
        await Promise.resolve(initFunction(this));
      });
    }
  }

  addInitialiser(initialiser, stage?:string)
  {
    stage = stage ? stage : 'default';
    if (this.initialisers[stage] === undefined) {
      this.initialisers[stage] = [];
    }
    this.initialisers[stage].push(initialiser);
  }

  addInitialisers(initialisers, stage?:string)
  {
    initialisers.forEach(initialiser => {
      this.addInitialiser(initialiser, stage);
    });
  }

  addRoleAssessor(roleAssessor:ServerAclRoleAssessor)
  {
    this.aclRoleAssessor[roleAssessor.role] = roleAssessor;
  }

  addRoleAssessors(roleAssessors:ServerAclRoleAssessor[])
  {
    roleAssessors.forEach(roleAssessor => {
      this.addRoleAssessor(roleAssessor);
    });
  }

  addApiConfig(config:ServerApiConfig)
  {
    this.apiConfigs.push(config);
  }

  addApiConfigs(configs:Array<ServerApiConfig>)
  {
    this.apiConfigs = this.apiConfigs.concat(configs);
  }

  registerEndpoints() 
  {
    if (this.apiConfigs) {
      for (var apiConfig of this.apiConfigs) {
        this.registerEndpointsConfig(apiConfig);
      }
    }
  }

  registerEndpointsConfig(config:ServerApiConfig)
  {
    var remoteObjectType = null;
    var remoteObjectName = null;
    var remoteObject = null;
    if (config.object) {
      remoteObject = config.object;
    } else if (config.service) {
      remoteObjectType = 'service';
      remoteObjectName = config.service;
      remoteObject = this.modelManager.services[remoteObjectName];
    } else if (config.repo) {
      remoteObjectType = 'repo';
      remoteObjectName = config.repo;
      remoteObject = this.modelManager.repos[remoteObjectName];
    }

    var defaultPathParts = [remoteObjectType];
    if (remoteObjectName) {
      defaultPathParts.push(
        camelToKebab(remoteObjectName)
      );
    }

    var path = config.path != null 
      ? config.path 
      : '/' + defaultPathParts.join('/');

    var enable = config.enable ? config.enable : {};
    var aclConfig = config.acl ? config.acl : {};
    var endpointsDisable = config.disable ? config.disable : {};
    var endpointDisableGroup = config.disableGroup ? config.disableGroup : {};
    var endpoints = config.endpoints ? config.endpoints : {};<commit_msg>Api paths no longer use /repo and /service prefix<commit_after>import { 
  ModelManager, 
  ModelManagerConfig 
} from 'mzen';
import { 
  ServerRemoteObject
} from './remote-object';
import { 
  ServerApiConfig
} from './api-config';
import ServerAcl from './acl';
import ServerAclRoleAssessor from './acl/role-assessor';
import Http = require('http');
import express = require('express');
import path = require('path');

export interface ServerConfig
{
  path?: string;
  port?: number;
  appDir?: string;
  model?: ModelManagerConfig; 
  [key: string]: any; // Any custom config options
}

export class Server
{
  modelManager: ModelManager;
  config: ServerConfig;
  apiConfigs: Array<ServerApiConfig>;
  app: express.Application;
  server: Http.Server;
  router: express.Router;
  aclRoleAssessor: {[key: string]: any};
  logger: any;
  initialisers: {
    [key: string]: any[]
  };
  initialised: boolean;
  
  constructor(options?: ServerConfig, modelManager?: ModelManager)
  {
    this.config = options ? options : {};
    this.config.path = this.config.path ? this.config.path : '/api';
    this.config.port = this.config.port ? this.config.port : 3838;
    // Default appDir directory is the same directory as the executed script
    this.config.appDir = this.config.appDir ? path.resolve(this.config.appDir) : '';
    
    this.modelManager = modelManager 
      ? modelManager 
      : new ModelManager(this.config.model ? this.config.model : undefined);

    this.apiConfigs = [];
    this.app = express();
    this.server = null;
    this.router = express.Router();
    this.aclRoleAssessor = {};
    this.logger = console;
    this.initialisers = {};
    this.initialised = false;
  }
  
  setLogger(logger)
  {
    this.logger = logger;
    this.modelManager.setLogger(logger);
    return this;
  }

  async init()
  {
    if (!this.initialised) {
      await this.runInitialisers();
      await this.runInitialisers('00-init');

      await this.modelManager.init();
      await this.runInitialisers('01-model-initialised');

      await this.runInitialisers('02-resources-loaded');

      this.registerEndpoints();
      await this.runInitialisers('03-endpoints-registered');

      this.app.use(this.config.path, this.router);
      await this.runInitialisers('04-router-mounted');

      this.app.use((err, req, res, next) => {
        this.logger.error({err, req, res});
        res.status(500).send('Something broke!');
        next();
      });

      await this.runInitialisers('99-final');

      this.initialised = true;
    }
  }

  async runInitialisers(stage?:string)
  {
    stage = stage ? stage : 'default';
    if (this.initialisers[stage]) {
      this.initialisers[stage].forEach(async initFunction => {
        await Promise.resolve(initFunction(this));
      });
    }
  }

  addInitialiser(initialiser, stage?:string)
  {
    stage = stage ? stage : 'default';
    if (this.initialisers[stage] === undefined) {
      this.initialisers[stage] = [];
    }
    this.initialisers[stage].push(initialiser);
  }

  addInitialisers(initialisers, stage?:string)
  {
    initialisers.forEach(initialiser => {
      this.addInitialiser(initialiser, stage);
    });
  }

  addRoleAssessor(roleAssessor:ServerAclRoleAssessor)
  {
    this.aclRoleAssessor[roleAssessor.role] = roleAssessor;
  }

  addRoleAssessors(roleAssessors:ServerAclRoleAssessor[])
  {
    roleAssessors.forEach(roleAssessor => {
      this.addRoleAssessor(roleAssessor);
    });
  }

  addApiConfig(config:ServerApiConfig)
  {
    this.apiConfigs.push(config);
  }

  addApiConfigs(configs:Array<ServerApiConfig>)
  {
    this.apiConfigs = this.apiConfigs.concat(configs);
  }

  registerEndpoints() 
  {
    if (this.apiConfigs) {
      for (var apiConfig of this.apiConfigs) {
        this.registerEndpointsConfig(apiConfig);
      }
    }
  }

  registerEndpointsConfig(config:ServerApiConfig)
  {
    var remoteObjectName = null;
    var remoteObject = null;
    if (config.object) {
      remoteObject = config.object;
    } else if (config.service) {
      remoteObjectName = config.service;
      remoteObject = this.modelManager.services[remoteObjectName];
    } else if (config.repo) {
      remoteObjectName = config.repo;
      remoteObject = this.modelManager.repos[remoteObjectName];
    }

    var path = config.path != null 
      ? config.path 
      : '/' + camelToKebab(remoteObjectName);

    var enable = config.enable ? config.enable : {};
    var aclConfig = config.acl ? config.acl : {};
    var endpointsDisable = config.disable ? config.disable : {};
    var endpointDisableGroup = config.disableGroup ? config.disableGroup : {};
    var endpoints = config.endpoints ? config.endpoints : {};
{'fraction_non_alphanumeric': 0.13014195420163713, 'fraction_numerical': 0.00393741581183297, 'mean_word_length': 3.2222222222222223, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1012738', 'n_tokens_mistral': 3071, 'n_tokens_neox': 2956, 'n_words': 550}