1 |
|
2 |
|
3 |
|
4 | import { HttpClient } from "./HttpClient";
|
5 | import { ILogger, LogLevel } from "./ILogger";
|
6 | import { NullLogger } from "./Loggers";
|
7 | import { IStreamSubscriber, ISubscription } from "./Stream";
|
8 | import { Subject } from "./Subject";
|
9 |
|
10 |
|
11 | export class Arg {
|
12 | public static isRequired(val: any, name: string): void {
|
13 | if (val === null || val === undefined) {
|
14 | throw new Error(`The '${name}' argument is required.`);
|
15 | }
|
16 | }
|
17 |
|
18 | public static isIn(val: any, values: any, name: string): void {
|
19 |
|
20 | if (!(val in values)) {
|
21 | throw new Error(`Unknown ${name} value: ${val}.`);
|
22 | }
|
23 | }
|
24 | }
|
25 |
|
26 |
|
27 | export class Platform {
|
28 |
|
29 | public static get isBrowser(): boolean {
|
30 | return typeof window === "object";
|
31 | }
|
32 |
|
33 | public static get isWebWorker(): boolean {
|
34 | return typeof self === "object" && "importScripts" in self;
|
35 | }
|
36 |
|
37 | public static get isNode(): boolean {
|
38 | return !this.isBrowser && !this.isWebWorker;
|
39 | }
|
40 | }
|
41 |
|
42 |
|
43 | export function getDataDetail(data: any, includeContent: boolean): string {
|
44 | let detail = "";
|
45 | if (isArrayBuffer(data)) {
|
46 | detail = `Binary data of length ${data.byteLength}`;
|
47 | if (includeContent) {
|
48 | detail += `. Content: '${formatArrayBuffer(data)}'`;
|
49 | }
|
50 | } else if (typeof data === "string") {
|
51 | detail = `String data of length ${data.length}`;
|
52 | if (includeContent) {
|
53 | detail += `. Content: '${data}'`;
|
54 | }
|
55 | }
|
56 | return detail;
|
57 | }
|
58 |
|
59 |
|
60 | export function formatArrayBuffer(data: ArrayBuffer): string {
|
61 | const view = new Uint8Array(data);
|
62 |
|
63 |
|
64 | let str = "";
|
65 | view.forEach((num) => {
|
66 | const pad = num < 16 ? "0" : "";
|
67 | str += `0x${pad}${num.toString(16)} `;
|
68 | });
|
69 |
|
70 |
|
71 | return str.substr(0, str.length - 1);
|
72 | }
|
73 |
|
74 |
|
75 |
|
76 | export function isArrayBuffer(val: any): val is ArrayBuffer {
|
77 | return val && typeof ArrayBuffer !== "undefined" &&
|
78 | (val instanceof ArrayBuffer ||
|
79 |
|
80 | (val.constructor && val.constructor.name === "ArrayBuffer"));
|
81 | }
|
82 |
|
83 |
|
84 | export async function sendMessage(logger: ILogger, transportName: string, httpClient: HttpClient, url: string, accessTokenFactory: (() => string | Promise<string>) | undefined, content: string | ArrayBuffer, logMessageContent: boolean): Promise<void> {
|
85 | let headers;
|
86 | if (accessTokenFactory) {
|
87 | const token = await accessTokenFactory();
|
88 | if (token) {
|
89 | headers = {
|
90 | ["Authorization"]: `Bearer ${token}`,
|
91 | };
|
92 | }
|
93 | }
|
94 |
|
95 | logger.log(LogLevel.Trace, `(${transportName} transport) sending data. ${getDataDetail(content, logMessageContent)}.`);
|
96 |
|
97 | const responseType = isArrayBuffer(content) ? "arraybuffer" : "text";
|
98 | const response = await httpClient.post(url, {
|
99 | content,
|
100 | headers,
|
101 | responseType,
|
102 | });
|
103 |
|
104 | logger.log(LogLevel.Trace, `(${transportName} transport) request complete. Response status: ${response.statusCode}.`);
|
105 | }
|
106 |
|
107 |
|
108 | export function createLogger(logger?: ILogger | LogLevel) {
|
109 | if (logger === undefined) {
|
110 | return new ConsoleLogger(LogLevel.Information);
|
111 | }
|
112 |
|
113 | if (logger === null) {
|
114 | return NullLogger.instance;
|
115 | }
|
116 |
|
117 | if ((logger as ILogger).log) {
|
118 | return logger as ILogger;
|
119 | }
|
120 |
|
121 | return new ConsoleLogger(logger as LogLevel);
|
122 | }
|
123 |
|
124 |
|
125 | export class SubjectSubscription<T> implements ISubscription<T> {
|
126 | private subject: Subject<T>;
|
127 | private observer: IStreamSubscriber<T>;
|
128 |
|
129 | constructor(subject: Subject<T>, observer: IStreamSubscriber<T>) {
|
130 | this.subject = subject;
|
131 | this.observer = observer;
|
132 | }
|
133 |
|
134 | public dispose(): void {
|
135 | const index: number = this.subject.observers.indexOf(this.observer);
|
136 | if (index > -1) {
|
137 | this.subject.observers.splice(index, 1);
|
138 | }
|
139 |
|
140 | if (this.subject.observers.length === 0 && this.subject.cancelCallback) {
|
141 | this.subject.cancelCallback().catch((_) => { });
|
142 | }
|
143 | }
|
144 | }
|
145 |
|
146 |
|
147 | export class ConsoleLogger implements ILogger {
|
148 | private readonly minimumLogLevel: LogLevel;
|
149 |
|
150 |
|
151 | public outputConsole: {
|
152 | error(message: any): void,
|
153 | warn(message: any): void,
|
154 | info(message: any): void,
|
155 | log(message: any): void,
|
156 | };
|
157 |
|
158 | constructor(minimumLogLevel: LogLevel) {
|
159 | this.minimumLogLevel = minimumLogLevel;
|
160 | this.outputConsole = console;
|
161 | }
|
162 |
|
163 | public log(logLevel: LogLevel, message: string): void {
|
164 | if (logLevel >= this.minimumLogLevel) {
|
165 | switch (logLevel) {
|
166 | case LogLevel.Critical:
|
167 | case LogLevel.Error:
|
168 | this.outputConsole.error(`[${new Date().toISOString()}] ${LogLevel[logLevel]}: ${message}`);
|
169 | break;
|
170 | case LogLevel.Warning:
|
171 | this.outputConsole.warn(`[${new Date().toISOString()}] ${LogLevel[logLevel]}: ${message}`);
|
172 | break;
|
173 | case LogLevel.Information:
|
174 | this.outputConsole.info(`[${new Date().toISOString()}] ${LogLevel[logLevel]}: ${message}`);
|
175 | break;
|
176 | default:
|
177 |
|
178 | this.outputConsole.log(`[${new Date().toISOString()}] ${LogLevel[logLevel]}: ${message}`);
|
179 | break;
|
180 | }
|
181 | }
|
182 | }
|
183 | }
|