operation-hardcode / smpp-php
PHP的异步SMPP协议实现。
v0.1.7
2022-04-04 09:46 UTC
Requires
- php: >=8.1
- amphp/http-client: ^4.6
- amphp/socket: ^1.2
- amphp/sync: ^1.4
- phpinnacle/buffer: ^1.2
- psr/log: ^1.0 || ^2.0 || ^3.0
Requires (Dev)
- amphp/log: ^1.1
- phpunit/phpunit: ^9.5
- vimeo/psalm: ^4.18
This package is not auto-updated.
Last update: 2024-09-16 20:41:54 UTC
README
❗ 该库在第一次主要版本发布之前将处于实验性状态。
有关协议的更多信息,请参阅规范。
内容
安装
composer require operation-hardcode/smpp-php
要求
此库需要PHP 8.1或更高版本。
建议安装phpinnacle/ext-buffer扩展以加速phpinnacle/buffer。
特性
- BIND_RECEIVER
- BIND_TRANSMITTER
- BIND_TRANSCEIVER
- ALERT_NOTIFICATION
- CANCEL_SM
- DATA_SM
- DELIVER_SM
- ENQUIRE_LINK
- GENERIC_NACK
- OUTBIND
- QUERY_SM
- REPLACE_SM
- SUBMIT_SM
- UNBIND
- SUBMIT_MULTI
用法
接收器
<?php declare(strict_types=1); require_once __DIR__.'/../vendor/autoload.php'; use OperationHardcode\Smpp; use OperationHardcode\Smpp\Interaction\Connector; use OperationHardcode\Smpp\Protocol\PDU; use OperationHardcode\Smpp\Transport\ConnectionContext; Amp\Loop::run(function (): \Generator { $executor = Connector::connect() ->asReceiver(ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775')); try { yield $executor->consume(function (PDU $pdu, Smpp\Interaction\SmppExecutor $executor): \Generator { var_dump($pdu); yield $executor->fin(); }); } catch (Smpp\Interaction\ConnectionWasNotEstablished) { yield $executor->fin(); Amp\Loop::stop(); } });
发送器
<?php declare(strict_types=1); require_once __DIR__.'/../vendor/autoload.php'; use OperationHardcode\Smpp\Interaction\Connector; use OperationHardcode\Smpp\Protocol\Command\SubmitSm; use OperationHardcode\Smpp\Protocol\Destination; use OperationHardcode\Smpp\Transport\ConnectionContext; Amp\Loop::run(function (): \Generator { $transmitter = Connector::connect() ->asTransmitter(ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775')); yield $transmitter->produce(new SubmitSm(new Destination('xxxx'), new Destination('xxxxx'), 'Hello, world')); yield $transmitter->fin(); });
收发器
<?php declare(strict_types=1); require_once __DIR__.'/../vendor/autoload.php'; use Amp\Log\ConsoleFormatter; use Amp\Log\StreamHandler; use Monolog\Logger; use Monolog\Processor\MemoryPeakUsageProcessor; use Monolog\Processor\MemoryUsageProcessor; use Monolog\Processor\PsrLogMessageProcessor; use OperationHardcode\Smpp; use OperationHardcode\Smpp\Interaction\Connector; use OperationHardcode\Smpp\Protocol\PDU; use OperationHardcode\Smpp\Transport\ConnectionContext; use Psr\Log\LoggerInterface; function stdoutLogger(string $loggerName): LoggerInterface { $handler = new StreamHandler(Amp\ByteStream\getStdout()); $handler->setFormatter(new ConsoleFormatter()); return new Logger($loggerName, [$handler], [new PsrLogMessageProcessor(), new MemoryUsageProcessor(), new MemoryPeakUsageProcessor()]); } Amp\Loop::run(function (): \Generator { $transceiver = Connector::connect()->asTransceiver( ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'), stdoutLogger('transceiver'), ); try { yield $transceiver->consume(function (PDU $pdu, Smpp\Interaction\SmppExecutor $executor): \Generator { if ($pdu instanceof Smpp\Protocol\Command\Replyable) { yield $executor->produce($pdu->reply()); } var_dump($pdu); return new Amp\Success(); }); } catch (\Throwable $e) { echo $e->getMessage() . \PHP_EOL; Amp\Loop::stop(); } });
信号
<?php declare(strict_types=1); require_once __DIR__.'/../vendor/autoload.php'; use Amp; use OperationHardcode\Smpp\Interaction\Connector; use OperationHardcode\Smpp\Transport\ConnectionContext; use OperationHardcode\Smpp; Amp\Loop::run(function (): \Generator { $logger = stdoutLogger('transceiver'); $transceiver = Connector::connect() ->asTransceiver( ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'), $logger ); Amp\Loop::unreference( Amp\Loop::onSignal(\SIGINT, function () use ($transceiver): \Generator { yield $transceiver->fin(); }) ); try { yield $transceiver->consume(function (PDU $pdu, SmppExecutor $executor): \Generator { if ($pdu instanceof Smpp\Protocol\Command\Replyable) { $reply = $pdu->reply(); yield $executor->produce($reply); } return new Amp\Success(); }); } catch (\Throwable $e) { echo $e->getMessage() . \PHP_EOL; Amp\Loop::stop(); } });
扩展
如果您在处理库时需要更多选项,可以编写一个扩展。该库提供了4个钩子,这些钩子在执行器工作不同时间被调用。
- 如果您想扩展成功连接的行为,实现
OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionEstablishedExtension接口。 - 如果您想扩展断开连接的行为,实现
OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionClosedExtension接口。 - 如果您想扩展执行器产生的每个
PDU的行为,实现OperationHardcode\Smpp\Interaction\Extensions\AfterPduProducedExtension接口。 - 或者相反,如果您想扩展执行器消耗的每个
PDU的行为,实现OperationHardcode\Smpp\Interaction\Extensions\AfterPduConsumedExtension接口。
<?php declare(strict_types=1); require_once __DIR__.'/../vendor/autoload.php'; use Amp; use OperationHardcode\Smpp\Interaction\Connector; use OperationHardcode\Smpp\Transport\ConnectionContext; use OperationHardcode\Smpp; use OperationHardcode\Smpp\Interaction\SmppExecutor; use OperationHardcode\Smpp\Protocol\PDU; use Psr\Log\LoggerInterface; use OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionEstablishedExtension; use OperationHardcode\Smpp\Interaction\Extensions\AfterConnectionClosedExtension; use OperationHardcode\Smpp\Interaction\Extensions\AfterPduConsumedExtension; use OperationHardcode\Smpp\Interaction\Extensions\AfterPduProducedExtension; final class Debug implements AfterConnectionEstablishedExtension, AfterConnectionClosedExtension, AfterPduConsumedExtension, AfterPduProducedExtension { public function __construct(private LoggerInterface $logger) { } public function afterConnectionEstablished(SmppExecutor $smppExecutor): Amp\Promise { return Amp\call(function (): void { $this->logger->debug('Connection was established.'); }); } public function afterConnectionClosed(?\Throwable $e = null): Amp\Promise { return Amp\call(function () use ($e): void { $this->logger->debug('Connection was closed.'); }); } public function afterPduConsumed(PDU $pdu, SmppExecutor $smppExecutor): Amp\Promise { return Amp\call(function () use ($pdu): void { $this->logger->debug('The pdu "{pdu}" was consumed.', [ 'pdu' => get_class($pdu), ]); }); } public function afterPduProduced(PDU $pdu, SmppExecutor $smppExecutor): Amp\Promise { return Amp\call(function () use ($pdu): void { $this->logger->debug('The pdu "{pdu}" was produced.', [ 'pdu' => get_class($pdu), ]); }); } } Amp\Loop::run(function (): \Generator { $logger = stdoutLogger('transceiver'); $transceiver = Connector::connect() ->asTransceiver( ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'), $logger ) ->withExtensions([ new Debug($logger), ]); Amp\Loop::unreference( Amp\Loop::onSignal(\SIGINT, function () use ($transceiver): \Generator { yield $transceiver->fin(); }) ); try { yield $transceiver->consume(function (PDU $pdu, SmppExecutor $executor): \Generator { if ($pdu instanceof Smpp\Protocol\Command\Replyable) { $reply = $pdu->reply(); yield $executor->produce($reply); } return new Amp\Success(); }); } catch (\Throwable $e) { echo $e->getMessage() . \PHP_EOL; Amp\Loop::stop(); } });
心跳
该库提供了一个Heartbeat扩展,它定期发送SMPP规范要求的ENQUIRE_LINK命令。您可以配置间隔和超时,以便在此期间必须接收到带有命令状态ESME_ROK的ENQUIRE_LINK_RESP。
<?php declare(strict_types=1); require_once __DIR__.'/../vendor/autoload.php'; use Amp; use OperationHardcode\Smpp\Interaction\Connector; use OperationHardcode\Smpp\Transport\ConnectionContext; use OperationHardcode\Smpp\Interaction\SmppExecutor; use OperationHardcode\Smpp\Interaction\Heartbeat\Heartbeat; use OperationHardcode\Smpp\Time; Amp\Loop::run(function (): \Generator { $logger = stdoutLogger('transceiver'); $transceiver = Connector::connect() ->asTransceiver( ConnectionContext::default(uri: 'smscsim.melroselabs.com:2775', systemId: '900238', password: 'c58775'), $logger ) ->withExtensions([ new Heartbeat( Time::fromSeconds(10), // interval Time::fromSeconds(2), // timeout $logger, ), ]); Amp\Loop::unreference( Amp\Loop::onSignal(\SIGINT, function () use ($transceiver): \Generator { yield $transceiver->fin(); }) ); try { yield $transceiver->consume(function (PDU $pdu, SmppExecutor $executor): \Generator { if ($pdu instanceof Smpp\Protocol\Command\Replyable) { $reply = $pdu->reply(); yield $executor->produce($reply); } return new Amp\Success(); }); } catch (\Throwable $e) { echo $e->getMessage() . \PHP_EOL; Amp\Loop::stop(); } });
测试
$ composer test
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件。