Support multi trunks

This commit is contained in:
2026-04-01 22:17:59 -04:00
parent e6a7a40ea3
commit 75aa6129b6
9 changed files with 304 additions and 43 deletions

View File

@@ -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<String>,
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<Did, Error> {
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<Vec<Did>, Error> {
@@ -123,6 +124,7 @@ pub fn list_did() ->Result<Vec<Did>, Error> {
let mut conn = connect();
let res = dids
.order_by(id.asc())
.load(&mut conn)?;
Ok(res)

View File

@@ -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<u8> {
pub fn route_call(did: String, caller_number: String,caller_ipaddr: String) -> Vec<u8> {
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<u8> {
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");

View File

@@ -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<RouteData>) -> 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<RouteRequest>) -> 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<RouteData>) -> impl Responder {
async fn did_post(d: web::Json<JsonDid>) -> 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<JsonDid>, path: web::Path<i32>) -> 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))
})

View File

@@ -18,5 +18,7 @@ diesel::table! {
#[max_length = 512]
target -> Nullable<Varchar>,
active -> Bool,
#[max_length = 32]
trunk -> Varchar,
}
}