rusmpp

Crates.iorusmpp
lib.rsrusmpp
version0.2.3
created_at2024-03-02 10:45:44.122791+00
updated_at2025-09-09 19:11:12.478144+00
descriptionA Rust SMPP library.
homepage
repositoryhttps://github.com/JadKHaddad/Rusmpp
max_upload_size
id1159607
size718,232
Jad K. Haddad (JadKHaddad)

documentation

README

Rusmpp

Build Status crates.io Crates.io (MSRV) docs.rs Crates.io (Downloads) Crates.io (License)

Rust implementation of the SMPP v5 protocol.

This is a low level library for implementing clients and servers. If you are looking for a client, check out rusmppc.

use core::error::Error;
use futures::{SinkExt, StreamExt};
use rusmpp::{
    codec::{tokio::EncodeError, CommandCodec},
    Command, CommandId, CommandStatus, Pdu,
};
use tokio::io::DuplexStream;
use tokio_util::codec::Framed;
use tracing::info;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Rusmpp produces a lot of logs while decoding and encoding PDUs.
    // You can filter them out by setting the `rusmpp` target to `off`,
    // or by disabling the `tracing` feature.
    tracing_subscriber::fmt()
        .with_env_filter("client=info,server=info,rusmpp=trace")
        .init();

    // In-memory duplex stream to simulate a server and client.
    let (server_stream, client_stream) = tokio::io::duplex(4096);

    launch_server(server_stream).await?;

    // The CommandCodec encodes/decodes SMPP commands into/from bytes.
    let mut framed = Framed::new(client_stream, CommandCodec::new());

    // Rusmpp takes care of setting the correct command ID.
    let command = Command::new(CommandStatus::EsmeRok, 1, Pdu::EnquireLink);

    info!(target: "client", "EnquireLink sent");

    framed.send(command).await?;

    while let Some(Ok(command)) = framed.next().await {
        if let CommandId::EnquireLinkResp = command.id() {
            info!(target: "client", "EnquireLink response received");

            break;
        }
    }

    Ok(())
}

async fn launch_server(stream: DuplexStream) -> Result<(), Box<dyn Error>> {
    tokio::spawn(async move {
        let mut framed = Framed::new(stream, CommandCodec::new());

        while let Some(Ok(command)) = framed.next().await {
            if let CommandId::EnquireLink = command.id() {
                info!(target: "server", "EnquireLink received");

                // We can also use the Command::builder() to create commands.
                let response = Command::builder()
                    .status(CommandStatus::EsmeRok)
                    .sequence_number(command.sequence_number())
                    .pdu(Pdu::EnquireLinkResp);

                framed.send(response).await?;

                info!(target: "server", "EnquireLink response sent");

                break;
            }
        }

        Ok::<(), EncodeError>(())
    });

    Ok(())
}

See the examples directory for more examples.

Features

  • tokio-codec: Implements Encoder and Decoder traits for the CommandCodec.
  • tracing: Enables logging using tracing.
  • arbitrary: Implements Arbitrary trait for all SMPP types.
  • verbose: Enables verbose error reports.
  • pretty-hex-fmt: Logs byte slices like [0x00, 0x00, 0x00, 0x6F] instead of [00, 00, 00, 6F], if tracing feature is enabled.
  • serde: Implements Serialize trait for all SMPP types.
  • serde-deserialize-unchecked: Implements Deserialize trait for all SMPP types, but does not check the validity of the data. Use with caution.

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Commit count: 753

cargo fmt