Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4a5aa484ba | ||
a18ac0355c | |||
a1e7d3f885 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,3 +6,6 @@ client_sessions.json
|
|||||||
center_sessions.json
|
center_sessions.json
|
||||||
dist
|
dist
|
||||||
main.exe
|
main.exe
|
||||||
|
.run
|
||||||
|
.vscode
|
||||||
|
build
|
||||||
|
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": true
|
||||||
|
}
|
@@ -1,19 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Build To Web" type="ShConfigurationType">
|
|
||||||
<option name="SCRIPT_TEXT" value="rsync -auzhvisP ./dist ../smsgw-tester-web/electron" />
|
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
|
||||||
<option name="SCRIPT_PATH" value="" />
|
|
||||||
<option name="SCRIPT_OPTIONS" value="" />
|
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
||||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
|
||||||
<option name="INTERPRETER_PATH" value="" />
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
|
||||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
|
||||||
<envs />
|
|
||||||
<method v="2">
|
|
||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="tsc" run_configuration_type="js.build_tools.npm" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
@@ -1,18 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="main.ts" type="TypeScriptProgramRunner" factoryName="TypeScript">
|
|
||||||
<module name="smsgwtester" />
|
|
||||||
<envs>
|
|
||||||
<env name="LOG_LEVEL" value="0" />
|
|
||||||
</envs>
|
|
||||||
<option name="interpreterRef" value="project" />
|
|
||||||
<option name="enabledTsNodeEsmLoader" value="false" />
|
|
||||||
<option name="interpreterOptions" value="" />
|
|
||||||
<option name="workingDirectory" value="C:\Users\Administrator\WebstormProjects\smsgwtester\src" />
|
|
||||||
<option name="tsconfigFile" value="" />
|
|
||||||
<option name="extraTypeScriptOptions" value="" />
|
|
||||||
<option name="scriptName" value="$PROJECT_DIR$/src/main.ts" />
|
|
||||||
<option name="programParameters" value="" />
|
|
||||||
<option name="tsnodePackage" value="~\WebstormProjects\smsgwtester\node_modules\ts-node" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
@@ -1,14 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="pkg:windows" type="js.build_tools.npm" nameIsGenerated="true">
|
|
||||||
<package-json value="$PROJECT_DIR$/package.json" />
|
|
||||||
<command value="run" />
|
|
||||||
<scripts>
|
|
||||||
<script value="pkg:windows" />
|
|
||||||
</scripts>
|
|
||||||
<node-interpreter value="project" />
|
|
||||||
<envs />
|
|
||||||
<method v="2">
|
|
||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="tsc" run_configuration_type="js.build_tools.npm" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
@@ -1,12 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="tsc" type="js.build_tools.npm" nameIsGenerated="true">
|
|
||||||
<package-json value="$PROJECT_DIR$/package.json" />
|
|
||||||
<command value="run" />
|
|
||||||
<scripts>
|
|
||||||
<script value="tsc" />
|
|
||||||
</scripts>
|
|
||||||
<node-interpreter value="project" />
|
|
||||||
<envs />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY "./main.exe/" "./"
|
||||||
|
|
||||||
|
EXPOSE 6555
|
||||||
|
EXPOSE 6556
|
||||||
|
|
||||||
|
ENTRYPOINT "./main.exe"
|
29
README.md
29
README.md
@@ -70,10 +70,37 @@ With this preprocessor enabled the messages body is chopped up into segments bas
|
|||||||
|
|
||||||
**With this preprocessor disabled any message whose body exceeds the maximum smpp message size is truncated to size**.
|
**With this preprocessor disabled any message whose body exceeds the maximum smpp message size is truncated to size**.
|
||||||
|
|
||||||
|
#### Protocol ID (+2/3 Digit Versions) (1.2)
|
||||||
|
|
||||||
|
This processor sets the protocol_id field to a value.
|
||||||
|
The basic one (ProtocolIdProcessor) sets the value to 1, 2Digit version to 16 and 3Digit version to 128.
|
||||||
|
|
||||||
|
#### Source/Destination Set Processor
|
||||||
|
|
||||||
|
Generates X random numbers that are then used for sending Y messages.
|
||||||
|
The interface with this processor is somewhat specific: To specify the amount of msisdns generated prepend "arg:X;" to the message body.
|
||||||
|
Example: message "arg:100;test123" generates 100 msisdns and sends messages with the body of "test123".
|
||||||
|
The point of this processor is to generate a set of msisdns to use with a greater number of messages.
|
||||||
|
For example sending 100k messages from 100 msisdns (effectively sending 100 messages per msisdn) to simulate 100 users.
|
||||||
|
Note, the picked msisdn per message is random (from the generated set).
|
||||||
|
|
||||||
### Center Preprocessors
|
### Center Preprocessors
|
||||||
|
|
||||||
None as of 1.0
|
#### Destination & Source Enumerator (1.2)
|
||||||
|
|
||||||
|
Same as the Client version.
|
||||||
|
|
||||||
|
#### Long SMS (1.2)
|
||||||
|
|
||||||
|
Same as the Client version.
|
||||||
|
|
||||||
|
#### Protocol ID (+2/3 Digit Versions) (1.2)
|
||||||
|
|
||||||
|
Same as the Client version.
|
||||||
|
|
||||||
|
#### Source/Destination Set Processor (1.2)
|
||||||
|
|
||||||
|
Same as the Client version.
|
||||||
|
|
||||||
### Client Postprocessors
|
### Client Postprocessors
|
||||||
|
|
||||||
|
11
package.json
11
package.json
@@ -3,21 +3,26 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"tsc": "tsc",
|
"dev": "tsup && node build/main.cjs",
|
||||||
"pkg:windows": "pkg ./dist/main.js --target node16-windows-x64 --output main.exe",
|
"pkg:windows": "pkg ./dist/main.js --target node16-windows-x64 --output main.exe",
|
||||||
"pkg:linux": "pkg ./dist/main.js --target node16-linux-x64 --output main.exe"
|
"pkg:linux": "pkg ./dist/main.js --target node16-linux-x64 --output main.exe"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.4.9",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"nanotimer": "^0.3.15",
|
"nanotimer": "^0.3.15",
|
||||||
"smpp": "^0.6.0-rc.4",
|
"smpp": "0.6.0-rc.4",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
"tsup": "^7.2.0",
|
||||||
|
"typescript": "^5.1.6",
|
||||||
"ws": "^8.13.0",
|
"ws": "^8.13.0",
|
||||||
"zlib": "^1.0.5"
|
"zlib": "^1.0.5"
|
||||||
}
|
}
|
||||||
|
1705
pnpm-lock.yaml
generated
Normal file
1705
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
smpp_tester_options.json
Normal file
32
smpp_tester_options.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"url": "smpp://localhost:4445",
|
||||||
|
"connection_count": 8,
|
||||||
|
"system_id": "snt",
|
||||||
|
"password": "snt",
|
||||||
|
"source_addr": "44455",
|
||||||
|
"destination_addr": "test123",
|
||||||
|
"short_message": "SNT BENCHMARK!",
|
||||||
|
"message_count": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "smpp://172.17.77.204:4445",
|
||||||
|
"connection_count": 8,
|
||||||
|
"system_id": "snt",
|
||||||
|
"password": "snt",
|
||||||
|
"source_addr": "44455",
|
||||||
|
"destination_addr": "test123",
|
||||||
|
"short_message": "SNT BENCHMARK!",
|
||||||
|
"message_count": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "smpp://172.17.77.14:4445",
|
||||||
|
"connection_count": 8,
|
||||||
|
"system_id": "snt",
|
||||||
|
"password": "snt",
|
||||||
|
"source_addr": "44455",
|
||||||
|
"destination_addr": "test123",
|
||||||
|
"short_message": "SNT BENCHMARK!",
|
||||||
|
"message_count": 100
|
||||||
|
}
|
||||||
|
]
|
@@ -14,199 +14,199 @@ const smpp = require("smpp");
|
|||||||
const PORT_RELISTEN_DELAY: number = Number(process.env.PORT_RELISTEN_DELAY) || 500;
|
const PORT_RELISTEN_DELAY: number = Number(process.env.PORT_RELISTEN_DELAY) || 500;
|
||||||
|
|
||||||
export default class Center extends SmppSession {
|
export default class Center extends SmppSession {
|
||||||
readonly STATUSES: string[] = [
|
readonly STATUSES: string[] = [
|
||||||
"PORT BUSY",
|
"PORT BUSY",
|
||||||
"WAITING CONNECTION",
|
"WAITING CONNECTION",
|
||||||
"CONNECTING",
|
"CONNECTING",
|
||||||
"CONNECTED",
|
"CONNECTED",
|
||||||
"BUSY"
|
"BUSY"
|
||||||
];
|
];
|
||||||
_username: string;
|
_username: string;
|
||||||
_password: string;
|
_password: string;
|
||||||
_id: number;
|
_id: number;
|
||||||
_status: string = this.STATUSES[0];
|
_status: string = this.STATUSES[0];
|
||||||
port: number;
|
port: number;
|
||||||
|
|
||||||
readonly logger: Logger;
|
readonly logger: Logger;
|
||||||
pendingSessions: any[] = [];
|
pendingSessions: any[] = [];
|
||||||
sessions: any[] = [];
|
sessions: any[] = [];
|
||||||
private nextSession: number = 0;
|
private nextSession: number = 0;
|
||||||
private server: any;
|
private server: any;
|
||||||
|
|
||||||
constructor(id: number, port: number, username: string, password: string) {
|
constructor(id: number, port: number, username: string, password: string) {
|
||||||
super();
|
super();
|
||||||
this._id = id;
|
this._id = id;
|
||||||
this._username = username;
|
this._username = username;
|
||||||
this._password = password;
|
this._password = password;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
|
||||||
this._defaultSingleJob = Job.createEmptySingle('deliver_sm');
|
this._defaultSingleJob = Job.createEmptySingle('deliver_sm');
|
||||||
this._defaultMultipleJob = Job.createEmptyMultiple('deliver_sm');
|
this._defaultMultipleJob = Job.createEmptyMultiple('deliver_sm');
|
||||||
|
|
||||||
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(SubmitSmReplyProcessor.name));
|
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(SubmitSmReplyProcessor.name));
|
||||||
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(BindTranscieverReplyProcessor.name));
|
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(BindTranscieverReplyProcessor.name));
|
||||||
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(EnquireLinkReplyProcessor.name));
|
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(EnquireLinkReplyProcessor.name));
|
||||||
|
|
||||||
this.logger = new Logger(`Center-${id}`);
|
this.logger = new Logger(`Center-${id}`);
|
||||||
|
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaultSingleJob: Job;
|
_defaultSingleJob: Job;
|
||||||
|
|
||||||
get defaultSingleJob(): Job {
|
get defaultSingleJob(): Job {
|
||||||
return this._defaultSingleJob;
|
return this._defaultSingleJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
set defaultSingleJob(job: Job) {
|
set defaultSingleJob(job: Job) {
|
||||||
if (job.pdu && !job.pdu.command) {
|
if (job.pdu && !job.pdu.command) {
|
||||||
job.pdu.command = 'deliver_sm';
|
job.pdu.command = 'deliver_sm';
|
||||||
}
|
}
|
||||||
super.defaultSingleJob = job;
|
super.defaultSingleJob = job;
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaultMultipleJob: Job;
|
_defaultMultipleJob: Job;
|
||||||
|
|
||||||
get defaultMultipleJob(): Job {
|
get defaultMultipleJob(): Job {
|
||||||
return this._defaultMultipleJob;
|
return this._defaultMultipleJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
set defaultMultipleJob(job: Job) {
|
set defaultMultipleJob(job: Job) {
|
||||||
if (job.pdu && !job.pdu.command) {
|
if (job.pdu && !job.pdu.command) {
|
||||||
job.pdu.command = 'deliver_sm';
|
job.pdu.command = 'deliver_sm';
|
||||||
}
|
}
|
||||||
super.defaultMultipleJob = job;
|
super.defaultMultipleJob = job;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPdu(pdu: PDU, force?: boolean): Promise<object> {
|
sendPdu(pdu: PDU, force?: boolean): Promise<object> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
this.validateSessions(reject);
|
this.validateSessions(reject);
|
||||||
}
|
}
|
||||||
this.logger.log5(`Center-${this.id} sending PDU: ${JSON.stringify(pdu)}`);
|
let pduCopy = new smpp.PDU(pdu.command, {...pdu});
|
||||||
let pduCopy = new smpp.PDU(pdu.command, {...pdu});
|
let session = this.getNextSession();
|
||||||
let session = this.getNextSession();
|
this.processors.Preprocessor.forEach((processor: PduProcessor) => processor.processPdu(session, pduCopy, this));
|
||||||
this.processors.Preprocessor.forEach((processor: PduProcessor) => processor.processPdu(session, pduCopy, this));
|
this.logger.log5(`Center-${this.id} sending PDU: ${JSON.stringify(pduCopy)}`);
|
||||||
this.doSendPdu(pduCopy, session).then((replyPdu: any) => {
|
this.doSendPdu(pduCopy, session).then((replyPdu: any) => {
|
||||||
resolve(replyPdu);
|
resolve(replyPdu);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMultiple(job: Job): Promise<void> {
|
sendMultiple(job: Job): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.validateSessions(reject);
|
this.validateSessions(reject);
|
||||||
if (!job.count || !job.perSecond) {
|
if (!job.count || !job.perSecond) {
|
||||||
reject(`Center-${this.id} sendMultiple failed: invalid job, missing fields`);
|
reject(`Center-${this.id} sendMultiple failed: invalid job, missing fields`);
|
||||||
}
|
}
|
||||||
this.logger.log1(`Center-${this.id} sending multiple messages: ${JSON.stringify(job)}`);
|
this.logger.log1(`Center-${this.id} sending multiple messages: ${JSON.stringify(job)}`);
|
||||||
|
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
let previousUpdateCounter = 0;
|
let previousUpdateCounter = 0;
|
||||||
|
|
||||||
this.counterUpdateTimer.setInterval(() => {
|
this.counterUpdateTimer.setInterval(() => {
|
||||||
if (previousUpdateCounter !== counter) {
|
if (previousUpdateCounter !== counter) {
|
||||||
this.eventEmitter.emit(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, counter);
|
this.eventEmitter.emit(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, counter);
|
||||||
previousUpdateCounter = counter;
|
previousUpdateCounter = counter;
|
||||||
}
|
}
|
||||||
}, '', `${this.MESSAGE_SEND_UPDATE_DELAY / 1000} s`);
|
}, '', `${this.MESSAGE_SEND_UPDATE_DELAY / 1000} s`);
|
||||||
|
|
||||||
let count = job.count || 1;
|
let count = job.count || 1;
|
||||||
let interval = 1 / (job.perSecond || 1);
|
let interval = 1 / (job.perSecond || 1);
|
||||||
this.setStatus(4);
|
this.setStatus(4);
|
||||||
this.sendTimer.setInterval(() => {
|
this.sendTimer.setInterval(() => {
|
||||||
if (count > 0 && counter >= count) {
|
if (count > 0 && counter >= count) {
|
||||||
this.cancelSendInterval();
|
this.cancelSendInterval();
|
||||||
} else {
|
} else {
|
||||||
this.sendPdu(job.pdu, true);
|
this.sendPdu(job.pdu, true);
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}, '', `${interval} s`);
|
}, '', `${interval} s`);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(): void {
|
initialize(): void {
|
||||||
this.server = smpp.createServer({}, this.eventSessionConnected.bind(this));
|
this.server = smpp.createServer({}, this.eventSessionConnected.bind(this));
|
||||||
this.server.on('error', this.eventServerError.bind(this));
|
this.server.on('error', this.eventServerError.bind(this));
|
||||||
this.doListen();
|
this.doListen();
|
||||||
this.setStatus(1);
|
this.setStatus(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(): Promise<void> {
|
close(): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.logger.log1(`Center-${this.id} closing active connections`);
|
this.logger.log1(`Center-${this.id} closing active connections`);
|
||||||
this.sessions.forEach((session: any) => {
|
this.sessions.forEach((session: any) => {
|
||||||
session.close();
|
session.close();
|
||||||
});
|
});
|
||||||
this.setStatus(1);
|
this.setStatus(1);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
this.server.close();
|
this.server.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
postSerialize(obj: any): object {
|
postSerialize(obj: any): object {
|
||||||
obj.port = this.port;
|
obj.port = this.port;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStatus(): void {
|
updateStatus(): void {
|
||||||
if (this.sessions.length > 0) {
|
if (this.sessions.length > 0) {
|
||||||
this.setStatus(3);
|
this.setStatus(3);
|
||||||
} else if (this.pendingSessions.length > 0) {
|
} else if (this.pendingSessions.length > 0) {
|
||||||
this.setStatus(2);
|
this.setStatus(2);
|
||||||
} else {
|
} else {
|
||||||
this.setStatus(1);
|
this.setStatus(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private doListen(): void {
|
private doListen(): void {
|
||||||
this.server.listen(this.port);
|
this.server.listen(this.port);
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateSessions(reject: (reason?: any) => void) {
|
private validateSessions(reject: (reason?: any) => void) {
|
||||||
if (this.sessions.length === 0) {
|
if (this.sessions.length === 0) {
|
||||||
reject(`No clients connected`);
|
reject(`No clients connected`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getNextSession(): any {
|
private getNextSession(): any {
|
||||||
if (this.sessions.length === 0) {
|
if (this.sessions.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let session = this.sessions[this.nextSession];
|
let session = this.sessions[this.nextSession];
|
||||||
this.nextSession = (this.nextSession + 1) % this.sessions.length;
|
this.nextSession = (this.nextSession + 1) % this.sessions.length;
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventSessionConnected(session: any): void {
|
private eventSessionConnected(session: any): void {
|
||||||
this.logger.log1(`A client connected to center-${this.id}`);
|
this.logger.log1(`A client connected to center-${this.id}`);
|
||||||
this.pendingSessions.push(session);
|
this.pendingSessions.push(session);
|
||||||
session.on('close', this.eventSessionClose.bind(this, session));
|
session.on('close', this.eventSessionClose.bind(this, session));
|
||||||
session.on('error', this.eventSessionError.bind(this, session));
|
session.on('error', this.eventSessionError.bind(this, session));
|
||||||
session.on('pdu', this.eventAnyPdu.bind(this, session));
|
session.on('pdu', this.eventAnyPdu.bind(this, session));
|
||||||
this.updateStatus();
|
this.updateStatus();
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventSessionError(session: any): void {
|
private eventSessionError(session: any): void {
|
||||||
this.logger.log1(`A client encountered an error on center-${this.id}`);
|
this.logger.log1(`A client encountered an error on center-${this.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventServerError(): void {
|
private eventServerError(): void {
|
||||||
this.logger.log1(`Center tried listening on port which is already in use, retrying in ${PORT_RELISTEN_DELAY}`);
|
this.logger.log1(`Center tried listening on port which is already in use, retrying in ${PORT_RELISTEN_DELAY}`);
|
||||||
this.setStatus(0);
|
this.setStatus(0);
|
||||||
setTimeout(this.doListen.bind(this), PORT_RELISTEN_DELAY);
|
setTimeout(this.doListen.bind(this), PORT_RELISTEN_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventSessionClose(session: any): void {
|
private eventSessionClose(session: any): void {
|
||||||
this.logger.log1(`A client disconnected from center-${this.id}`);
|
this.logger.log1(`A client disconnected from center-${this.id}`);
|
||||||
this.sessions = this.sessions.filter((s: any) => s !== session);
|
this.sessions = this.sessions.filter((s: any) => s !== session);
|
||||||
this.nextSession = 0;
|
this.nextSession = 0;
|
||||||
this.pendingSessions = this.pendingSessions.filter((s: any) => s !== session);
|
this.pendingSessions = this.pendingSessions.filter((s: any) => s !== session);
|
||||||
this.updateStatus();
|
this.updateStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,15 +6,15 @@ import Center from "./Center";
|
|||||||
const CENTER_SESSIONS_FILE: string = process.env.CENTER_SESSIONS_FILE || "center_sessions.json";
|
const CENTER_SESSIONS_FILE: string = process.env.CENTER_SESSIONS_FILE || "center_sessions.json";
|
||||||
|
|
||||||
export default class CenterSessionManager extends SessionManager {
|
export default class CenterSessionManager extends SessionManager {
|
||||||
StorageFile: string = CENTER_SESSIONS_FILE
|
StorageFile: string = CENTER_SESSIONS_FILE
|
||||||
ManagedSessionClass: typeof Center = Center;
|
ManagedSessionClass: typeof Center = Center;
|
||||||
identifier: string = "Center";
|
identifier: string = "Center";
|
||||||
readonly logger: Logger = new Logger("CenterSessionManager");
|
readonly logger: Logger = new Logger("CenterSessionManager");
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.setup();
|
this.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
comparatorFn: (arg: any, session: SmppSession) => boolean = (arg: any, session: SmppSession) => (session as Center).port === arg;
|
comparatorFn: (arg: any, session: SmppSession) => boolean = (arg: any, session: SmppSession) => (session as Center).port === arg;
|
||||||
}
|
}
|
@@ -13,271 +13,271 @@ const smpp = require("smpp");
|
|||||||
const AUTO_ENQUIRE_LINK_PERIOD: number = Number(process.env.AUTO_ENQUIRE_LINK_PERIOD) || 30000;
|
const AUTO_ENQUIRE_LINK_PERIOD: number = Number(process.env.AUTO_ENQUIRE_LINK_PERIOD) || 30000;
|
||||||
|
|
||||||
export default class Client extends SmppSession {
|
export default class Client extends SmppSession {
|
||||||
readonly STATUSES: string[] = [
|
readonly STATUSES: string[] = [
|
||||||
"NOT CONNECTED",
|
"NOT CONNECTED",
|
||||||
"CONNECTING",
|
"CONNECTING",
|
||||||
"CONNECTED",
|
"CONNECTED",
|
||||||
"BINDING",
|
"BINDING",
|
||||||
"BOUND",
|
"BOUND",
|
||||||
"BUSY",
|
"BUSY",
|
||||||
]
|
]
|
||||||
url: string;
|
url: string;
|
||||||
_username: string;
|
_username: string;
|
||||||
_password: string;
|
_password: string;
|
||||||
_id: number;
|
_id: number;
|
||||||
_status: string = this.STATUSES[0];
|
_status: string = this.STATUSES[0];
|
||||||
readonly logger: Logger;
|
readonly logger: Logger;
|
||||||
private session?: any;
|
private session?: any;
|
||||||
private connectPromise: PersistentPromise | null = null;
|
private connectPromise: PersistentPromise | null = null;
|
||||||
private bindPromise: PersistentPromise | null = null;
|
private bindPromise: PersistentPromise | null = null;
|
||||||
private closePromise: PersistentPromise | null = null;
|
private closePromise: PersistentPromise | null = null;
|
||||||
|
|
||||||
constructor(id: number, url: string, username: string, password: string) {
|
constructor(id: number, url: string, username: string, password: string) {
|
||||||
super();
|
super();
|
||||||
this._id = id;
|
this._id = id;
|
||||||
this._username = username;
|
this._username = username;
|
||||||
this._password = password;
|
this._password = password;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
|
||||||
this._defaultSingleJob = Job.createEmptySingle('submit_sm');
|
this._defaultSingleJob = Job.createEmptySingle('submit_sm');
|
||||||
this._defaultMultipleJob = Job.createEmptyMultiple('submit_sm');
|
this._defaultMultipleJob = Job.createEmptyMultiple('submit_sm');
|
||||||
|
|
||||||
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(DeliverSmReplyProcessor.name));
|
ProcessorManager.attachProcessors(this, ProcessorManager.getProcessors(DeliverSmReplyProcessor.name));
|
||||||
|
|
||||||
this.logger = new Logger(`Client-${id}`);
|
this.logger = new Logger(`Client-${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaultSingleJob: Job;
|
_defaultSingleJob: Job;
|
||||||
|
|
||||||
get defaultSingleJob(): Job {
|
get defaultSingleJob(): Job {
|
||||||
return this._defaultSingleJob;
|
return this._defaultSingleJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
set defaultSingleJob(job: Job) {
|
set defaultSingleJob(job: Job) {
|
||||||
if (job.pdu && !job.pdu.command) {
|
if (job.pdu && !job.pdu.command) {
|
||||||
job.pdu.command = 'submit_sm';
|
job.pdu.command = 'submit_sm';
|
||||||
}
|
}
|
||||||
super.defaultSingleJob = job;
|
super.defaultSingleJob = job;
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaultMultipleJob: Job;
|
_defaultMultipleJob: Job;
|
||||||
|
|
||||||
get defaultMultipleJob(): Job {
|
get defaultMultipleJob(): Job {
|
||||||
return this._defaultMultipleJob;
|
return this._defaultMultipleJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
set defaultMultipleJob(job: Job) {
|
set defaultMultipleJob(job: Job) {
|
||||||
if (job.pdu && !job.pdu.command) {
|
if (job.pdu && !job.pdu.command) {
|
||||||
job.pdu.command = 'submit_sm';
|
job.pdu.command = 'submit_sm';
|
||||||
}
|
}
|
||||||
super.defaultMultipleJob = job;
|
super.defaultMultipleJob = job;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
doConnect(): PersistentPromise {
|
doConnect(): PersistentPromise {
|
||||||
this.connectPromise = new PersistentPromise((resolve, reject) => {
|
this.connectPromise = new PersistentPromise((resolve, reject) => {
|
||||||
if (this.status !== this.STATUSES[0]) {
|
if (this.status !== this.STATUSES[0]) {
|
||||||
let errorString = `Client-${this.id} already connected`;
|
let errorString = `Client-${this.id} already connected`;
|
||||||
this.logger.log1(errorString);
|
this.logger.log1(errorString);
|
||||||
reject(errorString);
|
reject(errorString);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.log1(`Client-${this.id} connecting to ${this.url}`);
|
this.logger.log1(`Client-${this.id} connecting to ${this.url}`);
|
||||||
this.setStatus(1);
|
this.setStatus(1);
|
||||||
this.connectSession().then(resolve, ((err: any) => {
|
this.connectSession().then(resolve, ((err: any) => {
|
||||||
this.logger.log1(`Client-${this.id} connection failed: ${err}`);
|
this.logger.log1(`Client-${this.id} connection failed: ${err}`);
|
||||||
this.setStatus(0);
|
this.setStatus(0);
|
||||||
this.session.close();
|
this.session.close();
|
||||||
reject(err);
|
reject(err);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
return this.connectPromise;
|
return this.connectPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
doBind(): PersistentPromise {
|
doBind(): PersistentPromise {
|
||||||
this.bindPromise = new PersistentPromise((resolve, reject) => {
|
this.bindPromise = new PersistentPromise((resolve, reject) => {
|
||||||
this.validateFields(reject);
|
this.validateFields(reject);
|
||||||
|
|
||||||
this.session.bind_transceiver({
|
this.session.bind_transceiver({
|
||||||
system_id: this.username,
|
system_id: this.username,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
}, this.eventBindReply.bind(this));
|
}, this.eventBindReply.bind(this));
|
||||||
this.setStatus(3);
|
this.setStatus(3);
|
||||||
});
|
});
|
||||||
return this.bindPromise;
|
return this.bindPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectAndBind(): Promise<void> {
|
connectAndBind(): Promise<void> {
|
||||||
return this.doConnect().then(this.doBind.bind(this), (error) => {
|
return this.doConnect().then(this.doBind.bind(this), (error) => {
|
||||||
this.logger.log1(`Client-${this.id} connectAndBind failed: ${error}`);
|
this.logger.log1(`Client-${this.id} connectAndBind failed: ${error}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
postSerialize(obj: any): object {
|
postSerialize(obj: any): object {
|
||||||
obj.url = this.url;
|
obj.url = this.url;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(): Promise<void> {
|
close(): Promise<void> {
|
||||||
this.logger.log1(`Client-${this.id} closing connection`);
|
this.logger.log1(`Client-${this.id} closing connection`);
|
||||||
if (this.session) {
|
if (this.session) {
|
||||||
return Promise.resolve(this.session.close());
|
return Promise.resolve(this.session.close());
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPdu(pdu: PDU, force?: boolean): Promise<object> {
|
sendPdu(pdu: PDU, force?: boolean): Promise<object> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
this.validateSession(reject);
|
this.validateSession(reject);
|
||||||
this.validateBound(reject);
|
this.validateBound(reject);
|
||||||
}
|
}
|
||||||
// Is this expensive...?
|
// Is this expensive...?
|
||||||
let pduCopy = new smpp.PDU(pdu.command, {...pdu});
|
let pduCopy = new smpp.PDU(pdu.command, {...pdu});
|
||||||
this.processors.Preprocessor.forEach((processor: PduProcessor) => processor.processPdu(this.session, pduCopy, this));
|
this.processors.Preprocessor.forEach((processor: PduProcessor) => processor.processPdu(this.session, pduCopy, this));
|
||||||
this.logger.log5(`Client-${this.id} sending PDU: ${JSON.stringify(pduCopy)}`);
|
this.logger.log5(`Client-${this.id} sending PDU: ${JSON.stringify(pduCopy)}`);
|
||||||
this.doSendPdu(pduCopy, this.session).then((replyPdu: any) => {
|
this.doSendPdu(pduCopy, this.session).then((replyPdu: any) => {
|
||||||
resolve(replyPdu);
|
resolve(replyPdu);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMultiple(job: Job): Promise<void> {
|
sendMultiple(job: Job): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.validateSession(reject);
|
this.validateSession(reject);
|
||||||
this.validateBound(reject);
|
this.validateBound(reject);
|
||||||
if (!job.count || !job.perSecond) {
|
if (!job.count || !job.perSecond) {
|
||||||
reject(`Client-${this.id} sendMultiple failed: invalid job, missing fields`);
|
reject(`Client-${this.id} sendMultiple failed: invalid job, missing fields`);
|
||||||
}
|
}
|
||||||
this.logger.log1(`Client-${this.id} sending multiple messages: ${JSON.stringify(job)}`);
|
this.logger.log1(`Client-${this.id} sending multiple messages: ${JSON.stringify(job)}`);
|
||||||
|
|
||||||
this.setStatus(4);
|
this.setStatus(4);
|
||||||
|
|
||||||
let counter: number = 0;
|
let counter: number = 0;
|
||||||
let previousUpdateCounter: number = 0;
|
let previousUpdateCounter: number = 0;
|
||||||
|
|
||||||
this.counterUpdateTimer.setInterval(() => {
|
this.counterUpdateTimer.setInterval(() => {
|
||||||
if (previousUpdateCounter !== counter) {
|
if (previousUpdateCounter !== counter) {
|
||||||
this.eventEmitter.emit(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, counter);
|
this.eventEmitter.emit(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, counter);
|
||||||
previousUpdateCounter = counter;
|
previousUpdateCounter = counter;
|
||||||
}
|
}
|
||||||
}, '', `${this.MESSAGE_SEND_UPDATE_DELAY / 1000} s`);
|
}, '', `${this.MESSAGE_SEND_UPDATE_DELAY / 1000} s`);
|
||||||
|
|
||||||
let count: number = job.count || 1;
|
let count: number = job.count || 1;
|
||||||
let interval: number = 1 / (job.perSecond || 1);
|
let interval: number = 1 / (job.perSecond || 1);
|
||||||
this.setStatus(5);
|
this.setStatus(5);
|
||||||
this.sendTimer.setInterval(() => {
|
this.sendTimer.setInterval(() => {
|
||||||
if (count > 0 && counter >= count) {
|
if (count > 0 && counter >= count) {
|
||||||
this.cancelSendInterval();
|
this.cancelSendInterval();
|
||||||
} else {
|
} else {
|
||||||
this.sendPdu(job.pdu, true)
|
this.sendPdu(job.pdu, true)
|
||||||
.catch(e => this.logger.log1(`Error sending message: ${e}`));
|
.catch(e => this.logger.log1(`Error sending message: ${e}`));
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}, '', `${interval} s`);
|
}, '', `${interval} s`);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private connectSession(): Promise<void> {
|
private connectSession(): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
this.validateFields(reject);
|
this.validateFields(reject);
|
||||||
this.logger.log1(`Client-${this.id} connecting to ${this.url}`);
|
this.logger.log1(`Client-${this.id} connecting to ${this.url}`);
|
||||||
|
|
||||||
this.session = smpp.connect({
|
this.session = smpp.connect({
|
||||||
url: this.url, auto_enquire_link_period: AUTO_ENQUIRE_LINK_PERIOD,
|
url: this.url, auto_enquire_link_period: AUTO_ENQUIRE_LINK_PERIOD,
|
||||||
}, this.eventSessionConnected.bind(this));
|
}, this.eventSessionConnected.bind(this));
|
||||||
this.session.on('error', this.eventSessionError.bind(this));
|
this.session.on('error', this.eventSessionError.bind(this));
|
||||||
this.session.on('close', this.eventSessionClose.bind(this));
|
this.session.on('close', this.eventSessionClose.bind(this));
|
||||||
this.session.on('pdu', this.eventAnyPdu.bind(this, this.session));
|
this.session.on('pdu', this.eventAnyPdu.bind(this, this.session));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventSessionConnected(): void {
|
private eventSessionConnected(): void {
|
||||||
this.logger.log1(`Client-${this.id} connected to ${this.url}`);
|
this.logger.log1(`Client-${this.id} connected to ${this.url}`);
|
||||||
this.setStatus(2);
|
this.setStatus(2);
|
||||||
if (this.connectPromise) {
|
if (this.connectPromise) {
|
||||||
this.connectPromise.resolve();
|
this.connectPromise.resolve();
|
||||||
} else {
|
} else {
|
||||||
this.logger.log1(`Client-${this.id} connected without connect promise`);
|
this.logger.log1(`Client-${this.id} connected without connect promise`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventSessionError(pdu: any): void {
|
private eventSessionError(pdu: any): void {
|
||||||
this.logger.log1(`Client-${this.id} error on ${this.url} - ${pdu.message}`);
|
this.logger.log1(`Client-${this.id} error on ${this.url} - ${pdu.message}`);
|
||||||
this.setStatus(0);
|
this.setStatus(0);
|
||||||
this.rejectPromises();
|
this.rejectPromises();
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventSessionClose(): void {
|
private eventSessionClose(): void {
|
||||||
this.logger.log1(`Client-${this.id} closed on ${this.url}`);
|
this.logger.log1(`Client-${this.id} closed on ${this.url}`);
|
||||||
this.setStatus(0);
|
this.setStatus(0);
|
||||||
this.rejectPromises();
|
this.rejectPromises();
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventBindReply(pdu: PDU): void {
|
private eventBindReply(pdu: PDU): void {
|
||||||
if (pdu.command_status === 0) {
|
if (pdu.command_status === 0) {
|
||||||
this.logger.log1(`Client-${this.id} bound to ${this.url}`);
|
this.logger.log1(`Client-${this.id} bound to ${this.url}`);
|
||||||
this.setStatus(4);
|
this.setStatus(4);
|
||||||
if (this.bindPromise) {
|
if (this.bindPromise) {
|
||||||
this.bindPromise.resolve();
|
this.bindPromise.resolve();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.logger.log1(`Client-${this.id} bind failed to ${this.url}`);
|
this.logger.log1(`Client-${this.id} bind failed to ${this.url}`);
|
||||||
this.setStatus(2);
|
this.setStatus(2);
|
||||||
if (this.bindPromise) {
|
if (this.bindPromise) {
|
||||||
this.bindPromise.reject(pdu);
|
this.bindPromise.reject(pdu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private rejectPromises(err?: any): void {
|
private rejectPromises(err?: any): void {
|
||||||
if (this.connectPromise) {
|
if (this.connectPromise) {
|
||||||
this.connectPromise.reject(err);
|
this.connectPromise.reject(err);
|
||||||
}
|
}
|
||||||
if (this.bindPromise) {
|
if (this.bindPromise) {
|
||||||
this.bindPromise.reject(err);
|
this.bindPromise.reject(err);
|
||||||
}
|
}
|
||||||
if (this.closePromise) {
|
if (this.closePromise) {
|
||||||
this.closePromise.resolve();
|
this.closePromise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateFields(reject: (reason?: any) => void) {
|
private validateFields(reject: (reason?: any) => void) {
|
||||||
if (!this.url) {
|
if (!this.url) {
|
||||||
let error = `Client-${this.id} has no url set`;
|
let error = `Client-${this.id} has no url set`;
|
||||||
this.logger.log1(error);
|
this.logger.log1(error);
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
if (!this.username) {
|
if (!this.username) {
|
||||||
let error = `Client-${this.id} has no username set`;
|
let error = `Client-${this.id} has no username set`;
|
||||||
this.logger.log1(error);
|
this.logger.log1(error);
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
if (!this.password) {
|
if (!this.password) {
|
||||||
let error = `Client-${this.id} has no password set`;
|
let error = `Client-${this.id} has no password set`;
|
||||||
this.logger.log1(error);
|
this.logger.log1(error);
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateSession(reject: (reason?: any) => void) {
|
private validateSession(reject: (reason?: any) => void) {
|
||||||
if (!this.session) {
|
if (!this.session) {
|
||||||
let errorMessage = `Client-${this.id} session is not defined`;
|
let errorMessage = `Client-${this.id} session is not defined`;
|
||||||
this.logger.log1(errorMessage);
|
this.logger.log1(errorMessage);
|
||||||
reject(errorMessage);
|
reject(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateBound(reject: (reason?: any) => void) {
|
private validateBound(reject: (reason?: any) => void) {
|
||||||
if (this.status !== this.STATUSES[4]) {
|
if (this.status !== this.STATUSES[4]) {
|
||||||
let errorMessage = `Client-${this.id} is not bound`;
|
let errorMessage = `Client-${this.id} is not bound`;
|
||||||
this.logger.log1(errorMessage);
|
this.logger.log1(errorMessage);
|
||||||
reject(errorMessage);
|
reject(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,15 +6,15 @@ import Client from "./Client";
|
|||||||
const CLIENT_SESSIONS_FILE: string = process.env.CLIENT_SESSIONS_FILE || "client_sessions.json";
|
const CLIENT_SESSIONS_FILE: string = process.env.CLIENT_SESSIONS_FILE || "client_sessions.json";
|
||||||
|
|
||||||
export default class ClientSessionManager extends SessionManager {
|
export default class ClientSessionManager extends SessionManager {
|
||||||
StorageFile: string = CLIENT_SESSIONS_FILE;
|
StorageFile: string = CLIENT_SESSIONS_FILE;
|
||||||
ManagedSessionClass: typeof Client = Client;
|
ManagedSessionClass: typeof Client = Client;
|
||||||
identifier: string = "Client";
|
identifier: string = "Client";
|
||||||
readonly logger: Logger = new Logger("ClientSessionManager");
|
readonly logger: Logger = new Logger("ClientSessionManager");
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.setup();
|
this.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
comparatorFn: (arg: any, session: SmppSession) => boolean = (arg: any, session: SmppSession) => (session as Client).url === arg;
|
comparatorFn: (arg: any, session: SmppSession) => boolean = (arg: any, session: SmppSession) => (session as Client).url === arg;
|
||||||
}
|
}
|
@@ -1,37 +1,37 @@
|
|||||||
export type PDU = {
|
export type PDU = {
|
||||||
command?: string;
|
command?: string;
|
||||||
command_id?: number;
|
command_id?: number;
|
||||||
command_length?: number;
|
command_length?: number;
|
||||||
command_status?: number;
|
command_status?: number;
|
||||||
data_coding?: number;
|
data_coding?: number;
|
||||||
dest_addr_npi?: number;
|
dest_addr_npi?: number;
|
||||||
dest_addr_ton?: number;
|
dest_addr_ton?: number;
|
||||||
destination_addr?: string;
|
destination_addr?: string;
|
||||||
esm_class?: number,
|
esm_class?: number,
|
||||||
password?: string,
|
password?: string,
|
||||||
priority_flag?: number,
|
priority_flag?: number,
|
||||||
protocol_id?: number,
|
protocol_id?: number,
|
||||||
registered_delivery?: number,
|
registered_delivery?: number,
|
||||||
replace_if_present_flag?: number,
|
replace_if_present_flag?: number,
|
||||||
response?: (...args: any[]) => PDU,
|
response?: (...args: any[]) => PDU,
|
||||||
schedule_delivery_time?: string,
|
schedule_delivery_time?: string,
|
||||||
sequence_number?: number,
|
sequence_number?: number,
|
||||||
service_type?: string,
|
service_type?: string,
|
||||||
short_message?: any,
|
short_message?: any,
|
||||||
sm_default_msg_id?: number,
|
sm_default_msg_id?: number,
|
||||||
source_addr?: string,
|
source_addr?: string,
|
||||||
source_addr_npi?: number,
|
source_addr_npi?: number,
|
||||||
source_addr_ton?: number,
|
source_addr_ton?: number,
|
||||||
system_id?: string,
|
system_id?: string,
|
||||||
validity_period?: string
|
validity_period?: string
|
||||||
};
|
};
|
||||||
export type SerializedJob = {
|
export type SerializedJob = {
|
||||||
pdu: PDU;
|
pdu: PDU;
|
||||||
count?: number;
|
count?: number;
|
||||||
perSecond?: number;
|
perSecond?: number;
|
||||||
};
|
};
|
||||||
export type WSMessage = {
|
export type WSMessage = {
|
||||||
type: string;
|
type: string;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
data?: any;
|
data?: any;
|
||||||
};
|
};
|
@@ -8,58 +8,58 @@ import SmppSession from "../SmppSession";
|
|||||||
import RequestHandler from "./RequestHandler";
|
import RequestHandler from "./RequestHandler";
|
||||||
|
|
||||||
export default class CenterRequestHandler extends RequestHandler {
|
export default class CenterRequestHandler extends RequestHandler {
|
||||||
sessionManager: CenterSessionManager;
|
sessionManager: CenterSessionManager;
|
||||||
logger: Logger = new Logger(this.constructor.name);
|
logger: Logger = new Logger(this.constructor.name);
|
||||||
|
|
||||||
constructor(sessionManager: SessionManager) {
|
constructor(sessionManager: SessionManager) {
|
||||||
super();
|
super();
|
||||||
this.sessionManager = sessionManager as CenterSessionManager;
|
this.sessionManager = sessionManager as CenterSessionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
doGetAvailableProcessors(req: any, res: any): void {
|
doGetAvailableProcessors(req: any, res: any): void {
|
||||||
this.logger.log1("Getting available processors");
|
this.logger.log1("Getting available processors");
|
||||||
let processors: PduProcessor[] = ProcessorManager.getProcessorsForType(Center.name);
|
let processors: PduProcessor[] = ProcessorManager.getProcessorsForType(Center.name);
|
||||||
res.send(processors.map((processor: any) => processor.serialize()));
|
res.send(processors.map((processor: any) => processor.serialize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
doGetAppliedProcessors(req: any, res: any): void {
|
doGetAppliedProcessors(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
let processors: PduProcessor[] = session.appliedProcessors;
|
let processors: PduProcessor[] = session.appliedProcessors;
|
||||||
res.send(processors.map((processor: any) => processor.serialize()));
|
res.send(processors.map((processor: any) => processor.serialize()));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doAddProcessor(req: any, res: any): void {
|
doAddProcessor(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
||||||
ProcessorManager.attachProcessors(session, processors);
|
ProcessorManager.attachProcessors(session, processors);
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doRemoveProcessor(req: any, res: any): void {
|
doRemoveProcessor(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
||||||
ProcessorManager.detachProcessors(session, processors);
|
ProcessorManager.detachProcessors(session, processors);
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doPost(req: any, res: any): void {
|
doPost(req: any, res: any): void {
|
||||||
this.logger.log1("Creating center session");
|
this.logger.log1("Creating center session");
|
||||||
this.sessionManager.createSession(req.body.port, req.body.username, req.body.password).then((session: SmppSession) => {
|
this.sessionManager.createSession(req.body.port, req.body.username, req.body.password).then((session: SmppSession) => {
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, (err: any) => {
|
}, (err: any) => {
|
||||||
this.logger.log1(`Failed to create center session: ${err}`);
|
this.logger.log1(`Failed to create center session: ${err}`);
|
||||||
res.status(500).send();
|
res.status(500).send();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doConnect(req: any, res: any): void {
|
doConnect(req: any, res: any): void {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
doBind(req: any, res: any): void {
|
doBind(req: any, res: any): void {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,76 +8,76 @@ import SmppSession from "../SmppSession";
|
|||||||
import RequestHandler from "./RequestHandler";
|
import RequestHandler from "./RequestHandler";
|
||||||
|
|
||||||
export default class ClientRequestHandler extends RequestHandler {
|
export default class ClientRequestHandler extends RequestHandler {
|
||||||
sessionManager: ClientSessionManager;
|
sessionManager: ClientSessionManager;
|
||||||
logger: Logger = new Logger(this.constructor.name);
|
logger: Logger = new Logger(this.constructor.name);
|
||||||
|
|
||||||
constructor(sessionManager: SessionManager) {
|
constructor(sessionManager: SessionManager) {
|
||||||
super();
|
super();
|
||||||
this.sessionManager = sessionManager as ClientSessionManager;
|
this.sessionManager = sessionManager as ClientSessionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
doGetAvailableProcessors(req: any, res: any): void {
|
doGetAvailableProcessors(req: any, res: any): void {
|
||||||
this.logger.log1("Getting available processors");
|
this.logger.log1("Getting available processors");
|
||||||
let processors: PduProcessor[] = ProcessorManager.getProcessorsForType(Client.name);
|
let processors: PduProcessor[] = ProcessorManager.getProcessorsForType(Client.name);
|
||||||
res.send(processors.map((processor: any) => processor.serialize()));
|
res.send(processors.map((processor: any) => processor.serialize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
doGetAppliedProcessors(req: any, res: any): void {
|
doGetAppliedProcessors(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
let processors: PduProcessor[] = session.appliedProcessors;
|
let processors: PduProcessor[] = session.appliedProcessors;
|
||||||
res.send(processors.map((processor: any) => processor.serialize()));
|
res.send(processors.map((processor: any) => processor.serialize()));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doAddProcessor(req: any, res: any): void {
|
doAddProcessor(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
||||||
ProcessorManager.attachProcessors(session, processors);
|
ProcessorManager.attachProcessors(session, processors);
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doRemoveProcessor(req: any, res: any): void {
|
doRemoveProcessor(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
let processors: PduProcessor[] = ProcessorManager.getProcessors(req.body.name);
|
||||||
ProcessorManager.detachProcessors(session, processors);
|
ProcessorManager.detachProcessors(session, processors);
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doPost(req: any, res: any): void {
|
doPost(req: any, res: any): void {
|
||||||
this.logger.log1("Creating client session");
|
this.logger.log1("Creating client session");
|
||||||
this.sessionManager.createSession(req.body.url, req.body.username, req.body.password).then((session: SmppSession) => {
|
this.sessionManager.createSession(req.body.url, req.body.username, req.body.password).then((session: SmppSession) => {
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, (err: any) => {
|
}, (err: any) => {
|
||||||
this.logger.log1(`Failed to create client session: ${err}`);
|
this.logger.log1(`Failed to create client session: ${err}`);
|
||||||
res.status(500).send();
|
res.status(500).send();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doBind(req: any, res: any): void {
|
doBind(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Binding client session with ID ${req.params.id}`)
|
this.logger.log1(`Binding client session with ID ${req.params.id}`)
|
||||||
let client = session as Client;
|
let client = session as Client;
|
||||||
client.doBind()
|
client.doBind()
|
||||||
.then(() => res.send(session.serialize()))
|
.then(() => res.send(session.serialize()))
|
||||||
.catch(err => res.status(400).send({
|
.catch(err => res.status(400).send({
|
||||||
err: true,
|
err: true,
|
||||||
msg: err
|
msg: err
|
||||||
}));
|
}));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doConnect(req: any, res: any): void {
|
doConnect(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Connecting client session with ID ${req.params.id}`);
|
this.logger.log1(`Connecting client session with ID ${req.params.id}`);
|
||||||
let client = session as Client;
|
let client = session as Client;
|
||||||
client.doConnect()
|
client.doConnect()
|
||||||
.then(() => res.send(session.serialize()))
|
.then(() => res.send(session.serialize()))
|
||||||
.catch(err => res.status(400).send({
|
.catch(err => res.status(400).send({
|
||||||
err: true,
|
err: true,
|
||||||
msg: err
|
msg: err
|
||||||
}));
|
}));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,79 +8,81 @@ const express = require("express");
|
|||||||
const bodyParser = require("body-parser");
|
const bodyParser = require("body-parser");
|
||||||
const compression = require("compression");
|
const compression = require("compression");
|
||||||
const zlib = require("zlib");
|
const zlib = require("zlib");
|
||||||
|
const cors = require("cors");
|
||||||
|
|
||||||
const SERVER_PORT: number = Number(process.env.SERVER_PORT) || 8190;
|
const SERVER_PORT: number = Number(process.env.SERVER_PORT) || 8190;
|
||||||
|
|
||||||
export default class HttpServer {
|
export default class HttpServer {
|
||||||
private readonly clientRequestHandler: RequestHandler;
|
private readonly clientRequestHandler: RequestHandler;
|
||||||
private readonly centerRequestHandler: RequestHandler;
|
private readonly centerRequestHandler: RequestHandler;
|
||||||
|
|
||||||
private app: any;
|
private app: any;
|
||||||
private server: any;
|
private server: any;
|
||||||
private readonly logger: Logger = new Logger(this.constructor.name);
|
private readonly logger: Logger = new Logger(this.constructor.name);
|
||||||
|
|
||||||
constructor(clientManager: SessionManager, centerManager: SessionManager) {
|
constructor(clientManager: SessionManager, centerManager: SessionManager) {
|
||||||
this.clientRequestHandler = new ClientRequestHandler(clientManager);
|
this.clientRequestHandler = new ClientRequestHandler(clientManager);
|
||||||
this.centerRequestHandler = new CenterRequestHandler(centerManager);
|
this.centerRequestHandler = new CenterRequestHandler(centerManager);
|
||||||
|
|
||||||
this.app = express();
|
this.app = express();
|
||||||
this.app.use(bodyParser.json());
|
this.app.use(cors());
|
||||||
|
this.app.use(bodyParser.json());
|
||||||
|
|
||||||
this.app.use(compression({
|
this.app.use(compression({
|
||||||
level: 9,
|
level: 9,
|
||||||
strategy: zlib.constants.BROTLI_MODE_TEXT,
|
strategy: zlib.constants.BROTLI_MODE_TEXT,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let clientApiPath: string = 'ClientEntity';
|
let clientApiPath: string = 'ClientEntity';
|
||||||
let centerApiPath: string = 'CenterEntity';
|
let centerApiPath: string = 'CenterEntity';
|
||||||
|
|
||||||
this.app.get(`/api/${clientApiPath}`, this.clientRequestHandler.doGet.bind(this.clientRequestHandler));
|
this.app.get(`/api/${clientApiPath}`, this.clientRequestHandler.doGet.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}`, this.clientRequestHandler.doPost.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}`, this.clientRequestHandler.doPost.bind(this.clientRequestHandler));
|
||||||
this.app.put(`/api/${clientApiPath}/:id/send`, this.clientRequestHandler.doConfigureSingleJob.bind(this.clientRequestHandler));
|
this.app.put(`/api/${clientApiPath}/:id/send`, this.clientRequestHandler.doConfigureSingleJob.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/send/default`, this.clientRequestHandler.doSendSingleJob.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/send/default`, this.clientRequestHandler.doSendSingleJob.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/send`, this.clientRequestHandler.doSend.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/send`, this.clientRequestHandler.doSend.bind(this.clientRequestHandler));
|
||||||
this.app.put(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doConfigureManyJob.bind(this.clientRequestHandler));
|
this.app.put(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doConfigureManyJob.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/sendMany/default`, this.clientRequestHandler.doSendManyJob.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/sendMany/default`, this.clientRequestHandler.doSendManyJob.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doSendMany.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doSendMany.bind(this.clientRequestHandler));
|
||||||
this.app.delete(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doCancelSendMany.bind(this.clientRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doCancelSendMany.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/bind`, this.clientRequestHandler.doBind.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/bind`, this.clientRequestHandler.doBind.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doConnect.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doConnect.bind(this.clientRequestHandler));
|
||||||
this.app.delete(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doDisconnect.bind(this.clientRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doDisconnect.bind(this.clientRequestHandler));
|
||||||
this.app.get(`/api/${clientApiPath}/processors`, this.clientRequestHandler.doGetAvailableProcessors.bind(this.clientRequestHandler));
|
this.app.get(`/api/${clientApiPath}/processors`, this.clientRequestHandler.doGetAvailableProcessors.bind(this.clientRequestHandler));
|
||||||
this.app.get(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doGetAppliedProcessors.bind(this.clientRequestHandler));
|
this.app.get(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doGetAppliedProcessors.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doAddProcessor.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doAddProcessor.bind(this.clientRequestHandler));
|
||||||
this.app.delete(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doRemoveProcessor.bind(this.clientRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doRemoveProcessor.bind(this.clientRequestHandler));
|
||||||
|
|
||||||
this.app.get(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doGetById.bind(this.clientRequestHandler));
|
this.app.get(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doGetById.bind(this.clientRequestHandler));
|
||||||
this.app.patch(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doPatch.bind(this.clientRequestHandler));
|
this.app.patch(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doPatch.bind(this.clientRequestHandler));
|
||||||
this.app.delete(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doDelete.bind(this.clientRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doDelete.bind(this.clientRequestHandler));
|
||||||
|
|
||||||
this.app.get(`/api/${centerApiPath}`, this.centerRequestHandler.doGet.bind(this.centerRequestHandler));
|
this.app.get(`/api/${centerApiPath}`, this.centerRequestHandler.doGet.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}`, this.centerRequestHandler.doPost.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}`, this.centerRequestHandler.doPost.bind(this.centerRequestHandler));
|
||||||
this.app.put(`/api/${centerApiPath}/:id/send`, this.centerRequestHandler.doConfigureSingleJob.bind(this.centerRequestHandler));
|
this.app.put(`/api/${centerApiPath}/:id/send`, this.centerRequestHandler.doConfigureSingleJob.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/send/default`, this.centerRequestHandler.doSendSingleJob.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/send/default`, this.centerRequestHandler.doSendSingleJob.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/send`, this.centerRequestHandler.doSend.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/send`, this.centerRequestHandler.doSend.bind(this.centerRequestHandler));
|
||||||
this.app.put(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doConfigureManyJob.bind(this.centerRequestHandler));
|
this.app.put(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doConfigureManyJob.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/sendMany/default`, this.centerRequestHandler.doSendManyJob.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/sendMany/default`, this.centerRequestHandler.doSendManyJob.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doSendMany.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doSendMany.bind(this.centerRequestHandler));
|
||||||
this.app.delete(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doCancelSendMany.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doCancelSendMany.bind(this.centerRequestHandler));
|
||||||
this.app.delete(`/api/${centerApiPath}/:id/connect`, this.centerRequestHandler.doDisconnect.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${centerApiPath}/:id/connect`, this.centerRequestHandler.doDisconnect.bind(this.centerRequestHandler));
|
||||||
this.app.get(`/api/${centerApiPath}/processors`, this.centerRequestHandler.doGetAvailableProcessors.bind(this.centerRequestHandler));
|
this.app.get(`/api/${centerApiPath}/processors`, this.centerRequestHandler.doGetAvailableProcessors.bind(this.centerRequestHandler));
|
||||||
this.app.get(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doGetAppliedProcessors.bind(this.centerRequestHandler));
|
this.app.get(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doGetAppliedProcessors.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doAddProcessor.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doAddProcessor.bind(this.centerRequestHandler));
|
||||||
this.app.delete(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doRemoveProcessor.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doRemoveProcessor.bind(this.centerRequestHandler));
|
||||||
|
|
||||||
this.app.get(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doGetById.bind(this.centerRequestHandler));
|
this.app.get(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doGetById.bind(this.centerRequestHandler));
|
||||||
this.app.patch(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doPatch.bind(this.centerRequestHandler));
|
this.app.patch(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doPatch.bind(this.centerRequestHandler));
|
||||||
this.app.delete(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doDelete.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doDelete.bind(this.centerRequestHandler));
|
||||||
|
|
||||||
this.app.get('/api/ping', function (req: any, res: any) {
|
this.app.get('/api/ping', function (req: any, res: any) {
|
||||||
res.send('pong');
|
res.send('pong');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.server = this.app.listen(SERVER_PORT, function () {
|
this.server = this.app.listen(SERVER_PORT, function () {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.logger.log1(`HTTPServer listening at http://localhost:${SERVER_PORT}`)
|
this.logger.log1(`HTTPServer listening at http://localhost:${SERVER_PORT}`)
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,156 +4,156 @@ import SessionManager from "../SessionManager";
|
|||||||
import SmppSession from "../SmppSession";
|
import SmppSession from "../SmppSession";
|
||||||
|
|
||||||
export default abstract class RequestHandler {
|
export default abstract class RequestHandler {
|
||||||
abstract sessionManager: SessionManager;
|
abstract sessionManager: SessionManager;
|
||||||
logger: Logger = new Logger(this.constructor.name);
|
logger: Logger = new Logger(this.constructor.name);
|
||||||
|
|
||||||
doGet(req: any, res: any): void {
|
doGet(req: any, res: any): void {
|
||||||
this.logger.log1(`Getting sessions`);
|
this.logger.log1(`Getting sessions`);
|
||||||
res.send(this.sessionManager.serialize());
|
res.send(this.sessionManager.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
doGetById(req: any, res: any): void {
|
doGetById(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Session found with ID ${req.params.id}`)
|
this.logger.log1(`Session found with ID ${req.params.id}`)
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doPatch(req: any, res: any): void {
|
doPatch(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Session found with ID ${req.params.id}`)
|
this.logger.log1(`Session found with ID ${req.params.id}`)
|
||||||
if (!!req.body.username && req.body.username !== session.username) {
|
if (!!req.body.username && req.body.username !== session.username) {
|
||||||
session.username = req.body.username;
|
session.username = req.body.username;
|
||||||
}
|
}
|
||||||
if (!!req.body.password && req.body.password !== session.password) {
|
if (!!req.body.password && req.body.password !== session.password) {
|
||||||
session.password = req.body.password;
|
session.password = req.body.password;
|
||||||
}
|
}
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doConfigureSingleJob(req: any, res: any): void {
|
doConfigureSingleJob(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(Number(req.params.id)).then((session: SmppSession) => {
|
this.sessionManager.getSession(Number(req.params.id)).then((session: SmppSession) => {
|
||||||
let job: Job = session.defaultSingleJob;
|
let job: Job = session.defaultSingleJob;
|
||||||
job.update(req);
|
job.update(req);
|
||||||
this.logger.log1(`Updating default job on session with ID ${req.params.id}`);
|
this.logger.log1(`Updating default job on session with ID ${req.params.id}`);
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doSendSingleJob(req: any, res: any): void {
|
doSendSingleJob(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Sending pre-configured message on session with ID ${req.params.id}`);
|
this.logger.log1(`Sending pre-configured message on session with ID ${req.params.id}`);
|
||||||
session.sendSingleDefault()
|
session.sendSingleDefault()
|
||||||
.then(pdu => res.send(pdu),
|
.then(pdu => res.send(pdu),
|
||||||
err => res.status(400).send({
|
err => res.status(400).send({
|
||||||
err: true,
|
err: true,
|
||||||
message: err
|
message: err
|
||||||
}));
|
}));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doSend(req: any, res: any): void {
|
doSend(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Sending message on session with ID ${req.params.id}`);
|
this.logger.log1(`Sending message on session with ID ${req.params.id}`);
|
||||||
let tempJob: Job = JSON.parse(JSON.stringify(session.defaultSingleJob));
|
let tempJob: Job = JSON.parse(JSON.stringify(session.defaultSingleJob));
|
||||||
tempJob.pdu.source_addr = req.body.source;
|
tempJob.pdu.source_addr = req.body.source;
|
||||||
tempJob.pdu.destination_addr = req.body.destination;
|
tempJob.pdu.destination_addr = req.body.destination;
|
||||||
tempJob.pdu.short_message = req.body.message;
|
tempJob.pdu.short_message = req.body.message;
|
||||||
session.sendSingle(tempJob)
|
session.sendSingle(tempJob)
|
||||||
.then(pdu => res.send(pdu),
|
.then(pdu => res.send(pdu),
|
||||||
err => res.status(400).send({
|
err => res.status(400).send({
|
||||||
err: true,
|
err: true,
|
||||||
message: err
|
message: err
|
||||||
}));
|
}));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doConfigureManyJob(req: any, res: any): void {
|
doConfigureManyJob(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
let job: Job = session.defaultMultipleJob;
|
let job: Job = session.defaultMultipleJob;
|
||||||
job.update(req);
|
job.update(req);
|
||||||
this.logger.log1(`Updating default job on session with ID ${req.params.id}`);
|
this.logger.log1(`Updating default job on session with ID ${req.params.id}`);
|
||||||
res.send(session.serialize());
|
res.send(session.serialize());
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doSendManyJob(req: any, res: any): void {
|
doSendManyJob(req: any, res: any): void {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Sending pre-configured messages on session with ID ${req.params.id}`);
|
this.logger.log1(`Sending pre-configured messages on session with ID ${req.params.id}`);
|
||||||
session.sendMultipleDefault()
|
session.sendMultipleDefault()
|
||||||
.then(() => res.send({}),
|
.then(() => res.send({}),
|
||||||
err => res.status(400).send({
|
err => res.status(400).send({
|
||||||
err: true,
|
err: true,
|
||||||
message: err
|
message: err
|
||||||
}));
|
}));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doSendMany(req: any, res: any) {
|
doSendMany(req: any, res: any) {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Sending message on session with ID ${req.params.id}`);
|
this.logger.log1(`Sending message on session with ID ${req.params.id}`);
|
||||||
let tempJob: Job = JSON.parse(JSON.stringify(session.defaultMultipleJob));
|
let tempJob: Job = JSON.parse(JSON.stringify(session.defaultMultipleJob));
|
||||||
tempJob.pdu.source_addr = req.body.source;
|
tempJob.pdu.source_addr = req.body.source;
|
||||||
tempJob.pdu.destination_addr = req.body.destination;
|
tempJob.pdu.destination_addr = req.body.destination;
|
||||||
tempJob.pdu.short_message = req.body.message;
|
tempJob.pdu.short_message = req.body.message;
|
||||||
tempJob.perSecond = 1 / (req.body.interval / 1000);
|
tempJob.perSecond = 1 / (req.body.interval / 1000);
|
||||||
tempJob.count = req.body.count;
|
tempJob.count = req.body.count;
|
||||||
session.sendMultiple(tempJob)
|
session.sendMultiple(tempJob)
|
||||||
.then(pdu => res.send(pdu),
|
.then(pdu => res.send(pdu),
|
||||||
err => res.status(400).send({
|
err => res.status(400).send({
|
||||||
err: true,
|
err: true,
|
||||||
message: err
|
message: err
|
||||||
}));
|
}));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doCancelSendMany(req: any, res: any) {
|
doCancelSendMany(req: any, res: any) {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Cancelling send timer for session with ID ${req.params.id}`);
|
this.logger.log1(`Cancelling send timer for session with ID ${req.params.id}`);
|
||||||
session.cancelSendInterval();
|
session.cancelSendInterval();
|
||||||
res.send({});
|
res.send({});
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doDisconnect(req: any, res: any) {
|
doDisconnect(req: any, res: any) {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Disconnecting session with ID ${req.params.id}`)
|
this.logger.log1(`Disconnecting session with ID ${req.params.id}`)
|
||||||
session.close().then(() => res.send(session.serialize()), err => res.status(400).send({
|
session.close().then(() => res.send(session.serialize()), err => res.status(400).send({
|
||||||
err: true,
|
err: true,
|
||||||
message: err
|
message: err
|
||||||
}));
|
}));
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
doDelete(req: any, res: any) {
|
doDelete(req: any, res: any) {
|
||||||
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
this.sessionManager.getSession(req.params.id).then((session: SmppSession) => {
|
||||||
this.logger.log1(`Deleting session with ID ${req.params.id}`);
|
this.logger.log1(`Deleting session with ID ${req.params.id}`);
|
||||||
this.sessionManager.removeSession(session);
|
this.sessionManager.removeSession(session);
|
||||||
res.send({});
|
res.send({});
|
||||||
}, this.handleSessionNotFound.bind(this, req, res));
|
}, this.handleSessionNotFound.bind(this, req, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract doPost(req: any, res: any): void;
|
abstract doPost(req: any, res: any): void;
|
||||||
|
|
||||||
abstract doConnect(req: any, res: any): void;
|
abstract doConnect(req: any, res: any): void;
|
||||||
|
|
||||||
abstract doBind(req: any, res: any): void;
|
abstract doBind(req: any, res: any): void;
|
||||||
|
|
||||||
abstract doGetAvailableProcessors(req: any, res: any): void;
|
abstract doGetAvailableProcessors(req: any, res: any): void;
|
||||||
|
|
||||||
abstract doGetAppliedProcessors(req: any, res: any): void;
|
abstract doGetAppliedProcessors(req: any, res: any): void;
|
||||||
|
|
||||||
abstract doAddProcessor(req: any, res: any): void;
|
abstract doAddProcessor(req: any, res: any): void;
|
||||||
|
|
||||||
abstract doRemoveProcessor(req: any, res: any): void;
|
abstract doRemoveProcessor(req: any, res: any): void;
|
||||||
|
|
||||||
handleSessionNotFound(req: any, res: any): void {
|
handleSessionNotFound(req: any, res: any): void {
|
||||||
let error = `No session found with ID ${req.params.id}`;
|
let error = `No session found with ID ${req.params.id}`;
|
||||||
this.logger.log1(error);
|
this.logger.log1(error);
|
||||||
res.status(404).send({
|
res.status(404).send({
|
||||||
err: true,
|
err: true,
|
||||||
message: error
|
message: error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
162
src/Job/Job.ts
162
src/Job/Job.ts
@@ -4,102 +4,102 @@ import {PDU, SerializedJob} from "../CommonObjects";
|
|||||||
const smpp = require("smpp");
|
const smpp = require("smpp");
|
||||||
|
|
||||||
export default class Job {
|
export default class Job {
|
||||||
static readonly STATE_CHANGED: string = "STATE_CHANGED";
|
static readonly STATE_CHANGED: string = "STATE_CHANGED";
|
||||||
private eventEmitter: EventEmitter = new EventEmitter();
|
private eventEmitter: EventEmitter = new EventEmitter();
|
||||||
|
|
||||||
constructor(pdu: PDU, perSecond?: number, count?: number) {
|
constructor(pdu: PDU, perSecond?: number, count?: number) {
|
||||||
Job.pduParseShortMessage(pdu);
|
Job.pduParseShortMessage(pdu);
|
||||||
this._pdu = pdu;
|
this._pdu = pdu;
|
||||||
this._perSecond = perSecond;
|
this._perSecond = perSecond;
|
||||||
this._count = count;
|
this._count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _pdu: PDU;
|
private _pdu: PDU;
|
||||||
|
|
||||||
get pdu(): PDU {
|
get pdu(): PDU {
|
||||||
return this._pdu;
|
return this._pdu;
|
||||||
}
|
}
|
||||||
|
|
||||||
set pdu(value: PDU) {
|
set pdu(value: PDU) {
|
||||||
this._pdu = value;
|
this._pdu = value;
|
||||||
this.eventEmitter.emit(Job.STATE_CHANGED, {});
|
this.eventEmitter.emit(Job.STATE_CHANGED, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _perSecond?: number;
|
private _perSecond?: number;
|
||||||
|
|
||||||
get perSecond(): number {
|
get perSecond(): number {
|
||||||
return <number>this._perSecond;
|
return <number>this._perSecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
set perSecond(value: number) {
|
set perSecond(value: number) {
|
||||||
this._perSecond = value;
|
this._perSecond = value;
|
||||||
this.eventEmitter.emit(Job.STATE_CHANGED, {});
|
this.eventEmitter.emit(Job.STATE_CHANGED, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _count?: number;
|
private _count?: number;
|
||||||
|
|
||||||
get count(): number {
|
get count(): number {
|
||||||
return <number>this._count;
|
return <number>this._count;
|
||||||
}
|
}
|
||||||
|
|
||||||
set count(value: number) {
|
set count(value: number) {
|
||||||
this._count = value;
|
this._count = value;
|
||||||
this.eventEmitter.emit(Job.STATE_CHANGED, {});
|
this.eventEmitter.emit(Job.STATE_CHANGED, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
static pduParseShortMessage(pdu: PDU) {
|
static pduParseShortMessage(pdu: PDU) {
|
||||||
if (pdu.short_message && pdu.short_message.type === "Buffer") {
|
if (pdu.short_message && pdu.short_message.type === "Buffer") {
|
||||||
pdu.short_message = Buffer.from(pdu.short_message.data, 'ascii').toString();
|
pdu.short_message = Buffer.from(pdu.short_message.data, 'ascii').toString();
|
||||||
}
|
}
|
||||||
if (typeof pdu.short_message === "object") {
|
if (typeof pdu.short_message === "object") {
|
||||||
pdu.short_message = pdu.short_message.toString();
|
pdu.short_message = pdu.short_message.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static createEmptySingle(command: string): Job {
|
static createEmptySingle(command: string): Job {
|
||||||
let pdu1 = new smpp.PDU(command, {});
|
let pdu1 = new smpp.PDU(command, {});
|
||||||
Job.pduParseShortMessage(pdu1);
|
Job.pduParseShortMessage(pdu1);
|
||||||
return new Job(pdu1);
|
return new Job(pdu1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createEmptyMultiple(command: string): Job {
|
static createEmptyMultiple(command: string): Job {
|
||||||
let pdu1 = new smpp.PDU(command, {});
|
let pdu1 = new smpp.PDU(command, {});
|
||||||
Job.pduParseShortMessage(pdu1);
|
Job.pduParseShortMessage(pdu1);
|
||||||
return new Job(pdu1, 1, 1);
|
return new Job(pdu1, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static deserialize(serialized: SerializedJob): Job {
|
static deserialize(serialized: SerializedJob): Job {
|
||||||
let pdu: PDU = new smpp.PDU(serialized.pdu.command, serialized.pdu);
|
let pdu: PDU = new smpp.PDU(serialized.pdu.command, serialized.pdu);
|
||||||
return new Job(pdu, serialized.perSecond, serialized.count);
|
return new Job(pdu, serialized.perSecond, serialized.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(req: any): void {
|
update(req: any): void {
|
||||||
if (req.body.source != this._pdu.source_addr) {
|
if (req.body.source != this._pdu.source_addr) {
|
||||||
this._pdu.source_addr = req.body.source;
|
this._pdu.source_addr = req.body.source;
|
||||||
}
|
}
|
||||||
if (req.body.destination != this._pdu.destination_addr) {
|
if (req.body.destination != this._pdu.destination_addr) {
|
||||||
this._pdu.destination_addr = req.body.destination;
|
this._pdu.destination_addr = req.body.destination;
|
||||||
}
|
}
|
||||||
if (req.body.message != this._pdu.short_message) {
|
if (req.body.message != this._pdu.short_message) {
|
||||||
this._pdu.short_message = req.body.message;
|
this._pdu.short_message = req.body.message;
|
||||||
}
|
}
|
||||||
if (!!this._perSecond && !!req.body.perSecond && req.body.perSecond != this._perSecond) {
|
if (!!this._perSecond && !!req.body.perSecond && req.body.perSecond != this._perSecond) {
|
||||||
this._perSecond = req.body.perSecond;
|
this._perSecond = req.body.perSecond;
|
||||||
}
|
}
|
||||||
if (!!this._count && !!req.body.count && req.body.count != this._count) {
|
if (!!this._count && !!req.body.count && req.body.count != this._count) {
|
||||||
this._count = req.body.count;
|
this._count = req.body.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): SerializedJob {
|
serialize(): SerializedJob {
|
||||||
return {
|
return {
|
||||||
pdu: this.pdu,
|
pdu: this.pdu,
|
||||||
perSecond: this.perSecond,
|
perSecond: this.perSecond,
|
||||||
count: this.count
|
count: this.count
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
on(event: string, callback: (...args: any[]) => void): void {
|
on(event: string, callback: (...args: any[]) => void): void {
|
||||||
this.eventEmitter.on(event, callback);
|
this.eventEmitter.on(event, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
102
src/Logger.ts
102
src/Logger.ts
@@ -6,63 +6,63 @@ const LOG_LEVEL: number = Number(process.env.LOG_LEVEL) || 0;
|
|||||||
const LOG_FILE: string = process.env.LOG_FILE || "";
|
const LOG_FILE: string = process.env.LOG_FILE || "";
|
||||||
|
|
||||||
export default class Logger {
|
export default class Logger {
|
||||||
log1 = this.log.bind(this, 1);
|
log1 = this.log.bind(this, 1);
|
||||||
log2 = this.log.bind(this, 2);
|
log2 = this.log.bind(this, 2);
|
||||||
log3 = this.log.bind(this, 3);
|
log3 = this.log.bind(this, 3);
|
||||||
log4 = this.log.bind(this, 4);
|
log4 = this.log.bind(this, 4);
|
||||||
log5 = this.log.bind(this, 5);
|
log5 = this.log.bind(this, 5);
|
||||||
log6 = this.log.bind(this, 6);
|
log6 = this.log.bind(this, 6);
|
||||||
private clazz: string;
|
private clazz: string;
|
||||||
private readonly logLevel: number;
|
private readonly logLevel: number;
|
||||||
private readonly logFile: string;
|
private readonly logFile: string;
|
||||||
private readonly logFileWriteStream: WriteStream | null = null;
|
private readonly logFileWriteStream: WriteStream | null = null;
|
||||||
|
|
||||||
constructor(clazz: string) {
|
constructor(clazz: string) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
this.logLevel = LOG_LEVEL;
|
this.logLevel = LOG_LEVEL;
|
||||||
this.logFile = LOG_FILE;
|
this.logFile = LOG_FILE;
|
||||||
|
|
||||||
if (!!this.logFile) {
|
if (!!this.logFile) {
|
||||||
this.logFileWriteStream = fs.createWriteStream(this.logFile, {flags: 'a'});
|
this.logFileWriteStream = fs.createWriteStream(this.logFile, {flags: 'a'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leftPad(str: string, len: number, char: string): string {
|
leftPad(str: string, len: number, char: string): string {
|
||||||
str = String(str);
|
str = String(str);
|
||||||
let i: number = -1;
|
let i: number = -1;
|
||||||
len = len - str.length;
|
len = len - str.length;
|
||||||
if (char === undefined) {
|
if (char === undefined) {
|
||||||
char = " ";
|
char = " ";
|
||||||
}
|
}
|
||||||
while (++i < len) {
|
while (++i < len) {
|
||||||
str = char + str;
|
str = char + str;
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
log(logLevel: number, data: any): void {
|
log(logLevel: number, data: any): void {
|
||||||
if (typeof data === "object") {
|
if (typeof data === "object") {
|
||||||
data = JSON.stringify(data);
|
data = JSON.stringify(data);
|
||||||
}
|
}
|
||||||
let date = new Date();
|
let date = new Date();
|
||||||
|
|
||||||
let year: string = this.leftPad(String(date.getFullYear()), 4, '0');
|
let year: string = this.leftPad(String(date.getFullYear()), 4, '0');
|
||||||
let month: string = this.leftPad(String(date.getMonth() + 1), 2, '0');
|
let month: string = this.leftPad(String(date.getMonth() + 1), 2, '0');
|
||||||
let day: string = this.leftPad(String(date.getDate()), 2, '0');
|
let day: string = this.leftPad(String(date.getDate()), 2, '0');
|
||||||
|
|
||||||
let hours: string = this.leftPad(String(date.getHours()), 2, '0');
|
let hours: string = this.leftPad(String(date.getHours()), 2, '0');
|
||||||
let minutes: string = this.leftPad(String(date.getMinutes()), 2, '0');
|
let minutes: string = this.leftPad(String(date.getMinutes()), 2, '0');
|
||||||
let seconds: string = this.leftPad(String(date.getSeconds()), 2, '0');
|
let seconds: string = this.leftPad(String(date.getSeconds()), 2, '0');
|
||||||
let milliseconds: string = this.leftPad(String(date.getMilliseconds()), 3, '0');
|
let milliseconds: string = this.leftPad(String(date.getMilliseconds()), 3, '0');
|
||||||
|
|
||||||
let datePrefix: string = `[${day}/${month}/${year}-${hours}:${minutes}:${seconds}:${milliseconds}]`
|
let datePrefix: string = `[${day}/${month}/${year}-${hours}:${minutes}:${seconds}:${milliseconds}]`
|
||||||
|
|
||||||
let out: string = datePrefix.padEnd(30, ' ') + `[${this.clazz}]`.padEnd(28, ' ') + `(${logLevel})`.padEnd(8, ' ') + data;
|
let out: string = datePrefix.padEnd(30, ' ') + `[${this.clazz}]`.padEnd(28, ' ') + `(${logLevel})`.padEnd(8, ' ') + data;
|
||||||
if (logLevel <= this.logLevel) {
|
if (logLevel <= this.logLevel) {
|
||||||
console.log(out);
|
console.log(out);
|
||||||
}
|
}
|
||||||
if (!!this.logFileWriteStream) {
|
if (!!this.logFileWriteStream) {
|
||||||
this.logFileWriteStream.write(out + "\n");
|
this.logFileWriteStream.write(out + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,17 +1,17 @@
|
|||||||
import {PDU} from "./CommonObjects";
|
import {PDU} from "./CommonObjects";
|
||||||
|
|
||||||
export default class MessageIdManager {
|
export default class MessageIdManager {
|
||||||
private static messages: { [key: string]: number } = {};
|
private static messages: { [key: string]: number } = {};
|
||||||
|
|
||||||
static addMessageId(message: PDU, id: number): void {
|
static addMessageId(message: PDU, id: number): void {
|
||||||
this.messages[this.getMessageHash(message)] = id;
|
this.messages[this.getMessageHash(message)] = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getMessageId(message: PDU): number | undefined {
|
static getMessageId(message: PDU): number | undefined {
|
||||||
return this.messages[this.getMessageHash(message)];
|
return this.messages[this.getMessageHash(message)];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getMessageHash(message: PDU): string {
|
private static getMessageHash(message: PDU): string {
|
||||||
return btoa(`${message.source_addr}:${message.destination_addr}:${message.short_message}`);
|
return btoa(`${message.source_addr}:${message.destination_addr}:${message.short_message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -2,36 +2,36 @@ import Logger from "../Logger";
|
|||||||
import SmppSession from "../SmppSession";
|
import SmppSession from "../SmppSession";
|
||||||
|
|
||||||
export default abstract class PduProcessor {
|
export default abstract class PduProcessor {
|
||||||
readonly abstract type: string
|
readonly abstract type: string
|
||||||
readonly sessionType: string;
|
readonly sessionType: string;
|
||||||
readonly name: string = this.constructor.name;
|
readonly name: string = this.constructor.name;
|
||||||
readonly logger: Logger = new Logger(`PduProcessor: ${this.name}`);
|
readonly logger: Logger = new Logger(`PduProcessor: ${this.name}`);
|
||||||
abstract applicableCommands: string[];
|
abstract applicableCommands: string[];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
this.sessionType = type;
|
this.sessionType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected pduDoesApply(pdu: any): boolean {
|
processPdu(session: any, pdu: any, entity?: SmppSession | undefined): any {
|
||||||
if (pdu.command) {
|
if (this.pduDoesApply(pdu)) {
|
||||||
return this.applicableCommands.includes(pdu.command);
|
return this.doProcess(session, pdu, entity);
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract doProcess(session: any, pdu: any, entity?: SmppSession | undefined): any;
|
serialize(): object {
|
||||||
|
return {
|
||||||
|
servesSessionType: this.sessionType,
|
||||||
|
name: this.name,
|
||||||
|
type: this.type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
processPdu(session: any, pdu: any, entity?: SmppSession | undefined): any {
|
protected pduDoesApply(pdu: any): boolean {
|
||||||
if (this.pduDoesApply(pdu)) {
|
if (pdu.command) {
|
||||||
return this.doProcess(session, pdu, entity);
|
return this.applicableCommands.includes(pdu.command);
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
serialize(): object {
|
protected abstract doProcess(session: any, pdu: any, entity?: SmppSession | undefined): any;
|
||||||
return {
|
|
||||||
servesSessionType: this.sessionType,
|
|
||||||
name: this.name,
|
|
||||||
type: this.type
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -4,42 +4,42 @@ import Postprocessor from "../Postprocessor";
|
|||||||
const smpp = require("smpp");
|
const smpp = require("smpp");
|
||||||
|
|
||||||
export default class BindTranscieverReplyProcessor extends Postprocessor {
|
export default class BindTranscieverReplyProcessor extends Postprocessor {
|
||||||
applicableCommands: string[] = ['bind_transceiver'];
|
applicableCommands: string[] = ['bind_transceiver'];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
doProcess(session: any, pdu: any, entity?: Center | undefined): Promise<any> {
|
doProcess(session: any, pdu: any, entity?: Center | undefined): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.log1(`Center-${entity?.id} got a bind_transceiver with system_id ${pdu.system_id} and password ${pdu.password}`);
|
this.logger.log1(`Center-${entity?.id} got a bind_transceiver with system_id ${pdu.system_id} and password ${pdu.password}`);
|
||||||
session.pause();
|
session.pause();
|
||||||
if (pdu.system_id === entity?.username && pdu.password === entity?.password) {
|
if (pdu.system_id === entity?.username && pdu.password === entity?.password) {
|
||||||
this.logger.log1(`Center-${entity?.id} client connection successful`);
|
this.logger.log1(`Center-${entity?.id} client connection successful`);
|
||||||
if (pdu.response) {
|
if (pdu.response) {
|
||||||
entity?.doSendPdu(pdu.response(), session);
|
entity?.doSendPdu(pdu.response(), session);
|
||||||
}
|
}
|
||||||
session.resume();
|
session.resume();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
entity?.pendingSessions = entity?.pendingSessions.filter((s) => s !== session);
|
entity.pendingSessions = entity?.pendingSessions.filter((s) => s !== session);
|
||||||
entity?.sessions.push(session);
|
entity?.sessions.push(session);
|
||||||
entity?.updateStatus();
|
entity?.updateStatus();
|
||||||
} else {
|
} else {
|
||||||
this.logger.log1(`Center-${entity?.id} client connection failed, invalid credentials (expected: ${entity?.username}, ${entity?.password})`);
|
this.logger.log1(`Center-${entity?.id} client connection failed, invalid credentials (expected: ${entity?.username}, ${entity?.password})`);
|
||||||
if (pdu.response) {
|
if (pdu.response) {
|
||||||
entity?.doSendPdu(pdu.response({
|
entity?.doSendPdu(pdu.response({
|
||||||
command_status: smpp.ESME_RBINDFAIL
|
command_status: smpp.ESME_RBINDFAIL
|
||||||
}), session);
|
}), session);
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
entity?.pendingSessions = entity?.pendingSessions.filter((s) => s !== session);
|
entity.pendingSessions = entity?.pendingSessions.filter((s) => s !== session);
|
||||||
entity?.updateStatus();
|
entity?.updateStatus();
|
||||||
session.close();
|
session.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,38 +6,44 @@ const smpp = require("smpp");
|
|||||||
|
|
||||||
export default class DeliveryReceiptProcessor extends Postprocessor {
|
export default class DeliveryReceiptProcessor extends Postprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm'];
|
applicableCommands: string[] = ['submit_sm'];
|
||||||
constructor(type: string) {
|
|
||||||
super(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
constructor(type: string) {
|
||||||
return new Promise<any>((resolve, reject) => {
|
super(type);
|
||||||
if (pdu.registered_delivery) {
|
}
|
||||||
let drMessage: string = "";
|
|
||||||
let date: string = new Date().toISOString().replace(/T/, '').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').substring(2, 12);
|
|
||||||
|
|
||||||
let relatedMessageId: number | undefined = MessageIdManager.getMessageId(pdu);
|
sleep(ms: number) {
|
||||||
if (relatedMessageId) {
|
return new Promise((resolve) => {
|
||||||
drMessage += "id:" + relatedMessageId + " ";
|
setTimeout(resolve, ms);
|
||||||
drMessage += "sub:001 ";
|
});
|
||||||
drMessage += "dlvrd:001 ";
|
}
|
||||||
drMessage += "submit date:" + date + " ";
|
|
||||||
drMessage += "done date:" + date + " ";
|
|
||||||
drMessage += "stat:DELIVRD ";
|
|
||||||
drMessage += "err:000 ";
|
|
||||||
drMessage += "text:";
|
|
||||||
|
|
||||||
let DRPdu = new smpp.PDU('deliver_sm', {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
source_addr: pdu.source_addr,
|
return new Promise<any>((resolve, reject) => {
|
||||||
destination_addr: pdu.destination_addr,
|
let drMessage: string = "";
|
||||||
short_message: drMessage,
|
let date: string = new Date().toISOString().replace(/T/, '').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').substring(2, 12);
|
||||||
esm_class: 4,
|
|
||||||
});
|
|
||||||
entity?.doSendPdu(DRPdu, session);
|
|
||||||
|
|
||||||
resolve(pdu);
|
let relatedMessageId: number | undefined = MessageIdManager.getMessageId(pdu);
|
||||||
}
|
if (relatedMessageId) {
|
||||||
}
|
drMessage += "id:" + relatedMessageId + " ";
|
||||||
});
|
drMessage += "sub:001 ";
|
||||||
}
|
drMessage += "dlvrd:001 ";
|
||||||
|
drMessage += "submit date:" + date + " ";
|
||||||
|
drMessage += "done date:" + date + " ";
|
||||||
|
drMessage += "stat:DELIVRD ";
|
||||||
|
drMessage += "err:000 ";
|
||||||
|
drMessage += "text:";
|
||||||
|
|
||||||
|
let sleepTime = 0;
|
||||||
|
let DRPdu = new smpp.PDU('deliver_sm', {
|
||||||
|
source_addr: pdu.source_addr,
|
||||||
|
destination_addr: pdu.destination_addr,
|
||||||
|
short_message: drMessage,
|
||||||
|
esm_class: 4,
|
||||||
|
});
|
||||||
|
setTimeout(() => entity?.doSendPdu(DRPdu, session), sleepTime);
|
||||||
|
|
||||||
|
resolve(pdu);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,20 +5,21 @@ const smpp = require("smpp");
|
|||||||
|
|
||||||
export default class EchoPduProcessor extends Postprocessor {
|
export default class EchoPduProcessor extends Postprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm'];
|
applicableCommands: string[] = ['submit_sm'];
|
||||||
constructor(type: string) {
|
|
||||||
super(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
constructor(type: string) {
|
||||||
return new Promise<any>((resolve, reject) => {
|
super(type);
|
||||||
// Temporary (?) safeguard against echoing long sms
|
}
|
||||||
if (!pdu.short_message.udh) {
|
|
||||||
let echoPdu = new smpp.PDU('deliver_sm', {...pdu});
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
echoPdu.source_addr = pdu.destination_addr;
|
return new Promise<any>((resolve, reject) => {
|
||||||
echoPdu.destination_addr = pdu.source_addr;
|
// Temporary (?) safeguard against echoing long sms
|
||||||
entity?.doSendPdu(echoPdu, session);
|
if (!pdu.short_message.udh) {
|
||||||
resolve(echoPdu);
|
let echoPdu = new smpp.PDU('deliver_sm', {...pdu});
|
||||||
}
|
echoPdu.source_addr = pdu.destination_addr;
|
||||||
});
|
echoPdu.destination_addr = pdu.source_addr;
|
||||||
}
|
entity?.doSendPdu(echoPdu, session);
|
||||||
|
resolve(echoPdu);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,16 @@ import SmppSession from "../../../SmppSession";
|
|||||||
import Postprocessor from "../Postprocessor";
|
import Postprocessor from "../Postprocessor";
|
||||||
|
|
||||||
export default class EnquireLinkReplyProcessor extends Postprocessor {
|
export default class EnquireLinkReplyProcessor extends Postprocessor {
|
||||||
applicableCommands: string[] = ['enquire_link'];
|
applicableCommands: string[] = ['enquire_link'];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
entity?.doSendPdu(pdu.response(), session);
|
entity?.doSendPdu(pdu.response(), session);
|
||||||
resolve(pdu);
|
resolve(pdu);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,20 +3,20 @@ import SmppSession from "../../../SmppSession";
|
|||||||
import Postprocessor from "../Postprocessor";
|
import Postprocessor from "../Postprocessor";
|
||||||
|
|
||||||
export default class SubmitSmReplyProcessor extends Postprocessor {
|
export default class SubmitSmReplyProcessor extends Postprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm'];
|
applicableCommands: string[] = ['submit_sm'];
|
||||||
private messageIdIterator: number = 0;
|
private messageIdIterator: number = 0;
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let response = pdu.response();
|
let response = pdu.response();
|
||||||
response.message_id = this.messageIdIterator++;
|
response.message_id = this.messageIdIterator++;
|
||||||
MessageIdManager.addMessageId(pdu, response.message_id);
|
MessageIdManager.addMessageId(pdu, response.message_id);
|
||||||
entity?.doSendPdu(response, session);
|
entity?.doSendPdu(response, session);
|
||||||
resolve(pdu);
|
resolve(pdu);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,16 @@ import SmppSession from "../../../SmppSession";
|
|||||||
import Postprocessor from "../Postprocessor";
|
import Postprocessor from "../Postprocessor";
|
||||||
|
|
||||||
export default class DeliverSmReplyProcessor extends Postprocessor {
|
export default class DeliverSmReplyProcessor extends Postprocessor {
|
||||||
applicableCommands: string[] = ['deliver_sm'];
|
applicableCommands: string[] = ['deliver_sm'];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
entity?.doSendPdu(pdu.response(), session);
|
entity?.doSendPdu(pdu.response(), session);
|
||||||
resolve(pdu);
|
resolve(pdu);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import PduProcessor from "../PduProcessor";
|
import PduProcessor from "../PduProcessor";
|
||||||
|
|
||||||
export default abstract class Postprocessor extends PduProcessor {
|
export default abstract class Postprocessor extends PduProcessor {
|
||||||
readonly type: string = Postprocessor.name;
|
readonly type: string = Postprocessor.name;
|
||||||
}
|
}
|
@@ -2,15 +2,15 @@ import SmppSession from "../../../SmppSession";
|
|||||||
import Preprocessor from "../Preprocessor";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class DeliveryReceiptRequestProcessor extends Preprocessor {
|
export default class DeliveryReceiptRequestProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm'];
|
applicableCommands: string[] = ['submit_sm'];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
pdu.registered_delivery = 1;
|
pdu.registered_delivery = 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,21 +3,21 @@ import Preprocessor from "../Preprocessor";
|
|||||||
|
|
||||||
export default class DestinationEnumeratorProcessor extends Preprocessor {
|
export default class DestinationEnumeratorProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
private iterator: number = 0;
|
private iterator: number = 0;
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
if (!!pdu.destination_addr) {
|
if (!!pdu.destination_addr) {
|
||||||
pdu.destination_addr = pdu.destination_addr + this.padLeft(String(this.iterator++), '0', 5);
|
pdu.destination_addr = pdu.destination_addr + this.padLeft(String(this.iterator++), '0', 5);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private padLeft(str: string, pad: string, length: number): string {
|
private padLeft(str: string, pad: string, length: number): string {
|
||||||
return (new Array(length + 1).join(pad) + str).slice(-length);
|
return (new Array(length + 1).join(pad) + str).slice(-length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
import {PDU} from "../../../CommonObjects";
|
||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class DestinationSetPreprocessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
private sourceSet: string[] = [];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
while (this.sourceSet.length < 100) {
|
||||||
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: PDU, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
if (pdu.short_message) {
|
||||||
|
if (pdu.short_message.includes("arg:")) {
|
||||||
|
let temp: string = pdu.short_message.split(";");
|
||||||
|
let arg: number = Number(temp[0].split(":")[1]);
|
||||||
|
while (this.sourceSet.length < arg) {
|
||||||
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
|
}
|
||||||
|
while (this.sourceSet.length > arg) {
|
||||||
|
this.sourceSet.pop();
|
||||||
|
}
|
||||||
|
pdu.short_message = temp[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pdu.destination_addr = pdu.destination_addr + this.sourceSet[this.getRandomInt(0, this.sourceSet.length)];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRandomInt(min: number, max: number): number {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(Math.random() * (max - min) + min);
|
||||||
|
}
|
||||||
|
}
|
17
src/PDUProcessor/Preprocessor/Client/GSM0338Preprocessor.ts
Normal file
17
src/PDUProcessor/Preprocessor/Client/GSM0338Preprocessor.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import {PDU} from "../../../CommonObjects";
|
||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class GSM0338Preprocessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: PDU, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
pdu.data_coding = 0xf6;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -5,83 +5,83 @@ import Preprocessor from "../Preprocessor";
|
|||||||
const smpp = require('smpp');
|
const smpp = require('smpp');
|
||||||
|
|
||||||
export default class LongSmsProcessor extends Preprocessor {
|
export default class LongSmsProcessor extends Preprocessor {
|
||||||
|
static readonly maxMessageSizeBits = 1072;
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
static readonly maxMessageSizeBits = 1072;
|
private iterator: number = 0;
|
||||||
private iterator: number = 0;
|
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
// An sms can have a maximum length (short_message) of 1120 bits or 140 bytes.
|
// An sms can have a maximum length (short_message) of 1120 bits or 140 bytes.
|
||||||
// For a message encoded in UCS-2, the maximum length is 70 characters. (2 bytes per character)
|
// For a message encoded in UCS-2, the maximum length is 70 characters. (2 bytes per character)
|
||||||
// For a message encoded in GSM-7, the maximum length is 160 characters. (7 bits per character)
|
// For a message encoded in GSM-7, the maximum length is 160 characters. (7 bits per character)
|
||||||
// Once a message is split the part information is placed into udh
|
// Once a message is split the part information is placed into udh
|
||||||
// Like
|
// Like
|
||||||
// destination_addr: config.destinationAddress,
|
// destination_addr: config.destinationAddress,
|
||||||
// short_message: {
|
// short_message: {
|
||||||
// udh: Buffer.from([0x05, 0x00, 0x03, 0x05, 0x02, 0x01]),
|
// udh: Buffer.from([0x05, 0x00, 0x03, 0x05, 0x02, 0x01]),
|
||||||
// message: "Hello World!"
|
// message: "Hello World!"
|
||||||
// }
|
// }
|
||||||
// The UDH parameters are as follows:
|
// The UDH parameters are as follows:
|
||||||
// 0x05: Length of UDH (5 bytes to follow)
|
// 0x05: Length of UDH (5 bytes to follow)
|
||||||
// 0x00: Concatenated message Information Element (8-bit reference number)
|
// 0x00: Concatenated message Information Element (8-bit reference number)
|
||||||
// 0x03: Length of Information Element data (3 bytes to follow)
|
// 0x03: Length of Information Element data (3 bytes to follow)
|
||||||
// 0xXX: Reference number for this concatenated message
|
// 0xXX: Reference number for this concatenated message
|
||||||
// 0xYY: Number of fragments in the concatenated message
|
// 0xYY: Number of fragments in the concatenated message
|
||||||
// 0xZZ: Fragment number/index within the concatenated message 1072
|
// 0xZZ: Fragment number/index within the concatenated message 1072
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getCharacterSizeForEncoding(pdu: PDU) {
|
static getCharacterSizeForEncoding(pdu: PDU) {
|
||||||
let encoding: number | undefined = pdu.data_coding;
|
let encoding: number | undefined = pdu.data_coding;
|
||||||
if (!encoding) {
|
if (!encoding) {
|
||||||
encoding = 0;
|
encoding = 0;
|
||||||
}
|
}
|
||||||
let characterSizeBits: number = 0;
|
let characterSizeBits: number = 0;
|
||||||
switch (encoding) {
|
switch (encoding) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
characterSizeBits = 8;
|
characterSizeBits = 8;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
characterSizeBits = 16;
|
characterSizeBits = 16;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return characterSizeBits;
|
return characterSizeBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: PDU, entity?: SmppSession | undefined): Promise<any> {
|
protected doProcess(session: any, pdu: PDU, entity?: SmppSession | undefined): Promise<any> {
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
if (!!pdu.short_message) {
|
if (!!pdu.short_message) {
|
||||||
let characterSizeBits: number = LongSmsProcessor.getCharacterSizeForEncoding(pdu);
|
let characterSizeBits: number = LongSmsProcessor.getCharacterSizeForEncoding(pdu);
|
||||||
let maxMessageLength: number = LongSmsProcessor.maxMessageSizeBits / characterSizeBits;
|
let maxMessageLength: number = LongSmsProcessor.maxMessageSizeBits / characterSizeBits;
|
||||||
if (characterSizeBits) {
|
if (characterSizeBits) {
|
||||||
let splitMessage: string[] = [];
|
let splitMessage: string[] = [];
|
||||||
let message: string = pdu.short_message;
|
let message: string = pdu.short_message;
|
||||||
let messageLength: number = message.length;
|
let messageLength: number = message.length;
|
||||||
let messageCount: number = Math.ceil(messageLength / maxMessageLength);
|
let messageCount: number = Math.ceil(messageLength / maxMessageLength);
|
||||||
for (let i = 0; i < messageCount; i++) {
|
for (let i = 0; i < messageCount; i++) {
|
||||||
splitMessage.push(message.substr(i * maxMessageLength, maxMessageLength));
|
splitMessage.push(message.substr(i * maxMessageLength, maxMessageLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
splitMessage.forEach((messagePart: string, index: number) => {
|
splitMessage.forEach((messagePart: string, index: number) => {
|
||||||
let udh: Buffer = Buffer.from([0x05, 0x00, 0x03, this.iterator++, messageCount, index + 1]);
|
let udh: Buffer = Buffer.from([0x05, 0x00, 0x03, this.iterator++, messageCount, index + 1]);
|
||||||
|
|
||||||
if (index < (messageCount - 1)) {
|
if (index < (messageCount - 1)) {
|
||||||
let partPdu = new smpp.PDU(pdu.command, {...pdu});
|
let partPdu = new smpp.PDU(pdu.command, {...pdu});
|
||||||
partPdu.short_message = {
|
partPdu.short_message = {
|
||||||
udh: udh,
|
udh: udh,
|
||||||
message: messagePart
|
message: messagePart
|
||||||
}
|
}
|
||||||
entity?.doSendPdu(partPdu, session);
|
entity?.doSendPdu(partPdu, session);
|
||||||
} else {
|
} else {
|
||||||
pdu.short_message = {
|
pdu.short_message = {
|
||||||
udh: udh,
|
udh: udh,
|
||||||
message: messagePart
|
message: messagePart
|
||||||
}
|
}
|
||||||
resolve(pdu);
|
resolve(pdu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,16 @@
|
|||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class ProtocolId2DigitProcessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
pdu.protocol_id = 16;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class ProtocolId3DigitProcessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
pdu.protocol_id = 128;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,17 @@
|
|||||||
|
import {PDU} from "../../../CommonObjects";
|
||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class ProtocolId4DigitProcessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: PDU, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
pdu.data_coding = 2048;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
16
src/PDUProcessor/Preprocessor/Client/ProtocolIdProcessor.ts
Normal file
16
src/PDUProcessor/Preprocessor/Client/ProtocolIdProcessor.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class ProtocolIdProcessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
pdu.protocol_id = 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -2,22 +2,22 @@ import SmppSession from "../../../SmppSession";
|
|||||||
import Preprocessor from "../Preprocessor";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class SourceEnumeratorProcessor extends Preprocessor {
|
export default class SourceEnumeratorProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
private iterator: number = 0;
|
private iterator: number = 0;
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
if (!!pdu.source_addr) {
|
if (!!pdu.source_addr) {
|
||||||
pdu.source_addr = pdu.source_addr + this.padLeft(String(this.iterator++), '0', 5);
|
pdu.source_addr = pdu.source_addr + this.padLeft(String(this.iterator++), '0', 5);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private padLeft(str: string, pad: string, length: number): string {
|
private padLeft(str: string, pad: string, length: number): string {
|
||||||
return (new Array(length + 1).join(pad) + str).slice(-length);
|
return (new Array(length + 1).join(pad) + str).slice(-length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
import {PDU} from "../../../CommonObjects";
|
||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class SourceSetPreprocessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
private sourceSet: string[] = [];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
while (this.sourceSet.length < 100) {
|
||||||
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: PDU, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
if (pdu.short_message) {
|
||||||
|
if (pdu.short_message.includes("arg:")) {
|
||||||
|
let temp: string = pdu.short_message.split(";");
|
||||||
|
let arg: number = Number(temp[0].split(":")[1]);
|
||||||
|
while (this.sourceSet.length < arg) {
|
||||||
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
|
}
|
||||||
|
while (this.sourceSet.length > arg) {
|
||||||
|
this.sourceSet.pop();
|
||||||
|
}
|
||||||
|
pdu.short_message = temp[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pdu.source_addr = pdu.source_addr + this.sourceSet[this.getRandomInt(0, this.sourceSet.length)];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRandomInt(min: number, max: number): number {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(Math.random() * (max - min) + min);
|
||||||
|
}
|
||||||
|
}
|
17
src/PDUProcessor/Preprocessor/Client/UCS2Preprocessor.ts
Normal file
17
src/PDUProcessor/Preprocessor/Client/UCS2Preprocessor.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import {PDU} from "../../../CommonObjects";
|
||||||
|
import SmppSession from "../../../SmppSession";
|
||||||
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
|
export default class UCS2Preprocessor extends Preprocessor {
|
||||||
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
|
constructor(type: string) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doProcess(session: any, pdu: PDU, entity?: SmppSession | undefined): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
pdu.data_coding = 8;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
import PduProcessor from "../PduProcessor";
|
import PduProcessor from "../PduProcessor";
|
||||||
|
|
||||||
export default abstract class Preprocessor extends PduProcessor {
|
export default abstract class Preprocessor extends PduProcessor {
|
||||||
readonly type: string = Preprocessor.name;
|
readonly type: string = Preprocessor.name;
|
||||||
}
|
}
|
@@ -12,98 +12,120 @@ import DeliverSmReplyProcessor from "./Postprocessor/Client/DeliverSmReplyProces
|
|||||||
import Postprocessor from "./Postprocessor/Postprocessor";
|
import Postprocessor from "./Postprocessor/Postprocessor";
|
||||||
import DeliveryReceiptRequestProcessor from "./Preprocessor/Client/DeliveryReceiptRequestProcessor";
|
import DeliveryReceiptRequestProcessor from "./Preprocessor/Client/DeliveryReceiptRequestProcessor";
|
||||||
import DestinationEnumeratorProcessor from "./Preprocessor/Client/DestinationEnumeratorProcessor";
|
import DestinationEnumeratorProcessor from "./Preprocessor/Client/DestinationEnumeratorProcessor";
|
||||||
|
import DestinationSetPreprocessor from "./Preprocessor/Client/DestinationSetPreprocessor";
|
||||||
|
import GSM0338Preprocessor from "./Preprocessor/Client/GSM0338Preprocessor";
|
||||||
import LongSmsProcessor from "./Preprocessor/Client/LongSmsProcessor";
|
import LongSmsProcessor from "./Preprocessor/Client/LongSmsProcessor";
|
||||||
|
import ProtocolId2DigitProcessor from "./Preprocessor/Client/ProtocolId-2Digit-Processor";
|
||||||
|
import ProtocolId3DigitProcessor from "./Preprocessor/Client/ProtocolId-3Digit-Processor";
|
||||||
|
import ProtocolIdProcessor from "./Preprocessor/Client/ProtocolIdProcessor";
|
||||||
import SourceEnumeratorProcessor from "./Preprocessor/Client/SourceEnumeratorProcessor";
|
import SourceEnumeratorProcessor from "./Preprocessor/Client/SourceEnumeratorProcessor";
|
||||||
|
import SourceSetPreprocessor from "./Preprocessor/Client/SourceSetPreprocessor";
|
||||||
|
import UCS2Preprocessor from "./Preprocessor/Client/UCS2Preprocessor";
|
||||||
import Preprocessor from "./Preprocessor/Preprocessor";
|
import Preprocessor from "./Preprocessor/Preprocessor";
|
||||||
|
|
||||||
export default class ProcessorManager {
|
export default class ProcessorManager {
|
||||||
static preprocessors: PduProcessor[];
|
static preprocessors: PduProcessor[];
|
||||||
static postprocessors: PduProcessor[];
|
static postprocessors: PduProcessor[];
|
||||||
private static readonly logger: Logger = new Logger(this.name);
|
private static readonly logger: Logger = new Logger(this.name);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// This is an IDIOTIC solution, but it works
|
// This is an IDIOTIC solution, but it works
|
||||||
// Try running eb22a43 to find out what's wrong with the previous approach
|
// Try running eb22a43 to find out what's wrong with the previous approach
|
||||||
ProcessorManager.postprocessors = [
|
ProcessorManager.postprocessors = [
|
||||||
new EnquireLinkReplyProcessor(Center.name),
|
new EnquireLinkReplyProcessor(Center.name),
|
||||||
new DeliverSmReplyProcessor(Client.name),
|
new DeliverSmReplyProcessor(Client.name),
|
||||||
new SubmitSmReplyProcessor(Center.name),
|
new SubmitSmReplyProcessor(Center.name),
|
||||||
new BindTranscieverReplyProcessor(Center.name),
|
new BindTranscieverReplyProcessor(Center.name),
|
||||||
new EchoPduProcessor(Center.name),
|
new EchoPduProcessor(Center.name),
|
||||||
new DeliveryReceiptProcessor(Center.name)
|
new DeliveryReceiptProcessor(Center.name)
|
||||||
];
|
];
|
||||||
ProcessorManager.preprocessors = [
|
ProcessorManager.preprocessors = [
|
||||||
new DestinationEnumeratorProcessor(Client.name),
|
new DestinationEnumeratorProcessor(Client.name),
|
||||||
new SourceEnumeratorProcessor(Client.name),
|
new SourceEnumeratorProcessor(Client.name),
|
||||||
new DestinationEnumeratorProcessor(Center.name),
|
new DestinationEnumeratorProcessor(Center.name),
|
||||||
new SourceEnumeratorProcessor(Center.name),
|
new SourceEnumeratorProcessor(Center.name),
|
||||||
new DeliveryReceiptRequestProcessor(Client.name),
|
new DeliveryReceiptRequestProcessor(Client.name),
|
||||||
new LongSmsProcessor(Client.name)
|
new LongSmsProcessor(Client.name),
|
||||||
];
|
new LongSmsProcessor(Center.name),
|
||||||
}
|
new ProtocolIdProcessor(Client.name),
|
||||||
|
new ProtocolIdProcessor(Center.name),
|
||||||
|
new UCS2Preprocessor(Client.name),
|
||||||
|
new UCS2Preprocessor(Center.name),
|
||||||
|
new ProtocolId2DigitProcessor(Client.name),
|
||||||
|
new ProtocolId2DigitProcessor(Center.name),
|
||||||
|
new ProtocolId3DigitProcessor(Client.name),
|
||||||
|
new ProtocolId3DigitProcessor(Center.name),
|
||||||
|
new SourceSetPreprocessor(Client.name),
|
||||||
|
new SourceSetPreprocessor(Center.name),
|
||||||
|
new DestinationSetPreprocessor(Client.name),
|
||||||
|
new DestinationSetPreprocessor(Center.name),
|
||||||
|
new GSM0338Preprocessor(Client.name),
|
||||||
|
new GSM0338Preprocessor(Center.name)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
static get processors(): PduProcessor[] {
|
static get processors(): PduProcessor[] {
|
||||||
return this.preprocessors.concat(this.postprocessors);
|
return this.preprocessors.concat(this.postprocessors);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getProcessors(name: string): PduProcessor[] {
|
static getProcessors(name: string): PduProcessor[] {
|
||||||
this.logger.log1(`Looking for processor with name ${name}...`);
|
this.logger.log1(`Looking for processor with name ${name}...`);
|
||||||
let pduProcessors: PduProcessor[] = this.processors.filter((processor: PduProcessor) => processor.name === name);
|
let pduProcessors: PduProcessor[] = this.processors.filter((processor: PduProcessor) => processor.name === name);
|
||||||
this.logger.log1(`Found ${pduProcessors.length} processor(s) with name ${name}`);
|
this.logger.log1(`Found ${pduProcessors.length} processor(s) with name ${name}`);
|
||||||
return pduProcessors;
|
return pduProcessors;
|
||||||
}
|
}
|
||||||
|
|
||||||
static attachProcessors(session: SmppSession, processors: PduProcessor[]): void {
|
static attachProcessors(session: SmppSession, processors: PduProcessor[]): void {
|
||||||
this.logger.log1(`Trying to attach processor ${processors.toString()} to session ${session.constructor.name}-${session.id}`);
|
this.logger.log1(`Trying to attach processor ${processors.toString()} to session ${session.constructor.name}-${session.id}`);
|
||||||
for (const processor of processors) {
|
for (const processor of processors) {
|
||||||
if (this.areCompatible(session, processor)) {
|
if (this.areCompatible(session, processor)) {
|
||||||
// This could be done a little better but this is OK for now
|
// This could be done a little better but this is OK for now
|
||||||
switch (processor.type) {
|
switch (processor.type) {
|
||||||
case Preprocessor.name:
|
case Preprocessor.name:
|
||||||
session.attachPreprocessor(processor);
|
session.attachPreprocessor(processor);
|
||||||
break;
|
break;
|
||||||
case Postprocessor.name:
|
case Postprocessor.name:
|
||||||
session.attachPostprocessor(processor);
|
session.attachPostprocessor(processor);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.logger.log1(`Processor ${processor.name} is not a preprocessor or a postprocessor`);
|
this.logger.log1(`Processor ${processor.name} is not a preprocessor or a postprocessor`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static detachProcessors(session: SmppSession, processors: PduProcessor[]): void {
|
static detachProcessors(session: SmppSession, processors: PduProcessor[]): void {
|
||||||
this.logger.log1(`Trying to detach processors ${processors.toString()} from session ${session.constructor.name}-${session.id}`);
|
this.logger.log1(`Trying to detach processors ${processors.toString()} from session ${session.constructor.name}-${session.id}`);
|
||||||
for (const processor of processors) {
|
for (const processor of processors) {
|
||||||
switch (processor.type) {
|
switch (processor.type) {
|
||||||
case Preprocessor.name:
|
case Preprocessor.name:
|
||||||
session.detachPreprocessor(processor);
|
session.detachPreprocessor(processor);
|
||||||
break;
|
break;
|
||||||
case Postprocessor.name:
|
case Postprocessor.name:
|
||||||
session.detachPostprocessor(processor);
|
session.detachPostprocessor(processor);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.logger.log1(`Processor ${processor.name} is not a preprocessor or a postprocessor`);
|
this.logger.log1(`Processor ${processor.name} is not a preprocessor or a postprocessor`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static areCompatible(session: SmppSession, processor: PduProcessor): boolean {
|
static areCompatible(session: SmppSession, processor: PduProcessor): boolean {
|
||||||
this.logger.log1(`Checking compatibility between session ${session.constructor.name}-${session.id} and processor ${processor.name}`);
|
this.logger.log1(`Checking compatibility between session ${session.constructor.name}-${session.id} and processor ${processor.name}`);
|
||||||
return session.constructor.name === processor.sessionType;
|
return session.constructor.name === processor.sessionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getProcessorsForType(type: string): PduProcessor[] {
|
static getProcessorsForType(type: string): PduProcessor[] {
|
||||||
return this.processors.filter((processor: PduProcessor) => processor.sessionType === type);
|
return this.processors.filter((processor: PduProcessor) => processor.sessionType === type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getPreprocessorsForType(type: string): PduProcessor[] {
|
static getPreprocessorsForType(type: string): PduProcessor[] {
|
||||||
return this.preprocessors.filter((processor: PduProcessor) => processor.sessionType === type);
|
return this.preprocessors.filter((processor: PduProcessor) => processor.sessionType === type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getPostprocessorsForType(type: string): PduProcessor[] {
|
static getPostprocessorsForType(type: string): PduProcessor[] {
|
||||||
return this.postprocessors.filter((processor: PduProcessor) => processor.sessionType === type);
|
return this.postprocessors.filter((processor: PduProcessor) => processor.sessionType === type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,29 +1,29 @@
|
|||||||
export default class PersistentPromise {
|
export default class PersistentPromise {
|
||||||
private readonly promise: Promise<any>;
|
private readonly promise: Promise<any>;
|
||||||
private promiseResolve: ((value?: any) => void) | undefined;
|
private promiseResolve: ((value?: any) => void) | undefined;
|
||||||
private promiseReject: ((reason?: any) => void) | undefined;
|
private promiseReject: ((reason?: any) => void) | undefined;
|
||||||
|
|
||||||
constructor(callback: (resolve: (value?: any) => void, reject: (reason?: any) => void) => void) {
|
constructor(callback: (resolve: (value?: any) => void, reject: (reason?: any) => void) => void) {
|
||||||
this.promise = new Promise((resolve, reject) => {
|
this.promise = new Promise((resolve, reject) => {
|
||||||
this.promiseResolve = resolve;
|
this.promiseResolve = resolve;
|
||||||
this.promiseReject = reject;
|
this.promiseReject = reject;
|
||||||
callback(resolve, reject);
|
callback(resolve, reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(value?: any): void {
|
resolve(value?: any): void {
|
||||||
if (this.promiseResolve) {
|
if (this.promiseResolve) {
|
||||||
this.promiseResolve(value);
|
this.promiseResolve(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reject(reason?: any): void {
|
reject(reason?: any): void {
|
||||||
if (this.promiseReject) {
|
if (this.promiseReject) {
|
||||||
this.promiseReject(reason);
|
this.promiseReject(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
then(onfulfilled?: ((value: any) => any) | undefined | null, onrejected?: ((reason: any) => any) | undefined | null): Promise<any> {
|
then(onfulfilled?: ((value: any) => any) | undefined | null, onrejected?: ((reason: any) => any) | undefined | null): Promise<any> {
|
||||||
return this.promise.then(onfulfilled, onrejected);
|
return this.promise.then(onfulfilled, onrejected);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,138 +7,138 @@ import ProcessorManager from "./PDUProcessor/ProcessorManager";
|
|||||||
import SmppSession from "./SmppSession";
|
import SmppSession from "./SmppSession";
|
||||||
|
|
||||||
export default abstract class SessionManager {
|
export default abstract class SessionManager {
|
||||||
// I could've done this by passing these abstract properties to the constructor, but I wanted to have the possibility
|
// I could've done this by passing these abstract properties to the constructor, but I wanted to have the possibility
|
||||||
// of implementing additional methods
|
// of implementing additional methods
|
||||||
abstract comparatorFn: (arg: any, session: SmppSession) => boolean;
|
abstract comparatorFn: (arg: any, session: SmppSession) => boolean;
|
||||||
readonly abstract identifier: string;
|
readonly abstract identifier: string;
|
||||||
readonly abstract ManagedSessionClass: any;
|
readonly abstract ManagedSessionClass: any;
|
||||||
readonly abstract StorageFile: string;
|
readonly abstract StorageFile: string;
|
||||||
readonly SESSION_ADDED_EVENT: string = "SESSION ADDED";
|
readonly SESSION_ADDED_EVENT: string = "SESSION ADDED";
|
||||||
|
|
||||||
sessions: SmppSession[] = [];
|
sessions: SmppSession[] = [];
|
||||||
sessionId: number = 0;
|
sessionId: number = 0;
|
||||||
readonly logger: Logger = new Logger("SessionManager");
|
readonly logger: Logger = new Logger("SessionManager");
|
||||||
readonly eventEmitter: EventEmitter = new EventEmitter();
|
readonly eventEmitter: EventEmitter = new EventEmitter();
|
||||||
|
|
||||||
addSession(session: SmppSession): Promise<void> {
|
addSession(session: SmppSession): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
this.logger.log1(`Adding session with id ${session.id}`);
|
this.logger.log1(`Adding session with id ${session.id}`);
|
||||||
this.sessions.push(session);
|
this.sessions.push(session);
|
||||||
this.eventEmitter.emit(this.SESSION_ADDED_EVENT, session.id);
|
this.eventEmitter.emit(this.SESSION_ADDED_EVENT, session.id);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
on(event: string, listener: (...args: any[]) => void): void {
|
on(event: string, listener: (...args: any[]) => void): void {
|
||||||
this.eventEmitter.on(event, listener);
|
this.eventEmitter.on(event, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSessions(): Promise<SmppSession[]> {
|
getSessions(): Promise<SmppSession[]> {
|
||||||
return Promise.resolve(this.sessions);
|
return Promise.resolve(this.sessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSession(session: SmppSession): Promise<void> {
|
removeSession(session: SmppSession): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
this.logger.log1(`Removing session with id ${session.id}`);
|
this.logger.log1(`Removing session with id ${session.id}`);
|
||||||
session.close();
|
session.close();
|
||||||
session.destroy();
|
session.destroy();
|
||||||
this.sessions = this.sessions.filter(s => s.id !== session.id);
|
this.sessions = this.sessions.filter(s => s.id !== session.id);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getSession(id: number): Promise<SmppSession> {
|
getSession(id: number): Promise<SmppSession> {
|
||||||
return new Promise<SmppSession>((resolve, reject) => {
|
return new Promise<SmppSession>((resolve, reject) => {
|
||||||
this.logger.log1(`Looking for session with id ${id}...`);
|
this.logger.log1(`Looking for session with id ${id}...`);
|
||||||
let session: SmppSession | undefined = this.sessions.find(s => s.id == id);
|
let session: SmppSession | undefined = this.sessions.find(s => s.id == id);
|
||||||
if (session) {
|
if (session) {
|
||||||
this.logger.log1(`Found session with id ${id}`);
|
this.logger.log1(`Found session with id ${id}`);
|
||||||
resolve(session);
|
resolve(session);
|
||||||
} else {
|
} else {
|
||||||
this.logger.log1(`Session with id ${id} not found`);
|
this.logger.log1(`Session with id ${id} not found`);
|
||||||
reject(`Session with id ${id} not found`);
|
reject(`Session with id ${id} not found`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setup(): void {
|
setup(): void {
|
||||||
try {
|
try {
|
||||||
this.logger.log1(`Loading ${this.ManagedSessionClass.name} from ${this.StorageFile}`)
|
this.logger.log1(`Loading ${this.ManagedSessionClass.name} from ${this.StorageFile}`)
|
||||||
let sessions: Buffer = fs.readFileSync(this.StorageFile);
|
let sessions: Buffer = fs.readFileSync(this.StorageFile);
|
||||||
let loadedSessions: any[] = JSON.parse(String(sessions));
|
let loadedSessions: any[] = JSON.parse(String(sessions));
|
||||||
this.logger.log1(`Loaded ${loadedSessions.length} clients from ${this.StorageFile}`);
|
this.logger.log1(`Loaded ${loadedSessions.length} clients from ${this.StorageFile}`);
|
||||||
loadedSessions.forEach(session => {
|
loadedSessions.forEach(session => {
|
||||||
this.createSession(session.url || session.port, session.username, session.password).then((sessionObj: SmppSession) => {
|
this.createSession(session.url || session.port, session.username, session.password).then((sessionObj: SmppSession) => {
|
||||||
sessionObj.defaultSingleJob = Job.deserialize(session.defaultSingleJob);
|
sessionObj.defaultSingleJob = Job.deserialize(session.defaultSingleJob);
|
||||||
sessionObj.defaultMultipleJob = Job.deserialize(session.defaultMultipleJob);
|
sessionObj.defaultMultipleJob = Job.deserialize(session.defaultMultipleJob);
|
||||||
|
|
||||||
let loadedProcessors: PduProcessor[] = session.preprocessors.concat(session.postprocessors);
|
let loadedProcessors: PduProcessor[] = session.preprocessors.concat(session.postprocessors);
|
||||||
sessionObj.appliedProcessors.forEach((processor: PduProcessor) => {
|
sessionObj.appliedProcessors.forEach((processor: PduProcessor) => {
|
||||||
let processorsToDetach: PduProcessor[] = loadedProcessors.filter(p => p.name === processor.name);
|
let processorsToDetach: PduProcessor[] = loadedProcessors.filter(p => p.name === processor.name);
|
||||||
ProcessorManager.detachProcessors(sessionObj, processorsToDetach);
|
ProcessorManager.detachProcessors(sessionObj, processorsToDetach);
|
||||||
});
|
});
|
||||||
loadedProcessors.forEach((processor: PduProcessor) => {
|
loadedProcessors.forEach((processor: PduProcessor) => {
|
||||||
if (!sessionObj.appliedProcessors.find(p => p.name === processor.name)) {
|
if (!sessionObj.appliedProcessors.find(p => p.name === processor.name)) {
|
||||||
ProcessorManager.attachProcessors(sessionObj, ProcessorManager.getProcessors(processor.name));
|
ProcessorManager.attachProcessors(sessionObj, ProcessorManager.getProcessors(processor.name));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.log1(`Error loading centers from ${this.StorageFile}: ${e}`);
|
this.logger.log1(`Error loading centers from ${this.StorageFile}: ${e}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createSession(arg: any, username: string, password: string): Promise<SmppSession> {
|
createSession(arg: any, username: string, password: string): Promise<SmppSession> {
|
||||||
return new Promise<SmppSession>((resolve, reject) => {
|
return new Promise<SmppSession>((resolve, reject) => {
|
||||||
this.logger.log1(`Creating session of type ${this.ManagedSessionClass.name} with arg ${arg}`);
|
this.logger.log1(`Creating session of type ${this.ManagedSessionClass.name} with arg ${arg}`);
|
||||||
this.getExisting(arg).then((s: SmppSession) => {
|
this.getExisting(arg).then((s: SmppSession) => {
|
||||||
resolve(s);
|
resolve(s);
|
||||||
}, err => {
|
}, err => {
|
||||||
});
|
});
|
||||||
this.verifyField(arg, reject);
|
this.verifyField(arg, reject);
|
||||||
username = username || "";
|
username = username || "";
|
||||||
password = password || "";
|
password = password || "";
|
||||||
|
|
||||||
let session = new this.ManagedSessionClass(this.sessionId++, arg, username, password);
|
let session = new this.ManagedSessionClass(this.sessionId++, arg, username, password);
|
||||||
this.addSession(session).then(() => {
|
this.addSession(session).then(() => {
|
||||||
resolve(session);
|
resolve(session);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyField(field: string, reject: (reason?: any) => void) {
|
verifyField(field: string, reject: (reason?: any) => void) {
|
||||||
if (!field) {
|
if (!field) {
|
||||||
let error = `Request to make a new session failed because of missing ${field}.`;
|
let error = `Request to make a new session failed because of missing ${field}.`;
|
||||||
this.logger.log1(error);
|
this.logger.log1(error);
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup(): void {
|
cleanup(): void {
|
||||||
this.logger.log1(`Saving centers to ${this.StorageFile}...`);
|
this.logger.log1(`Saving centers to ${this.StorageFile}...`);
|
||||||
fs.writeFileSync(this.StorageFile, JSON.stringify(this.serialize(), null, 4));
|
fs.writeFileSync(this.StorageFile, JSON.stringify(this.serialize(), null, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): object {
|
serialize(): object {
|
||||||
this.logger.log1(`Serializing ${this.sessions.length} clients`);
|
this.logger.log1(`Serializing ${this.sessions.length} clients`);
|
||||||
return this.sessions.map((session: SmppSession) => {
|
return this.sessions.map((session: SmppSession) => {
|
||||||
return session.serialize();
|
return session.serialize();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getExisting(arg: any): Promise<SmppSession> {
|
getExisting(arg: any): Promise<SmppSession> {
|
||||||
return new Promise<SmppSession>((resolve, reject) => {
|
return new Promise<SmppSession>((resolve, reject) => {
|
||||||
this.logger.log1(`Looking for session with arg ${arg}...`);
|
this.logger.log1(`Looking for session with arg ${arg}...`);
|
||||||
let session: SmppSession | undefined = this.sessions.find(this.comparatorFn.bind(this, arg));
|
let session: SmppSession | undefined = this.sessions.find(this.comparatorFn.bind(this, arg));
|
||||||
if (session) {
|
if (session) {
|
||||||
this.logger.log1(`Found session with arg ${arg}`);
|
this.logger.log1(`Found session with arg ${arg}`);
|
||||||
resolve(session);
|
resolve(session);
|
||||||
} else {
|
} else {
|
||||||
this.logger.log1(`Session with arg ${arg} not found`);
|
this.logger.log1(`Session with arg ${arg} not found`);
|
||||||
reject(`Session with arg ${arg} not found`);
|
reject(`Session with arg ${arg} not found`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,235 +12,235 @@ const NanoTimer = require("nanotimer");
|
|||||||
const smpp = require("smpp");
|
const smpp = require("smpp");
|
||||||
|
|
||||||
export default abstract class SmppSession {
|
export default abstract class SmppSession {
|
||||||
readonly EVENT: any = {
|
readonly EVENT: any = {
|
||||||
STATUS_CHANGED: "STATUS_CHANGED",
|
STATUS_CHANGED: "STATUS_CHANGED",
|
||||||
STATE_CHANGED: "STATE_CHANGED",
|
STATE_CHANGED: "STATE_CHANGED",
|
||||||
ANY_PDU_TX: "ANY_PDU_TX",
|
ANY_PDU_TX: "ANY_PDU_TX",
|
||||||
ANY_PDU_RX: "ANY_PDU_RX",
|
ANY_PDU_RX: "ANY_PDU_RX",
|
||||||
MESSAGE_SEND_COUNTER_UPDATE_EVENT: "MESSAGE_SEND_COUNTER_UPDATE_EVENT",
|
MESSAGE_SEND_COUNTER_UPDATE_EVENT: "MESSAGE_SEND_COUNTER_UPDATE_EVENT",
|
||||||
};
|
};
|
||||||
abstract STATUSES: string[];
|
abstract STATUSES: string[];
|
||||||
|
|
||||||
processors: { [key: string]: PduProcessor[] } = {};
|
processors: { [key: string]: PduProcessor[] } = {};
|
||||||
readonly UPDATE_WS: string = "UPDATE_WS";
|
readonly UPDATE_WS: string = "UPDATE_WS";
|
||||||
readonly eventEmitter: EventEmitter = new EventEmitter();
|
readonly eventEmitter: EventEmitter = new EventEmitter();
|
||||||
readonly logger: Logger = new Logger(this.constructor.name);
|
readonly logger: Logger = new Logger(this.constructor.name);
|
||||||
readonly sendTimer: any = new NanoTimer();
|
readonly sendTimer: any = new NanoTimer();
|
||||||
readonly counterUpdateTimer: any = new NanoTimer();
|
readonly counterUpdateTimer: any = new NanoTimer();
|
||||||
readonly MESSAGE_SEND_UPDATE_DELAY: number = Number(process.env.MESSAGE_SEND_UPDATE_DELAY) || 500;
|
readonly MESSAGE_SEND_UPDATE_DELAY: number = Number(process.env.MESSAGE_SEND_UPDATE_DELAY) || 500;
|
||||||
|
|
||||||
protected constructor() {
|
protected constructor() {
|
||||||
this.eventEmitter.on(this.EVENT.STATE_CHANGED, () => this.updateWs(this.EVENT.STATE_CHANGED));
|
this.eventEmitter.on(this.EVENT.STATE_CHANGED, () => this.updateWs(this.EVENT.STATE_CHANGED));
|
||||||
this.eventEmitter.on(this.EVENT.STATUS_CHANGED, () => this.updateWs(this.EVENT.STATUS_CHANGED));
|
this.eventEmitter.on(this.EVENT.STATUS_CHANGED, () => this.updateWs(this.EVENT.STATUS_CHANGED));
|
||||||
this.eventEmitter.on(this.EVENT.ANY_PDU_TX, (pdu: any) => this.updateWs(this.EVENT.ANY_PDU_TX, [pdu]));
|
this.eventEmitter.on(this.EVENT.ANY_PDU_TX, (pdu: any) => this.updateWs(this.EVENT.ANY_PDU_TX, [pdu]));
|
||||||
this.eventEmitter.on(this.EVENT.ANY_PDU_RX, (pdu: any) => this.updateWs(this.EVENT.ANY_PDU_RX, [pdu]));
|
this.eventEmitter.on(this.EVENT.ANY_PDU_RX, (pdu: any) => this.updateWs(this.EVENT.ANY_PDU_RX, [pdu]));
|
||||||
this.eventEmitter.on(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, (count: number) => this.updateWs(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, [count]));
|
this.eventEmitter.on(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, (count: number) => this.updateWs(this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT, [count]));
|
||||||
|
|
||||||
this.processors[Preprocessor.name] = [];
|
this.processors[Preprocessor.name] = [];
|
||||||
this.processors[Postprocessor.name] = [];
|
this.processors[Postprocessor.name] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
get appliedProcessors(): PduProcessor[] {
|
get appliedProcessors(): PduProcessor[] {
|
||||||
return this.processors[Preprocessor.name].concat(this.processors[Postprocessor.name]);
|
return this.processors[Preprocessor.name].concat(this.processors[Postprocessor.name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract _username: string;
|
abstract _username: string;
|
||||||
|
|
||||||
get username(): string {
|
get username(): string {
|
||||||
return this._username;
|
return this._username;
|
||||||
}
|
}
|
||||||
|
|
||||||
set username(username: string) {
|
set username(username: string) {
|
||||||
this._username = username;
|
this._username = username;
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract _password: string;
|
abstract _password: string;
|
||||||
|
|
||||||
get password(): string {
|
get password(): string {
|
||||||
return this._password;
|
return this._password;
|
||||||
}
|
}
|
||||||
|
|
||||||
set password(password: string) {
|
set password(password: string) {
|
||||||
this._password = password;
|
this._password = password;
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract _id: number;
|
abstract _id: number;
|
||||||
|
|
||||||
get id(): number {
|
get id(): number {
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract _status: string;
|
abstract _status: string;
|
||||||
|
|
||||||
get status(): string {
|
get status(): string {
|
||||||
return this._status;
|
return this._status;
|
||||||
}
|
}
|
||||||
|
|
||||||
set status(status: string) {
|
set status(status: string) {
|
||||||
this._status = status;
|
this._status = status;
|
||||||
this.eventEmitter.emit(this.EVENT.STATUS_CHANGED, this.status);
|
this.eventEmitter.emit(this.EVENT.STATUS_CHANGED, this.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract _defaultSingleJob: Job;
|
abstract _defaultSingleJob: Job;
|
||||||
|
|
||||||
get defaultSingleJob(): Job {
|
get defaultSingleJob(): Job {
|
||||||
return this._defaultSingleJob;
|
return this._defaultSingleJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
set defaultSingleJob(job: Job) {
|
set defaultSingleJob(job: Job) {
|
||||||
this._defaultSingleJob = job;
|
this._defaultSingleJob = job;
|
||||||
job.on(Job.STATE_CHANGED, this.eventJobUpdated);
|
job.on(Job.STATE_CHANGED, this.eventJobUpdated);
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract _defaultMultipleJob: Job;
|
abstract _defaultMultipleJob: Job;
|
||||||
|
|
||||||
get defaultMultipleJob(): Job {
|
get defaultMultipleJob(): Job {
|
||||||
return this._defaultMultipleJob;
|
return this._defaultMultipleJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
set defaultMultipleJob(job: Job) {
|
set defaultMultipleJob(job: Job) {
|
||||||
this._defaultMultipleJob = job;
|
this._defaultMultipleJob = job;
|
||||||
job.on(Job.STATE_CHANGED, this.eventJobUpdated);
|
job.on(Job.STATE_CHANGED, this.eventJobUpdated);
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatus(statusIndex: number) {
|
setStatus(statusIndex: number) {
|
||||||
this._status = this.STATUSES[statusIndex];
|
this._status = this.STATUSES[statusIndex];
|
||||||
this.eventEmitter.emit(this.EVENT.STATUS_CHANGED, this.status);
|
this.eventEmitter.emit(this.EVENT.STATUS_CHANGED, this.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract sendPdu(pdu: object, force?: boolean): Promise<object>;
|
abstract sendPdu(pdu: object, force?: boolean): Promise<object>;
|
||||||
|
|
||||||
doSendPdu(pdu: PDU, session: any): Promise<any> {
|
doSendPdu(pdu: PDU, session: any): Promise<any> {
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
let characterSizeBits: number = LongSmsProcessor.getCharacterSizeForEncoding(pdu);
|
let characterSizeBits: number = LongSmsProcessor.getCharacterSizeForEncoding(pdu);
|
||||||
let maxMessageLength: number = LongSmsProcessor.maxMessageSizeBits / characterSizeBits;
|
let maxMessageLength: number = LongSmsProcessor.maxMessageSizeBits / characterSizeBits;
|
||||||
if (!!pdu.short_message && pdu.short_message.length > maxMessageLength) {
|
if (!!pdu.short_message && pdu.short_message.length > maxMessageLength) {
|
||||||
pdu.short_message = pdu.short_message.substring(0, maxMessageLength);
|
pdu.short_message = pdu.short_message.substring(0, maxMessageLength);
|
||||||
}
|
}
|
||||||
session.send(pdu, (reply: any) => resolve(reply));
|
session.send(pdu, (reply: any) => resolve(reply));
|
||||||
this.eventEmitter.emit(this.EVENT.ANY_PDU_TX, pdu);
|
this.eventEmitter.emit(this.EVENT.ANY_PDU_TX, pdu);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract destroy(): void;
|
abstract destroy(): void;
|
||||||
|
|
||||||
sendSingle(job: Job): Promise<object> {
|
sendSingle(job: Job): Promise<object> {
|
||||||
return this.sendPdu(job.pdu);
|
return this.sendPdu(job.pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendSingleDefault(): Promise<object> {
|
sendSingleDefault(): Promise<object> {
|
||||||
return this.sendSingle(this.defaultSingleJob);
|
return this.sendSingle(this.defaultSingleJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract sendMultiple(job: Job): Promise<void>;
|
abstract sendMultiple(job: Job): Promise<void>;
|
||||||
|
|
||||||
sendMultipleDefault(): Promise<void> {
|
sendMultipleDefault(): Promise<void> {
|
||||||
return this.sendMultiple(this.defaultMultipleJob);
|
return this.sendMultiple(this.defaultMultipleJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelSendInterval(): void {
|
cancelSendInterval(): void {
|
||||||
this.sendTimer.clearInterval();
|
this.sendTimer.clearInterval();
|
||||||
this.counterUpdateTimer.clearInterval();
|
this.counterUpdateTimer.clearInterval();
|
||||||
this.setStatus(this.STATUSES.length - 2);
|
this.setStatus(this.STATUSES.length - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract close(): Promise<void>;
|
abstract close(): Promise<void>;
|
||||||
|
|
||||||
serialize(): object {
|
serialize(): object {
|
||||||
let obj = {
|
let obj = {
|
||||||
id: this._id,
|
id: this._id,
|
||||||
username: this._username,
|
username: this._username,
|
||||||
password: this._password,
|
password: this._password,
|
||||||
status: this._status,
|
status: this._status,
|
||||||
defaultSingleJob: this._defaultSingleJob.serialize(),
|
defaultSingleJob: this._defaultSingleJob.serialize(),
|
||||||
defaultMultipleJob: this._defaultMultipleJob.serialize(),
|
defaultMultipleJob: this._defaultMultipleJob.serialize(),
|
||||||
preprocessors: this.processors.Preprocessor.map((p: PduProcessor) => p.serialize()),
|
preprocessors: this.processors.Preprocessor.map((p: PduProcessor) => p.serialize()),
|
||||||
postprocessors: this.processors.Postprocessor.map((p: PduProcessor) => p.serialize()),
|
postprocessors: this.processors.Postprocessor.map((p: PduProcessor) => p.serialize()),
|
||||||
availablePreprocessors: ProcessorManager.getPreprocessorsForType(this.constructor.name).map((p: PduProcessor) => p.serialize()),
|
availablePreprocessors: ProcessorManager.getPreprocessorsForType(this.constructor.name).map((p: PduProcessor) => p.serialize()),
|
||||||
availablePostprocessors: ProcessorManager.getPostprocessorsForType(this.constructor.name).map((p: PduProcessor) => p.serialize()),
|
availablePostprocessors: ProcessorManager.getPostprocessorsForType(this.constructor.name).map((p: PduProcessor) => p.serialize()),
|
||||||
};
|
};
|
||||||
return this.postSerialize(obj);
|
return this.postSerialize(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract postSerialize(obj: object): object;
|
abstract postSerialize(obj: object): object;
|
||||||
|
|
||||||
on(event: string, callback: (...args: any[]) => void): void {
|
on(event: string, callback: (...args: any[]) => void): void {
|
||||||
this.eventEmitter.on(event, callback);
|
this.eventEmitter.on(event, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateWs(event: string, args?: any[]): void {
|
updateWs(event: string, args?: any[]): void {
|
||||||
this.logger.log1(`Update WS: ${event}`);
|
this.logger.log1(`Update WS: ${event}`);
|
||||||
let message: WSMessage = {
|
let message: WSMessage = {
|
||||||
type: event,
|
type: event,
|
||||||
identifier: `${this.constructor.name}:${this.id.toString()}`
|
identifier: `${this.constructor.name}:${this.id.toString()}`
|
||||||
};
|
};
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case this.EVENT.STATE_CHANGED:
|
case this.EVENT.STATE_CHANGED:
|
||||||
message.data = this.serialize();
|
message.data = this.serialize();
|
||||||
break;
|
break;
|
||||||
case this.EVENT.STATUS_CHANGED:
|
case this.EVENT.STATUS_CHANGED:
|
||||||
message.data = this.status;
|
message.data = this.status;
|
||||||
break;
|
break;
|
||||||
case this.EVENT.ANY_PDU_RX:
|
case this.EVENT.ANY_PDU_RX:
|
||||||
case this.EVENT.ANY_PDU_TX:
|
case this.EVENT.ANY_PDU_TX:
|
||||||
message.data = args![0];
|
message.data = args![0];
|
||||||
break;
|
break;
|
||||||
case this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT:
|
case this.EVENT.MESSAGE_SEND_COUNTER_UPDATE_EVENT:
|
||||||
message.data = args![0];
|
message.data = args![0];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.eventEmitter.emit(this.UPDATE_WS, message);
|
this.eventEmitter.emit(this.UPDATE_WS, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
eventJobUpdated(): void {
|
eventJobUpdated(): void {
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
attachPreprocessor(processor: PduProcessor): void {
|
attachPreprocessor(processor: PduProcessor): void {
|
||||||
this.attachProcessor(processor, this.processors.Preprocessor);
|
this.attachProcessor(processor, this.processors.Preprocessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
attachPostprocessor(processor: PduProcessor): void {
|
attachPostprocessor(processor: PduProcessor): void {
|
||||||
this.attachProcessor(processor, this.processors.Postprocessor);
|
this.attachProcessor(processor, this.processors.Postprocessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
detachPreprocessor(processor: PduProcessor): void {
|
detachPreprocessor(processor: PduProcessor): void {
|
||||||
this.detachProcessor(processor, this.processors.Preprocessor);
|
this.detachProcessor(processor, this.processors.Preprocessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
detachPostprocessor(processor: PduProcessor): void {
|
detachPostprocessor(processor: PduProcessor): void {
|
||||||
this.detachProcessor(processor, this.processors.Postprocessor);
|
this.detachProcessor(processor, this.processors.Postprocessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
eventAnyPdu(session: any, pdu: PDU): Promise<any> {
|
eventAnyPdu(session: any, pdu: PDU): Promise<any> {
|
||||||
if (!!pdu) {
|
if (!!pdu) {
|
||||||
this.eventEmitter.emit(this.EVENT.ANY_PDU_RX, pdu);
|
this.eventEmitter.emit(this.EVENT.ANY_PDU_RX, pdu);
|
||||||
// console.log("IS PDU TIME");
|
// console.log("IS PDU TIME");
|
||||||
this.logger.log6(pdu);
|
this.logger.log6(pdu);
|
||||||
this.processors.Postprocessor.forEach((processor: PduProcessor) => processor.processPdu(session, pdu, this));
|
this.processors.Postprocessor.forEach((processor: PduProcessor) => processor.processPdu(session, pdu, this));
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
private detachProcessor(processor: PduProcessor, array: PduProcessor[]): void {
|
private detachProcessor(processor: PduProcessor, array: PduProcessor[]): void {
|
||||||
if (array.indexOf(processor) >= 0) {
|
if (array.indexOf(processor) >= 0) {
|
||||||
array.splice(array.indexOf(processor), 1);
|
array.splice(array.indexOf(processor), 1);
|
||||||
this.logger.log1(`Detaching PDU processor: ${processor.constructor.name}-${this.id}, now active: ${array.length} processors`);
|
this.logger.log1(`Detaching PDU processor: ${processor.constructor.name}-${this.id}, now active: ${array.length} processors`);
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachProcessor(processor: PduProcessor, array: PduProcessor[]): void {
|
private attachProcessor(processor: PduProcessor, array: PduProcessor[]): void {
|
||||||
if (array.indexOf(processor) === -1) {
|
if (array.indexOf(processor) === -1) {
|
||||||
array.push(processor);
|
array.push(processor);
|
||||||
this.logger.log1(`Attaching PDU processor: ${processor.constructor.name}-${this.id}, now active: ${array.length} processors`);
|
this.logger.log1(`Attaching PDU processor: ${processor.constructor.name}-${this.id}, now active: ${array.length} processors`);
|
||||||
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
this.eventEmitter.emit(this.EVENT.STATE_CHANGED, this.serialize());
|
||||||
} else {
|
} else {
|
||||||
this.logger.log1(`PDU processor: ${processor.constructor.name}-${this.id} already attached to session`);
|
this.logger.log1(`PDU processor: ${processor.constructor.name}-${this.id} already attached to session`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,70 +5,70 @@ import SmppSession from "../SmppSession";
|
|||||||
import ZlibCoder from "../ZlibCoder";
|
import ZlibCoder from "../ZlibCoder";
|
||||||
|
|
||||||
export default class ClientSet {
|
export default class ClientSet {
|
||||||
identifier: string;
|
identifier: string;
|
||||||
private clients: any[];
|
private clients: any[];
|
||||||
private readonly type: string;
|
private readonly type: string;
|
||||||
private readonly sessionId: number;
|
private readonly sessionId: number;
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
private readonly relevantSessionManager: SessionManager | undefined;
|
private readonly relevantSessionManager: SessionManager | undefined;
|
||||||
|
|
||||||
constructor(identifier: string, sessionManagers: SessionManager[]) {
|
constructor(identifier: string, sessionManagers: SessionManager[]) {
|
||||||
this.clients = [];
|
this.clients = [];
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
|
|
||||||
let data: string[] = identifier.split(':');
|
let data: string[] = identifier.split(':');
|
||||||
this.type = data[0];
|
this.type = data[0];
|
||||||
this.sessionId = parseInt(data[1]);
|
this.sessionId = parseInt(data[1]);
|
||||||
|
|
||||||
this.logger = new Logger(`ClientSet-${this.type}-${this.sessionId}`);
|
this.logger = new Logger(`ClientSet-${this.type}-${this.sessionId}`);
|
||||||
this.logger.log1(`Created client set for ${this.type} ${this.sessionId}`);
|
this.logger.log1(`Created client set for ${this.type} ${this.sessionId}`);
|
||||||
|
|
||||||
this.relevantSessionManager = sessionManagers.find(sm => sm.identifier === this.type);
|
this.relevantSessionManager = sessionManagers.find(sm => sm.identifier === this.type);
|
||||||
if (!this.relevantSessionManager) {
|
if (!this.relevantSessionManager) {
|
||||||
this.logger.log1(`No session manager found for type ${this.type}`);
|
this.logger.log1(`No session manager found for type ${this.type}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.relevantSessionManager) {
|
if (this.relevantSessionManager) {
|
||||||
this.relevantSessionManager.getSessions().then((sessions) => {
|
this.relevantSessionManager.getSessions().then((sessions) => {
|
||||||
sessions.forEach((session) => {
|
sessions.forEach((session) => {
|
||||||
this.attachListener(session);
|
this.attachListener(session);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.relevantSessionManager.on(this.relevantSessionManager.SESSION_ADDED_EVENT, this.eventOnSessionAdded.bind(this));
|
this.relevantSessionManager.on(this.relevantSessionManager.SESSION_ADDED_EVENT, this.eventOnSessionAdded.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
eventOnSessionAdded(sessionId: number): void {
|
eventOnSessionAdded(sessionId: number): void {
|
||||||
this.logger.log2(`Session added: ${sessionId}`);
|
this.logger.log2(`Session added: ${sessionId}`);
|
||||||
this.relevantSessionManager?.getSession(sessionId).then((session) => {
|
this.relevantSessionManager?.getSession(sessionId).then((session) => {
|
||||||
this.attachListener(session);
|
this.attachListener(session);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
add(ws: any): void {
|
add(ws: any): void {
|
||||||
this.logger.log2(`Added client`);
|
this.logger.log2(`Added client`);
|
||||||
this.clients.push(ws);
|
this.clients.push(ws);
|
||||||
ws.on('close', this.eventOnClose.bind(this, ws));
|
ws.on('close', this.eventOnClose.bind(this, ws));
|
||||||
}
|
}
|
||||||
|
|
||||||
eventOnClose(ws: any): void {
|
eventOnClose(ws: any): void {
|
||||||
this.logger.log2(`Removed client`);
|
this.logger.log2(`Removed client`);
|
||||||
this.clients.splice(this.clients.indexOf(ws), 1);
|
this.clients.splice(this.clients.indexOf(ws), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyClients(message: WSMessage) {
|
notifyClients(message: WSMessage) {
|
||||||
if (message.identifier !== this.identifier) return;
|
if (message.identifier !== this.identifier) return;
|
||||||
let textMessage: string = JSON.stringify(message);
|
let textMessage: string = JSON.stringify(message);
|
||||||
let compressedMessage = ZlibCoder.compress(textMessage);
|
let compressedMessage = ZlibCoder.compress(textMessage);
|
||||||
if (this.clients.length > 0) {
|
if (this.clients.length > 0) {
|
||||||
this.logger.log2(`Notifying clients: ${message}`);
|
this.logger.log2(`Notifying clients: ${message}`);
|
||||||
this.clients.forEach((ws) => {
|
this.clients.forEach((ws) => {
|
||||||
ws.send(compressedMessage);
|
ws.send(compressedMessage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachListener(session: SmppSession) {
|
private attachListener(session: SmppSession) {
|
||||||
session.on(session.UPDATE_WS, (message: WSMessage) => this.notifyClients(message));
|
session.on(session.UPDATE_WS, (message: WSMessage) => this.notifyClients(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,45 +7,45 @@ const WebSocket = require("ws");
|
|||||||
const WS_SERVER_PORT: number = Number(process.env.WS_SERVER_PORT) || 8191;
|
const WS_SERVER_PORT: number = Number(process.env.WS_SERVER_PORT) || 8191;
|
||||||
|
|
||||||
export default class WSServer {
|
export default class WSServer {
|
||||||
private readonly clients: ClientSet[];
|
private readonly clients: ClientSet[];
|
||||||
private readonly unknownClients: any[];
|
private readonly unknownClients: any[];
|
||||||
private readonly server: any;
|
private readonly server: any;
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
private readonly sessionManagers: SessionManager[];
|
private readonly sessionManagers: SessionManager[];
|
||||||
|
|
||||||
constructor(sessionManagers: SessionManager[]) {
|
constructor(sessionManagers: SessionManager[]) {
|
||||||
this.clients = [];
|
this.clients = [];
|
||||||
this.unknownClients = [];
|
this.unknownClients = [];
|
||||||
this.server = new WebSocket.Server({port: WS_SERVER_PORT});
|
this.server = new WebSocket.Server({port: WS_SERVER_PORT});
|
||||||
this.sessionManagers = sessionManagers;
|
this.sessionManagers = sessionManagers;
|
||||||
this.logger = new Logger("WSServer");
|
this.logger = new Logger("WSServer");
|
||||||
this.server.on('connection', this.eventOnConnection.bind(this));
|
this.server.on('connection', this.eventOnConnection.bind(this));
|
||||||
this.logger.log1(`WSServer listening at ws://localhost:${WS_SERVER_PORT}`);
|
this.logger.log1(`WSServer listening at ws://localhost:${WS_SERVER_PORT}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventOnConnection(ws: WebSocket): void {
|
private eventOnConnection(ws: WebSocket): void {
|
||||||
this.logger.log1("New connection");
|
this.logger.log1("New connection");
|
||||||
this.unknownClients.push(ws);
|
this.unknownClients.push(ws);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ws.on('message', this.eventOnMessage.bind(this, ws));
|
ws.on('message', this.eventOnMessage.bind(this, ws));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ws.on('close', this.eventOnClose.bind(this, ws));
|
ws.on('close', this.eventOnClose.bind(this, ws));
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventOnMessage(ws: any, message: string): void {
|
private eventOnMessage(ws: any, message: string): void {
|
||||||
this.logger.log1("New message");
|
this.logger.log1("New message");
|
||||||
message = String(message);
|
message = String(message);
|
||||||
this.unknownClients.splice(this.unknownClients.indexOf(ws), 1);
|
this.unknownClients.splice(this.unknownClients.indexOf(ws), 1);
|
||||||
let clientSet: ClientSet | undefined = this.clients.find((clientSet: ClientSet) => clientSet.identifier === message);
|
let clientSet: ClientSet | undefined = this.clients.find((clientSet: ClientSet) => clientSet.identifier === message);
|
||||||
if (!clientSet) {
|
if (!clientSet) {
|
||||||
clientSet = new ClientSet(message, this.sessionManagers);
|
clientSet = new ClientSet(message, this.sessionManagers);
|
||||||
this.clients.push(clientSet);
|
this.clients.push(clientSet);
|
||||||
}
|
}
|
||||||
clientSet.add(ws);
|
clientSet.add(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
private eventOnClose(ws: any): void {
|
private eventOnClose(ws: any): void {
|
||||||
this.logger.log1("Connection closed");
|
this.logger.log1("Connection closed");
|
||||||
this.unknownClients.splice(this.unknownClients.indexOf(ws), 1);
|
this.unknownClients.splice(this.unknownClients.indexOf(ws), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,11 +1,11 @@
|
|||||||
const zlib = require("zlib");
|
const zlib = require("zlib");
|
||||||
|
|
||||||
export default class ZlibCoder {
|
export default class ZlibCoder {
|
||||||
static compress(input: string): Buffer {
|
static compress(input: string): Buffer {
|
||||||
return zlib.deflateSync(input).toString('base64');
|
return zlib.deflateSync(input).toString('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
static decompress(input: Buffer): string {
|
static decompress(input: Buffer): string {
|
||||||
return zlib.decompress(input).toString();
|
return zlib.decompress(input).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
25
src/main.js
Normal file
25
src/main.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
var CenterSessionManager_1 = require("./Center/CenterSessionManager");
|
||||||
|
var ClientSessionManager_1 = require("./Client/ClientSessionManager");
|
||||||
|
var HttpServer_1 = require("./HttpServer/HttpServer");
|
||||||
|
var Logger_1 = require("./Logger");
|
||||||
|
var ProcessorManager_1 = require("./PDUProcessor/ProcessorManager");
|
||||||
|
var WSServer_1 = require("./WS/WSServer");
|
||||||
|
var PDU = require("smpp").PDU;
|
||||||
|
var logger = new Logger_1.default("main");
|
||||||
|
var pm = new ProcessorManager_1.default();
|
||||||
|
var clientManager = new ClientSessionManager_1.default();
|
||||||
|
var centerManager = new CenterSessionManager_1.default();
|
||||||
|
var wss = new WSServer_1.default([clientManager, centerManager]);
|
||||||
|
var httpServer = new HttpServer_1.default(clientManager, centerManager);
|
||||||
|
function cleanup() {
|
||||||
|
logger.log1("Cleaning up...");
|
||||||
|
clientManager.cleanup();
|
||||||
|
centerManager.cleanup();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
process.on('exit', cleanup);
|
||||||
|
process.on('SIGINT', cleanup);
|
||||||
|
process.on('SIGUSR1', cleanup);
|
||||||
|
process.on('SIGUSR2', cleanup);
|
@@ -17,10 +17,10 @@ let wss: WSServer = new WSServer([clientManager, centerManager]);
|
|||||||
let httpServer: HttpServer = new HttpServer(clientManager, centerManager);
|
let httpServer: HttpServer = new HttpServer(clientManager, centerManager);
|
||||||
|
|
||||||
function cleanup(): void {
|
function cleanup(): void {
|
||||||
logger.log1("Cleaning up...");
|
logger.log1("Cleaning up...");
|
||||||
clientManager.cleanup();
|
clientManager.cleanup();
|
||||||
centerManager.cleanup();
|
centerManager.cleanup();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.on('exit', cleanup);
|
process.on('exit', cleanup);
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"strict": false,
|
||||||
"module": "commonjs",
|
"verbatimModuleSyntax": false,
|
||||||
"outDir": "./dist",
|
"noUncheckedIndexedAccess": false,
|
||||||
"rootDir": "./src",
|
|
||||||
"strict": true,
|
"moduleResolution": "NodeNext",
|
||||||
"moduleResolution": "node",
|
"module": "NodeNext",
|
||||||
|
"target": "ESNext",
|
||||||
|
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"noImplicitAny": true,
|
"noEmit": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"include": ["src/**/*", "src/main.ts"]
|
||||||
"./node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
13
tsup.config.ts
Normal file
13
tsup.config.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { defineConfig } from 'tsup';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/main.ts'],
|
||||||
|
dts: false,
|
||||||
|
splitting: false,
|
||||||
|
sourcemap: false,
|
||||||
|
outDir: 'build',
|
||||||
|
clean: true,
|
||||||
|
minify: true,
|
||||||
|
target: ['esnext'],
|
||||||
|
format: ['cjs']
|
||||||
|
});
|
61
workfile.js
Normal file
61
workfile.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { connect } from "smpp";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
const optionsFile = "smpp_tester_options.json";
|
||||||
|
|
||||||
|
const exampleSession = {
|
||||||
|
url: "smpp://172.17.77.203:4445",
|
||||||
|
connection_count: 1,
|
||||||
|
system_id: "snt",
|
||||||
|
password: "snt",
|
||||||
|
source_addr: "44455",
|
||||||
|
destination_addr: "test123",
|
||||||
|
short_message: "SNT BENCHMARK!",
|
||||||
|
message_count: 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!fs.existsSync(optionsFile)) {
|
||||||
|
fs.writeFileSync(optionsFile, JSON.stringify([exampleSession], null, 4));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const options = fs.readFileSync(optionsFile, "utf8") ?? "[]";
|
||||||
|
const sessions = JSON.parse(options);
|
||||||
|
const smppSessions = [];
|
||||||
|
|
||||||
|
for (const session of sessions) {
|
||||||
|
for (let i = 0; i < session.connection_count; i++) {
|
||||||
|
const smppSession = connect(
|
||||||
|
{
|
||||||
|
url: session.url,
|
||||||
|
auto_enquire_link_period: 10000,
|
||||||
|
debug: true,
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
smppSession.bind_transceiver({
|
||||||
|
system_id: session.system_id,
|
||||||
|
password: session.password,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
smppSessions.push({ properties: session, session: smppSession });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
for (const session of smppSessions) {
|
||||||
|
for (let i = 0; i < session.properties.message_count; i++) {
|
||||||
|
session.session.submit_sm(
|
||||||
|
{
|
||||||
|
source_addr: session.properties.source_addr,
|
||||||
|
destination_addr: session.properties.destination_addr,
|
||||||
|
short_message: session.properties.short_message,
|
||||||
|
},
|
||||||
|
function (pdu) {
|
||||||
|
if (pdu.command_status === 0) {
|
||||||
|
console.log(pdu.message_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
Reference in New Issue
Block a user