@signalk/streams 1.18.0 → 2.0.2

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.
@@ -0,0 +1,4 @@
1
+ {
2
+ "semi": false,
3
+ "singleQuote": true
4
+ }
package/README.md CHANGED
@@ -0,0 +1,14 @@
1
+ # @signalk/streams
2
+
3
+ Used within the [Signal K](http://signalk.org) [Node Server](https://github.com/SignalK/signalk-server-node) for streaming and converting input data in different formats.
4
+
5
+ The code is not compiled and is not more effective, but allows using the streams and their conversions independently outside the server.
6
+
7
+ ## Development
8
+
9
+ - Install dev packages with `npm i`.
10
+ - Edit files with `/src`.
11
+ - `npm link`
12
+ - `cd ../../`
13
+ - `npm link @signalk/streams`
14
+ - Restart signalk `npm start`
package/autodetect.js CHANGED
@@ -45,12 +45,12 @@ A => actisense-serial format N2K data
45
45
  1471172400153;A;2016-07-16T12:00:00.000Z,2,130306,105,255,8,00,d1,03,c9,23,fa,ff,ff
46
46
  */
47
47
 
48
- function DeMultiplexer (options) {
48
+ function DeMultiplexer(options) {
49
49
  Writable.call(this)
50
50
 
51
51
  this.toTimestamped = new ToTimestamped(this, options)
52
52
  this.timestampThrottle = new TimestampThrottle({
53
- getMilliseconds: msg => msg.timestamp
53
+ getMilliseconds: (msg) => msg.timestamp,
54
54
  })
55
55
  this.splitter = new Splitter(this, options)
56
56
  this.options = options
@@ -66,7 +66,7 @@ DeMultiplexer.prototype.write = function (chunk, encoding, callback) {
66
66
  return this.toTimestamped.write(chunk, encoding, callback)
67
67
  }
68
68
 
69
- function Splitter (deMultiplexer, options) {
69
+ function Splitter(deMultiplexer, options) {
70
70
  Transform.call(this, { objectMode: true })
71
71
  this.demuxEmitData = function (msg) {
72
72
  deMultiplexer.emit('data', msg)
@@ -91,7 +91,7 @@ Splitter.prototype._transform = function (msg, encoding, _done) {
91
91
  let done = _done
92
92
  try {
93
93
  switch (msg.discriminator) {
94
- case 'A': {
94
+ case 'A': {
95
95
  msg.fromFile = true
96
96
  const result = this.fromActisenseSerial.write(msg, encoding)
97
97
  if (!result) {
@@ -130,7 +130,7 @@ Splitter.prototype.pipe = function (target) {
130
130
  return Transform.prototype.pipe.call(this, target)
131
131
  }
132
132
 
133
- function ToTimestamped (deMultiplexer, options) {
133
+ function ToTimestamped(deMultiplexer, options) {
134
134
  Transform.call(this, { objectMode: true })
135
135
  this.deMultiplexer = deMultiplexer
136
136
  this.options = options
package/canboatjs.js CHANGED
@@ -16,21 +16,24 @@
16
16
 
17
17
  const Transform = require('stream').Transform
18
18
  const FromPgn = require('@canboat/canboatjs').FromPgn
19
- const debug = require('debug')('signalk:streams:canboatjs')
20
19
  const _ = require('lodash')
21
20
 
22
- function CanboatJs (options) {
21
+ function CanboatJs(options) {
23
22
  Transform.call(this, {
24
- objectMode: true
23
+ objectMode: true,
25
24
  })
26
25
 
27
26
  this.fromPgn = new FromPgn(options)
27
+ const createDebug = options.createDebug || require('debug')
28
+ const debug = createDebug('signalk:streams:nmea0183-signalk')
28
29
 
29
30
  this.fromPgn.on('warning', (pgn, warning) => {
30
31
  debug(`[warning] ${pgn.pgn} ${warning}`)
31
32
  })
32
33
 
33
- this.fromPgn.on('error', (pgn, err) => {console.log(err)} )
34
+ this.fromPgn.on('error', (pgn, err) => {
35
+ console.log(err)
36
+ })
34
37
 
35
38
  this.app = options.app
36
39
  }
@@ -40,14 +43,14 @@ require('util').inherits(CanboatJs, Transform)
40
43
  CanboatJs.prototype._transform = function (chunk, encoding, done) {
41
44
  if (_.isObject(chunk) && chunk.fromFile) {
42
45
  const pgnData = this.fromPgn.parse(chunk.data)
43
- if ( pgnData ) {
46
+ if (pgnData) {
44
47
  pgnData.timestamp = new Date(Number(chunk.timestamp)).toISOString()
45
48
  this.push(pgnData)
46
49
  this.app.emit('N2KAnalyzerOut', pgnData)
47
50
  }
48
51
  } else {
49
52
  const pgnData = this.fromPgn.parse(chunk)
50
- if ( pgnData ) {
53
+ if (pgnData) {
51
54
  this.push(pgnData)
52
55
  this.app.emit('N2KAnalyzerOut', pgnData)
53
56
  }
package/execute.js CHANGED
@@ -39,10 +39,11 @@
39
39
  const Transform = require('stream').Transform
40
40
  const { pgnToActisenseSerialFormat } = require('@canboat/canboatjs')
41
41
 
42
- function Execute (options) {
42
+ function Execute(options) {
43
43
  Transform.call(this, {})
44
44
  this.options = options
45
- this.debug = options.debug || require('debug')('signalk:streams:execute')
45
+ const createDebug = options.createDebug || require('debug')
46
+ this.debug = options.debug || createDebug('signalk:streams:execute')
46
47
  }
47
48
 
48
49
  require('util').inherits(Execute, Transform)
@@ -52,7 +53,7 @@ Execute.prototype._transform = function (chunk, encoding, done) {
52
53
  this.analyzerProcess.stdin.write(chunk.toString())
53
54
  done()
54
55
  }
55
- function start (command, that) {
56
+ function start(command, that) {
56
57
  that.debug(`starting |${command}|`)
57
58
  if (process.platform === 'win32') {
58
59
  that.childProcess = require('child_process').spawn('cmd', ['/c', command])
@@ -75,7 +76,7 @@ function start (command, that) {
75
76
  that.push(data)
76
77
  })
77
78
 
78
- that.childProcess.on('close', code => {
79
+ that.childProcess.on('close', (code) => {
79
80
  const msg = `|${command}| exited with ${code}`
80
81
  // that.options.app.setProviderError(that.options.providerId, msg)
81
82
  console.error(msg)
@@ -106,7 +107,9 @@ Execute.prototype.pipe = function (pipeTo) {
106
107
  start(this.options.command, this)
107
108
 
108
109
  const stdOutEvent = this.options.toChildProcess || 'toChildProcess'
109
- this.debug('Using event ' + stdOutEvent + " for output to child process's stdin")
110
+ this.debug(
111
+ 'Using event ' + stdOutEvent + " for output to child process's stdin"
112
+ )
110
113
  const that = this
111
114
  that.options.app.on(stdOutEvent, function (d) {
112
115
  try {
@@ -117,7 +120,7 @@ Execute.prototype.pipe = function (pipeTo) {
117
120
  })
118
121
 
119
122
  if (stdOutEvent === 'nmea2000out') {
120
- that.options.app.on('nmea2000JsonOut', pgn => {
123
+ that.options.app.on('nmea2000JsonOut', (pgn) => {
121
124
  that.childProcess.stdin.write(pgnToActisenseSerialFormat(pgn) + '\r\n')
122
125
  })
123
126
  that.options.app.emit('nmea2000OutAvailable')
package/filestream.js CHANGED
@@ -37,7 +37,7 @@ const path = require('path')
37
37
  const PassThrough = require('stream').PassThrough
38
38
  const fs = require('fs')
39
39
 
40
- function EndIgnoringPassThrough () {
40
+ function EndIgnoringPassThrough() {
41
41
  PassThrough.call(this)
42
42
  }
43
43
 
@@ -72,7 +72,7 @@ FileStream.prototype.startStream = function () {
72
72
  }
73
73
 
74
74
  this.filestream = require('fs').createReadStream(filename)
75
- this.filestream.on('error', err => {
75
+ this.filestream.on('error', (err) => {
76
76
  console.error(err.message)
77
77
  this.keepRunning = false
78
78
  })
package/folderstream.js CHANGED
@@ -1,39 +1,36 @@
1
- const Transform = require("stream").Transform;
2
- const fs = require("fs");
1
+ const Transform = require('stream').Transform
2
+ const fs = require('fs')
3
3
 
4
4
  function FolderStreamProvider(folder) {
5
5
  Transform.call(this, {
6
6
  objectMode: false,
7
- });
8
- this.folder = folder;
9
- this.fileIndex = 0;
7
+ })
8
+ this.folder = folder
9
+ this.fileIndex = 0
10
10
  }
11
11
 
12
- require("util").inherits(FolderStreamProvider, Transform);
12
+ require('util').inherits(FolderStreamProvider, Transform)
13
13
 
14
- FolderStreamProvider.prototype.pipe = function(pipeTo) {
15
- const files = fs.readdirSync(this.folder);
16
- pipeNextFile.bind(this)();
14
+ FolderStreamProvider.prototype.pipe = function (pipeTo) {
15
+ const files = fs.readdirSync(this.folder)
16
+ pipeNextFile.bind(this)()
17
17
 
18
18
  function pipeNextFile() {
19
19
  const fileStream = fs.createReadStream(
20
- this.folder + "/" + files[this.fileIndex]
21
- );
22
- fileStream.pipe(
23
- pipeTo,
24
- { end: false }
25
- );
26
- fileStream.on("end", () => {
27
- this.fileIndex++;
20
+ this.folder + '/' + files[this.fileIndex]
21
+ )
22
+ fileStream.pipe(pipeTo, { end: false })
23
+ fileStream.on('end', () => {
24
+ this.fileIndex++
28
25
  if (this.fileIndex === files.length) {
29
- pipeTo.end();
26
+ pipeTo.end()
30
27
  } else {
31
- pipeNextFile.bind(this)();
28
+ pipeNextFile.bind(this)()
32
29
  }
33
- });
30
+ })
34
31
  }
35
32
 
36
- return pipeTo;
37
- };
33
+ return pipeTo
34
+ }
38
35
 
39
- module.exports = FolderStreamProvider;
36
+ module.exports = FolderStreamProvider
package/from_json.js CHANGED
@@ -27,9 +27,9 @@
27
27
 
28
28
  const Transform = require('stream').Transform
29
29
 
30
- function FromJson () {
30
+ function FromJson() {
31
31
  Transform.call(this, {
32
- objectMode: true
32
+ objectMode: true,
33
33
  })
34
34
  }
35
35
 
package/gpsd.js CHANGED
@@ -32,35 +32,39 @@
32
32
 
33
33
  const Transform = require('stream').Transform
34
34
  const gpsd = require('node-gpsd')
35
- const debug = require('debug')('signalk:streams:gpsd')
36
35
 
37
- function Gpsd (options) {
36
+ function Gpsd(options) {
38
37
  Transform.call(this, {
39
- objectMode: true
38
+ objectMode: true,
40
39
  })
41
-
40
+
42
41
  const port = options.port || 2947
43
42
  const hostname = options.hostname || options.host || 'localhost'
44
43
 
45
44
  function setProviderStatus(msg) {
46
45
  options.app.setProviderStatus(options.providerId, msg)
47
46
  }
48
-
47
+
48
+ const createDebug = options.createDebug || require('debug')
49
+
49
50
  this.listener = new gpsd.Listener({
50
51
  port,
51
52
  hostname,
52
53
  logger: {
53
- info: debug,
54
+ info: createDebug('signalk:streams:gpsd'),
54
55
  warn: console.warn,
55
56
  error: (msg) => {
56
- options.app.setProviderError(options.providerId, `${hostname}:${port}: ` + msg)
57
- }
57
+ options.app.setProviderError(
58
+ options.providerId,
59
+ `${hostname}:${port}: ` + msg
60
+ )
61
+ },
58
62
  },
59
- parse: false
63
+ parse: false,
60
64
  })
61
65
 
62
66
  setProviderStatus(`Connecting to ${hostname}:${port}`)
63
-
67
+
64
68
  this.listener.connect(function () {
65
69
  setProviderStatus(`Connected to ${hostname}:${port}`)
66
70
  })
@@ -72,7 +76,7 @@ function Gpsd (options) {
72
76
 
73
77
  this.listener.watch({
74
78
  class: 'WATCH',
75
- nmea: true
79
+ nmea: true,
76
80
  })
77
81
  }
78
82
 
package/keys-filter.js CHANGED
@@ -1,13 +1,14 @@
1
1
  'use strict'
2
2
 
3
3
  const Transform = require('stream').Transform
4
- const debug = require('debug')('signalk:streams:keys-filter')
5
4
 
6
- function ToSignalK (options) {
5
+ function ToSignalK(options) {
7
6
  Transform.call(this, {
8
- objectMode: true
7
+ objectMode: true,
9
8
  })
10
9
 
10
+ const createDebug = options.createDebug || require('debug')
11
+ this.debug = createDebug('signalk:streams:keys-filter')
11
12
  this.exclude = options.excludeMatchingPaths
12
13
  }
13
14
 
@@ -25,17 +26,17 @@ ToSignalK.prototype._transform = function (chunk, encoding, done) {
25
26
  delta = JSON.parse(chunk)
26
27
  string = true
27
28
  } catch (e) {
28
- debug(`Error parsing chunk: ${e.message}`)
29
+ this.debug(`Error parsing chunk: ${e.message}`)
29
30
  }
30
31
  }
31
32
 
32
33
  if (Array.isArray(delta.updates)) {
33
34
  const updates = []
34
- delta.updates.forEach(update => {
35
+ delta.updates.forEach((update) => {
35
36
  if (Array.isArray(update.values)) {
36
37
  const values = []
37
38
 
38
- update.values.forEach(value => {
39
+ update.values.forEach((value) => {
39
40
  if (this.exclude.includes(value.path) !== true) {
40
41
  values.push(value)
41
42
  }
@@ -43,7 +44,7 @@ ToSignalK.prototype._transform = function (chunk, encoding, done) {
43
44
 
44
45
  if (values.length > 0) {
45
46
  const upd = {
46
- values
47
+ values,
47
48
  }
48
49
 
49
50
  if (update.hasOwnProperty('$source')) {
package/liner.js CHANGED
@@ -28,9 +28,9 @@ const Transform = require('stream').Transform
28
28
 
29
29
  require('util').inherits(Liner, Transform)
30
30
 
31
- function Liner (options) {
31
+ function Liner(options) {
32
32
  Transform.call(this, {
33
- objectMode: true
33
+ objectMode: true,
34
34
  })
35
35
  this.doPush = this.push.bind(this)
36
36
  this.lineSeparator = options.lineSeparator || '\n'
package/log.js CHANGED
@@ -32,9 +32,9 @@
32
32
  const Transform = require('stream').Transform
33
33
  const getLogger = require('./logging').getLogger
34
34
 
35
- function Log (options) {
35
+ function Log(options) {
36
36
  Transform.call(this, {
37
- objectMode: true
37
+ objectMode: true,
38
38
  })
39
39
 
40
40
  this.logger = getLogger(options.app, options.discriminator, options.logdir)
@@ -48,7 +48,7 @@ Log.prototype._transform = function (msg, encoding, done) {
48
48
  done()
49
49
  }
50
50
 
51
- function pad (num) {
51
+ function pad(num) {
52
52
  return (num > 9 ? '' : '0') + num
53
53
  }
54
54
 
package/logging.js CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  const { FileTimestampStream } = require('file-timestamp-stream')
18
18
  const path = require('path')
19
- const debug = require('debug')('signalk:streams:logging')
19
+ let debug = require('debug')('signalk:streams:logging')
20
20
  const fs = require('fs')
21
21
 
22
22
  const filenamePattern = /skserver\-raw\_\d\d\d\d\-\d\d\-\d\dT\d\d\.log/
@@ -25,10 +25,58 @@ const loggers = {}
25
25
  module.exports = {
26
26
  getLogger,
27
27
  getFullLogDir,
28
- listLogFiles
28
+ listLogFiles,
29
29
  }
30
30
 
31
- function getLogger (app, discriminator = '', logdir) {
31
+ class FileTimestampStreamWithDelete extends FileTimestampStream {
32
+ constructor(app, fullLogDir, filesToKeep, options) {
33
+ super(options)
34
+ this.app = app
35
+ this.filesToKeep = filesToKeep
36
+ this.fullLogDir = fullLogDir
37
+ this.prevFilename = undefined
38
+ debug = (options.createDebug || require('debug'))('signalk:streams:logging')
39
+ }
40
+
41
+ // This method of base class is called when new file name is contemplated
42
+ // So let's override it to check how many files are there and delete the oldest ones
43
+ newFilename() {
44
+ if (this.prevFilename !== this.currentFilename) {
45
+ // Only do that after new file created
46
+ this.prevFilename = this.currentFilename
47
+ this.deleteOldFiles()
48
+ }
49
+ return super.newFilename()
50
+ }
51
+
52
+ deleteOldFiles() {
53
+ debug(`Checking for old log files`)
54
+ listLogFiles(this.app, (err, files) => {
55
+ if (err) {
56
+ console.error(err)
57
+ } else {
58
+ if (files.length > this.filesToKeep) {
59
+ const sortedFiles = files.sort()
60
+ const numToDelete = files.length - this.filesToKeep
61
+ debug(`Will delete ${numToDelete} files`)
62
+ for (let i = 0; i < numToDelete; i++) {
63
+ const fileName = path.join(this.fullLogDir, sortedFiles[i])
64
+ debug(`Deleting ${fileName}`)
65
+ fs.unlink(fileName, (err) => {
66
+ if (err) {
67
+ console.error(err)
68
+ } else {
69
+ debug(`${fileName} was deleted`)
70
+ }
71
+ })
72
+ }
73
+ }
74
+ }
75
+ })
76
+ }
77
+ }
78
+
79
+ function getLogger(app, discriminator = '', logdir) {
32
80
  const fullLogdir = getFullLogDir(app, logdir)
33
81
 
34
82
  if (!loggers[fullLogdir]) {
@@ -36,16 +84,29 @@ function getLogger (app, discriminator = '', logdir) {
36
84
 
37
85
  debug(`logging to ${fileName}`)
38
86
 
39
- loggers[fullLogdir] = new FileTimestampStream({
40
- path: fileName
41
- })
87
+ let fileTimestampStream
88
+ if (app.config.settings.keepMostRecentLogsOnly) {
89
+ // Delete old logs
90
+ fileTimestampStream = new FileTimestampStreamWithDelete(
91
+ app,
92
+ fullLogdir,
93
+ app.config.settings.logCountToKeep,
94
+ { path: fileName }
95
+ )
96
+ } else {
97
+ // Don't delete any logs
98
+ fileTimestampStream = new FileTimestampStream({ path: fileName })
99
+ }
100
+
101
+ loggers[fullLogdir] = fileTimestampStream
42
102
  }
103
+
43
104
  const logger = loggers[fullLogdir]
44
- logger.on('error', err => {
105
+ logger.on('error', (err) => {
45
106
  console.error(`Error opening data logging file: ${err.message}`)
46
107
  })
47
108
 
48
- return msg => {
109
+ return (msg) => {
49
110
  try {
50
111
  logger.write(
51
112
  Date.now() +
@@ -61,7 +122,7 @@ function getLogger (app, discriminator = '', logdir) {
61
122
  }
62
123
  }
63
124
 
64
- function getFullLogDir (app, logdir) {
125
+ function getFullLogDir(app, logdir) {
65
126
  if (!logdir) {
66
127
  logdir = app.config.settings.loggingDirectory || app.config.configPath
67
128
  }
@@ -70,10 +131,13 @@ function getFullLogDir (app, logdir) {
70
131
  : path.join(app.config.configPath, logdir)
71
132
  }
72
133
 
73
- function listLogFiles (app, cb) {
134
+ function listLogFiles(app, cb) {
74
135
  fs.readdir(getFullLogDir(app), (err, files) => {
75
136
  if (!err) {
76
- cb(undefined, files.filter(filename => filename.match(filenamePattern)))
137
+ cb(
138
+ undefined,
139
+ files.filter((filename) => filename.match(filenamePattern))
140
+ )
77
141
  } else {
78
142
  cb(err)
79
143
  }