diff --git a/src/api/abstract-bshc-client.ts b/src/api/abstract-bshc-client.ts index 099e998..2f04371 100644 --- a/src/api/abstract-bshc-client.ts +++ b/src/api/abstract-bshc-client.ts @@ -8,6 +8,8 @@ import { BshbError } from "../error/bshb-error"; import { BshbErrorType } from "../error/bshb-error-type"; import { BshbCallOptions } from "../bshb-call-options"; import { BshbUtils } from "../bshb-utils"; +import * as util from "util"; +import * as http from "http"; /** * This class provides a simple call for all defined clients @@ -101,8 +103,6 @@ export abstract class AbstractBshcClient { requestOptions.headers["Systempassword"] = Buffer.from(options.systemPassword).toString("base64"); } - this.logger.fine("requestOptions: ", requestOptions); - let postData: string | undefined = undefined; if (data) { if (typeof data === "string") { @@ -113,27 +113,18 @@ export abstract class AbstractBshcClient { requestOptions.headers["Content-Length"] = postData.length; } - this.logger.fine(""); - this.logger.fine( - "call:\n" + - requestOptions.method + - " | " + - requestOptions.hostname + - ":" + - requestOptions.port + - requestOptions.path + this.logger.debug( + ` +Request: (${requestOptions.method}) ${requestOptions.hostname}:${requestOptions.port}${requestOptions.path} +Headers: +${util.inspect(requestOptions.headers, { colors: true })} +Body: +${util.inspect(data, { colors: true, depth: 10 })} +` ); - this.logger.fine("headers:\n", requestOptions.headers); - this.logger.fine("body:\n", postData ? postData : ""); - this.logger.fine(""); return new Observable>((observer) => { const req = https.request(requestOptions, (res) => { - this.logger.fine(""); - this.logger.fine("response information:"); - this.logger.fine("status:", res.statusCode); - this.logger.fine("headers:", res.headers); - const chunks: any[] = []; res @@ -147,31 +138,34 @@ export abstract class AbstractBshcClient { dataString = data.toString("utf-8"); } - this.logger.fine("content: ", dataString); - this.logger.fine(""); - try { - let parsedData = undefined; - if (dataString) { - parsedData = JSON.parse(dataString); - } - if (res.statusCode && res.statusCode >= 300) { + this.logResponse(requestOptions, res, dataString); + this.handleError( observer, BshbErrorType.ERROR, `call to BSHC failed with HTTP status=${res.statusCode}` ); } else { + let parsedData = undefined; + if (dataString) { + parsedData = JSON.parse(dataString); + } + + this.logResponse(requestOptions, res, parsedData); + observer.next(new BshbResponse(res, parsedData)); } } catch (e) { + this.logResponse(requestOptions, res, dataString); observer.error(new BshbError("error during parsing response from BSHC", BshbErrorType.PARSING, e)); } finally { observer.complete(); } }) .on("error", (err) => { + this.logResponse(requestOptions, res, undefined); this.handleError(observer, BshbErrorType.ERROR, err); }); }); @@ -197,17 +191,28 @@ export abstract class AbstractBshcClient { } private handleError(observer: Subscriber>, errorType: BshbErrorType, errorDetails: any): void { - this.logger.error("error during call to BSHC: ", errorDetails); + this.logger.error("Error during call to BSHC: ", errorDetails); try { if (errorDetails instanceof Error) { - observer.error(new BshbError("error during call to BSHC: ", errorType, errorDetails)); + observer.error(new BshbError("Error during call to BSHC: ", errorType, errorDetails)); } else if (typeof errorDetails === "string") { observer.error(new BshbError(errorDetails, errorType)); } else { - observer.error(new BshbError("error during call to BSHC", errorType)); + observer.error(new BshbError("Error during call to BSHC", errorType)); } } finally { observer.complete(); } } + + private logResponse(requestOptions: RequestOptions, res: http.IncomingMessage, data?: any) { + this.logger.debug(` +Response: (${requestOptions.method}) ${requestOptions.hostname}:${requestOptions.port}${requestOptions.path} +Status: ${util.inspect(res.statusCode, { colors: true })} +Headers: +${util.inspect(res.headers, { colors: true })} +Content: +${typeof data === "object" ? util.inspect(data, { colors: true }) : data} +`); + } } diff --git a/src/api/pairing-client.ts b/src/api/pairing-client.ts index 81cc851..c4986ff 100644 --- a/src/api/pairing-client.ts +++ b/src/api/pairing-client.ts @@ -53,8 +53,7 @@ export class PairingClient extends AbstractBshcClient { token: string; }> > { - const clientData = new BoschClientData(name, identifier, certificate); - const postData = JSON.stringify(clientData); + const postData = new BoschClientData(name, identifier, certificate); return new Observable>((subscriber) => { this.simpleCall<{ url: string; token: string }>( diff --git a/test/bosch-smart-home-bridge.spec.ts b/test/bosch-smart-home-bridge.spec.ts index bb33f70..9435357 100644 --- a/test/bosch-smart-home-bridge.spec.ts +++ b/test/bosch-smart-home-bridge.spec.ts @@ -1,12 +1,12 @@ import { expect } from "chai"; -import { BshbUtils } from "../src/bshb-utils"; -import { BoschSmartHomeBridge, BoschSmartHomeBridgeBuilder } from "../src"; -import { createBshcRouter } from "./bshc-mock"; +import { BoschSmartHomeBridge, BoschSmartHomeBridgeBuilder, BshbUtils } from "../src"; +import { DefaultTestLogger, resetBshcAdminRouter, resetBshcRouter } from "./bshc-mock"; import { Router } from "express"; describe("BoschSmartHomeBridge", () => { let bshb: BoschSmartHomeBridge; let bshc: Router; + let bshcAdmin: Router; before(() => { const certResult = BshbUtils.generateClientCertificate(); bshb = BoschSmartHomeBridgeBuilder.builder() @@ -14,24 +14,13 @@ describe("BoschSmartHomeBridge", () => { .withClientCert(certResult.cert) .withClientPrivateKey(certResult.private) .withIgnoreCertificateCheck(true) - /*.withLogger( - new (class implements Logger { - fine(message?: any, ...optionalParams: any[]): void {} - - debug(message?: any, ...optionalParams: any[]): void {} - - info(message?: any, ...optionalParams: any[]): void {} - - warn(message?: any, ...optionalParams: any[]): void {} - - error(message?: any, ...optionalParams: any[]): void {} - })() - )*/ + .withLogger(new DefaultTestLogger()) .build(); }); beforeEach(() => { - bshc = createBshcRouter(); + bshc = resetBshcRouter(); + bshcAdmin = resetBshcAdminRouter(); }); it("test not paired", (done) => { @@ -39,6 +28,10 @@ describe("BoschSmartHomeBridge", () => { res.statusCode = 401; res.json({}); }); + bshcAdmin.post("/smarthome/clients", (req, res) => { + res.statusCode = 401; + res.json({}); + }); const identifier = BshbUtils.generateIdentifier(); diff --git a/test/bshc-mock.ts b/test/bshc-mock.ts index aa24747..e8a3c76 100644 --- a/test/bshc-mock.ts +++ b/test/bshc-mock.ts @@ -1,23 +1,34 @@ -import express, { Router } from "express"; +import express from "express"; import bodyParser from "body-parser"; -import { BshbUtils } from "../src"; +import { BshbUtils, Logger } from "../src"; import https from "https"; const bshc = express(); -let bshcRouter: Router; -export const createBshcRouter = () => { +let bshcRouter = express.Router(); +export const resetBshcRouter = () => { bshcRouter = express.Router(); return bshcRouter; }; + +let bshcAdminRouter = express.Router(); +export const resetBshcAdminRouter = () => { + bshcAdminRouter = express.Router(); + return bshcAdminRouter; +}; const bshcAdmin = express(); bshc.use(bodyParser.json()); bshc.use((req, res, next) => { - console.log(`@${req.method} ${req.path}`); bshcRouter(req, res, next); next(); }); +bshcAdmin.use(bodyParser.json()); +bshcAdmin.use((req, res, next) => { + bshcAdminRouter(req, res, next); + next(); +}); + const certResult = BshbUtils.generateClientCertificate(); const server = https.createServer({ key: certResult.private, cert: certResult.cert }, bshc); @@ -25,3 +36,51 @@ const adminServer = https.createServer({ key: certResult.private, cert: certResu server.listen(8444, () => {}); adminServer.listen(8443, () => {}); + +export class DefaultTestLogger implements Logger { + fine(message?: any, ...optionalParams: any[]): void { + DefaultTestLogger.log("debug", message, ...optionalParams); + } + + debug(message?: any, ...optionalParams: any[]): void { + DefaultTestLogger.log("debug", message, ...optionalParams); + } + + info(message?: any, ...optionalParams: any[]): void { + DefaultTestLogger.log("info", message, ...optionalParams); + } + + warn(message?: any, ...optionalParams: any[]): void { + DefaultTestLogger.log("warn", message, ...optionalParams); + } + + error(message?: any, ...optionalParams: any[]): void { + DefaultTestLogger.log("error", message, ...optionalParams); + } + + private static log(msgType: "debug" | "info" | "warn" | "error", message?: any, ...optionalParams: any[]) { + if (optionalParams[0] && optionalParams[0].ca) { + optionalParams = [ + { + path: optionalParams[0].path, + method: optionalParams[0].method, + headers: optionalParams[0].headers, + body: optionalParams[0].body, + }, + ]; + } + if (message) { + if (optionalParams.length > 0) { + console[msgType](message, optionalParams); + } else { + console[msgType](message); + } + } else { + if (optionalParams.length > 0) { + console[msgType](optionalParams); + } else { + console[msgType](); + } + } + } +}