Skip to content

Commit

Permalink
pass routers in observables
Browse files Browse the repository at this point in the history
  • Loading branch information
kimjoar committed May 23, 2017
1 parent 356e9d3 commit f5c4fce
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 55 deletions.
8 changes: 5 additions & 3 deletions platform/server/elasticsearch/api.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { logger } from '../../logger'
import { Routing } from '../http';
import { RouterFactory } from '../http';
import { Schema } from '../../types';

const log = logger.get('elasticsearch', 'api')

export function createElasticsearchRoutes(routing: Routing, schema: Schema) {
export function createElasticsearchRoutes(routerFactory: RouterFactory, schema: Schema) {
log.info('creating elasticsearch api');

const router = routing.createRouter('/plugin/elasticsearch');
const router = routerFactory.createRouter('/plugin/elasticsearch');

router.get({
path: '/:field',
Expand Down Expand Up @@ -38,4 +38,6 @@ export function createElasticsearchRoutes(routing: Routing, schema: Schema) {
query: req.query
};
});

return router;
}
6 changes: 3 additions & 3 deletions platform/server/elasticsearch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Observable } from 'rxjs';
import { ElasticsearchService } from './ElasticsearchService';
import { ElasticsearchFacade } from './ElasticsearchFacade';
import { createElasticsearchRoutes } from './api';
import { Routing } from '../http';
import { RouterFactory } from '../http';
import { IsRouteable } from '../../types';
import { Config } from '../../config';
import { Schema } from '../../types';
Expand All @@ -25,7 +25,7 @@ export class ElasticsearchModule implements IsRouteable {
this.facade = new ElasticsearchFacade(this.service);
}

createRoutes(routing: Routing, schema: Schema) {
createElasticsearchRoutes(routing, schema);
createRoutes(routerFactory: RouterFactory, schema: Schema) {
return createElasticsearchRoutes(routerFactory, schema);
}
}
27 changes: 19 additions & 8 deletions platform/server/http/HttpService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Observable, Subscription } from 'rxjs';
import { HttpConfig } from './HttpConfig';
import { Service } from '../../types';
import { logger } from '../../logger';
import { Routing } from './Routing';
import { Router } from './Routing';

const log = logger.get('http');

Expand All @@ -14,12 +14,23 @@ export class HttpService implements Service {
private readonly httpServer: http.Server;

private readonly server$: Observable<HttpConfig>;
private readonly routers$: Observable<Router[]>;
private subscription?: Subscription;

constructor(config$: Observable<HttpConfig>) {
constructor(
config$: Observable<HttpConfig>,
router$: Observable<Router>
) {
this.app = express();
this.httpServer = http.createServer(this.app);

this.routers$ = router$
.scan((routers, route) => {
routers.push(route);
return routers;
}, [])
.last();

this.server$ = config$
// TODO Add an `equals` check to the http config
// .distinctUntilChanged((prev, next) => false)
Expand All @@ -38,11 +49,11 @@ export class HttpService implements Service {
})
}

start(routing: Routing) {
this.subscription = this.server$
.switchMap(config =>
start() {
this.subscription = Observable.combineLatest(this.server$, this.routers$)
.switchMap(([config, routers]) =>
new Observable<http.Server>(() => {
this.startHttpServer(config, routing);
this.startHttpServer(config, routers);

return () => {
// TODO: This is async! :/
Expand All @@ -59,10 +70,10 @@ export class HttpService implements Service {
}
}

private startHttpServer(config: HttpConfig, routing: Routing) {
private startHttpServer(config: HttpConfig, routers: Router[]) {
const { host, port } = config;

routing.routers.forEach(router => {
routers.forEach(router => {
log.info(`registering route handler for [${router.path}]`);
this.app.use(router.path, router.router);
});
Expand Down
8 changes: 2 additions & 6 deletions platform/server/http/Routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,11 @@ export class Router {
}
}

export class Routing {
readonly routers: Router[] = [];

export class RouterFactory {
constructor(private readonly kibana: KibanaRequestHelpers) {
}

createRouter(path: string) {
const router = new Router(path, this.kibana)
this.routers.push(router);
return router;
return new Router(path, this.kibana)
}
}
9 changes: 5 additions & 4 deletions platform/server/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ import { Observable } from 'rxjs';
import { Config } from '../../config';
import { HttpService } from './HttpService';
import { HttpConfig } from './HttpConfig';
import { Router } from './Routing';

export { httpSchema } from './HttpConfig';
export { Routing, KibanaRequest, KibanaResponse } from './Routing';
export { HttpService };
export { RouterFactory, KibanaRequest, KibanaResponse } from './Routing';
export { HttpService, Router };

export class HttpModule {
service: HttpService;
config$: Observable<HttpConfig>;

constructor(config$: Observable<Config>) {
constructor(config$: Observable<Config>, router$: Observable<Router>) {
this.config$ = config$.map(config =>
new HttpConfig(config.atPath('server'), config.env)
);
this.service = new HttpService(this.config$);
this.service = new HttpService(this.config$, router$);
}
}
51 changes: 28 additions & 23 deletions platform/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Observable } from 'rxjs';
import { Observable, ReplaySubject } from 'rxjs';

import { HttpModule, Routing } from './http';
import { HttpModule, RouterFactory, Router } from './http';
import { PidModule } from './pid';
import { SavedObjectsModule } from './savedObjects';
import { ElasticsearchModule } from './elasticsearch';
Expand All @@ -12,12 +12,16 @@ import { IsRouteable } from '../types';

const log = logger.get('server');

const toArray = <T>(items: T | T[]) =>
Array.isArray(items) ? items : [items];

export class Server {
private readonly elasticsearch: ElasticsearchModule;
private readonly http: HttpModule;
private readonly pid: PidModule;
private readonly savedObjects: SavedObjectsModule;
private readonly kibana: KibanaModule;
private readonly isRouteable$: ReplaySubject<IsRouteable>;

constructor(
private readonly config$: Observable<Config>
Expand All @@ -29,19 +33,8 @@ export class Server {
this.kibana.config$,
this.elasticsearch.service
);
this.http = new HttpModule(config$);
}

start() {
log.info('starting server :tada:');

const coreRoutes: IsRouteable[] = [
this.elasticsearch,
this.savedObjects
];

// start services
this.elasticsearch.service.start();
this.isRouteable$ = new ReplaySubject();

// We make this object available in all requests. It's basically "helpers"
// so we don't need to handle observables directly in the requests, but
Expand All @@ -56,19 +49,31 @@ export class Server {
savedObjects: this.savedObjects.facade
};

// Routing depends on other services, so must start after most of them
const routing = new Routing(kibana);
coreRoutes.forEach(routesFactory => {
routesFactory.createRoutes(routing, schema);
});
const routerFactory = new RouterFactory(kibana);
const routers = this.isRouteable$
.flatMap(routable =>
toArray(routable.createRoutes(routerFactory, schema))
);

this.http = new HttpModule(config$, routers);
}

start() {
log.info('starting server :tada:');

// TODO loop through all modules and `next` all `IsRoutable`s.
this.isRouteable$.next(this.elasticsearch);
this.isRouteable$.next(this.savedObjects);

// start services
this.elasticsearch.service.start();

// we finish by starting the rest of the services
this.pid.service.start();

// TODO: Looks like this param can now be pushed into constructor instead
// Hm, maybe we can rely on observables here?
// e.g. `Observable<RouteFactory>` or something like that
this.http.service.start(routing);
// We're about to start the http services, so we no longer allow new routes
this.isRouteable$.complete();
this.http.service.start();
}

stop() {
Expand Down
8 changes: 5 additions & 3 deletions platform/server/savedObjects/api.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { logger } from '../../logger'
import { Routing, KibanaResponse } from '../http';
import { RouterFactory, KibanaResponse } from '../http';
import { Schema } from '../../types';

const log = logger.get('savedObjects', 'api')

export function createSavedObjectsRoutes(routing: Routing, schema: Schema) {
export function createSavedObjectsRoutes(routerFactory: RouterFactory, schema: Schema) {
log.info('creating saved objects api');

const router = routing.createRouter('/saved_objects');
const router = routerFactory.createRouter('/saved_objects');

router.get({
path: '/fail'
Expand Down Expand Up @@ -61,4 +61,6 @@ export function createSavedObjectsRoutes(routing: Routing, schema: Schema) {

return res.ok(savedObjects);
});

return router;
}
6 changes: 3 additions & 3 deletions platform/server/savedObjects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SavedObjectsFacade } from './SavedObjectsFacade';
import { ElasticsearchService } from '../elasticsearch';
import { KibanaConfig } from '../kibana';
import { Config } from '../../config';
import { Routing } from '../http/Routing';
import { RouterFactory } from '../http/Routing';
import { IsRouteable } from '../../types';
import { Schema } from '../../types';

Expand All @@ -24,7 +24,7 @@ export class SavedObjectsModule implements IsRouteable {
)
}

createRoutes(routing: Routing, schema: Schema): void {
createSavedObjectsRoutes(routing, schema);
createRoutes(routerFactory: RouterFactory, schema: Schema) {
return createSavedObjectsRoutes(routerFactory, schema);
}
}
4 changes: 2 additions & 2 deletions platform/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as schema from './lib/schema';
import { Routing } from './server/http';
import { RouterFactory, Router } from './server/http';
import { ElasticsearchFacade } from './server/elasticsearch';
import { SavedObjectsFacade } from './server/savedObjects';

Expand All @@ -11,7 +11,7 @@ export interface Service {
}

export interface IsRouteable {
createRoutes(routing: Routing, schema: Schema): void;
createRoutes(routerFactory: RouterFactory, schema: Schema): Router | Router[];
}

export type KibanaRequestHelpers = {
Expand Down

0 comments on commit f5c4fce

Please sign in to comment.