diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..eb5a316
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+target
diff --git a/conf/autoload_configs/httapi.conf.xml b/conf/autoload_configs/httapi.conf.xml
index c3566d1..c4102e0 100644
--- a/conf/autoload_configs/httapi.conf.xml
+++ b/conf/autoload_configs/httapi.conf.xml
@@ -29,20 +29,20 @@
-
-
@@ -58,15 +58,15 @@
-
@@ -79,11 +79,11 @@
-
+
-
-
+
+
diff --git a/conf/dialplan/default.xml b/conf/dialplan/default.xml
index 88045bc..5dbbed1 100644
--- a/conf/dialplan/default.xml
+++ b/conf/dialplan/default.xml
@@ -45,5 +45,10 @@
+
+
+
+
+
diff --git a/did_router/.env b/did_router/.env
new file mode 100644
index 0000000..b692b9c
--- /dev/null
+++ b/did_router/.env
@@ -0,0 +1,2 @@
+DATABASE_URL=postgres://freeswitch:T5NyU2NwQb5DD9oV@localhost/did_router
+
diff --git a/did_router/Cargo.lock b/did_router/Cargo.lock
index f7c3205..a559391 100644
--- a/did_router/Cargo.lock
+++ b/did_router/Cargo.lock
@@ -257,6 +257,12 @@ dependencies = [
"alloc-stdlib",
]
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
[[package]]
name = "bytes"
version = "1.11.1"
@@ -338,6 +344,41 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "darling"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "deranged"
version = "0.5.8"
@@ -375,6 +416,60 @@ name = "did_router"
version = "0.1.0"
dependencies = [
"actix-web",
+ "diesel",
+ "diesel-derive-enum",
+ "dotenvy",
+ "serde",
+ "serde_json",
+ "xml-builder",
+]
+
+[[package]]
+name = "diesel"
+version = "2.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ae09a41a4b89f94ec1e053623da8340d996bc32c6517d325a9daad9b239358"
+dependencies = [
+ "bitflags",
+ "byteorder",
+ "diesel_derives",
+ "downcast-rs",
+ "itoa",
+ "pq-sys",
+]
+
+[[package]]
+name = "diesel-derive-enum"
+version = "3.0.0-beta.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50a8c082045d01debc8589f8a0db9f2855a37c99c9b031325c856b5b98e1625f"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "diesel_derives"
+version = "2.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47618bf0fac06bb670c036e48404c26a865e6a71af4114dfd97dfe89936e404e"
+dependencies = [
+ "diesel_table_macro_syntax",
+ "dsl_auto_type",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "diesel_table_macro_syntax"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c"
+dependencies = [
+ "syn",
]
[[package]]
@@ -398,6 +493,38 @@ dependencies = [
"syn",
]
+[[package]]
+name = "dotenvy"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
+
+[[package]]
+name = "downcast-rs"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc"
+
+[[package]]
+name = "dsl_auto_type"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd122633e4bef06db27737f21d3738fb89c8f6d5360d6d9d7635dda142a7757e"
+dependencies = [
+ "darling",
+ "either",
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
[[package]]
name = "encoding_rs"
version = "0.8.35"
@@ -537,6 +664,18 @@ version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
[[package]]
name = "http"
version = "0.2.12"
@@ -641,6 +780,12 @@ dependencies = [
"zerovec",
]
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
[[package]]
name = "idna"
version = "1.1.0"
@@ -855,6 +1000,17 @@ dependencies = [
"zerocopy",
]
+[[package]]
+name = "pq-sys"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "574ddd6a267294433f140b02a726b0640c43cf7c6f717084684aaa3b285aba61"
+dependencies = [
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.106"
@@ -986,6 +1142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
+ "serde_derive",
]
[[package]]
@@ -1104,6 +1261,12 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
[[package]]
name = "syn"
version = "2.0.117"
@@ -1270,6 +1433,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
[[package]]
name = "version_check"
version = "0.9.5"
@@ -1391,6 +1560,12 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
+[[package]]
+name = "xml-builder"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d5951f276a574fce1cf86598f6143778be7ac5585c241f5e39dbdb0371d8b4"
+
[[package]]
name = "yoke"
version = "0.8.1"
diff --git a/did_router/Cargo.toml b/did_router/Cargo.toml
index a44a41e..959ad4c 100644
--- a/did_router/Cargo.toml
+++ b/did_router/Cargo.toml
@@ -5,3 +5,9 @@ edition = "2024"
[dependencies]
actix-web = "4"
+xml-builder = "*"
+diesel = { version = "2.3", features = ["postgres"] }
+dotenvy = "0.15"
+serde = { version = "1.0.228", features = ["derive"] }
+serde_json = "1.0.149"
+diesel-derive-enum = { version = "3.0.0-beta.1", features = ["postgres"] }
diff --git a/did_router/diesel.toml b/did_router/diesel.toml
new file mode 100644
index 0000000..a0d61bf
--- /dev/null
+++ b/did_router/diesel.toml
@@ -0,0 +1,9 @@
+# For documentation on how to configure this file,
+# see https://diesel.rs/guides/configuring-diesel-cli
+
+[print_schema]
+file = "src/schema.rs"
+custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
+
+[migrations_directory]
+dir = "migrations"
diff --git a/did_router/migrations/.diesel_lock b/did_router/migrations/.diesel_lock
new file mode 100644
index 0000000..e69de29
diff --git a/did_router/migrations/.keep b/did_router/migrations/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/did_router/migrations/00000000000000_diesel_initial_setup/down.sql b/did_router/migrations/00000000000000_diesel_initial_setup/down.sql
new file mode 100644
index 0000000..a9f5260
--- /dev/null
+++ b/did_router/migrations/00000000000000_diesel_initial_setup/down.sql
@@ -0,0 +1,6 @@
+-- This file was automatically created by Diesel to setup helper functions
+-- and other internal bookkeeping. This file is safe to edit, any future
+-- changes will be added to existing projects as new migrations.
+
+DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
+DROP FUNCTION IF EXISTS diesel_set_updated_at();
diff --git a/did_router/migrations/00000000000000_diesel_initial_setup/up.sql b/did_router/migrations/00000000000000_diesel_initial_setup/up.sql
new file mode 100644
index 0000000..d68895b
--- /dev/null
+++ b/did_router/migrations/00000000000000_diesel_initial_setup/up.sql
@@ -0,0 +1,36 @@
+-- This file was automatically created by Diesel to setup helper functions
+-- and other internal bookkeeping. This file is safe to edit, any future
+-- changes will be added to existing projects as new migrations.
+
+
+
+
+-- Sets up a trigger for the given table to automatically set a column called
+-- `updated_at` whenever the row is modified (unless `updated_at` was included
+-- in the modified columns)
+--
+-- # Example
+--
+-- ```sql
+-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
+--
+-- SELECT diesel_manage_updated_at('users');
+-- ```
+CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
+BEGIN
+ EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
+ FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD AND
+ NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
+ ) THEN
+ NEW.updated_at := current_timestamp;
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
diff --git a/did_router/migrations/2026-03-23-013910-0000_create_dids/down.sql b/did_router/migrations/2026-03-23-013910-0000_create_dids/down.sql
new file mode 100644
index 0000000..b910c19
--- /dev/null
+++ b/did_router/migrations/2026-03-23-013910-0000_create_dids/down.sql
@@ -0,0 +1,3 @@
+-- This file should undo anything in `up.sql`
+DROP TABLE dids;
+DROP TYPE did_target_type;
diff --git a/did_router/migrations/2026-03-23-013910-0000_create_dids/up.sql b/did_router/migrations/2026-03-23-013910-0000_create_dids/up.sql
new file mode 100644
index 0000000..6956d71
--- /dev/null
+++ b/did_router/migrations/2026-03-23-013910-0000_create_dids/up.sql
@@ -0,0 +1,9 @@
+-- Your SQL goes here
+CREATE TYPE did_target_type AS ENUM ('URL', 'MOH', 'EXTERNAL_NUMBER', 'NO_SERVICE', 'NIGHT_MODE', 'CUSTOME_MESSAGE');
+CREATE TABLE dids (
+ id SERIAL PRIMARY KEY,
+ did VARCHAR(64) NOT NULL,
+ target_type DID_TARGET_TYPE NOT NULL DEFAULT 'NO_SERVICE',
+ target VARCHAR(512),
+ active BOOLEAN NOT NULL DEFAULT TRUE
+)
diff --git a/did_router/src/database.rs b/did_router/src/database.rs
new file mode 100644
index 0000000..61b5ca0
--- /dev/null
+++ b/did_router/src/database.rs
@@ -0,0 +1,82 @@
+use diesel::prelude::*;
+use diesel::pg::PgConnection;
+use diesel::result::Error;
+use dotenvy::dotenv;
+use std::env;
+use serde::{Serialize};
+use diesel_derive_enum::DbEnum;
+
+
+#[derive(Debug, PartialEq, DbEnum, Serialize)]
+#[db_enum(existing_type_path = "crate::schema::sql_types::DidTargetType")]
+pub enum DidTargetType {
+ #[db_enum(rename ="URL")]
+ Url,
+ #[db_enum(rename ="MOH")]
+ Moh,
+ #[db_enum(rename ="EXTERNAL_NUMBER")]
+ ExternalNumber,
+ #[db_enum(rename ="NO_SERVICE")]
+ NoService,
+ #[db_enum(rename ="NIGHT_MODE")]
+ NightMode,
+ #[db_enum(rename ="CUSTOME_MESSAGE")]
+ CustomMessage
+}
+
+#[derive(Queryable, Selectable, Serialize)]
+#[diesel(table_name = crate::schema::dids)]
+#[diesel(check_for_backend(diesel::pg::Pg))]
+pub struct Did {
+ pub id: i32,
+ pub did: String,
+ pub target_type: DidTargetType,
+ pub target: Option,
+ pub active: bool
+}
+
+#[derive(Insertable)]
+#[diesel(table_name = crate::schema::dids)]
+pub struct NewDid<'a> {
+ pub did: &'a str,
+ pub target_type: DidTargetType,
+ pub target: Option<&'a str>,
+ pub active: bool
+}
+
+pub fn connect() -> PgConnection {
+ dotenv().ok();
+
+ let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
+ PgConnection::establish(&database_url)
+ .unwrap_or_else(|_| panic!("Error connecting to database"))
+}
+
+pub fn add_did() -> Result {
+ use crate::schema::dids;
+
+ let mut conn = connect();
+ let new_did = NewDid {
+ did: "123456",
+ target_type: DidTargetType::Url,
+ target: Some("123456"),
+ active: true
+ };
+
+ let did = diesel::insert_into(dids::table)
+ .values(&new_did)
+ .returning(Did::as_returning())
+ .get_result(&mut conn)?;
+
+ Ok(did)
+}
+
+pub fn list_did() ->Result, Error> {
+ use crate::schema::dids::dsl::*;
+ let mut conn = connect();
+
+ let res = dids
+ .load(&mut conn)?;
+
+ Ok(res)
+}
diff --git a/did_router/src/main.rs b/did_router/src/main.rs
index 555283f..85d067f 100644
--- a/did_router/src/main.rs
+++ b/did_router/src/main.rs
@@ -1,28 +1,86 @@
-use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
+pub mod database;
+pub mod schema;
-#[get("/")]
-async fn hello() -> impl Responder {
- HttpResponse::Ok().body("Hello world!")
+use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
+use actix_web::{get, post, web, App,
+ HttpResponse,
+ HttpServer,
+ http::header::ContentType,
+ Responder,
+};
+
+use database::{ add_did,
+ list_did
+};
+
+async fn route_did() -> impl Responder {
+ let mut xml = XMLBuilder::new()
+ .version(XMLVersion::XML1_1)
+ .encoding("UTF-8".into())
+ .build();
+
+ let mut doc = XMLElement::new("document");
+ doc.add_attribute("type", "xml/freeswitch-httapi");
+
+ let params = XMLElement::new("params");
+ let mut work = XMLElement::new("work");
+
+ let mut playback = XMLElement::new("playback");
+ playback.add_attribute("name", "exten");
+ playback.add_attribute("file", "ivr/ivr-welcome_to_freeswitch.wav");
+ work.add_child(playback).unwrap();
+
+ doc.add_child(params).unwrap();
+ doc.add_child(work).unwrap();
+
+ xml.set_root_element(doc);
+
+ let mut writer: Vec = Vec::new();
+ xml.generate(&mut writer).unwrap();
+
+ HttpResponse::Ok()
+ .content_type(ContentType::xml())
+ .body(writer)
}
-#[post("/echo")]
-async fn echo(req_body: String) -> impl Responder {
- HttpResponse::Ok().body(req_body)
+async fn did_post() -> impl Responder {
+ add_did().unwrap();
+ HttpResponse::Ok().body("DID added.")
}
-async fn manual_hello() -> impl Responder {
- HttpResponse::Ok().body("Hey there!")
+async fn did_index() -> impl Responder {
+ let dids = list_did().unwrap();
+ HttpResponse::Ok().json(dids)
+}
+
+fn api_config(cfg: &mut web::ServiceConfig) {
+ cfg.service(
+ web::resource("/fs")
+ .route(web::get().to(did_index))
+ .route(web::post().to(did_post))
+ .route(web::patch().to(|| async { HttpResponse::Ok().body("did patch") }))
+ .route(web::delete().to(|| async { HttpResponse::Ok().body("did delete") }))
+ );
+ cfg.service(
+ web::resource("/fs/{id}")
+ .route(web::get().to(|| async { HttpResponse::Ok().body("did get")}))
+ .route(web::patch().to(|| async { HttpResponse::Ok().body("did patch")}))
+ .route(web::delete().to(|| async { HttpResponse::Ok().body("did delete")}))
+ );
+ cfg.service(
+ web::resource("/route_did")
+ .route(web::post().to(route_did))
+ );
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
- .service(hello)
- .service(echo)
- .route("/hey", web::get().to(manual_hello))
+ .service(
+ web::scope("/api").configure(api_config))
})
- .bind(("127.0.0.1", 8080))?
+ .bind(("0.0.0.0", 3000))?
.run()
.await
}
diff --git a/did_router/src/schema.rs b/did_router/src/schema.rs
new file mode 100644
index 0000000..3ad4696
--- /dev/null
+++ b/did_router/src/schema.rs
@@ -0,0 +1,22 @@
+// @generated automatically by Diesel CLI.
+
+pub mod sql_types {
+ #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)]
+ #[diesel(postgres_type(name = "did_target_type"))]
+ pub struct DidTargetType;
+}
+
+diesel::table! {
+ use diesel::sql_types::*;
+ use super::sql_types::DidTargetType;
+
+ dids (id) {
+ id -> Int4,
+ #[max_length = 64]
+ did -> Varchar,
+ target_type -> DidTargetType,
+ #[max_length = 512]
+ target -> Nullable,
+ active -> Bool,
+ }
+}