|
1 | 1 | import type { IMethodExecuteOptions, IRestfulConnect, IRestMethodOperator } from '@unioc/web'
|
2 | 2 | import type { INestJSMethodParamMetadata, NestJSMethodWrapper } from './method-wrapper'
|
| 3 | +import { UnauthorizedException } from '@nestjs/common' |
| 4 | +import { ExecutionContextBuilder } from '../execution-context-builder' |
| 5 | +import { EndingHandler } from './ending-handler' |
3 | 6 | import { NestJSMethodOperator } from './method-operator'
|
4 | 7 |
|
5 | 8 | export class NestJSRestfulHandler implements IRestfulConnect.Handler {
|
@@ -55,7 +58,7 @@ export class NestJSRestfulHandler implements IRestfulConnect.Handler {
|
55 | 58 | }
|
56 | 59 | }
|
57 | 60 |
|
58 |
| - private async _buildParams(methodWrapper: NestJSMethodWrapper, ctx: IRestfulConnect.WebContext): Promise<unknown[]> { |
| 61 | + protected async buildParams(methodWrapper: NestJSMethodWrapper, ctx: IRestfulConnect.WebContext): Promise<unknown[]> { |
59 | 62 | const params: unknown[] = []
|
60 | 63 | const metadata = methodWrapper.getMethodParamMetadata()
|
61 | 64 | const paramTypes = methodWrapper.getParamTypes()
|
@@ -109,83 +112,59 @@ export class NestJSRestfulHandler implements IRestfulConnect.Handler {
|
109 | 112 | && typeof options.adapterType === 'string'
|
110 | 113 | }
|
111 | 114 |
|
| 115 | + private readonly _endingHandler = new EndingHandler() |
| 116 | + |
| 117 | + protected async executeGuards(methodWrapper: NestJSMethodWrapper, ctx: IRestfulConnect.WebContext, params: unknown[]): Promise<void> { |
| 118 | + const methodGuards = methodWrapper.getMethodGuards() |
| 119 | + const controllerGuards = methodWrapper.getControllerOperator().getControllerGuards() |
| 120 | + |
| 121 | + const controllerTarget = methodWrapper |
| 122 | + .getControllerOperator() |
| 123 | + .getControllerWrapper() |
| 124 | + .getClassWrapper() |
| 125 | + .getTarget() |
| 126 | + |
| 127 | + const resolvedGuards = await methodWrapper.getControllerOperator() |
| 128 | + .getControllerWrapper() |
| 129 | + .getRestfulScanner() |
| 130 | + .mergeAndResolveToInstance( |
| 131 | + methodGuards, |
| 132 | + controllerGuards, |
| 133 | + ) |
| 134 | + |
| 135 | + const canActivate = await methodWrapper.getControllerOperator() |
| 136 | + .getControllerWrapper() |
| 137 | + .getRestfulScanner() |
| 138 | + .executeGuards( |
| 139 | + resolvedGuards, |
| 140 | + new ExecutionContextBuilder( |
| 141 | + params, |
| 142 | + 'http', |
| 143 | + controllerTarget, |
| 144 | + controllerTarget.prototype[methodWrapper.getPropertyKey()], |
| 145 | + ), |
| 146 | + ) |
| 147 | + |
| 148 | + if (canActivate === false) |
| 149 | + throw new UnauthorizedException() |
| 150 | + } |
| 151 | + |
112 | 152 | async handleConnectRequest(methodOperator: IRestMethodOperator, ctx: IRestfulConnect.WebContext): Promise<void> {
|
113 | 153 | if (!(methodOperator instanceof NestJSMethodOperator))
|
114 | 154 | throw new Error('Method operator is not a NestJSMethodOperator')
|
115 | 155 |
|
116 | 156 | const methodWrapper = methodOperator.getMethodWrapper()
|
117 |
| - const params = await this._buildParams(methodWrapper, ctx) |
118 | 157 |
|
| 158 | + // 1. Build params with pipes |
| 159 | + const params = await this.buildParams(methodWrapper, ctx) |
| 160 | + // 2. Execute guards |
| 161 | + await this.executeGuards(methodWrapper, ctx, params) |
| 162 | + // 3. Execute the controller method |
119 | 163 | const result = await methodWrapper.execute(params, {
|
120 | 164 | webContext: ctx,
|
121 | 165 | adapterType: 'connect',
|
122 | 166 | handlerType: 'nestjs',
|
123 | 167 | })
|
124 |
| - |
125 |
| - if (ctx.response.writableEnded || ctx.response.writableFinished) |
126 |
| - return |
127 |
| - |
128 |
| - if ('send' in ctx.response && typeof ctx.response.send === 'function' && 'status' in ctx.response && typeof ctx.response.status === 'function') { |
129 |
| - if (result.type === 'result') { |
130 |
| - ctx.response.send(result.value) |
131 |
| - } |
132 |
| - else { |
133 |
| - ctx.response.status(500).send({ |
134 |
| - statusCode: 500, |
135 |
| - message: 'Internal Server Error', |
136 |
| - error: await this._toReadableError(result.error), |
137 |
| - }) |
138 |
| - } |
139 |
| - return |
140 |
| - } |
141 |
| - |
142 |
| - if (result.type === 'result') { |
143 |
| - ctx.response.end(await this._toSendableString(result.value)) |
144 |
| - } |
145 |
| - else { |
146 |
| - ctx.response.statusCode = 500 |
147 |
| - ctx.response.end( |
148 |
| - await this._toSendableString({ |
149 |
| - statusCode: 500, |
150 |
| - message: 'Internal Server Error', |
151 |
| - error: await this._toReadableError(result.error), |
152 |
| - }), |
153 |
| - ) |
154 |
| - } |
155 |
| - } |
156 |
| - |
157 |
| - private async _toReadableError(error: unknown): Promise<Record<string, unknown>> { |
158 |
| - if (error && error instanceof Error) { |
159 |
| - const result: Record<string, unknown> = {} |
160 |
| - if (error.name !== undefined) |
161 |
| - result.name = error.name |
162 |
| - for (const key of Reflect.ownKeys(error)) |
163 |
| - result[key as string] = error[key as keyof Error] |
164 |
| - return result |
165 |
| - } |
166 |
| - return error as Record<string, unknown> |
167 |
| - } |
168 |
| - |
169 |
| - private async _stringifyAsync(data: unknown): Promise<string> { |
170 |
| - return JSON.stringify(data) |
171 |
| - } |
172 |
| - |
173 |
| - private async _toSendableString(data: unknown): Promise<string> { |
174 |
| - if (typeof data === 'string') |
175 |
| - return data |
176 |
| - if (typeof data === 'object' && data !== null) { |
177 |
| - return await this._stringifyAsync(data) |
178 |
| - .catch(async error => this._stringifyAsync({ |
179 |
| - statusCode: 500, |
180 |
| - message: 'Internal Server Error', |
181 |
| - error: await this._toReadableError(error), |
182 |
| - })) |
183 |
| - .catch(async error => this._stringifyAsync({ |
184 |
| - statusCode: 500, |
185 |
| - message: 'Internal Server Error', |
186 |
| - error: await this._toReadableError(error), |
187 |
| - })) |
188 |
| - } |
189 |
| - return String(data) |
| 168 | + await this._endingHandler.sendConnectEndingResponse(ctx, result) |
190 | 169 | }
|
191 | 170 | }
|
0 commit comments