This commit is contained in:
PhatPhuckDave
2024-07-22 19:52:53 +02:00
parent a18ac0355c
commit 4a5aa484ba
57 changed files with 4213 additions and 3046 deletions

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@ client_sessions.json
center_sessions.json center_sessions.json
dist dist
main.exe main.exe
.run
.vscode
build

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"tabWidth": 4,
"useTabs": true
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
View File

@@ -0,0 +1,10 @@
FROM ubuntu:22.04
WORKDIR /app
COPY "./main.exe/" "./"
EXPOSE 6555
EXPOSE 6556
ENTRYPOINT "./main.exe"

View File

@@ -70,10 +70,37 @@ With this preprocessor enabled the messages body is chopped up into segments bas
**With this preprocessor disabled any message whose body exceeds the maximum smpp message size is truncated to size**. **With this preprocessor disabled any message whose body exceeds the maximum smpp message size is truncated to size**.
#### Protocol ID (+2/3 Digit Versions) (1.2)
This processor sets the protocol_id field to a value.
The basic one (ProtocolIdProcessor) sets the value to 1, 2Digit version to 16 and 3Digit version to 128.
#### Source/Destination Set Processor
Generates X random numbers that are then used for sending Y messages.
The interface with this processor is somewhat specific: To specify the amount of msisdns generated prepend "arg:X;" to the message body.
Example: message "arg:100;test123" generates 100 msisdns and sends messages with the body of "test123".
The point of this processor is to generate a set of msisdns to use with a greater number of messages.
For example sending 100k messages from 100 msisdns (effectively sending 100 messages per msisdn) to simulate 100 users.
Note, the picked msisdn per message is random (from the generated set).
### Center Preprocessors ### Center Preprocessors
None as of 1.0 #### Destination & Source Enumerator (1.2)
Same as the Client version.
#### Long SMS (1.2)
Same as the Client version.
#### Protocol ID (+2/3 Digit Versions) (1.2)
Same as the Client version.
#### Source/Destination Set Processor (1.2)
Same as the Client version.
### Client Postprocessors ### Client Postprocessors

View File

@@ -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"
} }

1736
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

32
smpp_tester_options.json Normal file
View 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
}
]

View File

@@ -83,10 +83,10 @@ export default class Center extends SmppSession {
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);
}); });

View File

@@ -8,6 +8,7 @@ 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;
@@ -24,6 +25,7 @@ export default class HttpServer {
this.centerRequestHandler = new CenterRequestHandler(centerManager); this.centerRequestHandler = new CenterRequestHandler(centerManager);
this.app = express(); this.app = express();
this.app.use(cors());
this.app.use(bodyParser.json()); this.app.use(bodyParser.json());
this.app.use(compression({ this.app.use(compression({

View File

@@ -12,15 +12,6 @@ export default abstract class PduProcessor {
this.sessionType = type; this.sessionType = type;
} }
protected pduDoesApply(pdu: any): boolean {
if (pdu.command) {
return this.applicableCommands.includes(pdu.command);
}
return false;
}
protected abstract doProcess(session: any, pdu: any, entity?: SmppSession | undefined): any;
processPdu(session: any, pdu: any, entity?: SmppSession | undefined): any { processPdu(session: any, pdu: any, entity?: SmppSession | undefined): any {
if (this.pduDoesApply(pdu)) { if (this.pduDoesApply(pdu)) {
return this.doProcess(session, pdu, entity); return this.doProcess(session, pdu, entity);
@@ -34,4 +25,13 @@ export default abstract class PduProcessor {
type: this.type type: this.type
}; };
} }
protected pduDoesApply(pdu: any): boolean {
if (pdu.command) {
return this.applicableCommands.includes(pdu.command);
}
return false;
}
protected abstract doProcess(session: any, pdu: any, entity?: SmppSession | undefined): any;
} }

View File

@@ -25,7 +25,7 @@ export default class BindTranscieverReplyProcessor extends Postprocessor {
} }
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 {
@@ -36,7 +36,7 @@ export default class BindTranscieverReplyProcessor extends Postprocessor {
}), 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();
} }

View File

@@ -6,13 +6,19 @@ 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) { constructor(type: string) {
super(type); super(type);
} }
sleep(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
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.registered_delivery) {
let drMessage: string = ""; let drMessage: string = "";
let date: string = new Date().toISOString().replace(/T/, '').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').substring(2, 12); let date: string = new Date().toISOString().replace(/T/, '').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').substring(2, 12);
@@ -27,17 +33,17 @@ export default class DeliveryReceiptProcessor extends Postprocessor {
drMessage += "err:000 "; drMessage += "err:000 ";
drMessage += "text:"; drMessage += "text:";
let sleepTime = 0;
let DRPdu = new smpp.PDU('deliver_sm', { let DRPdu = new smpp.PDU('deliver_sm', {
source_addr: pdu.source_addr, source_addr: pdu.source_addr,
destination_addr: pdu.destination_addr, destination_addr: pdu.destination_addr,
short_message: drMessage, short_message: drMessage,
esm_class: 4, esm_class: 4,
}); });
entity?.doSendPdu(DRPdu, session); setTimeout(() => entity?.doSendPdu(DRPdu, session), sleepTime);
resolve(pdu); resolve(pdu);
} }
}
}); });
} }
} }

View File

@@ -5,6 +5,7 @@ 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) { constructor(type: string) {
super(type); super(type);
} }

View File

@@ -1,6 +1,6 @@
import {PDU} from "../../../CommonObjects";
import SmppSession from "../../../SmppSession"; import SmppSession from "../../../SmppSession";
import Preprocessor from "../Preprocessor"; import Preprocessor from "../Preprocessor";
import {PDU} from "../../../CommonObjects";
export default class DestinationSetPreprocessor extends Preprocessor { export default class DestinationSetPreprocessor extends Preprocessor {
applicableCommands: string[] = ['submit_sm', 'deliver_sm']; applicableCommands: string[] = ['submit_sm', 'deliver_sm'];

View 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;
});
}
}

View File

@@ -5,8 +5,8 @@ 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) {

View File

@@ -10,7 +10,7 @@ export default class ProtocolId3DigitProcessor extends Preprocessor {
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;
}); });
} }
} }

View File

@@ -1,6 +1,6 @@
import {PDU} from "../../../CommonObjects";
import SmppSession from "../../../SmppSession"; import SmppSession from "../../../SmppSession";
import Preprocessor from "../Preprocessor"; import Preprocessor from "../Preprocessor";
import {PDU} from "../../../CommonObjects";
export default class ProtocolId4DigitProcessor extends Preprocessor { export default class ProtocolId4DigitProcessor extends Preprocessor {
applicableCommands: string[] = ['submit_sm', 'deliver_sm']; applicableCommands: string[] = ['submit_sm', 'deliver_sm'];

View File

@@ -10,7 +10,7 @@ export default class ProtocolIdProcessor extends Preprocessor {
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;
}); });
} }
} }

View File

@@ -1,6 +1,6 @@
import {PDU} from "../../../CommonObjects";
import SmppSession from "../../../SmppSession"; import SmppSession from "../../../SmppSession";
import Preprocessor from "../Preprocessor"; import Preprocessor from "../Preprocessor";
import {PDU} from "../../../CommonObjects";
export default class SourceSetPreprocessor extends Preprocessor { export default class SourceSetPreprocessor extends Preprocessor {
applicableCommands: string[] = ['submit_sm', 'deliver_sm']; applicableCommands: string[] = ['submit_sm', 'deliver_sm'];

View File

@@ -1,6 +1,6 @@
import {PDU} from "../../../CommonObjects";
import SmppSession from "../../../SmppSession"; import SmppSession from "../../../SmppSession";
import Preprocessor from "../Preprocessor"; import Preprocessor from "../Preprocessor";
import {PDU} from "../../../CommonObjects";
export default class UCS2Preprocessor extends Preprocessor { export default class UCS2Preprocessor extends Preprocessor {
applicableCommands: string[] = ['submit_sm', 'deliver_sm']; applicableCommands: string[] = ['submit_sm', 'deliver_sm'];

View File

@@ -12,16 +12,16 @@ import DeliverSmReplyProcessor from "./Postprocessor/Client/DeliverSmReplyProces
import Postprocessor from "./Postprocessor/Postprocessor"; import Postprocessor from "./Postprocessor/Postprocessor";
import DeliveryReceiptRequestProcessor from "./Preprocessor/Client/DeliveryReceiptRequestProcessor"; import DeliveryReceiptRequestProcessor from "./Preprocessor/Client/DeliveryReceiptRequestProcessor";
import DestinationEnumeratorProcessor from "./Preprocessor/Client/DestinationEnumeratorProcessor"; import DestinationEnumeratorProcessor from "./Preprocessor/Client/DestinationEnumeratorProcessor";
import DestinationSetPreprocessor from "./Preprocessor/Client/DestinationSetPreprocessor";
import GSM0338Preprocessor from "./Preprocessor/Client/GSM0338Preprocessor";
import LongSmsProcessor from "./Preprocessor/Client/LongSmsProcessor"; import LongSmsProcessor from "./Preprocessor/Client/LongSmsProcessor";
import SourceEnumeratorProcessor from "./Preprocessor/Client/SourceEnumeratorProcessor";
import Preprocessor from "./Preprocessor/Preprocessor";
import ProtocolIdProcessor from "./Preprocessor/Client/ProtocolIdProcessor";
import UCS2Preprocessor from "./Preprocessor/Client/UCS2Preprocessor";
import ProtocolId2DigitProcessor from "./Preprocessor/Client/ProtocolId-2Digit-Processor"; import ProtocolId2DigitProcessor from "./Preprocessor/Client/ProtocolId-2Digit-Processor";
import ProtocolId3DigitProcessor from "./Preprocessor/Client/ProtocolId-3Digit-Processor"; import ProtocolId3DigitProcessor from "./Preprocessor/Client/ProtocolId-3Digit-Processor";
import ProtocolId4DigitProcessor from "./Preprocessor/Client/ProtocolId-4Digit-Processor"; import ProtocolIdProcessor from "./Preprocessor/Client/ProtocolIdProcessor";
import SourceEnumeratorProcessor from "./Preprocessor/Client/SourceEnumeratorProcessor";
import SourceSetPreprocessor from "./Preprocessor/Client/SourceSetPreprocessor"; import SourceSetPreprocessor from "./Preprocessor/Client/SourceSetPreprocessor";
import DestinationSetPreprocessor from "./Preprocessor/Client/DestinationSetPreprocessor"; import UCS2Preprocessor from "./Preprocessor/Client/UCS2Preprocessor";
import Preprocessor from "./Preprocessor/Preprocessor";
export default class ProcessorManager { export default class ProcessorManager {
static preprocessors: PduProcessor[]; static preprocessors: PduProcessor[];
@@ -55,12 +55,12 @@ export default class ProcessorManager {
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 ProtocolId4DigitProcessor(Center.name),
new SourceSetPreprocessor(Client.name), new SourceSetPreprocessor(Client.name),
new SourceSetPreprocessor(Center.name), new SourceSetPreprocessor(Center.name),
new DestinationSetPreprocessor(Client.name), new DestinationSetPreprocessor(Client.name),
new DestinationSetPreprocessor(Center.name) new DestinationSetPreprocessor(Center.name),
new GSM0338Preprocessor(Client.name),
new GSM0338Preprocessor(Center.name)
]; ];
} }

25
src/main.js Normal file
View 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);

View File

@@ -23,7 +23,7 @@ function cleanup(): void {
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);

View File

@@ -1,15 +1,15 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es6", "strict": false,
"module": "commonjs", "verbatimModuleSyntax": false,
"outDir": "./dist", "noUncheckedIndexedAccess": false,
"rootDir": "./src",
"strict": true, "moduleResolution": "NodeNext",
"moduleResolution": "node", "module": "NodeNext",
"target": "ESNext",
"esModuleInterop": true, "esModuleInterop": true,
"noImplicitAny": true, "noEmit": true
}, },
"exclude": [ "include": ["src/**/*", "src/main.ts"]
"./node_modules"
]
} }

13
tsup.config.ts Normal file
View File

@@ -0,0 +1,13 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/main.ts'],
dts: false,
splitting: false,
sourcemap: false,
outDir: 'build',
clean: true,
minify: true,
target: ['esnext'],
format: ['cjs']
});

61
workfile.js Normal file
View 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);