mirror of
https://github.com/jambonz/jambonz-api-server.git
synced 2026-02-09 02:29:59 +00:00
* feat: schema change * feat: record all calls * add bucket test for S3 * wip: add S3 upload stream implementation * wip * wip: add ws server * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip: modify sub folder * wip: add record endpoint * wip: add record endpoint * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * fix: failing testcase * bucket credentials with tags * add tagging * wip * wip * wip * wip * wip * wip * fixed phone number is not in order * feat: schema change * feat: record all calls * add bucket test for S3 * wip: add S3 upload stream implementation * wip * wip: add ws server * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip: modify sub folder * wip: add record endpoint * wip: add record endpoint * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * fix: failing testcase * bucket credentials with tags * add tagging * wip * wip * wip * wip * wip * fixed phone number is not in order * add schema changes to upgrade script * use aws-sdk v3 * jambonz lamejs * jambonz lamejs * add back wav encoder * wip: add record format to schema * add record_format * fix: record file ext * fix: record file ext * fix: record file ext * fix: record file ext * fix download audio * bug fix: dtmf metadata is causing closure of websocket * fix: add extra data to S3 metadata * upgrade db script * bugfix: region was being ignored in test s3 upload --------- Co-authored-by: Dave Horton <daveh@beachdognet.com>
104 lines
2.6 KiB
JavaScript
104 lines
2.6 KiB
JavaScript
const { Writable } = require('stream');
|
|
const {
|
|
S3Client,
|
|
CreateMultipartUploadCommand,
|
|
UploadPartCommand,
|
|
CompleteMultipartUploadCommand,
|
|
} = require('@aws-sdk/client-s3');
|
|
|
|
class S3MultipartUploadStream extends Writable {
|
|
constructor(logger, opts) {
|
|
super(opts);
|
|
this.logger = logger;
|
|
this.bucketName = opts.bucketName;
|
|
this.objectKey = opts.Key;
|
|
this.uploadId = null;
|
|
this.partNumber = 1;
|
|
this.multipartETags = [];
|
|
this.buffer = Buffer.alloc(0);
|
|
this.minPartSize = 5 * 1024 * 1024; // 5 MB
|
|
this.s3 = new S3Client(opts.bucketCredential);
|
|
this.metadata = opts.metadata;
|
|
}
|
|
|
|
async _initMultipartUpload() {
|
|
const command = new CreateMultipartUploadCommand({
|
|
Bucket: this.bucketName,
|
|
Key: this.objectKey,
|
|
Metadata: this.metadata
|
|
});
|
|
const response = await this.s3.send(command);
|
|
return response.UploadId;
|
|
}
|
|
|
|
async _uploadBuffer() {
|
|
const uploadPartCommand = new UploadPartCommand({
|
|
Bucket: this.bucketName,
|
|
Key: this.objectKey,
|
|
PartNumber: this.partNumber,
|
|
UploadId: this.uploadId,
|
|
Body: this.buffer,
|
|
});
|
|
|
|
const uploadPartResponse = await this.s3.send(uploadPartCommand);
|
|
this.multipartETags.push({
|
|
ETag: uploadPartResponse.ETag,
|
|
PartNumber: this.partNumber,
|
|
});
|
|
this.partNumber += 1;
|
|
}
|
|
|
|
async _write(chunk, encoding, callback) {
|
|
try {
|
|
if (!this.uploadId) {
|
|
this.uploadId = await this._initMultipartUpload();
|
|
}
|
|
|
|
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
|
|
if (this.buffer.length >= this.minPartSize) {
|
|
await this._uploadBuffer();
|
|
this.buffer = Buffer.alloc(0);
|
|
}
|
|
|
|
callback(null);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
}
|
|
|
|
async _finalize(err) {
|
|
try {
|
|
if (this.buffer.length > 0) {
|
|
await this._uploadBuffer();
|
|
}
|
|
|
|
const completeMultipartUploadCommand = new CompleteMultipartUploadCommand({
|
|
Bucket: this.bucketName,
|
|
Key: this.objectKey,
|
|
MultipartUpload: {
|
|
Parts: this.multipartETags.sort((a, b) => a.PartNumber - b.PartNumber),
|
|
},
|
|
UploadId: this.uploadId,
|
|
});
|
|
|
|
await this.s3.send(completeMultipartUploadCommand);
|
|
this.logger.info('Finished upload to S3');
|
|
} catch (error) {
|
|
this.logger.error('Error completing multipart upload:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async _final(callback) {
|
|
try {
|
|
await this._finalize();
|
|
callback(null);
|
|
} catch (error) {
|
|
callback(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = S3MultipartUploadStream;
|