A STOMP client in Rust. Compatible with RabbitMQ, ActiveMQ.

Overview

stomp-rs

stomp-rs provides a full STOMP 1.2 client implementation for the Rust programming language. This allows programs written in Rust to interact with message queueing services like ActiveMQ, RabbitMQ, HornetQ and OpenMQ.

  • Connect
  • Subscribe
  • Send
  • Acknowledge (Auto/Client/ClientIndividual)
  • Transactions
  • Receipts
  • Disconnect
  • Heartbeats

The APIs for stomp-rs are not yet stable and are likely to fluctuate before v1.0.

Examples

Connect / Subscribe / Send

extern crate stomp;
use stomp::frame::Frame;
use stomp::subscription::AckOrNack::Ack;

fn main() {
  
  let destination = "/topic/messages";
  let mut message_count: u64 = 0;

  let mut session = match stomp::session("127.0.0.1", 61613).start() {
      Ok(session) => session,
      Err(error)  => panic!("Could not connect to the server: {}", error)
   };
  
  session.subscription(destination, |frame: &Frame| {
    message_count += 1;
    println!("Received message #{}:\n{}", message_count, frame);
    Ack
  }).start();
  
  session.message(destination, "Animal").send();
  session.message(destination, "Vegetable").send();
  session.message(destination, "Mineral").send();
  
  session.listen(); // Loops infinitely, awaiting messages

  session.disconnect();
}

Session Configuration

use stomp::header::header::Header;
use stomp::connection::{HeartBeat, Credentials};
// ...
let mut session = match stomp::session("127.0.0.1", 61613)
  .with(Credentials("sullivan", "m1k4d0"))
  .with(HeartBeat(5000, 2000))
  .with(Header::new("custom-client-id", "hmspna4"))
  .start() {
      Ok(session) => session,
      Err(error)  => panic!("Could not connect to the server: {}", error)
   };

Message Configuration

use stomp::header::{Header, SuppressedHeader, ContentType};
// ...
session.message(destination, "Hypoteneuse".as_bytes())
  .with(ContentType("text/plain"))
  .with(Header::new("persistent", "true"))
  .with(SuppressedHeader("content-length")
  .send();

Subscription Configuration

use stomp::subscription::AckMode;
use stomp::header::Header;
use stomp::frame::Frame;
// ...
  let id = session.subscription(destination, |frame: &Frame| {
    message_count += 1;
    println!("Received message #{}:\n{}", message_count, frame);
    Ack
  })
  .with(AckMode::Client)
  .with(Header::new("custom-subscription-header", "lozenge"))
  .start();

Transactions

match session.begin_transaction() {
  Ok(mut transaction) => {
    transaction.message(destination, "Animal").send();
    transaction.message(destination, "Vegetable").send();
    transaction.message(destination, "Mineral").send();
    transaction.commit();
},
  Err(error)  => panic!("Could not connect to the server: {}", error)
};

Handling RECEIPT frames

If you include a ReceiptHandler in your message, the client will request that the server send a receipt when it has successfully processed the frame.

session.message(destination, "text/plain", "Hypoteneuse".as_bytes())
  .with(ReceiptHandler::new(|frame: &Frame| println!("Got a receipt for 'Hypoteneuse'.")))
  .send();

Handling ERROR frames

To handle errors, you can register an error handler

session.on_error(|frame: &Frame| {
  panic!("ERROR frame received:\n{}", frame);
});

Manipulating inbound and outbound frames

In some cases, brokers impose rules or restrictions which may make it necessary to directly modify frames in ways that are not conveniently exposed by the API. In such cases, you can use the on_before_send and on_before_receive methods to specify a callback to perform this custom logic prior to the sending or receipt of each frame.

For example:

// Require that all NACKs include a header specifying an optional requeue policy
session.on_before_send(|frame: &mut Frame| {
  if frame.command == "NACK" {
    frame.headers.push(Header::new("requeue", "false"));
  }
});

session.on_before_receive(|frame: &mut Frame| {
  if frame.command == "MESSAGE" {
    // Modify the frame
  }
});

Cargo.toml

[package]

name = "stomp_test"
version = "0.0.1"
authors = ["your_name_here"]

[[bin]]

name = "stomp_test"

[dependencies.stomp]

stomp = "*"

keywords: Stomp, Rust, rust-lang, rustlang, cargo, ActiveMQ, RabbitMQ, HornetQ, OpenMQ, Message Queue, MQ

Comments
  • upgraded to mio v0.4

    upgraded to mio v0.4

    Just started with Rust and wanted to do something with RabbitMQ, came accross your library. Thanks for the work. Hope this pull request helps for the future.

    Since I am really a Rust beginner, there might errors in the modifications I made.

    opened by frederikbosch 10
  • Nack requeue false

    Nack requeue false

    Sending a Nack frame with Rabbit MQ automatically enables requeue. If this is not desired behaviour, like in my case, then there is no way to change it to false as default on the server-side. So it must be implemented client-side.

    The STOMP spec is ambiguous on what the default setting should be and leaves it up to the server. It does even not specify the name of header that should be send if you do want control over the behaviour.

    So with respect to the library, I would suggest adding a on_frame method to the session struct. This enables anyone to hack into the frame for these kind of situations: when the spec leaves it open how to implement something.

    From the perspective of the user it then can look like this.

    session.on_frame(|frame : &mut Frame| {
        match frame.command.as_ref() {
            "NACK" => {
                &frame.headers.push(Header::new("requeue", "false"));
            },
            _ => {}
        }
    });
    
    opened by frederikbosch 7
  • Add Support for Suppressing Content Length

    Add Support for Suppressing Content Length

    The suppression of the content-length header is used by ActiveMQ to differentiate binary and text messages [1], and should be supported.

    [1] http://activemq.apache.org/stomp.html

    opened by fribeiro1 7
  • Can't Compile with Rust 0.13.0-nightly

    Can't Compile with Rust 0.13.0-nightly

    I am getting the following error when compiling 0.3.4:

    src\connection.rs:91:22: 91:97 error: mismatched types: expected `core::option::Option<collections::string::String>`, found `core::result::Result<collections::string::String, core::str::Utf8Error>` (expected enum core::option::Option, found enum core::result::Result)
    src\connection.rs:91              detail: from_utf8(connected_frame.body.as_slice()).map(|err: &str| err.to_string())
                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    src\frame.rs:60:7: 60:18 error: mismatched types: expected `core::result::Result<&str, core::str::Utf8Error>`, found `core::option::Option<_>` (expected enum core::result::Result, found enum core::option::Option)
    src\frame.rs:60       Some(ref s) => *s,
                          ^~~~~~~~~~~
    src\frame.rs:61:7: 61:11 error: mismatched types: expected `core::result::Result<&str, core::str::Utf8Error>`, found `core::option::Option<_>` (expected enum core::result::Result, found enum core::option::Option)
    src\frame.rs:61       None => "<Binary content>" // Space is wasted in this case. Could shrink to fit?
                          ^~~~
    error: aborting due to 3 previous errors
    Could not compile `stomp`.
    

    Please advise.

    opened by fribeiro1 7
  • Multiple clients on same machine

    Multiple clients on same machine

    When I have two clients (gworkerd) on the same machine, one the of clients refuses to take messages after a while. Logs do not help me address why. Things that I am observing.

    1. The specific client does not have receive a lot of messages. Sometimes less than 1/day.
    2. There is one stomp server (RabbitMQ) to which all client connect (different number of consumers)
    3. RabbitMQ management tool tells the specific queue still has consumers (4). The specific client has 4 open connections while there should be 5. So one of the connections was dropped without reconnecting. Nothing in the logs on this.
    4. The last debug message is from the last received mq message, no logs on disconnection or reconnect tries
    5. The other client on the same machine has no problems, but also receives more messages (10/day).
    6. After closing all connections, one the consumers reconnects and continues receiving messages

    Last log

    [2016-05-27 11:49:08:194429] DEBUG [stomp::header] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/header.rs:75: Recycling Header: message-id:T_stomp-rs/0@@session-cUPwn1scQoX8CJ7ABo-25Q@@1
    [2016-05-27 11:49:08:194434] DEBUG [stomp::header] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/header.rs:75: Recycling Header: destination:/queue/gworkerd_web2_platform
    [2016-05-27 11:49:08:194438] DEBUG [stomp::header] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/header.rs:75: Recycling Header: subscription:stomp-rs/0
    [2016-05-27 11:49:08:194443] DEBUG [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:143: Reading from frame buffer
    [2016-05-27 11:49:08:194448] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:103: Parsing command.
    [2016-05-27 11:49:08:194453] DEBUG [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:159: Done. Read 1 frames.
    [2016-05-27 11:49:08:234951] INFO [gworkerd] src/main.rs:118: ["41106dd6-23f0-11e6-8ff4-00155d028200"] added to result backend
    

    Then I closed the remaining connections.

    [2016-06-01 10:36:30:954354] DEBUG [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:124: Readable! Buffer size: 65536
    [2016-06-01 10:36:31:114965] DEBUG [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:125: Frame buffer length: 0
    [2016-06-01 10:36:31:114998] INFO [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:139: Read 125 bytes
    [2016-06-01 10:36:31:115005] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:91: Copied 125 bytes into the frame buffer.
    [2016-06-01 10:36:31:115012] DEBUG [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:143: Reading from frame buffer
    [2016-06-01 10:36:31:115017] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:103: Parsing command.
    [2016-06-01 10:36:31:115022] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:204: Found command ending @ index 5
    [2016-06-01 10:36:31:115027] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:176: Removed 6 bytes from frame buffer, new size: 1
    19
    [2016-06-01 10:36:31:115034] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:208: Chomped length: 5
    [2016-06-01 10:36:31:115039] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:217: Command -> 'ERROR'
    [2016-06-01 10:36:31:127990] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:116: Parsing headers.
    [2016-06-01 10:36:31:128009] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:227: Found header ending @ index 25
    [2016-06-01 10:36:31:128016] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:176: Removed 26 bytes from frame buffer, new size: 
    93
    [2016-06-01 10:36:31:128041] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:231: Header -> 'message:connection_forced'
    [2016-06-01 10:36:31:128051] DEBUG [stomp::header] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/header.rs:75: Recycling Header: message:connection_forced
    [2016-06-01 10:36:31:128056] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:227: Found header ending @ index 23
    [2016-06-01 10:36:31:128061] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:176: Removed 24 bytes from frame buffer, new size: 
    69
    [2016-06-01 10:36:31:128066] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:231: Header -> 'content-type:text/plain'
    [2016-06-01 10:36:31:128072] DEBUG [stomp::header] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/header.rs:75: Recycling Header: content-type:text/plain
    [2016-06-01 10:36:31:128077] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:227: Found header ending @ index 19
    [2016-06-01 10:36:31:128081] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:176: Removed 20 bytes from frame buffer, new size: 
    49
    [2016-06-01 10:36:31:128086] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:231: Header -> 'version:1.0,1.1,1.2'
    [2016-06-01 10:36:31:128092] DEBUG [stomp::header] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/header.rs:75: Recycling Header: version:1.0,1.1,1.2
    [2016-06-01 10:36:31:128156] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:227: Found header ending @ index 17
    [2016-06-01 10:36:31:128163] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:176: Removed 18 bytes from frame buffer, new size: 
    31
    [2016-06-01 10:36:31:128168] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:231: Header -> 'content-length:29'
    [2016-06-01 10:36:31:128174] DEBUG [stomp::header] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/header.rs:75: Recycling Header: content-length:29
    [2016-06-01 10:36:31:128179] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:227: Found header ending @ index 0
    [2016-06-01 10:36:31:128184] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:176: Removed 1 bytes from frame buffer, new size: 3
    0
    [2016-06-01 10:36:31:128189] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:231: Header -> ''
    [2016-06-01 10:36:31:128193] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:133: Parsing body.
    [2016-06-01 10:36:31:128199] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:256: Reading body by content length.
    [2016-06-01 10:36:31:128203] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:176: Removed 30 bytes from frame buffer, new size: 
    0
    [2016-06-01 10:36:31:128208] DEBUG [stomp::frame_buffer] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/frame_buffer.rs:264: Body -> 'Closed via management plugin
    '
    [2016-06-01 10:36:31:128219] DEBUG [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:147: Received frame!:
    ERROR
    message:connection_forced
    content-type:text/plain
    version:1.0,1.1,1.2
    content-length:29
    
    Closed via management plugin
    
    [2016-06-01 10:36:31:128226] DEBUG [stomp::session] /home/.cargo/registry/src/github.com-0a35038f75765ae4/stomp-0.11.0/src/session.rs:263: Resetting heartbeat rx timeout
    

    Conclusion

    1. When you start multiple subscriptions, reconnection only starts when there are no consumers left.
    2. But why do the remaining connections/consumers do not receive any messages any more?

    In my worker I subscribe to the queues here via my wrapper that uses stomp-rs.

    @zslayton Do you have any idea what might be causing this?

    opened by frederikbosch 4
  • Can't Compile with Rust 1.0.0-nightly

    Can't Compile with Rust 1.0.0-nightly

    I am getting the following error when compiling 0.3.6:

    src\stomp.rs:3:12: 3:17 error: feature has been removed
    src\stomp.rs:3 #![feature(phase)]
                              ^~~~~
    error: aborting due to previous error
    Could not compile `stomp`.
    

    Please advise.

    opened by fribeiro1 4
  • Turn `Subscription` into a Trait

    Turn `Subscription` into a Trait

    cc @fribeiro1

    Possibly the greatest shortcoming in the stomp library is that the on_message callback is a bare function (fn). This burdens the message handler with creating its own resources each time a message is received. It is impossible[1], for example, to have the message handling function send a message somewhere meaningful via a channel or to keep count of how many times it has been called. This dramatically limits what can be done using this crate.

    There are two possible solutions to this issue:

    1. Use closures instead of bare functions
    2. Create a Subscription trait that the developer can implement.

    Having used the Stomp protocol in the past mostly from dynamic languages like JS and Python, closures seemed to me like the most ergonomic way of offering this functionality. (Note the existence of issue #33.) This would look something like:

      let topic = "/topic/messages";
      let mut message_count = 0u64;
      session.subscribe(topic, Client, |frame: &Frame| {
        message_count += 1;
        println!("Received {} messages", message_count);
      });
    

    However, it may be more idiomatic to convert Subscription into a Trait and require the developer to create a struct with the desired environment which implements it. That would look something like:

    struct ExampleSubscription {
      count: u64
    }
    
    impl Subscription for ExampleSubscription {
      fn on_message(&mut self) -> AckOrNack {
        self.count += 1;
        Ack
      }
    }
    
    fn main() {
      let subscription = ExampleSubscription::new();
      session.subscribe(topic, Client, subscription);
    }
    

    This is obviously more verbose and isn't quite as nice for short demonstrations. However, it feels as though it may be more fitting for non-trivial programs relying on an MQ broker.

    I'm currently leaning towards the Trait approach, but I wanted to open this issue to request input on the topic before jumping into revisions.

    [1] It is possible to do something like this using static data structures, but this is not idiomatic Rust.

    opened by zslayton 3
  • Allow a handler to be specified per-receipt

    Allow a handler to be specified per-receipt

    When sending a message, the developer should have the ability to provide a callback to be fired when the requested server RECEIPT frame for that message is received. The handler should not block other incoming frames from being read/processed.

    opened by zslayton 2
  • Auto-reconnect

    Auto-reconnect

    In the event that the server connection is severed, reconnect and resubscribe to the appropriate topics. Offer configuration variables around this functionality.

    enhancement 
    opened by zslayton 2
  • Modify callbacks to take a closure

    Modify callbacks to take a closure

    The present implementation limits callbacks to being environment-less functions. This makes it inconvenient for library users to perform non-trivial processing on incoming messages.

    opened by zslayton 2
  • Eliminate excess clone()s of TcpStream

    Eliminate excess clone()s of TcpStream

    Before a full Session can be created, the server must receive HeartBeat preferences from the server via a CONNECTED frame. To achieve this, the client manually writes out a CONNECT frame and reads in CONNECTED before instantiating the session. In this process, it clone()s the TcpStream to satisfy the compiler. This is unnecessary and kludge-y.

    refactor 
    opened by zslayton 2
  • Error with example

    Error with example

    Problem with example

    pdobryakov@pdobryakov:~/rust/t1$ cat ./src/main.rs 
    extern crate stomp;
    use stomp::frame::Frame;
    use stomp::subscription::AckOrNack::Ack;
    
    fn main() {
      
      let destination = "/topic/messages";
      let mut message_count: u64 = 0;
    
      let mut session = match stomp::session("127.0.0.1", 61613).start() {
          Ok(session) => session,
          Err(error)  => panic!("Could not connect to the server: {}", error)
       };
      
      session.subscription(destination, |frame: &Frame| {
        message_count += 1;
        println!("Received message #{}:\n{}", message_count, frame);
        Ack
      }).start();
      
      session.message(destination, "Animal").send();
      session.message(destination, "Vegetable").send();
      session.message(destination, "Mineral").send();
      
      session.listen(); // Loops infinitely, awaiting messages
    
      session.disconnect();
    }
    pdobryakov@pdobryakov:~/rust/t1$ cargo build
       Compiling t1 v0.1.0 (file:///home/pdobryakov/rust/t1)
    error[E0423]: expected function, found module `stomp::session`
      --> src/main.rs:10:27
       |
    10 |   let mut session = match stomp::session("127.0.0.1", 61613).start() {
       |                           ^^^^^^^^^^^^^^ not a function
    
    error: aborting due to previous error
    
    error: Could not compile `t1`.
    
    To learn more, run the command again with --verbose.
    
    opened by kvendi 1
  • Reconnecting changes state of session

    Reconnecting changes state of session

    In my app I connect to a queue with 5 threads with Heartbeat enabled on the connection and prefetch_count enabled on the subscription which is equal to 1. All works great.

    However, there are connections that have very little connectivity causing the session to disconnect. Now it is great that reconnect is build-in, but there seems to be a problem after reconnecting. Suddenly my worker queue turns into a publish/subscribe queue. All 5 threads receive the same message when it is published on the queue, where as before reconnecting only one thread/worker received the message.

    @zslayton My guess is that some of the headers are not added again after reconnecting. Do you have a clue where to look for? Because I would love to help with solving issue. Maybe you can point me into a direction where things might go wrong. Of course, I will also start investigating myself too.

    opened by frederikbosch 2
  • Don't detach Strings from Pool<String>

    Don't detach Strings from Pool

    This was done to minimize refactoring required to release v0.10.0, which included auto-reconnect, reduced memory allocation and became usable from rustc's stable channel. However, the resulting code is a bit cluttered.

    Instances of String in the Frame struct should be replaced with lifeguard's Recycled<String> type. This will allow all of the strings.attach(...) calls to be deleted.

    opened by zslayton 0
Releases(v0.11.0)
  • v0.11.0(Aug 24, 2015)

    • Internal Pool<String> instances now make use of lifeguard v0.3.0's maximum sizes to prevent memory leaks.
    • @frederikbosch added hooks for on_before_send and on_before_receive to allow for mutable access to inbound/outbound frames, useful for manually addressing gray areas in the STOMP protocol.
    Source code(tar.gz)
    Source code(zip)
  • v0.10.2(Aug 7, 2015)

  • v0.10.1(May 29, 2015)

  • v0.10.0(May 27, 2015)

    • stomp-rs can now be used with rustc's stable channel
    • Introduced automatic reconnect; in the event that the connection with the server is lost, the client will stop processing and attempt to re-establish it. Once the connection is up, all of the previous subscriptions will be re-established. Work is planned to make this configurable: #85.
    • Created and incorporated the Lifeguard object pool to re-use Strings and Vecs rather than allocating new ones. Benchmarks with perf and valgrind show a marked improvement.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.0(Apr 29, 2015)

    • Migrated to mio. The entire library is now single-threaded.
    • Some tracking of breaking changes to rustc
    • Migrated from old_io to io
    • Replaced uses of now-deprecated Timer with mio's timeouts
    Source code(tar.gz)
    Source code(zip)
  • v0.8.4(Apr 5, 2015)

    • Structs implementing Copy now also implement Clone
    • Uses of as_slice transitioned to as_ref
    • Fixed calls to Error::new, which now expects only two arguments
    Source code(tar.gz)
    Source code(zip)
  • v0.8.3(Mar 29, 2015)

  • v0.8.2(Mar 25, 2015)

    Across the board migration from std::old_io to std::io with the exception of Timer, which has no analogous mechanism in std::io as of yet.

    Source code(tar.gz)
    Source code(zip)
  • v0.8.1(Mar 4, 2015)

    Tracking upstream changes to rustc:

    • Lifetime issue in ReceiptHandler resolved using PhantomData. (Thanks to @cstorey!)
    • Warnings about using old_io suppressed.
    • Example code updated
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Feb 8, 2015)

    • Created a ToFrameBody trait to reduce noise at the Session::message callsite.
    • Removed the Session::send_text and Session::send_bytes methods as well as their counterparts in Transaction
    • mime_type is no longer a required parameter for Session::message. A ContentType can now be specified as an OptionSetter if desired.
    • Exposed the MessageBuilder API from Transaction.
    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Feb 8, 2015)

    • Created FrameHandler trait to make error and receipt handling more ergonomic. Closures and custom structs are now supported.
    • A per-message ReceiptHandler mechanism was added, allowing the developer to react statefully to the server's confirmation that a message was processed.
    • SUBSCRIBE frames can now request a receipt by specifying a ReceiptHandler via the SubscriptionBuilder.
    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Feb 5, 2015)

    • Builder APIs for Sessions, Subscriptions and Messages. Allows for setting:
      • Custom headers
      • Suppressed headers
      • Heartbeat parameters
      • Credentials
      • Ack mode
    • Tracking upstream change to the parse() method's return value
    Source code(tar.gz)
    Source code(zip)
  • v0.5.2(Feb 1, 2015)

    • Rearranged example code following this upstream change.
    • Simplified implementations of MessageHandler and ToMessageHandler
    • Added groundwork for builder APIs
    • Added examples directory
    • Transaction::abort and Transaction::commit now consume self
    Source code(tar.gz)
    Source code(zip)
  • v0.5.1(Jan 30, 2015)

    Minor cleanup, tracking upstream changes.

    • Added header_list! macro variant to simplify encoding Headers. Invoked as header_list![ "key1" => "value1", "key2" => "value2", ... ]
    • Modified Session::send and Session::receive to return an IoResult.
    • std::io renamed to std::old_io as Rust developers refactor std::io.
    • #[allow(unstable)] dropped in favor of per-feature allow statements
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Jan 27, 2015)

    • Introduced the ToMessageHandler trait, allowing the Session::subscribe method to take any of the following as its callback:
      • Fn(&Frame) -> AckOrNack
      • FnMut(&Frame) -> AckOrNack
      • Sender<Frame>
      • Custom implementation
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Jan 25, 2015)

    • The subscription::MessageHandler trait replaced bare functions (fn) in subscriptions to allow state to be tracked across invocations.
    • @fribeiro1 added a convenience macro for creating a set of Headers (header_list!)
    • Updates to now-deprecated method calls
    Source code(tar.gz)
    Source code(zip)
  • v0.3.7(Jan 11, 2015)

    Tracking upstream changes:

    • isize/usize
    • Threads are already detached by default following spawn()
    • macro_use pragma required for logging crate
    Source code(tar.gz)
    Source code(zip)
  • v0.3.6(Jan 6, 2015)

    Tracked upstream changes:

    • from_str replaced with parse
    • from_utf8 returns a Result instead of an Option
    • std::slice::Items became collections::Iter
    • deriving renamed to derive
    Source code(tar.gz)
    Source code(zip)
  • v0.3.4(Dec 21, 2014)

  • v0.3.3(Nov 23, 2014)

  • v0.3.2(Nov 21, 2014)

  • v0.3.1(Nov 8, 2014)

    Small changes to catch up after a number of breaking changes landed in the language this past week.

    • Rename fail! to panic!
    • Update usage of &str with HashMap's find_equiv and pop_equiv
    • Constants made uppercase
    • Fixed renamed imports
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Oct 1, 2014)

  • v0.2.0(Sep 27, 2014)

  • v0.1.0(Aug 3, 2014)

Owner
Zack Slayton
Zack Slayton
A skyline mod that enables manual choosing of desired input latency in Smash Ultimate, compatible with every online mode.

Latency Slider (Definitive Edition) This is a fork of - and an improvement upon - the original "Arena Latency Slider". Unfortunately, upon SSBU updati

null 8 Mar 5, 2024
Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password.

nostr-irc Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password. Experimental code, use

null 11 Dec 26, 2022
FTP client for Rust

rust-ftp FTP client for Rust Documentation rust-ftp Installation Usage License Contribution Development environment Installation FTPS support is achie

Matt McCoy 155 Nov 12, 2022
NNTP client for Rust

rust-nntp NNTP Client for Rust Usage extern crate nntp; use nntp::{Article, NNTPStream}; fn main() { let mut nntp_stream = match NNTPStream::connec

Matt McCoy 13 Jan 22, 2022
POP3 client for Rust

rust-pop3 POP3 Client for Rust This client has SSL support. SSL is configured using an SSLContext that is passed into the connect method of a POP3Stre

Matt McCoy 26 Dec 19, 2022
Rust client for NATS, the cloud native messaging system.

A Rust client for the NATS messaging system. Status Motivation Rust may be the most interesting new language the NATS ecosystem has seen. We believe t

NATS - The Cloud Native Messaging System 651 Jan 3, 2023
rqbit - bittorrent client in Rust

rqbit - bittorrent client in Rust

Igor Katson 177 Jan 2, 2023
Simple project to test grpc between ruby (client) and rust (server)

grpc-example Simple project to test grpc between ruby (client) and rust (server). Usage To simplify a lot this project uses docker and docker compose

Bruno Arueira 2 Oct 14, 2021
A rust client and structures to interact with the Clever-Cloud API.

Clever-Cloud Software Development Kit - Rust edition This crate provides structures and client to interact with the Clever-Cloud API. Status This crat

Clever Cloud 6 Jun 3, 2022
Third party Google DNS client for rust.

google-dns-rs Documentation Install Add the following line to your Cargo.toml file: google-dns-rs = "0.3.0" Usage use google_dns_rs::api::{Dns, DoH, R

Eduardo Stuart 2 Nov 13, 2021
A ddns client written in Rust.

ddns-rs ready for use with one cloudflare A/AAAA record ?? A ddns client written in Rust. Features get public ip cloudflare (A or AAAA record) toml co

Ric Li 1 Oct 25, 2022
Rust client for apache iotdb.

Apache IoTDB Apache IoTDB (Database for Internet of Things) is an IoT native database with high performance for data management and analysis, deployab

Mark Liu 7 Aug 4, 2022
Rust client for Kubernetes

Rust client for Kubernetes API.

null 244 Dec 17, 2022
A Rust based DNS client, server, and resolver

Trust-DNS A Rust based DNS client, server, and Resolver, built to be safe and secure from the ground up. This repo consists of multiple crates: Librar

Benjamin Fry 2.7k Dec 30, 2022
An online version of the popular game four in a row, written in Rust on the server side and Flutter + Dart on the client.

Four in a Row - Server An online version of the popular game four in a row, written in Rust on the server side and Flutter + Dart on the client. Downl

Filippo OrrĂ¹ 8 Sep 16, 2022
A minimalist socket-based client/server in Rust to illustrate a tutorial

The basics of unix sockets This repository serves as a reference for this tutorial blogpost How to run Install Rust and Cargo, and then do: cargo run

Emmanuel Bosquet 4 Dec 4, 2022
Rust Verbio SpeechCenter Client

The CLI client allows you to launch a single file to the server. It also allows you to use either a grammar or a language model.

Verbio Technologies 3 Sep 16, 2022
Fast Discord RPC Client written in Rust

Discord RPC Client Examples Big image, small image, details and one button discordrpc -c 942151169185316874 -d 'untypeable nickname' --button-1-text '

Oskar 10 Jan 1, 2023
Rust client for Apache Kafka

Kafka Rust Client Project Status This project is starting to be maintained by John Ward, the current status is that I am bringing the project up to da

Kafka Rust 900 Dec 26, 2022