ControlMessage

Struct ControlMessage 

Source
pub struct ControlMessage {
    pub arrived_at: i64,
    /* private fields */
}
Expand description

A parsed control protocol message from Tor.

ControlMessage represents a complete response from Tor’s control interface. It handles both single-line and multi-line responses, parsing the status codes, dividers, and content according to the control protocol specification.

§Response Format

Each line in a control message has the format:

STATUS DIVIDER CONTENT

Where STATUS is a 3-digit code, DIVIDER indicates continuation, and CONTENT is the payload. The parsed content is stored as tuples of (status_code, divider, content).

§Status Codes

  • 2xx: Success (e.g., 250 OK)
  • 4xx: Temporary failure
  • 5xx: Permanent failure (e.g., 552 Unrecognized key)
  • 6xx: Asynchronous event notification

§Invariants

  • A ControlMessage is never empty; construction fails if no valid lines exist
  • The arrived_at timestamp is set at construction time
  • Raw content preserves the original bytes for hashing and equality

§Thread Safety

ControlMessage is Send and Sync. It is immutable after construction.

§Example

use stem_rs::response::ControlMessage;

// Parse a GETINFO response
let response = "250-version=0.4.7.8\r\n250 OK\r\n";
let msg = ControlMessage::from_str(response, None, false).unwrap();

// Check if successful
assert!(msg.is_ok());

// Access parsed content
let content = msg.content();
assert_eq!(content[0].0, "250"); // status code
assert_eq!(content[0].1, '-');   // divider (more lines follow)

// Iterate over lines
for line in msg.iter() {
    if let Ok((key, value)) = line.clone().pop_mapping(false, false) {
        println!("{} = {}", key, value);
    }
}

Fields§

§arrived_at: i64

Unix timestamp (seconds since epoch) when this message arrived.

Implementations§

Source§

impl ControlMessage

Source

pub fn new( parsed_content: Vec<(String, char, Vec<u8>)>, raw_content: Vec<u8>, arrived_at: Option<i64>, ) -> Result<Self, Error>

Creates a new ControlMessage from pre-parsed content.

This is a low-level constructor typically used internally. Most users should use from_str instead.

§Arguments
  • parsed_content - Vector of (status_code, divider, content) tuples
  • raw_content - Original raw bytes of the message
  • arrived_at - Optional Unix timestamp; defaults to current time if None
§Errors

Returns Error::Protocol if parsed_content is empty, as control messages must contain at least one line.

§Example
use stem_rs::response::ControlMessage;

let parsed = vec![("250".to_string(), ' ', b"OK".to_vec())];
let raw = b"250 OK\r\n".to_vec();
let msg = ControlMessage::new(parsed, raw, None).unwrap();
assert!(msg.is_ok());
Source

pub fn from_str( content: &str, msg_type: Option<&str>, normalize: bool, ) -> Result<Self, Error>

Parses a control message from a string.

This is the primary way to create a ControlMessage from raw protocol data. It handles both single-line and multi-line responses, including data sections.

§Arguments
  • content - The raw message string to parse
  • msg_type - Optional response type for validation (e.g., “SINGLELINE”, “GETINFO”)
  • normalize - If true, ensures proper \r\n line endings
§Normalization

When normalize is true:

  • Adds a trailing newline if missing
  • Converts \n to \r\n (CRLF) as required by the protocol
§Errors

Returns Error::Protocol if:

  • The content contains no valid control protocol lines
  • The specified msg_type validation fails
§Example
use stem_rs::response::ControlMessage;

// Parse without normalization (content already has \r\n)
let msg = ControlMessage::from_str("250 OK\r\n", None, false).unwrap();

// Parse with normalization (adds \r\n if needed)
let msg = ControlMessage::from_str("250 OK", None, true).unwrap();

// Parse and validate as single-line response
let msg = ControlMessage::from_str("250 OK\r\n", Some("SINGLELINE"), false).unwrap();
Source

pub fn is_ok(&self) -> bool

Checks if the response indicates success.

A response is considered successful if any of its lines has a status code in the 2xx range (200-299). This is the standard success range in the Tor control protocol.

§Returns

true if at least one line has a 2xx status code, false otherwise.

§Example
use stem_rs::response::ControlMessage;

let ok = ControlMessage::from_str("250 OK\r\n", None, false).unwrap();
assert!(ok.is_ok());

let err = ControlMessage::from_str("552 Unrecognized key\r\n", None, false).unwrap();
assert!(!err.is_ok());
Source

pub fn content(&self) -> Vec<(String, char, String)>

Returns the parsed content as string tuples.

Each tuple contains:

  • Status code (e.g., “250”, “552”, “650”)
  • Divider character ( , -, or +)
  • Content as a UTF-8 string (lossy conversion from bytes)
§Returns

A vector of (status_code, divider, content) tuples.

§Example
use stem_rs::response::ControlMessage;

let msg = ControlMessage::from_str("250-version=0.4.7.8\r\n250 OK\r\n", None, false).unwrap();
let content = msg.content();

assert_eq!(content[0].0, "250");
assert_eq!(content[0].1, '-');
assert!(content[0].2.starts_with("version="));

assert_eq!(content[1].0, "250");
assert_eq!(content[1].1, ' ');
assert_eq!(content[1].2, "OK");
Source

pub fn content_bytes(&self) -> &[(String, char, Vec<u8>)]

Returns the parsed content with raw bytes.

Similar to content, but preserves the original bytes without UTF-8 conversion. Useful when handling binary data or when exact byte preservation is required.

§Returns

A slice of (status_code, divider, content_bytes) tuples.

Source

pub fn raw_content(&self) -> &[u8]

Returns the original raw bytes of the message.

This is the unmodified data as received from the control socket, including all protocol formatting (\r\n, status codes, etc.).

§Returns

A byte slice of the original message data.

Source

pub fn raw_content_str(&self) -> String

Returns the raw content as a UTF-8 string.

Performs lossy UTF-8 conversion, replacing invalid sequences with the Unicode replacement character (U+FFFD).

§Returns

The raw message content as a string.

Source

pub fn iter(&self) -> impl Iterator<Item = ControlLine> + '_

Returns an iterator over the message lines as ControlLine instances.

Each ControlLine provides parsing utilities for extracting values, key-value mappings, and quoted strings from the line content.

§Example
use stem_rs::response::ControlMessage;

let msg = ControlMessage::from_str(
    "250-version=0.4.7.8\r\n250 OK\r\n",
    None,
    false
).unwrap();

for line in msg.iter() {
    println!("Line: {}", line);
}
Source

pub fn len(&self) -> usize

Returns the number of lines in the message.

§Returns

The count of parsed lines. Always at least 1 for valid messages.

Source

pub fn is_empty(&self) -> bool

Checks if the message has no lines.

§Returns

true if the message is empty, false otherwise.

§Note

Valid ControlMessage instances are never empty; this method exists for API completeness with len().

Source

pub fn get(&self, index: usize) -> Option<ControlLine>

Returns the line at the specified index as a ControlLine.

§Arguments
  • index - Zero-based index of the line to retrieve
§Returns

Some(ControlLine) if the index is valid, None otherwise.

§Example
use stem_rs::response::ControlMessage;

let msg = ControlMessage::from_str("250-first\r\n250 second\r\n", None, false).unwrap();

assert!(msg.get(0).is_some());
assert!(msg.get(1).is_some());
assert!(msg.get(2).is_none());

Trait Implementations§

Source§

impl Clone for ControlMessage

Source§

fn clone(&self) -> ControlMessage

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ControlMessage

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ControlMessage

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Hash for ControlMessage

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Index<usize> for ControlMessage

Source§

type Output = str

The returned type after indexing.
Source§

fn index(&self, _index: usize) -> &Self::Output

Performs the indexing (container[index]) operation. Read more
Source§

impl PartialEq for ControlMessage

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for ControlMessage

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.