Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/#9 #11

Merged
merged 2 commits into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ futures = "0.3"
serde_json = "1.0"
uuid = { version = "1.4", features = ["v4"] }
thiserror = "1.0"
serde = "1.0.158"
serde = "1.0"

[dev-dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ FreeSwitch ESL implementation for Rust

```rust
use freeswitch_esl::{Esl, EslError};
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> Result<(), EslError> {
let addr = "localhost:8021"; // Freeswitch host
let stream = TcpStream::connect(addr).await?;
let password = "ClueCon";
let inbound = Esl::inbound(addr, password).await?;
let inbound = Esl::inbound(stream, password).await?;

let reloadxml = inbound.api("reloadxml").await?;
println!("reloadxml response : {:?}", reloadxml);
Expand All @@ -34,6 +36,7 @@ async fn main() -> Result<(), EslError> {

```rust
use freeswitch_esl::{Esl, EslConnection, EslError};
use tokio::net::TcpListener;

async fn process_call(conn: EslConnection) -> Result<(), EslError> {
conn.answer().await?;
Expand All @@ -58,13 +61,15 @@ async fn process_call(conn: EslConnection) -> Result<(), EslError> {

#[tokio::main]
async fn main() -> Result<(), EslError> {
env_logger::init();
let addr = "0.0.0.0:8085"; // Listening address
let listener = Esl::outbound(addr).await?;
let listener = TcpListener::bind(addr).await?;

loop {
let (socket, _) = listener.accept().await?;
tokio::spawn(async move { process_call(socket).await });
tokio::spawn(async move {
let stream = Esl::outbound(socket).await.expect("Unable to create outbound connection");
process_call(stream).await.expect("Unable to process call");
});
}
}

Expand Down
4 changes: 3 additions & 1 deletion examples/inbound.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use freeswitch_esl::{Esl, EslError};
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> Result<(), EslError> {
let addr = "localhost:8021"; // Freeswitch host
let stream = TcpStream::connect(addr).await?;
let password = "ClueCon";
let inbound = Esl::inbound(addr, password).await?;
let inbound = Esl::inbound(stream, password).await?;

let reloadxml = inbound.api("reloadxml").await?;
println!("reloadxml response : {:?}", reloadxml);
Expand Down
8 changes: 6 additions & 2 deletions examples/outbound.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use freeswitch_esl::{Esl, EslConnection, EslError};
use tokio::net::TcpListener;

async fn process_call(conn: EslConnection) -> Result<(), EslError> {
conn.answer().await?;
Expand Down Expand Up @@ -26,10 +27,13 @@ async fn process_call(conn: EslConnection) -> Result<(), EslError> {
async fn main() -> Result<(), EslError> {
let addr = "0.0.0.0:8085"; // Listening address
println!("Listening on {}", addr);
let listener = Esl::outbound(addr).await?;
let listener = TcpListener::bind(addr).await?;

loop {
let (socket, _) = listener.accept().await?;
tokio::spawn(async move { process_call(socket).await });
tokio::spawn(async move {
let stream = Esl::outbound(socket).await.unwrap();
process_call(stream).await.unwrap();
});
}
}
12 changes: 2 additions & 10 deletions src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::collections::{HashMap, VecDeque};
use std::sync::atomic::Ordering;
use std::sync::{atomic::AtomicBool, Arc};
use tokio::io::WriteHalf;
use tokio::net::{TcpStream, ToSocketAddrs};
use tokio::net::TcpStream;
use tokio::sync::{
oneshot::{channel, Sender},
Mutex,
Expand Down Expand Up @@ -69,7 +69,7 @@ impl EslConnection {
Ok(rx.await?)
}

pub(crate) async fn with_tcpstream(
pub(crate) async fn new(
stream: TcpStream,
password: impl ToString,
connection_type: EslConnectionType,
Expand Down Expand Up @@ -195,14 +195,6 @@ impl EslConnection {
self.send_recv(message.as_bytes()).await
}

pub(crate) async fn new(
socket: impl ToSocketAddrs,
password: impl ToString,
connection_type: EslConnectionType,
) -> Result<Self, EslError> {
let stream = TcpStream::connect(socket).await?;
Self::with_tcpstream(stream, password, connection_type).await
}
pub(crate) async fn auth(&self) -> Result<String, EslError> {
let auth_response = self
.send_recv(format!("auth {}", self.password).as_bytes())
Expand Down
12 changes: 6 additions & 6 deletions src/esl.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use tokio::net::ToSocketAddrs;
use tokio::net::TcpStream;

use crate::{connection::EslConnection, outbound::Outbound, EslError};
use crate::{connection::EslConnection, EslError};
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum EslConnectionType {
Inbound,
Expand All @@ -11,14 +11,14 @@ pub struct Esl;
impl Esl {
/// Creates new inbound connection to freeswitch
pub async fn inbound(
addr: impl ToSocketAddrs,
stream: TcpStream,
password: impl ToString,
) -> Result<EslConnection, EslError> {
EslConnection::new(addr, password, EslConnectionType::Inbound).await
EslConnection::new(stream, password, EslConnectionType::Inbound).await
}

/// Creates new server for outbound connection
pub async fn outbound(addr: impl ToSocketAddrs) -> Result<Outbound, EslError> {
Outbound::bind(addr).await
pub async fn outbound(stream: TcpStream) -> Result<EslConnection, EslError> {
EslConnection::new(stream, "None", EslConnectionType::Outbound).await
}
}
14 changes: 10 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
//!
//!```rust,no_run
//! use freeswitch_esl::{Esl, EslError};
//! use tokio::net::TcpStream;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), EslError> {
//! let addr = "localhost:8021"; // Freeswitch host
//! let password = "ClueCon";
//! let inbound = Esl::inbound(addr, password).await?;
//! let stream = TcpStream::connect(addr).await?;
//! let inbound = Esl::inbound(stream, "ClueCon").await?;
//!
//! let reloadxml = inbound.api("reloadxml").await?;
//! println!("reloadxml response : {:?}", reloadxml);
Expand All @@ -28,6 +30,7 @@
//!
//!```rust,no_run
//! use freeswitch_esl::{Esl, EslConnection, EslError};
//! use tokio::net::TcpListener;
//!
//! async fn process_call(conn: EslConnection) -> Result<(), EslError> {
//! conn.answer().await?;
Expand Down Expand Up @@ -55,12 +58,16 @@
//! async fn main() -> Result<(), EslError> {
//! let addr = "0.0.0.0:8085"; // Listening address
//! println!("Listening on {}", addr);
//! let listener = Esl::outbound(addr).await?;
//! let listener = TcpListener::bind(addr).await?;
//!
//! loop {
//! let (socket, _) = listener.accept().await?;
//! tokio::spawn(async move { process_call(socket).await });
//! tokio::spawn(async move {
//! let stream = Esl::outbound(socket).await.unwrap();
//! process_call(stream).await.unwrap();
//! });
//! }
//!
//! }
//! ```

Expand All @@ -71,7 +78,6 @@ pub(crate) mod error;
pub(crate) mod esl;
pub(crate) mod event;
pub(crate) mod io;
pub(crate) mod outbound;

pub use connection::EslConnection;
pub use error::*;
Expand Down
21 changes: 0 additions & 21 deletions src/outbound.rs

This file was deleted.

40 changes: 25 additions & 15 deletions tests/inbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ntest::timeout;
use regex::Regex;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpListener,
net::{TcpListener, TcpStream},
task::JoinHandle,
};

Expand Down Expand Up @@ -133,7 +133,8 @@ async fn mock_test_server() -> Result<(JoinHandle<()>, SocketAddr)> {
#[timeout(1000)]
async fn reloadxml() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let response = inbound.api("reloadxml").await;
assert_eq!(Ok("[Success]".into()), response);
Ok(())
Expand All @@ -142,7 +143,8 @@ async fn reloadxml() -> Result<()> {
#[timeout(10000)]
async fn reloadxml_with_bgapi() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let response = inbound.bgapi("reloadxml").await;
assert_eq!(Ok("[Success]".into()), response);
Ok(())
Expand All @@ -152,7 +154,8 @@ async fn reloadxml_with_bgapi() -> Result<()> {
#[timeout(10000)]
async fn call_user_that_doesnt_exists() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let response = inbound
.api("originate user/some_user_that_doesnt_exists karan")
.await
Expand All @@ -165,7 +168,8 @@ async fn call_user_that_doesnt_exists() -> Result<()> {
#[timeout(10000)]
async fn send_recv_test() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let response = inbound.send_recv(b"api reloadxml").await?;
let body = response.body().clone().unwrap();
assert_eq!("+OK [Success]\n", body);
Expand All @@ -176,16 +180,18 @@ async fn send_recv_test() -> Result<()> {
#[timeout(10000)]
async fn wrong_password() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let result = Esl::inbound(addr, "ClueCons").await;
assert_eq!(EslError::AuthFailed, result.unwrap_err());
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCons").await;
assert_eq!(EslError::AuthFailed, inbound.unwrap_err());
Ok(())
}

#[tokio::test]
#[timeout(10000)]
async fn multiple_actions() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let body = inbound.bgapi("reloadxml").await;
assert_eq!(Ok("[Success]".into()), body);
let body = inbound
Expand All @@ -202,7 +208,8 @@ async fn multiple_actions() -> Result<()> {
#[timeout(10000)]
async fn concurrent_api() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let response1 = inbound.api("reloadxml");
let response2 = inbound.api("originate user/some_user_that_doesnt_exists karan");
let response3 = inbound.api("reloadxml");
Expand All @@ -221,7 +228,8 @@ async fn concurrent_api() -> Result<()> {
async fn concurrent_bgapi() -> Result<()> {
let (_, addr) = mock_test_server().await?;

let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let response1 = inbound.bgapi("reloadxml");
let response2 = inbound.bgapi("originate user/some_user_that_doesnt_exists karan");
let response3 = inbound.bgapi("reloadxml");
Expand All @@ -239,7 +247,8 @@ async fn concurrent_bgapi() -> Result<()> {
#[timeout(10000)]
async fn connected_status() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
assert!(inbound.connected());
Ok(())
}
Expand All @@ -248,7 +257,8 @@ async fn connected_status() -> Result<()> {
#[timeout(10000)]
async fn restart_external_profile() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let inbound = Esl::inbound(addr, "ClueCon").await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;
let body = inbound.api("sofia profile external restart").await;
assert_eq!(
Ok("Reload XML [Success]\nrestarting: external".into()),
Expand All @@ -261,14 +271,14 @@ async fn restart_external_profile() -> Result<()> {
#[timeout(10000)]
async fn uuid_kill() -> Result<()> {
let (_, addr) = mock_test_server().await?;
let password = "ClueCon";
let inbound = Esl::inbound(addr, password).await?;
let stream = TcpStream::connect(addr).await?;
let inbound = Esl::inbound(stream, "ClueCon").await?;

let uuid = inbound
.api("originate {origination_uuid=karan}loopback/1000 &conference(karan)")
.await?;
assert_eq!("karan", uuid);
let uuid_kill_response = inbound.api(&format!("uuid_kill karan")).await?;
let uuid_kill_response = inbound.api("uuid_kill karan").await?;
assert_eq!("", uuid_kill_response);
Ok(())
}
Loading