Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/origin/master' into v1
Browse files Browse the repository at this point in the history
# Conflicts:
#	.gitignore
#	README.md
#	package-lock.json
#	package.json
  • Loading branch information
agsh committed Jun 26, 2024
2 parents b8c00eb + d44f7a7 commit 2d13a75
Show file tree
Hide file tree
Showing 20 changed files with 1,349 additions and 7,976 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/npm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Node.js Package

on:
release:
types: [created]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test

publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
6 changes: 3 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [14.x,16.x,18.x]
node-version: [16.x,18.x,20.x]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
Expand Down
18 changes: 0 additions & 18 deletions .github/workflows/publish.yml

This file was deleted.

1 change: 0 additions & 1 deletion .nyc_output/6f8e2fb0-0e2d-410d-8361-422c514bf877.json

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion .nyc_output/processinfo/index.json

This file was deleted.

36 changes: 0 additions & 36 deletions .vscode/launch.json

This file was deleted.

1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# ONVIF

[![Build Status](https://travis-ci.org/agsh/onvif.png)](https://travis-ci.org/agsh/onvif)
[![Coverage Status](https://img.shields.io/coveralls/agsh/onvif.svg)](https://coveralls.io/r/agsh/onvif?branch=master)
[![NPM version](https://img.shields.io/npm/v/onvif.svg)](https://www.npmjs.com/package/onvif)

Expand Down
14 changes: 7 additions & 7 deletions examples/example3.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
*
* The GetPresets command is left as an asynchronous command
* and the presets list may come in some time after the StreamURI is displayed
*
*
*/

var HOSTNAME = '192.168.1.128',
PORT = 80,
USERNAME = '',
PASSWORD = '',
var HOSTNAME = '192.168.0.116',
PORT = 2020,
USERNAME = 'username',
PASSWORD = 'password',
STOP_DELAY_MS = 50;

var Cam = require('../lib/onvif').Cam;
Expand Down Expand Up @@ -160,7 +160,7 @@ new Cam({

function move(x_speed, y_speed, zoom_speed, msg) {
// Step 1 - Turn off the keyboard processing (so keypresses do not buffer up)
// Step 2 - Clear any existing 'stop' timeouts. We will re-schedule a new 'stop' command in this function
// Step 2 - Clear any existing 'stop' timeouts. We will re-schedule a new 'stop' command in this function
// Step 3 - Send the Pan/Tilt/Zoom 'move' command.
// Step 4 - In the callback from the PTZ 'move' command we schedule the ONVIF Stop command to be executed after a short delay and re-enable the keyboard

Expand All @@ -181,7 +181,7 @@ new Cam({
console.log(err);
} else {
console.log('move command sent ' + msg);
// schedule a Stop command to run in the future
// schedule a Stop command to run in the future
stop_timer = setTimeout(stop,STOP_DELAY_MS);
}
// Resume keyboard processing
Expand Down
28 changes: 16 additions & 12 deletions lib/cam.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,23 @@ const http = require('http'),
* @property {?Error} error
*/

/**
* @typedef Cam~Options
* @property {boolean} useSecure Set true if `https:`, defaults to false
* @property {object} secureOpts Set options for https like ca, cert, ciphers, rejectUnauthorized, secureOptions, secureProtocol, etc.
* @property {string} hostname
* @property {string} [username]
* @property {string} [password]
* @property {number} [port=80]
* @property {string} [path=/onvif/device_service]
* @property {number} [timeout=120000]
* @property {boolean} [autoconnect=true] Set false if the camera should not connect automatically. The callback will not be executed.
* @property {boolean} [preserveAddress=false] Force using hostname and port from constructor for the services
*/

/**
* Camera class
* @param {object} options
* @param {boolean} options.useSecure Set true if `https:`, defaults to false
* @param {object} options.secureOpts Set options for https like ca, cert, ciphers, rejectUnauthorized, secureOptions, secureProtocol, etc.
* @param {string} options.hostname
* @param {string} [options.username]
* @param {string} [options.password]
* @param {number} [options.port=80]
* @param {string} [options.path=/onvif/device_service]
* @param {number} [options.timeout=120000]
* @param {boolean} [options.autoconnect=true] Set false if the camera should not connect automatically. The callback will not be executed.
* @param {boolean} [options.preserveAddress=false] Force using hostname and port from constructor for the services
* @param {Cam~Options} options
* @param {Cam~ConnectionCallback} [callback]
* @fires Cam#rawRequest
* @fires Cam#rawResponse
Expand Down Expand Up @@ -260,7 +264,7 @@ Cam.prototype._requestPart2 = function(options, callback) {
agent: this.agent //Supports things like https://www.npmjs.com/package/proxy-agent which provide SOCKS5 and other connections
,
path: options.service ?
(this.uri[options.service] ? this.uri[options.service].path : options.service) : this.path,
(this.uri && this.uri[options.service] ? this.uri[options.service].path : options.service) : this.path,
timeout: this.timeout
};
reqOptions.headers = {
Expand Down
66 changes: 48 additions & 18 deletions lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ module.exports = function(Cam) {

const linerase = require('./utils').linerase;
const parseSOAPString = require('./utils').parseSOAPString;
const retryErrorCodes = ['ECONNREFUSED','ECONNRESET','ETIMEDOUT', 'ENETUNREACH'];
const maxEventReconnectMs = 2 * 60 * 1000;


/**
Expand Down Expand Up @@ -144,11 +146,13 @@ module.exports = function(Cam) {

/**
* Renew pull-point subscription
* @param {options} callback
* @param {function} callback
* @param {Object|Function} [options]
* @param {Function} callback
*/

Cam.prototype.renew = function(options, callback) {
if (!callback) {
callback = options;
}
let urlAddress = null;
let subscriptionId = null;
try {
Expand Down Expand Up @@ -272,7 +276,8 @@ module.exports = function(Cam) {

/**
* Unsubscribe from pull-point subscription
* @param {Cam~PullMessagesResponse} callback
* @param {Cam~PullMessagesResponse} [callback]
* @param {boolean} [preserveListeners=false] Don't remove listeners on 'event'
* @throws {Error} {@link Cam#events.subscription} must exists
*/
Cam.prototype.unsubscribe = function(callback, preserveListeners) {
Expand Down Expand Up @@ -332,9 +337,7 @@ module.exports = function(Cam) {
* @private
*/
function _terminationTime(response) {
let result = new Date(Date.now() - response.currentTime.getTime() + response.terminationTime.getTime());
// console.log("Events: Termination Time is " + result);
return result;
return new Date(Date.now() - response.currentTime.getTime() + response.terminationTime.getTime());
}

/**
Expand All @@ -348,15 +351,21 @@ module.exports = function(Cam) {
// if there is no pull-point subscription or it has expired, create new subscription
this.createPullPointSubscription(function(error) {
if (!error) {
delete this._eventReconnectms;
this._eventPull();
} else {
this.emit('eventsError', error);
if (typeof error === 'object' && retryErrorCodes.includes(error.code)) {
// connection reset on creation - restart Event loop for pullMessages request
this._restartEventRequest();
}
}
}.bind(this));
} else {
this._eventPull();
}
} else {
delete this.events.terminationTime;

this.unsubscribe();
}
};
Expand All @@ -370,8 +379,9 @@ module.exports = function(Cam) {
if (this.listeners('event').length && this.events.subscription) { // check for event listeners, if zero, or no subscription then stop pulling
this.pullMessages({
messageLimit: this.events.messageLimit
}, function(err, data, xml) {
if (!err) {
}, function(error, data, xml) {
if (!error) {
delete this._eventReconnectms;
if (data.notificationMessage) {
if (!Array.isArray(data.notificationMessage)) {
data.notificationMessage = [data.notificationMessage];
Expand All @@ -388,29 +398,49 @@ module.exports = function(Cam) {
this.events.terminationTime = _terminationTime(data); // Axis does not increment the termination time. Use RENEW. Vista returns a termination time with the time now (ie we have expired) even if there was still time left over. Use RENEW

// Axis cameras require us to Rewew the Pull Point Subscription
this.renew({},function(err,data) {
if (!err) {
this.renew({},function(error, data) {
if (!error) {
this.events.terminationTime = _terminationTime(data);
}
this._eventRequest(); // go around the loop again, once the RENEW has completed (and terminationTime updated)
});
} else {
// there was an error pulling the message
this.unsubscribe(function(_err,_data,_xml) {
// once the unsubsribe has completed (even if it failed), go around the loop again
this._eventRequest();
}, true);
this.emit('eventsError', error);
if (typeof error === 'object' && retryErrorCodes.includes(error.code)) {
// connection reset - restart Event loop for pullMessages request
this._restartEventRequest();
} else {
// there was an error pulling the message
this.unsubscribe(function(_err, _data, _xml) {
// once the unsubsribe has completed (even if it failed), go around the loop again
this._eventRequest();
}, true);
}
}
}.bind(this));
} else {
delete this.events.terminationTime;

if (this.events.subscription) {
this.unsubscribe();
}
}
};

/**
* Restart the event request with an increasing interval when the connection to the device is refused
* @private
*/
Cam.prototype._restartEventRequest = function() {
// TODO maybe stop trying to connect after some time
if (!this._eventReconnectms) {
this._eventReconnectms = 10;
}
setTimeout(this._eventRequest.bind(this), this._eventReconnectms);
if (this._eventReconnectms < maxEventReconnectMs) {
this._eventReconnectms = 1.111 * this._eventReconnectms;
}
};

/**
* Helper Function to Parse XML Event data received by an external TCP port and
* a camera in Event PUSH mode (ie not in subscribe mode)
Expand Down
Loading

0 comments on commit 2d13a75

Please sign in to comment.