diff --git a/conf/sip_profiles/external/powernet.xml b/conf/sip_profiles/external/powernet.xml index b620196..2916087 100644 --- a/conf/sip_profiles/external/powernet.xml +++ b/conf/sip_profiles/external/powernet.xml @@ -7,7 +7,7 @@ - + diff --git a/did_router/Cargo.lock b/did_router/Cargo.lock index ec54397..42c22f3 100644 --- a/did_router/Cargo.lock +++ b/did_router/Cargo.lock @@ -19,6 +19,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-cors" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa239b93927be1ff123eebada5a3ff23e89f0124ccb8609234e5103d5a5ae6d" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more 2.1.1", + "futures-util", + "log", + "once_cell", + "smallvec", +] + [[package]] name = "actix-http" version = "3.12.0" @@ -34,7 +49,7 @@ dependencies = [ "brotli", "bytes", "bytestring", - "derive_more", + "derive_more 2.1.1", "encoding_rs", "flate2", "foldhash", @@ -49,7 +64,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.9.2", "sha1", "smallvec", "tokio", @@ -68,6 +83,44 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "actix-multipart" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5118a26dee7e34e894f7e85aa0ee5080ae4c18bf03c0e30d49a80e418f00a53" +dependencies = [ + "actix-multipart-derive", + "actix-utils", + "actix-web", + "derive_more 0.99.20", + "futures-core", + "futures-util", + "httparse", + "local-waker", + "log", + "memchr", + "mime", + "rand 0.8.5", + "serde", + "serde_json", + "serde_plain", + "tempfile", + "tokio", +] + +[[package]] +name = "actix-multipart-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11eb847f49a700678ea2fa73daeb3208061afa2b9d1a8527c03390f4c4a1c6b" +dependencies = [ + "darling 0.20.11", + "parse-size", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "actix-router" version = "0.5.4" @@ -149,7 +202,7 @@ dependencies = [ "bytestring", "cfg-if", "cookie", - "derive_more", + "derive_more 2.1.1", "encoding_rs", "foldhash", "futures-core", @@ -296,6 +349,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "convert_case" version = "0.10.0" @@ -344,14 +403,38 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + [[package]] name = "darling" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", ] [[package]] @@ -368,13 +451,24 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.117", +] + [[package]] name = "darling_macro" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core", + "darling_core 0.21.3", "quote", "syn 2.0.117", ] @@ -388,6 +482,19 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + [[package]] name = "derive_more" version = "2.1.1" @@ -403,7 +510,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", + "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", @@ -415,10 +522,13 @@ dependencies = [ name = "did_router" version = "0.1.0" dependencies = [ + "actix-cors", + "actix-multipart", "actix-web", "diesel", "diesel-derive-enum", "dotenvy", + "futures-util", "serde", "serde_json", "strum", @@ -513,7 +623,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd122633e4bef06db27737f21d3738fb89c8f6d5360d6d9d7635dda142a7757e" dependencies = [ - "darling", + "darling 0.21.3", "either", "heck 0.5.0", "proc-macro2", @@ -552,6 +662,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -595,6 +711,17 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "futures-sink" version = "0.3.32" @@ -614,6 +741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", + "futures-macro", "futures-task", "pin-project-lite", "slab", @@ -629,6 +757,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "getrandom" version = "0.3.4" @@ -837,7 +976,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom", + "getrandom 0.3.4", "libc", ] @@ -853,6 +992,12 @@ version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "litemap" version = "0.8.1" @@ -960,6 +1105,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "parse-size" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487f2ccd1e17ce8c1bfab3a65c89525af41cfad4c8659021a1e9a2aacd73b89b" + [[package]] name = "percent-encoding" version = "2.3.2" @@ -1037,14 +1188,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -1054,7 +1226,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", ] [[package]] @@ -1063,7 +1244,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom", + "getrandom 0.3.4", ] [[package]] @@ -1119,6 +1300,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -1186,6 +1380,15 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1327,6 +1530,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "time" version = "0.3.47" diff --git a/did_router/Cargo.toml b/did_router/Cargo.toml index 8a957fa..4def76c 100644 --- a/did_router/Cargo.toml +++ b/did_router/Cargo.toml @@ -5,6 +5,8 @@ edition = "2024" [dependencies] actix-web = "4" +actix-multipart = "0.7" +futures-util = "0.3" xml-builder = "*" diesel = { version = "2.3", features = ["postgres"] } dotenvy = "0.15" @@ -12,4 +14,5 @@ serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" diesel-derive-enum = { version = "3.0.0-beta.1", features = ["postgres"] } strum = "0.24" -strum_macros = "0.24" \ No newline at end of file +strum_macros = "0.24" +actix-cors = "0.7.1" diff --git a/did_router/migrations/2026-04-01-090126-0000_add_trunk_column_to_dids/down.sql b/did_router/migrations/2026-04-01-090126-0000_add_trunk_column_to_dids/down.sql new file mode 100644 index 0000000..8701579 --- /dev/null +++ b/did_router/migrations/2026-04-01-090126-0000_add_trunk_column_to_dids/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE dids DROP COLUMN trunk; diff --git a/did_router/migrations/2026-04-01-090126-0000_add_trunk_column_to_dids/up.sql b/did_router/migrations/2026-04-01-090126-0000_add_trunk_column_to_dids/up.sql new file mode 100644 index 0000000..61b3293 --- /dev/null +++ b/did_router/migrations/2026-04-01-090126-0000_add_trunk_column_to_dids/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE dids ADD COLUMN trunk varchar(32) NOT NULL DEFAULT '3229'; diff --git a/did_router/src/database.rs b/did_router/src/database.rs index 7476988..b2a28a5 100644 --- a/did_router/src/database.rs +++ b/did_router/src/database.rs @@ -7,6 +7,7 @@ use serde::{Serialize}; use diesel_derive_enum::DbEnum; use std::str::FromStr; use strum_macros::EnumString; +use crate::schema::dids; #[derive(Debug, PartialEq, DbEnum, Serialize, EnumString)] #[db_enum(existing_type_path = "crate::schema::sql_types::DidTargetType")] @@ -26,23 +27,25 @@ pub enum DidTargetType { } #[derive(Debug, Queryable, Selectable, Serialize, AsChangeset)] -#[diesel(table_name = crate::schema::dids)] +#[diesel(table_name = dids)] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct Did { pub id: i32, pub did_number: String, pub target_type: DidTargetType, pub target: Option, - pub active: bool + pub active: bool, + pub trunk: String, } #[derive(Insertable)] -#[diesel(table_name = crate::schema::dids)] +#[diesel(table_name = dids)] pub struct NewDid<'a> { pub did_number: &'a str, pub target_type: DidTargetType, pub target: Option<&'a str>, - pub active: bool + pub active: bool, + pub trunk: &'a str, } pub fn connect() -> PgConnection { @@ -98,24 +101,22 @@ pub fn update_did(d: Did)-> Result<(), Error> { Ok(()) } -pub fn add_did(did_number: &str, target_type: &str, target: &str, active: bool) - -> Result { - use crate::schema::dids; - +pub fn add_did(did_number: &str, target_type: &str, target: &str, active: bool, trunk: &str) + -> Result<(), Error> { let mut conn = connect(); let new_did = NewDid { did_number: did_number, target_type: DidTargetType::from_str(target_type).unwrap(), target: Some(target), - active: active + active: active, + trunk: trunk, }; - let did = diesel::insert_into(dids::table) + diesel::insert_into(dids::table) .values(&new_did) - .returning(Did::as_returning()) - .get_result(&mut conn)?; + .execute(&mut conn)?; - Ok(did) + Ok(()) } pub fn list_did() ->Result, Error> { @@ -123,6 +124,7 @@ pub fn list_did() ->Result, Error> { let mut conn = connect(); let res = dids + .order_by(id.asc()) .load(&mut conn)?; Ok(res) diff --git a/did_router/src/httapi.rs b/did_router/src/httapi.rs index e41761e..c5f24df 100644 --- a/did_router/src/httapi.rs +++ b/did_router/src/httapi.rs @@ -30,10 +30,11 @@ pub fn moh(_did: Did) -> XMLElement { pub fn external_number(did: Did) -> XMLElement { let mut work = XMLElement::new("work"); let mut bridge = XMLElement::new("execute"); - let target = did.target.unwrap(); + let callee_number = did.target.unwrap(); + let ds = build_dial_string(&callee_number, &did.did_number); bridge.add_attribute("application", "bridge"); - bridge.add_attribute("data", format!("sofia/gateway/powernet_1/{}", target).as_str()); + bridge.add_attribute("data", &ds); work.add_child(bridge).unwrap(); @@ -68,12 +69,36 @@ pub fn custom_message(_did: Did) -> XMLElement { work } -pub fn outbound(d: &str) -> XMLElement { +fn build_dial_string(callee_number: &str, caller_number: &str) -> String { + let ds = match db::get_did_by(&caller_number) { + Ok(d) => { + if d.trunk == "3229" || d.trunk == "3401" { + format!("{{origination_caller_id_number={} }}sofia/gateway/powernet_1/{}", + caller_number, + callee_number) + } else { + format!("{{origination_caller_id_number={} }}sofia/gateway/powernet_2/{}", + caller_number, + callee_number) + } + }, + Err(..) =>{ + format!("{{origination_caller_id_number={} }}sofia/gateway/powernet_1/{}", + caller_number, + callee_number) + } + }; + + ds +} + +pub fn outbound(did: &str, caller_number: &str) -> XMLElement { let mut work = XMLElement::new("work"); let mut bridge = XMLElement::new("execute"); + let ds = build_dial_string(did, caller_number); bridge.add_attribute("application", "bridge"); - bridge.add_attribute("data", format!("sofia/gateway/powernet_1/{}", d).as_str()); + bridge.add_attribute("data", &ds); work.add_child(bridge).unwrap(); @@ -90,9 +115,9 @@ pub fn add_playback_element(work: &mut XMLElement ,file_path: &str) { work.add_child(playback).unwrap(); } -pub fn build_work_element(did: &str, caller_ipaddr: &str) -> XMLElement { +pub fn build_work_element(did: &str, caller_number: &str, caller_ipaddr: &str) -> XMLElement { if db::from_pbx(&caller_ipaddr).unwrap() == true { - outbound(did) + outbound(did, caller_number) } else { let d = db::get_did_by(&did).unwrap(); let work = match d.target_type { @@ -120,7 +145,7 @@ pub fn build_work_element(did: &str, caller_ipaddr: &str) -> XMLElement { } } -pub fn route_call(did: String, caller_ipaddr: String) -> Vec { +pub fn route_call(did: String, caller_number: String,caller_ipaddr: String) -> Vec { let mut xml = XMLBuilder::new() .version(XMLVersion::XML1_1) .encoding("UTF-8".into()) @@ -130,7 +155,7 @@ pub fn route_call(did: String, caller_ipaddr: String) -> Vec { doc.add_attribute("type", "xml/freeswitch-httapi"); let params = XMLElement::new("params"); - let mut work = build_work_element(&did, &caller_ipaddr); + let mut work = build_work_element(&did, &caller_number, &caller_ipaddr); let mut hangup = XMLElement::new("execute"); hangup.add_attribute("application", "hangup"); diff --git a/did_router/src/main.rs b/did_router/src/main.rs index 4fbf1b8..3134833 100644 --- a/did_router/src/main.rs +++ b/did_router/src/main.rs @@ -10,14 +10,17 @@ use actix_web::{web, App, http::header::ContentType, Responder, }; +use actix_cors::Cors; use serde::Deserialize; use database as db; use database::DidTargetType; #[derive(Debug, Deserialize)] -struct RouteData { +struct RouteRequest { #[serde(rename = "Caller-Destination-Number")] - dest_did: String, + callee_number: String, + #[serde(rename = "Caller-Caller-ID-Number")] + caller_number: String, #[serde(rename = "Caller-Network-Addr")] caller_ipaddr: String } @@ -27,13 +30,15 @@ struct JsonDid { did_number: String, target_type: String, target: String, + trunk: String, active: bool } -async fn route_did(form_data: web::Form) -> impl Responder { - let did = form_data.dest_did.clone(); - let caller_ipaddr = form_data.caller_ipaddr.clone(); - let xml = httapi::route_call(did, caller_ipaddr); +async fn route_did(request: web::Form) -> impl Responder { + let callee_number = request.callee_number.clone(); + let caller_number = request.caller_number.clone(); + let caller_ipaddr = request.caller_ipaddr.clone(); + let xml = httapi::route_call(callee_number, caller_number,caller_ipaddr); HttpResponse::Ok() .content_type(ContentType::xml()) .body(xml) @@ -42,7 +47,8 @@ async fn route_did(form_data: web::Form) -> impl Responder { async fn did_post(d: web::Json) -> impl Responder { let did = d.deref(); - db::add_did(&did.did_number, &did.target_type, &did.target, did.active).unwrap(); + println!("{:?}", did); + db::add_did(&did.did_number, &did.target_type, &did.target, did.active ,&did.trunk).unwrap(); HttpResponse::Ok().body("DID added.") } @@ -66,6 +72,7 @@ async fn did_patch(d: web::Json, path: web::Path) -> impl Responde did_number: d.did_number.clone(), target_type: DidTargetType::from_str(&d.target_type).unwrap(), target: Some(d.target.clone()), + trunk: d.trunk.clone(), active: d.active }; @@ -103,7 +110,9 @@ fn api_config(cfg: &mut web::ServiceConfig) { #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { + let cors = Cors::permissive(); App::new() + .wrap(cors) .service( web::scope("/api").configure(api_config)) }) diff --git a/did_router/src/schema.rs b/did_router/src/schema.rs index 1640db7..65ac790 100644 --- a/did_router/src/schema.rs +++ b/did_router/src/schema.rs @@ -18,5 +18,7 @@ diesel::table! { #[max_length = 512] target -> Nullable, active -> Bool, + #[max_length = 32] + trunk -> Varchar, } }