Skip to content

Commit fff030a

Browse files
committed
feat(config): extend RouteResult with DialplanHints for enhanced routing
1 parent 229e429 commit fff030a

File tree

20 files changed

+277
-226
lines changed

20 files changed

+277
-226
lines changed

src/callrecord/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,18 @@ fn merge_metadata(record: &CallRecord, extra_metadata: Option<Value>) -> Option<
14671467
"status_code".to_string(),
14681468
Value::Number(JsonNumber::from(record.status_code)),
14691469
);
1470+
if let Some(ring_time) = record.ring_time {
1471+
map.insert(
1472+
"ring_time".to_string(),
1473+
Value::String(ring_time.to_rfc3339()),
1474+
);
1475+
}
1476+
if let Some(answer_time) = record.answer_time {
1477+
map.insert(
1478+
"answer_time".to_string(),
1479+
Value::String(answer_time.to_rfc3339()),
1480+
);
1481+
}
14701482
if let Some(reason) = record
14711483
.hangup_reason
14721484
.as_ref()

src/config.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,13 +383,21 @@ pub struct ProxyConfig {
383383
pub addons: Option<Vec<String>>,
384384
}
385385

386+
#[derive(Debug, Clone, Default)]
387+
pub struct DialplanHints {
388+
pub enable_recording: Option<bool>,
389+
pub bypass_media: Option<bool>,
390+
pub max_duration: Option<std::time::Duration>,
391+
}
392+
386393
pub enum RouteResult {
387-
Forward(InviteOption),
394+
Forward(InviteOption, Option<DialplanHints>),
388395
Queue {
389396
option: InviteOption,
390397
queue: QueuePlan,
398+
hints: Option<DialplanHints>,
391399
},
392-
NotHandled(InviteOption),
400+
NotHandled(InviteOption, Option<DialplanHints>),
393401
Abort(StatusCode, Option<String>),
394402
}
395403

src/console/handlers/call_record.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ use tokio_util::io::ReaderStream;
3030
use tracing::warn;
3131
use urlencoding::encode;
3232

33-
const BILLING_STATUS_CHARGED: &str = "charged";
34-
const BILLING_STATUS_INCLUDED: &str = "included";
35-
const BILLING_STATUS_ZERO_DURATION: &str = "zero-duration";
36-
const BILLING_STATUS_UNRATED: &str = "unrated";
37-
3833
use crate::models::{
3934
call_record::{
4035
ActiveModel as CallRecordActiveModel, Column as CallRecordColumn,
@@ -1000,13 +995,6 @@ async fn load_filters(db: &DatabaseConnection) -> Result<Value, DbErr> {
1000995
"departments": departments,
1001996
"sip_trunks": sip_trunks,
1002997
"tags": [],
1003-
"billing_status": [
1004-
"any",
1005-
BILLING_STATUS_CHARGED,
1006-
BILLING_STATUS_INCLUDED,
1007-
BILLING_STATUS_ZERO_DURATION,
1008-
BILLING_STATUS_UNRATED,
1009-
],
1010998
}))
1011999
}
10121000

@@ -1017,16 +1005,11 @@ fn build_condition(filters: &Option<QueryCallRecordFilters>) -> Condition {
10171005
if let Some(q_raw) = filters.q.as_ref() {
10181006
let trimmed = q_raw.trim();
10191007
if !trimmed.is_empty() {
1020-
let mut any_match = Condition::any();
1021-
any_match = any_match.add(CallRecordColumn::CallId.contains(trimmed));
1022-
any_match = any_match.add(CallRecordColumn::DisplayId.contains(trimmed));
1023-
any_match = any_match.add(CallRecordColumn::FromNumber.contains(trimmed));
1024-
any_match = any_match.add(CallRecordColumn::ToNumber.contains(trimmed));
1025-
any_match = any_match.add(CallRecordColumn::CallerName.contains(trimmed));
1026-
any_match = any_match.add(CallRecordColumn::AgentName.contains(trimmed));
1027-
any_match = any_match.add(CallRecordColumn::Queue.contains(trimmed));
1028-
any_match = any_match.add(CallRecordColumn::SipGateway.contains(trimmed));
1029-
condition = condition.add(any_match);
1008+
let mut q_condition = Condition::any();
1009+
q_condition = q_condition.add(CallRecordColumn::CallId.eq(trimmed));
1010+
q_condition = q_condition.add(CallRecordColumn::ToNumber.eq(trimmed));
1011+
q_condition = q_condition.add(CallRecordColumn::FromNumber.eq(trimmed));
1012+
condition = condition.add(q_condition);
10301013
}
10311014
}
10321015

@@ -1045,10 +1028,18 @@ fn build_condition(filters: &Option<QueryCallRecordFilters>) -> Condition {
10451028
}
10461029
}
10471030

1048-
if let Some(from) = parse_date(filters.date_from.as_ref(), false) {
1031+
let date_from = parse_date(filters.date_from.as_ref(), false);
1032+
let date_to = parse_date(filters.date_to.as_ref(), true);
1033+
1034+
if let Some(from) = date_from {
10491035
condition = condition.add(CallRecordColumn::StartedAt.gte(from));
1036+
} else if filters.q.is_some() {
1037+
// Default to 30 days if searching without date range to prevent full table scan
1038+
let thirty_days_ago = Utc::now() - chrono::Duration::days(30);
1039+
condition = condition.add(CallRecordColumn::StartedAt.gte(thirty_days_ago));
10501040
}
1051-
if let Some(to) = parse_date(filters.date_to.as_ref(), true) {
1041+
1042+
if let Some(to) = date_to {
10521043
condition = condition.add(CallRecordColumn::StartedAt.lte(to));
10531044
}
10541045

@@ -1469,6 +1460,8 @@ fn build_record_payload(
14691460
let rewrite_destination = json_lookup_nested_str(&record.metadata, &["rewrite", "destination"]);
14701461
let billing = build_billing_payload(record);
14711462
let status_code = json_lookup_u16(&record.metadata, "status_code");
1463+
let ring_time = json_lookup_str(&record.metadata, "ring_time");
1464+
let answer_time = json_lookup_str(&record.metadata, "answer_time");
14721465
let hangup_reason = json_lookup_str(&record.metadata, "hangup_reason");
14731466
let hangup_messages = extract_hangup_messages(&record.metadata);
14741467

@@ -1497,6 +1490,8 @@ fn build_record_payload(
14971490
"recording": recording,
14981491
"quality": quality,
14991492
"started_at": record.started_at.to_rfc3339(),
1493+
"ring_time": ring_time,
1494+
"answer_time": answer_time,
15001495
"ended_at": record.ended_at.map(|dt| dt.to_rfc3339()),
15011496
"detail_url": state.url_for(&format!("/call-records/{}", record.id)),
15021497
"billing": billing,

src/console/handlers/diagnostics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,7 +1274,7 @@ async fn route_evaluate(
12741274
};
12751275

12761276
let (outcome, caller_render, callee_render, request_render, rewrites) = match result {
1277-
RouteResult::Forward(option) => {
1277+
RouteResult::Forward(option, _) => {
12781278
let rewrites = collect_rewrite_diff(&original_option, &option);
12791279
(
12801280
RouteOutcomeView::Forward(RouteForwardOutcome {
@@ -1296,7 +1296,7 @@ async fn route_evaluate(
12961296
rewrites,
12971297
)
12981298
}
1299-
RouteResult::Queue { option, queue } => {
1299+
RouteResult::Queue { option, queue, .. } => {
13001300
let rewrites = collect_rewrite_diff(&original_option, &option);
13011301
let forward = RouteForwardOutcome {
13021302
destination: option.destination.map(|d| d.addr.to_string()),
@@ -1322,7 +1322,7 @@ async fn route_evaluate(
13221322
rewrites,
13231323
)
13241324
}
1325-
RouteResult::NotHandled(option) => {
1325+
RouteResult::NotHandled(option, _) => {
13261326
let rewrites = collect_rewrite_diff(&original_option, &option);
13271327
(
13281328
RouteOutcomeView::NotHandled,

src/handler/ami.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use tracing::{info, warn};
1919

2020
pub fn router(app_state: AppState) -> Router<AppState> {
2121
Router::new()
22+
.route("/health", get(health_handler))
2223
.route("/dialogs", get(list_dialogs))
2324
.route("/hangup/{id}", get(hangup_dialog))
2425
.route("/transactions", get(list_transactions))

src/handler/handler.rs

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/handler/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
pub mod handler;
2-
pub mod middleware;
3-
pub use handler::router;
41
pub mod ami;
2+
pub mod middleware;
3+
pub use ami::router;
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
use sea_orm_migration::prelude::*;
2+
3+
#[derive(DeriveMigrationName)]
4+
pub struct Migration;
5+
6+
#[async_trait::async_trait]
7+
impl MigrationTrait for Migration {
8+
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
9+
let table = crate::models::call_record::Entity;
10+
let col_started_at = crate::models::call_record::Column::StartedAt;
11+
let col_from_number = crate::models::call_record::Column::FromNumber;
12+
let col_to_number = crate::models::call_record::Column::ToNumber;
13+
14+
// Index on from_number
15+
if !manager
16+
.has_index(
17+
"rustpbx_call_records",
18+
"idx_rustpbx_call_records_from_number",
19+
)
20+
.await?
21+
{
22+
manager
23+
.create_index(
24+
Index::create()
25+
.name("idx_rustpbx_call_records_from_number")
26+
.table(table)
27+
.col(col_from_number)
28+
.to_owned(),
29+
)
30+
.await?;
31+
}
32+
33+
// Composite index on started_at + from_number
34+
if !manager
35+
.has_index(
36+
"rustpbx_call_records",
37+
"idx_rustpbx_call_records_started_from",
38+
)
39+
.await?
40+
{
41+
manager
42+
.create_index(
43+
Index::create()
44+
.name("idx_rustpbx_call_records_started_from")
45+
.table(table)
46+
.col(col_started_at)
47+
.col(col_from_number)
48+
.to_owned(),
49+
)
50+
.await?;
51+
}
52+
53+
// Composite index on started_at + to_number
54+
if !manager
55+
.has_index(
56+
"rustpbx_call_records",
57+
"idx_rustpbx_call_records_started_to",
58+
)
59+
.await?
60+
{
61+
manager
62+
.create_index(
63+
Index::create()
64+
.name("idx_rustpbx_call_records_started_to")
65+
.table(table)
66+
.col(col_started_at)
67+
.col(col_to_number)
68+
.to_owned(),
69+
)
70+
.await?;
71+
}
72+
73+
Ok(())
74+
}
75+
76+
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
77+
let table = crate::models::call_record::Entity;
78+
79+
manager
80+
.drop_index(
81+
Index::drop()
82+
.name("idx_rustpbx_call_records_from_number")
83+
.table(table)
84+
.to_owned(),
85+
)
86+
.await?;
87+
88+
manager
89+
.drop_index(
90+
Index::drop()
91+
.name("idx_rustpbx_call_records_started_from")
92+
.table(table)
93+
.to_owned(),
94+
)
95+
.await?;
96+
97+
manager
98+
.drop_index(
99+
Index::drop()
100+
.name("idx_rustpbx_call_records_started_to")
101+
.table(table)
102+
.to_owned(),
103+
)
104+
.await?;
105+
106+
Ok(())
107+
}
108+
}

src/models/migration.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ impl MigratorTrait for Migrator {
1717
Box::new(super::call_record_indices::Migration),
1818
Box::new(super::call_record_optimization_indices::Migration),
1919
Box::new(super::call_record_dashboard_index::Migration),
20+
Box::new(super::call_record_from_number_index::Migration),
2021
]
2122
}
2223
}

src/models/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use url::Url;
66

77
pub mod call_record;
88
pub mod call_record_dashboard_index;
9+
pub mod call_record_from_number_index;
910
pub mod call_record_indices;
1011
pub mod call_record_optimization_indices;
1112
pub mod department;

0 commit comments

Comments
 (0)