presidium 0.15.20 → 0.15.27

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/DynamoStream.js CHANGED
@@ -155,7 +155,9 @@ DynamoStream.prototype.getRecords = async function* getRecords(
155
155
  shardId: always(Shard.ShardId),
156
156
  }))
157
157
  }
158
+
158
159
  while (!this.closed && records.NextShardIterator != null) {
160
+ await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
159
161
  records = await this.client.getRecords({
160
162
  ShardIterator: records.NextShardIterator,
161
163
  Limit: this.getRecordsLimit
@@ -166,7 +168,6 @@ DynamoStream.prototype.getRecords = async function* getRecords(
166
168
  shardId: always(Shard.ShardId),
167
169
  }))
168
170
  }
169
- await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
170
171
  }
171
172
  }
172
173
 
package/KinesisStream.js CHANGED
@@ -50,7 +50,7 @@ const KinesisStream = function (options) {
50
50
  this.name = options.name
51
51
  this.listShardsLimit = options.listShardsLimit ?? 1000
52
52
  this.getRecordsLimit = options.getRecordsLimit ?? 1000
53
- this.shardUpdateInterval = options.shardUpdateInterval ?? 10000
53
+ this.shardUpdatePeriod = options.shardUpdatePeriod ?? 15000
54
54
  this.getRecordsInterval = options.getRecordsInterval ?? 1000
55
55
  this.shardIteratorType = options.shardIteratorType ?? 'LATEST'
56
56
  this.shardIteratorTimestamp = options.shardIteratorTimestamp
@@ -116,7 +116,6 @@ KinesisStream.prototype.delete = function deleteStream() {
116
116
  * ```
117
117
  */
118
118
  KinesisStream.prototype.putRecord = async function putRecord(data, options = {}) {
119
- await this.ready
120
119
  return this.kinesis.client.putRecord({
121
120
  StreamName: this.name,
122
121
  Data: data,
@@ -142,14 +141,19 @@ KinesisStream.prototype.listShards = async function* listShards() {
142
141
  StreamName: this.name,
143
142
  MaxResults: this.listShardsLimit,
144
143
  }).promise()
145
- yield* shards.Shards
144
+ if (shards.Shards.length > 0) {
145
+ yield* shards.Shards
146
+ }
147
+
146
148
  while (!this.closed && shards.NextToken != null) {
147
149
  shards = await this.kinesis.client.listShards({
148
150
  StreamName: this.name,
149
151
  MaxResults: this.listShardsLimit,
150
152
  NextToken: shards.NextToken,
151
153
  })
152
- yield* shards.Shards
154
+ if (shards.Shards.length > 0) {
155
+ yield* shards.Shards
156
+ }
153
157
  }
154
158
  }
155
159
 
@@ -163,19 +167,24 @@ KinesisStream.prototype.getRecords = async function* getRecords(Shard) {
163
167
  Timestamp: this.shardIteratorTimestamp,
164
168
  },
165
169
  }).promise().then(get('ShardIterator'))
170
+
166
171
  let records = await this.kinesis.client.getRecords({
167
172
  ShardIterator: startingShardIterator,
168
173
  Limit: this.getRecordsLimit,
169
174
  }).promise()
170
- await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
171
- yield* records.Records
175
+ if (records.Records.length > 0) {
176
+ yield* records.Records
177
+ }
178
+
172
179
  while (!this.closed && records.NextShardIterator != null) {
180
+ await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
173
181
  records = await this.kinesis.client.getRecords({
174
182
  ShardIterator: records.NextShardIterator,
175
183
  Limit: this.getRecordsLimit,
176
184
  }).promise()
177
- await new Promise(resolve => setTimeout(resolve, this.getRecordsInterval))
178
- yield* records.Records
185
+ if (records.Records.length > 0) {
186
+ yield* records.Records
187
+ }
179
188
  }
180
189
  }
181
190
 
@@ -183,43 +192,46 @@ const SymbolUpdateShards = Symbol('UpdateShards')
183
192
 
184
193
  KinesisStream.prototype[Symbol.asyncIterator] = async function* generateRecords() {
185
194
  let shards = await transform(map(identity), [])(this.listShards())
186
- let muxAsyncIterator = Mux.race(shards.map(Shard => this.getRecords(Shard)))
187
- let iterationPromise = muxAsyncIterator.next()
188
- let shardUpdatePromise = new Promise(resolve => setTimeout(
189
- thunkify(resolve, SymbolUpdateShards),
190
- this.shardUpdateInterval,
191
- ))
195
+ let muxAsyncIterator = Mux.race([
196
+ ...shards.map(Shard => this.getRecords(Shard)),
197
+ (async function* UpdateShardsGenerator() {
198
+ while (!this.closed) {
199
+ await new Promise(resolve => {
200
+ setTimeout(resolve, this.shardUpdatePeriod)
201
+ })
202
+ if (!this.closed) {
203
+ yield SymbolUpdateShards
204
+ }
205
+ }
206
+ }).call(this),
207
+ ])
192
208
 
193
209
  while (!this.closed) {
194
- const iteration = await Promise.race([
195
- shardUpdatePromise,
196
- iterationPromise,
197
- ])
198
- if (iteration == SymbolUpdateShards) {
210
+ const { value, done } = await muxAsyncIterator.next()
211
+ if (value == SymbolUpdateShards) {
199
212
  const latestShards = await transform(map(identity), [])(this.listShards())
200
- const newShards = differenceWith(
201
- (ShardA, ShardB) => ShardA.ShardId == ShardB.ShardId,
202
- latestShards,
203
- )(shards)
204
- const closedShards = differenceWith(
205
- (ShardA, ShardB) => ShardA.ShardId == ShardB.ShardId,
206
- shards,
207
- )(latestShards)
208
-
209
- closedShards.forEach(Shard => (Shard.closed = true))
213
+ const newShards = pipe([
214
+ always(shards),
215
+ differenceWith(
216
+ (ShardA, ShardB) => ShardA.ShardId == ShardB.ShardId,
217
+ latestShards,
218
+ ),
219
+ map(assign({
220
+ ShardIteratorType: always('TRIM_HORIZON'),
221
+ })),
222
+ ])()
223
+
210
224
  shards = latestShards
211
- muxAsyncIterator = newShards.length == 0 ? muxAsyncIterator : Mux.race([
212
- ...newShards.map(Shard => this.getRecords(Shard)),
213
- muxAsyncIterator,
214
- ])
215
- shardUpdatePromise = new Promise(resolve => setTimeout(
216
- thunkify(resolve, SymbolUpdateShards), this.shardUpdateInterval))
217
- } else if (iteration.done) {
225
+ if (newShards.length > 0) {
226
+ muxAsyncIterator = Mux.race([
227
+ ...newShards.map(Shard => this.getRecords(Shard)),
228
+ muxAsyncIterator,
229
+ ])
230
+ }
231
+ } else if (done) {
218
232
  await new Promise(resolve => setTimeout(resolve, 1000))
219
- iterationPromise = muxAsyncIterator.next()
220
233
  } else {
221
- yield iteration.value
222
- iterationPromise = muxAsyncIterator.next()
234
+ yield value
223
235
  }
224
236
  }
225
237
  }
@@ -27,6 +27,7 @@ const test = new Test('KinesisStream', KinesisStream)
27
27
  assert.deepEqual(first3, first3Again)
28
28
  this.streams.push(myStream)
29
29
  })
30
+
30
31
  .case({
31
32
  name: 'my-stream',
32
33
  endpoint: 'http://localhost:4567',
@@ -46,6 +47,28 @@ const test = new Test('KinesisStream', KinesisStream)
46
47
  myStream.close()
47
48
  this.streams.push(myStream)
48
49
  })
50
+
51
+ .case({
52
+ name: 'my-stream',
53
+ endpoint: 'http://localhost:4567',
54
+ shardUpdatePeriod: 500,
55
+ }, async function (myStream) {
56
+ await myStream.ready
57
+
58
+ // there shouldn't be any more records, so this should hang
59
+ const latestRecordPromise = asyncIterableTake(1)(myStream)
60
+ const raceResult = await Promise.race([
61
+ latestRecordPromise,
62
+ new Promise(resolve => setTimeout(thunkify(resolve, 'hey'), 3000))
63
+ ])
64
+ assert.equal(raceResult, 'hey')
65
+ // wait a second for shard update
66
+ await new Promise(resolve => setTimeout(thunkify(resolve, 'hey'), 1000))
67
+ myStream.close()
68
+ // ensure shards don't update after close
69
+ await new Promise(resolve => setTimeout(resolve, 1000))
70
+ })
71
+
49
72
  .after(async function() {
50
73
  await map(stream => stream.delete())(this.streams)
51
74
  })
@@ -29,11 +29,11 @@ const CHECKSUM_LENGTH = 4
29
29
  const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2
30
30
 
31
31
  /**
32
- * @name TranscribeStreaming
32
+ * @name TranscribeStream
33
33
  *
34
34
  * @synopsis
35
35
  * ```coffeescript [specscript]
36
- * const myTranscribeStream = new TranscribeStreaming(options {
36
+ * const myTranscribeStream = new TranscribeStream(options {
37
37
  * accessKeyId: string,
38
38
  * secretAccessKey: string,
39
39
  * region: string,
@@ -44,6 +44,24 @@ const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2
44
44
  * sessionId?: string,
45
45
  * vocabularyName?: string,
46
46
  * })
47
+ *
48
+ * myTranscribeStream.on('transcription', transcriptionHandler (transcription {
49
+ * Alternatives: Array<{
50
+ * Items: Array<{
51
+ * Confidence?: number,
52
+ * Content: string,
53
+ * EndTime: number, // seconds
54
+ * StartTime: number, // seconds
55
+ * Type: 'pronunciation'|'punctuation',
56
+ * VocabularyFilterMatch: boolean,
57
+ * }>,
58
+ * Transcript: string,
59
+ * }>,
60
+ * EndTime: number, // seconds
61
+ * IsPartial: boolean,
62
+ * ResultId: string, // uuid
63
+ * StartTime: number, // seconds
64
+ * })=><>)
47
65
  * ```
48
66
  *
49
67
  * @description
@@ -59,7 +77,7 @@ const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2
59
77
  *
60
78
  * `vocabularyName` - The name of the vocabulary to use when processing the transcription job, if any.
61
79
  */
62
- const TranscribeStreaming = function (options) {
80
+ const TranscribeStream = function (options) {
63
81
  const {
64
82
  accessKeyId,
65
83
  secretAccessKey,
@@ -109,10 +127,10 @@ const TranscribeStreaming = function (options) {
109
127
  return this
110
128
  }
111
129
 
112
- TranscribeStreaming.prototype = EventEmitter.prototype
130
+ TranscribeStream.prototype = EventEmitter.prototype
113
131
 
114
132
  /**
115
- * @name TranscribeStreaming.prototype.sendAudioChunk
133
+ * @name TranscribeStream.prototype.sendAudioChunk
116
134
  *
117
135
  * @synopsis
118
136
  * ```coffeescript [specscript]
@@ -125,7 +143,7 @@ TranscribeStreaming.prototype = EventEmitter.prototype
125
143
  * https://docs.aws.amazon.com/transcribe/latest/dg/event-stream.html
126
144
  * https://github.com/aws-samples/amazon-transcribe-comprehend-medical-twilio/blob/main/lib/transcribe-service.js
127
145
  */
128
- TranscribeStreaming.prototype.sendAudioChunk = function (chunk) {
146
+ TranscribeStream.prototype.sendAudioChunk = function (chunk) {
129
147
  const headersBytes = marshalHeaders({
130
148
  ':message-type': {
131
149
  type: 'string',
@@ -273,4 +291,4 @@ const unmarshalHeaders = function (headersView) {
273
291
  return headers
274
292
  }
275
293
 
276
- module.exports = TranscribeStreaming
294
+ module.exports = TranscribeStream
@@ -4,7 +4,7 @@ const WaveFile = require('wavefile').WaveFile
4
4
  const Test = require('thunk-test')
5
5
  const assert = require('assert')
6
6
  const rubico = require('rubico')
7
- const TranscribeStreaming = require('./TranscribeStreaming')
7
+ const TranscribeStream = require('./TranscribeStream')
8
8
  const AwsCredentials = require('./internal/AwsCredentials')
9
9
 
10
10
  const {
@@ -18,7 +18,7 @@ const {
18
18
  curry, __,
19
19
  } = rubico
20
20
 
21
- const test = new Test('TranscribeStreaming', async function () {
21
+ const test = new Test('TranscribeStream', async function () {
22
22
  const awsCreds = await AwsCredentials('default').catch(error => {
23
23
  if (error.code == 'ENOENT') {
24
24
  const accessKeyId = process.env.AWS_ACCESS_KEY_ID
@@ -32,13 +32,13 @@ const test = new Test('TranscribeStreaming', async function () {
32
32
  })
33
33
  awsCreds.region = 'us-east-1' // only valid region for transcribe
34
34
 
35
- const testTranscribeStreaming = new TranscribeStreaming({
35
+ const testTranscribeStream = new TranscribeStream({
36
36
  languageCode: 'en-US',
37
37
  mediaEncoding: 'pcm',
38
38
  sampleRate: 8000,
39
39
  ...awsCreds,
40
40
  })
41
- await testTranscribeStreaming.ready
41
+ await testTranscribeStream.ready
42
42
 
43
43
  const mediaStreamFixtureAwsKeynote =
44
44
  fs.createReadStream('./media-stream-fixture-aws-keynote.txt')
@@ -51,14 +51,14 @@ const test = new Test('TranscribeStreaming', async function () {
51
51
  const wav = new WaveFile()
52
52
  wav.fromScratch(1, 8000, '8', Buffer.from(event.media.payload, 'base64'))
53
53
  wav.fromMuLaw()
54
- testTranscribeStreaming.sendAudioChunk(Buffer.from(wav.data.samples))
54
+ testTranscribeStream.sendAudioChunk(Buffer.from(wav.data.samples))
55
55
  } else if (event.event == 'stop') {
56
- testTranscribeStreaming.websocket.close()
56
+ testTranscribeStream.websocket.close()
57
57
  }
58
58
  })
59
59
 
60
60
  const testTranscription = await new Promise(resolve => {
61
- testTranscribeStreaming.on('transcription', transcription => {
61
+ testTranscribeStream.on('transcription', transcription => {
62
62
  resolve(transcription.Alternatives[0].Transcript)
63
63
  })
64
64
  })
package/index.js CHANGED
@@ -31,24 +31,43 @@ const S3Bucket = require('./S3Bucket')
31
31
  // const Redshift = require('./Redshift')
32
32
  // const Gremlin = require('./Gremlin')
33
33
  const Redis = require('./Redis')
34
+ const TranscribeStream = require('./TranscribeStream')
34
35
 
35
36
  const Presidium = {
36
- Http, HttpServer,
37
- WebSocket, WebSocketServer,
38
- Dynamo, DynamoTable, DynamoIndex, DynamoStream,
39
- Docker, DockerImage, DockerContainer, DockerSwarm, DockerService,
40
- // ElasticTranscoder, ElasticTranscoderPipeline,
41
- // KinesisAnalytics, KinesisAnalyticsStream,
42
- // KinesisVideo, KinesisVideoStream,
43
- Kinesis, KinesisStream,
44
- Lambda, LambdaFunction,
45
- Mongo, MongoCollection,
37
+ Http,
38
+ HttpServer,
39
+ WebSocket,
40
+ WebSocketServer,
41
+ Dynamo,
42
+ DynamoTable,
43
+ DynamoIndex,
44
+ DynamoStream,
45
+ Docker,
46
+ DockerImage,
47
+ DockerContainer,
48
+ DockerSwarm,
49
+ DockerService,
50
+ // ElasticTranscoder,
51
+ // ElasticTranscoderPipeline,
52
+ // KinesisAnalytics,
53
+ // KinesisAnalyticsStream,
54
+ // KinesisVideo,
55
+ // KinesisVideoStream,
56
+ Kinesis,
57
+ KinesisStream,
58
+ Lambda,
59
+ LambdaFunction,
60
+ Mongo,
61
+ MongoCollection,
46
62
  ElasticsearchIndex,
47
- // SNS, SNSTopic,
48
- S3, S3Bucket,
63
+ // SNS,
64
+ // SNSTopic,
65
+ S3,
66
+ S3Bucket,
49
67
  // Redshift,
50
68
  // Gremlin,
51
69
  Redis,
70
+ TranscribeStream,
52
71
  }
53
72
 
54
73
  module.exports = Presidium
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "presidium",
3
- "version": "0.15.20",
3
+ "version": "0.15.27",
4
4
  "description": "A library for creating web services",
5
5
  "author": "Richard Tong",
6
6
  "license": "MIT",