1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
use core::fmt;
use std::net::SocketAddr;
use std::str::FromStr;
use ockam_core::{Address, Result};
use ockam_node::Context;
use crate::{parse_socket_addr, WebSocketRouter, WebSocketRouterHandle, WS};
/// High level management interface for WebSocket transports.
///
/// Be aware that only one `WebSocketTransport` can exist per node, as it
/// registers itself as a router for the `WS` address type. Multiple
/// calls to [`WebSocketTransport::create`](crate::WebSocketTransport::create)
/// will fail.
///
/// To listen for incoming connections use
/// [`ws.listen()`](crate::WebSocketTransport::listen).
///
/// To register additional connections on an already initialised
/// `WebSocketTransport`, use [`ws.connect()`](crate::WebSocketTransport::connect).
/// This step is optional because the underlying WebSocketRouter is capable of lazily
/// establishing a connection upon arrival of an initial message.
///
/// ```rust
/// use ockam_transport_websocket::WebSocketTransport;
/// # use ockam_core::Result;
/// # use ockam_node::Context;
/// # async fn test(ctx: Context) -> Result<()> {
/// let ws = WebSocketTransport::create(&ctx).await?;
/// ws.listen("127.0.0.1:8000").await?; // Listen on port 8000
/// ws.connect("127.0.0.1:5000").await?; // And connect to port 5000
/// # Ok(()) }
/// ```
///
/// The same `WebSocketTransport` can also bind to multiple ports.
///
/// ```rust
/// use ockam_transport_websocket::WebSocketTransport;
/// # use ockam_core::{Address, Result};
/// # use ockam_node::Context;
/// # async fn test(ctx: Context) -> Result<()> {
/// let ws = WebSocketTransport::create(&ctx).await?;
/// ws.listen("127.0.0.1:8000").await?; // Listen on port 8000
/// ws.listen("127.0.0.1:9000").await?; // Listen on port 9000
/// # Ok(()) }
/// ```
pub struct WebSocketTransport {
router_handle: WebSocketRouterHandle,
}
impl WebSocketTransport {
/// Create a new WebSocket transport and router for the current node.
///
/// ```rust
/// use ockam_transport_websocket::WebSocketTransport;
/// # use ockam_node::Context;
/// # use ockam_core::Result;
/// # async fn test(ctx: Context) -> Result<()> {
/// let ws = WebSocketTransport::create(&ctx).await?;
/// # Ok(()) }
/// ```
pub async fn create(ctx: &Context) -> Result<WebSocketTransport> {
let router_handle = WebSocketRouter::register(ctx).await?;
Ok(Self { router_handle })
}
/// Establish an outgoing WebSocket connection on an existing transport.
///
/// ```rust
/// use ockam_transport_websocket::WebSocketTransport;
/// # use ockam_node::Context;
/// # use ockam_core::Result;
/// # async fn test(ctx: Context) -> Result<()> {
/// let ws = WebSocketTransport::create(&ctx).await?;
/// ws.listen("127.0.0.1:8000").await?; // Listen on port 8000
/// ws.connect("127.0.0.1:5000").await?; // and connect to port 5000
/// # Ok(()) }
/// ```
pub async fn connect<S: AsRef<str>>(&self, peer: S) -> Result<()> {
self.router_handle.connect(peer).await
}
/// Start listening to incoming connections on an existing transport.
///
/// Returns the local address that this transport is bound to.
///
/// This can be useful, for example, when binding to port 0 to figure out
/// which port was actually bound.
///
/// ```rust
/// use ockam_transport_websocket::WebSocketTransport;
/// # use ockam_node::Context;
/// # use ockam_core::Result;
/// # async fn test(ctx: Context) -> Result<()> {
/// let ws = WebSocketTransport::create(&ctx).await?;
/// ws.listen("127.0.0.1:8000").await?;
/// # Ok(()) }
pub async fn listen<S: AsRef<str>>(&self, bind_addr: S) -> Result<SocketAddr> {
let bind_addr = parse_socket_addr(bind_addr)?;
self.router_handle.bind(bind_addr).await
}
}
#[derive(Clone)]
pub(crate) struct WebSocketAddress {
protocol: String,
socket_addr: SocketAddr,
}
impl From<WebSocketAddress> for Address {
fn from(other: WebSocketAddress) -> Self {
format!("{}#{}", WS, other.socket_addr).into()
}
}
impl From<SocketAddr> for WebSocketAddress {
fn from(socket_addr: SocketAddr) -> Self {
Self {
protocol: "ws".to_string(),
socket_addr,
}
}
}
impl From<WebSocketAddress> for SocketAddr {
fn from(other: WebSocketAddress) -> Self {
other.socket_addr
}
}
impl From<&WebSocketAddress> for String {
fn from(other: &WebSocketAddress) -> Self {
other.to_string()
}
}
impl FromStr for WebSocketAddress {
type Err = ockam_core::Error;
fn from_str(s: &str) -> Result<Self> {
let socket_addr = parse_socket_addr(s)?;
Ok(WebSocketAddress::from(socket_addr))
}
}
impl fmt::Display for WebSocketAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}://{}", &self.protocol, &self.socket_addr)
}
}