Update
This commit is contained in:
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,8 +1,11 @@
|
|||||||
.idea
|
.idea
|
||||||
node_modules
|
node_modules
|
||||||
package-lock.json
|
package-lock.json
|
||||||
sessions.json
|
sessions.json
|
||||||
client_sessions.json
|
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="6" />
|
|
||||||
</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,15 +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" />
|
|
||||||
<package-manager value="pnpm" />
|
|
||||||
<envs />
|
|
||||||
<method v="2">
|
|
||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="tsc" run_configuration_type="js.build_tools.npm" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
@@ -1,13 +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" />
|
|
||||||
<package-manager value="pnpm" />
|
|
||||||
<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"
|
265
README.md
265
README.md
@@ -1,120 +1,147 @@
|
|||||||
# smsgw-tester-api
|
# smsgw-tester-api
|
||||||
|
|
||||||
#### This application is meant to be used for performance or functionality testing smpp processing systems such as sms centers, clients or sms gateways.
|
#### This application is meant to be used for performance or functionality testing smpp processing systems such as sms centers, clients or sms gateways.
|
||||||
|
|
||||||
The application is capable of hosting any number of smpp clients or centers. The centers automatically accept any smpp connections while the clients can be connected/bound/disconnected at will.
|
The application is capable of hosting any number of smpp clients or centers. The centers automatically accept any smpp connections while the clients can be connected/bound/disconnected at will.
|
||||||
|
|
||||||
---
|
---
|
||||||
## General use
|
## General use
|
||||||
|
|
||||||
The api is meant to be used along with the [web application](https://github.com/PhatDave/smsgw-tester-web) but can also be used standalone via http requests. The request examples can be found in the insomnia export file (although they are outdated as of 1.0).
|
The api is meant to be used along with the [web application](https://github.com/PhatDave/smsgw-tester-web) but can also be used standalone via http requests. The request examples can be found in the insomnia export file (although they are outdated as of 1.0).
|
||||||
|
|
||||||
The web view consists of a Client and Center segment. Each entity has it's 3 parameters (for a client those are the url [the client connects to], the username and password, for the center those are the port [the center listens on], username and password) of which 2 are modifiable (username and password).
|
The web view consists of a Client and Center segment. Each entity has it's 3 parameters (for a client those are the url [the client connects to], the username and password, for the center those are the port [the center listens on], username and password) of which 2 are modifiable (username and password).
|
||||||
|
|
||||||
Each entity can be configured to send one smpp message or multiple smpp messages at a given rate (of messages per second).
|
Each entity can be configured to send one smpp message or multiple smpp messages at a given rate (of messages per second).
|
||||||
|
|
||||||
Each entity also includes a live graph representing the incoming and outgoing traffic.
|
Each entity also includes a live graph representing the incoming and outgoing traffic.
|
||||||
|
|
||||||
Each entity also supports a set of pre and post processors that in some way modify the incoming or outgoing pdu. These processors will be described in the processor segment.
|
Each entity also supports a set of pre and post processors that in some way modify the incoming or outgoing pdu. These processors will be described in the processor segment.
|
||||||
|
|
||||||
Entities can also be deleted by **double clicking** the delete button.
|
Entities can also be deleted by **double clicking** the delete button.
|
||||||
|
|
||||||
Currently it is not possible to temporarily disable entities but this is planned for a future release (as of 1.0).
|
Currently it is not possible to temporarily disable entities but this is planned for a future release (as of 1.0).
|
||||||
|
|
||||||
### Center modes of operation
|
### Center modes of operation
|
||||||
|
|
||||||
Center entities are "special" in the sense that they can have a few different modes of operation.
|
Center entities are "special" in the sense that they can have a few different modes of operation.
|
||||||
|
|
||||||
As of 1.0 the following modes are implemented (and later described in the center postprocessor segment): "Debug", Echo and DeliveryReport.
|
As of 1.0 the following modes are implemented (and later described in the center postprocessor segment): "Debug", Echo and DeliveryReport.
|
||||||
|
|
||||||
- **Debug mode** (1.0)
|
- **Debug mode** (1.0)
|
||||||
- Only "Deliver\_sm Reply" is enabled, the center does not reply to messages with any other messages and only acknowledges the ones delivered to it.
|
- Only "Deliver\_sm Reply" is enabled, the center does not reply to messages with any other messages and only acknowledges the ones delivered to it.
|
||||||
- **Echo mode** (1.0)
|
- **Echo mode** (1.0)
|
||||||
- "Echo PDU" is enabled, the center replies to messages with a copy of the received message whose source and destination fields have been swapped.
|
- "Echo PDU" is enabled, the center replies to messages with a copy of the received message whose source and destination fields have been swapped.
|
||||||
- For example a center receiving a message (src:123, dst:321) will reply to it with a message (src:321, dst:123) where the text of the message is the same as the text of the received message.
|
- For example a center receiving a message (src:123, dst:321) will reply to it with a message (src:321, dst:123) where the text of the message is the same as the text of the received message.
|
||||||
- **Delivery Report mode** (1.0)
|
- **Delivery Report mode** (1.0)
|
||||||
- "Delivery Receipt" is enabled, the center replies to messages with delivery report. You can learn more about delivery reports [here](https://smpp.org/smpp-delivery-receipt.html)
|
- "Delivery Receipt" is enabled, the center replies to messages with delivery report. You can learn more about delivery reports [here](https://smpp.org/smpp-delivery-receipt.html)
|
||||||
- Details of the implementation can be found in the last segment, Delivery Reports
|
- Details of the implementation can be found in the last segment, Delivery Reports
|
||||||
|
|
||||||
Enabling multiple modes at once will have the center send more than one reply message at once. For example enabling echo mode and delivery report mode will have the center reply with an echo message and a delivery report at the same time.
|
Enabling multiple modes at once will have the center send more than one reply message at once. For example enabling echo mode and delivery report mode will have the center reply with an echo message and a delivery report at the same time.
|
||||||
|
|
||||||
---
|
---
|
||||||
## Processors
|
## Processors
|
||||||
|
|
||||||
Processors handle the majority of this application's functionality. On the web application active processors are highlighted green and they can be toggled by clicking on the appropriate button.
|
Processors handle the majority of this application's functionality. On the web application active processors are highlighted green and they can be toggled by clicking on the appropriate button.
|
||||||
|
|
||||||
Preprocessors generally do something with the message before it is sent while postprocessors generally reply to a message.
|
Preprocessors generally do something with the message before it is sent while postprocessors generally reply to a message.
|
||||||
|
|
||||||
These are the available pre and post processors per entity:
|
These are the available pre and post processors per entity:
|
||||||
|
|
||||||
### Client Preprocessors
|
### Client Preprocessors
|
||||||
|
|
||||||
#### Destination & Source Enumerator (1.0)
|
#### Destination & Source Enumerator (1.0)
|
||||||
|
|
||||||
These processors append an incrementing 4 digit number to the end of either the source or destination. For example given a destination of "3851728381" and destinationEnumerator toggled on, sending 5 messages would have their destinations be:
|
These processors append an incrementing 4 digit number to the end of either the source or destination. For example given a destination of "3851728381" and destinationEnumerator toggled on, sending 5 messages would have their destinations be:
|
||||||
- 38517283810000
|
- 38517283810000
|
||||||
- 38517283810001
|
- 38517283810001
|
||||||
- 38517283810002
|
- 38517283810002
|
||||||
- 38517283810003
|
- 38517283810003
|
||||||
- 38517283810004
|
- 38517283810004
|
||||||
|
|
||||||
The functionality is identical for source enumerator.
|
The functionality is identical for source enumerator.
|
||||||
|
|
||||||
#### Delivery Receipt Request (1.0)
|
#### Delivery Receipt Request (1.0)
|
||||||
|
|
||||||
This preprocessor adds a field to the pdu (registered\_delivery) and sets it to 1. This signals to the smsc that a delivery report is requested to this message.
|
This preprocessor adds a field to the pdu (registered\_delivery) and sets it to 1. This signals to the smsc that a delivery report is requested to this message.
|
||||||
|
|
||||||
#### Long SMS (1.0)
|
#### Long SMS (1.0)
|
||||||
|
|
||||||
With this preprocessor enabled the messages body is chopped up into segments based on the encoding and maximum size of an smpp message given that encoding and each segment is sent separately. (Message segment information is set in the form of udh)
|
With this preprocessor enabled the messages body is chopped up into segments based on the encoding and maximum size of an smpp message given that encoding and each segment is sent separately. (Message segment information is set in the form of udh)
|
||||||
|
|
||||||
**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**.
|
||||||
|
|
||||||
### Center Preprocessors
|
#### Protocol ID (+2/3 Digit Versions) (1.2)
|
||||||
|
|
||||||
None as of 1.0
|
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.
|
||||||
|
|
||||||
### Client Postprocessors
|
#### Source/Destination Set Processor
|
||||||
|
|
||||||
#### Deliver\_sm Reply (1.0)
|
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.
|
||||||
This postprocessor should never be disabled (unless you know what you're doing). It enables the client to reply to deliver\_sm pdus. (deliver\_sm -> deliver\_sm\_resp)
|
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.
|
||||||
### Center Postprocessors
|
Note, the picked msisdn per message is random (from the generated set).
|
||||||
|
|
||||||
#### Bind Transciever Reply (1.0)
|
### Center Preprocessors
|
||||||
|
|
||||||
This postprocessor should never be disabled (unless you know what you're doing). It enables client authentication. (By replying to bind\_transceiver pdus)
|
#### Destination & Source Enumerator (1.2)
|
||||||
|
|
||||||
#### Submit\_sm Reply (1.0)
|
Same as the Client version.
|
||||||
|
|
||||||
This postprocessor should never be disabled (unless you know what you're doing). It enables the center to reply to submit\_sm pdus. (submit\_sm -> submit\_sm\_resp)
|
#### Long SMS (1.2)
|
||||||
|
|
||||||
#### Enquire Link Reply (1.0)
|
Same as the Client version.
|
||||||
|
|
||||||
This postprocessor should never be disabled (unless you know what you're doing). It replies to the clients "heartbeat" (the enquire\_link pdu). (enquire\_link -> enquire\_link\_resp)
|
#### Protocol ID (+2/3 Digit Versions) (1.2)
|
||||||
|
|
||||||
#### Echo PDU (1.0)
|
Same as the Client version.
|
||||||
|
|
||||||
This is the first "real" postprocessor for center entities. It is one of 3 (as of 1.0) choices of center operation.
|
#### Source/Destination Set Processor (1.2)
|
||||||
|
|
||||||
The "Echo" mode of operation has the center reply to any submit\_sm with a deliver\_sm whose message body is the same (as the submit\_sm) and source and destination swapped.
|
Same as the Client version.
|
||||||
|
|
||||||
For example, sending a submit\_sm with the source of "1234" and a destination of "4321" and text of "test123" will have the center reply with a deliver\_sm with the source of "4321" and destination of "1234" with the text "test123".
|
### Client Postprocessors
|
||||||
|
|
||||||
#### Delivery Receipt (1.0)
|
#### Deliver\_sm Reply (1.0)
|
||||||
|
|
||||||
The "most important" postprocessor for an smsc the delivery receipt postprocessor handles generating and sending delivery reports. You can read more about delivery reports in the Delivery Reports section.
|
This postprocessor should never be disabled (unless you know what you're doing). It enables the client to reply to deliver\_sm pdus. (deliver\_sm -> deliver\_sm\_resp)
|
||||||
|
|
||||||
---
|
|
||||||
## Delivery Reports
|
### Center Postprocessors
|
||||||
|
|
||||||
Upon receiving a submit_sm on the center whose "Delivery Receipt" postprocessor has been enabled it:
|
#### Bind Transciever Reply (1.0)
|
||||||
- Checks whether the pdus "registered_delivery" field is set
|
|
||||||
- Generates a delivery report in the form of `id:<messageId> sub:001 dlvrd:001 submit date:<date> done date:<date> stat:DELIVERD err:000 text:`
|
This postprocessor should never be disabled (unless you know what you're doing). It enables client authentication. (By replying to bind\_transceiver pdus)
|
||||||
- The messageId here is the one id returned in the submit_sm_resp
|
|
||||||
- The date is simply the current date as of generation of the DR
|
#### Submit\_sm Reply (1.0)
|
||||||
- Sets the newly generated pdu esm class to 04
|
|
||||||
|
This postprocessor should never be disabled (unless you know what you're doing). It enables the center to reply to submit\_sm pdus. (submit\_sm -> submit\_sm\_resp)
|
||||||
|
|
||||||
|
#### Enquire Link Reply (1.0)
|
||||||
|
|
||||||
|
This postprocessor should never be disabled (unless you know what you're doing). It replies to the clients "heartbeat" (the enquire\_link pdu). (enquire\_link -> enquire\_link\_resp)
|
||||||
|
|
||||||
|
#### Echo PDU (1.0)
|
||||||
|
|
||||||
|
This is the first "real" postprocessor for center entities. It is one of 3 (as of 1.0) choices of center operation.
|
||||||
|
|
||||||
|
The "Echo" mode of operation has the center reply to any submit\_sm with a deliver\_sm whose message body is the same (as the submit\_sm) and source and destination swapped.
|
||||||
|
|
||||||
|
For example, sending a submit\_sm with the source of "1234" and a destination of "4321" and text of "test123" will have the center reply with a deliver\_sm with the source of "4321" and destination of "1234" with the text "test123".
|
||||||
|
|
||||||
|
#### Delivery Receipt (1.0)
|
||||||
|
|
||||||
|
The "most important" postprocessor for an smsc the delivery receipt postprocessor handles generating and sending delivery reports. You can read more about delivery reports in the Delivery Reports section.
|
||||||
|
|
||||||
|
---
|
||||||
|
## Delivery Reports
|
||||||
|
|
||||||
|
Upon receiving a submit_sm on the center whose "Delivery Receipt" postprocessor has been enabled it:
|
||||||
|
- Checks whether the pdus "registered_delivery" field is set
|
||||||
|
- Generates a delivery report in the form of `id:<messageId> sub:001 dlvrd:001 submit date:<date> done date:<date> stat:DELIVERD err:000 text:`
|
||||||
|
- The messageId here is the one id returned in the submit_sm_resp
|
||||||
|
- The date is simply the current date as of generation of the DR
|
||||||
|
- Sets the newly generated pdu esm class to 04
|
||||||
- Sends the pdu (delivery report) back to the client
|
- Sends the pdu (delivery report) back to the client
|
11
package.json
11
package.json
@@ -3,23 +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.2.5",
|
"@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",
|
||||||
"typescript": "^5.1.3",
|
"tsup": "^7.2.0",
|
||||||
|
"typescript": "^5.1.6",
|
||||||
"ws": "^8.13.0",
|
"ws": "^8.13.0",
|
||||||
"zlib": "^1.0.5"
|
"zlib": "^1.0.5"
|
||||||
}
|
}
|
||||||
|
1786
pnpm-lock.yaml
generated
1786
pnpm-lock.yaml
generated
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
|
||||||
|
}
|
||||||
|
]
|
@@ -1,212 +1,212 @@
|
|||||||
import {PDU} from "../CommonObjects";
|
import {PDU} from "../CommonObjects";
|
||||||
import Job from "../Job/Job";
|
import Job from "../Job/Job";
|
||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import PduProcessor from "../PDUProcessor/PduProcessor";
|
import PduProcessor from "../PDUProcessor/PduProcessor";
|
||||||
import BindTranscieverReplyProcessor from "../PDUProcessor/Postprocessor/Center/BindTranscieverReplyProcessor";
|
import BindTranscieverReplyProcessor from "../PDUProcessor/Postprocessor/Center/BindTranscieverReplyProcessor";
|
||||||
import EnquireLinkReplyProcessor from "../PDUProcessor/Postprocessor/Center/EnquireLinkReplyProcessor";
|
import EnquireLinkReplyProcessor from "../PDUProcessor/Postprocessor/Center/EnquireLinkReplyProcessor";
|
||||||
import SubmitSmReplyProcessor from "../PDUProcessor/Postprocessor/Center/SubmitSmReplyProcessor";
|
import SubmitSmReplyProcessor from "../PDUProcessor/Postprocessor/Center/SubmitSmReplyProcessor";
|
||||||
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
||||||
import SmppSession from "../SmppSession";
|
import SmppSession from "../SmppSession";
|
||||||
|
|
||||||
const NanoTimer = require('nanotimer');
|
const NanoTimer = require('nanotimer');
|
||||||
const smpp = require("smpp");
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import SessionManager from "../SessionManager";
|
import SessionManager from "../SessionManager";
|
||||||
import SmppSession from "../SmppSession";
|
import SmppSession from "../SmppSession";
|
||||||
import Center from "./Center";
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -1,283 +1,283 @@
|
|||||||
import {PDU} from "../CommonObjects";
|
import {PDU} from "../CommonObjects";
|
||||||
import Job from "../Job/Job";
|
import Job from "../Job/Job";
|
||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import PduProcessor from "../PDUProcessor/PduProcessor";
|
import PduProcessor from "../PDUProcessor/PduProcessor";
|
||||||
import DeliverSmReplyProcessor from "../PDUProcessor/Postprocessor/Client/DeliverSmReplyProcessor";
|
import DeliverSmReplyProcessor from "../PDUProcessor/Postprocessor/Client/DeliverSmReplyProcessor";
|
||||||
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
||||||
import PersistentPromise from "../PersistentPromise";
|
import PersistentPromise from "../PersistentPromise";
|
||||||
import SmppSession from "../SmppSession";
|
import SmppSession from "../SmppSession";
|
||||||
|
|
||||||
const NanoTimer = require('nanotimer');
|
const NanoTimer = require('nanotimer');
|
||||||
const smpp = require("smpp");
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import SessionManager from "../SessionManager";
|
import SessionManager from "../SessionManager";
|
||||||
import SmppSession from "../SmppSession";
|
import SmppSession from "../SmppSession";
|
||||||
import Client from "./Client";
|
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;
|
||||||
};
|
};
|
||||||
|
@@ -1,65 +1,65 @@
|
|||||||
import Center from "../Center/Center";
|
import Center from "../Center/Center";
|
||||||
import CenterSessionManager from "../Center/CenterSessionManager";
|
import CenterSessionManager from "../Center/CenterSessionManager";
|
||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import PduProcessor from "../PDUProcessor/PduProcessor";
|
import PduProcessor from "../PDUProcessor/PduProcessor";
|
||||||
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
||||||
import SessionManager from "../SessionManager";
|
import SessionManager from "../SessionManager";
|
||||||
import SmppSession from "../SmppSession";
|
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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,83 +1,83 @@
|
|||||||
import Client from "../Client/Client";
|
import Client from "../Client/Client";
|
||||||
import ClientSessionManager from "../Client/ClientSessionManager";
|
import ClientSessionManager from "../Client/ClientSessionManager";
|
||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import PduProcessor from "../PDUProcessor/PduProcessor";
|
import PduProcessor from "../PDUProcessor/PduProcessor";
|
||||||
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
import ProcessorManager from "../PDUProcessor/ProcessorManager";
|
||||||
import SessionManager from "../SessionManager";
|
import SessionManager from "../SessionManager";
|
||||||
import SmppSession from "../SmppSession";
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,86 +1,88 @@
|
|||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import SessionManager from "../SessionManager";
|
import SessionManager from "../SessionManager";
|
||||||
import CenterRequestHandler from "./CenterRequestHandler";
|
import CenterRequestHandler from "./CenterRequestHandler";
|
||||||
import ClientRequestHandler from "./ClientRequestHandler";
|
import ClientRequestHandler from "./ClientRequestHandler";
|
||||||
import RequestHandler from "./RequestHandler";
|
import RequestHandler from "./RequestHandler";
|
||||||
|
|
||||||
const express = require("express");
|
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 {
|
|
||||||
private readonly clientRequestHandler: RequestHandler;
|
export default class HttpServer {
|
||||||
private readonly centerRequestHandler: RequestHandler;
|
private readonly clientRequestHandler: RequestHandler;
|
||||||
|
private readonly centerRequestHandler: RequestHandler;
|
||||||
private app: any;
|
|
||||||
private server: any;
|
private app: any;
|
||||||
private readonly logger: Logger = new Logger(this.constructor.name);
|
private server: any;
|
||||||
|
private readonly logger: Logger = new Logger(this.constructor.name);
|
||||||
constructor(clientManager: SessionManager, centerManager: SessionManager) {
|
|
||||||
this.clientRequestHandler = new ClientRequestHandler(clientManager);
|
constructor(clientManager: SessionManager, centerManager: SessionManager) {
|
||||||
this.centerRequestHandler = new CenterRequestHandler(centerManager);
|
this.clientRequestHandler = new ClientRequestHandler(clientManager);
|
||||||
|
this.centerRequestHandler = new CenterRequestHandler(centerManager);
|
||||||
this.app = express();
|
|
||||||
this.app.use(bodyParser.json());
|
this.app = express();
|
||||||
|
this.app.use(cors());
|
||||||
this.app.use(compression({
|
this.app.use(bodyParser.json());
|
||||||
level: 9,
|
|
||||||
strategy: zlib.constants.BROTLI_MODE_TEXT,
|
this.app.use(compression({
|
||||||
}));
|
level: 9,
|
||||||
|
strategy: zlib.constants.BROTLI_MODE_TEXT,
|
||||||
let clientApiPath: string = 'ClientEntity';
|
}));
|
||||||
let centerApiPath: string = 'CenterEntity';
|
|
||||||
|
let clientApiPath: string = 'ClientEntity';
|
||||||
this.app.get(`/api/${clientApiPath}`, this.clientRequestHandler.doGet.bind(this.clientRequestHandler));
|
let centerApiPath: string = 'CenterEntity';
|
||||||
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.get(`/api/${clientApiPath}`, this.clientRequestHandler.doGet.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/send/default`, this.clientRequestHandler.doSendSingleJob.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}`, this.clientRequestHandler.doPost.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/send`, this.clientRequestHandler.doSend.bind(this.clientRequestHandler));
|
this.app.put(`/api/${clientApiPath}/:id/send`, this.clientRequestHandler.doConfigureSingleJob.bind(this.clientRequestHandler));
|
||||||
this.app.put(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doConfigureManyJob.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/send/default`, this.clientRequestHandler.doSendSingleJob.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/sendMany/default`, this.clientRequestHandler.doSendManyJob.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/send`, this.clientRequestHandler.doSend.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doSendMany.bind(this.clientRequestHandler));
|
this.app.put(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doConfigureManyJob.bind(this.clientRequestHandler));
|
||||||
this.app.delete(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doCancelSendMany.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/sendMany/default`, this.clientRequestHandler.doSendManyJob.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/bind`, this.clientRequestHandler.doBind.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doSendMany.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doConnect.bind(this.clientRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id/sendMany`, this.clientRequestHandler.doCancelSendMany.bind(this.clientRequestHandler));
|
||||||
this.app.delete(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doDisconnect.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/bind`, this.clientRequestHandler.doBind.bind(this.clientRequestHandler));
|
||||||
this.app.get(`/api/${clientApiPath}/processors`, this.clientRequestHandler.doGetAvailableProcessors.bind(this.clientRequestHandler));
|
this.app.post(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doConnect.bind(this.clientRequestHandler));
|
||||||
this.app.get(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doGetAppliedProcessors.bind(this.clientRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id/connect`, this.clientRequestHandler.doDisconnect.bind(this.clientRequestHandler));
|
||||||
this.app.post(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doAddProcessor.bind(this.clientRequestHandler));
|
this.app.get(`/api/${clientApiPath}/processors`, this.clientRequestHandler.doGetAvailableProcessors.bind(this.clientRequestHandler));
|
||||||
this.app.delete(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doRemoveProcessor.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.get(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doGetById.bind(this.clientRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id/processors`, this.clientRequestHandler.doRemoveProcessor.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.get(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doGetById.bind(this.clientRequestHandler));
|
||||||
|
this.app.patch(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doPatch.bind(this.clientRequestHandler));
|
||||||
this.app.get(`/api/${centerApiPath}`, this.centerRequestHandler.doGet.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${clientApiPath}/:id`, this.clientRequestHandler.doDelete.bind(this.clientRequestHandler));
|
||||||
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.get(`/api/${centerApiPath}`, this.centerRequestHandler.doGet.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/send/default`, this.centerRequestHandler.doSendSingleJob.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}`, this.centerRequestHandler.doPost.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/send`, this.centerRequestHandler.doSend.bind(this.centerRequestHandler));
|
this.app.put(`/api/${centerApiPath}/:id/send`, this.centerRequestHandler.doConfigureSingleJob.bind(this.centerRequestHandler));
|
||||||
this.app.put(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doConfigureManyJob.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/send/default`, this.centerRequestHandler.doSendSingleJob.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/sendMany/default`, this.centerRequestHandler.doSendManyJob.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/send`, this.centerRequestHandler.doSend.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doSendMany.bind(this.centerRequestHandler));
|
this.app.put(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doConfigureManyJob.bind(this.centerRequestHandler));
|
||||||
this.app.delete(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doCancelSendMany.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/sendMany/default`, this.centerRequestHandler.doSendManyJob.bind(this.centerRequestHandler));
|
||||||
this.app.delete(`/api/${centerApiPath}/:id/connect`, this.centerRequestHandler.doDisconnect.bind(this.centerRequestHandler));
|
this.app.post(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doSendMany.bind(this.centerRequestHandler));
|
||||||
this.app.get(`/api/${centerApiPath}/processors`, this.centerRequestHandler.doGetAvailableProcessors.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${centerApiPath}/:id/sendMany`, this.centerRequestHandler.doCancelSendMany.bind(this.centerRequestHandler));
|
||||||
this.app.get(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doGetAppliedProcessors.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${centerApiPath}/:id/connect`, this.centerRequestHandler.doDisconnect.bind(this.centerRequestHandler));
|
||||||
this.app.post(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doAddProcessor.bind(this.centerRequestHandler));
|
this.app.get(`/api/${centerApiPath}/processors`, this.centerRequestHandler.doGetAvailableProcessors.bind(this.centerRequestHandler));
|
||||||
this.app.delete(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doRemoveProcessor.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.get(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doGetById.bind(this.centerRequestHandler));
|
this.app.delete(`/api/${centerApiPath}/:id/processors`, this.centerRequestHandler.doRemoveProcessor.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.get(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doGetById.bind(this.centerRequestHandler));
|
||||||
|
this.app.patch(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doPatch.bind(this.centerRequestHandler));
|
||||||
this.app.get('/api/ping', function (req: any, res: any) {
|
this.app.delete(`/api/${centerApiPath}/:id`, this.centerRequestHandler.doDelete.bind(this.centerRequestHandler));
|
||||||
res.send('pong');
|
|
||||||
});
|
this.app.get('/api/ping', function (req: any, res: any) {
|
||||||
|
res.send('pong');
|
||||||
this.server = this.app.listen(SERVER_PORT, function () {
|
});
|
||||||
// @ts-ignore
|
|
||||||
this.logger.log1(`HTTPServer listening at http://localhost:${SERVER_PORT}`)
|
this.server = this.app.listen(SERVER_PORT, function () {
|
||||||
}.bind(this));
|
// @ts-ignore
|
||||||
}
|
this.logger.log1(`HTTPServer listening at http://localhost:${SERVER_PORT}`)
|
||||||
}
|
}.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,159 +1,159 @@
|
|||||||
import Job from "../Job/Job";
|
import Job from "../Job/Job";
|
||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import SessionManager from "../SessionManager";
|
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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
210
src/Job/Job.ts
210
src/Job/Job.ts
@@ -1,105 +1,105 @@
|
|||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import {PDU, SerializedJob} from "../CommonObjects";
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
136
src/Logger.ts
136
src/Logger.ts
@@ -1,68 +1,68 @@
|
|||||||
import {WriteStream} from "fs";
|
import {WriteStream} from "fs";
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const LOG_LEVEL: number = Number(process.env.LOG_LEVEL) || 0;
|
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}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,37 +1,37 @@
|
|||||||
import Logger from "../Logger";
|
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;
|
}
|
||||||
}
|
|
||||||
|
serialize(): object {
|
||||||
protected abstract doProcess(session: any, pdu: any, entity?: SmppSession | undefined): any;
|
return {
|
||||||
|
servesSessionType: this.sessionType,
|
||||||
processPdu(session: any, pdu: any, entity?: SmppSession | undefined): any {
|
name: this.name,
|
||||||
if (this.pduDoesApply(pdu)) {
|
type: this.type
|
||||||
return this.doProcess(session, pdu, entity);
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
protected pduDoesApply(pdu: any): boolean {
|
||||||
serialize(): object {
|
if (pdu.command) {
|
||||||
return {
|
return this.applicableCommands.includes(pdu.command);
|
||||||
servesSessionType: this.sessionType,
|
}
|
||||||
name: this.name,
|
return false;
|
||||||
type: this.type
|
}
|
||||||
};
|
|
||||||
}
|
protected abstract doProcess(session: any, pdu: any, entity?: SmppSession | undefined): any;
|
||||||
}
|
}
|
||||||
|
@@ -1,45 +1,45 @@
|
|||||||
import Center from "../../../Center/Center";
|
import Center from "../../../Center/Center";
|
||||||
import Postprocessor from "../Postprocessor";
|
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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,43 +1,49 @@
|
|||||||
import MessageIdManager from "../../../MessageIdManager";
|
import MessageIdManager from "../../../MessageIdManager";
|
||||||
import SmppSession from "../../../SmppSession";
|
import SmppSession from "../../../SmppSession";
|
||||||
import Postprocessor from "../Postprocessor";
|
import Postprocessor from "../Postprocessor";
|
||||||
|
|
||||||
const smpp = require("smpp");
|
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);
|
constructor(type: string) {
|
||||||
}
|
super(type);
|
||||||
|
}
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
|
||||||
return new Promise<any>((resolve, reject) => {
|
sleep(ms: number) {
|
||||||
if (pdu.registered_delivery) {
|
return new Promise((resolve) => {
|
||||||
let drMessage: string = "";
|
setTimeout(resolve, ms);
|
||||||
let date: string = new Date().toISOString().replace(/T/, '').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').substring(2, 12);
|
});
|
||||||
|
}
|
||||||
let relatedMessageId: number | undefined = MessageIdManager.getMessageId(pdu);
|
|
||||||
if (relatedMessageId) {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
drMessage += "id:" + relatedMessageId + " ";
|
return new Promise<any>((resolve, reject) => {
|
||||||
drMessage += "sub:001 ";
|
let drMessage: string = "";
|
||||||
drMessage += "dlvrd:001 ";
|
let date: string = new Date().toISOString().replace(/T/, '').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').substring(2, 12);
|
||||||
drMessage += "submit date:" + date + " ";
|
|
||||||
drMessage += "done date:" + date + " ";
|
let relatedMessageId: number | undefined = MessageIdManager.getMessageId(pdu);
|
||||||
drMessage += "stat:DELIVRD ";
|
if (relatedMessageId) {
|
||||||
drMessage += "err:000 ";
|
drMessage += "id:" + relatedMessageId + " ";
|
||||||
drMessage += "text:";
|
drMessage += "sub:001 ";
|
||||||
|
drMessage += "dlvrd:001 ";
|
||||||
let DRPdu = new smpp.PDU('deliver_sm', {
|
drMessage += "submit date:" + date + " ";
|
||||||
source_addr: pdu.source_addr,
|
drMessage += "done date:" + date + " ";
|
||||||
destination_addr: pdu.destination_addr,
|
drMessage += "stat:DELIVRD ";
|
||||||
short_message: drMessage,
|
drMessage += "err:000 ";
|
||||||
esm_class: 4,
|
drMessage += "text:";
|
||||||
});
|
|
||||||
entity?.doSendPdu(DRPdu, session);
|
let sleepTime = 0;
|
||||||
|
let DRPdu = new smpp.PDU('deliver_sm', {
|
||||||
resolve(pdu);
|
source_addr: pdu.source_addr,
|
||||||
}
|
destination_addr: pdu.destination_addr,
|
||||||
}
|
short_message: drMessage,
|
||||||
});
|
esm_class: 4,
|
||||||
}
|
});
|
||||||
}
|
setTimeout(() => entity?.doSendPdu(DRPdu, session), sleepTime);
|
||||||
|
|
||||||
|
resolve(pdu);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,24 +1,25 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import SmppSession from "../../../SmppSession";
|
||||||
import Postprocessor from "../Postprocessor";
|
import Postprocessor from "../Postprocessor";
|
||||||
|
|
||||||
const smpp = require("smpp");
|
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);
|
constructor(type: string) {
|
||||||
}
|
super(type);
|
||||||
|
}
|
||||||
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
|
||||||
return new Promise<any>((resolve, reject) => {
|
protected doProcess(session: any, pdu: any, entity?: SmppSession | undefined): Promise<any> {
|
||||||
// Temporary (?) safeguard against echoing long sms
|
return new Promise<any>((resolve, reject) => {
|
||||||
if (!pdu.short_message.udh) {
|
// Temporary (?) safeguard against echoing long sms
|
||||||
let echoPdu = new smpp.PDU('deliver_sm', {...pdu});
|
if (!pdu.short_message.udh) {
|
||||||
echoPdu.source_addr = pdu.destination_addr;
|
let echoPdu = new smpp.PDU('deliver_sm', {...pdu});
|
||||||
echoPdu.destination_addr = pdu.source_addr;
|
echoPdu.source_addr = pdu.destination_addr;
|
||||||
entity?.doSendPdu(echoPdu, session);
|
echoPdu.destination_addr = pdu.source_addr;
|
||||||
resolve(echoPdu);
|
entity?.doSendPdu(echoPdu, session);
|
||||||
}
|
resolve(echoPdu);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,22 +1,22 @@
|
|||||||
import MessageIdManager from "../../../MessageIdManager";
|
import MessageIdManager from "../../../MessageIdManager";
|
||||||
import SmppSession from "../../../SmppSession";
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,23 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import SmppSession from "../../../SmppSession";
|
||||||
import Preprocessor from "../Preprocessor";
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,40 +1,40 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import {PDU} from "../../../CommonObjects";
|
||||||
import Preprocessor from "../Preprocessor";
|
import SmppSession from "../../../SmppSession";
|
||||||
import {PDU} from "../../../CommonObjects";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class DestinationSetPreprocessor extends Preprocessor {
|
export default class DestinationSetPreprocessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
private sourceSet: string[] = [];
|
private sourceSet: string[] = [];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
while (this.sourceSet.length < 100) {
|
while (this.sourceSet.length < 100) {
|
||||||
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
if (pdu.short_message.includes("arg:")) {
|
if (pdu.short_message.includes("arg:")) {
|
||||||
let temp: string = pdu.short_message.split(";");
|
let temp: string = pdu.short_message.split(";");
|
||||||
let arg: number = Number(temp[0].split(":")[1]);
|
let arg: number = Number(temp[0].split(":")[1]);
|
||||||
while (this.sourceSet.length < arg) {
|
while (this.sourceSet.length < arg) {
|
||||||
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
}
|
}
|
||||||
while (this.sourceSet.length > arg) {
|
while (this.sourceSet.length > arg) {
|
||||||
this.sourceSet.pop();
|
this.sourceSet.pop();
|
||||||
}
|
}
|
||||||
pdu.short_message = temp[1];
|
pdu.short_message = temp[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pdu.destination_addr = pdu.destination_addr + this.sourceSet[this.getRandomInt(0, this.sourceSet.length)];
|
pdu.destination_addr = pdu.destination_addr + this.sourceSet[this.getRandomInt(0, this.sourceSet.length)];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRandomInt(min: number, max: number): number {
|
private getRandomInt(min: number, max: number): number {
|
||||||
min = Math.ceil(min);
|
min = Math.ceil(min);
|
||||||
max = Math.floor(max);
|
max = Math.floor(max);
|
||||||
return Math.floor(Math.random() * (max - min) + min);
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -1,87 +1,87 @@
|
|||||||
import {PDU} from "../../../CommonObjects";
|
import {PDU} from "../../../CommonObjects";
|
||||||
import SmppSession from "../../../SmppSession";
|
import SmppSession from "../../../SmppSession";
|
||||||
import Preprocessor from "../Preprocessor";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
const smpp = require('smpp');
|
const smpp = require('smpp');
|
||||||
|
|
||||||
export default class LongSmsProcessor extends Preprocessor {
|
export default class LongSmsProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
static readonly maxMessageSizeBits = 1072;
|
||||||
static readonly maxMessageSizeBits = 1072;
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import SmppSession from "../../../SmppSession";
|
||||||
import Preprocessor from "../Preprocessor";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class ProtocolId2DigitProcessor extends Preprocessor {
|
export default class ProtocolId2DigitProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', '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<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
pdu.protocol_id = 16;
|
pdu.protocol_id = 16;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import SmppSession from "../../../SmppSession";
|
||||||
import Preprocessor from "../Preprocessor";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class ProtocolId3DigitProcessor extends Preprocessor {
|
export default class ProtocolId3DigitProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', '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<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
pdu.protocol_id = 2048;
|
pdu.protocol_id = 128;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import {PDU} from "../../../CommonObjects";
|
||||||
import Preprocessor from "../Preprocessor";
|
import SmppSession from "../../../SmppSession";
|
||||||
import {PDU} from "../../../CommonObjects";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class ProtocolId4DigitProcessor extends Preprocessor {
|
export default class ProtocolId4DigitProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) => {
|
||||||
pdu.data_coding = 2048;
|
pdu.data_coding = 2048;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import SmppSession from "../../../SmppSession";
|
||||||
import Preprocessor from "../Preprocessor";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class ProtocolIdProcessor extends Preprocessor {
|
export default class ProtocolIdProcessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', '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<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
pdu.protocol_id = 4;
|
pdu.protocol_id = 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,23 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,40 +1,40 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import {PDU} from "../../../CommonObjects";
|
||||||
import Preprocessor from "../Preprocessor";
|
import SmppSession from "../../../SmppSession";
|
||||||
import {PDU} from "../../../CommonObjects";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class SourceSetPreprocessor extends Preprocessor {
|
export default class SourceSetPreprocessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
private sourceSet: string[] = [];
|
private sourceSet: string[] = [];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
while (this.sourceSet.length < 100) {
|
while (this.sourceSet.length < 100) {
|
||||||
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
if (pdu.short_message.includes("arg:")) {
|
if (pdu.short_message.includes("arg:")) {
|
||||||
let temp: string = pdu.short_message.split(";");
|
let temp: string = pdu.short_message.split(";");
|
||||||
let arg: number = Number(temp[0].split(":")[1]);
|
let arg: number = Number(temp[0].split(":")[1]);
|
||||||
while (this.sourceSet.length < arg) {
|
while (this.sourceSet.length < arg) {
|
||||||
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
this.sourceSet.push(this.getRandomInt(100000, 999999).toString());
|
||||||
}
|
}
|
||||||
while (this.sourceSet.length > arg) {
|
while (this.sourceSet.length > arg) {
|
||||||
this.sourceSet.pop();
|
this.sourceSet.pop();
|
||||||
}
|
}
|
||||||
pdu.short_message = temp[1];
|
pdu.short_message = temp[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pdu.source_addr = pdu.source_addr + this.sourceSet[this.getRandomInt(0, this.sourceSet.length)];
|
pdu.source_addr = pdu.source_addr + this.sourceSet[this.getRandomInt(0, this.sourceSet.length)];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRandomInt(min: number, max: number): number {
|
private getRandomInt(min: number, max: number): number {
|
||||||
min = Math.ceil(min);
|
min = Math.ceil(min);
|
||||||
max = Math.floor(max);
|
max = Math.floor(max);
|
||||||
return Math.floor(Math.random() * (max - min) + min);
|
return Math.floor(Math.random() * (max - min) + min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
import SmppSession from "../../../SmppSession";
|
import {PDU} from "../../../CommonObjects";
|
||||||
import Preprocessor from "../Preprocessor";
|
import SmppSession from "../../../SmppSession";
|
||||||
import {PDU} from "../../../CommonObjects";
|
import Preprocessor from "../Preprocessor";
|
||||||
|
|
||||||
export default class UCS2Preprocessor extends Preprocessor {
|
export default class UCS2Preprocessor extends Preprocessor {
|
||||||
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
applicableCommands: string[] = ['submit_sm', 'deliver_sm'];
|
||||||
|
|
||||||
constructor(type: string) {
|
constructor(type: string) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) => {
|
||||||
pdu.data_coding = 8;
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -1,131 +1,131 @@
|
|||||||
import Center from "../Center/Center";
|
import Center from "../Center/Center";
|
||||||
import Client from "../Client/Client";
|
import Client from "../Client/Client";
|
||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import SmppSession from "../SmppSession";
|
import SmppSession from "../SmppSession";
|
||||||
import PduProcessor from "./PduProcessor";
|
import PduProcessor from "./PduProcessor";
|
||||||
import BindTranscieverReplyProcessor from "./Postprocessor/Center/BindTranscieverReplyProcessor";
|
import BindTranscieverReplyProcessor from "./Postprocessor/Center/BindTranscieverReplyProcessor";
|
||||||
import DeliveryReceiptProcessor from "./Postprocessor/Center/DeliveryReceiptProcessor";
|
import DeliveryReceiptProcessor from "./Postprocessor/Center/DeliveryReceiptProcessor";
|
||||||
import EchoPduProcessor from "./Postprocessor/Center/EchoPduProcessor";
|
import EchoPduProcessor from "./Postprocessor/Center/EchoPduProcessor";
|
||||||
import EnquireLinkReplyProcessor from "./Postprocessor/Center/EnquireLinkReplyProcessor";
|
import EnquireLinkReplyProcessor from "./Postprocessor/Center/EnquireLinkReplyProcessor";
|
||||||
import SubmitSmReplyProcessor from "./Postprocessor/Center/SubmitSmReplyProcessor";
|
import SubmitSmReplyProcessor from "./Postprocessor/Center/SubmitSmReplyProcessor";
|
||||||
import DeliverSmReplyProcessor from "./Postprocessor/Client/DeliverSmReplyProcessor";
|
import DeliverSmReplyProcessor from "./Postprocessor/Client/DeliverSmReplyProcessor";
|
||||||
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 LongSmsProcessor from "./Preprocessor/Client/LongSmsProcessor";
|
import DestinationSetPreprocessor from "./Preprocessor/Client/DestinationSetPreprocessor";
|
||||||
import SourceEnumeratorProcessor from "./Preprocessor/Client/SourceEnumeratorProcessor";
|
import GSM0338Preprocessor from "./Preprocessor/Client/GSM0338Preprocessor";
|
||||||
import Preprocessor from "./Preprocessor/Preprocessor";
|
import LongSmsProcessor from "./Preprocessor/Client/LongSmsProcessor";
|
||||||
import ProtocolIdProcessor from "./Preprocessor/Client/ProtocolIdProcessor";
|
import ProtocolId2DigitProcessor from "./Preprocessor/Client/ProtocolId-2Digit-Processor";
|
||||||
import UCS2Preprocessor from "./Preprocessor/Client/UCS2Preprocessor";
|
import ProtocolId3DigitProcessor from "./Preprocessor/Client/ProtocolId-3Digit-Processor";
|
||||||
import ProtocolId2DigitProcessor from "./Preprocessor/Client/ProtocolId-2Digit-Processor";
|
import ProtocolIdProcessor from "./Preprocessor/Client/ProtocolIdProcessor";
|
||||||
import ProtocolId3DigitProcessor from "./Preprocessor/Client/ProtocolId-3Digit-Processor";
|
import SourceEnumeratorProcessor from "./Preprocessor/Client/SourceEnumeratorProcessor";
|
||||||
import ProtocolId4DigitProcessor from "./Preprocessor/Client/ProtocolId-4Digit-Processor";
|
import SourceSetPreprocessor from "./Preprocessor/Client/SourceSetPreprocessor";
|
||||||
import SourceSetPreprocessor from "./Preprocessor/Client/SourceSetPreprocessor";
|
import UCS2Preprocessor from "./Preprocessor/Client/UCS2Preprocessor";
|
||||||
import DestinationSetPreprocessor from "./Preprocessor/Client/DestinationSetPreprocessor";
|
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 LongSmsProcessor(Center.name),
|
||||||
new ProtocolIdProcessor(Client.name),
|
new ProtocolIdProcessor(Client.name),
|
||||||
new ProtocolIdProcessor(Center.name),
|
new ProtocolIdProcessor(Center.name),
|
||||||
new UCS2Preprocessor(Client.name),
|
new UCS2Preprocessor(Client.name),
|
||||||
new UCS2Preprocessor(Center.name),
|
new UCS2Preprocessor(Center.name),
|
||||||
new ProtocolId2DigitProcessor(Client.name),
|
new ProtocolId2DigitProcessor(Client.name),
|
||||||
new ProtocolId2DigitProcessor(Center.name),
|
new ProtocolId2DigitProcessor(Center.name),
|
||||||
new ProtocolId3DigitProcessor(Client.name),
|
new ProtocolId3DigitProcessor(Client.name),
|
||||||
new ProtocolId3DigitProcessor(Center.name),
|
new ProtocolId3DigitProcessor(Center.name),
|
||||||
new ProtocolId4DigitProcessor(Client.name),
|
new SourceSetPreprocessor(Client.name),
|
||||||
new ProtocolId4DigitProcessor(Center.name),
|
new SourceSetPreprocessor(Center.name),
|
||||||
new SourceSetPreprocessor(Client.name),
|
new DestinationSetPreprocessor(Client.name),
|
||||||
new SourceSetPreprocessor(Center.name),
|
new DestinationSetPreprocessor(Center.name),
|
||||||
new DestinationSetPreprocessor(Client.name),
|
new GSM0338Preprocessor(Client.name),
|
||||||
new DestinationSetPreprocessor(Center.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,144 +1,144 @@
|
|||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import Job from "./Job/Job";
|
import Job from "./Job/Job";
|
||||||
import Logger from "./Logger";
|
import Logger from "./Logger";
|
||||||
import PduProcessor from "./PDUProcessor/PduProcessor";
|
import PduProcessor from "./PDUProcessor/PduProcessor";
|
||||||
import ProcessorManager from "./PDUProcessor/ProcessorManager";
|
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`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,246 +1,246 @@
|
|||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import {PDU, WSMessage} from "./CommonObjects";
|
import {PDU, WSMessage} from "./CommonObjects";
|
||||||
import Job from "./Job/Job";
|
import Job from "./Job/Job";
|
||||||
import Logger from "./Logger";
|
import Logger from "./Logger";
|
||||||
import PduProcessor from "./PDUProcessor/PduProcessor";
|
import PduProcessor from "./PDUProcessor/PduProcessor";
|
||||||
import Postprocessor from "./PDUProcessor/Postprocessor/Postprocessor";
|
import Postprocessor from "./PDUProcessor/Postprocessor/Postprocessor";
|
||||||
import LongSmsProcessor from "./PDUProcessor/Preprocessor/Client/LongSmsProcessor";
|
import LongSmsProcessor from "./PDUProcessor/Preprocessor/Client/LongSmsProcessor";
|
||||||
import Preprocessor from "./PDUProcessor/Preprocessor/Preprocessor";
|
import Preprocessor from "./PDUProcessor/Preprocessor/Preprocessor";
|
||||||
import ProcessorManager from "./PDUProcessor/ProcessorManager";
|
import ProcessorManager from "./PDUProcessor/ProcessorManager";
|
||||||
|
|
||||||
const NanoTimer = require("nanotimer");
|
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`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,74 +1,74 @@
|
|||||||
import {WSMessage} from "../CommonObjects";
|
import {WSMessage} from "../CommonObjects";
|
||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import SessionManager from "../SessionManager";
|
import SessionManager from "../SessionManager";
|
||||||
import SmppSession from "../SmppSession";
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,51 +1,51 @@
|
|||||||
import Logger from "../Logger";
|
import Logger from "../Logger";
|
||||||
import SessionManager from "../SessionManager";
|
import SessionManager from "../SessionManager";
|
||||||
import ClientSet from "./ClientSet";
|
import ClientSet from "./ClientSet";
|
||||||
|
|
||||||
const WebSocket = require("ws");
|
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);
|
58
src/main.ts
58
src/main.ts
@@ -1,29 +1,29 @@
|
|||||||
import CenterSessionManager from "./Center/CenterSessionManager";
|
import CenterSessionManager from "./Center/CenterSessionManager";
|
||||||
import ClientSessionManager from "./Client/ClientSessionManager";
|
import ClientSessionManager from "./Client/ClientSessionManager";
|
||||||
import HttpServer from "./HttpServer/HttpServer";
|
import HttpServer from "./HttpServer/HttpServer";
|
||||||
import Logger from "./Logger";
|
import Logger from "./Logger";
|
||||||
import ProcessorManager from "./PDUProcessor/ProcessorManager";
|
import ProcessorManager from "./PDUProcessor/ProcessorManager";
|
||||||
import WSServer from "./WS/WSServer";
|
import WSServer from "./WS/WSServer";
|
||||||
|
|
||||||
const {PDU} = require("smpp");
|
const {PDU} = require("smpp");
|
||||||
|
|
||||||
let logger: Logger = new Logger("main");
|
let logger: Logger = new Logger("main");
|
||||||
|
|
||||||
let pm: ProcessorManager = new ProcessorManager();
|
let pm: ProcessorManager = new ProcessorManager();
|
||||||
let clientManager: ClientSessionManager = new ClientSessionManager();
|
let clientManager: ClientSessionManager = new ClientSessionManager();
|
||||||
let centerManager: CenterSessionManager = new CenterSessionManager();
|
let centerManager: CenterSessionManager = new CenterSessionManager();
|
||||||
|
|
||||||
let wss: WSServer = new WSServer([clientManager, centerManager]);
|
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);
|
||||||
// process.on('SIGINT', cleanup);
|
process.on('SIGINT', cleanup);
|
||||||
// process.on('SIGUSR1', cleanup);
|
process.on('SIGUSR1', cleanup);
|
||||||
// process.on('SIGUSR2', cleanup);
|
process.on('SIGUSR2', 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",
|
||||||
"esModuleInterop": true,
|
"target": "ESNext",
|
||||||
"noImplicitAny": true,
|
|
||||||
},
|
"esModuleInterop": true,
|
||||||
"exclude": [
|
"noEmit": true
|
||||||
"./node_modules"
|
},
|
||||||
]
|
"include": ["src/**/*", "src/main.ts"]
|
||||||
}
|
}
|
||||||
|
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']
|
||||||
|
});
|
120
websocketTest.js
120
websocketTest.js
@@ -1,61 +1,61 @@
|
|||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
|
|
||||||
const WS_SERVER_PORT = process.env.WS_SERVER_PORT || 8191;
|
const WS_SERVER_PORT = process.env.WS_SERVER_PORT || 8191;
|
||||||
|
|
||||||
class Metrics {
|
class Metrics {
|
||||||
static interestingMetrics = [
|
static interestingMetrics = [
|
||||||
'submit_sm',
|
'submit_sm',
|
||||||
'deliver_sm'
|
'deliver_sm'
|
||||||
];
|
];
|
||||||
metrics = {};
|
metrics = {};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
processPdu(pdu) {
|
processPdu(pdu) {
|
||||||
if (Metrics.interestingMetrics.indexOf(pdu.command) !== -1) {
|
if (Metrics.interestingMetrics.indexOf(pdu.command) !== -1) {
|
||||||
let timestamp = Math.floor(new Date().getTime() / 1000);
|
let timestamp = Math.floor(new Date().getTime() / 1000);
|
||||||
|
|
||||||
if (!!!this.metrics[timestamp]) {
|
if (!!!this.metrics[timestamp]) {
|
||||||
this.metrics[timestamp] = {};
|
this.metrics[timestamp] = {};
|
||||||
}
|
}
|
||||||
if (!!!this.metrics[timestamp][pdu.command]) {
|
if (!!!this.metrics[timestamp][pdu.command]) {
|
||||||
this.metrics[timestamp][pdu.command] = 0;
|
this.metrics[timestamp][pdu.command] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.metrics[timestamp][pdu.command] += 1;
|
this.metrics[timestamp][pdu.command] += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let clientMetrics = new Metrics();
|
let clientMetrics = new Metrics();
|
||||||
let centerMetrics = new Metrics();
|
let centerMetrics = new Metrics();
|
||||||
|
|
||||||
const ws = new WebSocket(`ws://localhost:${WS_SERVER_PORT}`);
|
const ws = new WebSocket(`ws://localhost:${WS_SERVER_PORT}`);
|
||||||
ws.on('open', () => {
|
ws.on('open', () => {
|
||||||
console.log('WebSocket connection established');
|
console.log('WebSocket connection established');
|
||||||
ws.send("client:0");
|
ws.send("client:0");
|
||||||
});
|
});
|
||||||
ws.on('message', (data) => {
|
ws.on('message', (data) => {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
const ws2 = new WebSocket(`ws://localhost:${WS_SERVER_PORT}`);
|
const ws2 = new WebSocket(`ws://localhost:${WS_SERVER_PORT}`);
|
||||||
ws2.on('open', () => {
|
ws2.on('open', () => {
|
||||||
console.log('WebSocket connection established');
|
console.log('WebSocket connection established');
|
||||||
ws2.send("center:0");
|
ws2.send("center:0");
|
||||||
});
|
});
|
||||||
ws2.on('message', (data) => {
|
ws2.on('message', (data) => {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
// if (data.type === 'pdu') {
|
// if (data.type === 'pdu') {
|
||||||
// centerMetrics.processPdu(data.value);
|
// centerMetrics.processPdu(data.value);
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
|
||||||
// setInterval(() => {
|
// setInterval(() => {
|
||||||
// console.log(clientMetrics.metrics);
|
// console.log(clientMetrics.metrics);
|
||||||
// // console.log(centerMetrics.metrics);
|
// // console.log(centerMetrics.metrics);
|
||||||
// console.log("");
|
// console.log("");
|
||||||
// }, 500);
|
// }, 500);
|
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