lemon-core
Version:
Lemon Serverless Micro-Service Platform
261 lines • 10.8 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MyDummySQSService = exports.AWSSQSService = void 0;
/**
* `aws-sqs-service.ts`
* - sqs service for AWS `SQS`.
*
*
* //TODO - move to `lemon-core` shared lib.
*
* @author Steve Jung <steve@lemoncloud.io>
* @date 2019-09-27 initial version
*
* @copyright (C) lemoncloud.io 2019 - All Rights Reserved.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const engine_1 = require("../../engine/");
const NS = engine_1.$U.NS('SQSS', 'blue'); // NAMESPACE TO BE PRINTED.
const aws_sdk_1 = __importDefault(require("aws-sdk"));
/**
* class: AWSSQSService
* - support of AWS `SQS` Service
*/
class AWSSQSService {
/**
* default constructor.
*/
constructor(endpoint, region) {
/**
* hello
*/
this.hello = () => `aws-sqs-service:${this._endpoint || ''}`;
region = region || engine_1.$engine.environ(AWSSQSService.SQS_REGION, 'ap-northeast-2') || '';
endpoint = endpoint || engine_1.$engine.environ(AWSSQSService.SQS_ENDPOINT, '') || '';
// const stage = $engine.environ('STAGE', '') as string;
// if (!endpoint && stage != 'local')
// throw new Error(`env.${AWSSQSService.SQS_ENDPOINT} is required w/ stage:${stage}`);
(0, engine_1._log)(NS, `AWSSQSService(${endpoint}, ${region})...`);
this._region = region;
this._endpoint = endpoint;
}
region() {
return this._region;
}
endpoint() {
return this._endpoint;
}
/**
* send message into SQS.
*
* @param data object data to be json.
* @param attr attribute set.
*/
sendMessage(data, attr) {
return __awaiter(this, void 0, void 0, function* () {
if (!data)
throw new Error('@data(object) is required!');
//! prepare params.
const asAttr = (param) => Object.keys(param || {}).reduce((O, key) => {
const val = param[key];
const isNum = typeof val === 'number' ? true : false;
O[key] = {
DataType: isNum ? 'Number' : 'String',
StringValue: `${val}`,
};
return O;
}, {});
const params = {
// DelaySeconds: 10, //NOTE - use SQS's configuration.
MessageAttributes: asAttr(attr),
MessageBody: engine_1.$U.json(data && typeof data == 'object' ? data : { data }),
QueueUrl: this.endpoint(),
};
(0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params));
const sqs = new aws_sdk_1.default.SQS({ region: this.region() });
const result = yield sqs.sendMessage(params).promise();
(0, engine_1._log)(NS, '> result =', result);
return (result && result.MessageId) || '';
});
}
/**
* receive message by size.
*
* @param size (default 1) size of message
*/
receiveMessage(size = 1) {
return __awaiter(this, void 0, void 0, function* () {
size = size === undefined ? 1 : size;
size = engine_1.$U.N(size, 0);
if (!size)
throw new Error('@size(number) is required!');
//! prepare param.
const params = {
AttributeNames: ['SentTimestamp'],
MaxNumberOfMessages: size,
MessageAttributeNames: ['All'],
QueueUrl: this.endpoint(),
// VisibilityTimeout: 0, //WARN! DUPLICATE MESSAGES CAN BE SEEN.
WaitTimeSeconds: 0, //WARN! WAIT FOR EMPTY QUEUE.
};
(0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params));
//! call api
const sqs = new aws_sdk_1.default.SQS({ region: this.region() });
const result = yield sqs.receiveMessage(params).promise();
(0, engine_1._log)(NS, '> result =', engine_1.$U.json(result));
//! transform list.
const list = (result && result.Messages).map(_ => {
const N = {};
N.sent = _.Attributes.SentTimestamp;
const $attr = _.MessageAttributes || {};
N.attr = Object.keys($attr).reduce((O, key) => {
const V = $attr[key];
const type = (V && V.DataType) || '';
const val = (V && V.StringValue) || '';
O[key] = type == 'Number' ? Number(val) : val;
return O;
}, {});
N.data = JSON.parse(_.Body || '{}');
N.id = _.MessageId;
N.handle = _.ReceiptHandle;
return N;
});
//! returns.
return { list };
});
}
/**
* delete message by id
* @param handle handle-id to delete.
*/
deleteMessage(handle) {
return __awaiter(this, void 0, void 0, function* () {
if (!handle)
throw new Error('@handle(string) is required!');
//! prepare param
const params = {
QueueUrl: this.endpoint(),
ReceiptHandle: handle,
};
(0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params));
//! call delete.
const sqs = new aws_sdk_1.default.SQS({ region: this.region() });
const result = yield sqs.deleteMessage(params).promise();
(0, engine_1._log)(NS, '> result =', engine_1.$U.json(result));
return;
});
}
/**
* statistics for the given type.
*
* @param {*} TYPE
*/
statistics() {
return __awaiter(this, void 0, void 0, function* () {
const params = {
QueueUrl: this.endpoint(),
AttributeNames: ['All'],
};
(0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params));
//! call delete.
const sqs = new aws_sdk_1.default.SQS({ region: this.region() });
const result = yield sqs.getQueueAttributes(params).promise();
(0, engine_1._log)(NS, '> result =', engine_1.$U.json(result));
const attr = result.Attributes || {};
const stat = {
available: engine_1.$U.N(attr.ApproximateNumberOfMessages, 0),
inflight: engine_1.$U.N(attr.ApproximateNumberOfMessagesNotVisible, 0),
delayed: engine_1.$U.N(attr.ApproximateNumberOfMessagesDelayed, 0),
timeout: engine_1.$U.N(attr.VisibilityTimeout, 0),
};
//! returns finally.
return stat;
});
}
}
exports.AWSSQSService = AWSSQSService;
AWSSQSService.SQS_REGION = 'MY_SQS_REGION';
AWSSQSService.SQS_ENDPOINT = 'MY_SQS_ENDPOINT';
/** ****************************************************************************************************************
* Dummy SQS Service
** ****************************************************************************************************************/
/**
* class: MyDummySQSService
* - simulated dummy `SQSService` which is identical to real-service.
*/
class MyDummySQSService {
constructor(endpoint, timeout = 30) {
this.buffer = [];
this.hello = () => `dummy-sqs-service:${this.endpoint}`;
(0, engine_1._log)(NS, `MyDummySQSService(${endpoint}, ${timeout})...`);
this.endpoint = endpoint;
this.timeout = timeout;
}
sendMessage(data, attr) {
return __awaiter(this, void 0, void 0, function* () {
if (!data)
throw new Error('@data(object) is required!');
const fn = (n) => {
const [S, s] = ['ff2cb2000000', `${n}`];
return n > 0 ? `${S.substring(s.length)}${s}` : s.startsWith('-') ? `N${s.substring(1)}` : s;
};
const payload = { sent: new Date().getTime(), attr, data, id: '', handle: '' };
this.buffer.push(payload);
const len = this.buffer.length;
const id = `aabbccdd-dummy-sqs-b29b-${fn(len)}`;
(0, engine_1._inf)(NS, `> queue[${id}] :=`, engine_1.$U.json(payload));
if (this.timeout > 0) {
setTimeout(() => {
payload.id = id;
}, this.timeout);
}
else if (this.timeout == 0) {
payload.id = id;
}
return id;
});
}
receiveMessage(size) {
return __awaiter(this, void 0, void 0, function* () {
size = size === undefined ? 1 : size;
const list = this.buffer.filter(data => (data.id && data.data ? true : false));
const list2 = list
.filter((_data, index) => index < size)
.map(data => {
const data2 = Object.assign({}, data); // copy
data2.handle = `${data.id}`;
data.id = ''; // mark received.
return data2;
});
return { list: list2 };
});
}
deleteMessage(handle) {
return __awaiter(this, void 0, void 0, function* () {
this.buffer.filter(data => data.handle == handle).map(data => delete data.data);
});
}
statistics() {
return __awaiter(this, void 0, void 0, function* () {
const available = this.buffer.filter(data => !!data.id).length;
const inflight = 0;
const delayed = 0;
const timeout = this.timeout;
return { available, inflight, delayed, timeout };
});
}
}
exports.MyDummySQSService = MyDummySQSService;
//# sourceMappingURL=aws-sqs-service.js.map
;