Compare commits
21 Commits
c36774db3b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3de54fa0dc | |||
| 55b37e5156 | |||
| 36629ab436 | |||
| 6a720f7364 | |||
| 75aa6129b6 | |||
| e6a7a40ea3 | |||
| 03d60266cd | |||
| 743fe69f99 | |||
| c8065caf1f | |||
| a068db1595 | |||
| a21c8f5b70 | |||
| 0483588af5 | |||
| 06c8bd9919 | |||
| a0d4ff493f | |||
| e5acb2b435 | |||
| fc9ea660de | |||
| e45f067021 | |||
| fdac73f799 | |||
| fc2f3ef6b4 | |||
| 68d1e9d154 | |||
| e67940a90b |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
target
|
||||
dist
|
||||
|
||||
@@ -24,9 +24,13 @@
|
||||
<!-- domain= is special it scans the domain from the directory to build the ACL -->
|
||||
<node type="allow" domain="$${domain}"/>
|
||||
<!-- use cidr= if you wish to allow ip ranges to this domains acl. -->
|
||||
<!-- <node type="allow" cidr="192.168.0.0/24"/> -->
|
||||
<node type="allow" cidr="66.234.186.77/32"/>
|
||||
<node type="allow" cidr="76.72.215.16/32"/>
|
||||
<node type="allow" cidr="66.234.186.78/32"/>
|
||||
<node type="allow" cidr="66.234.186.87/32"/>
|
||||
<node type="allow" cidr="66.234.186.88/32"/>
|
||||
<node type="allow" cidr="172.16.0.213/24"/>
|
||||
</list>
|
||||
|
||||
</network-lists>
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
<include>
|
||||
<extension name="public_did">
|
||||
<condition field="destination_number" expression="^(5551212)$">
|
||||
<!--
|
||||
If you're hosting multiple domains you will want to set the
|
||||
target_domain on these calls so they hit the proper domain after you
|
||||
transfer the caller into the default context.
|
||||
|
||||
$${domain} is the default domain set from vars.xml but you can set it
|
||||
to any domain you have setup in your user directory.
|
||||
|
||||
-->
|
||||
<condition field="destination_number" expression="^1\d{10}$">
|
||||
<action application="set" data="domain_name=$${domain}"/>
|
||||
<!-- This example maps the DID 5551212 to ring 1000 in the default context -->
|
||||
<action application="transfer" data="1000 XML default"/>
|
||||
<action application="transfer" data="${destination_number} XML default"/>
|
||||
</condition>
|
||||
</extension>
|
||||
</include>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<!--<param name="disable-srv503" value="true"/>-->
|
||||
<!-- This could be set to "passive" -->
|
||||
<param name="local-network-acl" value="localnet.auto"/>
|
||||
<param name="apply-inbound-acl" value="domains" />
|
||||
<param name="manage-presence" value="false"/>
|
||||
|
||||
<!-- used to share presence info across sofia profiles
|
||||
|
||||
41
conf/sip_profiles/external/example.xml
vendored
41
conf/sip_profiles/external/example.xml
vendored
@@ -1,41 +0,0 @@
|
||||
<include>
|
||||
<!--<gateway name="asterlink.com">-->
|
||||
<!--/// account username *required* ///-->
|
||||
<!--<param name="username" value="cluecon"/>-->
|
||||
<!--/// auth realm: *optional* same as gateway name, if blank ///-->
|
||||
<!--<param name="realm" value="asterlink.com"/>-->
|
||||
<!--/// username to use in from: *optional* same as username, if blank ///-->
|
||||
<!--<param name="from-user" value="cluecon"/>-->
|
||||
<!--/// domain to use in from: *optional* same as realm, if blank ///-->
|
||||
<!--<param name="from-domain" value="asterlink.com"/>-->
|
||||
<!--/// account password *required* ///-->
|
||||
<!--<param name="password" value="2007"/>-->
|
||||
<!--/// extension for inbound calls: *optional* same as username, if blank ///-->
|
||||
<!--<param name="extension" value="cluecon"/>-->
|
||||
<!--/// proxy host: *optional* same as realm, if blank ///-->
|
||||
<!--<param name="proxy" value="asterlink.com"/>-->
|
||||
<!--/// send register to this proxy: *optional* same as proxy, if blank ///-->
|
||||
<!--<param name="register-proxy" value="mysbc.com"/>-->
|
||||
<!--/// expire in seconds: *optional* 3600, if blank ///-->
|
||||
<!--<param name="expire-seconds" value="60"/>-->
|
||||
<!--/// do not register ///-->
|
||||
<!--<param name="register" value="false"/>-->
|
||||
<!-- which transport to use for register -->
|
||||
<!--<param name="register-transport" value="udp"/>-->
|
||||
<!--How many seconds before a retry when a failure or timeout occurs -->
|
||||
<!--<param name="retry-seconds" value="30"/>-->
|
||||
<!--Use the callerid of an inbound call in the from field on outbound calls via this gateway -->
|
||||
<!--<param name="caller-id-in-from" value="false"/>-->
|
||||
<!--extra sip params to send in the contact-->
|
||||
<!--<param name="contact-params" value=""/>-->
|
||||
<!-- Put the extension in the contact -->
|
||||
<!--<param name="extension-in-contact" value="true"/>-->
|
||||
<!--send an options ping every x seconds, failure will unregister and/or mark it down-->
|
||||
<!--<param name="ping" value="25"/>-->
|
||||
<!--<param name="cid-type" value="rpid"/>-->
|
||||
<!--rfc5626 : Abilitazione rfc5626 ///-->
|
||||
<!--<param name="rfc-5626" value="true"/>-->
|
||||
<!--rfc5626 : extra sip params to send in the contact-->
|
||||
<!--<param name="reg-id" value="1"/>-->
|
||||
<!--</gateway>-->
|
||||
</include>
|
||||
14
conf/sip_profiles/external/powernet.xml
vendored
Normal file
14
conf/sip_profiles/external/powernet.xml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<include>
|
||||
<gateway name="powernet_1">
|
||||
<param name="register" value="false"/>
|
||||
<param name="proxy" value="66.234.186.77" />
|
||||
<param name="caller-id-in-from" value="true"/>
|
||||
<param name="ping" value="60"/>
|
||||
</gateway>
|
||||
<gateway name="powernet_2">
|
||||
<param name="register" value="false"/>
|
||||
<param name="proxy" value="76.72.215.16" />
|
||||
<param name="caller-id-in-from" value="true"/>
|
||||
<param name="ping" value="60"/>
|
||||
</gateway>
|
||||
</include>
|
||||
@@ -291,7 +291,7 @@
|
||||
If unspecified, the bind_server_ip value is used.
|
||||
Used by: sofia.conf.xml dingaling.conf.xml
|
||||
-->
|
||||
<X-PRE-PROCESS cmd="stun-set" data="external_rtp_ip=47.206.161.244"/>
|
||||
<X-PRE-PROCESS cmd="stun-set" data="external_rtp_ip=47.206.161.230"/>
|
||||
|
||||
<!-- external_sip_ip
|
||||
Used as the public IP address for SDP.
|
||||
@@ -304,7 +304,7 @@
|
||||
If unspecified, the bind_server_ip value is used.
|
||||
Used by: sofia.conf.xml dingaling.conf.xml
|
||||
-->
|
||||
<X-PRE-PROCESS cmd="stun-set" data="external_sip_ip=47.206.161.244"/>
|
||||
<X-PRE-PROCESS cmd="stun-set" data="external_sip_ip=47.206.161.230"/>
|
||||
|
||||
<!-- unroll-loops
|
||||
Used to turn on sip loopback unrolling.
|
||||
@@ -412,14 +412,14 @@
|
||||
|
||||
<!-- Internal SIP Profile -->
|
||||
<X-PRE-PROCESS cmd="set" data="internal_auth_calls=true"/>
|
||||
<X-PRE-PROCESS cmd="set" data="internal_sip_port=5060"/>
|
||||
<X-PRE-PROCESS cmd="set" data="internal_tls_port=5061"/>
|
||||
<X-PRE-PROCESS cmd="set" data="internal_sip_port=5080"/>
|
||||
<X-PRE-PROCESS cmd="set" data="internal_tls_port=5081"/>
|
||||
<X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false"/>
|
||||
|
||||
<!-- External SIP Profile -->
|
||||
<X-PRE-PROCESS cmd="set" data="external_auth_calls=false"/>
|
||||
<X-PRE-PROCESS cmd="set" data="external_sip_port=5080"/>
|
||||
<X-PRE-PROCESS cmd="set" data="external_tls_port=5081"/>
|
||||
<X-PRE-PROCESS cmd="set" data="external_sip_port=5060"/>
|
||||
<X-PRE-PROCESS cmd="set" data="external_tls_port=5061"/>
|
||||
<X-PRE-PROCESS cmd="set" data="external_ssl_enable=false"/>
|
||||
|
||||
<!-- Video Settings -->
|
||||
|
||||
294
did_router/Cargo.lock
generated
294
did_router/Cargo.lock
generated
@@ -19,6 +19,44 @@ 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-files"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8c4f30e3272d7c345f88ae0aac3848507ef5ba871f9cc2a41c8085a0f0523b"
|
||||
dependencies = [
|
||||
"actix-http",
|
||||
"actix-service",
|
||||
"actix-utils",
|
||||
"actix-web",
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"derive_more 2.1.1",
|
||||
"futures-core",
|
||||
"http-range",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"v_htmlescape",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-http"
|
||||
version = "3.12.0"
|
||||
@@ -34,7 +72,7 @@ dependencies = [
|
||||
"brotli",
|
||||
"bytes",
|
||||
"bytestring",
|
||||
"derive_more",
|
||||
"derive_more 2.1.1",
|
||||
"encoding_rs",
|
||||
"flate2",
|
||||
"foldhash",
|
||||
@@ -49,7 +87,7 @@ dependencies = [
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
"sha1",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
@@ -68,6 +106,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 +225,7 @@ dependencies = [
|
||||
"bytestring",
|
||||
"cfg-if",
|
||||
"cookie",
|
||||
"derive_more",
|
||||
"derive_more 2.1.1",
|
||||
"encoding_rs",
|
||||
"foldhash",
|
||||
"futures-core",
|
||||
@@ -296,6 +372,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 +426,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 +474,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 +505,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 +533,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 +545,14 @@ dependencies = [
|
||||
name = "did_router"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-cors",
|
||||
"actix-files",
|
||||
"actix-multipart",
|
||||
"actix-web",
|
||||
"diesel",
|
||||
"diesel-derive-enum",
|
||||
"dotenvy",
|
||||
"futures-util",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
@@ -513,7 +647,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 +686,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 +735,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 +765,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 +781,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"
|
||||
@@ -689,6 +852,12 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
@@ -837,7 +1006,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 +1022,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"
|
||||
@@ -903,6 +1078,16 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
@@ -960,6 +1145,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 +1228,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 +1266,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 +1284,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 +1340,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 +1420,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 +1570,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"
|
||||
@@ -1435,6 +1691,12 @@ version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
@@ -1471,6 +1733,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "v_htmlescape"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
||||
@@ -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"
|
||||
@@ -13,3 +15,5 @@ serde_json = "1.0.149"
|
||||
diesel-derive-enum = { version = "3.0.0-beta.1", features = ["postgres"] }
|
||||
strum = "0.24"
|
||||
strum_macros = "0.24"
|
||||
actix-cors = "0.7.1"
|
||||
actix-files = "0.6.10"
|
||||
|
||||
12
did_router/justfile
Normal file
12
did_router/justfile
Normal file
@@ -0,0 +1,12 @@
|
||||
build:
|
||||
cargo build --release
|
||||
|
||||
install: build
|
||||
cargo install --path . --root /usr/local
|
||||
cp .env /etc/did_router.conf
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/did_router
|
||||
rm -f /etc/did_router.conf
|
||||
|
||||
clean:
|
||||
cargo clean
|
||||
@@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
ALTER TABLE dids DROP COLUMN trunk;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Your SQL goes here
|
||||
ALTER TABLE dids ADD COLUMN trunk varchar(32) NOT NULL DEFAULT '3229';
|
||||
@@ -1,12 +1,14 @@
|
||||
use diesel::prelude::*;
|
||||
use diesel::pg::PgConnection;
|
||||
use diesel::result::Error;
|
||||
use dotenvy::dotenv;
|
||||
use dotenvy::{from_path};
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
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,27 +28,30 @@ 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 {
|
||||
dotenv().ok();
|
||||
let env_path = Path::new("/etc/did_router.conf");
|
||||
from_path(env_path).expect("env file missed");
|
||||
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
PgConnection::establish(&database_url)
|
||||
@@ -98,24 +103,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,7 +126,37 @@ pub fn list_did() ->Result<Vec<Did>, Error> {
|
||||
let mut conn = connect();
|
||||
|
||||
let res = dids
|
||||
.order_by(id.asc())
|
||||
.load(&mut conn)?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn from_pbx(ipaddr: &str) -> Result<bool, Error> {
|
||||
use crate::schema::dids::dsl::*;
|
||||
|
||||
let pattern = format!("%{}%", ipaddr);
|
||||
let mut conn = connect();
|
||||
let count = dids
|
||||
.filter(target.is_not_null().and(target.ilike(&pattern)))
|
||||
.count()
|
||||
.get_result::<i64>(&mut conn)?;
|
||||
|
||||
Ok(count > 0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn validate_from_pbx() {
|
||||
assert_eq!(Ok(true), from_pbx("172.16.0.213"));
|
||||
assert_eq!(Ok(true), from_pbx("172.16.0.215"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_not_from_pbx() {
|
||||
assert_eq!(Ok(false), from_pbx("192.168.1.1"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use dotenvy::dotenv;
|
||||
use dotenvy::{from_path};
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
|
||||
use super::database as db;
|
||||
use super::database::{DidTargetType, Did};
|
||||
@@ -10,7 +11,7 @@ pub fn url(did: Did) -> XMLElement {
|
||||
let target = did.target.unwrap();
|
||||
|
||||
bridge.add_attribute("application", "bridge");
|
||||
bridge.add_attribute("data", format!("sofia/internal/{}", target).as_str());
|
||||
bridge.add_attribute("data", format!("sofia/external/{}", target).as_str());
|
||||
|
||||
work.add_child(bridge).unwrap();
|
||||
|
||||
@@ -18,34 +19,52 @@ pub fn url(did: Did) -> XMLElement {
|
||||
}
|
||||
|
||||
pub fn moh(_did: Did) -> XMLElement {
|
||||
let work = XMLElement::new("work");
|
||||
let mut work = XMLElement::new("work");
|
||||
|
||||
let mut playback = XMLElement::new("playback");
|
||||
playback.add_attribute("file", "local_stream://default");
|
||||
work.add_child(playback).unwrap();
|
||||
|
||||
work
|
||||
}
|
||||
|
||||
pub fn external_number(_did: Did) -> XMLElement {
|
||||
let work = XMLElement::new("work");
|
||||
pub fn external_number(did: Did) -> XMLElement {
|
||||
let mut work = XMLElement::new("work");
|
||||
let mut bridge = XMLElement::new("execute");
|
||||
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", &ds);
|
||||
|
||||
work.add_child(bridge).unwrap();
|
||||
|
||||
work
|
||||
}
|
||||
|
||||
pub fn no_service(_did: Did) -> XMLElement {
|
||||
dotenv().ok();
|
||||
let env_path = Path::new("/etc/did_router.conf");
|
||||
from_path(env_path).expect("env file missed");
|
||||
|
||||
let sound_path = env::var("SOUND_PATH").expect("SOUND_PATH must be set");
|
||||
let no_service_path = format!("{}/no_service.wav", sound_path);
|
||||
let mut work = XMLElement::new("work");
|
||||
|
||||
add_playback(&mut work, &no_service_path);
|
||||
add_playback_element(&mut work, &no_service_path);
|
||||
|
||||
work
|
||||
}
|
||||
|
||||
pub fn night_mode(_did: Did) -> XMLElement {
|
||||
dotenv().ok();
|
||||
let env_path = Path::new("/etc/did_router.conf");
|
||||
from_path(env_path).expect("env file missed");
|
||||
|
||||
let sound_path = env::var("SOUND_PATH").expect("SOUND_PATH must be set");
|
||||
let night_mode_path = format!("{}/night_mode.wav", sound_path);
|
||||
|
||||
let mut work = XMLElement::new("work");
|
||||
|
||||
add_playback(&mut work, &night_mode_path);
|
||||
add_playback_element(&mut work, &night_mode_path);
|
||||
|
||||
work
|
||||
}
|
||||
@@ -55,32 +74,57 @@ pub fn custom_message(_did: Did) -> XMLElement {
|
||||
work
|
||||
}
|
||||
|
||||
pub fn add_playback(work: &mut XMLElement ,file_path: &str) {
|
||||
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", &ds);
|
||||
|
||||
work.add_child(bridge).unwrap();
|
||||
|
||||
work
|
||||
}
|
||||
|
||||
pub fn add_playback_element(work: &mut XMLElement ,file_path: &str) {
|
||||
let mut answer = XMLElement::new("execute");
|
||||
answer.add_attribute("application", "answer");
|
||||
work.add_child(answer).unwrap();
|
||||
|
||||
let mut playback = XMLElement::new("playback");
|
||||
playback.add_attribute("name", "exten");
|
||||
playback.add_attribute("file", &file_path);
|
||||
work.add_child(playback).unwrap();
|
||||
|
||||
let mut hangup = XMLElement::new("execute");
|
||||
hangup.add_attribute("application", "hangup");
|
||||
work.add_child(hangup).unwrap();
|
||||
}
|
||||
|
||||
pub fn route_call(did: String) -> Vec<u8> {
|
||||
pub fn build_work_element(did: &str, caller_number: &str, caller_ipaddr: &str) -> XMLElement {
|
||||
if db::from_pbx(&caller_ipaddr).unwrap() == true {
|
||||
outbound(did, caller_number)
|
||||
} else {
|
||||
let d = db::get_did_by(&did).unwrap();
|
||||
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 work = match d.target_type {
|
||||
DidTargetType::Url => {
|
||||
url(d)
|
||||
@@ -102,8 +146,39 @@ pub fn route_call(did: String) -> Vec<u8> {
|
||||
}
|
||||
};
|
||||
|
||||
work
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
.build();
|
||||
|
||||
let mut doc = XMLElement::new("document");
|
||||
doc.add_attribute("type", "xml/freeswitch-httapi");
|
||||
|
||||
let params = XMLElement::new("params");
|
||||
let mut work = build_work_element(&did, &caller_number, &caller_ipaddr);
|
||||
|
||||
let mut hangup = XMLElement::new("execute");
|
||||
hangup.add_attribute("application", "hangup");
|
||||
work.add_child(hangup).unwrap();
|
||||
|
||||
doc.add_child(params).unwrap();
|
||||
|
||||
let d = db::get_did_by(&did);
|
||||
match d {
|
||||
Ok(d) => {
|
||||
if d.active == true {
|
||||
doc.add_child(work).unwrap();
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
doc.add_child(work).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
xml.set_root_element(doc);
|
||||
|
||||
@@ -111,5 +186,4 @@ pub fn route_call(did: String) -> Vec<u8> {
|
||||
xml.generate(&mut writer).unwrap();
|
||||
|
||||
writer
|
||||
|
||||
}
|
||||
|
||||
@@ -8,16 +8,22 @@ use actix_web::{web, App,
|
||||
HttpResponse,
|
||||
HttpServer,
|
||||
http::header::ContentType,
|
||||
Responder,
|
||||
Responder, Result
|
||||
};
|
||||
use actix_cors::Cors;
|
||||
use actix_files::{Files, NamedFile};
|
||||
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
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -25,12 +31,15 @@ struct JsonDid {
|
||||
did_number: String,
|
||||
target_type: String,
|
||||
target: String,
|
||||
trunk: String,
|
||||
active: bool
|
||||
}
|
||||
|
||||
async fn route_did(data: web::Form<RouteData>) -> impl Responder {
|
||||
let did = data.dest_did.clone();
|
||||
let xml = httapi::route_call(did);
|
||||
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)
|
||||
@@ -39,7 +48,7 @@ async fn route_did(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();
|
||||
db::add_did(&did.did_number, &did.target_type, &did.target, did.active ,&did.trunk).unwrap();
|
||||
HttpResponse::Ok().body("DID added.")
|
||||
}
|
||||
|
||||
@@ -63,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
|
||||
};
|
||||
|
||||
@@ -97,12 +107,19 @@ fn api_config(cfg: &mut web::ServiceConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
async fn index() -> Result<NamedFile> {
|
||||
Ok(NamedFile::open("/var/www/did_router/index.html")?)
|
||||
}
|
||||
#[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))
|
||||
.service(Files::new("/", "/var/www/did_router/").index_file("index.html"))
|
||||
.default_service(web::route().to(index))
|
||||
})
|
||||
.bind(("0.0.0.0", 3000))?
|
||||
.run()
|
||||
|
||||
@@ -18,5 +18,7 @@ diesel::table! {
|
||||
#[max_length = 512]
|
||||
target -> Nullable<Varchar>,
|
||||
active -> Bool,
|
||||
#[max_length = 32]
|
||||
trunk -> Varchar,
|
||||
}
|
||||
}
|
||||
|
||||
1040
frontend/Cargo.lock
generated
Normal file
1040
frontend/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
frontend/Cargo.toml
Normal file
15
frontend/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "frontend"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
serde = {version = "1.0.228", features = ["derive"]}
|
||||
gloo-net = "0.7.0"
|
||||
wasm-bindgen = "0.2.116"
|
||||
wasm-bindgen-futures = "0.4.66"
|
||||
yew = { version = "0.23", features = ["csr"] }
|
||||
yew-router = "0.20.0"
|
||||
yew_icons = { version = "0.10.0", features = ["lucide"] }
|
||||
web-sys = {version = "0.3.93", features = ["HtmlSelectElement", "HtmlDialogElement"] }
|
||||
gloo-console = "0.4.0"
|
||||
8
frontend/Trunk.toml
Normal file
8
frontend/Trunk.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[serve]
|
||||
address = "127.0.0.1"
|
||||
port = 8080
|
||||
|
||||
[[hooks]]
|
||||
stage = "pre_build"
|
||||
command = "./tailwindcss"
|
||||
command_arguments = ["-i", "input.css", "-o", "./dist/.stage/app.css"]
|
||||
93
frontend/daisyui-theme.mjs
Normal file
93
frontend/daisyui-theme.mjs
Normal file
File diff suppressed because one or more lines are too long
1026
frontend/daisyui.mjs
Normal file
1026
frontend/daisyui.mjs
Normal file
File diff suppressed because one or more lines are too long
9
frontend/index.html
Normal file
9
frontend/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Did Router</title>
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
10
frontend/input.css
Normal file
10
frontend/input.css
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
@import "tailwindcss";
|
||||
|
||||
@source not "./tailwindcss";
|
||||
@source not "./daisyui{,*}.mjs";
|
||||
|
||||
@plugin "./daisyui.mjs";
|
||||
|
||||
@plugin "./daisyui-theme.mjs"{
|
||||
}
|
||||
12
frontend/justfile
Normal file
12
frontend/justfile
Normal file
@@ -0,0 +1,12 @@
|
||||
build:
|
||||
trunk build --release
|
||||
install: build
|
||||
mkdir -p /var/www/did_router
|
||||
cp dist/* /var/www/did_router/
|
||||
|
||||
uninstall:
|
||||
rm -rf /var/www/did_router
|
||||
|
||||
clean:
|
||||
trunk clean
|
||||
cargo clean
|
||||
61
frontend/src/main.rs
Normal file
61
frontend/src/main.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
mod pages;
|
||||
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
|
||||
use pages::cdr::{Cdr};
|
||||
use pages::did::{DidListComponent};
|
||||
|
||||
#[derive(Clone, Routable, PartialEq)]
|
||||
enum Route {
|
||||
#[at("/")]
|
||||
Home,
|
||||
#[at("/did")]
|
||||
Did,
|
||||
#[at("/cdr")]
|
||||
Cdr,
|
||||
}
|
||||
|
||||
fn switch(routes: Route) -> Html {
|
||||
match routes {
|
||||
Route::Home => html! {
|
||||
<DidListComponent />
|
||||
},
|
||||
Route::Did => html! {
|
||||
<DidListComponent />
|
||||
},
|
||||
Route::Cdr => html! {
|
||||
<Cdr />
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn App() -> Html {
|
||||
html! {
|
||||
<BrowserRouter>
|
||||
<div class="w-full lg:w-3/4 lg:mx-auto p-4 bg-gray-100">
|
||||
<div class="navbar bg-base-100 shadow-sm">
|
||||
<div class="navbar-start">
|
||||
</div>
|
||||
<div class="navbar-center lg:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li>
|
||||
<Link<Route> to={Route::Home}>{"DID"}</Link<Route>>
|
||||
</li>
|
||||
<li><Link<Route> to={Route::Cdr}>{"CDR"}</Link<Route>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
</div>
|
||||
</div>
|
||||
<Switch<Route> render={switch} />
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
yew::Renderer::<App>::new().render();
|
||||
}
|
||||
8
frontend/src/pages/cdr.rs
Normal file
8
frontend/src/pages/cdr.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use yew::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn Cdr() -> Html {
|
||||
html!{
|
||||
<div>{"Cdr page"}</div>
|
||||
}
|
||||
}
|
||||
335
frontend/src/pages/did.rs
Normal file
335
frontend/src/pages/did.rs
Normal file
@@ -0,0 +1,335 @@
|
||||
use yew::prelude::*;
|
||||
use web_sys::{Event, HtmlInputElement, HtmlSelectElement, HtmlDialogElement};
|
||||
use web_sys::wasm_bindgen::JsCast;
|
||||
use gloo_net::http::Request;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use yew_icons::{Icon, IconData};
|
||||
|
||||
const API_BASE: &str ="http://172.16.0.155:3000/api/fs";
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Did {
|
||||
id: i32,
|
||||
did_number: String,
|
||||
target_type: String,
|
||||
target: Option<String>,
|
||||
active: bool,
|
||||
trunk: String,
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct DidProps {
|
||||
pub did_id: i32,
|
||||
pub did_number: String,
|
||||
pub target_type: String,
|
||||
pub target: String,
|
||||
pub active: bool,
|
||||
pub trunk: String,
|
||||
pub on_changed: Callback<()>
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn DidComponent(props: &DidProps) -> Html {
|
||||
let id = props.did_id;
|
||||
let changed = use_state(||false);
|
||||
let did_number = use_state(||props.did_number.clone());
|
||||
let target_type = use_state(||props.target_type.clone());
|
||||
let target = use_state(||props.target.clone());
|
||||
let active= use_state(||props.active);
|
||||
let trunk= use_state(||props.trunk.clone());
|
||||
let on_changed = props.on_changed.clone();
|
||||
let dialog_ref: NodeRef = use_node_ref();
|
||||
|
||||
let handle_did_input = {
|
||||
let did_number = did_number.clone();
|
||||
let changed = changed.clone();
|
||||
Callback::from(move |event: InputEvent| {
|
||||
let did_number = did_number.clone();
|
||||
let t = event.target().and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
|
||||
if let Some(input) = t {
|
||||
did_number.set(input.value());
|
||||
}
|
||||
changed.set(true);
|
||||
}
|
||||
)};
|
||||
|
||||
let handle_target_input = {
|
||||
let target = target.clone();
|
||||
let changed = changed.clone();
|
||||
Callback::from(move |event: InputEvent| {
|
||||
let target = target.clone();
|
||||
let t = event.target().and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
|
||||
if let Some(input) = t {
|
||||
target.set(input.value());
|
||||
}
|
||||
changed.set(true);
|
||||
}
|
||||
)};
|
||||
|
||||
let handle_active_change = {
|
||||
let active = active.clone();
|
||||
let changed = changed.clone();
|
||||
Callback::from(move |event: Event| {
|
||||
let active = active.clone();
|
||||
let t = event
|
||||
.target()
|
||||
.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
|
||||
if let Some(input) = t {
|
||||
active.set(input.checked());
|
||||
}
|
||||
changed.set(true);
|
||||
}
|
||||
)};
|
||||
|
||||
let handle_target_type_change = {
|
||||
let target_type = target_type.clone();
|
||||
let changed = changed.clone();
|
||||
Callback::from(move |event: Event| {
|
||||
let t = event
|
||||
.target()
|
||||
.and_then(|t| t.dyn_into::<HtmlSelectElement>().ok())
|
||||
.unwrap();
|
||||
target_type.set(t.value());
|
||||
changed.set(true);
|
||||
}
|
||||
)};
|
||||
|
||||
let handle_trunk_change = {
|
||||
let trunk = trunk.clone();
|
||||
let changed = changed.clone();
|
||||
Callback::from(move |event: Event| {
|
||||
let t = event
|
||||
.target()
|
||||
.and_then(|t| t.dyn_into::<HtmlSelectElement>().ok())
|
||||
.unwrap();
|
||||
trunk.set(t.value());
|
||||
changed.set(true);
|
||||
}
|
||||
)};
|
||||
let handle_save = {
|
||||
let changed = changed.clone();
|
||||
let did_number = did_number.clone();
|
||||
let target_type = target_type.clone();
|
||||
let target = target.clone();
|
||||
let active = active.clone();
|
||||
let on_changed = on_changed.clone();
|
||||
Callback::from(move |_| {
|
||||
let changed = changed.clone();
|
||||
let on_changed = on_changed.clone();
|
||||
let did = Did {
|
||||
id,
|
||||
did_number: (*did_number).clone(),
|
||||
target_type: (*target_type).clone(),
|
||||
target: Some((*target).clone()),
|
||||
active: (*active).clone(),
|
||||
trunk: (*trunk).clone(),
|
||||
};
|
||||
let url = if id == 0 {
|
||||
API_BASE.to_string()
|
||||
} else {
|
||||
format!("{}/{}", API_BASE, id)
|
||||
};
|
||||
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let changed = changed.clone();
|
||||
let on_changed = on_changed.clone();
|
||||
let req = if id == 0 {
|
||||
Request::post(&url)
|
||||
.json(&did)
|
||||
.unwrap()
|
||||
} else {
|
||||
Request::patch(&url)
|
||||
.json(&did)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
req.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
changed.set(false);
|
||||
on_changed.emit(());
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
let handle_confirm = Callback::from(move |_| {
|
||||
let on_changed = on_changed.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let on_changed = on_changed.clone();
|
||||
Request::delete(&format!("{}/{}",API_BASE, id))
|
||||
.body("")
|
||||
.unwrap()
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
on_changed.emit(());
|
||||
})
|
||||
});
|
||||
|
||||
let handle_delete: Callback<MouseEvent> = {
|
||||
let dialog_ref = dialog_ref.clone();
|
||||
Callback::from(move |_e| {
|
||||
let d = dialog_ref.cast::<HtmlDialogElement>().unwrap();
|
||||
d.show_modal().unwrap();
|
||||
})
|
||||
};
|
||||
|
||||
html!{
|
||||
<tr>
|
||||
<td>
|
||||
<input type="text"
|
||||
class="input"
|
||||
value={(*did_number).to_string()}
|
||||
id="did_number"
|
||||
oninput={handle_did_input.clone()}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<select class="select select-ghost" onchange={handle_target_type_change}>
|
||||
<option selected={props.target_type == "Url"}>{"Url"}</option>
|
||||
<option selected={props.target_type == "Moh"}>{"Moh"}</option>
|
||||
<option selected={props.target_type == "NoService"}>{"NoService"}</option>
|
||||
<option selected={props.target_type == "NightMode"}>{"NightMode"}</option>
|
||||
<option selected={props.target_type == "ExternalNumber"}>{"ExternalNumber"}</option>
|
||||
<option selected={props.target_type == "CustomMessage"}>{"CustomMessage"}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text"
|
||||
class="input"
|
||||
id="target"
|
||||
value={(*target).clone()}
|
||||
oninput={handle_target_input.clone()}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<select class="select select-ghost" onchange={handle_trunk_change}>
|
||||
<option selected={props.trunk == "3229"}>{"3229"}</option>
|
||||
<option selected={props.trunk == "3401"}>{"3401"}</option>
|
||||
<option selected={props.trunk == "413"}>{"413"}</option>
|
||||
<option selected={props.trunk == "435"}>{"435"}</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
checked={*active}
|
||||
class="toggle"
|
||||
id="active"
|
||||
onchange={handle_active_change.clone()}
|
||||
/>
|
||||
</td>
|
||||
<td class="flex justify-end">
|
||||
if *changed && id != 0 {
|
||||
<button class="btn btn-primary btn-outline btn-circle" onclick={handle_save.clone()}>
|
||||
<Icon
|
||||
data={IconData::LUCIDE_SAVE}
|
||||
/>
|
||||
</button>
|
||||
}
|
||||
if id != 0 {
|
||||
<button class="btn btn-warning btn-outline btn-circle ml-2" onclick={handle_delete}>
|
||||
<Icon
|
||||
data={IconData::LUCIDE_TRASH_2}
|
||||
/>
|
||||
</button>
|
||||
}
|
||||
if id == 0 {
|
||||
<button class="btn btn-primary btn-outline btn-circle ml-2" onclick={handle_save}>
|
||||
<Icon
|
||||
data={IconData::LUCIDE_PLUS}
|
||||
/>
|
||||
</button>
|
||||
}
|
||||
</td>
|
||||
<dialog ref={dialog_ref} class="modal">
|
||||
<div class="modal-box">
|
||||
<h3 class="font-bold text-lg">{"Warning"}</h3>
|
||||
<p class="py-4">{format!("About to delete DID: {}", *did_number)}</p>
|
||||
<div class="modal-action">
|
||||
<form method="dialog">
|
||||
<button onclick={handle_confirm} class="btn btn-warning mr-2">{"Yes"}</button>
|
||||
<button class="btn">{"No"}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn DidListComponent() -> Html {
|
||||
let changed = use_state(||0);
|
||||
let trigger = use_force_update();
|
||||
let dids: UseStateHandle<Vec<Did>> = use_state(||vec![]);
|
||||
{
|
||||
let changed = changed.clone();
|
||||
let dids = dids.clone();
|
||||
use_effect_with(changed, move |_| {
|
||||
let dids = dids.clone();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let res = Request::get(API_BASE)
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let dids_fetched: Vec<Did> = res.json().await.unwrap();
|
||||
dids.set(dids_fetched);
|
||||
});
|
||||
});
|
||||
}
|
||||
let handle_change = Callback::from(move |()| {
|
||||
let count = *changed + 1;
|
||||
gloo_console::log!(count);
|
||||
changed.set(count);
|
||||
trigger.force_update();
|
||||
web_sys::window().unwrap().location().reload().unwrap();
|
||||
});
|
||||
|
||||
html!{
|
||||
<div>
|
||||
<table class="table">
|
||||
<DidComponent
|
||||
did_id={0}
|
||||
did_number={""}
|
||||
target_type={"NoService"}
|
||||
target={""}
|
||||
active=true
|
||||
trunk="3229"
|
||||
on_changed={handle_change.clone()}
|
||||
/>
|
||||
</table>
|
||||
<div class="divider"></div>
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{"DID number"}</th>
|
||||
<th>{"Target type"}</th>
|
||||
<th>{"Target"}</th>
|
||||
<th>{"Trunk"}</th>
|
||||
<th>{"Active"}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
dids.iter().map(|d|{
|
||||
html!{
|
||||
<DidComponent
|
||||
did_id={d.id}
|
||||
did_number={d.did_number.clone()}
|
||||
target_type={d.target_type.clone()}
|
||||
target={d.target.clone().unwrap_or_default()}
|
||||
active ={d.active}
|
||||
trunk = {d.trunk.clone()}
|
||||
on_changed={handle_change.clone()}
|
||||
/>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
2
frontend/src/pages/mod.rs
Normal file
2
frontend/src/pages/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod cdr;
|
||||
pub mod did;
|
||||
10
frontend/tailwind.config.js
Normal file
10
frontend/tailwind.config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
content: [
|
||||
"index.html",
|
||||
"./src/*.rs"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
BIN
frontend/tailwindcss
Executable file
BIN
frontend/tailwindcss
Executable file
Binary file not shown.
26
justfile
Normal file
26
justfile
Normal file
@@ -0,0 +1,26 @@
|
||||
default: build-all
|
||||
|
||||
build-all: build-api build-frontend
|
||||
|
||||
build-api:
|
||||
just --justfile ./did_router/justfile -d did_router build
|
||||
build-frontend:
|
||||
just --justfile ./frontend/justfile -d frontend build
|
||||
|
||||
install: install-api install-frontend
|
||||
install-api:
|
||||
just --justfile ./did_router/justfile -d did_router install
|
||||
install-frontend:
|
||||
just --justfile ./frontend/justfile -d frontend install
|
||||
|
||||
uninstall: uninstall-api uninstall-frontend
|
||||
uninstall-api:
|
||||
just --justfile ./did_router/justfile -d did_router uninstall
|
||||
uninstall-frontend:
|
||||
just --justfile ./frontend/justfile -d frontend uninstall
|
||||
|
||||
clean: clean-api clean-frontend
|
||||
clean-api:
|
||||
just --justfile ./did_router/justfile -d did_router clean
|
||||
clean-frontend:
|
||||
just --justfile ./frontend/justfile -d frontend clean
|
||||
Reference in New Issue
Block a user