initial subscription support

This commit is contained in:
Wyatt Johnson
2018-06-20 15:56:15 -06:00
parent 1917a17929
commit a3e3d93607
19 changed files with 422 additions and 145 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
node_modules
dist
.env
*.js
*.js
yarn.lock
+95 -6
View File
@@ -173,6 +173,16 @@
"@types/node": "*"
}
},
"@types/ws": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-5.1.2.tgz",
"integrity": "sha512-NkTXUKTYdXdnPE2aUUbGOXE1XfMK527SCvU/9bj86kyFF6kZ9ZnOQ3mK5jADn98Y2vEUD/7wKDgZa7Qst2wYOg==",
"dev": true,
"requires": {
"@types/events": "*",
"@types/node": "*"
}
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -226,9 +236,9 @@
},
"dependencies": {
"@types/node": {
"version": "9.6.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.21.tgz",
"integrity": "sha512-zQS6mHzxEstR8Vvnpc3JDUCDGWnHFzMTcBu9UCZoVLuj1Uvkkk0qFKJQEhlvbsX34m3xt12ejV09eO/ljZcn7A=="
"version": "9.6.22",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.22.tgz",
"integrity": "sha512-RIg9EkxzVMkNH0M4sLRngK23f5QiigJC0iODQmu4nopzstt8AjegYund3r82iMrd2BNCjcZVnklaItvKHaGfBA=="
}
}
},
@@ -265,9 +275,12 @@
}
},
"apollo-utilities": {
"version": "1.0.13",
"resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.13.tgz",
"integrity": "sha512-WIbKDsFsLXMgPPGmlB2pL2noHT13TOLU2eRSyPjQMQwcz9lO9UKRkwK8pRJ8b4Zo/9qQHm30F/xlfP/OSr2ZSw=="
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.16.tgz",
"integrity": "sha512-5oKnElKqkV920KRbitiyISLeG63tUGAyNdotg58bQSX9Omr+smoNDTIRMRLbyIdKOYLaw3LpDaRepOPqljj0NQ==",
"requires": {
"fast-json-stable-stringify": "^2.0.0"
}
},
"argparse": {
"version": "1.0.10",
@@ -324,12 +337,22 @@
"integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
"dev": true
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"atob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz",
"integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=",
"dev": true
},
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -941,6 +964,11 @@
"through": "~2.3.1"
}
},
"eventemitter3": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA=="
},
"execa": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
@@ -1122,6 +1150,11 @@
}
}
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -1874,6 +1907,16 @@
"graphql-playground-html": "1.6.0"
}
},
"graphql-redis-subscriptions": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/graphql-redis-subscriptions/-/graphql-redis-subscriptions-1.5.0.tgz",
"integrity": "sha512-4R/rv3qg61/UuB/9enCdWJM9s4x6TRwXYubjAlPWXJuNhGcZXn6oELu9mrhm+8QuA924/GvOo8Z7hCqE617SeQ==",
"requires": {
"graphql-subscriptions": "^0.5.6",
"ioredis": "^3.1.2",
"iterall": "^1.1.3"
}
},
"graphql-request": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.6.0.tgz",
@@ -1882,6 +1925,14 @@
"cross-fetch": "2.0.0"
}
},
"graphql-subscriptions": {
"version": "0.5.8",
"resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-0.5.8.tgz",
"integrity": "sha512-0CaZnXKBw2pwnIbvmVckby5Ge5e2ecmjofhYCdyeACbCly2j3WXDP/pl+s+Dqd2GQFC7y99NB+53jrt55CKxYQ==",
"requires": {
"iterall": "^1.2.1"
}
},
"graphql-tools": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-3.0.2.tgz",
@@ -2355,6 +2406,16 @@
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
"integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4="
},
"lodash.isobject": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
"integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.keys": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz",
@@ -3460,6 +3521,26 @@
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true
},
"subscriptions-transport-ws": {
"version": "0.9.11",
"resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.11.tgz",
"integrity": "sha512-B8fwTIJy2buUcBXM6Ffbax30XcEqvCqL8RXwbivBAiB3X9ezrTcF5nYMmNGZ47sxrDYA1XfQ5W3aTgJEm8BFJA==",
"requires": {
"backo2": "^1.0.2",
"eventemitter3": "^3.1.0",
"iterall": "^1.2.1",
"lodash.assign": "^4.2.0",
"lodash.isobject": "^3.0.2",
"lodash.isstring": "^4.0.1",
"symbol-observable": "^1.0.4",
"ws": "^5.2.0"
}
},
"symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"term-size": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
@@ -3836,6 +3917,14 @@
"signal-exit": "^3.0.2"
}
},
"ws": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.0.tgz",
"integrity": "sha512-c18dMeW+PEQdDFzkhDsnBAlS4Z8KGStBQQUcQ5mf7Nf689jyGk0594L+i9RaQuf4gog6SvWLJorz2NfSaqxZ7w==",
"requires": {
"async-limiter": "~1.0.0"
}
},
"xdg-basedir": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
+3 -1
View File
@@ -21,6 +21,7 @@
"express-static-gzip": "^0.3.2",
"graphql": "^0.13.2",
"graphql-config": "^2.0.1",
"graphql-redis-subscriptions": "^1.5.0",
"graphql-tools": "^3.0.2",
"ioredis": "^3.2.2",
"joi": "^13.4.0",
@@ -28,6 +29,7 @@
"luxon": "^1.2.1",
"mongodb": "^3.0.10",
"performance-now": "^2.1.0",
"subscriptions-transport-ws": "^0.9.11",
"uuid": "^3.2.1"
},
"devDependencies": {
@@ -42,7 +44,7 @@
"@types/luxon": "^0.5.3",
"@types/mongodb": "^3.0.19",
"@types/uuid": "^3.4.3",
"graphql-playground-html": "^1.6.0",
"@types/ws": "^5.1.2",
"graphql-playground-middleware-express": "^1.7.0",
"nodemon": "^1.17.5",
"prettier": "^1.13.4",
+41 -79
View File
@@ -1,99 +1,34 @@
import express, { Express, Router } from 'express';
import { Express } from 'express';
import { Db } from 'mongodb';
import http from 'http';
import { Redis } from 'ioredis';
import { Config } from 'talk-server/config';
import { create } from 'talk-server/services/mongodb';
import tenantGraphMiddleware from 'talk-server/graph/tenant/middleware';
import managementGraphMiddleware from 'talk-server/graph/management/middleware';
import { Schemas } from 'talk-server/graph/schemas';
import { handleSubscriptions } from 'talk-server/graph/common/subscriptions/middleware';
import { createRouter } from './router';
import serveStatic from './middleware/serveStatic';
import playground from './middleware/playground';
import {
access as accessLogger,
error as errorLogger,
} from './middleware/logging';
import { Redis } from 'ioredis';
export interface AppOptions {
parent: Express;
config: Config;
mongo: Db;
redis: Redis;
}
async function createManagementRouter(opts: AppOptions): Promise<Router> {
const router = express.Router();
if (opts.config.get('env') === 'development') {
// GraphiQL
router.get(
'/graphiql',
playground({
endpoint: '/api/management/graphql',
})
);
}
// Management API
router.use(
'/graphql',
express.json(),
managementGraphMiddleware(opts.mongo)
);
return router;
}
async function createTenantRouter(opts: AppOptions): Promise<Router> {
const router = express.Router();
if (opts.config.get('env') === 'development') {
// GraphiQL
router.get(
'/graphiql',
playground({
endpoint: '/api/tenant/graphql',
})
);
}
// Tenant API
router.use('/graphql', express.json(), tenantGraphMiddleware(opts.mongo));
return router;
}
async function createAPIRouter(opts: AppOptions): Promise<Router> {
// Create a router.
const router = express.Router();
// Configure the tenant routes.
router.use('/tenant', await createTenantRouter(opts));
// Configure the management routes.
router.use('/management', await createManagementRouter(opts));
return router;
}
async function createRouter(opts: AppOptions): Promise<Router> {
// Create a router.
const router = express.Router();
router.use('/api', await createAPIRouter(opts));
return router;
schemas: Schemas;
}
/**
* createApp will create a Talk Express app that can be used to handle requests.
*
* @param parent the root application to attach the Talk routes/middleware to.
*/
export async function createApp(
parent: Express,
options: AppOptions
): Promise<Express> {
export async function createApp(options: AppOptions): Promise<Express> {
// Pull the parent out of the options.
const { parent } = options;
// Logging
parent.use(accessLogger);
@@ -110,13 +45,40 @@ export async function createApp(
}
/**
* startApp will start the given express application.
* listenAndServe will start the given express application.
*
* @param port the port to listen on
* @param app the express application to start
* @param port the port to listen on
*/
export const startApp = (port: number, app: Express): Promise<http.Server> =>
export const listenAndServe = (
app: Express,
port: number
): Promise<http.Server> =>
new Promise(async resolve => {
// Listen on the designated port.
const httpServer = app.listen(port, () => resolve(httpServer));
});
/**
* attachSubscriptionHandlers attaches all the handlers to the http.Server to
* handle websocket traffic by upgrading their http connections to websocket.
*
* @param schemas schemas for every schema this application handles
* @param server the http.Server to attach the websocket upgraders to
*/
export async function attachSubscriptionHandlers(
schemas: Schemas,
server: http.Server
) {
// Setup the Management Subscription endpoint.
handleSubscriptions(server, {
schema: schemas.management,
path: '/api/management/live',
});
// Setup the Tenant Subscription endpoint.
handleSubscriptions(server, {
schema: schemas.tenant,
path: '/api/tenant/live',
});
}
+85
View File
@@ -0,0 +1,85 @@
import express, { Router } from 'express';
import tenantGraphMiddleware from 'talk-server/graph/tenant/middleware';
import managementGraphMiddleware from 'talk-server/graph/management/middleware';
import { AppOptions } from './index';
import playground from './middleware/playground';
async function createManagementRouter(opts: AppOptions) {
const router = express.Router();
if (opts.config.get('env') === 'development') {
// GraphiQL
router.get(
'/graphiql',
playground({
endpoint: '/api/management/graphql',
subscriptionEndpoint: '/api/management/live',
})
);
}
// Management API
router.use(
'/graphql',
express.json(),
await managementGraphMiddleware(
opts.schemas.management,
opts.config,
opts.mongo
)
);
return router;
}
async function createTenantRouter(opts: AppOptions) {
const router = express.Router();
if (opts.config.get('env') === 'development') {
// GraphiQL
router.get(
'/graphiql',
playground({
endpoint: '/api/tenant/graphql',
subscriptionEndpoint: '/api/tenant/live',
})
);
}
// Tenant API
router.use(
'/graphql',
express.json(),
await tenantGraphMiddleware(
opts.schemas.tenant,
opts.config,
opts.mongo
)
);
return router;
}
async function createAPIRouter(opts: AppOptions) {
// Create a router.
const router = express.Router();
// Configure the tenant routes.
router.use('/tenant', await createTenantRouter(opts));
// Configure the management routes.
router.use('/management', await createManagementRouter(opts));
return router;
}
export async function createRouter(opts: AppOptions) {
// Create a router.
const router = express.Router();
router.use('/api', await createAPIRouter(opts));
return router;
}
+8 -1
View File
@@ -32,7 +32,7 @@ convict.addFormat({
},
});
export const config = convict({
const config = convict({
env: {
doc: 'The application environment.',
format: ['production', 'development', 'test'],
@@ -67,6 +67,13 @@ export const config = convict({
env: 'SECRET',
arg: 'secret',
},
logging_level: {
doc: 'The logging level to print to the console',
format: ['fatal', 'error', 'warn', 'info', 'debug', 'trace'],
default: 'info',
env: 'LOGGING_LEVEL',
arg: 'logging',
},
});
export type Config = typeof config;
@@ -0,0 +1,52 @@
import {
graphqlExpress,
ExpressGraphQLOptionsFunction,
GraphQLOptions,
} from 'apollo-server-express';
import { GraphQLError, FieldDefinitionNode, ValidationContext } from 'graphql';
import { resolveGraphqlOptions } from 'apollo-server-core';
import { Config } from 'talk-server/config';
// Sourced from: https://github.com/apollographql/apollo-server/blob/958846887598491fadea57b3f9373d129300f250/packages/apollo-server-core/src/ApolloServer.ts#L46-L57
const NoIntrospection = (context: ValidationContext) => ({
Field(node: FieldDefinitionNode) {
if (node.name.value === '__schema' || node.name.value === '__type') {
context.reportError(
new GraphQLError(
'GraphQL introspection is not allowed in production, but the query contained __schema or __type.',
[node]
)
);
}
},
});
export const graphqlMiddleware = (
config: Config,
baseOptions: GraphQLOptions | ExpressGraphQLOptionsFunction
) => {
// Generate the validation rules.
const validationRules: Array<(context: ValidationContext) => any> = [];
if (config.get('env') !== 'production') {
// Disable introspection in production.
validationRules.push(NoIntrospection);
}
// Generate the actual middleware.
return graphqlExpress(async (req, res) => {
// Resolve the base options.
const requestOptions = await resolveGraphqlOptions(
baseOptions,
req,
res
);
// Apply the validators, sourced from: https://github.com/apollographql/apollo-server/blob/958846887598491fadea57b3f9373d129300f250/packages/apollo-server-core/src/ApolloServer.ts#L104-L107
requestOptions.validationRules = requestOptions.validationRules
? requestOptions.validationRules.concat(validationRules)
: validationRules;
return requestOptions;
});
};
@@ -0,0 +1,15 @@
import { addResolveFunctionsToSchema, IResolvers } from 'graphql-tools';
import { getGraphQLProjectConfig } from 'graphql-config';
export default function loadSchema(projectName: string, resolvers: IResolvers) {
// Load the configuration from the provided `.graphqlconfig` file.
const config = getGraphQLProjectConfig(__dirname, projectName);
// Get the GraphQLSchema from the configuration.
const schema = config.getSchema();
// Attach the resolvers to the schema.
addResolveFunctionsToSchema({ schema, resolvers });
return schema;
}
@@ -0,0 +1,29 @@
import http from 'http';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { GraphQLSchema, execute, subscribe } from 'graphql';
export interface SubscriptionMiddlewareOptions {
schema: GraphQLSchema;
path: string;
}
export function handleSubscriptions(
server: http.Server,
{ schema, path }: SubscriptionMiddlewareOptions
): SubscriptionServer {
// Configure some options for the subscription system.
const options = {
schema,
execute,
subscribe,
};
// Configure the socket options for the websocket server. It needs to handle
// upgrade requests on that route.
const socketOption = {
server,
path,
};
return new SubscriptionServer(options, socketOption);
}
@@ -0,0 +1,15 @@
import { RedisPubSub } from 'graphql-redis-subscriptions';
import { createRedisClient } from 'talk-server/services/redis';
import { Config } from 'talk-server/config';
export async function createPubSub(config: Config): Promise<RedisPubSub> {
// Create the Redis clients for the PubSub server.
const publisher = await createRedisClient(config);
const subscriber = await createRedisClient(config);
// Create the new PubSub manager.
return new RedisPubSub({
publisher,
subscriber,
});
}
+11 -10
View File
@@ -1,12 +1,13 @@
import { graphqlExpress } from 'apollo-server-express';
import schema from './schema';
import Context from './context';
import { Db } from 'mongodb';
import { GraphQLSchema } from 'graphql';
export default (db: Db) =>
graphqlExpress(async req => {
return {
schema,
context: new Context({ db }),
};
});
import { graphqlMiddleware } from 'talk-server/graph/common/middleware';
import { Config } from 'talk-server/config';
import Context from './context';
export default (schema: GraphQLSchema, config: Config, db: Db) =>
graphqlMiddleware(config, async () => ({
schema,
context: new Context({ db }),
}));
@@ -1,15 +1,6 @@
import { addResolveFunctionsToSchema } from 'graphql-tools';
import { getGraphQLProjectConfig } from 'graphql-config';
import loadSchema from 'talk-server/graph/common/schema';
import resolvers from 'talk-server/graph/management/resolvers';
import resolvers from '../resolvers';
// Load the configuration from the provided `.graphqlconfig` file.
const config = getGraphQLProjectConfig(__dirname, 'management');
// Get the GraphQLSchema from the configuration.
const schema = config.getSchema();
// Attach the resolvers to the schema.
addResolveFunctionsToSchema({ schema, resolvers });
export default schema;
export default function getManagementSchema() {
return loadSchema('management', resolvers);
}
+6
View File
@@ -0,0 +1,6 @@
import { GraphQLSchema } from 'graphql';
export interface Schemas {
management: GraphQLSchema;
tenant: GraphQLSchema;
}
+18 -7
View File
@@ -1,13 +1,24 @@
import { graphqlExpress } from 'apollo-server-express';
import schema from './schema';
import TenantContext from './context';
import { Db } from 'mongodb';
import { Tenant } from 'talk-server/models/tenant';
import { GraphQLSchema } from 'graphql';
import { retrieveByDomain } from 'talk-server/models/tenant';
import { createPubSub } from 'talk-server/graph/common/subscriptions/pubsub';
import { Config } from 'talk-server/config';
import { graphqlMiddleware } from 'talk-server/graph/common/middleware';
import TenantContext from './context';
export default async (schema: GraphQLSchema, config: Config, db: Db) => {
// Configure the PubSub broker.
const pubsub = await createPubSub(config);
return graphqlMiddleware(config, async req => {
// TODO: replace with shared synced cache instead of direct db access.
const tenant = await retrieveByDomain(db, req.hostname);
export default (db: Db) =>
graphqlExpress(async req => {
return {
schema,
context: new TenantContext({ db, tenant: { id: '1' } as Tenant }),
context: new TenantContext({ db, tenant }),
};
});
};
@@ -1,12 +1,13 @@
import Context from 'talk-server/graph/tenant/context';
import TenantContext from 'talk-server/graph/tenant/context';
import { Asset } from 'talk-server/models/asset';
export default {
asset: async (
_: any,
{ id, url }: { id?: string; url: string },
ctx: Context
ctx: TenantContext
): Promise<Asset> => {
return ctx.loaders.Assets.asset.load(id);
},
settings: async (parent: any, args: any, ctx: TenantContext) => ctx.tenant,
};
+5 -14
View File
@@ -1,15 +1,6 @@
import { addResolveFunctionsToSchema } from 'graphql-tools';
import { getGraphQLProjectConfig } from 'graphql-config';
import loadSchema from 'talk-server/graph/common/schema';
import resolvers from 'talk-server/graph/tenant/resolvers';
import resolvers from '../resolvers';
// Load the configuration from the provided `.graphqlconfig` file.
const config = getGraphQLProjectConfig(__dirname, 'tenant');
// Get the GraphQLSchema from the configuration.
const schema = config.getSchema();
// Attach the resolvers to the schema.
addResolveFunctionsToSchema({ schema, resolvers });
export default schema;
export default function getTenantSchema() {
return loadSchema('tenant', resolvers);
}
+27 -8
View File
@@ -1,10 +1,14 @@
import config, { Config } from './config';
import express, { Express } from 'express';
import http from 'http';
import { createApp, startApp } from './app';
import config, { Config } from './config';
import { createApp, listenAndServe, attachSubscriptionHandlers } from './app';
import logger from './logger';
import { create as createMongoDB } from './services/mongodb';
import { create as createRedis } from 'talk-server/services/redis';
import { createMongoDB } from './services/mongodb';
import { createRedisClient } from './services/redis';
import getManagementSchema from 'talk-server/graph/management/schema';
import getTenantSchema from 'talk-server/graph/tenant/schema';
import { Schemas } from 'talk-server/graph/schemas';
export interface ServerOptions {
config?: Config;
@@ -17,6 +21,10 @@ class Server {
// parentApp is the root application that the server will bind to.
private parentApp: Express;
// schemas are the set of GraphQLSchema objects for each schema used by the
// server.
private schemas: Schemas;
// config exposes application specific configuration.
public config: Config;
@@ -29,6 +37,12 @@ class Server {
this.config = config
.load(options.config || {})
.validate({ allowed: 'strict' });
// Load the graph schemas.
this.schemas = {
management: getManagementSchema(),
tenant: getTenantSchema(),
};
}
/**
@@ -47,17 +61,22 @@ class Server {
const mongo = await createMongoDB(config);
// Setup Redis.
const redis = await createRedis(config);
const redis = await createRedisClient(config);
// Create the Talk App, branching off from the parent app.
const app = await createApp(parent, {
const app: Express = await createApp({
parent,
mongo,
redis,
config: this.config,
schemas: this.schemas,
});
// Start the application.
this.httpServer = await startApp(port, app);
// Start the application and store the resulting http.Server.
this.httpServer = await listenAndServe(app, port);
// Setup the websocket servers on the new http.Server.
attachSubscriptionHandlers(this.schemas, this.httpServer);
logger.info({ port }, 'now listening');
}
+1 -1
View File
@@ -6,7 +6,7 @@ import { Config } from 'talk-server/config';
*
* @param config application configuration.
*/
export async function create(config: Config): Promise<Db> {
export async function createMongoDB(config: Config): Promise<Db> {
// Connect and create a client for MongoDB.
const client = await MongoClient.connect(config.get('mongodb'));
+1 -1
View File
@@ -6,6 +6,6 @@ import { Config } from 'talk-server/config';
*
* @param config application configuration.
*/
export async function create(config: Config): Promise<Redis> {
export async function createRedisClient(config: Config): Promise<Redis> {
return new RedisClient(config.get('redis'), {});
}