refactor websocket veilid_config and update scripts
This commit is contained in:
parent
de36b0d6d6
commit
ea8ffea1c9
@ -15,10 +15,10 @@ if sys.version_info < (3, 0, 0):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
veilid_server_exe_debug = os.path.join(script_dir, '..', 'veilid-server',
|
veilid_server_exe_debug = os.path.join(script_dir, '..',
|
||||||
'target', 'debug', 'veilid-server')
|
'target', 'debug', 'veilid-server')
|
||||||
veilid_server_exe_release = os.path.join(
|
veilid_server_exe_release = os.path.join(
|
||||||
script_dir, '..', 'veilid-server', 'target', 'release', 'veilid-server')
|
script_dir, '..', 'target', 'release', 'veilid-server')
|
||||||
main_process = None
|
main_process = None
|
||||||
subindex_processes = []
|
subindex_processes = []
|
||||||
|
|
@ -860,11 +860,11 @@ impl Network {
|
|||||||
|
|
||||||
pub async fn start_ws_listeners(&self) -> Result<(), String> {
|
pub async fn start_ws_listeners(&self) -> Result<(), String> {
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
let (listen_address, public_address, path) = {
|
let (listen_address, url, path) = {
|
||||||
let c = self.config.get();
|
let c = self.config.get();
|
||||||
(
|
(
|
||||||
c.network.protocol.ws.listen_address.clone(),
|
c.network.protocol.ws.listen_address.clone(),
|
||||||
c.network.protocol.ws.public_address.clone(),
|
c.network.protocol.ws.url.clone(),
|
||||||
c.network.protocol.ws.path.clone(),
|
c.network.protocol.ws.path.clone(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -888,21 +888,20 @@ impl Network {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Add static public dialinfo if it's configured
|
// Add static public dialinfo if it's configured
|
||||||
if let Some(public_address) = public_address.as_ref() {
|
if let Some(url) = url.as_ref() {
|
||||||
let (public_fqdn, public_port) = split_port(public_address).map_err(|_| {
|
let split_url = SplitUrl::from_str(url)?;
|
||||||
"invalid WS public address, port not specified correctly".to_owned()
|
if split_url.scheme.to_ascii_lowercase() != "ws" {
|
||||||
})?;
|
return Err("WS URL must use 'ws://' scheme".to_owned());
|
||||||
let public_port = public_port
|
}
|
||||||
.ok_or_else(|| "port must be specified for public WS address".to_owned())?;
|
|
||||||
|
|
||||||
routing_table.register_global_dial_info(
|
routing_table.register_global_dial_info(
|
||||||
DialInfo::ws(fqdn, public_port, public_fqdn),
|
DialInfo::ws(
|
||||||
Some(NetworkClass::Server),
|
split_url.host,
|
||||||
DialInfoOrigin::Static,
|
split_url.port.unwrap_or(80),
|
||||||
);
|
split_url
|
||||||
} else {
|
.path
|
||||||
routing_table.register_global_dial_info(
|
.map(|p| p.to_string())
|
||||||
DialInfo::ws(fqdn, port, path.clone()),
|
.unwrap_or_else(|| "/".to_string()),
|
||||||
|
),
|
||||||
Some(NetworkClass::Server),
|
Some(NetworkClass::Server),
|
||||||
DialInfoOrigin::Static,
|
DialInfoOrigin::Static,
|
||||||
);
|
);
|
||||||
@ -914,11 +913,11 @@ impl Network {
|
|||||||
|
|
||||||
pub async fn start_wss_listeners(&self) -> Result<(), String> {
|
pub async fn start_wss_listeners(&self) -> Result<(), String> {
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
let (listen_address, public_address, path) = {
|
let (listen_address, url, path) = {
|
||||||
let c = self.config.get();
|
let c = self.config.get();
|
||||||
(
|
(
|
||||||
c.network.protocol.wss.listen_address.clone(),
|
c.network.protocol.wss.listen_address.clone(),
|
||||||
c.network.protocol.wss.public_address.clone(),
|
c.network.protocol.wss.url.clone(),
|
||||||
c.network.protocol.wss.path.clone(),
|
c.network.protocol.wss.path.clone(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -943,24 +942,25 @@ impl Network {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Add static public dialinfo if it's configured
|
// Add static public dialinfo if it's configured
|
||||||
if let Some(public_address) = public_address.as_ref() {
|
if let Some(url) = url.as_ref() {
|
||||||
let (public_fqdn, public_port) = split_port(public_address).map_err(|_| {
|
let split_url = SplitUrl::from_str(url)?;
|
||||||
"invalid WSS public address, port not specified correctly".to_owned()
|
if split_url.scheme.to_ascii_lowercase() != "wss" {
|
||||||
})?;
|
return Err("WSS URL must use 'wss://' scheme".to_owned());
|
||||||
let public_port = public_port
|
}
|
||||||
.ok_or_else(|| "port must be specified for public WSS address".to_owned())?;
|
|
||||||
|
|
||||||
routing_table.register_global_dial_info(
|
routing_table.register_global_dial_info(
|
||||||
DialInfo::wss(fqdn, public_port, public_fqdn),
|
DialInfo::wss(
|
||||||
None,
|
split_url.host,
|
||||||
|
split_url.port.unwrap_or(443),
|
||||||
|
split_url
|
||||||
|
.path
|
||||||
|
.map(|p| p.to_string())
|
||||||
|
.unwrap_or_else(|| "/".to_string()),
|
||||||
|
),
|
||||||
|
Some(NetworkClass::Server),
|
||||||
DialInfoOrigin::Static,
|
DialInfoOrigin::Static,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
routing_table.register_global_dial_info(
|
return Err("WSS URL must be specified due to TLS requirements".to_owned());
|
||||||
DialInfo::wss(fqdn, port, path.clone()),
|
|
||||||
None,
|
|
||||||
DialInfoOrigin::Static,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inner.lock().wss_listen = true;
|
self.inner.lock().wss_listen = true;
|
||||||
|
@ -227,10 +227,11 @@ impl NetworkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn tick(&self) -> Result<(), String> {
|
pub async fn tick(&self) -> Result<(), String> {
|
||||||
let (net, lease_manager, receipt_manager) = {
|
let (routing_table, net, lease_manager, receipt_manager) = {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
let components = inner.components.as_ref().unwrap();
|
let components = inner.components.as_ref().unwrap();
|
||||||
(
|
(
|
||||||
|
inner.routing_table.as_ref().unwrap().clone(),
|
||||||
components.net.clone(),
|
components.net.clone(),
|
||||||
components.lease_manager.clone(),
|
components.lease_manager.clone(),
|
||||||
components.receipt_manager.clone(),
|
components.receipt_manager.clone(),
|
||||||
@ -244,6 +245,9 @@ impl NetworkManager {
|
|||||||
net.startup().await?;
|
net.startup().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the routing table tick
|
||||||
|
routing_table.tick().await?;
|
||||||
|
|
||||||
// Run the low level network tick
|
// Run the low level network tick
|
||||||
net.tick().await?;
|
net.tick().await?;
|
||||||
|
|
||||||
|
@ -205,14 +205,14 @@ impl RoutingTable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Local Dial Info: {} ({:?})",
|
"Local Dial Info: {}",
|
||||||
NodeDialInfoSingle {
|
NodeDialInfoSingle {
|
||||||
node_id: NodeId::new(inner.node_id),
|
node_id: NodeId::new(inner.node_id),
|
||||||
dial_info
|
dial_info
|
||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
origin,
|
|
||||||
);
|
);
|
||||||
|
debug!(" Origin: {:?}", origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_local_dial_info(&self) {
|
pub fn clear_local_dial_info(&self) {
|
||||||
@ -281,15 +281,15 @@ impl RoutingTable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Public Dial Info: {} ({:?}#{:?})",
|
"Public Dial Info: {}",
|
||||||
NodeDialInfoSingle {
|
NodeDialInfoSingle {
|
||||||
node_id: NodeId::new(inner.node_id),
|
node_id: NodeId::new(inner.node_id),
|
||||||
dial_info
|
dial_info
|
||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
origin,
|
|
||||||
network_class,
|
|
||||||
);
|
);
|
||||||
|
debug!(" Origin: {:?}", origin);
|
||||||
|
debug!(" Network Class: {:?}", network_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_global_dial_info(&self) {
|
pub fn clear_global_dial_info(&self) {
|
||||||
@ -613,6 +613,8 @@ impl RoutingTable {
|
|||||||
c.network.bootstrap.clone()
|
c.network.bootstrap.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
trace!("Bootstrap task with: {:?}", bootstrap);
|
||||||
|
|
||||||
// Map all bootstrap entries to a single key with multiple dialinfo
|
// Map all bootstrap entries to a single key with multiple dialinfo
|
||||||
let mut bsmap: BTreeMap<DHTKey, Vec<DialInfo>> = BTreeMap::new();
|
let mut bsmap: BTreeMap<DHTKey, Vec<DialInfo>> = BTreeMap::new();
|
||||||
for b in bootstrap {
|
for b in bootstrap {
|
||||||
|
@ -311,6 +311,131 @@ pub async fn test_sleep() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_split_url {
|
||||||
|
($url:expr, $scheme:expr, $host:expr) => {
|
||||||
|
assert_eq!(
|
||||||
|
SplitUrl::from_str($url),
|
||||||
|
Ok(SplitUrl::new($scheme, None, $host, None, None))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
($url:expr, $scheme:expr, $host:expr, $port:expr) => {
|
||||||
|
assert_eq!(
|
||||||
|
SplitUrl::from_str($url),
|
||||||
|
Ok(SplitUrl::new($scheme, None, $host, $port, None))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
($url:expr, $scheme:expr, $host:expr, $port:expr, $path:expr) => {
|
||||||
|
assert_eq!(
|
||||||
|
SplitUrl::from_str($url),
|
||||||
|
Ok(SplitUrl::new(
|
||||||
|
$scheme,
|
||||||
|
None,
|
||||||
|
$host,
|
||||||
|
$port,
|
||||||
|
Some(SplitUrlPath::new(
|
||||||
|
$path,
|
||||||
|
Option::<String>::None,
|
||||||
|
Option::<String>::None
|
||||||
|
))
|
||||||
|
))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
($url:expr, $scheme:expr, $host:expr, $port:expr, $path:expr, $frag:expr, $query:expr) => {
|
||||||
|
assert_eq!(
|
||||||
|
SplitUrl::from_str($url),
|
||||||
|
Ok(SplitUrl::new(
|
||||||
|
$scheme,
|
||||||
|
None,
|
||||||
|
$host,
|
||||||
|
$port,
|
||||||
|
Some(SplitUrlPath::new($path, $frag, $query))
|
||||||
|
))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_split_url_parse {
|
||||||
|
($url:expr) => {
|
||||||
|
let url = $url;
|
||||||
|
let su1 = SplitUrl::from_str(url).expect("should parse");
|
||||||
|
assert_eq!(su1.to_string(), url);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! assert_err {
|
||||||
|
($ex:expr) => {
|
||||||
|
if let Ok(v) = $ex {
|
||||||
|
panic!("assertion failed, expected Err(..), got {:?}", v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_split_url() {
|
||||||
|
info!("testing split_url");
|
||||||
|
|
||||||
|
assert_split_url!("http://foo", "http", "foo");
|
||||||
|
assert_split_url!("http://foo:1234", "http", "foo", Some(1234));
|
||||||
|
assert_split_url!("http://foo:1234/", "http", "foo", Some(1234), "");
|
||||||
|
assert_split_url!(
|
||||||
|
"http://foo:1234/asdf/qwer",
|
||||||
|
"http",
|
||||||
|
"foo",
|
||||||
|
Some(1234),
|
||||||
|
"asdf/qwer"
|
||||||
|
);
|
||||||
|
assert_split_url!("http://foo/", "http", "foo", None, "");
|
||||||
|
assert_split_url!("http://foo/asdf/qwer", "http", "foo", None, "asdf/qwer");
|
||||||
|
assert_split_url!(
|
||||||
|
"http://foo/asdf/qwer#3",
|
||||||
|
"http",
|
||||||
|
"foo",
|
||||||
|
None,
|
||||||
|
"asdf/qwer",
|
||||||
|
Some("3"),
|
||||||
|
Option::<String>::None
|
||||||
|
);
|
||||||
|
assert_split_url!(
|
||||||
|
"http://foo/asdf/qwer?xxx",
|
||||||
|
"http",
|
||||||
|
"foo",
|
||||||
|
None,
|
||||||
|
"asdf/qwer",
|
||||||
|
Option::<String>::None,
|
||||||
|
Some("xxx")
|
||||||
|
);
|
||||||
|
assert_split_url!(
|
||||||
|
"http://foo/asdf/qwer#yyy?xxx",
|
||||||
|
"http",
|
||||||
|
"foo",
|
||||||
|
None,
|
||||||
|
"asdf/qwer",
|
||||||
|
Some("yyy"),
|
||||||
|
Some("xxx")
|
||||||
|
);
|
||||||
|
assert_err!(SplitUrl::from_str("://asdf"));
|
||||||
|
assert_err!(SplitUrl::from_str(""));
|
||||||
|
assert_err!(SplitUrl::from_str("::"));
|
||||||
|
assert_err!(SplitUrl::from_str("://:"));
|
||||||
|
assert_err!(SplitUrl::from_str("a://:"));
|
||||||
|
assert_err!(SplitUrl::from_str("a://:1243"));
|
||||||
|
assert_err!(SplitUrl::from_str("a://:65536"));
|
||||||
|
assert_err!(SplitUrl::from_str("a://:-16"));
|
||||||
|
assert_err!(SplitUrl::from_str("a:///"));
|
||||||
|
assert_err!(SplitUrl::from_str("a:///qwer:"));
|
||||||
|
assert_err!(SplitUrl::from_str("a:///qwer://"));
|
||||||
|
assert_err!(SplitUrl::from_str("a://qwer://"));
|
||||||
|
|
||||||
|
assert_split_url_parse!("sch://foo:bar@baz.com:1234/fnord#qux?zuz");
|
||||||
|
assert_split_url_parse!("sch://foo:bar@baz.com:1234/fnord#qux");
|
||||||
|
assert_split_url_parse!("sch://foo:bar@baz.com:1234/fnord?zuz");
|
||||||
|
assert_split_url_parse!("sch://foo:bar@baz.com:1234/fnord/");
|
||||||
|
assert_split_url_parse!("sch://foo:bar@baz.com:1234//");
|
||||||
|
assert_split_url_parse!("sch://foo:bar@baz.com:1234");
|
||||||
|
assert_split_url_parse!("sch://@baz.com:1234");
|
||||||
|
assert_split_url_parse!("sch://baz.com/asdf/asdf");
|
||||||
|
assert_split_url_parse!("sch://baz.com/");
|
||||||
|
assert_split_url_parse!("s://s");
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn test_protected_store() {
|
pub async fn test_protected_store() {
|
||||||
info!("testing protected store");
|
info!("testing protected store");
|
||||||
|
|
||||||
@ -518,6 +643,7 @@ pub async fn test_all() {
|
|||||||
test_log().await;
|
test_log().await;
|
||||||
test_get_timestamp().await;
|
test_get_timestamp().await;
|
||||||
test_tools().await;
|
test_tools().await;
|
||||||
|
test_split_url().await;
|
||||||
test_get_random_u64().await;
|
test_get_random_u64().await;
|
||||||
test_get_random_u32().await;
|
test_get_random_u32().await;
|
||||||
test_sleep().await;
|
test_sleep().await;
|
||||||
|
@ -189,13 +189,16 @@ pub fn config_callback(key: String) -> Result<Box<dyn core::any::Any>, String> {
|
|||||||
"network.tls.certificate_path" => Ok(Box::new(get_certfile_path())),
|
"network.tls.certificate_path" => Ok(Box::new(get_certfile_path())),
|
||||||
"network.tls.private_key_path" => Ok(Box::new(get_keyfile_path())),
|
"network.tls.private_key_path" => Ok(Box::new(get_keyfile_path())),
|
||||||
"network.tls.connection_initial_timeout" => Ok(Box::new(2_000_000u64)),
|
"network.tls.connection_initial_timeout" => Ok(Box::new(2_000_000u64)),
|
||||||
"network.application.path" => Ok(Box::new(String::from("/app"))),
|
"network.application.https.enabled" => Ok(Box::new(false)),
|
||||||
"network.application.https.enabled" => Ok(Box::new(true)),
|
|
||||||
"network.application.https.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
"network.application.https.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
||||||
"network.application.http.enabled" => Ok(Box::new(true)),
|
"network.application.https.path" => Ok(Box::new(String::from("app"))),
|
||||||
|
"network.application.https.url" => Ok(Box::new(Option::<String>::None)),
|
||||||
|
"network.application.http.enabled" => Ok(Box::new(false)),
|
||||||
"network.application.http.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
"network.application.http.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
||||||
|
"network.application.http.path" => Ok(Box::new(String::from("app"))),
|
||||||
|
"network.application.http.url" => Ok(Box::new(Option::<String>::None)),
|
||||||
"network.protocol.udp.enabled" => Ok(Box::new(true)),
|
"network.protocol.udp.enabled" => Ok(Box::new(true)),
|
||||||
"network.protocol.udp.socket_pool_size" => Ok(Box::new(0u32)),
|
"network.protocol.udp.socket_pool_size" => Ok(Box::new(16u32)),
|
||||||
"network.protocol.udp.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
"network.protocol.udp.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
||||||
"network.protocol.udp.public_address" => Ok(Box::new(Option::<String>::None)),
|
"network.protocol.udp.public_address" => Ok(Box::new(Option::<String>::None)),
|
||||||
"network.protocol.tcp.connect" => Ok(Box::new(true)),
|
"network.protocol.tcp.connect" => Ok(Box::new(true)),
|
||||||
@ -203,23 +206,27 @@ pub fn config_callback(key: String) -> Result<Box<dyn core::any::Any>, String> {
|
|||||||
"network.protocol.tcp.max_connections" => Ok(Box::new(32u32)),
|
"network.protocol.tcp.max_connections" => Ok(Box::new(32u32)),
|
||||||
"network.protocol.tcp.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
"network.protocol.tcp.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
||||||
"network.protocol.tcp.public_address" => Ok(Box::new(Option::<String>::None)),
|
"network.protocol.tcp.public_address" => Ok(Box::new(Option::<String>::None)),
|
||||||
"network.protocol.ws.connect" => Ok(Box::new(true)),
|
"network.protocol.ws.connect" => Ok(Box::new(false)),
|
||||||
"network.protocol.ws.listen" => Ok(Box::new(true)),
|
"network.protocol.ws.listen" => Ok(Box::new(false)),
|
||||||
"network.protocol.ws.max_connections" => Ok(Box::new(16u32)),
|
"network.protocol.ws.max_connections" => Ok(Box::new(16u32)),
|
||||||
"network.protocol.ws.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
"network.protocol.ws.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
||||||
"network.protocol.ws.path" => Ok(Box::new(String::from("/ws"))),
|
"network.protocol.ws.path" => Ok(Box::new(String::from("ws"))),
|
||||||
"network.protocol.ws.public_address" => Ok(Box::new(Option::<String>::None)),
|
"network.protocol.ws.url" => Ok(Box::new(Option::<String>::None)),
|
||||||
"network.protocol.wss.connect" => Ok(Box::new(true)),
|
"network.protocol.wss.connect" => Ok(Box::new(false)),
|
||||||
"network.protocol.wss.listen" => Ok(Box::new(true)),
|
"network.protocol.wss.listen" => Ok(Box::new(false)),
|
||||||
"network.protocol.wss.max_connections" => Ok(Box::new(16u32)),
|
"network.protocol.wss.max_connections" => Ok(Box::new(16u32)),
|
||||||
"network.protocol.wss.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
"network.protocol.wss.listen_address" => Ok(Box::new(String::from("[::1]:5150"))),
|
||||||
"network.protocol.wss.path" => Ok(Box::new(String::from("/ws"))),
|
"network.protocol.wss.path" => Ok(Box::new(String::from("ws"))),
|
||||||
"network.protocol.wss.public_address" => Ok(Box::new(Option::<String>::None)),
|
"network.protocol.wss.url" => Ok(Box::new(Option::<String>::None)),
|
||||||
"network.leases.max_server_signal_leases" => Ok(Box::new(256u32)),
|
"network.leases.max_server_signal_leases" => Ok(Box::new(256u32)),
|
||||||
"network.leases.max_server_relay_leases" => Ok(Box::new(8u32)),
|
"network.leases.max_server_relay_leases" => Ok(Box::new(8u32)),
|
||||||
"network.leases.max_client_signal_leases" => Ok(Box::new(2u32)),
|
"network.leases.max_client_signal_leases" => Ok(Box::new(2u32)),
|
||||||
"network.leases.max_client_relay_leases" => Ok(Box::new(2u32)),
|
"network.leases.max_client_relay_leases" => Ok(Box::new(2u32)),
|
||||||
_ => Err(format!("config key '{}' doesn't exist", key)),
|
_ => {
|
||||||
|
let err = format!("config key '{}' doesn't exist", key);
|
||||||
|
debug!("{}", err);
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,13 +285,16 @@ pub async fn test_config() {
|
|||||||
assert_eq!(inner.network.tls.private_key_path, get_keyfile_path());
|
assert_eq!(inner.network.tls.private_key_path, get_keyfile_path());
|
||||||
assert_eq!(inner.network.tls.connection_initial_timeout, 2_000_000u64);
|
assert_eq!(inner.network.tls.connection_initial_timeout, 2_000_000u64);
|
||||||
|
|
||||||
assert_eq!(inner.network.application.path, "/app");
|
assert_eq!(inner.network.application.https.enabled, false);
|
||||||
assert_eq!(inner.network.application.https.enabled, true);
|
|
||||||
assert_eq!(inner.network.application.https.listen_address, "[::1]:5150");
|
assert_eq!(inner.network.application.https.listen_address, "[::1]:5150");
|
||||||
assert_eq!(inner.network.application.http.enabled, true);
|
assert_eq!(inner.network.application.https.path, "app");
|
||||||
|
assert_eq!(inner.network.application.https.url, None);
|
||||||
|
assert_eq!(inner.network.application.http.enabled, false);
|
||||||
assert_eq!(inner.network.application.http.listen_address, "[::1]:5150");
|
assert_eq!(inner.network.application.http.listen_address, "[::1]:5150");
|
||||||
|
assert_eq!(inner.network.application.http.path, "app");
|
||||||
|
assert_eq!(inner.network.application.http.url, None);
|
||||||
assert_eq!(inner.network.protocol.udp.enabled, true);
|
assert_eq!(inner.network.protocol.udp.enabled, true);
|
||||||
assert_eq!(inner.network.protocol.udp.socket_pool_size, 0u32);
|
assert_eq!(inner.network.protocol.udp.socket_pool_size, 16u32);
|
||||||
assert_eq!(inner.network.protocol.udp.listen_address, "[::1]:5150");
|
assert_eq!(inner.network.protocol.udp.listen_address, "[::1]:5150");
|
||||||
assert_eq!(inner.network.protocol.udp.public_address, None);
|
assert_eq!(inner.network.protocol.udp.public_address, None);
|
||||||
assert_eq!(inner.network.protocol.tcp.connect, true);
|
assert_eq!(inner.network.protocol.tcp.connect, true);
|
||||||
@ -292,18 +302,18 @@ pub async fn test_config() {
|
|||||||
assert_eq!(inner.network.protocol.tcp.max_connections, 32u32);
|
assert_eq!(inner.network.protocol.tcp.max_connections, 32u32);
|
||||||
assert_eq!(inner.network.protocol.tcp.listen_address, "[::1]:5150");
|
assert_eq!(inner.network.protocol.tcp.listen_address, "[::1]:5150");
|
||||||
assert_eq!(inner.network.protocol.tcp.public_address, None);
|
assert_eq!(inner.network.protocol.tcp.public_address, None);
|
||||||
assert_eq!(inner.network.protocol.ws.connect, true);
|
assert_eq!(inner.network.protocol.ws.connect, false);
|
||||||
assert_eq!(inner.network.protocol.ws.listen, true);
|
assert_eq!(inner.network.protocol.ws.listen, false);
|
||||||
assert_eq!(inner.network.protocol.ws.max_connections, 16u32);
|
assert_eq!(inner.network.protocol.ws.max_connections, 16u32);
|
||||||
assert_eq!(inner.network.protocol.ws.listen_address, "[::1]:5150");
|
assert_eq!(inner.network.protocol.ws.listen_address, "[::1]:5150");
|
||||||
assert_eq!(inner.network.protocol.ws.path, "/ws");
|
assert_eq!(inner.network.protocol.ws.path, "ws");
|
||||||
assert_eq!(inner.network.protocol.ws.public_address, None);
|
assert_eq!(inner.network.protocol.ws.url, None);
|
||||||
assert_eq!(inner.network.protocol.wss.connect, true);
|
assert_eq!(inner.network.protocol.wss.connect, false);
|
||||||
assert_eq!(inner.network.protocol.wss.listen, true);
|
assert_eq!(inner.network.protocol.wss.listen, false);
|
||||||
assert_eq!(inner.network.protocol.wss.max_connections, 16u32);
|
assert_eq!(inner.network.protocol.wss.max_connections, 16u32);
|
||||||
assert_eq!(inner.network.protocol.wss.listen_address, "[::1]:5150");
|
assert_eq!(inner.network.protocol.wss.listen_address, "[::1]:5150");
|
||||||
assert_eq!(inner.network.protocol.wss.path, "/ws");
|
assert_eq!(inner.network.protocol.wss.path, "ws");
|
||||||
assert_eq!(inner.network.protocol.wss.public_address, None);
|
assert_eq!(inner.network.protocol.wss.url, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn test_all() {
|
pub async fn test_all() {
|
||||||
|
@ -385,7 +385,7 @@ impl DialInfo {
|
|||||||
let addr: IpAddr = di
|
let addr: IpAddr = di
|
||||||
.fqdn
|
.fqdn
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| format!("Failed to parse WS fqdn: {}", e))?;
|
.map_err(|e| format!("Failed to parse WSS fqdn: {}", e))?;
|
||||||
Ok(addr)
|
Ok(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -896,7 +896,7 @@ impl fmt::Debug for VeilidAPIInner {
|
|||||||
impl Drop for VeilidAPIInner {
|
impl Drop for VeilidAPIInner {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(core) = self.core.take() {
|
if let Some(core) = self.core.take() {
|
||||||
intf::spawn_local(core.internal_shutdown()).detach();
|
intf::spawn_local(core.shutdown()).detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -953,7 +953,7 @@ impl VeilidAPI {
|
|||||||
pub async fn shutdown(self) {
|
pub async fn shutdown(self) {
|
||||||
let core = { self.inner.lock().core.take() };
|
let core = { self.inner.lock().core.take() };
|
||||||
if let Some(core) = core {
|
if let Some(core) = core {
|
||||||
core.internal_shutdown().await;
|
core.shutdown().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,17 +14,20 @@ cfg_if! {
|
|||||||
pub struct VeilidConfigHTTPS {
|
pub struct VeilidConfigHTTPS {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub listen_address: String,
|
pub listen_address: String,
|
||||||
|
pub path: String,
|
||||||
|
pub url: Option<String>, // Fixed URL is not optional for TLS-based protocols and is dynamically validated
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct VeilidConfigHTTP {
|
pub struct VeilidConfigHTTP {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub listen_address: String,
|
pub listen_address: String,
|
||||||
|
pub path: String,
|
||||||
|
pub url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct VeilidConfigApplication {
|
pub struct VeilidConfigApplication {
|
||||||
pub path: String,
|
|
||||||
pub https: VeilidConfigHTTPS,
|
pub https: VeilidConfigHTTPS,
|
||||||
pub http: VeilidConfigHTTP,
|
pub http: VeilidConfigHTTP,
|
||||||
}
|
}
|
||||||
@ -53,7 +56,7 @@ pub struct VeilidConfigWS {
|
|||||||
pub max_connections: u32,
|
pub max_connections: u32,
|
||||||
pub listen_address: String,
|
pub listen_address: String,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub public_address: Option<String>,
|
pub url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
@ -63,7 +66,7 @@ pub struct VeilidConfigWSS {
|
|||||||
pub max_connections: u32,
|
pub max_connections: u32,
|
||||||
pub listen_address: String,
|
pub listen_address: String,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub public_address: Option<String>,
|
pub url: Option<String>, // Fixed URL is not optional for TLS-based protocols and is dynamically validated
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
@ -184,9 +187,11 @@ impl VeilidConfig {
|
|||||||
macro_rules! get_config {
|
macro_rules! get_config {
|
||||||
($key:expr) => {
|
($key:expr) => {
|
||||||
let keyname = &stringify!($key)[6..];
|
let keyname = &stringify!($key)[6..];
|
||||||
$key = *cb(keyname.to_owned())?
|
$key = *cb(keyname.to_owned())?.downcast().map_err(|_| {
|
||||||
.downcast()
|
let err = format!("incorrect type for key: {}", keyname);
|
||||||
.map_err(|_| format!("incorrect type for key: {}", keyname))?;
|
debug!("{}", err);
|
||||||
|
err
|
||||||
|
})?;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,11 +237,14 @@ impl VeilidConfig {
|
|||||||
get_config!(inner.network.tls.certificate_path);
|
get_config!(inner.network.tls.certificate_path);
|
||||||
get_config!(inner.network.tls.private_key_path);
|
get_config!(inner.network.tls.private_key_path);
|
||||||
get_config!(inner.network.tls.connection_initial_timeout);
|
get_config!(inner.network.tls.connection_initial_timeout);
|
||||||
get_config!(inner.network.application.path);
|
|
||||||
get_config!(inner.network.application.https.enabled);
|
get_config!(inner.network.application.https.enabled);
|
||||||
get_config!(inner.network.application.https.listen_address);
|
get_config!(inner.network.application.https.listen_address);
|
||||||
|
get_config!(inner.network.application.https.path);
|
||||||
|
get_config!(inner.network.application.https.url);
|
||||||
get_config!(inner.network.application.http.enabled);
|
get_config!(inner.network.application.http.enabled);
|
||||||
get_config!(inner.network.application.http.listen_address);
|
get_config!(inner.network.application.http.listen_address);
|
||||||
|
get_config!(inner.network.application.http.path);
|
||||||
|
get_config!(inner.network.application.http.url);
|
||||||
get_config!(inner.network.protocol.udp.enabled);
|
get_config!(inner.network.protocol.udp.enabled);
|
||||||
get_config!(inner.network.protocol.udp.socket_pool_size);
|
get_config!(inner.network.protocol.udp.socket_pool_size);
|
||||||
get_config!(inner.network.protocol.udp.listen_address);
|
get_config!(inner.network.protocol.udp.listen_address);
|
||||||
@ -251,13 +259,13 @@ impl VeilidConfig {
|
|||||||
get_config!(inner.network.protocol.ws.max_connections);
|
get_config!(inner.network.protocol.ws.max_connections);
|
||||||
get_config!(inner.network.protocol.ws.listen_address);
|
get_config!(inner.network.protocol.ws.listen_address);
|
||||||
get_config!(inner.network.protocol.ws.path);
|
get_config!(inner.network.protocol.ws.path);
|
||||||
get_config!(inner.network.protocol.ws.public_address);
|
get_config!(inner.network.protocol.ws.url);
|
||||||
get_config!(inner.network.protocol.wss.connect);
|
get_config!(inner.network.protocol.wss.connect);
|
||||||
get_config!(inner.network.protocol.wss.listen);
|
get_config!(inner.network.protocol.wss.listen);
|
||||||
get_config!(inner.network.protocol.wss.max_connections);
|
get_config!(inner.network.protocol.wss.max_connections);
|
||||||
get_config!(inner.network.protocol.wss.listen_address);
|
get_config!(inner.network.protocol.wss.listen_address);
|
||||||
get_config!(inner.network.protocol.wss.path);
|
get_config!(inner.network.protocol.wss.path);
|
||||||
get_config!(inner.network.protocol.wss.public_address);
|
get_config!(inner.network.protocol.wss.url);
|
||||||
get_config!(inner.network.leases.max_server_signal_leases);
|
get_config!(inner.network.leases.max_server_signal_leases);
|
||||||
get_config!(inner.network.leases.max_server_relay_leases);
|
get_config!(inner.network.leases.max_server_relay_leases);
|
||||||
get_config!(inner.network.leases.max_client_signal_leases);
|
get_config!(inner.network.leases.max_client_signal_leases);
|
||||||
@ -266,7 +274,12 @@ impl VeilidConfig {
|
|||||||
|
|
||||||
// Initialize node id as early as possible because it is used
|
// Initialize node id as early as possible because it is used
|
||||||
// for encryption purposes all over the program
|
// for encryption purposes all over the program
|
||||||
self.init_node_id().await
|
self.init_node_id().await?;
|
||||||
|
|
||||||
|
// Validate settings
|
||||||
|
self.validate().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn terminate(&self) {
|
pub async fn terminate(&self) {
|
||||||
@ -277,6 +290,85 @@ impl VeilidConfig {
|
|||||||
self.inner.read()
|
self.inner.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn validate(&self) -> Result<(), String> {
|
||||||
|
let inner = self.inner.read();
|
||||||
|
if inner.network.protocol.udp.enabled {
|
||||||
|
// Validate UDP settings
|
||||||
|
if inner.network.protocol.udp.socket_pool_size == 0 {
|
||||||
|
return Err("UDP socket pool size must be > 0 in config key 'network.protocol.udp.socket_pool_size'".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if inner.network.protocol.tcp.listen {
|
||||||
|
// Validate TCP settings
|
||||||
|
if inner.network.protocol.tcp.max_connections == 0 {
|
||||||
|
return Err("TCP max connections must be > 0 in config key 'network.protocol.tcp.max_connections'".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if inner.network.protocol.ws.listen {
|
||||||
|
// Validate WS settings
|
||||||
|
if inner.network.protocol.ws.max_connections == 0 {
|
||||||
|
return Err("WS max connections must be > 0 in config key 'network.protocol.ws.max_connections'".to_owned());
|
||||||
|
}
|
||||||
|
if inner.network.application.https.enabled
|
||||||
|
&& inner.network.application.https.path == inner.network.protocol.ws.path
|
||||||
|
{
|
||||||
|
return Err("WS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'".to_owned());
|
||||||
|
}
|
||||||
|
if inner.network.application.http.enabled
|
||||||
|
&& inner.network.application.http.path == inner.network.protocol.ws.path
|
||||||
|
{
|
||||||
|
return Err("WS path conflicts with HTTP application path in config key 'network.protocol.ws.path'".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if inner.network.protocol.wss.listen {
|
||||||
|
// Validate WSS settings
|
||||||
|
if inner.network.protocol.wss.max_connections == 0 {
|
||||||
|
return Err("WSS max connections must be > 0 in config key 'network.protocol.wss.max_connections'".to_owned());
|
||||||
|
}
|
||||||
|
if inner
|
||||||
|
.network
|
||||||
|
.protocol
|
||||||
|
.wss
|
||||||
|
.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|u| u.is_empty())
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
return Err(
|
||||||
|
"WSS URL must be specified in config key 'network.protocol.wss.url'".to_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if inner.network.application.https.enabled
|
||||||
|
&& inner.network.application.https.path == inner.network.protocol.wss.path
|
||||||
|
{
|
||||||
|
return Err("WSS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'".to_owned());
|
||||||
|
}
|
||||||
|
if inner.network.application.http.enabled
|
||||||
|
&& inner.network.application.http.path == inner.network.protocol.wss.path
|
||||||
|
{
|
||||||
|
return Err("WSS path conflicts with HTTP application path in config key 'network.protocol.ws.path'".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if inner.network.application.https.enabled {
|
||||||
|
// Validate HTTPS settings
|
||||||
|
if inner
|
||||||
|
.network
|
||||||
|
.application
|
||||||
|
.https
|
||||||
|
.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|u| u.is_empty())
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
return Err(
|
||||||
|
"HTTPS URL must be specified in config key 'network.application.https.url'"
|
||||||
|
.to_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// Get the node id from config if one is specified
|
// Get the node id from config if one is specified
|
||||||
async fn init_node_id(&self) -> Result<(), String> {
|
async fn init_node_id(&self) -> Result<(), String> {
|
||||||
let mut inner = self.inner.write();
|
let mut inner = self.inner.write();
|
||||||
|
@ -163,15 +163,13 @@ impl VeilidCore {
|
|||||||
match self.internal_startup(&mut *inner, setup).await {
|
match self.internal_startup(&mut *inner, setup).await {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.clone().internal_shutdown().await;
|
Self::internal_shutdown(&mut *inner).await;
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop the node gracefully because the veilid api was dropped
|
async fn internal_shutdown(inner: &mut VeilidCoreInner) {
|
||||||
pub(crate) async fn internal_shutdown(self) {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
trace!("VeilidCore::internal_shutdown starting");
|
trace!("VeilidCore::internal_shutdown starting");
|
||||||
|
|
||||||
// Detach the API object
|
// Detach the API object
|
||||||
@ -204,5 +202,11 @@ impl VeilidCore {
|
|||||||
trace!("VeilidCore::shutdown complete");
|
trace!("VeilidCore::shutdown complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stop the node gracefully because the veilid api was dropped
|
||||||
|
pub(crate) async fn shutdown(self) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
Self::internal_shutdown(&mut *inner);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,14 @@ mod ip_addr_port;
|
|||||||
mod ip_extra;
|
mod ip_extra;
|
||||||
mod single_future;
|
mod single_future;
|
||||||
mod single_shot_eventual;
|
mod single_shot_eventual;
|
||||||
|
mod split_url;
|
||||||
mod tick_task;
|
mod tick_task;
|
||||||
mod tools;
|
mod tools;
|
||||||
|
|
||||||
pub use cfg_if::*;
|
pub use cfg_if::*;
|
||||||
pub use log::*;
|
pub use log::*;
|
||||||
pub use parking_lot::*;
|
pub use parking_lot::*;
|
||||||
|
pub use split_url::*;
|
||||||
pub use static_assertions::*;
|
pub use static_assertions::*;
|
||||||
|
|
||||||
pub type PinBox<T> = Pin<Box<T>>;
|
pub type PinBox<T> = Pin<Box<T>>;
|
||||||
|
325
veilid-core/src/xx/split_url.rs
Normal file
325
veilid-core/src/xx/split_url.rs
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
// Loose subset interpretation of the URL standard
|
||||||
|
// Not using full Url crate here for no_std compatibility
|
||||||
|
//
|
||||||
|
// Caveats:
|
||||||
|
// No support for query string parsing
|
||||||
|
// No support for paths with ';' parameters
|
||||||
|
// URLs must convert to UTF8
|
||||||
|
// Only IP address and DNS hostname host fields are supported
|
||||||
|
|
||||||
|
use super::IpAddr;
|
||||||
|
use core::fmt;
|
||||||
|
use core::str::FromStr;
|
||||||
|
|
||||||
|
fn is_alphanum(c: u8) -> bool {
|
||||||
|
matches!(c,
|
||||||
|
b'A'..=b'Z'
|
||||||
|
| b'a'..=b'z'
|
||||||
|
| b'0'..=b'9'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn is_mark(c: u8) -> bool {
|
||||||
|
matches!(
|
||||||
|
c,
|
||||||
|
b'-' | b'_' | b'.' | b'!' | b'~' | b'*' | b'\'' | b'(' | b')'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn is_unreserved(c: u8) -> bool {
|
||||||
|
is_alphanum(c) || is_mark(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn must_encode_userinfo(c: u8) -> bool {
|
||||||
|
!(is_unreserved(c) || matches!(c, b'%' | b':' | b';' | b'&' | b'=' | b'+' | b'$' | b','))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn must_encode_path(c: u8) -> bool {
|
||||||
|
!(is_unreserved(c)
|
||||||
|
|| matches!(
|
||||||
|
c,
|
||||||
|
b'%' | b'/' | b':' | b'@' | b'&' | b'=' | b'+' | b'$' | b','
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid_host<H: AsRef<str>>(host: H) -> bool {
|
||||||
|
if host.as_ref().is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if IpAddr::from_str(host.as_ref()).is_err() {
|
||||||
|
for ch in host.as_ref().chars() {
|
||||||
|
if !matches!(ch,
|
||||||
|
'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '.' )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid_scheme<H: AsRef<str>>(host: H) -> bool {
|
||||||
|
let mut chars = host.as_ref().chars();
|
||||||
|
if let Some(ch) = chars.next() {
|
||||||
|
if !matches!(ch, 'A'..='Z' | 'a'..='z') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for ch in chars {
|
||||||
|
if !matches!(ch,
|
||||||
|
'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '+' | '.' )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hex_decode(h: u8) -> Result<u8, String> {
|
||||||
|
match h {
|
||||||
|
b'0'..=b'9' => Ok(h - b'0'),
|
||||||
|
b'A'..=b'F' => Ok(h - b'A' + 10),
|
||||||
|
b'a'..=b'f' => Ok(h - b'a' + 10),
|
||||||
|
_ => Err("Unexpected character in percent encoding".to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hex_encode(c: u8) -> (char, char) {
|
||||||
|
let c0 = c >> 4;
|
||||||
|
let c1 = c & 15;
|
||||||
|
(
|
||||||
|
if c0 < 10 {
|
||||||
|
char::from_u32((b'0' + c0) as u32).unwrap()
|
||||||
|
} else {
|
||||||
|
char::from_u32((b'A' + c0 - 10) as u32).unwrap()
|
||||||
|
},
|
||||||
|
if c1 < 10 {
|
||||||
|
char::from_u32((b'0' + c1) as u32).unwrap()
|
||||||
|
} else {
|
||||||
|
char::from_u32((b'A' + c1 - 10) as u32).unwrap()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn url_decode<S: AsRef<str>>(s: S) -> Result<String, String> {
|
||||||
|
let url = s.as_ref().to_owned();
|
||||||
|
if !url.is_ascii() {
|
||||||
|
return Err("URL is not in ASCII encoding".to_owned());
|
||||||
|
}
|
||||||
|
let url_bytes = url.as_bytes();
|
||||||
|
let mut dec_bytes: Vec<u8> = Vec::with_capacity(url_bytes.len());
|
||||||
|
let mut i = 0;
|
||||||
|
let end = url_bytes.len();
|
||||||
|
while i < end {
|
||||||
|
let mut b = url_bytes[i];
|
||||||
|
i += 1;
|
||||||
|
if b == b'%' {
|
||||||
|
if (i + 1) >= end {
|
||||||
|
return Err("Invalid URL encoding".to_owned());
|
||||||
|
}
|
||||||
|
b = hex_decode(url_bytes[i])? << 4 | hex_decode(url_bytes[i + 1])?;
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
dec_bytes.push(b);
|
||||||
|
}
|
||||||
|
String::from_utf8(dec_bytes).map_err(|e| format!("Decoded URL is not valid UTF-8: {}", e))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn url_encode<S: AsRef<str>>(s: S, must_encode: impl Fn(u8) -> bool) -> String {
|
||||||
|
let bytes = s.as_ref().as_bytes();
|
||||||
|
let mut out = String::new();
|
||||||
|
for b in bytes {
|
||||||
|
if must_encode(*b) {
|
||||||
|
let (c0, c1) = hex_encode(*b);
|
||||||
|
out.push('%');
|
||||||
|
out.push(c0);
|
||||||
|
out.push(c1);
|
||||||
|
} else {
|
||||||
|
out.push(char::from_u32(*b as u32).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_port<N>(port_str: N) -> Result<u16, String>
|
||||||
|
where
|
||||||
|
N: AsRef<str>,
|
||||||
|
{
|
||||||
|
port_str
|
||||||
|
.as_ref()
|
||||||
|
.parse::<u16>()
|
||||||
|
.map_err(|e| format!("Invalid port: {}", e))
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct SplitUrlPath {
|
||||||
|
pub path: String,
|
||||||
|
pub fragment: Option<String>,
|
||||||
|
pub query: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SplitUrlPath {
|
||||||
|
pub fn new<P, F, Q>(path: P, fragment: Option<F>, query: Option<Q>) -> Self
|
||||||
|
where
|
||||||
|
P: AsRef<str>,
|
||||||
|
F: AsRef<str>,
|
||||||
|
Q: AsRef<str>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
path: path.as_ref().to_owned(),
|
||||||
|
fragment: fragment.map(|f| f.as_ref().to_owned()),
|
||||||
|
query: query.map(|f| f.as_ref().to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for SplitUrlPath {
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(if let Some((p, q)) = s.split_once('?') {
|
||||||
|
if let Some((p, f)) = p.split_once('#') {
|
||||||
|
SplitUrlPath::new(url_decode(p)?, Some(url_decode(f)?), Some(q))
|
||||||
|
} else {
|
||||||
|
SplitUrlPath::new(url_decode(p)?, Option::<String>::None, Some(q))
|
||||||
|
}
|
||||||
|
} else if let Some((p, f)) = s.split_once('#') {
|
||||||
|
SplitUrlPath::new(url_decode(p)?, Some(url_decode(f)?), Option::<String>::None)
|
||||||
|
} else {
|
||||||
|
SplitUrlPath::new(
|
||||||
|
url_decode(s)?,
|
||||||
|
Option::<String>::None,
|
||||||
|
Option::<String>::None,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SplitUrlPath {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if let Some(fragment) = &self.fragment {
|
||||||
|
if let Some(query) = &self.query {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}#{}?{}",
|
||||||
|
url_encode(&self.path, must_encode_path),
|
||||||
|
url_encode(fragment, must_encode_path),
|
||||||
|
query
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}#{}", self.path, fragment)
|
||||||
|
}
|
||||||
|
} else if let Some(query) = &self.query {
|
||||||
|
write!(f, "{}?{}", url_encode(&self.path, must_encode_path), query)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", url_encode(&self.path, must_encode_path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct SplitUrl {
|
||||||
|
pub scheme: String,
|
||||||
|
pub userinfo: Option<String>,
|
||||||
|
pub host: String,
|
||||||
|
pub port: Option<u16>,
|
||||||
|
pub path: Option<SplitUrlPath>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SplitUrl {
|
||||||
|
pub fn new<S, H>(
|
||||||
|
scheme: S,
|
||||||
|
userinfo: Option<String>,
|
||||||
|
host: H,
|
||||||
|
port: Option<u16>,
|
||||||
|
path: Option<SplitUrlPath>,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
H: AsRef<str>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
scheme: scheme.as_ref().to_owned(),
|
||||||
|
userinfo,
|
||||||
|
host: host.as_ref().to_owned(),
|
||||||
|
port,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for SplitUrl {
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if let Some((scheme, mut rest)) = s.split_once("://") {
|
||||||
|
if !is_valid_scheme(scheme) {
|
||||||
|
return Err("Invalid scheme specified".to_owned());
|
||||||
|
}
|
||||||
|
let userinfo = {
|
||||||
|
if let Some((userinfo_str, after)) = rest.split_once("@") {
|
||||||
|
rest = after;
|
||||||
|
Some(url_decode(userinfo_str)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some((host, rest)) = rest.rsplit_once(':') {
|
||||||
|
if !is_valid_host(host) {
|
||||||
|
return Err("Invalid host specified".to_owned());
|
||||||
|
}
|
||||||
|
if let Some((portstr, path)) = rest.split_once('/') {
|
||||||
|
let port = convert_port(portstr)?;
|
||||||
|
let path = SplitUrlPath::from_str(path)?;
|
||||||
|
Ok(SplitUrl::new(
|
||||||
|
scheme,
|
||||||
|
userinfo,
|
||||||
|
host,
|
||||||
|
Some(port),
|
||||||
|
Some(path),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
let port = convert_port(rest)?;
|
||||||
|
Ok(SplitUrl::new(scheme, userinfo, host, Some(port), None))
|
||||||
|
}
|
||||||
|
} else if let Some((host, path)) = rest.split_once('/') {
|
||||||
|
if !is_valid_host(host) {
|
||||||
|
return Err("Invalid host specified".to_owned());
|
||||||
|
}
|
||||||
|
let path = SplitUrlPath::from_str(path)?;
|
||||||
|
Ok(SplitUrl::new(scheme, userinfo, host, None, Some(path)))
|
||||||
|
} else {
|
||||||
|
if !is_valid_host(rest) {
|
||||||
|
return Err("Invalid host specified".to_owned());
|
||||||
|
}
|
||||||
|
Ok(SplitUrl::new(scheme, userinfo, rest, None, None))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("No scheme specified".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SplitUrl {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let hostname = {
|
||||||
|
if let Some(userinfo) = &self.userinfo {
|
||||||
|
let userinfo = url_encode(userinfo, must_encode_userinfo);
|
||||||
|
if let Some(port) = self.port {
|
||||||
|
format!("{}@{}:{}", userinfo, self.host, port)
|
||||||
|
} else {
|
||||||
|
format!("{}@{}", userinfo, self.host)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.host.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(path) = &self.path {
|
||||||
|
write!(f, "{}://{}/{}", self.scheme, hostname, path)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}://{}", self.scheme, hostname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -70,13 +70,16 @@ core:
|
|||||||
private_key_path: "/etc/veilid/private/server.key"
|
private_key_path: "/etc/veilid/private/server.key"
|
||||||
connection_initial_timeout: 2000000
|
connection_initial_timeout: 2000000
|
||||||
application:
|
application:
|
||||||
path: "app"
|
|
||||||
https:
|
https:
|
||||||
enabled: true
|
enabled: false
|
||||||
listen_address: "[::]:5150"
|
listen_address: "[::]:5150"
|
||||||
|
path: "app"
|
||||||
|
# url: "https://localhost:5150"
|
||||||
http:
|
http:
|
||||||
enabled: true
|
enabled: false
|
||||||
listen_address: "[::]:5150"
|
listen_address: "[::]:5150"
|
||||||
|
path: "app"
|
||||||
|
# url: "http://localhost:5150"
|
||||||
protocol:
|
protocol:
|
||||||
udp:
|
udp:
|
||||||
enabled: true
|
enabled: true
|
||||||
@ -94,15 +97,15 @@ core:
|
|||||||
listen: true
|
listen: true
|
||||||
max_connections: 16
|
max_connections: 16
|
||||||
listen_address: "[::]:5150"
|
listen_address: "[::]:5150"
|
||||||
path: "/ws"
|
path: "ws"
|
||||||
# "public_address": ""
|
# url: "ws://localhost:5150/ws"
|
||||||
wss:
|
wss:
|
||||||
connect: true
|
connect: true
|
||||||
listen: true
|
listen: false
|
||||||
max_connections: 16
|
max_connections: 16
|
||||||
listen_address: "[::]:5150"
|
listen_address: "[::]:5150"
|
||||||
path: "/ws"
|
path: "ws"
|
||||||
# "public_address": ""
|
# url: ""
|
||||||
leases:
|
leases:
|
||||||
max_server_signal_leases: 256
|
max_server_signal_leases: 256
|
||||||
max_server_relay_leases: 8
|
max_server_relay_leases: 8
|
||||||
@ -173,30 +176,47 @@ pub fn convert_loglevel(log_level: LogLevel) -> LevelFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ParsedURL {
|
pub struct ParsedUrl {
|
||||||
pub urlstring: String,
|
pub urlstring: String,
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for ParsedURL {
|
impl ParsedUrl {
|
||||||
type Err = url::ParseError;
|
pub fn offset_port(&mut self, offset: u16) -> Result<(), ()> {
|
||||||
fn from_str(s: &str) -> Result<ParsedURL, url::ParseError> {
|
// Bump port on url
|
||||||
let url = Url::parse(s)?;
|
self.url.set_port(Some(self.url.port().unwrap() + offset))?;
|
||||||
|
self.urlstring = self.url.to_string();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ParsedUrl {
|
||||||
|
type Err = url::ParseError;
|
||||||
|
fn from_str(s: &str) -> Result<ParsedUrl, url::ParseError> {
|
||||||
|
let mut url = Url::parse(s)?;
|
||||||
|
if url.scheme().to_lowercase() == "http" && url.port().is_none() {
|
||||||
|
url.set_port(Some(80))
|
||||||
|
.map_err(|_| url::ParseError::InvalidPort)?
|
||||||
|
}
|
||||||
|
if url.scheme().to_lowercase() == "https" && url.port().is_none() {
|
||||||
|
url.set_port(Some(443))
|
||||||
|
.map_err(|_| url::ParseError::InvalidPort)?;
|
||||||
|
}
|
||||||
|
let parsed_urlstring = url.to_string();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
urlstring: s.to_string(),
|
urlstring: parsed_urlstring,
|
||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for ParsedURL {
|
impl<'de> serde::Deserialize<'de> for ParsedUrl {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let s = String::deserialize(deserializer)?;
|
let s = String::deserialize(deserializer)?;
|
||||||
ParsedURL::from_str(s.as_str()).map_err(serde::de::Error::custom)
|
ParsedUrl::from_str(s.as_str()).map_err(serde::de::Error::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,17 +299,20 @@ pub struct Logging {
|
|||||||
pub struct Https {
|
pub struct Https {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub listen_address: NamedSocketAddrs,
|
pub listen_address: NamedSocketAddrs,
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub url: Option<ParsedUrl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Http {
|
pub struct Http {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub listen_address: NamedSocketAddrs,
|
pub listen_address: NamedSocketAddrs,
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub url: Option<ParsedUrl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Application {
|
pub struct Application {
|
||||||
pub path: PathBuf,
|
|
||||||
pub https: Https,
|
pub https: Https,
|
||||||
pub http: Http,
|
pub http: Http,
|
||||||
}
|
}
|
||||||
@ -317,8 +340,8 @@ pub struct Ws {
|
|||||||
pub listen: bool,
|
pub listen: bool,
|
||||||
pub max_connections: u32,
|
pub max_connections: u32,
|
||||||
pub listen_address: NamedSocketAddrs,
|
pub listen_address: NamedSocketAddrs,
|
||||||
pub path: String,
|
pub path: PathBuf,
|
||||||
pub public_address: Option<NamedSocketAddrs>,
|
pub url: Option<ParsedUrl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -327,8 +350,8 @@ pub struct Wss {
|
|||||||
pub listen: bool,
|
pub listen: bool,
|
||||||
pub max_connections: u32,
|
pub max_connections: u32,
|
||||||
pub listen_address: NamedSocketAddrs,
|
pub listen_address: NamedSocketAddrs,
|
||||||
pub path: String,
|
pub path: PathBuf,
|
||||||
pub public_address: Option<NamedSocketAddrs>,
|
pub url: Option<ParsedUrl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -387,7 +410,7 @@ pub struct Network {
|
|||||||
pub connection_initial_timeout: u64,
|
pub connection_initial_timeout: u64,
|
||||||
pub node_id: veilid_core::DHTKey,
|
pub node_id: veilid_core::DHTKey,
|
||||||
pub node_id_secret: veilid_core::DHTKeySecret,
|
pub node_id_secret: veilid_core::DHTKeySecret,
|
||||||
pub bootstrap: Vec<ParsedURL>,
|
pub bootstrap: Vec<ParsedUrl>,
|
||||||
pub rpc: Rpc,
|
pub rpc: Rpc,
|
||||||
pub dht: Dht,
|
pub dht: Dht,
|
||||||
pub upnp: bool,
|
pub upnp: bool,
|
||||||
@ -450,8 +473,12 @@ impl Settings {
|
|||||||
load_config(&mut cfg, config_file_path)?;
|
load_config(&mut cfg, config_file_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate config
|
||||||
|
let inner: SettingsInner = cfg.try_into()?;
|
||||||
|
|
||||||
|
//
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: Arc::new(RwLock::new(cfg.try_into()?)),
|
inner: Arc::new(RwLock::new(inner)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn read(&self) -> RwLockReadGuard<SettingsInner> {
|
pub fn read(&self) -> RwLockReadGuard<SettingsInner> {
|
||||||
@ -493,6 +520,9 @@ impl Settings {
|
|||||||
.ws
|
.ws
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
|
if let Some(url) = &mut (*settingsrw).core.network.protocol.ws.url {
|
||||||
|
url.offset_port(idx)?;
|
||||||
|
}
|
||||||
(*settingsrw)
|
(*settingsrw)
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
@ -500,6 +530,9 @@ impl Settings {
|
|||||||
.wss
|
.wss
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
|
if let Some(url) = &mut (*settingsrw).core.network.protocol.wss.url {
|
||||||
|
url.offset_port(idx)?;
|
||||||
|
}
|
||||||
// bump application ports
|
// bump application ports
|
||||||
(*settingsrw)
|
(*settingsrw)
|
||||||
.core
|
.core
|
||||||
@ -508,6 +541,9 @@ impl Settings {
|
|||||||
.http
|
.http
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
|
if let Some(url) = &mut (*settingsrw).core.network.application.http.url {
|
||||||
|
url.offset_port(idx)?;
|
||||||
|
}
|
||||||
(*settingsrw)
|
(*settingsrw)
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
@ -515,7 +551,9 @@ impl Settings {
|
|||||||
.https
|
.https
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
|
if let Some(url) = &mut (*settingsrw).core.network.application.https.url {
|
||||||
|
url.offset_port(idx)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,15 +703,6 @@ impl Settings {
|
|||||||
"network.tls.connection_initial_timeout" => {
|
"network.tls.connection_initial_timeout" => {
|
||||||
Ok(Box::new(inner.core.network.tls.connection_initial_timeout))
|
Ok(Box::new(inner.core.network.tls.connection_initial_timeout))
|
||||||
}
|
}
|
||||||
"network.application.path" => Ok(Box::new(
|
|
||||||
inner
|
|
||||||
.core
|
|
||||||
.network
|
|
||||||
.application
|
|
||||||
.path
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string(),
|
|
||||||
)),
|
|
||||||
"network.application.https.enabled" => {
|
"network.application.https.enabled" => {
|
||||||
Ok(Box::new(inner.core.network.application.https.enabled))
|
Ok(Box::new(inner.core.network.application.https.enabled))
|
||||||
}
|
}
|
||||||
@ -687,6 +716,26 @@ impl Settings {
|
|||||||
.name
|
.name
|
||||||
.clone(),
|
.clone(),
|
||||||
)),
|
)),
|
||||||
|
"network.application.https.path" => Ok(Box::new(
|
||||||
|
inner
|
||||||
|
.core
|
||||||
|
.network
|
||||||
|
.application
|
||||||
|
.https
|
||||||
|
.path
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
)),
|
||||||
|
"network.application.https.url" => Ok(Box::new(
|
||||||
|
inner
|
||||||
|
.core
|
||||||
|
.network
|
||||||
|
.application
|
||||||
|
.https
|
||||||
|
.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|a| a.urlstring.clone()),
|
||||||
|
)),
|
||||||
"network.application.http.enabled" => {
|
"network.application.http.enabled" => {
|
||||||
Ok(Box::new(inner.core.network.application.http.enabled))
|
Ok(Box::new(inner.core.network.application.http.enabled))
|
||||||
}
|
}
|
||||||
@ -700,6 +749,26 @@ impl Settings {
|
|||||||
.name
|
.name
|
||||||
.clone(),
|
.clone(),
|
||||||
)),
|
)),
|
||||||
|
"network.application.http.path" => Ok(Box::new(
|
||||||
|
inner
|
||||||
|
.core
|
||||||
|
.network
|
||||||
|
.application
|
||||||
|
.http
|
||||||
|
.path
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
)),
|
||||||
|
"network.application.http.url" => Ok(Box::new(
|
||||||
|
inner
|
||||||
|
.core
|
||||||
|
.network
|
||||||
|
.application
|
||||||
|
.http
|
||||||
|
.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|a| a.urlstring.clone()),
|
||||||
|
)),
|
||||||
"network.protocol.udp.enabled" => {
|
"network.protocol.udp.enabled" => {
|
||||||
Ok(Box::new(inner.core.network.protocol.udp.enabled))
|
Ok(Box::new(inner.core.network.protocol.udp.enabled))
|
||||||
}
|
}
|
||||||
@ -751,18 +820,25 @@ impl Settings {
|
|||||||
"network.protocol.ws.listen_address" => Ok(Box::new(
|
"network.protocol.ws.listen_address" => Ok(Box::new(
|
||||||
inner.core.network.protocol.ws.listen_address.name.clone(),
|
inner.core.network.protocol.ws.listen_address.name.clone(),
|
||||||
)),
|
)),
|
||||||
"network.protocol.ws.path" => {
|
"network.protocol.ws.path" => Ok(Box::new(
|
||||||
Ok(Box::new(inner.core.network.protocol.ws.path.clone()))
|
|
||||||
}
|
|
||||||
"network.protocol.ws.public_address" => Ok(Box::new(
|
|
||||||
inner
|
inner
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.protocol
|
.protocol
|
||||||
.ws
|
.ws
|
||||||
.public_address
|
.path
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
)),
|
||||||
|
"network.protocol.ws.url" => Ok(Box::new(
|
||||||
|
inner
|
||||||
|
.core
|
||||||
|
.network
|
||||||
|
.protocol
|
||||||
|
.ws
|
||||||
|
.url
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|a| a.name.clone()),
|
.map(|a| a.urlstring.clone()),
|
||||||
)),
|
)),
|
||||||
"network.protocol.wss.connect" => {
|
"network.protocol.wss.connect" => {
|
||||||
Ok(Box::new(inner.core.network.protocol.wss.connect))
|
Ok(Box::new(inner.core.network.protocol.wss.connect))
|
||||||
@ -776,19 +852,19 @@ impl Settings {
|
|||||||
"network.protocol.wss.listen_address" => Ok(Box::new(
|
"network.protocol.wss.listen_address" => Ok(Box::new(
|
||||||
inner.core.network.protocol.wss.listen_address.name.clone(),
|
inner.core.network.protocol.wss.listen_address.name.clone(),
|
||||||
)),
|
)),
|
||||||
"network.protocol.wss.path" => {
|
"network.protocol.wss.path" => Ok(Box::new(
|
||||||
Ok(Box::new(inner.core.network.protocol.wss.path.clone()))
|
|
||||||
}
|
|
||||||
"network.protocol.wss.public_address" => Ok(Box::new(
|
|
||||||
inner
|
inner
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.protocol
|
.protocol
|
||||||
.wss
|
.wss
|
||||||
.public_address
|
.path
|
||||||
.as_ref()
|
.to_string_lossy()
|
||||||
.map(|a| a.name.clone()),
|
.to_string(),
|
||||||
)),
|
)),
|
||||||
|
"network.protocol.wss.url" => {
|
||||||
|
Ok(Box::new(inner.core.network.protocol.wss.url.clone()))
|
||||||
|
}
|
||||||
"network.leases.max_server_signal_leases" => {
|
"network.leases.max_server_signal_leases" => {
|
||||||
Ok(Box::new(inner.core.network.leases.max_server_signal_leases))
|
Ok(Box::new(inner.core.network.leases.max_server_signal_leases))
|
||||||
}
|
}
|
||||||
@ -899,11 +975,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(s.core.network.tls.connection_initial_timeout, 2_000_000u64);
|
assert_eq!(s.core.network.tls.connection_initial_timeout, 2_000_000u64);
|
||||||
//
|
//
|
||||||
assert_eq!(
|
assert_eq!(s.core.network.application.https.enabled, false);
|
||||||
s.core.network.application.path,
|
|
||||||
std::path::PathBuf::from("app")
|
|
||||||
);
|
|
||||||
assert_eq!(s.core.network.application.https.enabled, true);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.network.application.https.listen_address.name,
|
s.core.network.application.https.listen_address.name,
|
||||||
"[::]:5150"
|
"[::]:5150"
|
||||||
@ -915,7 +987,12 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Vec<SocketAddr>>()
|
.collect::<Vec<SocketAddr>>()
|
||||||
);
|
);
|
||||||
assert_eq!(s.core.network.application.http.enabled, true);
|
assert_eq!(
|
||||||
|
s.core.network.application.https.path,
|
||||||
|
std::path::PathBuf::from("app")
|
||||||
|
);
|
||||||
|
assert_eq!(s.core.network.application.https.url, None);
|
||||||
|
assert_eq!(s.core.network.application.http.enabled, false);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.network.application.http.listen_address.name,
|
s.core.network.application.http.listen_address.name,
|
||||||
"[::]:5150"
|
"[::]:5150"
|
||||||
@ -927,6 +1004,11 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Vec<SocketAddr>>()
|
.collect::<Vec<SocketAddr>>()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
s.core.network.application.http.path,
|
||||||
|
std::path::PathBuf::from("app")
|
||||||
|
);
|
||||||
|
assert_eq!(s.core.network.application.http.url, None);
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.protocol.udp.enabled, true);
|
assert_eq!(s.core.network.protocol.udp.enabled, true);
|
||||||
assert_eq!(s.core.network.protocol.udp.socket_pool_size, 0);
|
assert_eq!(s.core.network.protocol.udp.socket_pool_size, 0);
|
||||||
@ -966,11 +1048,14 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Vec<SocketAddr>>()
|
.collect::<Vec<SocketAddr>>()
|
||||||
);
|
);
|
||||||
assert_eq!(s.core.network.protocol.ws.path, "/ws");
|
assert_eq!(
|
||||||
assert_eq!(s.core.network.protocol.ws.public_address, None);
|
s.core.network.protocol.ws.path,
|
||||||
|
std::path::PathBuf::from("ws")
|
||||||
|
);
|
||||||
|
assert_eq!(s.core.network.protocol.ws.url, None);
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.protocol.wss.connect, true);
|
assert_eq!(s.core.network.protocol.wss.connect, true);
|
||||||
assert_eq!(s.core.network.protocol.wss.listen, true);
|
assert_eq!(s.core.network.protocol.wss.listen, false);
|
||||||
assert_eq!(s.core.network.protocol.wss.max_connections, 16);
|
assert_eq!(s.core.network.protocol.wss.max_connections, 16);
|
||||||
assert_eq!(s.core.network.protocol.wss.listen_address.name, "[::]:5150");
|
assert_eq!(s.core.network.protocol.wss.listen_address.name, "[::]:5150");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -980,9 +1065,12 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Vec<SocketAddr>>()
|
.collect::<Vec<SocketAddr>>()
|
||||||
);
|
);
|
||||||
assert_eq!(s.core.network.protocol.wss.path, "/ws");
|
assert_eq!(
|
||||||
assert_eq!(s.core.network.protocol.wss.public_address, None);
|
s.core.network.protocol.wss.path,
|
||||||
|
std::path::PathBuf::from("ws")
|
||||||
|
);
|
||||||
|
assert_eq!(s.core.network.protocol.wss.url, None);
|
||||||
|
//
|
||||||
assert_eq!(s.core.network.leases.max_server_signal_leases, 256);
|
assert_eq!(s.core.network.leases.max_server_signal_leases, 256);
|
||||||
assert_eq!(s.core.network.leases.max_server_relay_leases, 8);
|
assert_eq!(s.core.network.leases.max_server_relay_leases, 8);
|
||||||
assert_eq!(s.core.network.leases.max_client_signal_leases, 2);
|
assert_eq!(s.core.network.leases.max_client_signal_leases, 2);
|
||||||
|
@ -162,13 +162,12 @@ pub async fn main() -> Result<(), String> {
|
|||||||
let bootstrap = match matches.value_of("bootstrap") {
|
let bootstrap = match matches.value_of("bootstrap") {
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
println!("Overriding bootstrap with: ");
|
println!("Overriding bootstrap with: ");
|
||||||
let mut out: Vec<settings::ParsedURL> = Vec::new();
|
let mut out: Vec<settings::ParsedUrl> = Vec::new();
|
||||||
for x in x.split(',') {
|
for x in x.split(',') {
|
||||||
println!(" {}", x);
|
println!(" {}", x);
|
||||||
out.push(
|
out.push(settings::ParsedUrl::from_str(x).map_err(|e| {
|
||||||
settings::ParsedURL::from_str(x)
|
format!("unable to parse url in bootstrap list: {} for {}", e, x)
|
||||||
.map_err(|e| format!("unable to parse url in bootstrap list: {}", e))?,
|
})?);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user