Update - middlewares

This commit is contained in:
kamil.mysliwiec
2017-01-20 00:37:23 +01:00
parent f7c8d10fb2
commit 73997f52c4
36 changed files with 628 additions and 199 deletions

3
.gitignore vendored
View File

@@ -3,3 +3,6 @@
# IDE
/.idea
# misc
npm-debug.log

View File

@@ -1,111 +0,0 @@
0 info it worked if it ends with ok
1 verbose cli [ 'C:\\Program Files (x86)\\nodejs\\node.exe',
1 verbose cli 'C:\\Users\\Kamil\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js',
1 verbose cli 'i',
1 verbose cli '@types/rxjs' ]
2 info using npm@3.10.9
3 info using node@v6.9.2
4 silly loadCurrentTree Starting
5 silly install loadCurrentTree
6 silly install readLocalPackageData
7 silly fetchPackageMetaData @types/rxjs
8 silly fetchNamedPackageData @types/rxjs
9 silly mapToRegistry name @types/rxjs
10 silly mapToRegistry scope (from package name) @types
11 verbose mapToRegistry no registry URL found in name for scope @types
12 silly mapToRegistry using default registry
13 silly mapToRegistry registry https://registry.npmjs.org/
14 silly mapToRegistry data Result {
14 silly mapToRegistry raw: '@types/rxjs',
14 silly mapToRegistry scope: '@types',
14 silly mapToRegistry escapedName: '@types%2frxjs',
14 silly mapToRegistry name: '@types/rxjs',
14 silly mapToRegistry rawSpec: '',
14 silly mapToRegistry spec: 'latest',
14 silly mapToRegistry type: 'tag' }
15 silly mapToRegistry uri https://registry.npmjs.org/@types%2frxjs
16 verbose request uri https://registry.npmjs.org/@types%2frxjs
17 verbose request no auth needed
18 info attempt registry request try #1 at 10:01:48
19 verbose request id 27186320a047e737
20 http request GET https://registry.npmjs.org/@types%2frxjs
21 http 404 https://registry.npmjs.org/@types%2frxjs
22 verbose headers { 'content-type': 'application/json',
22 verbose headers 'cache-control': 'max-age=0',
22 verbose headers 'content-length': '2',
22 verbose headers 'accept-ranges': 'bytes',
22 verbose headers date: 'Sun, 08 Jan 2017 09:01:34 GMT',
22 verbose headers via: '1.1 varnish',
22 verbose headers age: '0',
22 verbose headers connection: 'keep-alive',
22 verbose headers 'x-served-by': 'cache-fra1246-FRA',
22 verbose headers 'x-cache': 'MISS',
22 verbose headers 'x-cache-hits': '0',
22 verbose headers 'x-timer': 'S1483866093.731878,VS0,VE329',
22 verbose headers vary: 'Accept-Encoding' }
23 silly get cb [ 404,
23 silly get { 'content-type': 'application/json',
23 silly get 'cache-control': 'max-age=0',
23 silly get 'content-length': '2',
23 silly get 'accept-ranges': 'bytes',
23 silly get date: 'Sun, 08 Jan 2017 09:01:34 GMT',
23 silly get via: '1.1 varnish',
23 silly get age: '0',
23 silly get connection: 'keep-alive',
23 silly get 'x-served-by': 'cache-fra1246-FRA',
23 silly get 'x-cache': 'MISS',
23 silly get 'x-cache-hits': '0',
23 silly get 'x-timer': 'S1483866093.731878,VS0,VE329',
23 silly get vary: 'Accept-Encoding' } ]
24 silly fetchPackageMetaData Error: Registry returned 404 for GET on https://registry.npmjs.org/@types%2frxjs
24 silly fetchPackageMetaData at makeError (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:302:12)
24 silly fetchPackageMetaData at CachingRegistryClient.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:280:14)
24 silly fetchPackageMetaData at Request._callback (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:210:14)
24 silly fetchPackageMetaData at Request.self.callback (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:187:22)
24 silly fetchPackageMetaData at emitTwo (events.js:106:13)
24 silly fetchPackageMetaData at Request.emit (events.js:191:7)
24 silly fetchPackageMetaData at Request.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:1048:10)
24 silly fetchPackageMetaData at emitOne (events.js:96:13)
24 silly fetchPackageMetaData at Request.emit (events.js:188:7)
24 silly fetchPackageMetaData at IncomingMessage.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:969:12)
24 silly fetchPackageMetaData error for @types/rxjs { Error: Registry returned 404 for GET on https://registry.npmjs.org/@types%2frxjs
24 silly fetchPackageMetaData at makeError (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:302:12)
24 silly fetchPackageMetaData at CachingRegistryClient.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:280:14)
24 silly fetchPackageMetaData at Request._callback (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:210:14)
24 silly fetchPackageMetaData at Request.self.callback (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:187:22)
24 silly fetchPackageMetaData at emitTwo (events.js:106:13)
24 silly fetchPackageMetaData at Request.emit (events.js:191:7)
24 silly fetchPackageMetaData at Request.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:1048:10)
24 silly fetchPackageMetaData at emitOne (events.js:96:13)
24 silly fetchPackageMetaData at Request.emit (events.js:188:7)
24 silly fetchPackageMetaData at IncomingMessage.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:969:12) pkgid: '@types/rxjs', statusCode: 404, code: 'E404' }
25 silly rollbackFailedOptional Starting
26 silly rollbackFailedOptional Finishing
27 silly runTopLevelLifecycles Finishing
28 silly install printInstalled
29 verbose stack Error: Registry returned 404 for GET on https://registry.npmjs.org/@types%2frxjs
29 verbose stack at makeError (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:302:12)
29 verbose stack at CachingRegistryClient.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:280:14)
29 verbose stack at Request._callback (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-client\lib\request.js:210:14)
29 verbose stack at Request.self.callback (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:187:22)
29 verbose stack at emitTwo (events.js:106:13)
29 verbose stack at Request.emit (events.js:191:7)
29 verbose stack at Request.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:1048:10)
29 verbose stack at emitOne (events.js:96:13)
29 verbose stack at Request.emit (events.js:188:7)
29 verbose stack at IncomingMessage.<anonymous> (C:\Users\Kamil\AppData\Roaming\npm\node_modules\npm\node_modules\request\request.js:969:12)
30 verbose statusCode 404
31 verbose pkgid @types/rxjs
32 verbose cwd C:\wamp\www\tracker-server
33 error Windows_NT 6.1.7601
34 error argv "C:\\Program Files (x86)\\nodejs\\node.exe" "C:\\Users\\Kamil\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js" "i" "@types/rxjs"
35 error node v6.9.2
36 error npm v3.10.9
37 error code E404
38 error 404 Registry returned 404 for GET on https://registry.npmjs.org/@types%2frxjs
39 error 404
40 error 404 '@types/rxjs' is not in the npm registry.
41 error 404 You should bug the author to publish it (or use the name yourself!)
42 error 404 Note that you can also install from a
43 error 404 tarball, folder, http url, or git url.
44 verbose exit [ 1, true ]

View File

@@ -13,12 +13,18 @@
"dependencies": {
"@types/body-parser": "0.0.33",
"@types/express": "^4.0.34",
"@types/jsonwebtoken": "^7.2.0",
"@types/lodash": "^4.14.45",
"@types/mongoose": "^4.7.2",
"@types/passport": "^0.3.2",
"@types/passport-jwt": "^2.0.19",
"body-parser": "^1.15.2",
"express": "^4.14.0",
"jsonwebtoken": "^7.2.1",
"lodash": "^4.17.4",
"mongoose": "^4.7.6",
"passport": "^0.3.2",
"passport-jwt": "^2.2.1",
"reflect-metadata": "^0.1.9",
"rxjs": "^5.0.3",
"socket.io": "^1.7.2",

View File

@@ -1,10 +1,13 @@
import* as express from "express";
import { ExpressConfig } from "./config";
import { NestApplication } from "./../nest/core/interfaces";
import { PassportJWTConfig } from "./config/passport-jwt.config";
export class Application implements NestApplication {
constructor(private app: express.Express) {
constructor(private app: express.Application) {
ExpressConfig.setupConfig(this.app);
PassportJWTConfig.setupConfig(this.app);
}
public start() {

View File

@@ -1,2 +1,3 @@
export * from "./app.config";
export * from "./express.config";
export * from "./passport-jwt.config";

View File

@@ -0,0 +1,45 @@
import * as _ from "lodash";
import { Application } from "express";
import * as passport from "passport";
import { ExtractJwt, Strategy, StrategyOptions } from "passport-jwt";
var users = [
{
id: 1,
name: 'jonathanmh',
password: '%2yx4'
},
{
id: 2,
name: 'test',
password: 'test'
}
];
export class PassportJWTConfig {
static readonly secretKey = "XD";
static readonly jwtOptions: StrategyOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeader(),
secretOrKey: PassportJWTConfig.secretKey,
};
static setupConfig(app: Application) {
this.init();
app.use(passport.initialize());
}
static init() {
var strategy = new Strategy(this.jwtOptions, (payload, next) => {
console.log('payload received', payload);
var user = users[_.findIndex(users, {id: payload.id})];
console.log(user);
next(null, user || false);
});
passport.use(strategy);
}
}

View File

@@ -1,3 +1,10 @@
import * as mongoose from "mongoose";
mongoose.connect("mongodb://localhost:27017/tracker");
mongoose.connect("mongodb://localhost:27017/tracker", {
server: {
socketOptions: {
socketTimeoutMS: 0,
connectTimeoutMS: 0
}
}
});
export { mongoose as db };

View File

@@ -1,9 +1,15 @@
import { Module } from "./../../nest/core/utils";
import { UsersModule } from "./users/users.module";
import { AuthModule } from "./auth/auth.module";
@Module({
modules: [
UsersModule
UsersModule,
AuthModule
],
})
export class ApplicationModule {}
export class ApplicationModule {
configure() {
console.log("app configured");
}
}

View File

@@ -0,0 +1,19 @@
import { Module } from "./../../../nest/core/utils";
import { AuthRoute } from "./login.route";
import { SharedModule } from "../shared.module";
@Module({
modules: [
SharedModule,
],
routes: [
AuthRoute
],
components: [
]
})
export class AuthModule {
configure() {
console.log("auth configured");
}
}

View File

@@ -0,0 +1,47 @@
import * as _ from "lodash";
import * as jwt from "jsonwebtoken";
import { Request, Response, NextFunction } from "express";
import { Route } from "./../../../nest/core/utils";
import { RequestMapping } from "../../../nest/core/utils/path.decorator";
import { RequestMethod } from "../../../nest/core/enums/request-method.enum";
import { PassportJWTConfig } from "../../config/passport-jwt.config";
var users = [
{
id: 1,
name: 'jonathanmh',
password: '%2yx4'
},
{
id: 2,
name: 'test',
password: 'test'
}
];
@Route({ path: "login" })
export class AuthRoute {
constructor() {}
@RequestMapping({ path: "/", method: RequestMethod.POST })
fetchToken(req: Request, res: Response, next: NextFunction) {
const { name, password } = req.body;
const user = users[_.findIndex(users, {name: name})];
if (!user){
res.status(401).json({message:"no such user found"});
}
if(user.password === password) {
const payload = {id: user.id};
const token = jwt.sign(payload, PassportJWTConfig.secretKey);
res.json({message: "ok", token: token});
}
else {
res.status(401).json({message:"passwords did not match"});
}
}
}

View File

@@ -0,0 +1,16 @@
import { Module } from "./../../nest/core/utils";
import { SharedService } from "./shared.service";
@Module({
components: [
SharedService,
],
exports: [
SharedService,
]
})
export class SharedModule {
configure() {
console.log("shared configured");
}
}

View File

@@ -0,0 +1,9 @@
import { Component } from "./../../nest/core/utils";
@Component()
export class SharedService {
constructor() {
console.log('stworzony');
}
}

View File

@@ -1,9 +1,13 @@
import { User } from "../../models/user";
import { Component } from "./../../../nest/core/utils";
import { SharedService } from "../shared.service";
@Component()
export class UsersQueryService {
constructor(private shared: SharedService) {
}
getAllUsers(): Promise<any> {
return new Promise((resolve) => {
User.find((err, res) => {

View File

@@ -0,0 +1,29 @@
import { Request, Response, NextFunction } from "express";
import { Route } from "./../../../nest/core/utils";
import { RequestMapping } from "../../../nest/core/utils/path.decorator";
import { UsersQueryService } from "./users-query.service";
import { RequestMethod } from "../../../nest/core/enums/request-method.enum";
@Route({ path: "users" })
export class UsersSecRoute {
constructor(private usersQueryService: UsersQueryService) {}
@RequestMapping({
path: "/",
method: RequestMethod.GET
})
async getAllUsers(req: Request, res: Response, next: NextFunction) {
console.log("sxd");
try {
const users = await this.usersQueryService.getAllUsers();
res.status(201).json(users);
next();
}
catch(e) {
next(e.message);
}
}
}

View File

@@ -0,0 +1,42 @@
import * as jwt from "jsonwebtoken";
import { UsersQueryService } from "./users-query.service";
import { Component } from "../../../nest/core/utils/component.decorator";
import { Middleware } from "../../../nest/core/middlewares/builder";
@Component()
export class JWTMiddleware implements Middleware {
constructor(private usersQueryService: UsersQueryService) {}
resolve() {
return (req, res, next) => {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
// verifies secret and checks exp
jwt.verify(token, "XD", function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}
}
}

View File

@@ -2,14 +2,35 @@ import { Module } from "./../../../nest/core/utils";
import { UsersRoute } from "./users.route";
import { UsersQueryService } from "./users-query.service";
import { UsersGateway } from "./users.gateway";
import { UsersSecRoute } from "./users-sec.route";
import { JWTMiddleware } from "./users.middleware";
import { SharedModule } from "../shared.module";
import { SharedService } from "../shared.service";
@Module({
modules: [
SharedModule,
],
routes: [
UsersRoute
UsersRoute,
UsersSecRoute
],
components: [
UsersQueryService,
UsersGateway,
]
})
export class UsersModule {}
export class UsersModule {
configure(router) {
return router
.use({
middlewares: [ JWTMiddleware ],
forRoutes: [
//UsersRoute,
{ path: "/users" }
]
});
}
}

View File

@@ -1,22 +1,25 @@
import { Request, Response, NextFunction } from "express";
import { Route } from "./../../../nest/core/utils";
import { Path } from "../../../nest/core/utils/path.decorator";
import { RequestMapping } from "../../../nest/core/utils/path.decorator";
import { UsersQueryService } from "./users-query.service";
import { RequestMethod } from "../../../nest/core/enums/request-method.enum";
@Route({ path: "users" })
export class UsersRoute {
constructor(private usersQueryService: UsersQueryService) {}
constructor(
private usersQueryService: UsersQueryService) {}
@Path({
@RequestMapping({
path: "/",
requestMethod: RequestMethod.GET
method: RequestMethod.GET
})
async getAllUsers(req: Request, res: Response, next: NextFunction) {
console.log("xd");
try {
const users = await this.usersQueryService.getAllUsers();
res.status(201).json(users);
next();
}
catch(e) {
next(e.message);

View File

@@ -4,11 +4,14 @@ import { Route, Component, AppModule } from "./interfaces";
export class NestContainer {
private readonly modules = new Map<AppModule, ModuleDependencies>();
addModule(module: AppModule) {
addModule(module) {
if(!this.modules.has(module)) {
this.modules.set(module, {
instance: new module(),
relatedModules: [],
components: new Map<Component, InstanceWrapper<any>>(),
routes: new Map<Route, InstanceWrapper<Route>>(),
exports: new Set<Component>(),
});
}
}
@@ -17,6 +20,15 @@ export class NestContainer {
return this.modules;
}
addRelatedModule(relatedModule: AppModule, module: AppModule) {
if(this.modules.has(module)) {
const storedModule = this.modules.get(module);
const related = this.modules.get(relatedModule);
storedModule.relatedModules.push(related);
}
}
addComponent(component: any, module: AppModule) {
if(this.modules.has(module)) {
const storedModule = this.modules.get(module);
@@ -24,6 +36,18 @@ export class NestContainer {
instance: null,
});
}
}
addExportedComponent(exportedComponent: any, module: AppModule) {
if(this.modules.has(module)) {
const storedModule = this.modules.get(module);
if (!storedModule.components.get(exportedComponent)) {
throw new Error("You are trying to export component, which is not in components array also.")
}
storedModule.exports.add(exportedComponent);
}
}
addRoute(route: Route, module: AppModule) {
@@ -37,9 +61,11 @@ export class NestContainer {
}
export interface ModuleDependencies {
export interface ModuleDependencies extends InstanceWrapper<AppModule> {
relatedModules: ModuleDependencies[];
components?: Map<Component, InstanceWrapper<Component>>;
routes?: Map<Route, InstanceWrapper<Route>>;
exports?: Set<Component>;
}
export interface InstanceWrapper<T> {

View File

@@ -16,14 +16,14 @@ export class NestInjector {
}
private createInstancesOfComponents(module: ModuleDependencies) {
module.components.forEach((wrapper, type) => {
this.instanceLoader.loadInstanceOfComponent(type, module.components);
module.components.forEach((wrapper, componentType) => {
this.instanceLoader.loadInstanceOfComponent(componentType, module);
});
}
private createInstancesOfRoutes(module: ModuleDependencies) {
module.routes.forEach((wrapper, type) => {
this.instanceLoader.loadInstanceOfRoute(type, module.routes, module.components);
module.routes.forEach((wrapper, routeType) => {
this.instanceLoader.loadInstanceOfRoute(routeType, module);
});
}

View File

@@ -1,62 +1,123 @@
import "reflect-metadata";
import { Route } from "./interfaces";
import { InstanceWrapper } from "./container";
import { InstanceWrapper, ModuleDependencies } from "./container";
import { Component } from "./interfaces/component.interface";
import { Middleware } from "./middlewares/builder";
export class NestInstanceLoader {
loadInstanceOfRoute(
routeType,
collection: Map<Route, InstanceWrapper<Route>>,
components: Map<Component, InstanceWrapper<Component>>
) {
const currentFetchedRoute = collection.get(routeType);
loadInstanceOfMiddleware(middlewareType, collection: Map<Middleware, Middleware>, module: ModuleDependencies) {
const currentFetchedMiddleware = collection.get(middlewareType);
if(currentFetchedMiddleware === null) {
const argsInstances = [];
const constructorParams = Reflect.getMetadata('design:paramtypes', middlewareType) || [];
constructorParams.map((param) => {
if (typeof param === "undefined") {
const msg = `Can't create instance of ${middlewareType} `
+ `It is possible that you are trying to do circular-dependency A->B, B->A.`;
throw new Error(msg);
}
const componentType = this.resolveComponentInstance(module, param, middlewareType);
argsInstances.push(componentType);
});
collection.set(middlewareType, new middlewareType(...argsInstances))
}
}
loadInstanceOfRoute(routeType, module: ModuleDependencies) {
const { routes } = module;
const currentFetchedRoute = routes.get(routeType);
if(currentFetchedRoute.instance === null) {
const argsInstances = [];
const params = Reflect.getMetadata('design:paramtypes', routeType) || [];
const constructorParams = Reflect.getMetadata('design:paramtypes', routeType) || [];
params.map((param) => {
if (typeof param === "undefined")
throw new Error(`Can't create instance of ` + routeType +
`. It is possible that you are trying to do cycle-dependency A->B, B->A.`);
constructorParams.map((param) => {
if (typeof param === "undefined") {
const msg = `Can't create instance of ${routeType} `
+ `It is possible that you are trying to do circular-dependency A->B, B->A.`;
const componentType = this.resolveComponentInstance(components, param, routeType);
throw new Error(msg);
}
const componentType = this.resolveComponentInstance(module, param, routeType);
argsInstances.push(componentType);
});
currentFetchedRoute.instance = new routeType(...argsInstances);
}
}
private resolveComponentInstance(collection: Map<Component, InstanceWrapper<Component>>, param, componentType) {
if (!collection.has(param))
throw new Error(`Can't recognize dependencies of ` + componentType);
const instanceWrapper = collection.get(param);
private resolveComponentInstance(module: ModuleDependencies, param, componentType) {
const components = module.components;
const instanceWrapper = this.scanForComponent(components, param, module, componentType);
if (instanceWrapper.instance === null) {
this.loadInstanceOfComponent(param, collection);
this.loadInstanceOfComponent(param, module);
}
return instanceWrapper.instance;
}
public loadInstanceOfComponent(componentType, collection: Map<Component, InstanceWrapper<Component>>) {
const currentFetchedComponentInstance = collection.get(componentType);
private scanForComponent(components, param, module, componentType) {
let instanceWrapper = null;
if (!components.has(param)) {
instanceWrapper = this.scanForComponentInRelatedModules(module, param);
if (instanceWrapper === null) {
throw new Error(`Can't recognize dependencies of ` + componentType);
}
}
else {
instanceWrapper = components.get(param);
}
return instanceWrapper;
}
public loadInstanceOfComponent(componentType, module: ModuleDependencies) {
const { components } = module;
const currentFetchedComponentInstance = components.get(componentType);
if(currentFetchedComponentInstance.instance === null) {
const argsInstances = [];
const params = Reflect.getMetadata('design:paramtypes', componentType) || [];
const constructorParams = Reflect.getMetadata('design:paramtypes', componentType) || [];
params.map((param) => {
if (typeof param === "undefined")
throw new Error(`Can't create instance of ` + componentType +
`. It is possible that you are trying to do cycle-dependency A->B, B->A.`);
constructorParams.map((param) => {
if (typeof param === "undefined") {
const msg = `Can't create instance of ${componentType} `
+ `It is possible that you are trying to do circular-dependency A->B, B->A.`;
const instance = this.resolveComponentInstance(collection, param, componentType);
throw new Error(msg);
}
const instance = this.resolveComponentInstance(module, param, componentType);
argsInstances.push(instance);
});
currentFetchedComponentInstance.instance = new componentType(...argsInstances);
}
}
private scanForComponentInRelatedModules(module: ModuleDependencies, componentType) {
const relatedModules = module.relatedModules;
let component = null;
relatedModules.forEach((relatedModule) => {
const components = relatedModule.components;
const exports = relatedModule.exports;
if (exports.has(componentType) && components.has(componentType)) {
component = components.get(componentType);
if (component.instance === null) {
this.loadInstanceOfComponent(componentType, relatedModule);
}
}
});
return component;
}
}

View File

@@ -4,4 +4,6 @@ export interface ModuleProps {
modules?: AppModule[],
components?: any[],
routes?: Route[],
exports?: any[],
}

View File

@@ -1,6 +1,6 @@
import { RequestMethod } from "./../enums";
export interface PathProps {
export interface RequestMappingProps {
path: string,
requestMethod?: RequestMethod
method?: RequestMethod
}

View File

@@ -0,0 +1,26 @@
import "reflect-metadata";
import { Route } from "../interfaces/route.interface";
import { RouteProps } from "../interfaces/route-props.interface";
export class MiddlewaresBuilder {
private storedConfiguration: MiddlewareConfiguration[] = [];
use(configuration: MiddlewareConfiguration) {
this.storedConfiguration.push(configuration);
return this;
}
build() {
return this.storedConfiguration.slice(0);
}
}
export interface MiddlewareConfiguration {
middlewares: Middleware | Middleware[];
forRoutes: (Route | RouteProps)[];
}
export interface Middleware {
resolve: () => (res, req, next) => void;
}

View File

@@ -0,0 +1,30 @@
import "reflect-metadata";
import { Middleware, MiddlewareConfiguration } from "./builder";
import { InstanceWrapper } from "../container";
import { Route } from "../interfaces/route.interface";
import { RouteProps } from "../interfaces/route-props.interface";
export class MiddlewaresContainer {
private readonly midlewares = new Map<Middleware, Middleware>();
private readonly configs: MiddlewareConfiguration[] = [];
getMiddlewares(): Map<Middleware, Middleware> {
return this.midlewares;
}
getConfigs(): MiddlewareConfiguration[] {
return this.configs.slice(0);
}
addConfig(configList: MiddlewareConfiguration[]) {
configList.map((config) => {
(<Middleware[]>config.middlewares).map((middleware) => this.midlewares.set(middleware, null));
this.configs.push(config);
});
}
}
export interface MiddlewareDependencies extends InstanceWrapper<Middleware> {
forRoutes: (Route | RouteProps)[];
}

View File

@@ -0,0 +1,3 @@
export interface GatewayProps {
namespace?: string,
}

View File

@@ -0,0 +1,4 @@
export interface Gateway {
onInit: (server: any) => void;
connection: (client: any) => void;
}

View File

@@ -0,0 +1,2 @@
export * from "./gateway-props.interface";
export * from "./gateway.interface";

View File

@@ -0,0 +1,58 @@
import "reflect-metadata";
import { Express } from "express";
import { NestContainer } from "../container";
import { MiddlewaresBuilder, MiddlewareConfiguration, Middleware } from "./builder";
import { MiddlewaresContainer } from "./container";
import { MiddlewaresResolver } from "./resolver";
import { RouteProps } from "../interfaces/route-props.interface";
export class MiddlewaresModule {
private static container = new MiddlewaresContainer();
private static resolver: MiddlewaresResolver;
static setup(container: NestContainer) {
const modules = container.getModules();
this.resolver = new MiddlewaresResolver(this.container, container);
modules.forEach((module) => {
const instance = module.instance;
this.loadConfiguration(instance);
this.resolver.resolveInstances(module);
});
}
static loadConfiguration(instance) {
if (!instance["configure"]) {
return;
}
const middlewaresBuilder = instance.configure(new MiddlewaresBuilder());
if (middlewaresBuilder) {
const config = middlewaresBuilder.build();
this.container.addConfig(config);
}
}
static setupMiddlewares(app: Express) {
const configs = this.container.getConfigs();
configs.map((config: MiddlewareConfiguration) => {
config.forRoutes.map((route: RouteProps) => {
const path = route.path;
(<Middleware[]>config.middlewares).map((middlewareType) => {
const middlewaresCollection = this.container.getMiddlewares();
const middleware = middlewaresCollection.get(middlewareType);
if (!middleware) {
throw new Error("Runtime error!");
}
app.use(path, middleware.resolve());
});
});
});
}
}

View File

@@ -0,0 +1,28 @@
import "reflect-metadata";
import { Middleware, MiddlewareConfiguration } from "./builder";
import { InstanceWrapper, NestContainer, ModuleDependencies } from "../container";
import { Route } from "../interfaces/route.interface";
import { RouteProps } from "../interfaces/route-props.interface";
import { MiddlewaresContainer } from "./container";
import { NestInstanceLoader } from "../instance-loader";
export class MiddlewaresResolver {
private instanceLoader = new NestInstanceLoader();
constructor(
private middlewaresContainer: MiddlewaresContainer,
private modulesContainer: NestContainer) {}
resolveInstances(module: ModuleDependencies) {
const middlewares = this.middlewaresContainer.getMiddlewares();
middlewares.forEach((val, middlewareType) => {
this.instanceLoader.loadInstanceOfMiddleware(middlewareType, middlewares, module);
});
}
}
export interface MiddlewareDependencies extends InstanceWrapper<Middleware> {
forRoutes: (Route | RouteProps)[];
}

View File

@@ -0,0 +1 @@
export * from "./socket-gateway.decorator";

View File

@@ -0,0 +1,10 @@
import "reflect-metadata";
import { GatewayProps } from "../interfaces";
export const SocketGateway = (props?: GatewayProps): ClassDecorator => {
props = props || {};
return (target: Object) => {
Reflect.defineMetadata("__isGateway", true, target);
Reflect.defineMetadata("namespace", props.namespace, target);
}
};

View File

@@ -1,5 +1,5 @@
import "reflect-metadata";
import * as express from "express";
import { Router, RequestHandler, ErrorRequestHandler } from "express";
import { Route } from "./interfaces";
import { RequestMethod } from "./enums";
@@ -9,24 +9,24 @@ export class RouterBuilder {
public build(instance: Route, routePrototype: Function) {
const router = this.routerFactory();
const path = this.fetchRouterPath(routePrototype);
const routerPaths = this.scanForPaths(instance);
let path = Reflect.getMetadata("path", routePrototype);
path = this.validateRoutePath(path);
const routePaths = this.scanForPaths(instance);
this.applyPathsToRouter(router, routePaths);
this.applyPathsToRouter(router, routerPaths);
return { path, router }
}
private validateRoutePath(path: string): string {
if(!path)
throw new Error("Path not defined in @Path() annotation!");
if(path.charAt(0) !== '/') {
return '/' + path;
private fetchRouterPath(routePrototype) {
const path = Reflect.getMetadata("path", routePrototype);
return this.validateRoutePath(path);
}
return path;
private validateRoutePath(routePath: string): string {
if(!routePath) {
throw new Error("RequestMapping not defined in @RequestMapping() annotation!");
}
return (routePath.charAt(0) !== '/') ? '/' + routePath : routePath;
}
private scanForPaths(instance: Route): RoutePathProperties[] {
@@ -47,34 +47,44 @@ export class RouterBuilder {
}
private exploreMethodMetadata(instance, instancePrototype, methodName): RoutePathProperties {
let method: express.RequestHandler | express.ErrorRequestHandler;
method = instancePrototype[methodName];
const method: RequestHandler | ErrorRequestHandler = instancePrototype[methodName];
let path: string = Reflect.getMetadata("path", method);
if(!path) {
return;
let routePath: string = Reflect.getMetadata("path", method);
if(!routePath) {
return null;
}
routePath = this.validateRoutePath(routePath);
path = this.validateRoutePath(path);
const requestMethod: RequestMethod = Reflect.getMetadata("requestMethod", method);
const requestMethod: RequestMethod = Reflect.getMetadata("method", method);
return {
path,
path: routePath,
requestMethod,
func: (method as Function).bind(instance),
func: (<Function>method).bind(instance),
};
}
private applyPathsToRouter(router: express.Router, routePaths: RoutePathProperties[]) {
private applyPathsToRouter(router: Router, routePaths: RoutePathProperties[]) {
(routePaths || []).map((pathProperties) => {
this.bindMethodToRouter(router, pathProperties);
});
}
private bindMethodToRouter(router: Router, pathProperties: RoutePathProperties) {
const { path, requestMethod, func } = pathProperties;
const routerMethod = this.retrieveRouterMethod(router, requestMethod);
routerMethod(path, func);
}
private retrieveRouterMethod(router: Router, requestMethod: RequestMethod) {
switch(requestMethod) {
case RequestMethod.GET: {
router.get(path, func);
break;
case RequestMethod.POST: {
return router.post.bind(router);
}
default: {
return router.get.bind(router);
}
}
});
}
}
@@ -82,5 +92,5 @@ export class RouterBuilder {
interface RoutePathProperties {
path: string,
requestMethod: RequestMethod,
func: express.RequestHandler | express.ErrorRequestHandler,
func: RequestHandler | ErrorRequestHandler | any,
}

View File

@@ -17,11 +17,11 @@ export class NestRoutesResolver {
const modules = this.container.getModules();
modules.forEach((module) => {
this.resolveRouters(module.routes, expressInstance);
this.setupRouters(module.routes, expressInstance);
});
}
private resolveRouters(routes: Map<Route, InstanceWrapper<Route>>, expressInstance: Express) {
private setupRouters(routes: Map<Route, InstanceWrapper<Route>>, expressInstance: Express) {
routes.forEach(({ instance }, routePrototype: Function) => {
const { path, router } = this.routerBuilder.build(instance, routePrototype);

View File

@@ -24,19 +24,34 @@ export class NestDependenciesScanner {
private scanModulesForDependencies() {
const modules = this.container.getModules();
modules.forEach((deps, module) => {
const modules = Reflect.getMetadata('modules', module) || [];
modules.map((related) => this.storeRelatedModule(related, module));
const components = Reflect.getMetadata('components', module) || [];
components.map((component) => this.storeComponent(component, module));
const routes = Reflect.getMetadata('routes', module) || [];
routes.map((route) => this.storeRoute(route, module));
const exports = Reflect.getMetadata('exports', module) || [];
exports.map((exportedComponent) => this.storeExportedComponent(exportedComponent, module));
});
}
private storeRelatedModule(related, module: AppModule) {
this.container.addRelatedModule(related, module);
}
private storeComponent(component, module: AppModule) {
this.container.addComponent(component, module);
}
private storeExportedComponent(exportedComponent, module: AppModule) {
this.container.addExportedComponent(exportedComponent, module);
}
private storeRoute(route: Route, module: AppModule) {
this.container.addRoute(route, module);
}

View File

@@ -1,13 +1,13 @@
import "reflect-metadata";
import { PathProps } from "./../interfaces";
import { RequestMappingProps } from "./../interfaces";
import { RequestMethod } from "./../enums";
export const Path = (props: PathProps): MethodDecorator => {
const requestMethod = props.requestMethod || RequestMethod.GET;
export const RequestMapping = (props: RequestMappingProps): MethodDecorator => {
const requestMethod = props.method || RequestMethod.GET;
return function(target, key, descriptor: PropertyDescriptor) {
Reflect.defineMetadata("path", props.path, descriptor.value);
Reflect.defineMetadata("requestMethod", requestMethod, descriptor.value);
Reflect.defineMetadata("method", requestMethod, descriptor.value);
return descriptor;
}

View File

@@ -5,6 +5,7 @@ import { NestInjector } from "./core/injector";
import { NestRoutesResolver } from "./core/routes-resolver";
import { NestContainer } from "./core/container";
import { SocketModule } from "./socket/socket-module";
import { MiddlewaresModule } from "./core/middlewares/module";
export class NestRunner {
private static container = new NestContainer();
@@ -25,14 +26,16 @@ export class NestRunner {
private static setupModules() {
SocketModule.setup(NestRunner.container);
MiddlewaresModule.setup(NestRunner.container);
}
private static setupApplication<T extends NestApplicationFactory>(app: { new(app): T }): NestApplication {
try {
const expressInstance = express();
this.routesResolver.resolve(expressInstance);
const appInstance = new app(expressInstance);
MiddlewaresModule.setupMiddlewares(expressInstance);
this.routesResolver.resolve(expressInstance);
return appInstance;
}
catch(e) {