camstreamerlib 3.1.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CamOverlayAPI.d.ts +2 -2
- package/CamOverlayDrawingAPI.d.ts +7 -6
- package/CamOverlayDrawingAPI.js +47 -80
- package/CamOverlayPainter/Painter.d.ts +2 -1
- package/CamOverlayPainter/Painter.js +9 -5
- package/CamScripterAPICameraEventsGenerator.d.ts +10 -5
- package/CamScripterAPICameraEventsGenerator.js +48 -63
- package/CamStreamerAPI.d.ts +2 -2
- package/CamSwitcherAPI.d.ts +2 -2
- package/CamSwitcherEvents.d.ts +7 -5
- package/CamSwitcherEvents.js +38 -32
- package/CameraVapix.d.ts +2 -2
- package/CameraVapix.js +11 -10
- package/CreatePackage.js +12 -5
- package/DefaultAgent.d.ts +4 -4
- package/DefaultAgent.js +27 -27
- package/README.md +11 -1
- package/VapixEvents.d.ts +4 -3
- package/VapixEvents.js +13 -20
- package/events/AxisCameraStationEvents.d.ts +2 -2
- package/internal/Digest.d.ts +2 -1
- package/internal/Digest.js +8 -3
- package/internal/HttpRequestSender.d.ts +28 -0
- package/internal/HttpRequestSender.js +118 -0
- package/internal/WsClient.d.ts +5 -4
- package/internal/WsClient.js +63 -30
- package/internal/common.d.ts +7 -1
- package/internal/common.js +5 -1
- package/package.json +2 -2
- package/internal/HttpRequest.d.ts +0 -15
- package/internal/HttpRequest.js +0 -82
- package/internal/fetchInsecure.d.ts +0 -4
- package/internal/fetchInsecure.js +0 -14
package/CreatePackage.js
CHANGED
|
@@ -4,16 +4,19 @@ const AdmZip = require("adm-zip");
|
|
|
4
4
|
const Path = require("path");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const child_process_1 = require("child_process");
|
|
7
|
+
const productionModulesFolder = 'production_modules';
|
|
7
8
|
function isDirectory(path) {
|
|
8
9
|
const stat = fs.statSync(path);
|
|
9
10
|
return stat.isDirectory();
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
function getPackageVersion(folder) {
|
|
12
|
+
function getPackageInfo(folder) {
|
|
13
13
|
try {
|
|
14
14
|
const manifest = fs.readFileSync(Path.join(folder, 'manifest.json'));
|
|
15
15
|
const manifestParsed = JSON.parse(manifest.toString());
|
|
16
|
-
return
|
|
16
|
+
return {
|
|
17
|
+
packageName: manifestParsed.package_name,
|
|
18
|
+
packageVersion: manifestParsed.package_version.replace(/\./g, '_'),
|
|
19
|
+
};
|
|
17
20
|
}
|
|
18
21
|
catch (err) {
|
|
19
22
|
console.error('Get package version:', err);
|
|
@@ -81,8 +84,12 @@ function main(args) {
|
|
|
81
84
|
options.typeScriptPackage = true;
|
|
82
85
|
}
|
|
83
86
|
const folder = Path.resolve('.');
|
|
84
|
-
const
|
|
85
|
-
|
|
87
|
+
const packageInfo = getPackageInfo(folder);
|
|
88
|
+
if (packageInfo === undefined) {
|
|
89
|
+
console.error('Package info not found');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const zipFile = `${options.outputFolder}/${packageInfo.packageName}_${packageInfo.packageVersion}.zip`;
|
|
86
93
|
if (fs.existsSync(zipFile)) {
|
|
87
94
|
try {
|
|
88
95
|
fs.unlinkSync(zipFile);
|
package/DefaultAgent.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
import {
|
|
3
|
+
import { IClient, HttpOptions } from './internal/common';
|
|
4
4
|
export declare class DefaultAgent implements IClient {
|
|
5
5
|
private tls;
|
|
6
|
-
private tlsInsecure;
|
|
7
6
|
private ip;
|
|
8
7
|
private port;
|
|
9
8
|
private user;
|
|
10
9
|
private pass;
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
private httpRequestSender;
|
|
11
|
+
constructor(opt?: HttpOptions);
|
|
13
12
|
get(path: string, parameters?: Record<string, string>, headers?: Record<string, string>): Promise<Response>;
|
|
14
13
|
post(path: string, data: string | Buffer | FormData, parameters?: Record<string, string>, headers?: Record<string, string>): Promise<Response>;
|
|
14
|
+
private getBaseConnectionParams;
|
|
15
15
|
}
|
package/DefaultAgent.js
CHANGED
|
@@ -10,22 +10,37 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.DefaultAgent = void 0;
|
|
13
|
-
const
|
|
14
|
-
function isBrowserEnvironment() {
|
|
15
|
-
return typeof process === 'undefined' || process.versions === null || process.versions.node === null;
|
|
16
|
-
}
|
|
13
|
+
const HttpRequestSender_1 = require("./internal/HttpRequestSender");
|
|
17
14
|
class DefaultAgent {
|
|
18
15
|
constructor(opt = {}) {
|
|
19
|
-
var _a, _b, _c, _d, _e
|
|
16
|
+
var _a, _b, _c, _d, _e;
|
|
20
17
|
this.tls = (_a = opt.tls) !== null && _a !== void 0 ? _a : false;
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
|
|
18
|
+
this.ip = (_b = opt.ip) !== null && _b !== void 0 ? _b : '127.0.0.1';
|
|
19
|
+
this.port = (_c = opt.port) !== null && _c !== void 0 ? _c : (this.tls ? 443 : 80);
|
|
20
|
+
this.user = (_d = opt.user) !== null && _d !== void 0 ? _d : '';
|
|
21
|
+
this.pass = (_e = opt.pass) !== null && _e !== void 0 ? _e : '';
|
|
22
|
+
let agentOptions;
|
|
23
|
+
if (opt.tlsInsecure !== undefined || opt.keepAlive !== undefined) {
|
|
24
|
+
agentOptions = {
|
|
25
|
+
rejectUnaurhorized: !opt.tlsInsecure,
|
|
26
|
+
keepAlive: opt.keepAlive,
|
|
27
|
+
};
|
|
28
28
|
}
|
|
29
|
+
this.httpRequestSender = new HttpRequestSender_1.HttpRequestSender(agentOptions);
|
|
30
|
+
}
|
|
31
|
+
get(path, parameters = {}, headers) {
|
|
32
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
const options = this.getBaseConnectionParams('GET', path, parameters);
|
|
34
|
+
options.headers = headers;
|
|
35
|
+
return this.httpRequestSender.sendRequest(options);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
post(path, data, parameters = {}, headers) {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
const options = this.getBaseConnectionParams('POST', path, parameters);
|
|
41
|
+
options.headers = headers;
|
|
42
|
+
return this.httpRequestSender.sendRequest(options, data);
|
|
43
|
+
});
|
|
29
44
|
}
|
|
30
45
|
getBaseConnectionParams(method, path, params) {
|
|
31
46
|
if (path.indexOf('?') === -1) {
|
|
@@ -46,22 +61,7 @@ class DefaultAgent {
|
|
|
46
61
|
path: path,
|
|
47
62
|
user: this.user,
|
|
48
63
|
pass: this.pass,
|
|
49
|
-
rejectUnauthorized: !this.tlsInsecure,
|
|
50
64
|
};
|
|
51
65
|
}
|
|
52
|
-
get(path, parameters = {}, headers) {
|
|
53
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
-
const options = this.getBaseConnectionParams('GET', path, parameters);
|
|
55
|
-
options.headers = headers;
|
|
56
|
-
return (0, HttpRequest_1.sendRequest)(options);
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
post(path, data, parameters = {}, headers) {
|
|
60
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
const options = this.getBaseConnectionParams('POST', path, parameters);
|
|
62
|
-
options.headers = headers;
|
|
63
|
-
return (0, HttpRequest_1.sendRequest)(options, data);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
66
|
}
|
|
67
67
|
exports.DefaultAgent = DefaultAgent;
|
package/README.md
CHANGED
|
@@ -14,13 +14,23 @@ npm install camstreamerlib
|
|
|
14
14
|
# Documentation for Node.js modules
|
|
15
15
|
|
|
16
16
|
- [HttpServer](doc/HttpServer.md) is a module for processing HTTP requests in your scripts. It also automatically serves up the content from html directory or you can register paths which you can process by your own (e.g. http://$CAMERA_IP/local/camscripter/proxy/$MY_PACKAGE_NAME/control.cgi).
|
|
17
|
+
|
|
17
18
|
- [CameraVapix](doc/CameraVapix.md) is a module to access Axis camera VAPIX interface.
|
|
19
|
+
|
|
18
20
|
- [CamStreamerAPI](doc/CamStreamerAPI.md) is a module for easy control of video streaming in the CamStreamer ACAP application (RTMP, HLS, SRT and MPEG-TS protocols).
|
|
21
|
+
|
|
19
22
|
- [CamOverlayAPI](doc/CamOverlayAPI.md) is a module to access CamOverlay HTTP interface.
|
|
23
|
+
|
|
20
24
|
- [CamOverlayDrawingAPI](doc/CamOverlayDrawingAPI.md) is a module for easy control of CamOverlay drawing API. For more details on supported video overlay drawing functions see https://camstreamer.com/camoverlay-api1
|
|
21
|
-
|
|
25
|
+
|
|
22
26
|
- [CamOverlayPainter/](doc/CamOverlayPainter.md) contains three modules which makes easier to use CamOverlayDrawingAPI.
|
|
23
27
|
|
|
28
|
+
- [CamScripterAPICameraEventsGenerator](doc/CamScripterAPICameraEventsGenerator.md) is a module which allows generating events on an Axis camera. These events can be used for triggers in the Axis camera rule engine (events/actions). It is also an easy way how to integrate events and metadata in VMS systems which support Axis camera events.
|
|
29
|
+
|
|
30
|
+
- [CamSwitcherEvents](doc/CamSwitcherEvents.md) is a module which allows receiving events from CamSwitcher ACAP application.
|
|
31
|
+
|
|
32
|
+
- [VapixEvents](doc/VapixEvents.md) is a module which allows receiving camera events from the VAPIX API.
|
|
33
|
+
|
|
24
34
|
## For Developers
|
|
25
35
|
|
|
26
36
|
### Publishing to npm repository
|
package/VapixEvents.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { EventEmitter2 as EventEmitter } from 'eventemitter2';
|
|
2
|
-
import {
|
|
3
|
-
export type VapixEventsOptions =
|
|
2
|
+
import { WsOptions } from './internal/common';
|
|
3
|
+
export type VapixEventsOptions = WsOptions;
|
|
4
4
|
export declare class VapixEvents extends EventEmitter {
|
|
5
|
-
private ws?;
|
|
6
5
|
private tls;
|
|
7
6
|
private tlsInsecure;
|
|
8
7
|
private ip;
|
|
9
8
|
private port;
|
|
10
9
|
private user;
|
|
11
10
|
private pass;
|
|
11
|
+
private ws;
|
|
12
12
|
constructor(options?: VapixEventsOptions);
|
|
13
13
|
connect(): void;
|
|
14
14
|
disconnect(): void;
|
|
15
|
+
private createWsClient;
|
|
15
16
|
private isReservedEventName;
|
|
16
17
|
}
|
package/VapixEvents.js
CHANGED
|
@@ -13,12 +13,16 @@ class VapixEvents extends eventemitter2_1.EventEmitter2 {
|
|
|
13
13
|
this.port = (_d = options.port) !== null && _d !== void 0 ? _d : (this.tls ? 443 : 80);
|
|
14
14
|
this.user = (_e = options.user) !== null && _e !== void 0 ? _e : 'root';
|
|
15
15
|
this.pass = (_f = options.pass) !== null && _f !== void 0 ? _f : '';
|
|
16
|
+
this.createWsClient();
|
|
16
17
|
eventemitter2_1.EventEmitter2.call(this);
|
|
17
18
|
}
|
|
18
19
|
connect() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
this.ws.open();
|
|
21
|
+
}
|
|
22
|
+
disconnect() {
|
|
23
|
+
this.ws.close();
|
|
24
|
+
}
|
|
25
|
+
createWsClient() {
|
|
22
26
|
const options = {
|
|
23
27
|
tls: this.tls,
|
|
24
28
|
tlsInsecure: this.tlsInsecure,
|
|
@@ -30,7 +34,6 @@ class VapixEvents extends eventemitter2_1.EventEmitter2 {
|
|
|
30
34
|
};
|
|
31
35
|
this.ws = new WsClient_1.WsClient(options);
|
|
32
36
|
this.ws.on('open', () => {
|
|
33
|
-
var _a;
|
|
34
37
|
const topics = [];
|
|
35
38
|
const eventNames = this.eventNames();
|
|
36
39
|
for (let i = 0; i < eventNames.length; i++) {
|
|
@@ -48,16 +51,16 @@ class VapixEvents extends eventemitter2_1.EventEmitter2 {
|
|
|
48
51
|
eventFilterList: topics,
|
|
49
52
|
},
|
|
50
53
|
};
|
|
51
|
-
|
|
54
|
+
this.ws.send(JSON.stringify(topicFilter));
|
|
52
55
|
});
|
|
53
56
|
this.ws.on('message', (data) => {
|
|
54
57
|
const dataJSON = JSON.parse(data.toString());
|
|
55
58
|
if (dataJSON.method === 'events:configure') {
|
|
56
59
|
if (dataJSON.error === undefined) {
|
|
57
|
-
this.emit('
|
|
60
|
+
this.emit('open');
|
|
58
61
|
}
|
|
59
62
|
else {
|
|
60
|
-
this.emit('
|
|
63
|
+
this.emit('error', dataJSON.error);
|
|
61
64
|
this.disconnect();
|
|
62
65
|
}
|
|
63
66
|
return;
|
|
@@ -66,24 +69,14 @@ class VapixEvents extends eventemitter2_1.EventEmitter2 {
|
|
|
66
69
|
this.emit(eventName, dataJSON);
|
|
67
70
|
});
|
|
68
71
|
this.ws.on('error', (error) => {
|
|
69
|
-
this.emit('
|
|
70
|
-
this.ws = undefined;
|
|
72
|
+
this.emit('error', error);
|
|
71
73
|
});
|
|
72
74
|
this.ws.on('close', () => {
|
|
73
|
-
|
|
74
|
-
this.emit('eventsClose');
|
|
75
|
-
}
|
|
76
|
-
this.ws = undefined;
|
|
75
|
+
this.emit('close');
|
|
77
76
|
});
|
|
78
|
-
this.ws.open();
|
|
79
|
-
}
|
|
80
|
-
disconnect() {
|
|
81
|
-
if (this.ws !== undefined) {
|
|
82
|
-
this.ws.close();
|
|
83
|
-
}
|
|
84
77
|
}
|
|
85
78
|
isReservedEventName(eventName) {
|
|
86
|
-
return eventName === '
|
|
79
|
+
return eventName === 'open' || eventName === 'close' || eventName === 'error';
|
|
87
80
|
}
|
|
88
81
|
}
|
|
89
82
|
exports.VapixEvents = VapixEvents;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IClient,
|
|
2
|
-
export type AcsEventsOptions =
|
|
1
|
+
import { IClient, HttpOptions } from '../internal/common';
|
|
2
|
+
export type AcsEventsOptions = HttpOptions;
|
|
3
3
|
export declare class AxisCameraStationEvents {
|
|
4
4
|
private sourceKey;
|
|
5
5
|
private client;
|
package/internal/Digest.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare class Digest {
|
|
2
|
-
|
|
2
|
+
private nonceCount;
|
|
3
|
+
getAuthHeader(user: string, pass: string, method: string, uri: string, wwwAuthenticateHeader: string): string;
|
|
3
4
|
}
|
package/internal/Digest.js
CHANGED
|
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Digest = void 0;
|
|
4
4
|
const crypto = require("crypto");
|
|
5
5
|
class Digest {
|
|
6
|
-
|
|
6
|
+
constructor() {
|
|
7
|
+
this.nonceCount = 1;
|
|
8
|
+
}
|
|
9
|
+
getAuthHeader(user, pass, method, uri, wwwAuthenticateHeader) {
|
|
7
10
|
const digestItems = {};
|
|
8
11
|
const digestArr = wwwAuthenticateHeader.substring(wwwAuthenticateHeader.indexOf('Digest') + 6).split(',');
|
|
9
12
|
for (let i = 0; i < digestArr.length; i++) {
|
|
@@ -14,11 +17,12 @@ class Digest {
|
|
|
14
17
|
}
|
|
15
18
|
const HA1 = crypto.createHash('md5').update(`${user}:${digestItems['realm']}:${pass}`).digest('hex');
|
|
16
19
|
const HA2 = crypto.createHash('md5').update(`${method}:${uri}`).digest('hex');
|
|
20
|
+
const ncValue = ('00000000' + this.nonceCount.toString(16)).slice(-8);
|
|
17
21
|
let response;
|
|
18
22
|
if (digestItems['qop'] !== undefined) {
|
|
19
23
|
response = crypto
|
|
20
24
|
.createHash('md5')
|
|
21
|
-
.update(`${HA1}:${digestItems['nonce']}:
|
|
25
|
+
.update(`${HA1}:${digestItems['nonce']}:${ncValue}:162d50aa594e9648:auth:${HA2}`)
|
|
22
26
|
.digest('hex');
|
|
23
27
|
}
|
|
24
28
|
else {
|
|
@@ -31,8 +35,9 @@ class Digest {
|
|
|
31
35
|
`uri="${uri}",` +
|
|
32
36
|
`response="${response}"`;
|
|
33
37
|
if (digestItems['qop'] !== undefined) {
|
|
34
|
-
header +=
|
|
38
|
+
header += `,qop=auth,nc=${ncValue},cnonce="162d50aa594e9648"`;
|
|
35
39
|
}
|
|
40
|
+
this.nonceCount++;
|
|
36
41
|
return header;
|
|
37
42
|
}
|
|
38
43
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
export type HttpRequestOptions = {
|
|
4
|
+
method?: string;
|
|
5
|
+
protocol: string;
|
|
6
|
+
host: string;
|
|
7
|
+
port: number;
|
|
8
|
+
path: string;
|
|
9
|
+
user?: string;
|
|
10
|
+
pass?: string;
|
|
11
|
+
timeout?: number;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
export type AgentOptions = {
|
|
15
|
+
rejectUnaurhorized?: boolean;
|
|
16
|
+
keepAlive?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export declare class HttpRequestSender {
|
|
19
|
+
private agent?;
|
|
20
|
+
private authData?;
|
|
21
|
+
constructor(agentOptions?: AgentOptions);
|
|
22
|
+
sendRequest(options: HttpRequestOptions, postData?: Buffer | string | FormData): Promise<Response>;
|
|
23
|
+
private sendRequestWithAuth;
|
|
24
|
+
private static getURL;
|
|
25
|
+
private getAuthorization;
|
|
26
|
+
private invalidateAuthorization;
|
|
27
|
+
private static getAuthHeader;
|
|
28
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.HttpRequestSender = void 0;
|
|
13
|
+
const Digest_1 = require("./Digest");
|
|
14
|
+
const undici_1 = require("undici");
|
|
15
|
+
const common_1 = require("./common");
|
|
16
|
+
class HttpRequestSender {
|
|
17
|
+
constructor(agentOptions) {
|
|
18
|
+
if ((0, common_1.isBrowserEnvironment)()) {
|
|
19
|
+
if (agentOptions !== undefined) {
|
|
20
|
+
throw new Error('Agent options can be specified only in Node.js environment.');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.agent = new undici_1.Agent({
|
|
25
|
+
connect: { rejectUnauthorized: agentOptions === null || agentOptions === void 0 ? void 0 : agentOptions.rejectUnaurhorized, keepAlive: agentOptions === null || agentOptions === void 0 ? void 0 : agentOptions.keepAlive },
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
sendRequest(options, postData) {
|
|
30
|
+
return this.sendRequestWithAuth(options, postData);
|
|
31
|
+
}
|
|
32
|
+
sendRequestWithAuth(options, postData, wwwAuthenticateHeader) {
|
|
33
|
+
var _a;
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
const url = HttpRequestSender.getURL(options);
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
if (options.timeout !== undefined) {
|
|
38
|
+
setTimeout(() => controller.abort(new Error('Request timeout')), options.timeout);
|
|
39
|
+
}
|
|
40
|
+
const authorization = this.getAuthorization(options, wwwAuthenticateHeader);
|
|
41
|
+
if (authorization !== undefined) {
|
|
42
|
+
(_a = options.headers) !== null && _a !== void 0 ? _a : (options.headers = {});
|
|
43
|
+
options.headers['Authorization'] = authorization;
|
|
44
|
+
}
|
|
45
|
+
let res;
|
|
46
|
+
if (this.agent) {
|
|
47
|
+
const req = new undici_1.Request(url, { body: postData, method: options.method, headers: options.headers });
|
|
48
|
+
res = yield (0, undici_1.fetch)(req, { signal: controller.signal, dispatcher: this.agent });
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const req = new Request(url, { body: postData, method: options.method, headers: options.headers });
|
|
52
|
+
res = yield fetch(req, { signal: controller.signal });
|
|
53
|
+
}
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
this.invalidateAuthorization();
|
|
56
|
+
}
|
|
57
|
+
if (res.status === 401) {
|
|
58
|
+
const authenticateHeader = res.headers.get('www-authenticate');
|
|
59
|
+
if (authenticateHeader !== null &&
|
|
60
|
+
authenticateHeader.indexOf('Digest') !== -1 &&
|
|
61
|
+
wwwAuthenticateHeader === undefined) {
|
|
62
|
+
return this.sendRequestWithAuth(options, postData, authenticateHeader);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
return res;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return res;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
static getURL(options) {
|
|
74
|
+
const url = new URL(`${options.protocol}//${options.host}:${options.port}${options.path}`);
|
|
75
|
+
return url.toString();
|
|
76
|
+
}
|
|
77
|
+
getAuthorization(options, wwwAuthenticateHeader) {
|
|
78
|
+
if (options.user === undefined || options.pass === undefined) {
|
|
79
|
+
this.authData = undefined;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (this.authData &&
|
|
83
|
+
(this.authData.host !== options.host ||
|
|
84
|
+
this.authData.port !== options.port ||
|
|
85
|
+
this.authData.user !== options.user ||
|
|
86
|
+
this.authData.pass !== options.pass ||
|
|
87
|
+
(wwwAuthenticateHeader !== undefined && this.authData.wwwAuthenticateHeader !== wwwAuthenticateHeader))) {
|
|
88
|
+
this.authData = undefined;
|
|
89
|
+
}
|
|
90
|
+
if (this.authData === undefined) {
|
|
91
|
+
this.authData = {
|
|
92
|
+
host: options.host,
|
|
93
|
+
port: options.port,
|
|
94
|
+
user: options.user,
|
|
95
|
+
pass: options.pass,
|
|
96
|
+
wwwAuthenticateHeader,
|
|
97
|
+
digest: new Digest_1.Digest(),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return HttpRequestSender.getAuthHeader(options, this.authData);
|
|
101
|
+
}
|
|
102
|
+
invalidateAuthorization() {
|
|
103
|
+
this.authData = undefined;
|
|
104
|
+
}
|
|
105
|
+
static getAuthHeader(options, authData) {
|
|
106
|
+
var _a;
|
|
107
|
+
if (options.user === undefined || options.pass === undefined) {
|
|
108
|
+
throw new Error('No credentials found');
|
|
109
|
+
}
|
|
110
|
+
if (authData.wwwAuthenticateHeader !== undefined && authData.wwwAuthenticateHeader.indexOf('Digest') !== -1) {
|
|
111
|
+
return authData.digest.getAuthHeader(options.user, options.pass, (_a = options.method) !== null && _a !== void 0 ? _a : 'GET', options.path, authData.wwwAuthenticateHeader);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
return `Basic ${btoa(options.user + ':' + options.pass)}`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.HttpRequestSender = HttpRequestSender;
|
package/internal/WsClient.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import * as EventEmitter from 'events';
|
|
4
|
-
import {
|
|
5
|
-
export type WsClientOptions =
|
|
4
|
+
import { WsOptions } from './common';
|
|
5
|
+
export type WsClientOptions = WsOptions & {
|
|
6
6
|
address: string;
|
|
7
7
|
headers?: Record<string, string>;
|
|
8
8
|
pingInterval?: number;
|
|
@@ -19,9 +19,10 @@ export declare class WsClient extends EventEmitter {
|
|
|
19
19
|
private isAlive;
|
|
20
20
|
private pingTimer?;
|
|
21
21
|
private ws?;
|
|
22
|
+
private isClosed;
|
|
22
23
|
constructor(options: WsClientOptions);
|
|
23
|
-
open(
|
|
24
|
+
open(wwwAuthenticateHeader?: string): void;
|
|
24
25
|
send(data: Buffer | string): void;
|
|
25
26
|
close(): void;
|
|
26
|
-
private
|
|
27
|
+
private closeWsConnection;
|
|
27
28
|
}
|
package/internal/WsClient.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.WsClient = void 0;
|
|
4
13
|
const EventEmitter = require("events");
|
|
5
14
|
const WebSocket = require("ws");
|
|
15
|
+
const timersPromises = require("timers/promises");
|
|
6
16
|
const Digest_1 = require("./Digest");
|
|
7
17
|
class WsClient extends EventEmitter {
|
|
8
18
|
constructor(options) {
|
|
9
19
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
10
20
|
super();
|
|
11
21
|
this.isAlive = true;
|
|
22
|
+
this.isClosed = false;
|
|
12
23
|
const tls = (_a = options === null || options === void 0 ? void 0 : options.tls) !== null && _a !== void 0 ? _a : false;
|
|
13
24
|
const tlsInsecure = (_b = options === null || options === void 0 ? void 0 : options.tlsInsecure) !== null && _b !== void 0 ? _b : false;
|
|
14
25
|
const ip = (_c = options === null || options === void 0 ? void 0 : options.ip) !== null && _c !== void 0 ? _c : '127.0.0.1';
|
|
@@ -26,7 +37,11 @@ class WsClient extends EventEmitter {
|
|
|
26
37
|
headers: (_h = options.headers) !== null && _h !== void 0 ? _h : {},
|
|
27
38
|
};
|
|
28
39
|
}
|
|
29
|
-
open(
|
|
40
|
+
open(wwwAuthenticateHeader) {
|
|
41
|
+
if (this.ws !== undefined) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.isClosed = false;
|
|
30
45
|
if (this.protocol === undefined) {
|
|
31
46
|
this.ws = new WebSocket(this.address, this.wsOptions);
|
|
32
47
|
}
|
|
@@ -35,39 +50,42 @@ class WsClient extends EventEmitter {
|
|
|
35
50
|
}
|
|
36
51
|
this.ws.binaryType = 'arraybuffer';
|
|
37
52
|
this.isAlive = true;
|
|
38
|
-
this.pingTimer = setInterval(() => {
|
|
53
|
+
this.pingTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
39
54
|
var _a;
|
|
40
55
|
if ((this.ws && this.ws.readyState !== WebSocket.OPEN) || this.isAlive === false) {
|
|
41
56
|
this.emit('error', new Error('Connection timeout'));
|
|
42
|
-
this.
|
|
57
|
+
yield this.closeWsConnection();
|
|
43
58
|
}
|
|
44
59
|
else {
|
|
45
60
|
this.isAlive = false;
|
|
46
61
|
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.ping();
|
|
47
62
|
}
|
|
48
|
-
}, this.pingInterval);
|
|
63
|
+
}), this.pingInterval);
|
|
49
64
|
this.ws.on('pong', () => {
|
|
50
65
|
this.isAlive = true;
|
|
51
66
|
});
|
|
52
|
-
if (
|
|
53
|
-
this.wsOptions.headers['Authorization'] = Digest_1.Digest.getAuthHeader(this.user, this.pass, 'GET', this.digestAddress,
|
|
67
|
+
if (wwwAuthenticateHeader !== undefined) {
|
|
68
|
+
this.wsOptions.headers['Authorization'] = new Digest_1.Digest().getAuthHeader(this.user, this.pass, 'GET', this.digestAddress, wwwAuthenticateHeader);
|
|
54
69
|
}
|
|
55
|
-
this.ws.on('unexpected-response', (req, res) => {
|
|
70
|
+
this.ws.on('unexpected-response', (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
var _b;
|
|
56
72
|
if (res.statusCode === 401 && res.headers['www-authenticate'] !== undefined) {
|
|
57
73
|
if (this.pingTimer) {
|
|
58
74
|
clearInterval(this.pingTimer);
|
|
59
75
|
}
|
|
76
|
+
(_b = this.ws) === null || _b === void 0 ? void 0 : _b.removeAllListeners();
|
|
77
|
+
this.ws = undefined;
|
|
60
78
|
this.open(res.headers['www-authenticate']);
|
|
61
79
|
}
|
|
62
80
|
else {
|
|
63
|
-
|
|
64
|
-
this.
|
|
81
|
+
this.emit('error', new Error('Status code: ' + res.statusCode));
|
|
82
|
+
yield this.closeWsConnection();
|
|
65
83
|
}
|
|
66
|
-
});
|
|
84
|
+
}));
|
|
67
85
|
this.ws.on('open', () => this.emit('open'));
|
|
68
86
|
this.ws.on('message', (data) => this.emit('message', data));
|
|
69
87
|
this.ws.on('error', (error) => this.emit('error', error));
|
|
70
|
-
this.ws.on('close', () => this.
|
|
88
|
+
this.ws.on('close', () => this.closeWsConnection());
|
|
71
89
|
}
|
|
72
90
|
send(data) {
|
|
73
91
|
if (this.ws === undefined) {
|
|
@@ -78,30 +96,45 @@ class WsClient extends EventEmitter {
|
|
|
78
96
|
}
|
|
79
97
|
}
|
|
80
98
|
close() {
|
|
81
|
-
if (this.
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
this.handleCloseEvent();
|
|
86
|
-
if (this.ws.readyState !== WebSocket.CLOSING && this.ws.readyState !== WebSocket.CLOSED) {
|
|
87
|
-
this.ws.close();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
99
|
+
if (this.isClosed) {
|
|
100
|
+
return;
|
|
91
101
|
}
|
|
102
|
+
this.isClosed = true;
|
|
103
|
+
const currentWs = this.ws;
|
|
104
|
+
this.closeWsConnection().catch((err) => {
|
|
105
|
+
console.error(err);
|
|
106
|
+
});
|
|
92
107
|
setTimeout(() => {
|
|
93
|
-
if (
|
|
94
|
-
|
|
108
|
+
if (currentWs && currentWs.readyState !== WebSocket.CLOSED) {
|
|
109
|
+
currentWs.terminate();
|
|
95
110
|
}
|
|
96
111
|
}, 5000);
|
|
97
112
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
closeWsConnection() {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
try {
|
|
116
|
+
if (this.ws === undefined) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.ws.removeAllListeners();
|
|
120
|
+
if (this.pingTimer) {
|
|
121
|
+
clearInterval(this.pingTimer);
|
|
122
|
+
}
|
|
123
|
+
if (this.ws.readyState !== WebSocket.CONNECTING &&
|
|
124
|
+
this.ws.readyState !== WebSocket.CLOSING &&
|
|
125
|
+
this.ws.readyState !== WebSocket.CLOSED) {
|
|
126
|
+
this.ws.close();
|
|
127
|
+
}
|
|
128
|
+
this.ws = undefined;
|
|
129
|
+
this.emit('close');
|
|
130
|
+
if (!this.isClosed) {
|
|
131
|
+
yield timersPromises.setTimeout(10000);
|
|
132
|
+
yield this.open();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
}
|
|
137
|
+
});
|
|
105
138
|
}
|
|
106
139
|
}
|
|
107
140
|
exports.WsClient = WsClient;
|
package/internal/common.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
|
|
3
|
+
type Options = {
|
|
4
4
|
ip?: string;
|
|
5
5
|
port?: number;
|
|
6
6
|
user?: string;
|
|
@@ -8,6 +8,10 @@ export type Options = {
|
|
|
8
8
|
tls?: boolean;
|
|
9
9
|
tlsInsecure?: boolean;
|
|
10
10
|
};
|
|
11
|
+
export type HttpOptions = Options & {
|
|
12
|
+
keepAlive?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type WsOptions = Options;
|
|
11
15
|
export type TGetFunction = (url: string, parameters?: Record<string, string>, headers?: Record<string, string>) => Promise<Response>;
|
|
12
16
|
export type TPostFunction = (url: string, data: string | Buffer | FormData, parameters?: Record<string, string>, headers?: Record<string, string>) => Promise<Response>;
|
|
13
17
|
export interface IClient {
|
|
@@ -15,3 +19,5 @@ export interface IClient {
|
|
|
15
19
|
post: TPostFunction;
|
|
16
20
|
}
|
|
17
21
|
export declare function isClient(arg?: Options | IClient): arg is IClient;
|
|
22
|
+
export declare function isBrowserEnvironment(): boolean;
|
|
23
|
+
export {};
|