refactor(rpc): Centralize RPC service and unify API (#1427)

This change introduces a major refactoring of the RPC service layer to improve modularity, unify the API, and simplify the overall architecture.

Key changes:
- Replaced per-network-instance RPC services with a single global RPC server, reducing resource usage and simplifying management.
- All clients (CLI, Web UI, etc.) now interact with EasyTier core through a unified RPC entrypoint, enabling consistent authentication and control.
- RPC implementation logic has been moved to `easytier/src/rpc_service/` and organized by functionality (e.g., `instance_manage.rs`, `peer_manage.rs`, `config.rs`) for better maintainability.
- Standardized Protobuf API definitions under `easytier/src/proto/` with an `api_` prefix (e.g., `cli.proto` → `api_instance.proto`) to provide a consistent interface.
- CLI commands now require explicit `--instance-id` or `--instance-name` when multiple network instances are running; the parameter is optional when only one instance exists.

BREAKING CHANGE:  
RPC portal configuration (`rpc_portal` and `rpc_portal_whitelist`) has been removed from per-instance configs and the Web UI. The RPC listen address must now be specified globally via the `--rpc-portal` command-line flag or the `ET_RPC_PORTAL` environment variable, as there is only one RPC service for the entire application.
This commit is contained in:
Mg Pig
2025-10-02 20:30:39 +08:00
committed by GitHub
parent d2efbbef04
commit 841d525913
65 changed files with 1953 additions and 1153 deletions

View File

@@ -144,11 +144,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let proto_files = [
"src/proto/error.proto",
"src/proto/tests.proto",
"src/proto/cli.proto",
"src/proto/api_instance.proto",
"src/proto/api_logger.proto",
"src/proto/api_config.proto",
"src/proto/api_manage.proto",
"src/proto/web.proto",
"src/proto/magic_dns.proto",
"src/proto/acl.proto",
"src/proto/config.proto",
];
for proto_file in proto_files.iter().chain(proto_files_reflect.iter()) {
@@ -161,7 +163,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.type_attribute(".acl", "#[derive(serde::Serialize, serde::Deserialize)]")
.type_attribute(".common", "#[derive(serde::Serialize, serde::Deserialize)]")
.type_attribute(".error", "#[derive(serde::Serialize, serde::Deserialize)]")
.type_attribute(".cli", "#[derive(serde::Serialize, serde::Deserialize)]")
.type_attribute(".api", "#[derive(serde::Serialize, serde::Deserialize)]")
.type_attribute(".web", "#[derive(serde::Serialize, serde::Deserialize)]")
.type_attribute(".config", "#[derive(serde::Serialize, serde::Deserialize)]")
.type_attribute(
@@ -180,7 +182,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
"#[derive(Hash, Eq, serde::Serialize, serde::Deserialize)]",
)
.type_attribute("common.RpcDescriptor", "#[derive(Hash, Eq)]")
.field_attribute(".web.NetworkConfig", "#[serde(default)]")
.field_attribute(".api.manage.NetworkConfig", "#[serde(default)]")
.service_generator(Box::new(rpc_build::ServiceGenerator::new()))
.btree_map(["."])
.skip_debug([".common.Ipv4Addr", ".common.Ipv6Addr", ".common.UUID"]);

View File

@@ -6,7 +6,6 @@ use std::{
};
use anyhow::Context;
use cidr::IpCidr;
use serde::{Deserialize, Serialize};
use crate::{
@@ -169,12 +168,6 @@ pub trait ConfigLoader: Send + Sync {
fn get_mapped_listeners(&self) -> Vec<url::Url>;
fn set_mapped_listeners(&self, listeners: Option<Vec<url::Url>>);
fn get_rpc_portal(&self) -> Option<SocketAddr>;
fn set_rpc_portal(&self, addr: SocketAddr);
fn get_rpc_portal_whitelist(&self) -> Option<Vec<IpCidr>>;
fn set_rpc_portal_whitelist(&self, whitelist: Option<Vec<IpCidr>>);
fn get_vpn_portal_config(&self) -> Option<VpnPortalConfig>;
fn set_vpn_portal_config(&self, config: VpnPortalConfig);
@@ -398,9 +391,6 @@ struct Config {
peer: Option<Vec<PeerConfig>>,
proxy_network: Option<Vec<ProxyNetworkConfig>>,
rpc_portal: Option<SocketAddr>,
rpc_portal_whitelist: Option<Vec<IpCidr>>,
vpn_portal_config: Option<VpnPortalConfig>,
routes: Option<Vec<cidr::Ipv4Cidr>>,
@@ -692,22 +682,6 @@ impl ConfigLoader for TomlConfigLoader {
self.config.lock().unwrap().mapped_listeners = listeners;
}
fn get_rpc_portal(&self) -> Option<SocketAddr> {
self.config.lock().unwrap().rpc_portal
}
fn set_rpc_portal(&self, addr: SocketAddr) {
self.config.lock().unwrap().rpc_portal = Some(addr);
}
fn get_rpc_portal_whitelist(&self) -> Option<Vec<IpCidr>> {
self.config.lock().unwrap().rpc_portal_whitelist.clone()
}
fn set_rpc_portal_whitelist(&self, whitelist: Option<Vec<IpCidr>>) {
self.config.lock().unwrap().rpc_portal_whitelist = whitelist;
}
fn get_vpn_portal_config(&self) -> Option<VpnPortalConfig> {
self.config.lock().unwrap().vpn_portal_config.clone()
}

View File

@@ -10,9 +10,9 @@ use crate::common::stats_manager::StatsManager;
use crate::common::token_bucket::TokenBucketManager;
use crate::peers::acl_filter::AclFilter;
use crate::proto::acl::GroupIdentity;
use crate::proto::cli::PeerConnInfo;
use crate::proto::api::config::InstanceConfigPatch;
use crate::proto::api::instance::PeerConnInfo;
use crate::proto::common::{PeerFeatureFlag, PortForwardConfigPb};
use crate::proto::config::InstanceConfigPatch;
use crate::proto::peer_rpc::PeerGroupInfo;
use crossbeam::atomic::AtomicCell;

View File

@@ -664,7 +664,7 @@ impl Default for StatsManager {
mod tests {
use super::*;
use crate::common::stats_manager::{LabelSet, LabelType, MetricName, StatsManager};
use crate::proto::cli::{
use crate::proto::api::instance::{
GetPrometheusStatsRequest, GetPrometheusStatsResponse, GetStatsRequest, GetStatsResponse,
};
use std::collections::BTreeMap;
@@ -818,16 +818,19 @@ mod tests {
#[tokio::test]
async fn test_stats_rpc_data_structures() {
// Test GetStatsRequest
let request = GetStatsRequest {};
assert_eq!(request, GetStatsRequest {});
let request = GetStatsRequest { instance: None };
assert_eq!(request, GetStatsRequest { instance: None });
// Test GetStatsResponse
let response = GetStatsResponse { metrics: vec![] };
assert!(response.metrics.is_empty());
// Test GetPrometheusStatsRequest
let prometheus_request = GetPrometheusStatsRequest {};
assert_eq!(prometheus_request, GetPrometheusStatsRequest {});
let prometheus_request = GetPrometheusStatsRequest { instance: None };
assert_eq!(
prometheus_request,
GetPrometheusStatsRequest { instance: None }
);
// Test GetPrometheusStatsResponse
let prometheus_response = GetPrometheusStatsResponse {
@@ -867,7 +870,7 @@ mod tests {
}
// This simulates what the RPC service would do
let _metric_snapshot = crate::proto::cli::MetricSnapshot {
let _metric_snapshot = crate::proto::api::instance::MetricSnapshot {
name: metric.name.to_string(),
value: metric.value,
labels,

View File

@@ -35,7 +35,7 @@ use crate::{
use_global_var,
};
use crate::proto::cli::PeerConnInfo;
use crate::proto::api::instance::PeerConnInfo;
use anyhow::Context;
use rand::Rng;
use tokio::{net::UdpSocket, task::JoinSet, time::timeout};

View File

@@ -18,12 +18,14 @@ use crate::{
common::{dns::socket_addrs, join_joinset_background, PeerId},
peers::peer_conn::PeerConnId,
proto::{
cli::{
ConnectorManageAction, ListConnectorResponse, ManageConnectorResponse, PeerConnInfo,
api::instance::{
Connector, ConnectorManageRpc, ConnectorStatus, ListConnectorRequest,
ListConnectorResponse, PeerConnInfo,
},
rpc_types::{self, controller::BaseController},
},
tunnel::{IpVersion, TunnelConnector},
utils::weak_upgrade,
};
use crate::{
@@ -33,10 +35,6 @@ use crate::{
netns::NetNS,
},
peers::peer_manager::PeerManager,
proto::cli::{
Connector, ConnectorManageRpc, ConnectorStatus, ListConnectorRequest,
ManageConnectorRequest,
},
use_global_var,
};
@@ -126,6 +124,14 @@ impl ManualConnectorManager {
Ok(())
}
pub async fn clear_connectors(&self) {
self.list_connectors().await.iter().for_each(|x| {
if let Some(url) = &x.url {
self.data.removed_conn_urls.insert(url.to_string());
}
});
}
pub async fn list_connectors(&self) -> Vec<Connector> {
let conn_urls: BTreeSet<String> = self
.data
@@ -421,7 +427,7 @@ impl ManualConnectorManager {
}
#[derive(Clone)]
pub struct ConnectorManagerRpcService(pub Arc<ManualConnectorManager>);
pub struct ConnectorManagerRpcService(pub Weak<ManualConnectorManager>);
#[async_trait::async_trait]
impl ConnectorManageRpc for ConnectorManagerRpcService {
@@ -433,31 +439,10 @@ impl ConnectorManageRpc for ConnectorManagerRpcService {
_request: ListConnectorRequest,
) -> Result<ListConnectorResponse, rpc_types::error::Error> {
let mut ret = ListConnectorResponse::default();
let connectors = self.0.list_connectors().await;
let connectors = weak_upgrade(&self.0)?.list_connectors().await;
ret.connectors = connectors;
Ok(ret)
}
async fn manage_connector(
&self,
_: BaseController,
req: ManageConnectorRequest,
) -> Result<ManageConnectorResponse, rpc_types::error::Error> {
let url: url::Url = req.url.ok_or(anyhow::anyhow!("url is empty"))?.into();
if req.action == ConnectorManageAction::Remove as i32 {
self.0
.remove_connector(url.clone())
.await
.with_context(|| format!("remove connector failed: {:?}", url))?;
return Ok(ManageConnectorResponse::default());
} else {
self.0
.add_connector_by_url(url.as_str())
.await
.with_context(|| format!("add connector failed: {:?}", url))?;
}
Ok(ManageConnectorResponse::default())
}
}
#[cfg(test)]

View File

@@ -26,25 +26,32 @@ use easytier::{
},
peers,
proto::{
cli::{
list_peer_route_pair, AclManageRpc, AclManageRpcClientFactory, ConnectorManageRpc,
ConnectorManageRpcClientFactory, DumpRouteRequest, GetAclStatsRequest,
GetLoggerConfigRequest, GetPrometheusStatsRequest, GetStatsRequest,
GetVpnPortalInfoRequest, GetWhitelistRequest, ListConnectorRequest,
ListForeignNetworkRequest, ListGlobalForeignNetworkRequest, ListMappedListenerRequest,
ListPeerRequest, ListPeerResponse, ListPortForwardRequest, ListRouteRequest,
ListRouteResponse, LogLevel, LoggerRpc, LoggerRpcClientFactory,
MappedListenerManageRpc, MappedListenerManageRpcClientFactory, NodeInfo, PeerManageRpc,
PeerManageRpcClientFactory, PortForwardManageRpc, PortForwardManageRpcClientFactory,
SetLoggerConfigRequest, ShowNodeInfoRequest, StatsRpc, StatsRpcClientFactory,
TcpProxyEntryState, TcpProxyEntryTransportType, TcpProxyRpc, TcpProxyRpcClientFactory,
VpnPortalRpc, VpnPortalRpcClientFactory,
api::{
config::{
AclPatch, ConfigPatchAction, ConfigRpc, ConfigRpcClientFactory,
InstanceConfigPatch, PatchConfigRequest, PortForwardPatch, StringPatch, UrlPatch,
},
instance::{
instance_identifier::{InstanceSelector, Selector},
list_peer_route_pair, AclManageRpc, AclManageRpcClientFactory, ConnectorManageRpc,
ConnectorManageRpcClientFactory, DumpRouteRequest, GetAclStatsRequest,
GetPrometheusStatsRequest, GetStatsRequest, GetVpnPortalInfoRequest,
GetWhitelistRequest, InstanceIdentifier, ListConnectorRequest,
ListForeignNetworkRequest, ListGlobalForeignNetworkRequest,
ListMappedListenerRequest, ListPeerRequest, ListPeerResponse,
ListPortForwardRequest, ListRouteRequest, ListRouteResponse,
MappedListenerManageRpc, MappedListenerManageRpcClientFactory, NodeInfo,
PeerManageRpc, PeerManageRpcClientFactory, PortForwardManageRpc,
PortForwardManageRpcClientFactory, ShowNodeInfoRequest, StatsRpc,
StatsRpcClientFactory, TcpProxyEntryState, TcpProxyEntryTransportType, TcpProxyRpc,
TcpProxyRpcClientFactory, VpnPortalRpc, VpnPortalRpcClientFactory,
},
logger::{
GetLoggerConfigRequest, LogLevel, LoggerRpc, LoggerRpcClientFactory,
SetLoggerConfigRequest,
},
},
common::{NatType, PortForwardConfigPb, SocketType},
config::{
AclPatch, ConfigPatchAction, ConfigRpc, ConfigRpcClientFactory, InstanceConfigPatch,
PatchConfigRequest, PortForwardPatch, StringPatch, UrlPatch,
},
peer_rpc::{GetGlobalPeerMapRequest, PeerCenterRpc, PeerCenterRpcClientFactory},
rpc_impl::standalone::StandAloneClient,
rpc_types::controller::BaseController,
@@ -58,8 +65,12 @@ rust_i18n::i18n!("locales", fallback = "en");
#[derive(Parser, Debug)]
#[command(name = "easytier-cli", author, version = EASYTIER_VERSION, about, long_about = None)]
struct Cli {
/// the instance name
#[arg(short = 'p', long, default_value = "127.0.0.1:15888")]
#[arg(
short = 'p',
long,
default_value = "127.0.0.1:15888",
help = "easytier-core rpc portal address"
)]
rpc_portal: SocketAddr,
#[arg(short, long, default_value = "false", help = "verbose output")]
@@ -74,6 +85,9 @@ struct Cli {
)]
output_format: OutputFormat,
#[command(flatten)]
instance_select: InstanceSelectArgs,
#[command(subcommand)]
sub_command: SubCommand,
}
@@ -120,6 +134,28 @@ enum OutputFormat {
Json,
}
#[derive(Parser, Debug)]
struct InstanceSelectArgs {
#[arg(short = 'i', long = "instance-id", help = "the instance id")]
id: Option<uuid::Uuid>,
#[arg(short = 'n', long = "instance-name", help = "the instance name")]
name: Option<String>,
}
impl From<&InstanceSelectArgs> for InstanceIdentifier {
fn from(args: &InstanceSelectArgs) -> Self {
InstanceIdentifier {
selector: match args.id {
Some(id) => Some(Selector::Id(id.into())),
None => Some(Selector::InstanceSelector(InstanceSelector {
name: args.name.clone(),
})),
},
}
}
}
#[derive(Args, Debug)]
struct PeerArgs {
#[command(subcommand)]
@@ -351,6 +387,7 @@ struct CommandHandler<'a> {
client: tokio::sync::Mutex<RpcClient>,
verbose: bool,
output_format: &'a OutputFormat,
instance_selector: InstanceIdentifier,
}
type RpcClient = StandAloneClient<TcpTunnelConnector>;
@@ -491,14 +528,18 @@ impl CommandHandler<'_> {
async fn list_peers(&self) -> Result<ListPeerResponse, Error> {
let client = self.get_peer_manager_client().await?;
let request = ListPeerRequest::default();
let request = ListPeerRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client.list_peer(BaseController::default(), request).await?;
Ok(response)
}
async fn list_routes(&self) -> Result<ListRouteResponse, Error> {
let client = self.get_peer_manager_client().await?;
let request = ListRouteRequest::default();
let request = ListRouteRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.list_route(BaseController::default(), request)
.await?;
@@ -618,7 +659,12 @@ impl CommandHandler<'_> {
let client = self.get_peer_manager_client().await?;
let node_info = client
.show_node_info(BaseController::default(), ShowNodeInfoRequest::default())
.show_node_info(
BaseController::default(),
ShowNodeInfoRequest {
instance: Some(self.instance_selector.clone()),
},
)
.await?
.node_info
.ok_or(anyhow::anyhow!("node info not found"))?;
@@ -671,7 +717,9 @@ impl CommandHandler<'_> {
async fn handle_route_dump(&self) -> Result<(), Error> {
let client = self.get_peer_manager_client().await?;
let request = DumpRouteRequest::default();
let request = DumpRouteRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.dump_route(BaseController::default(), request)
.await?;
@@ -681,7 +729,9 @@ impl CommandHandler<'_> {
async fn handle_foreign_network_list(&self) -> Result<(), Error> {
let client = self.get_peer_manager_client().await?;
let request = ListForeignNetworkRequest::default();
let request = ListForeignNetworkRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.list_foreign_network(BaseController::default(), request)
.await?;
@@ -724,7 +774,9 @@ impl CommandHandler<'_> {
async fn handle_global_foreign_network_list(&self) -> Result<(), Error> {
let client = self.get_peer_manager_client().await?;
let request = ListGlobalForeignNetworkRequest::default();
let request = ListGlobalForeignNetworkRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.list_global_foreign_network(BaseController::default(), request)
.await?;
@@ -773,7 +825,12 @@ impl CommandHandler<'_> {
let mut items: Vec<RouteTableItem> = vec![];
let client = self.get_peer_manager_client().await?;
let node_info = client
.show_node_info(BaseController::default(), ShowNodeInfoRequest::default())
.show_node_info(
BaseController::default(),
ShowNodeInfoRequest {
instance: Some(self.instance_selector.clone()),
},
)
.await?
.node_info
.ok_or(anyhow::anyhow!("node info not found"))?;
@@ -895,7 +952,9 @@ impl CommandHandler<'_> {
async fn handle_connector_list(&self) -> Result<(), Error> {
let client = self.get_connector_manager_client().await?;
let request = ListConnectorRequest::default();
let request = ListConnectorRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.list_connector(BaseController::default(), request)
.await?;
@@ -909,7 +968,9 @@ impl CommandHandler<'_> {
async fn handle_acl_stats(&self) -> Result<(), Error> {
let client = self.get_acl_manager_client().await?;
let request = GetAclStatsRequest::default();
let request = GetAclStatsRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.get_acl_stats(BaseController::default(), request)
.await?;
@@ -929,7 +990,9 @@ impl CommandHandler<'_> {
async fn handle_mapped_listener_list(&self) -> Result<(), Error> {
let client = self.get_mapped_listener_manager_client().await?;
let request = ListMappedListenerRequest::default();
let request = ListMappedListenerRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.list_mapped_listener(BaseController::default(), request)
.await?;
@@ -952,6 +1015,7 @@ impl CommandHandler<'_> {
let url = Self::mapped_listener_validate_url(url)?;
let client = self.get_config_client().await?;
let request = PatchConfigRequest {
instance: Some(self.instance_selector.clone()),
patch: Some(InstanceConfigPatch {
mapped_listeners: vec![UrlPatch {
action: action.into(),
@@ -997,6 +1061,7 @@ impl CommandHandler<'_> {
let client = self.get_config_client().await?;
let request = PatchConfigRequest {
instance: Some(self.instance_selector.clone()),
patch: Some(InstanceConfigPatch {
port_forwards: vec![PortForwardPatch {
action: action.into(),
@@ -1024,7 +1089,9 @@ impl CommandHandler<'_> {
async fn handle_port_forward_list(&self) -> Result<(), Error> {
let client = self.get_port_forward_manager_client().await?;
let request = ListPortForwardRequest::default();
let request = ListPortForwardRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.list_port_forward(BaseController::default(), request)
.await?;
@@ -1082,6 +1149,7 @@ impl CommandHandler<'_> {
let client = self.get_config_client().await?;
let request = PatchConfigRequest {
instance: Some(self.instance_selector.clone()),
patch: Some(InstanceConfigPatch {
acl: Some(AclPatch {
tcp_whitelist: whitelist,
@@ -1116,6 +1184,7 @@ impl CommandHandler<'_> {
let client = self.get_config_client().await?;
let request = PatchConfigRequest {
instance: Some(self.instance_selector.clone()),
patch: Some(InstanceConfigPatch {
acl: Some(AclPatch {
udp_whitelist: whitelist,
@@ -1136,6 +1205,7 @@ impl CommandHandler<'_> {
let client = self.get_config_client().await?;
let request = PatchConfigRequest {
instance: Some(self.instance_selector.clone()),
patch: Some(InstanceConfigPatch {
acl: Some(AclPatch {
tcp_whitelist: vec![StringPatch {
@@ -1159,6 +1229,7 @@ impl CommandHandler<'_> {
let client = self.get_config_client().await?;
let request = PatchConfigRequest {
instance: Some(self.instance_selector.clone()),
patch: Some(InstanceConfigPatch {
acl: Some(AclPatch {
udp_whitelist: vec![StringPatch {
@@ -1180,7 +1251,9 @@ impl CommandHandler<'_> {
async fn handle_whitelist_show(&self) -> Result<(), Error> {
let client = self.get_acl_manager_client().await?;
let request = GetWhitelistRequest::default();
let request = GetWhitelistRequest {
instance: Some(self.instance_selector.clone()),
};
let response = client
.get_whitelist(BaseController::default(), request)
.await?;
@@ -1213,7 +1286,7 @@ impl CommandHandler<'_> {
async fn handle_logger_get(&self) -> Result<(), Error> {
let client = self.get_logger_client().await?;
let request = GetLoggerConfigRequest {};
let request = GetLoggerConfigRequest::default();
let response = client
.get_logger_config(BaseController::default(), request)
.await?;
@@ -1601,6 +1674,7 @@ async fn main() -> Result<(), Error> {
client: tokio::sync::Mutex::new(client),
verbose: cli.verbose,
output_format: &cli.output_format,
instance_selector: (&cli.instance_select).into(),
};
match cli.sub_command {
@@ -1700,7 +1774,12 @@ async fn main() -> Result<(), Error> {
let node_info = handler
.get_peer_manager_client()
.await?
.show_node_info(BaseController::default(), ShowNodeInfoRequest::default())
.show_node_info(
BaseController::default(),
ShowNodeInfoRequest {
instance: Some((&cli.instance_select).into()),
},
)
.await?
.node_info
.ok_or(anyhow::anyhow!("node info not found"))?;
@@ -1804,7 +1883,9 @@ async fn main() -> Result<(), Error> {
let resp = vpn_portal_client
.get_vpn_portal_info(
BaseController::default(),
GetVpnPortalInfoRequest::default(),
GetVpnPortalInfoRequest {
instance: Some((&cli.instance_select).into()),
},
)
.await?
.vpn_portal_info
@@ -1823,7 +1904,12 @@ async fn main() -> Result<(), Error> {
SubCommand::Node(sub_cmd) => {
let client = handler.get_peer_manager_client().await?;
let node_info = client
.show_node_info(BaseController::default(), ShowNodeInfoRequest::default())
.show_node_info(
BaseController::default(),
ShowNodeInfoRequest {
instance: Some((&cli.instance_select).into()),
},
)
.await?
.node_info
.ok_or(anyhow::anyhow!("node info not found"))?;
@@ -2058,7 +2144,9 @@ async fn main() -> Result<(), Error> {
SubCommand::Stats(stats_args) => match &stats_args.sub_command {
Some(StatsSubCommand::Show) | None => {
let client = handler.get_stats_client().await?;
let request = GetStatsRequest {};
let request = GetStatsRequest {
instance: Some((&cli.instance_select).into()),
};
let response = client.get_stats(BaseController::default(), request).await?;
if cli.output_format == OutputFormat::Json {
@@ -2110,7 +2198,9 @@ async fn main() -> Result<(), Error> {
}
Some(StatsSubCommand::Prometheus) => {
let client = handler.get_stats_client().await?;
let request = GetPrometheusStatsRequest {};
let request = GetPrometheusStatsRequest {
instance: Some((&cli.instance_select).into()),
};
let response = client
.get_prometheus_stats(BaseController::default(), request)
.await?;

View File

@@ -30,6 +30,7 @@ use easytier::{
instance_manager::NetworkInstanceManager,
launcher::{add_proxy_network_to_config, ConfigSource},
proto::common::{CompressionAlgoPb, NatType},
rpc_service::ApiRpcServer,
tunnel::{IpVersion, PROTO_PORT_OFFSET},
utils::{init_logger, setup_panic_handler},
web_client,
@@ -130,6 +131,9 @@ struct Cli {
#[command(flatten)]
logging_options: LoggingOptions,
#[command(flatten)]
rpc_portal_options: RpcPortalOptions,
#[clap(long, help = t!("core_clap.generate_completions").to_string())]
gen_autocomplete: Option<Shell>,
@@ -205,22 +209,6 @@ struct NetworkOptions {
)]
proxy_networks: Vec<String>,
#[arg(
short,
long,
env = "ET_RPC_PORTAL",
help = t!("core_clap.rpc_portal").to_string(),
)]
rpc_portal: Option<String>,
#[arg(
long,
env = "ET_RPC_PORTAL_WHITELIST",
value_delimiter = ',',
help = t!("core_clap.rpc_portal_whitelist").to_string(),
)]
rpc_portal_whitelist: Option<Vec<IpCidr>>,
#[arg(
short,
long,
@@ -624,6 +612,25 @@ struct LoggingOptions {
file_log_count: Option<usize>,
}
#[derive(Parser, Debug)]
struct RpcPortalOptions {
#[arg(
short,
long,
env = "ET_RPC_PORTAL",
help = t!("core_clap.rpc_portal").to_string(),
)]
rpc_portal: Option<String>,
#[arg(
long,
env = "ET_RPC_PORTAL_WHITELIST",
value_delimiter = ',',
help = t!("core_clap.rpc_portal_whitelist").to_string(),
)]
rpc_portal_whitelist: Option<Vec<IpCidr>>,
}
rust_i18n::i18n!("locales", fallback = "en");
impl Cli {
@@ -671,14 +678,6 @@ impl Cli {
Ok(listeners)
}
fn parse_rpc_portal(rpc_portal: String) -> anyhow::Result<SocketAddr> {
if let Ok(port) = rpc_portal.parse::<u16>() {
return Ok(format!("0.0.0.0:{}", port).parse().unwrap());
}
Ok(rpc_portal.parse()?)
}
}
impl NetworkOptions {
@@ -786,24 +785,6 @@ impl NetworkOptions {
add_proxy_network_to_config(n, cfg)?;
}
let rpc_portal = if let Some(r) = &self.rpc_portal {
Cli::parse_rpc_portal(r.clone())
.with_context(|| format!("failed to parse rpc portal: {}", r))?
} else if let Some(r) = cfg.get_rpc_portal() {
r
} else {
Cli::parse_rpc_portal("0".into())?
};
cfg.set_rpc_portal(rpc_portal);
if let Some(rpc_portal_whitelist) = &self.rpc_portal_whitelist {
let mut whitelist = cfg.get_rpc_portal_whitelist().unwrap_or_default();
for cidr in rpc_portal_whitelist {
whitelist.push(*cidr);
}
cfg.set_rpc_portal_whitelist(Some(whitelist));
}
if let Some(external_nodes) = self.external_node.as_ref() {
let mut old_peers = cfg.get_peers();
old_peers.push(PeerConfig {
@@ -1127,6 +1108,16 @@ fn win_service_main(arg: Vec<std::ffi::OsString>) {
async fn run_main(cli: Cli) -> anyhow::Result<()> {
init_logger(&cli.logging_options, true)?;
let manager = Arc::new(NetworkInstanceManager::new());
let _rpc_server = ApiRpcServer::new(
cli.rpc_portal_options.rpc_portal,
cli.rpc_portal_options.rpc_portal_whitelist,
manager.clone(),
)?
.serve()
.await?;
if cli.config_server.is_some() {
set_default_machine_id(cli.machine_id);
let config_server_url_s = cli.config_server.clone().unwrap();
@@ -1175,11 +1166,11 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
create_connector_by_url(c_url.as_str(), &global_ctx, IpVersion::Both).await?,
token.to_string(),
hostname,
manager,
);
tokio::signal::ctrl_c().await.unwrap();
return Ok(());
}
let manager = NetworkInstanceManager::new();
let mut crate_cli_network =
cli.config_file.is_none() || cli.network_options.network_name.is_some();
if let Some(config_files) = cli.config_file {

View File

@@ -40,7 +40,7 @@ use crate::{
peers::{acl_filter::AclFilter, peer_manager::PeerManager, NicPacketFilter, PeerPacketFilter},
proto::{
acl::{Action, ChainType, Protocol},
cli::{
api::instance::{
ListTcpProxyEntryRequest, ListTcpProxyEntryResponse, TcpProxyEntry, TcpProxyEntryState,
TcpProxyEntryTransportType, TcpProxyRpc,
},

View File

@@ -22,7 +22,7 @@ use crate::gateway::tcp_proxy::{NatDstConnector, NatDstTcpConnector, TcpProxy};
use crate::gateway::CidrSet;
use crate::peers::peer_manager::PeerManager;
use crate::proto::acl::{ChainType, Protocol};
use crate::proto::cli::{
use crate::proto::api::instance::{
ListTcpProxyEntryRequest, ListTcpProxyEntryResponse, TcpProxyEntry, TcpProxyEntryState,
TcpProxyEntryTransportType, TcpProxyRpc,
};

View File

@@ -27,7 +27,7 @@ use crate::common::join_joinset_background;
use crate::common::stats_manager::{LabelSet, LabelType, MetricName};
use crate::peers::peer_manager::PeerManager;
use crate::peers::{NicPacketFilter, PeerPacketFilter};
use crate::proto::cli::{
use crate::proto::api::instance::{
ListTcpProxyEntryRequest, ListTcpProxyEntryResponse, TcpProxyEntry, TcpProxyEntryState,
TcpProxyEntryTransportType, TcpProxyRpc,
};

View File

@@ -5,7 +5,7 @@ use tokio::task::JoinSet;
use crate::{
peers::peer_manager::PeerManager,
proto::{
cli::Route,
api::instance::Route,
common::Void,
magic_dns::{
HandshakeRequest, MagicDnsServerRpc, MagicDnsServerRpcClientFactory,

View File

@@ -24,7 +24,7 @@ use crate::{
},
peers::{peer_manager::PeerManager, NicPacketFilter},
proto::{
cli::Route,
api::instance::Route,
common::{TunnelInfo, Void},
magic_dns::{
dns_record::{self},

View File

@@ -21,7 +21,7 @@ use crate::instance::virtual_nic::NicCtx;
use crate::peers::peer_manager::{PeerManager, RouteAlgoType};
use crate::peers::create_packet_recv_chan;
use crate::proto::cli::Route;
use crate::proto::api::instance::Route;
use crate::proto::common::NatType;
pub async fn prepare_env(dns_name: &str, tun_ip: Ipv4Inet) -> (Arc<PeerManager>, NicCtx) {

View File

@@ -32,23 +32,22 @@ use crate::peers::peer_conn::PeerConnId;
use crate::peers::peer_manager::{PeerManager, RouteAlgoType};
use crate::peers::rpc_service::PeerManagerRpcService;
use crate::peers::{create_packet_recv_chan, recv_packet_from_chan, PacketRecvChanReceiver};
use crate::proto::cli::VpnPortalRpc;
use crate::proto::cli::{
use crate::proto::api::config::{
ConfigPatchAction, ConfigRpc, PatchConfigRequest, PatchConfigResponse, PortForwardPatch,
};
use crate::proto::api::instance::{
GetPrometheusStatsRequest, GetPrometheusStatsResponse, GetStatsRequest, GetStatsResponse,
ListMappedListenerRequest, ListMappedListenerResponse, ListPortForwardRequest,
ListPortForwardResponse, MappedListener, MappedListenerManageRpc, MetricSnapshot,
PortForwardManageRpc, StatsRpc,
GetVpnPortalInfoRequest, GetVpnPortalInfoResponse, ListMappedListenerRequest,
ListMappedListenerResponse, ListPortForwardRequest, ListPortForwardResponse, MappedListener,
MappedListenerManageRpc, MetricSnapshot, PortForwardManageRpc, StatsRpc, VpnPortalInfo,
VpnPortalRpc,
};
use crate::proto::cli::{GetVpnPortalInfoRequest, GetVpnPortalInfoResponse, VpnPortalInfo};
use crate::proto::common::{PortForwardConfigPb, TunnelInfo, Void};
use crate::proto::config::{
ConfigPatchAction, ConfigRpc, ConfigRpcServer, PatchConfigRequest, PortForwardPatch,
};
use crate::proto::peer_rpc::PeerCenterRpcServer;
use crate::proto::rpc_impl::standalone::{RpcServerHook, StandAloneServer};
use crate::proto::common::{PortForwardConfigPb, TunnelInfo};
use crate::proto::rpc_impl::standalone::RpcServerHook;
use crate::proto::rpc_types;
use crate::proto::rpc_types::controller::BaseController;
use crate::tunnel::tcp::TcpTunnelListener;
use crate::rpc_service::InstanceRpcService;
use crate::utils::weak_upgrade;
use crate::vpn_portal::{self, VpnPortal};
use super::dns_server::runner::DnsRunner;
@@ -229,15 +228,16 @@ impl RpcServerHook for InstanceRpcServerHook {
#[derive(Clone)]
pub struct InstanceConfigPatcher {
global_ctx: ArcGlobalCtx,
global_ctx: Weak<GlobalCtx>,
socks5_server: Weak<Socks5Server>,
peer_manager: Arc<PeerManager>,
peer_manager: Weak<PeerManager>,
conn_manager: Weak<ManualConnectorManager>,
}
impl InstanceConfigPatcher {
pub async fn apply_patch(
&self,
patch: crate::proto::config::InstanceConfigPatch,
patch: crate::proto::api::config::InstanceConfigPatch,
) -> Result<(), anyhow::Error> {
let patch_for_event = patch.clone();
@@ -247,27 +247,32 @@ impl InstanceConfigPatcher {
self.patch_routes(patch.routes).await?;
self.patch_exit_nodes(patch.exit_nodes).await?;
self.patch_mapped_listeners(patch.mapped_listeners).await?;
self.patch_connector(patch.connectors).await?;
let global_ctx = weak_upgrade(&self.global_ctx)?;
if let Some(hostname) = patch.hostname {
self.global_ctx.set_hostname(hostname.clone());
self.global_ctx.config.set_hostname(Some(hostname));
global_ctx.set_hostname(hostname.clone());
global_ctx.config.set_hostname(Some(hostname));
}
if let Some(ipv4) = patch.ipv4 {
if !self.global_ctx.config.get_dhcp() {
self.global_ctx.set_ipv4(Some(ipv4.into()));
self.global_ctx.config.set_ipv4(Some(ipv4.into()));
if !global_ctx.config.get_dhcp() {
global_ctx.set_ipv4(Some(ipv4.into()));
global_ctx.config.set_ipv4(Some(ipv4.into()));
}
}
if let Some(ipv6) = patch.ipv6 {
self.global_ctx.set_ipv6(Some(ipv6.into()));
self.global_ctx.config.set_ipv6(Some(ipv6.into()));
global_ctx.set_ipv6(Some(ipv6.into()));
global_ctx.config.set_ipv6(Some(ipv6.into()));
}
self.global_ctx
.issue_event(GlobalCtxEvent::ConfigPatched(patch_for_event));
global_ctx.issue_event(GlobalCtxEvent::ConfigPatched(patch_for_event));
Ok(())
}
fn trace_patchables<T: std::fmt::Debug>(patches: &Vec<crate::proto::config::Patchable<T>>) {
fn trace_patchables<T: std::fmt::Debug>(
patches: &Vec<crate::proto::api::config::Patchable<T>>,
) {
for patch in patches {
match patch.action {
Some(ConfigPatchAction::Add) | Some(ConfigPatchAction::Remove) => {
@@ -304,13 +309,14 @@ impl InstanceConfigPatcher {
let Some(socks5_server) = self.socks5_server.upgrade() else {
return Err(anyhow::anyhow!("socks5 server not available"));
};
let global_ctx = weak_upgrade(&self.global_ctx)?;
let mut current_forwards = self.global_ctx.config.get_port_forwards();
let mut current_forwards = global_ctx.config.get_port_forwards();
let patches = port_forwards.into_iter().map(Into::into).collect();
InstanceConfigPatcher::trace_patchables(&patches);
crate::proto::config::patch_vec(&mut current_forwards, patches);
crate::proto::api::config::patch_vec(&mut current_forwards, patches);
self.global_ctx
global_ctx
.config
.set_port_forwards(current_forwards.clone());
socks5_server
@@ -323,49 +329,51 @@ impl InstanceConfigPatcher {
async fn patch_acl(
&self,
acl_patch: Option<crate::proto::config::AclPatch>,
acl_patch: Option<crate::proto::api::config::AclPatch>,
) -> Result<(), anyhow::Error> {
let Some(acl_patch) = acl_patch else {
return Ok(());
};
let global_ctx = weak_upgrade(&self.global_ctx)?;
if let Some(acl) = acl_patch.acl {
self.global_ctx.config.set_acl(Some(acl));
global_ctx.config.set_acl(Some(acl));
}
if !acl_patch.tcp_whitelist.is_empty() {
let mut current_whitelist = self.global_ctx.config.get_tcp_whitelist();
let mut current_whitelist = global_ctx.config.get_tcp_whitelist();
let patches = acl_patch
.tcp_whitelist
.into_iter()
.map(Into::into)
.collect();
InstanceConfigPatcher::trace_patchables(&patches);
crate::proto::config::patch_vec(&mut current_whitelist, patches);
self.global_ctx.config.set_tcp_whitelist(current_whitelist);
crate::proto::api::config::patch_vec(&mut current_whitelist, patches);
global_ctx.config.set_tcp_whitelist(current_whitelist);
}
if !acl_patch.udp_whitelist.is_empty() {
let mut current_whitelist = self.global_ctx.config.get_udp_whitelist();
let mut current_whitelist = global_ctx.config.get_udp_whitelist();
let patches = acl_patch
.udp_whitelist
.into_iter()
.map(Into::into)
.collect();
InstanceConfigPatcher::trace_patchables(&patches);
crate::proto::config::patch_vec(&mut current_whitelist, patches);
self.global_ctx.config.set_udp_whitelist(current_whitelist);
crate::proto::api::config::patch_vec(&mut current_whitelist, patches);
global_ctx.config.set_udp_whitelist(current_whitelist);
}
self.global_ctx
global_ctx
.get_acl_filter()
.reload_rules(AclRuleBuilder::build(&self.global_ctx)?.as_ref());
.reload_rules(AclRuleBuilder::build(&global_ctx)?.as_ref());
Ok(())
}
async fn patch_proxy_networks(
&self,
proxy_networks: Vec<crate::proto::config::ProxyNetworkPatch>,
proxy_networks: Vec<crate::proto::api::config::ProxyNetworkPatch>,
) -> Result<(), anyhow::Error> {
if proxy_networks.is_empty() {
return Ok(());
}
let global_ctx = weak_upgrade(&self.global_ctx)?;
for proxy_network_patch in proxy_networks {
let Some(cidr) = proxy_network_patch.cidr.map(|c| c.into()) else {
tracing::warn!("Proxy network cidr is None, skipping.");
@@ -376,15 +384,15 @@ impl InstanceConfigPatcher {
match ConfigPatchAction::try_from(proxy_network_patch.action) {
Ok(ConfigPatchAction::Add) => {
tracing::info!("Proxy network added: {}", cidr);
self.global_ctx.config.add_proxy_cidr(cidr, mapped_cidr)?;
global_ctx.config.add_proxy_cidr(cidr, mapped_cidr)?;
}
Ok(ConfigPatchAction::Remove) => {
tracing::info!("Proxy network removed: {}", cidr);
self.global_ctx.config.remove_proxy_cidr(cidr);
global_ctx.config.remove_proxy_cidr(cidr);
}
Ok(ConfigPatchAction::Clear) => {
tracing::info!("Proxy networks cleared.");
self.global_ctx.config.clear_proxy_cidrs();
global_ctx.config.clear_proxy_cidrs();
}
Err(_) => {
tracing::warn!(
@@ -399,60 +407,98 @@ impl InstanceConfigPatcher {
async fn patch_routes(
&self,
routes: Vec<crate::proto::config::RoutePatch>,
routes: Vec<crate::proto::api::config::RoutePatch>,
) -> Result<(), anyhow::Error> {
if routes.is_empty() {
return Ok(());
}
let mut current_routes = self.global_ctx.config.get_routes().unwrap_or_default();
let global_ctx = weak_upgrade(&self.global_ctx)?;
let mut current_routes = global_ctx.config.get_routes().unwrap_or_default();
let patches = routes.into_iter().map(Into::into).collect();
InstanceConfigPatcher::trace_patchables(&patches);
crate::proto::config::patch_vec(&mut current_routes, patches);
crate::proto::api::config::patch_vec(&mut current_routes, patches);
if current_routes.is_empty() {
self.global_ctx.config.set_routes(None);
global_ctx.config.set_routes(None);
} else {
self.global_ctx.config.set_routes(Some(current_routes));
global_ctx.config.set_routes(Some(current_routes));
}
Ok(())
}
async fn patch_exit_nodes(
&self,
exit_nodes: Vec<crate::proto::config::ExitNodePatch>,
exit_nodes: Vec<crate::proto::api::config::ExitNodePatch>,
) -> Result<(), anyhow::Error> {
if exit_nodes.is_empty() {
return Ok(());
}
let mut current_exit_nodes = self.global_ctx.config.get_exit_nodes();
let global_ctx = weak_upgrade(&self.global_ctx)?;
let peer_manager = weak_upgrade(&self.peer_manager)?;
let mut current_exit_nodes = global_ctx.config.get_exit_nodes();
let patches = exit_nodes.into_iter().map(Into::into).collect();
InstanceConfigPatcher::trace_patchables(&patches);
crate::proto::config::patch_vec(&mut current_exit_nodes, patches);
self.global_ctx.config.set_exit_nodes(current_exit_nodes);
self.peer_manager.update_exit_nodes().await;
crate::proto::api::config::patch_vec(&mut current_exit_nodes, patches);
global_ctx.config.set_exit_nodes(current_exit_nodes);
peer_manager.update_exit_nodes().await;
Ok(())
}
async fn patch_mapped_listeners(
&self,
mapped_listeners: Vec<crate::proto::config::UrlPatch>,
mapped_listeners: Vec<crate::proto::api::config::UrlPatch>,
) -> Result<(), anyhow::Error> {
if mapped_listeners.is_empty() {
return Ok(());
}
let mut current_mapped_listeners = self.global_ctx.config.get_mapped_listeners();
let global_ctx = weak_upgrade(&self.global_ctx)?;
let mut current_mapped_listeners = global_ctx.config.get_mapped_listeners();
let patches = mapped_listeners.into_iter().map(Into::into).collect();
InstanceConfigPatcher::trace_patchables(&patches);
crate::proto::config::patch_vec(&mut current_mapped_listeners, patches);
crate::proto::api::config::patch_vec(&mut current_mapped_listeners, patches);
if current_mapped_listeners.is_empty() {
self.global_ctx.config.set_mapped_listeners(None);
global_ctx.config.set_mapped_listeners(None);
} else {
self.global_ctx
global_ctx
.config
.set_mapped_listeners(Some(current_mapped_listeners));
}
Ok(())
}
async fn patch_connector(
&self,
connectors: Vec<crate::proto::api::config::UrlPatch>,
) -> Result<(), anyhow::Error> {
if connectors.is_empty() {
return Ok(());
}
let conn_manager = weak_upgrade(&self.conn_manager)?;
for connector in connectors {
let Some(url) = connector.url.map(Into::<url::Url>::into) else {
tracing::warn!("Connector url is None, skipping.");
return Ok(());
};
match ConfigPatchAction::try_from(connector.action) {
Ok(ConfigPatchAction::Add) => {
tracing::info!("Connector added: {}", url);
conn_manager.add_connector_by_url(url.as_str()).await?;
}
Ok(ConfigPatchAction::Remove) => {
tracing::info!("Connector removed: {}", url);
conn_manager.remove_connector(url).await?;
}
Ok(ConfigPatchAction::Clear) => {
tracing::info!("Connectors cleared.");
conn_manager.clear_connectors().await;
}
Err(_) => {
tracing::warn!("Invalid connector action: {}", connector.action);
}
}
}
Ok(())
}
}
pub struct Instance {
@@ -484,8 +530,6 @@ pub struct Instance {
#[cfg(feature = "socks5")]
socks5_server: Arc<Socks5Server>,
rpc_server: Option<StandAloneServer<TcpTunnelListener>>,
global_ctx: ArcGlobalCtx,
}
@@ -536,12 +580,6 @@ impl Instance {
#[cfg(feature = "socks5")]
let socks5_server = Socks5Server::new(global_ctx.clone(), peer_manager.clone(), None);
let rpc_server = global_ctx.config.get_rpc_portal().map(|s| {
StandAloneServer::new(TcpTunnelListener::new(
format!("tcp://{}", s).parse().unwrap(),
))
});
Instance {
inst_name: global_ctx.inst_name.clone(),
id,
@@ -569,8 +607,6 @@ impl Instance {
#[cfg(feature = "socks5")]
socks5_server,
rpc_server,
global_ctx,
}
}
@@ -934,8 +970,6 @@ impl Instance {
)
.await?;
self.run_rpc_server().await?;
Ok(())
}
@@ -1034,7 +1068,7 @@ impl Instance {
&self,
) -> impl MappedListenerManageRpc<Controller = BaseController> + Clone {
#[derive(Clone)]
pub struct MappedListenerManagerRpcService(Arc<GlobalCtx>);
pub struct MappedListenerManagerRpcService(Weak<GlobalCtx>);
#[async_trait::async_trait]
impl MappedListenerManageRpc for MappedListenerManagerRpcService {
@@ -1046,7 +1080,7 @@ impl Instance {
_request: ListMappedListenerRequest,
) -> Result<ListMappedListenerResponse, rpc_types::error::Error> {
let mut ret = ListMappedListenerResponse::default();
let urls = self.0.config.get_mapped_listeners();
let urls = weak_upgrade(&self.0)?.config.get_mapped_listeners();
let mapped_listeners: Vec<MappedListener> = urls
.into_iter()
.map(|u| MappedListener {
@@ -1058,7 +1092,7 @@ impl Instance {
}
}
MappedListenerManagerRpcService(self.global_ctx.clone())
MappedListenerManagerRpcService(Arc::downgrade(&self.global_ctx))
}
fn get_port_forward_manager_rpc_service(
@@ -1066,7 +1100,7 @@ impl Instance {
) -> impl PortForwardManageRpc<Controller = BaseController> + Clone {
#[derive(Clone)]
pub struct PortForwardManagerRpcService {
global_ctx: ArcGlobalCtx,
global_ctx: Weak<GlobalCtx>,
socks5_server: Weak<Socks5Server>,
}
@@ -1079,14 +1113,14 @@ impl Instance {
_: BaseController,
_request: ListPortForwardRequest,
) -> Result<ListPortForwardResponse, rpc_types::error::Error> {
let forwards = self.global_ctx.config.get_port_forwards();
let forwards = weak_upgrade(&self.global_ctx)?.config.get_port_forwards();
let cfgs: Vec<PortForwardConfigPb> = forwards.into_iter().map(Into::into).collect();
Ok(ListPortForwardResponse { cfgs })
}
}
PortForwardManagerRpcService {
global_ctx: self.global_ctx.clone(),
global_ctx: Arc::downgrade(&self.global_ctx),
socks5_server: Arc::downgrade(&self.socks5_server),
}
}
@@ -1094,7 +1128,7 @@ impl Instance {
fn get_stats_rpc_service(&self) -> impl StatsRpc<Controller = BaseController> + Clone {
#[derive(Clone)]
pub struct StatsRpcService {
global_ctx: ArcGlobalCtx,
global_ctx: Weak<GlobalCtx>,
}
#[async_trait::async_trait]
@@ -1106,8 +1140,9 @@ impl Instance {
_: BaseController,
_request: GetStatsRequest,
) -> Result<GetStatsResponse, rpc_types::error::Error> {
let stats_manager = self.global_ctx.stats_manager();
let snapshots = stats_manager.get_all_metrics();
let snapshots = weak_upgrade(&self.global_ctx)?
.stats_manager()
.get_all_metrics();
let metrics = snapshots
.into_iter()
@@ -1133,23 +1168,25 @@ impl Instance {
_: BaseController,
_request: GetPrometheusStatsRequest,
) -> Result<GetPrometheusStatsResponse, rpc_types::error::Error> {
let stats_manager = self.global_ctx.stats_manager();
let prometheus_text = stats_manager.export_prometheus();
let prometheus_text = weak_upgrade(&self.global_ctx)?
.stats_manager()
.export_prometheus();
Ok(GetPrometheusStatsResponse { prometheus_text })
}
}
StatsRpcService {
global_ctx: self.global_ctx.clone(),
global_ctx: Arc::downgrade(&self.global_ctx),
}
}
pub fn get_config_patcher(&self) -> InstanceConfigPatcher {
InstanceConfigPatcher {
global_ctx: self.global_ctx.clone(),
global_ctx: Arc::downgrade(&self.global_ctx),
socks5_server: Arc::downgrade(&self.socks5_server),
peer_manager: self.peer_manager.clone(),
peer_manager: Arc::downgrade(&self.peer_manager),
conn_manager: Arc::downgrade(&self.conn_manager),
}
}
@@ -1167,13 +1204,13 @@ impl Instance {
&self,
_: Self::Controller,
request: PatchConfigRequest,
) -> crate::proto::rpc_types::error::Result<Void> {
) -> crate::proto::rpc_types::error::Result<PatchConfigResponse> {
let Some(patch) = request.patch else {
return Ok(Void::default());
return Ok(PatchConfigResponse::default());
};
self.patcher.apply_patch(patch).await?;
Ok(Void::default())
Ok(PatchConfigResponse::default())
}
}
@@ -1182,97 +1219,140 @@ impl Instance {
}
}
async fn run_rpc_server(&mut self) -> Result<(), Error> {
let Some(_) = self.global_ctx.config.get_rpc_portal() else {
tracing::info!("rpc server not enabled, because rpc_portal is not set.");
return Ok(());
};
pub fn get_api_rpc_service(&self) -> impl InstanceRpcService {
use crate::proto::api::instance::*;
use crate::instance::logger_rpc_service::LoggerRpcService;
use crate::proto::cli::*;
let peer_mgr = self.peer_manager.clone();
let conn_manager = self.conn_manager.clone();
let peer_center = self.peer_center.clone();
let vpn_portal_rpc = self.get_vpn_portal_rpc_service();
let mapped_listener_manager_rpc = self.get_mapped_listener_manager_rpc_service();
let port_forward_manager_rpc = self.get_port_forward_manager_rpc_service();
let stats_rpc_service = self.get_stats_rpc_service();
let logger_rpc_service = LoggerRpcService::new();
let config_rpc_service = self.get_config_service();
let s = self.rpc_server.as_mut().unwrap();
let peer_mgr_rpc_service = PeerManagerRpcService::new(peer_mgr.clone());
s.registry()
.register(PeerManageRpcServer::new(peer_mgr_rpc_service.clone()), "");
s.registry()
.register(AclManageRpcServer::new(peer_mgr_rpc_service), "");
s.registry().register(
ConnectorManageRpcServer::new(ConnectorManagerRpcService(conn_manager)),
"",
);
s.registry()
.register(PeerCenterRpcServer::new(peer_center.get_rpc_service()), "");
s.registry()
.register(VpnPortalRpcServer::new(vpn_portal_rpc), "");
s.registry().register(
MappedListenerManageRpcServer::new(mapped_listener_manager_rpc),
"",
);
s.registry().register(
PortForwardManageRpcServer::new(port_forward_manager_rpc),
"",
);
s.registry().register(
crate::proto::cli::StatsRpcServer::new(stats_rpc_service),
"",
);
s.registry()
.register(LoggerRpcServer::new(logger_rpc_service), "");
s.registry()
.register(ConfigRpcServer::new(config_rpc_service), "");
if let Some(ip_proxy) = self.ip_proxy.as_ref() {
s.registry().register(
TcpProxyRpcServer::new(TcpProxyRpcService::new(ip_proxy.tcp_proxy.clone())),
"tcp",
);
}
if let Some(kcp_proxy) = self.kcp_proxy_src.as_ref() {
s.registry().register(
TcpProxyRpcServer::new(TcpProxyRpcService::new(kcp_proxy.get_tcp_proxy())),
"kcp_src",
);
#[derive(Clone)]
struct ApiRpcServiceImpl<A, B, C, D, E, F, G, H> {
peer_mgr_rpc_service: A,
connector_mgr_rpc_service: B,
mapped_listener_mgr_rpc_service: C,
vpn_portal_rpc_service: D,
tcp_proxy_rpc_services: dashmap::DashMap<
String,
Arc<dyn TcpProxyRpc<Controller = BaseController> + Send + Sync>,
>,
acl_manage_rpc_service: E,
port_forward_manage_rpc_service: F,
stats_rpc_service: G,
config_rpc_service: H,
}
if let Some(kcp_proxy) = self.kcp_proxy_dst.as_ref() {
s.registry().register(
TcpProxyRpcServer::new(KcpProxyDstRpcService::new(kcp_proxy)),
"kcp_dst",
);
#[async_trait::async_trait]
impl<
A: PeerManageRpc<Controller = BaseController> + Send + Sync,
B: ConnectorManageRpc<Controller = BaseController> + Send + Sync,
C: MappedListenerManageRpc<Controller = BaseController> + Send + Sync,
D: VpnPortalRpc<Controller = BaseController> + Send + Sync,
E: AclManageRpc<Controller = BaseController> + Send + Sync,
F: PortForwardManageRpc<Controller = BaseController> + Send + Sync,
G: StatsRpc<Controller = BaseController> + Send + Sync,
H: ConfigRpc<Controller = BaseController> + Send + Sync,
> InstanceRpcService for ApiRpcServiceImpl<A, B, C, D, E, F, G, H>
{
fn get_peer_manage_service(&self) -> &dyn PeerManageRpc<Controller = BaseController> {
&self.peer_mgr_rpc_service
}
fn get_connector_manage_service(
&self,
) -> &dyn ConnectorManageRpc<Controller = BaseController> {
&self.connector_mgr_rpc_service
}
fn get_mapped_listener_manage_service(
&self,
) -> &dyn MappedListenerManageRpc<Controller = BaseController> {
&self.mapped_listener_mgr_rpc_service
}
fn get_vpn_portal_service(&self) -> &dyn VpnPortalRpc<Controller = BaseController> {
&self.vpn_portal_rpc_service
}
fn get_proxy_service(
&self,
client_type: &str,
) -> Option<Arc<dyn TcpProxyRpc<Controller = BaseController> + Send + Sync>>
{
self.tcp_proxy_rpc_services
.get(client_type)
.map(|e| e.clone())
}
fn get_acl_manage_service(&self) -> &dyn AclManageRpc<Controller = BaseController> {
&self.acl_manage_rpc_service
}
fn get_port_forward_manage_service(
&self,
) -> &dyn PortForwardManageRpc<Controller = BaseController> {
&self.port_forward_manage_rpc_service
}
fn get_stats_service(&self) -> &dyn StatsRpc<Controller = BaseController> {
&self.stats_rpc_service
}
fn get_config_service(&self) -> &dyn ConfigRpc<Controller = BaseController> {
&self.config_rpc_service
}
}
if let Some(quic_proxy) = self.quic_proxy_src.as_ref() {
s.registry().register(
TcpProxyRpcServer::new(TcpProxyRpcService::new(quic_proxy.get_tcp_proxy())),
"quic_src",
);
ApiRpcServiceImpl {
peer_mgr_rpc_service: PeerManagerRpcService::new(self.peer_manager.clone()),
connector_mgr_rpc_service: ConnectorManagerRpcService(Arc::downgrade(
&self.conn_manager,
)),
mapped_listener_mgr_rpc_service: self.get_mapped_listener_manager_rpc_service(),
vpn_portal_rpc_service: self.get_vpn_portal_rpc_service(),
tcp_proxy_rpc_services: {
let tcp_proxy_rpc_services: dashmap::DashMap<
String,
Arc<dyn TcpProxyRpc<Controller = BaseController> + Send + Sync>,
> = dashmap::DashMap::new();
if let Some(ip_proxy) = self.ip_proxy.as_ref() {
tcp_proxy_rpc_services.insert(
"tcp".to_string(),
Arc::new(TcpProxyRpcService::new(ip_proxy.tcp_proxy.clone())),
);
}
if let Some(kcp_proxy) = self.kcp_proxy_src.as_ref() {
tcp_proxy_rpc_services.insert(
"kcp_src".to_string(),
Arc::new(TcpProxyRpcService::new(kcp_proxy.get_tcp_proxy())),
);
}
if let Some(kcp_proxy) = self.kcp_proxy_dst.as_ref() {
tcp_proxy_rpc_services.insert(
"kcp_dst".to_string(),
Arc::new(KcpProxyDstRpcService::new(kcp_proxy)),
);
}
if let Some(quic_proxy) = self.quic_proxy_src.as_ref() {
tcp_proxy_rpc_services.insert(
"quic_src".to_string(),
Arc::new(TcpProxyRpcService::new(quic_proxy.get_tcp_proxy())),
);
}
if let Some(quic_proxy) = self.quic_proxy_dst.as_ref() {
tcp_proxy_rpc_services.insert(
"quic_dst".to_string(),
Arc::new(QUICProxyDstRpcService::new(quic_proxy)),
);
}
tcp_proxy_rpc_services
},
acl_manage_rpc_service: PeerManagerRpcService::new(self.peer_manager.clone()),
port_forward_manage_rpc_service: self.get_port_forward_manager_rpc_service(),
stats_rpc_service: self.get_stats_rpc_service(),
config_rpc_service: self.get_config_service(),
}
if let Some(quic_proxy) = self.quic_proxy_dst.as_ref() {
s.registry().register(
TcpProxyRpcServer::new(QUICProxyDstRpcService::new(quic_proxy)),
"quic_dst",
);
}
s.set_hook(Arc::new(InstanceRpcServerHook::new(
self.global_ctx.config.get_rpc_portal_whitelist(),
)));
let _g = self.global_ctx.net_ns.guard();
Ok(s.serve().await.with_context(|| "rpc server start failed")?)
}
pub fn get_global_ctx(&self) -> ArcGlobalCtx {
@@ -1328,9 +1408,6 @@ impl Instance {
pub async fn clear_resources(&mut self) {
self.peer_manager.clear_resources().await;
let _ = self.nic_ctx.lock().await.take();
if let Some(rpc_server) = self.rpc_server.take() {
rpc_server.registry().unregister_all();
};
}
}
@@ -1339,9 +1416,6 @@ impl Drop for Instance {
let my_peer_id = self.peer_manager.my_peer_id();
let pm = Arc::downgrade(&self.peer_manager);
let nic_ctx = self.nic_ctx.clone();
if let Some(rpc_server) = self.rpc_server.take() {
rpc_server.registry().unregister_all();
};
tokio::spawn(async move {
nic_ctx.lock().await.take();
if let Some(pm) = pm.upgrade() {

View File

@@ -6,5 +6,3 @@ pub mod listeners;
#[cfg(feature = "tun")]
pub mod virtual_nic;
pub mod logger_rpc_service;

View File

@@ -9,7 +9,8 @@ use crate::{
scoped_task::ScopedTask,
},
launcher::{ConfigSource, NetworkInstance, NetworkInstanceRunningInfo},
proto,
proto::{self},
rpc_service::InstanceRpcService,
};
pub struct NetworkInstanceManager {
@@ -150,6 +151,26 @@ impl NetworkInstanceManager {
.map(|instance| instance.value().get_inst_name())
}
pub fn filter_network_instance(
&self,
filter: impl Fn(&uuid::Uuid, &NetworkInstance) -> bool,
) -> Vec<uuid::Uuid> {
self.instance_map
.iter()
.filter(|item| filter(item.key(), item.value()))
.map(|item| *item.key())
.collect()
}
pub fn get_instance_service(
&self,
instance_id: &uuid::Uuid,
) -> Option<Arc<dyn InstanceRpcService>> {
self.instance_map
.get(instance_id)
.and_then(|instance| instance.value().get_api_service())
}
pub fn set_tun_fd(&self, instance_id: &uuid::Uuid, fd: i32) -> Result<(), anyhow::Error> {
let mut instance = self
.instance_map
@@ -340,7 +361,7 @@ fn print_event(instance_id: uuid::Uuid, msg: String) {
);
}
fn peer_conn_info_to_string(p: proto::cli::PeerConnInfo) -> String {
fn peer_conn_info_to_string(p: proto::api::instance::PeerConnInfo) -> String {
format!(
"my_peer_id: {}, dst_peer_id: {}, tunnel_info: {:?}",
p.my_peer_id, p.peer_id, p.tunnel

View File

@@ -1,6 +1,7 @@
use crate::common::config::PortForwardConfig;
use crate::proto::api::manage;
use crate::proto::peer_rpc::RouteForeignNetworkSummary;
use crate::proto::web;
use crate::rpc_service::InstanceRpcService;
use crate::{
common::{
config::{
@@ -13,7 +14,7 @@ use crate::{
},
instance::instance::Instance,
peers::rpc_service::PeerManagerRpcService,
proto::cli::{list_peer_route_pair, PeerInfo, Route},
proto::api::instance::{list_peer_route_pair, PeerInfo, Route},
};
use anyhow::Context;
use chrono::{DateTime, Local};
@@ -24,7 +25,9 @@ use std::{
};
use tokio::{sync::broadcast, task::JoinSet};
pub type MyNodeInfo = crate::proto::web::MyNodeInfo;
pub type MyNodeInfo = crate::proto::api::manage::MyNodeInfo;
type ArcMutApiService = Arc<RwLock<Option<Arc<dyn InstanceRpcService>>>>;
#[derive(serde::Serialize, Clone)]
pub struct Event {
@@ -65,6 +68,7 @@ pub struct EasyTierLauncher {
instance_alive: Arc<AtomicBool>,
stop_flag: Arc<AtomicBool>,
thread_handle: Option<std::thread::JoinHandle<()>>,
api_service: ArcMutApiService,
running_cfg: String,
fetch_node_info: bool,
@@ -78,6 +82,7 @@ impl EasyTierLauncher {
Self {
instance_alive,
thread_handle: None,
api_service: Arc::new(RwLock::new(None)),
error_msg: Arc::new(RwLock::new(None)),
running_cfg: String::new(),
fetch_node_info,
@@ -136,12 +141,19 @@ impl EasyTierLauncher {
async fn easytier_routine(
cfg: TomlConfigLoader,
stop_signal: Arc<tokio::sync::Notify>,
api_service: ArcMutApiService,
data: Arc<EasyTierData>,
fetch_node_info: bool,
) -> Result<(), anyhow::Error> {
let mut instance = Instance::new(cfg);
let mut tasks = JoinSet::new();
api_service
.write()
.unwrap()
.replace(Arc::new(instance.get_api_rpc_service()));
drop(api_service);
// Subscribe to global context events
let global_ctx = instance.get_global_ctx();
let data_c = data.clone();
@@ -220,21 +232,6 @@ impl EasyTierLauncher {
Ok(())
}
fn select_proper_rpc_port(cfg: &TomlConfigLoader) {
let Some(mut f) = cfg.get_rpc_portal() else {
return;
};
if f.port() == 0 {
let Some(port) = crate::utils::find_free_tcp_port(15888..15900) else {
tracing::warn!("No free port found for RPC portal, skipping setting RPC portal");
return;
};
f.set_port(port);
cfg.set_rpc_portal(f);
}
}
pub fn start<F>(&mut self, cfg_generator: F)
where
F: FnOnce() -> Result<TomlConfigLoader, anyhow::Error> + Send + Sync,
@@ -250,8 +247,6 @@ impl EasyTierLauncher {
self.running_cfg = cfg.dump();
Self::select_proper_rpc_port(&cfg);
let stop_flag = self.stop_flag.clone();
let instance_alive = self.instance_alive.clone();
@@ -259,6 +254,7 @@ impl EasyTierLauncher {
let data = self.data.clone();
let fetch_node_info = self.fetch_node_info;
let api_service = self.api_service.clone();
self.thread_handle = Some(std::thread::spawn(move || {
let rt = if cfg.get_flags().multi_thread {
@@ -288,6 +284,7 @@ impl EasyTierLauncher {
let ret = rt.block_on(Self::easytier_routine(
cfg,
stop_notifier.clone(),
api_service,
data,
fetch_node_info,
));
@@ -332,6 +329,16 @@ impl EasyTierLauncher {
pub fn get_foreign_network_summary(&self) -> RouteForeignNetworkSummary {
self.data.foreign_network_summary.read().unwrap().clone()
}
pub fn get_api_service(&self) -> Option<Arc<dyn InstanceRpcService>> {
match self.api_service.read() {
Ok(guard) => guard.clone(),
Err(e) => {
tracing::error!("Failed to acquire read lock for api_service: {:?}", e);
None
}
}
}
}
impl Drop for EasyTierLauncher {
@@ -346,7 +353,7 @@ impl Drop for EasyTierLauncher {
}
}
pub type NetworkInstanceRunningInfo = crate::proto::web::NetworkInstanceRunningInfo;
pub type NetworkInstanceRunningInfo = crate::proto::api::manage::NetworkInstanceRunningInfo;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConfigSource {
@@ -460,6 +467,12 @@ impl NetworkInstance {
None
}
}
pub fn get_api_service(&self) -> Option<Arc<dyn InstanceRpcService>> {
self.launcher
.as_ref()
.and_then(|launcher| launcher.get_api_service())
}
}
pub fn add_proxy_network_to_config(
@@ -492,8 +505,8 @@ pub fn add_proxy_network_to_config(
Ok(())
}
pub type NetworkingMethod = crate::proto::web::NetworkingMethod;
pub type NetworkConfig = crate::proto::web::NetworkConfig;
pub type NetworkingMethod = crate::proto::api::manage::NetworkingMethod;
pub type NetworkConfig = crate::proto::api::manage::NetworkConfig;
impl NetworkConfig {
pub fn gen_config(&self) -> Result<TomlConfigLoader, anyhow::Error> {
@@ -574,26 +587,6 @@ impl NetworkConfig {
add_proxy_network_to_config(n, &cfg)?;
}
cfg.set_rpc_portal(
format!("0.0.0.0:{}", self.rpc_port.unwrap_or_default())
.parse()
.with_context(|| format!("failed to parse rpc portal port: {:?}", self.rpc_port))?,
);
if self.rpc_portal_whitelists.is_empty() {
cfg.set_rpc_portal_whitelist(None);
} else {
cfg.set_rpc_portal_whitelist(Some(
self.rpc_portal_whitelists
.iter()
.map(|s| {
s.parse()
.with_context(|| format!("failed to parse rpc portal whitelist: {}", s))
})
.collect::<Result<Vec<_>, _>>()?,
));
}
if !self.port_forwards.is_empty() {
cfg.set_port_forwards(
self.port_forwards
@@ -848,19 +841,11 @@ impl NetworkConfig {
})
.collect();
if let Some(rpc_portal) = config.get_rpc_portal() {
result.rpc_port = Some(rpc_portal.port() as i32);
}
if let Some(whitelist) = config.get_rpc_portal_whitelist() {
result.rpc_portal_whitelists = whitelist.iter().map(|w| w.to_string()).collect();
}
let port_forwards = config.get_port_forwards();
if !port_forwards.is_empty() {
result.port_forwards = port_forwards
.iter()
.map(|f| web::PortForwardConfig {
.map(|f| manage::PortForwardConfig {
proto: f.proto.clone(),
bind_ip: f.bind_addr.ip().to_string(),
bind_port: f.bind_addr.port() as u32,
@@ -949,7 +934,6 @@ mod tests {
config.set_dhcp(false);
config.set_inst_name("default".to_string());
config.set_listeners(vec![]);
config.set_rpc_portal(std::net::SocketAddr::from(([0, 0, 0, 0], 0)));
config
}
@@ -1061,27 +1045,6 @@ mod tests {
}
}
if rng.gen_bool(0.8) {
let port = rng.gen_range(0..65535);
config.set_rpc_portal(std::net::SocketAddr::from(([0, 0, 0, 0], port)));
if rng.gen_bool(0.6) {
let whitelist_count = rng.gen_range(1..3);
let mut whitelist = Vec::new();
for _ in 0..whitelist_count {
let ip = Ipv4Addr::new(
rng.gen_range(1..254),
rng.gen_range(0..255),
rng.gen_range(0..255),
rng.gen_range(0..255),
);
let cidr = format!("{}/32", ip);
whitelist.push(cidr.parse().unwrap());
}
config.set_rpc_portal_whitelist(Some(whitelist));
}
}
if rng.gen_bool(0.5) {
let vpn_network = format!(
"{}.{}.{}.0/{}",

View File

@@ -17,6 +17,7 @@ pub mod instance_manager;
pub mod launcher;
pub mod peers;
pub mod proto;
pub mod rpc_service;
pub mod tunnel;
pub mod utils;
pub mod web_client;

View File

@@ -39,7 +39,7 @@ pub trait PeerCenterPeerManagerTrait: Send + Sync + 'static {
fn my_peer_id(&self) -> PeerId;
fn get_global_ctx(&self) -> Arc<GlobalCtx>;
fn get_rpc_mgr(&self) -> Weak<PeerRpcManager>;
async fn list_routes(&self) -> Vec<crate::proto::cli::Route>;
async fn list_routes(&self) -> Vec<crate::proto::api::instance::Route>;
}
struct PeerCenterBase {
@@ -426,7 +426,7 @@ impl PeerCenterPeerManagerTrait for PeerManager {
Arc::downgrade(&self.get_peer_rpc_mgr())
}
async fn list_routes(&self) -> Vec<crate::proto::cli::Route> {
async fn list_routes(&self) -> Vec<crate::proto::api::instance::Route> {
self.list_routes().await
}
}
@@ -478,7 +478,7 @@ impl PeerCenterPeerManagerTrait for PeerMapWithPeerRpcManager {
Arc::downgrade(&self.rpc_mgr)
}
async fn list_routes(&self) -> Vec<crate::proto::cli::Route> {
async fn list_routes(&self) -> Vec<crate::proto::api::instance::Route> {
self.peer_map.list_route_infos().await
}
}

View File

@@ -7,7 +7,7 @@
use std::collections::BTreeMap;
use crate::proto::cli::PeerInfo;
use crate::proto::api::instance::PeerInfo;
use crate::proto::peer_rpc::{DirectConnectedPeerInfo, PeerInfoForGlobalMap};
pub mod instance;

View File

@@ -32,7 +32,7 @@ use crate::{
peer_center::instance::{PeerCenterInstance, PeerMapWithPeerRpcManager},
peers::route_trait::{Route, RouteInterface},
proto::{
cli::{ForeignNetworkEntryPb, ListForeignNetworkResponse, PeerInfo},
api::instance::{ForeignNetworkEntryPb, ListForeignNetworkResponse, PeerInfo},
common::LimiterConfig,
peer_rpc::DirectConnectorRpcServer,
},

View File

@@ -11,7 +11,7 @@ use super::{
peer_conn::{PeerConn, PeerConnId},
PacketRecvChan,
};
use crate::{common::scoped_task::ScopedTask, proto::cli::PeerConnInfo};
use crate::{common::scoped_task::ScopedTask, proto::api::instance::PeerConnInfo};
use crate::{
common::{
error::Error,

View File

@@ -32,7 +32,7 @@ use crate::{
PeerId,
},
proto::{
cli::{PeerConnInfo, PeerConnStats},
api::instance::{PeerConnInfo, PeerConnStats},
common::TunnelInfo,
peer_rpc::HandshakeRequest,
},

View File

@@ -36,7 +36,7 @@ use crate::{
PeerPacketFilter,
},
proto::{
cli::{
api::instance::{
self, list_global_foreign_network_response::OneForeignNetwork,
ListGlobalForeignNetworkResponse,
},
@@ -920,7 +920,7 @@ impl PeerManager {
}
}
pub async fn list_routes(&self) -> Vec<cli::Route> {
pub async fn list_routes(&self) -> Vec<instance::Route> {
self.get_route().list_routes().await
}
@@ -1305,8 +1305,8 @@ impl PeerManager {
self.foreign_network_client.clone()
}
pub async fn get_my_info(&self) -> cli::NodeInfo {
cli::NodeInfo {
pub async fn get_my_info(&self) -> instance::NodeInfo {
instance::NodeInfo {
peer_id: self.my_peer_id,
ipv4_addr: self
.global_ctx

View File

@@ -14,7 +14,7 @@ use crate::{
PeerId,
},
proto::{
cli::{self, PeerConnInfo},
api::instance::{self, PeerConnInfo},
peer_rpc::RoutePeerInfo,
},
tunnel::{packet_def::ZCPacket, TunnelError},
@@ -336,7 +336,7 @@ impl PeerMap {
route_map
}
pub async fn list_route_infos(&self) -> Vec<cli::Route> {
pub async fn list_route_infos(&self) -> Vec<instance::Route> {
if let Some(route) = self.routes.read().await.iter().next() {
return route.list_routes().await;
}

View File

@@ -193,7 +193,7 @@ impl RoutePeerInfo {
}
}
impl From<RoutePeerInfo> for crate::proto::cli::Route {
impl From<RoutePeerInfo> for crate::proto::api::instance::Route {
fn from(val: RoutePeerInfo) -> Self {
let network_length = if val.network_length == 0 {
24
@@ -201,7 +201,7 @@ impl From<RoutePeerInfo> for crate::proto::cli::Route {
val.network_length
};
crate::proto::cli::Route {
crate::proto::api::instance::Route {
peer_id: val.peer_id,
ipv4_addr: val.ipv4_addr.map(|ipv4_addr| Ipv4Inet {
address: Some(ipv4_addr),
@@ -2361,7 +2361,7 @@ impl Route for PeerRoute {
.map(|x| x.next_hop_peer_id)
}
async fn list_routes(&self) -> Vec<crate::proto::cli::Route> {
async fn list_routes(&self) -> Vec<crate::proto::api::instance::Route> {
let route_table = &self.service_impl.route_table;
let route_table_with_cost = &self.service_impl.route_table_with_cost;
let mut routes = Vec::new();
@@ -2373,7 +2373,7 @@ impl Route for PeerRoute {
continue;
};
let next_hop_peer_latency_first = route_table_with_cost.get_next_hop(*item.key());
let mut route: crate::proto::cli::Route = item.value().clone().into();
let mut route: crate::proto::api::instance::Route = item.value().clone().into();
route.next_hop_peer_id = next_hop_peer.next_hop_peer_id;
route.cost = next_hop_peer.path_len as i32;
route.path_latency = next_hop_peer.path_latency;

View File

@@ -74,7 +74,7 @@ pub trait Route {
self.get_next_hop(peer_id).await
}
async fn list_routes(&self) -> Vec<crate::proto::cli::Route>;
async fn list_routes(&self) -> Vec<crate::proto::api::instance::Route>;
async fn get_peer_id_by_ipv4(&self, _ipv4: &Ipv4Addr) -> Option<PeerId> {
None
@@ -161,7 +161,7 @@ impl Route for MockRoute {
panic!("mock route")
}
async fn list_routes(&self) -> Vec<crate::proto::cli::Route> {
async fn list_routes(&self) -> Vec<crate::proto::api::instance::Route> {
panic!("mock route")
}

View File

@@ -1,26 +1,34 @@
use std::sync::Arc;
use std::{
ops::Deref,
sync::{Arc, Weak},
};
use crate::proto::{
cli::{
AclManageRpc, DumpRouteRequest, DumpRouteResponse, GetAclStatsRequest, GetAclStatsResponse,
GetWhitelistRequest, GetWhitelistResponse, ListForeignNetworkRequest,
ListForeignNetworkResponse, ListGlobalForeignNetworkRequest,
ListGlobalForeignNetworkResponse, ListPeerRequest, ListPeerResponse, ListRouteRequest,
ListRouteResponse, PeerInfo, PeerManageRpc, ShowNodeInfoRequest, ShowNodeInfoResponse,
use crate::{
proto::{
api::instance::{
AclManageRpc, DumpRouteRequest, DumpRouteResponse, GetAclStatsRequest,
GetAclStatsResponse, GetWhitelistRequest, GetWhitelistResponse,
ListForeignNetworkRequest, ListForeignNetworkResponse, ListGlobalForeignNetworkRequest,
ListGlobalForeignNetworkResponse, ListPeerRequest, ListPeerResponse, ListRouteRequest,
ListRouteResponse, PeerInfo, PeerManageRpc, ShowNodeInfoRequest, ShowNodeInfoResponse,
},
rpc_types::{self, controller::BaseController},
},
rpc_types::{self, controller::BaseController},
utils::weak_upgrade,
};
use super::peer_manager::PeerManager;
#[derive(Clone)]
pub struct PeerManagerRpcService {
peer_manager: Arc<PeerManager>,
peer_manager: Weak<PeerManager>,
}
impl PeerManagerRpcService {
pub fn new(peer_manager: Arc<PeerManager>) -> Self {
PeerManagerRpcService { peer_manager }
PeerManagerRpcService {
peer_manager: Arc::downgrade(&peer_manager),
}
}
pub async fn list_peers(peer_manager: &PeerManager) -> Vec<PeerInfo> {
@@ -78,7 +86,8 @@ impl PeerManageRpc for PeerManagerRpcService {
) -> Result<ListPeerResponse, rpc_types::error::Error> {
let mut reply = ListPeerResponse::default();
let peers = PeerManagerRpcService::list_peers(&self.peer_manager).await;
let peers =
PeerManagerRpcService::list_peers(weak_upgrade(&self.peer_manager)?.deref()).await;
for peer in peers {
reply.peer_infos.push(peer);
}
@@ -92,7 +101,7 @@ impl PeerManageRpc for PeerManagerRpcService {
_request: ListRouteRequest, // Accept request of type HelloRequest
) -> Result<ListRouteResponse, rpc_types::error::Error> {
let reply = ListRouteResponse {
routes: self.peer_manager.list_routes().await,
routes: weak_upgrade(&self.peer_manager)?.list_routes().await,
};
Ok(reply)
}
@@ -103,7 +112,7 @@ impl PeerManageRpc for PeerManagerRpcService {
_request: DumpRouteRequest, // Accept request of type HelloRequest
) -> Result<DumpRouteResponse, rpc_types::error::Error> {
let reply = DumpRouteResponse {
result: self.peer_manager.dump_route().await,
result: weak_upgrade(&self.peer_manager)?.dump_route().await,
};
Ok(reply)
}
@@ -113,8 +122,7 @@ impl PeerManageRpc for PeerManagerRpcService {
_: BaseController,
_request: ListForeignNetworkRequest, // Accept request of type HelloRequest
) -> Result<ListForeignNetworkResponse, rpc_types::error::Error> {
let reply = self
.peer_manager
let reply = weak_upgrade(&self.peer_manager)?
.get_foreign_network_manager()
.list_foreign_networks()
.await;
@@ -126,7 +134,9 @@ impl PeerManageRpc for PeerManagerRpcService {
_: BaseController,
_request: ListGlobalForeignNetworkRequest,
) -> Result<ListGlobalForeignNetworkResponse, rpc_types::error::Error> {
Ok(self.peer_manager.list_global_foreign_network().await)
Ok(weak_upgrade(&self.peer_manager)?
.list_global_foreign_network()
.await)
}
async fn show_node_info(
@@ -135,7 +145,7 @@ impl PeerManageRpc for PeerManagerRpcService {
_request: ShowNodeInfoRequest, // Accept request of type HelloRequest
) -> Result<ShowNodeInfoResponse, rpc_types::error::Error> {
Ok(ShowNodeInfoResponse {
node_info: Some(self.peer_manager.get_my_info().await),
node_info: Some(weak_upgrade(&self.peer_manager)?.get_my_info().await),
})
}
}
@@ -149,8 +159,7 @@ impl AclManageRpc for PeerManagerRpcService {
_: BaseController,
_request: GetAclStatsRequest,
) -> Result<GetAclStatsResponse, rpc_types::error::Error> {
let acl_stats = self
.peer_manager
let acl_stats = weak_upgrade(&self.peer_manager)?
.get_global_ctx()
.get_acl_filter()
.get_stats();
@@ -164,7 +173,7 @@ impl AclManageRpc for PeerManagerRpcService {
_: BaseController,
_request: GetWhitelistRequest,
) -> Result<GetWhitelistResponse, rpc_types::error::Error> {
let global_ctx = self.peer_manager.get_global_ctx();
let global_ctx = weak_upgrade(&self.peer_manager)?.get_global_ctx();
let tcp_ports = global_ctx.config.get_tcp_whitelist();
let udp_ports = global_ctx.config.get_udp_whitelist();
tracing::info!(

262
easytier/src/proto/api.rs Normal file
View File

@@ -0,0 +1,262 @@
pub mod config {
include!(concat!(env!("OUT_DIR"), "/api.config.rs"));
pub struct Patchable<T> {
pub action: Option<ConfigPatchAction>,
pub value: Option<T>,
}
impl From<PortForwardPatch> for Patchable<crate::common::config::PortForwardConfig> {
fn from(patch: PortForwardPatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(patch.action).ok(),
value: patch.cfg.map(Into::into),
}
}
}
impl From<RoutePatch> for Patchable<cidr::Ipv4Cidr> {
fn from(value: RoutePatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: value.cidr.map(Into::into),
}
}
}
impl From<ExitNodePatch> for Patchable<std::net::IpAddr> {
fn from(value: ExitNodePatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: value.node.map(Into::into),
}
}
}
impl From<StringPatch> for Patchable<String> {
fn from(value: StringPatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: Some(value.value),
}
}
}
impl From<UrlPatch> for Patchable<url::Url> {
fn from(value: UrlPatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: value.url.map(Into::into),
}
}
}
pub fn patch_vec<T>(v: &mut Vec<T>, patches: Vec<Patchable<T>>)
where
T: PartialEq,
{
for patch in patches {
match patch.action {
Some(ConfigPatchAction::Add) => {
if let Some(value) = patch.value {
v.push(value);
}
}
Some(ConfigPatchAction::Remove) => {
if let Some(value) = patch.value {
v.retain(|x| x != &value);
}
}
Some(ConfigPatchAction::Clear) => {
v.clear();
}
None => {}
}
}
}
}
pub mod instance {
include!(concat!(env!("OUT_DIR"), "/api.instance.rs"));
impl PeerRoutePair {
pub fn get_latency_ms(&self) -> Option<f64> {
let mut ret = u64::MAX;
let p = self.peer.as_ref()?;
let default_conn_id = p.default_conn_id.map(|id| id.to_string());
for conn in p.conns.iter() {
let Some(stats) = &conn.stats else {
continue;
};
if default_conn_id == Some(conn.conn_id.to_string()) {
return Some(f64::from(stats.latency_us as u32) / 1000.0);
}
ret = ret.min(stats.latency_us);
}
if ret == u64::MAX {
None
} else {
Some(f64::from(ret as u32) / 1000.0)
}
}
pub fn get_rx_bytes(&self) -> Option<u64> {
let mut ret = 0;
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
let Some(stats) = &conn.stats else {
continue;
};
ret += stats.rx_bytes;
}
if ret == 0 {
None
} else {
Some(ret)
}
}
pub fn get_tx_bytes(&self) -> Option<u64> {
let mut ret = 0;
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
let Some(stats) = &conn.stats else {
continue;
};
ret += stats.tx_bytes;
}
if ret == 0 {
None
} else {
Some(ret)
}
}
pub fn get_loss_rate(&self) -> Option<f64> {
let mut ret = 0.0;
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
ret += conn.loss_rate;
}
if ret == 0.0 {
None
} else {
Some(ret as f64)
}
}
fn is_tunnel_ipv6(tunnel_info: &super::super::common::TunnelInfo) -> bool {
let Some(local_addr) = &tunnel_info.local_addr else {
return false;
};
let u: url::Url = local_addr.clone().into();
u.host()
.map(|h| matches!(h, url::Host::Ipv6(_)))
.unwrap_or(false)
}
fn get_tunnel_proto_str(tunnel_info: &super::super::common::TunnelInfo) -> String {
if Self::is_tunnel_ipv6(tunnel_info) {
format!("{}6", tunnel_info.tunnel_type)
} else {
tunnel_info.tunnel_type.clone()
}
}
pub fn get_conn_protos(&self) -> Option<Vec<String>> {
let mut ret = vec![];
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
let Some(tunnel_info) = &conn.tunnel else {
continue;
};
// insert if not exists
let tunnel_type = Self::get_tunnel_proto_str(tunnel_info);
if !ret.contains(&tunnel_type) {
ret.push(tunnel_type);
}
}
if ret.is_empty() {
None
} else {
Some(ret)
}
}
pub fn get_udp_nat_type(&self) -> String {
use crate::proto::common::NatType;
let mut ret = NatType::Unknown;
if let Some(r) = &self.route.clone().unwrap_or_default().stun_info {
ret = NatType::try_from(r.udp_nat_type).unwrap();
}
format!("{:?}", ret)
}
}
pub fn list_peer_route_pair(peers: Vec<PeerInfo>, routes: Vec<Route>) -> Vec<PeerRoutePair> {
let mut pairs: Vec<PeerRoutePair> = vec![];
for route in routes.iter() {
let peer = peers.iter().find(|peer| peer.peer_id == route.peer_id);
let pair = PeerRoutePair {
route: Some(route.clone()),
peer: peer.cloned(),
};
pairs.push(pair);
}
pairs.sort_by(|a, b| {
let a_is_public_server = a
.route
.as_ref()
.and_then(|r| r.feature_flag.as_ref())
.is_some_and(|f| f.is_public_server);
let b_is_public_server = b
.route
.as_ref()
.and_then(|r| r.feature_flag.as_ref())
.is_some_and(|f| f.is_public_server);
if a_is_public_server != b_is_public_server {
return if a_is_public_server {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
};
}
let a_ip = a
.route
.as_ref()
.and_then(|r| r.ipv4_addr.as_ref())
.and_then(|ipv4| ipv4.address.as_ref())
.map_or(0, |addr| addr.addr);
let b_ip = b
.route
.as_ref()
.and_then(|r| r.ipv4_addr.as_ref())
.and_then(|ipv4| ipv4.address.as_ref())
.map_or(0, |addr| addr.addr);
a_ip.cmp(&b_ip)
});
pairs
}
}
pub mod logger {
include!(concat!(env!("OUT_DIR"), "/api.logger.rs"));
}
pub mod manage {
include!(concat!(env!("OUT_DIR"), "/api.manage.rs"));
}

View File

@@ -2,8 +2,9 @@ syntax = "proto3";
import "common.proto";
import "acl.proto";
import "api_instance.proto";
package config;
package api.config;
enum ConfigPatchAction {
ADD = 0;
@@ -21,6 +22,7 @@ message InstanceConfigPatch {
repeated RoutePatch routes = 7;
repeated ExitNodePatch exit_nodes = 8;
repeated UrlPatch mapped_listeners = 9;
repeated UrlPatch connectors = 10;
}
message PortForwardPatch {
@@ -60,6 +62,13 @@ message ExitNodePatch {
common.IpAddr node = 2;
}
message PatchConfigRequest { InstanceConfigPatch patch = 1; }
message PatchConfigRequest {
InstanceConfigPatch patch = 1;
api.instance.InstanceIdentifier instance = 2;
}
service ConfigRpc { rpc PatchConfig(PatchConfigRequest) returns (common.Void); }
message PatchConfigResponse {}
service ConfigRpc {
rpc PatchConfig(PatchConfigRequest) returns (PatchConfigResponse);
}

View File

@@ -4,7 +4,16 @@ import "common.proto";
import "peer_rpc.proto";
import "acl.proto";
package cli;
package api.instance;
message InstanceIdentifier {
message InstanceSelector { optional string name = 1; }
oneof selector {
common.UUID id = 1;
InstanceSelector instance_selector = 2;
}
}
message Status {
int32 code = 1;
@@ -41,7 +50,7 @@ message PeerInfo {
repeated common.UUID directly_connected_conns = 4;
}
message ListPeerRequest {}
message ListPeerRequest { InstanceIdentifier instance = 1; }
message ListPeerResponse {
repeated PeerInfo peer_infos = 1;
@@ -89,19 +98,19 @@ message NodeInfo {
peer_rpc.GetIpListResponse ip_list = 11;
}
message ShowNodeInfoRequest {}
message ShowNodeInfoRequest { InstanceIdentifier instance = 1; }
message ShowNodeInfoResponse { NodeInfo node_info = 1; }
message ListRouteRequest {}
message ListRouteRequest { InstanceIdentifier instance = 1; }
message ListRouteResponse { repeated Route routes = 1; }
message DumpRouteRequest {}
message DumpRouteRequest { InstanceIdentifier instance = 1; }
message DumpRouteResponse { string result = 1; }
message ListForeignNetworkRequest {}
message ListForeignNetworkRequest { InstanceIdentifier instance = 1; }
message ForeignNetworkEntryPb {
repeated PeerInfo peers = 1;
@@ -114,7 +123,7 @@ message ListForeignNetworkResponse {
map<string, ForeignNetworkEntryPb> foreign_networks = 1;
}
message ListGlobalForeignNetworkRequest {}
message ListGlobalForeignNetworkRequest { InstanceIdentifier instance = 1; }
message ListGlobalForeignNetworkResponse {
// foreign network in the entire network
@@ -152,37 +161,25 @@ message Connector {
ConnectorStatus status = 2;
}
message ListConnectorRequest {}
message ListConnectorRequest { InstanceIdentifier instance = 1; }
message ListConnectorResponse { repeated Connector connectors = 1; }
enum ConnectorManageAction {
ADD = 0;
REMOVE = 1;
}
message ManageConnectorRequest {
ConnectorManageAction action = 1;
common.Url url = 2;
}
message ManageConnectorResponse {}
service ConnectorManageRpc {
rpc ListConnector(ListConnectorRequest) returns (ListConnectorResponse);
rpc ManageConnector(ManageConnectorRequest) returns (ManageConnectorResponse);
}
message MappedListener {
common.Url url = 1;
message MappedListener { common.Url url = 1; }
message ListMappedListenerRequest { InstanceIdentifier instance = 1; }
message ListMappedListenerResponse {
repeated MappedListener mappedlisteners = 1;
}
message ListMappedListenerRequest {}
message ListMappedListenerResponse { repeated MappedListener mappedlisteners = 1; }
service MappedListenerManageRpc {
rpc ListMappedListener(ListMappedListenerRequest) returns (ListMappedListenerResponse);
rpc ListMappedListener(ListMappedListenerRequest)
returns (ListMappedListenerResponse);
}
message VpnPortalInfo {
@@ -191,7 +188,7 @@ message VpnPortalInfo {
repeated string connected_clients = 3;
}
message GetVpnPortalInfoRequest {}
message GetVpnPortalInfoRequest { InstanceIdentifier instance = 1; }
message GetVpnPortalInfoResponse { VpnPortalInfo vpn_portal_info = 1; }
service VpnPortalRpc {
@@ -206,19 +203,19 @@ enum TcpProxyEntryTransportType {
}
enum TcpProxyEntryState {
Unknown = 0;
// receive syn packet but not start connecting to dst
SynReceived = 1;
// connecting to dst
ConnectingDst = 2;
// connected to dst
Connected = 3;
// connection closed
Closed = 4;
// closing src
ClosingSrc = 5;
// closing dst
ClosingDst = 6;
Unknown = 0;
// receive syn packet but not start connecting to dst
SynReceived = 1;
// connecting to dst
ConnectingDst = 2;
// connected to dst
Connected = 3;
// connection closed
Closed = 4;
// closing src
ClosingSrc = 5;
// closing dst
ClosingDst = 6;
}
message TcpProxyEntry {
@@ -229,36 +226,32 @@ message TcpProxyEntry {
TcpProxyEntryTransportType transport_type = 5;
}
message ListTcpProxyEntryRequest {}
message ListTcpProxyEntryRequest { InstanceIdentifier instance = 1; }
message ListTcpProxyEntryResponse {
repeated TcpProxyEntry entries = 1;
}
message ListTcpProxyEntryResponse { repeated TcpProxyEntry entries = 1; }
service TcpProxyRpc {
rpc ListTcpProxyEntry(ListTcpProxyEntryRequest)
returns (ListTcpProxyEntryResponse);
}
message GetAclStatsRequest {}
message GetAclStatsRequest { InstanceIdentifier instance = 1; }
message GetAclStatsResponse {
acl.AclStats acl_stats = 1;
}
message GetAclStatsResponse { acl.AclStats acl_stats = 1; }
service AclManageRpc {
rpc GetAclStats(GetAclStatsRequest) returns (GetAclStatsResponse);
rpc GetWhitelist(GetWhitelistRequest) returns (GetWhitelistResponse);
}
message GetWhitelistRequest {}
message GetWhitelistRequest { InstanceIdentifier instance = 1; }
message GetWhitelistResponse {
repeated string tcp_ports = 1;
repeated string udp_ports = 2;
}
message ListPortForwardRequest {}
message ListPortForwardRequest { InstanceIdentifier instance = 1; }
message ListPortForwardResponse {
repeated common.PortForwardConfigPb cfgs = 1;
@@ -274,47 +267,16 @@ message MetricSnapshot {
map<string, string> labels = 3;
}
message GetStatsRequest {}
message GetStatsRequest { InstanceIdentifier instance = 1; }
message GetStatsResponse {
repeated MetricSnapshot metrics = 1;
}
message GetStatsResponse { repeated MetricSnapshot metrics = 1; }
message GetPrometheusStatsRequest {}
message GetPrometheusStatsRequest { InstanceIdentifier instance = 1; }
message GetPrometheusStatsResponse {
string prometheus_text = 1;
}
message GetPrometheusStatsResponse { string prometheus_text = 1; }
service StatsRpc {
rpc GetStats(GetStatsRequest) returns (GetStatsResponse);
rpc GetPrometheusStats(GetPrometheusStatsRequest) returns (GetPrometheusStatsResponse);
}
enum LogLevel {
DISABLED = 0;
ERROR = 1;
WARNING = 2;
INFO = 3;
DEBUG = 4;
TRACE = 5;
}
message SetLoggerConfigRequest {
LogLevel level = 1;
}
message SetLoggerConfigResponse {
}
message GetLoggerConfigRequest {
}
message GetLoggerConfigResponse {
LogLevel level = 1;
}
service LoggerRpc {
rpc SetLoggerConfig(SetLoggerConfigRequest) returns (SetLoggerConfigResponse);
rpc GetLoggerConfig(GetLoggerConfigRequest) returns (GetLoggerConfigResponse);
rpc GetPrometheusStats(GetPrometheusStatsRequest)
returns (GetPrometheusStatsResponse);
}

View File

@@ -0,0 +1,24 @@
syntax = "proto3";
package api.logger;
enum LogLevel {
DISABLED = 0;
ERROR = 1;
WARNING = 2;
INFO = 3;
DEBUG = 4;
TRACE = 5;
}
message SetLoggerConfigRequest { LogLevel level = 1; }
message SetLoggerConfigResponse {}
message GetLoggerConfigRequest {}
message GetLoggerConfigResponse { LogLevel level = 1; }
service LoggerRpc {
rpc SetLoggerConfig(SetLoggerConfigRequest) returns (SetLoggerConfigResponse);
rpc GetLoggerConfig(GetLoggerConfigRequest) returns (GetLoggerConfigResponse);
}

View File

@@ -0,0 +1,157 @@
syntax = "proto3";
import "common.proto";
import "peer_rpc.proto";
import "api_instance.proto";
package api.manage;
enum NetworkingMethod {
PublicServer = 0;
Manual = 1;
Standalone = 2;
}
message NetworkConfig {
optional string instance_id = 1;
optional bool dhcp = 2;
optional string virtual_ipv4 = 3;
optional int32 network_length = 4;
optional string hostname = 5;
optional string network_name = 6;
optional string network_secret = 7;
optional NetworkingMethod networking_method = 8;
optional string public_server_url = 9;
repeated string peer_urls = 10;
repeated string proxy_cidrs = 11;
optional bool enable_vpn_portal = 12;
optional int32 vpn_portal_listen_port = 13;
optional string vpn_portal_client_network_addr = 14;
optional int32 vpn_portal_client_network_len = 15;
optional bool advanced_settings = 16;
repeated string listener_urls = 17;
// optional int32 rpc_port = 18;
optional bool latency_first = 19;
optional string dev_name = 20;
optional bool use_smoltcp = 21;
optional bool disable_ipv6 = 47;
optional bool enable_kcp_proxy = 22;
optional bool disable_kcp_input = 23;
optional bool disable_p2p = 24;
optional bool bind_device = 25;
optional bool no_tun = 26;
optional bool enable_exit_node = 27;
optional bool relay_all_peer_rpc = 28;
optional bool multi_thread = 29;
optional bool enable_relay_network_whitelist = 30;
repeated string relay_network_whitelist = 31;
optional bool enable_manual_routes = 32;
repeated string routes = 33;
repeated string exit_nodes = 34;
optional bool proxy_forward_by_system = 35;
optional bool disable_encryption = 36;
optional bool enable_socks5 = 37;
optional int32 socks5_port = 38;
optional bool disable_udp_hole_punching = 39;
optional int32 mtu = 40;
repeated string mapped_listeners = 41;
optional bool enable_magic_dns = 42;
optional bool enable_private_mode = 43;
// repeated string rpc_portal_whitelists = 44;
optional bool enable_quic_proxy = 45;
optional bool disable_quic_input = 46;
repeated PortForwardConfig port_forwards = 48;
optional bool disable_sym_hole_punching = 49;
}
message PortForwardConfig {
string bind_ip = 1;
uint32 bind_port = 2;
string dst_ip = 3;
uint32 dst_port = 4;
string proto = 5;
}
message MyNodeInfo {
common.Ipv4Inet virtual_ipv4 = 1;
string hostname = 2;
string version = 3;
peer_rpc.GetIpListResponse ips = 4;
common.StunInfo stun_info = 5;
repeated common.Url listeners = 6;
optional string vpn_portal_cfg = 7;
}
message NetworkInstanceRunningInfo {
string dev_name = 1;
MyNodeInfo my_node_info = 2;
repeated string events = 3;
repeated api.instance.Route routes = 4;
repeated api.instance.PeerInfo peers = 5;
repeated api.instance.PeerRoutePair peer_route_pairs = 6;
bool running = 7;
optional string error_msg = 8;
peer_rpc.RouteForeignNetworkSummary foreign_network_summary = 9;
}
message NetworkInstanceRunningInfoMap {
map<string, NetworkInstanceRunningInfo> map = 1;
}
message ValidateConfigRequest { NetworkConfig config = 1; }
message ValidateConfigResponse { string toml_config = 1; }
message RunNetworkInstanceRequest {
common.UUID inst_id = 1;
NetworkConfig config = 2;
}
message RunNetworkInstanceResponse { common.UUID inst_id = 1; }
message RetainNetworkInstanceRequest { repeated common.UUID inst_ids = 1; }
message RetainNetworkInstanceResponse {
repeated common.UUID remain_inst_ids = 1;
}
message CollectNetworkInfoRequest { repeated common.UUID inst_ids = 1; }
message CollectNetworkInfoResponse { NetworkInstanceRunningInfoMap info = 1; }
message ListNetworkInstanceRequest {}
message ListNetworkInstanceResponse { repeated common.UUID inst_ids = 1; }
message DeleteNetworkInstanceRequest { repeated common.UUID inst_ids = 1; }
message DeleteNetworkInstanceResponse {
repeated common.UUID remain_inst_ids = 1;
}
service WebClientService {
rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {}
rpc RunNetworkInstance(RunNetworkInstanceRequest)
returns (RunNetworkInstanceResponse) {}
rpc RetainNetworkInstance(RetainNetworkInstanceRequest)
returns (RetainNetworkInstanceResponse) {}
rpc CollectNetworkInfo(CollectNetworkInfoRequest)
returns (CollectNetworkInfoResponse) {}
rpc ListNetworkInstance(ListNetworkInstanceRequest)
returns (ListNetworkInstanceResponse) {}
rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest)
returns (DeleteNetworkInstanceResponse) {}
}

View File

@@ -1,177 +0,0 @@
use url::Host;
include!(concat!(env!("OUT_DIR"), "/cli.rs"));
impl PeerRoutePair {
pub fn get_latency_ms(&self) -> Option<f64> {
let mut ret = u64::MAX;
let p = self.peer.as_ref()?;
let default_conn_id = p.default_conn_id.map(|id| id.to_string());
for conn in p.conns.iter() {
let Some(stats) = &conn.stats else {
continue;
};
if default_conn_id == Some(conn.conn_id.to_string()) {
return Some(f64::from(stats.latency_us as u32) / 1000.0);
}
ret = ret.min(stats.latency_us);
}
if ret == u64::MAX {
None
} else {
Some(f64::from(ret as u32) / 1000.0)
}
}
pub fn get_rx_bytes(&self) -> Option<u64> {
let mut ret = 0;
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
let Some(stats) = &conn.stats else {
continue;
};
ret += stats.rx_bytes;
}
if ret == 0 {
None
} else {
Some(ret)
}
}
pub fn get_tx_bytes(&self) -> Option<u64> {
let mut ret = 0;
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
let Some(stats) = &conn.stats else {
continue;
};
ret += stats.tx_bytes;
}
if ret == 0 {
None
} else {
Some(ret)
}
}
pub fn get_loss_rate(&self) -> Option<f64> {
let mut ret = 0.0;
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
ret += conn.loss_rate;
}
if ret == 0.0 {
None
} else {
Some(ret as f64)
}
}
fn is_tunnel_ipv6(tunnel_info: &super::common::TunnelInfo) -> bool {
let Some(local_addr) = &tunnel_info.local_addr else {
return false;
};
let u: url::Url = local_addr.clone().into();
u.host()
.map(|h| matches!(h, Host::Ipv6(_)))
.unwrap_or(false)
}
fn get_tunnel_proto_str(tunnel_info: &super::common::TunnelInfo) -> String {
if Self::is_tunnel_ipv6(tunnel_info) {
format!("{}6", tunnel_info.tunnel_type)
} else {
tunnel_info.tunnel_type.clone()
}
}
pub fn get_conn_protos(&self) -> Option<Vec<String>> {
let mut ret = vec![];
let p = self.peer.as_ref()?;
for conn in p.conns.iter() {
let Some(tunnel_info) = &conn.tunnel else {
continue;
};
// insert if not exists
let tunnel_type = Self::get_tunnel_proto_str(tunnel_info);
if !ret.contains(&tunnel_type) {
ret.push(tunnel_type);
}
}
if ret.is_empty() {
None
} else {
Some(ret)
}
}
pub fn get_udp_nat_type(&self) -> String {
use crate::proto::common::NatType;
let mut ret = NatType::Unknown;
if let Some(r) = &self.route.clone().unwrap_or_default().stun_info {
ret = NatType::try_from(r.udp_nat_type).unwrap();
}
format!("{:?}", ret)
}
}
pub fn list_peer_route_pair(peers: Vec<PeerInfo>, routes: Vec<Route>) -> Vec<PeerRoutePair> {
let mut pairs: Vec<PeerRoutePair> = vec![];
for route in routes.iter() {
let peer = peers.iter().find(|peer| peer.peer_id == route.peer_id);
let pair = PeerRoutePair {
route: Some(route.clone()),
peer: peer.cloned(),
};
pairs.push(pair);
}
pairs.sort_by(|a, b| {
let a_is_public_server = a
.route
.as_ref()
.and_then(|r| r.feature_flag.as_ref())
.is_some_and(|f| f.is_public_server);
let b_is_public_server = b
.route
.as_ref()
.and_then(|r| r.feature_flag.as_ref())
.is_some_and(|f| f.is_public_server);
if a_is_public_server != b_is_public_server {
return if a_is_public_server {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
};
}
let a_ip = a
.route
.as_ref()
.and_then(|r| r.ipv4_addr.as_ref())
.and_then(|ipv4| ipv4.address.as_ref())
.map_or(0, |addr| addr.addr);
let b_ip = b
.route
.as_ref()
.and_then(|r| r.ipv4_addr.as_ref())
.and_then(|ipv4| ipv4.address.as_ref())
.map_or(0, |addr| addr.addr);
a_ip.cmp(&b_ip)
});
pairs
}

View File

@@ -1,75 +0,0 @@
include!(concat!(env!("OUT_DIR"), "/config.rs"));
pub struct Patchable<T> {
pub action: Option<ConfigPatchAction>,
pub value: Option<T>,
}
impl From<PortForwardPatch> for Patchable<crate::common::config::PortForwardConfig> {
fn from(patch: PortForwardPatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(patch.action).ok(),
value: patch.cfg.map(Into::into),
}
}
}
impl From<RoutePatch> for Patchable<cidr::Ipv4Cidr> {
fn from(value: RoutePatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: value.cidr.map(Into::into),
}
}
}
impl From<ExitNodePatch> for Patchable<std::net::IpAddr> {
fn from(value: ExitNodePatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: value.node.map(Into::into),
}
}
}
impl From<StringPatch> for Patchable<String> {
fn from(value: StringPatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: Some(value.value),
}
}
}
impl From<UrlPatch> for Patchable<url::Url> {
fn from(value: UrlPatch) -> Self {
Patchable {
action: ConfigPatchAction::try_from(value.action).ok(),
value: value.url.map(Into::into),
}
}
}
pub fn patch_vec<T>(v: &mut Vec<T>, patches: Vec<Patchable<T>>)
where
T: PartialEq,
{
for patch in patches {
match patch.action {
Some(ConfigPatchAction::Add) => {
if let Some(value) = patch.value {
v.push(value);
}
}
Some(ConfigPatchAction::Remove) => {
if let Some(value) = patch.value {
v.retain(|x| x != &value);
}
}
Some(ConfigPatchAction::Clear) => {
v.clear();
}
None => {}
}
}
}

View File

@@ -2,7 +2,7 @@ syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "common.proto";
import "cli.proto";
import "api_instance.proto";
package magic_dns;
@@ -30,7 +30,7 @@ message DnsRecordList {
message UpdateDnsRecordRequest {
string zone = 1;
repeated cli.Route routes = 2;
repeated api.instance.Route routes = 2;
}
message GetDnsRecordResponse {

View File

@@ -2,9 +2,8 @@ pub mod rpc_impl;
pub mod rpc_types;
pub mod acl;
pub mod cli;
pub mod api;
pub mod common;
pub mod config;
pub mod error;
pub mod magic_dns;
pub mod peer_rpc;

View File

@@ -6,7 +6,7 @@ use thiserror;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("rust tun error {0}")]
#[error("Rust error: {0}")]
ExecutionError(#[from] anyhow::Error),
#[error("Decode error: {0}")]

View File

@@ -1,188 +1,23 @@
syntax = "proto3";
import "common.proto";
import "peer_rpc.proto";
import "cli.proto";
package web;
enum NetworkingMethod {
PublicServer = 0;
Manual = 1;
Standalone = 2;
}
message NetworkConfig {
optional string instance_id = 1;
optional bool dhcp = 2;
optional string virtual_ipv4 = 3;
optional int32 network_length = 4;
optional string hostname = 5;
optional string network_name = 6;
optional string network_secret = 7;
optional NetworkingMethod networking_method = 8;
optional string public_server_url = 9;
repeated string peer_urls = 10;
repeated string proxy_cidrs = 11;
optional bool enable_vpn_portal = 12;
optional int32 vpn_portal_listen_port = 13;
optional string vpn_portal_client_network_addr = 14;
optional int32 vpn_portal_client_network_len = 15;
optional bool advanced_settings = 16;
repeated string listener_urls = 17;
optional int32 rpc_port = 18;
optional bool latency_first = 19;
optional string dev_name = 20;
optional bool use_smoltcp = 21;
optional bool disable_ipv6 = 47;
optional bool enable_kcp_proxy = 22;
optional bool disable_kcp_input = 23;
optional bool disable_p2p = 24;
optional bool bind_device = 25;
optional bool no_tun = 26;
optional bool enable_exit_node = 27;
optional bool relay_all_peer_rpc = 28;
optional bool multi_thread = 29;
optional bool enable_relay_network_whitelist = 30;
repeated string relay_network_whitelist = 31;
optional bool enable_manual_routes = 32;
repeated string routes = 33;
repeated string exit_nodes = 34;
optional bool proxy_forward_by_system = 35;
optional bool disable_encryption = 36;
optional bool enable_socks5 = 37;
optional int32 socks5_port = 38;
optional bool disable_udp_hole_punching = 39;
optional int32 mtu = 40;
repeated string mapped_listeners = 41;
optional bool enable_magic_dns = 42;
optional bool enable_private_mode = 43;
repeated string rpc_portal_whitelists = 44;
optional bool enable_quic_proxy = 45;
optional bool disable_quic_input = 46;
repeated PortForwardConfig port_forwards = 48;
optional bool disable_sym_hole_punching = 49;
}
message PortForwardConfig {
string bind_ip = 1;
uint32 bind_port = 2;
string dst_ip = 3;
uint32 dst_port = 4;
string proto = 5;
}
message MyNodeInfo {
common.Ipv4Inet virtual_ipv4 = 1;
string hostname = 2;
string version = 3;
peer_rpc.GetIpListResponse ips = 4;
common.StunInfo stun_info = 5;
repeated common.Url listeners = 6;
optional string vpn_portal_cfg = 7;
}
message NetworkInstanceRunningInfo {
string dev_name = 1;
MyNodeInfo my_node_info = 2;
repeated string events = 3;
repeated cli.Route routes = 4;
repeated cli.PeerInfo peers = 5;
repeated cli.PeerRoutePair peer_route_pairs = 6;
bool running = 7;
optional string error_msg = 8;
peer_rpc.RouteForeignNetworkSummary foreign_network_summary = 9;
}
message NetworkInstanceRunningInfoMap {
map<string, NetworkInstanceRunningInfo> map = 1;
}
message HeartbeatRequest {
common.UUID machine_id = 1;
common.UUID inst_id = 2;
string user_token = 3;
common.UUID machine_id = 1;
common.UUID inst_id = 2;
string user_token = 3;
string easytier_version = 4;
string report_time = 5;
string hostname = 6;
string easytier_version = 4;
string report_time = 5;
string hostname = 6;
repeated common.UUID running_network_instances = 7;
repeated common.UUID running_network_instances = 7;
}
message HeartbeatResponse {
}
message HeartbeatResponse {}
service WebServerService {
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {}
}
message ValidateConfigRequest {
NetworkConfig config = 1;
}
message ValidateConfigResponse {
string toml_config = 1;
}
message RunNetworkInstanceRequest {
common.UUID inst_id = 1;
NetworkConfig config = 2;
}
message RunNetworkInstanceResponse {
common.UUID inst_id = 1;
}
message RetainNetworkInstanceRequest {
repeated common.UUID inst_ids = 1;
}
message RetainNetworkInstanceResponse {
repeated common.UUID remain_inst_ids = 1;
}
message CollectNetworkInfoRequest {
repeated common.UUID inst_ids = 1;
}
message CollectNetworkInfoResponse {
NetworkInstanceRunningInfoMap info = 1;
}
message ListNetworkInstanceRequest {
}
message ListNetworkInstanceResponse {
repeated common.UUID inst_ids = 1;
}
message DeleteNetworkInstanceRequest {
repeated common.UUID inst_ids = 1;
}
message DeleteNetworkInstanceResponse {
repeated common.UUID remain_inst_ids = 1;
}
service WebClientService {
rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {}
rpc RunNetworkInstance(RunNetworkInstanceRequest) returns (RunNetworkInstanceResponse) {}
rpc RetainNetworkInstance(RetainNetworkInstanceRequest) returns (RetainNetworkInstanceResponse) {}
rpc CollectNetworkInfo(CollectNetworkInfoRequest) returns (CollectNetworkInfoResponse) {}
rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {}
rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {}
}
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
}

View File

@@ -0,0 +1,50 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{
AclManageRpc, GetAclStatsRequest, GetAclStatsResponse, GetWhitelistRequest,
GetWhitelistResponse,
},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct AclManageRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl AclManageRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl AclManageRpc for AclManageRpcService {
type Controller = BaseController;
async fn get_acl_stats(
&self,
ctrl: Self::Controller,
req: GetAclStatsRequest,
) -> crate::proto::rpc_types::error::Result<GetAclStatsResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_acl_manage_service()
.get_acl_stats(ctrl, req)
.await
}
async fn get_whitelist(
&self,
ctrl: Self::Controller,
req: GetWhitelistRequest,
) -> crate::proto::rpc_types::error::Result<GetWhitelistResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_acl_manage_service()
.get_whitelist(ctrl, req)
.await
}
}

View File

@@ -0,0 +1,164 @@
use std::{net::SocketAddr, sync::Arc};
use anyhow::Context;
use cidr::IpCidr;
use crate::{
instance::instance::InstanceRpcServerHook,
instance_manager::NetworkInstanceManager,
proto::{
api::{
config::ConfigRpcServer,
instance::{
AclManageRpcServer, ConnectorManageRpcServer, MappedListenerManageRpcServer,
PeerManageRpcServer, PortForwardManageRpcServer, StatsRpcServer, TcpProxyRpcServer,
VpnPortalRpcServer,
},
logger::LoggerRpcServer,
manage::WebClientServiceServer,
},
rpc_impl::{service_registry::ServiceRegistry, standalone::StandAloneServer},
rpc_types::error::Error,
},
rpc_service::{
acl_manage::AclManageRpcService, config::ConfigRpcService,
connector_manage::ConnectorManageRpcService, instance_manage::InstanceManageRpcService,
logger::LoggerRpcService, mapped_listener_manage::MappedListenerManageRpcService,
peer_manage::PeerManageRpcService, port_forward_manage::PortForwardManageRpcService,
proxy::TcpProxyRpcService, stats::StatsRpcService, vpn_portal::VpnPortalRpcService,
},
tunnel::tcp::TcpTunnelListener,
};
pub struct ApiRpcServer {
rpc_server: StandAloneServer<TcpTunnelListener>,
}
impl ApiRpcServer {
pub fn new(
rpc_portal: Option<String>,
rpc_portal_whitelist: Option<Vec<IpCidr>>,
instance_manager: Arc<NetworkInstanceManager>,
) -> anyhow::Result<Self> {
let mut rpc_server = StandAloneServer::new(TcpTunnelListener::new(
format!("tcp://{}", parse_rpc_portal(rpc_portal)?)
.parse()
.context("failed to parse rpc portal address")?,
));
rpc_server.set_hook(Arc::new(InstanceRpcServerHook::new(rpc_portal_whitelist)));
register_api_rpc_service(&instance_manager, rpc_server.registry());
Ok(Self { rpc_server })
}
pub async fn serve(mut self) -> Result<Self, Error> {
self.rpc_server.serve().await?;
Ok(self)
}
}
impl Drop for ApiRpcServer {
fn drop(&mut self) {
self.rpc_server.registry().unregister_all();
}
}
fn register_api_rpc_service(
instance_manager: &Arc<NetworkInstanceManager>,
registry: &ServiceRegistry,
) {
registry.register(
PeerManageRpcServer::new(PeerManageRpcService::new(instance_manager.clone())),
"",
);
registry.register(
ConnectorManageRpcServer::new(ConnectorManageRpcService::new(instance_manager.clone())),
"",
);
registry.register(
MappedListenerManageRpcServer::new(MappedListenerManageRpcService::new(
instance_manager.clone(),
)),
"",
);
registry.register(
VpnPortalRpcServer::new(VpnPortalRpcService::new(instance_manager.clone())),
"",
);
for client_type in ["tcp", "kcp_src", "kcp_dst", "quic_src", "quic_dst"] {
registry.register(
TcpProxyRpcServer::new(TcpProxyRpcService::new(
instance_manager.clone(),
client_type,
)),
client_type,
);
}
registry.register(
AclManageRpcServer::new(AclManageRpcService::new(instance_manager.clone())),
"",
);
registry.register(
PortForwardManageRpcServer::new(PortForwardManageRpcService::new(instance_manager.clone())),
"",
);
registry.register(
StatsRpcServer::new(StatsRpcService::new(instance_manager.clone())),
"",
);
registry.register(LoggerRpcServer::new(LoggerRpcService), "");
registry.register(
ConfigRpcServer::new(ConfigRpcService::new(instance_manager.clone())),
"",
);
registry.register(
WebClientServiceServer::new(InstanceManageRpcService::new(instance_manager.clone())),
"",
);
}
fn parse_rpc_portal(rpc_portal: Option<String>) -> anyhow::Result<SocketAddr> {
if let Some(Ok(port)) = rpc_portal.as_ref().map(|s| s.parse::<u16>()) {
Ok(SocketAddr::from(([0, 0, 0, 0], port)))
} else {
let mut rpc_addr = rpc_portal
.map(|addr| {
addr.parse::<SocketAddr>()
.context("failed to parse rpc portal address")
})
.transpose()?;
select_proper_rpc_port(&mut rpc_addr)?;
rpc_addr.ok_or_else(|| anyhow::anyhow!("failed to parse rpc portal address"))
}
}
fn select_proper_rpc_port(addr: &mut Option<SocketAddr>) -> anyhow::Result<()> {
match addr {
None => {
*addr = Some(SocketAddr::from(([0, 0, 0, 0], 0)));
select_proper_rpc_port(addr)?;
Ok(())
}
Some(addr) => {
if addr.port() == 0 {
let Some(port) = crate::utils::find_free_tcp_port(15888..15900) else {
tracing::warn!(
"No free port found for RPC portal, skipping setting RPC portal"
);
return Err(anyhow::anyhow!("No free port found for RPC portal"));
};
addr.set_port(port);
}
Ok(())
}
}
}

View File

@@ -0,0 +1,36 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::config::{ConfigRpc, PatchConfigRequest, PatchConfigResponse},
rpc_types::{self, controller::BaseController},
},
};
#[derive(Clone)]
pub struct ConfigRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl ConfigRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl ConfigRpc for ConfigRpcService {
type Controller = BaseController;
async fn patch_config(
&self,
ctrl: Self::Controller,
input: PatchConfigRequest,
) -> Result<PatchConfigResponse, rpc_types::error::Error> {
super::get_instance_service(&self.instance_manager, &input.instance)?
.get_config_service()
.patch_config(ctrl, input)
.await
}
}

View File

@@ -0,0 +1,36 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{ConnectorManageRpc, ListConnectorRequest, ListConnectorResponse},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct ConnectorManageRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl ConnectorManageRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl ConnectorManageRpc for ConnectorManageRpcService {
type Controller = BaseController;
async fn list_connector(
&self,
ctrl: Self::Controller,
req: ListConnectorRequest,
) -> crate::proto::rpc_types::error::Result<ListConnectorResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_connector_manage_service()
.list_connector(ctrl, req)
.await
}
}

View File

@@ -0,0 +1,135 @@
use std::sync::Arc;
use crate::{
common::config::ConfigLoader,
instance_manager::NetworkInstanceManager,
launcher::ConfigSource,
proto::{
api::manage::*,
rpc_types::{self, controller::BaseController},
},
};
#[derive(Clone)]
pub struct InstanceManageRpcService {
manager: Arc<NetworkInstanceManager>,
}
impl InstanceManageRpcService {
pub fn new(manager: Arc<NetworkInstanceManager>) -> Self {
Self { manager }
}
}
#[async_trait::async_trait]
impl WebClientService for InstanceManageRpcService {
type Controller = BaseController;
async fn validate_config(
&self,
_: BaseController,
req: ValidateConfigRequest,
) -> Result<ValidateConfigResponse, rpc_types::error::Error> {
let toml_config = req.config.unwrap_or_default().gen_config()?.dump();
Ok(ValidateConfigResponse { toml_config })
}
async fn run_network_instance(
&self,
_: BaseController,
req: RunNetworkInstanceRequest,
) -> Result<RunNetworkInstanceResponse, rpc_types::error::Error> {
if req.config.is_none() {
return Err(anyhow::anyhow!("config is required").into());
}
let cfg = req.config.unwrap().gen_config()?;
let id = cfg.get_id();
if let Some(inst_id) = req.inst_id {
cfg.set_id(inst_id.into());
}
self.manager.run_network_instance(cfg, ConfigSource::Web)?;
println!("instance {} started", id);
Ok(RunNetworkInstanceResponse {
inst_id: Some(id.into()),
})
}
async fn retain_network_instance(
&self,
_: BaseController,
req: RetainNetworkInstanceRequest,
) -> Result<RetainNetworkInstanceResponse, rpc_types::error::Error> {
let remain = self
.manager
.retain_network_instance(req.inst_ids.into_iter().map(Into::into).collect())?;
println!("instance {:?} retained", remain);
Ok(RetainNetworkInstanceResponse {
remain_inst_ids: remain.iter().map(|item| (*item).into()).collect(),
})
}
async fn collect_network_info(
&self,
_: BaseController,
req: CollectNetworkInfoRequest,
) -> Result<CollectNetworkInfoResponse, rpc_types::error::Error> {
let mut ret = NetworkInstanceRunningInfoMap {
map: self
.manager
.collect_network_infos()?
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect(),
};
let include_inst_ids = req
.inst_ids
.iter()
.cloned()
.map(|id| id.to_string())
.collect::<Vec<_>>();
if !include_inst_ids.is_empty() {
let mut to_remove = Vec::new();
for (k, _) in ret.map.iter() {
if !include_inst_ids.contains(k) {
to_remove.push(k.clone());
}
}
for k in to_remove {
ret.map.remove(&k);
}
}
Ok(CollectNetworkInfoResponse { info: Some(ret) })
}
// rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {}
async fn list_network_instance(
&self,
_: BaseController,
_: ListNetworkInstanceRequest,
) -> Result<ListNetworkInstanceResponse, rpc_types::error::Error> {
Ok(ListNetworkInstanceResponse {
inst_ids: self
.manager
.list_network_instance_ids()
.into_iter()
.map(Into::into)
.collect(),
})
}
// rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {}
async fn delete_network_instance(
&self,
_: BaseController,
req: DeleteNetworkInstanceRequest,
) -> Result<DeleteNetworkInstanceResponse, rpc_types::error::Error> {
let remain_inst_ids = self
.manager
.delete_network_instance(req.inst_ids.into_iter().map(Into::into).collect())?;
println!("instance {:?} retained", remain_inst_ids);
Ok(DeleteNetworkInstanceResponse {
remain_inst_ids: remain_inst_ids.into_iter().map(Into::into).collect(),
})
}
}

View File

@@ -1,7 +1,7 @@
use std::sync::{mpsc::Sender, Mutex, OnceLock};
use crate::proto::{
cli::{
api::logger::{
GetLoggerConfigRequest, GetLoggerConfigResponse, LogLevel, LoggerRpc,
SetLoggerConfigRequest, SetLoggerConfigResponse,
},
@@ -11,14 +11,10 @@ use crate::proto::{
pub static LOGGER_LEVEL_SENDER: std::sync::OnceLock<Mutex<Sender<String>>> = OnceLock::new();
pub static CURRENT_LOG_LEVEL: std::sync::OnceLock<Mutex<String>> = OnceLock::new();
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct LoggerRpcService;
impl LoggerRpcService {
pub fn new() -> Self {
Self
}
fn log_level_to_string(level: LogLevel) -> String {
match level {
LogLevel::Disabled => "off".to_string(),

View File

@@ -0,0 +1,38 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{
ListMappedListenerRequest, ListMappedListenerResponse, MappedListenerManageRpc,
},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct MappedListenerManageRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl MappedListenerManageRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl MappedListenerManageRpc for MappedListenerManageRpcService {
type Controller = BaseController;
async fn list_mapped_listener(
&self,
ctrl: Self::Controller,
req: ListMappedListenerRequest,
) -> crate::proto::rpc_types::error::Result<ListMappedListenerResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_mapped_listener_manage_service()
.list_mapped_listener(ctrl, req)
.await
}
}

View File

@@ -0,0 +1,108 @@
mod acl_manage;
mod api;
mod config;
mod connector_manage;
mod mapped_listener_manage;
mod peer_manage;
mod port_forward_manage;
mod proxy;
mod stats;
mod vpn_portal;
pub mod instance_manage;
pub mod logger;
pub type ApiRpcServer = self::api::ApiRpcServer;
pub trait InstanceRpcService: Sync + Send {
fn get_peer_manage_service(
&self,
) -> &dyn crate::proto::api::instance::PeerManageRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
fn get_connector_manage_service(
&self,
) -> &dyn crate::proto::api::instance::ConnectorManageRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
fn get_mapped_listener_manage_service(
&self,
) -> &dyn crate::proto::api::instance::MappedListenerManageRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
fn get_vpn_portal_service(
&self,
) -> &dyn crate::proto::api::instance::VpnPortalRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
fn get_proxy_service(
&self,
client_type: &str,
) -> Option<
std::sync::Arc<
dyn crate::proto::api::instance::TcpProxyRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
> + Send
+ Sync,
>,
>;
fn get_acl_manage_service(
&self,
) -> &dyn crate::proto::api::instance::AclManageRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
fn get_port_forward_manage_service(
&self,
) -> &dyn crate::proto::api::instance::PortForwardManageRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
fn get_stats_service(
&self,
) -> &dyn crate::proto::api::instance::StatsRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
fn get_config_service(
&self,
) -> &dyn crate::proto::api::config::ConfigRpc<
Controller = crate::proto::rpc_types::controller::BaseController,
>;
}
fn get_instance_service(
instance_manager: &std::sync::Arc<crate::instance_manager::NetworkInstanceManager>,
identifier: &Option<crate::proto::api::instance::InstanceIdentifier>,
) -> Result<std::sync::Arc<dyn InstanceRpcService>, anyhow::Error> {
use crate::proto::api;
let selector = identifier.as_ref().and_then(|s| s.selector.as_ref());
let id = if let Some(api::instance::instance_identifier::Selector::Id(id)) = selector {
(*id).into()
} else {
let ids = instance_manager.filter_network_instance(|_, i| {
if let Some(api::instance::instance_identifier::Selector::InstanceSelector(selector)) =
selector
{
if let Some(name) = selector.name.as_ref() {
if i.get_inst_name() != *name {
return false;
}
}
}
true
});
match ids.len() {
0 => return Err(anyhow::anyhow!("No instance matches the selector")),
1 => ids[0],
_ => {
return Err(anyhow::anyhow!(
"{} instances match the selector, please specify the instance ID",
ids.len()
))
}
}
};
instance_manager
.get_instance_service(&id)
.ok_or_else(|| anyhow::anyhow!("Instance not found or API service not available"))
}

View File

@@ -0,0 +1,91 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{self, ListPeerRequest, ListPeerResponse, PeerManageRpc},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct PeerManageRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl PeerManageRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl PeerManageRpc for PeerManageRpcService {
type Controller = BaseController;
async fn list_peer(
&self,
ctrl: Self::Controller,
req: ListPeerRequest,
) -> crate::proto::rpc_types::error::Result<ListPeerResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_peer_manage_service()
.list_peer(ctrl, req)
.await
}
async fn list_route(
&self,
ctrl: Self::Controller,
req: crate::proto::api::instance::ListRouteRequest,
) -> crate::proto::rpc_types::error::Result<instance::ListRouteResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_peer_manage_service()
.list_route(ctrl, req)
.await
}
async fn dump_route(
&self,
ctrl: Self::Controller,
req: crate::proto::api::instance::DumpRouteRequest,
) -> crate::proto::rpc_types::error::Result<instance::DumpRouteResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_peer_manage_service()
.dump_route(ctrl, req)
.await
}
async fn list_foreign_network(
&self,
ctrl: Self::Controller,
req: crate::proto::api::instance::ListForeignNetworkRequest,
) -> crate::proto::rpc_types::error::Result<instance::ListForeignNetworkResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_peer_manage_service()
.list_foreign_network(ctrl, req)
.await
}
async fn list_global_foreign_network(
&self,
ctrl: Self::Controller,
req: crate::proto::api::instance::ListGlobalForeignNetworkRequest,
) -> crate::proto::rpc_types::error::Result<instance::ListGlobalForeignNetworkResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_peer_manage_service()
.list_global_foreign_network(ctrl, req)
.await
}
async fn show_node_info(
&self,
ctrl: Self::Controller,
req: crate::proto::api::instance::ShowNodeInfoRequest,
) -> crate::proto::rpc_types::error::Result<instance::ShowNodeInfoResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_peer_manage_service()
.show_node_info(ctrl, req)
.await
}
}

View File

@@ -0,0 +1,36 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{ListPortForwardRequest, ListPortForwardResponse, PortForwardManageRpc},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct PortForwardManageRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl PortForwardManageRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl PortForwardManageRpc for PortForwardManageRpcService {
type Controller = BaseController;
async fn list_port_forward(
&self,
ctrl: Self::Controller,
req: ListPortForwardRequest,
) -> crate::proto::rpc_types::error::Result<ListPortForwardResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_port_forward_manage_service()
.list_port_forward(ctrl, req)
.await
}
}

View File

@@ -0,0 +1,41 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{ListTcpProxyEntryRequest, ListTcpProxyEntryResponse, TcpProxyRpc},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct TcpProxyRpcService {
instance_manager: Arc<NetworkInstanceManager>,
client_type: &'static str,
}
impl TcpProxyRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>, client_type: &'static str) -> Self {
Self {
instance_manager,
client_type,
}
}
}
#[async_trait::async_trait]
impl TcpProxyRpc for TcpProxyRpcService {
type Controller = BaseController;
async fn list_tcp_proxy_entry(
&self,
ctrl: Self::Controller,
req: ListTcpProxyEntryRequest,
) -> crate::proto::rpc_types::error::Result<ListTcpProxyEntryResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_proxy_service(self.client_type)
.ok_or_else(|| anyhow::anyhow!("TCP proxy service not found for {}", self.client_type))?
.list_tcp_proxy_entry(ctrl, req)
.await
}
}

View File

@@ -0,0 +1,50 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{
GetPrometheusStatsRequest, GetPrometheusStatsResponse, GetStatsRequest,
GetStatsResponse, StatsRpc,
},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct StatsRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl StatsRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl StatsRpc for StatsRpcService {
type Controller = BaseController;
async fn get_stats(
&self,
ctrl: Self::Controller,
req: GetStatsRequest,
) -> crate::proto::rpc_types::error::Result<GetStatsResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_stats_service()
.get_stats(ctrl, req)
.await
}
async fn get_prometheus_stats(
&self,
ctrl: Self::Controller,
req: GetPrometheusStatsRequest,
) -> crate::proto::rpc_types::error::Result<GetPrometheusStatsResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_stats_service()
.get_prometheus_stats(ctrl, req)
.await
}
}

View File

@@ -0,0 +1,36 @@
use std::sync::Arc;
use crate::{
instance_manager::NetworkInstanceManager,
proto::{
api::instance::{GetVpnPortalInfoRequest, GetVpnPortalInfoResponse, VpnPortalRpc},
rpc_types::controller::BaseController,
},
};
#[derive(Clone)]
pub struct VpnPortalRpcService {
instance_manager: Arc<NetworkInstanceManager>,
}
impl VpnPortalRpcService {
pub fn new(instance_manager: Arc<NetworkInstanceManager>) -> Self {
Self { instance_manager }
}
}
#[async_trait::async_trait]
impl VpnPortalRpc for VpnPortalRpcService {
type Controller = BaseController;
async fn get_vpn_portal_info(
&self,
ctrl: Self::Controller,
req: GetVpnPortalInfoRequest,
) -> crate::proto::rpc_types::error::Result<GetVpnPortalInfoResponse> {
super::get_instance_service(&self.instance_manager, &req.instance)?
.get_vpn_portal_service()
.get_vpn_portal_info(ctrl, req)
.await
}
}

View File

@@ -132,7 +132,7 @@ pub fn enable_log() {
.init();
}
fn check_route(ipv4: &str, dst_peer_id: PeerId, routes: Vec<crate::proto::cli::Route>) {
fn check_route(ipv4: &str, dst_peer_id: PeerId, routes: Vec<crate::proto::api::instance::Route>) {
let mut found = false;
for r in routes.iter() {
if r.ipv4_addr == Some(ipv4.parse().unwrap()) {
@@ -148,9 +148,9 @@ fn check_route(ipv4: &str, dst_peer_id: PeerId, routes: Vec<crate::proto::cli::R
}
fn check_route_ex(
routes: Vec<crate::proto::cli::Route>,
routes: Vec<crate::proto::api::instance::Route>,
peer_id: PeerId,
checker: impl Fn(&crate::proto::cli::Route) -> bool,
checker: impl Fn(&crate::proto::api::instance::Route) -> bool,
) {
let mut found = false;
for r in routes.iter() {

View File

@@ -18,7 +18,7 @@ use crate::{
stats_manager::{LabelType, MetricName},
},
instance::instance::Instance,
proto::{cli::TcpProxyEntryTransportType, common::CompressionAlgoPb},
proto::{api::instance::TcpProxyEntryTransportType, common::CompressionAlgoPb},
tunnel::{
common::tests::{_tunnel_bench_netns, wait_for_condition},
ring::RingTunnelConnector,
@@ -2100,8 +2100,10 @@ pub async fn acl_group_based_test(
#[serial_test::serial]
pub async fn config_patch_test() {
use crate::proto::{
api::config::{
ConfigPatchAction, InstanceConfigPatch, PortForwardPatch, ProxyNetworkPatch,
},
common::{PortForwardConfigPb, SocketType},
config::{ConfigPatchAction, InstanceConfigPatch, PortForwardPatch, ProxyNetworkPatch},
};
use crate::tunnel::common::tests::_tunnel_pingpong_netns_with_timeout;

View File

@@ -10,7 +10,7 @@ use crate::common::{
config::LoggingConfigLoader, get_logger_timer_rfc3339, tracing_rolling_appender::*,
};
pub type PeerRoutePair = crate::proto::cli::PeerRoutePair;
pub type PeerRoutePair = crate::proto::api::instance::PeerRoutePair;
pub fn cost_to_str(cost: i32) -> String {
if cost == 1 {
@@ -30,7 +30,7 @@ pub fn init_logger(
config: impl LoggingConfigLoader,
need_reload: bool,
) -> Result<Option<NewFilterSender>, anyhow::Error> {
use crate::instance::logger_rpc_service::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER};
use crate::rpc_service::logger::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER};
let file_config = config.get_file_logger_config();
let file_level = file_config
@@ -254,6 +254,11 @@ pub fn find_free_tcp_port(mut range: std::ops::Range<u16>) -> Option<u16> {
range.find(|&port| check_tcp_available(port))
}
pub fn weak_upgrade<T>(weak: &std::sync::Weak<T>) -> anyhow::Result<std::sync::Arc<T>> {
weak.upgrade()
.ok_or_else(|| anyhow::anyhow!("{} not available", std::any::type_name::<T>()))
}
#[cfg(test)]
mod tests {
use crate::common::config::{self};

View File

@@ -1,31 +1,22 @@
use std::sync::Arc;
use crate::{
common::config::ConfigLoader,
instance_manager::NetworkInstanceManager,
launcher::ConfigSource,
proto::{
rpc_types::{self, controller::BaseController},
web::{
CollectNetworkInfoRequest, CollectNetworkInfoResponse, DeleteNetworkInstanceRequest,
DeleteNetworkInstanceResponse, ListNetworkInstanceRequest, ListNetworkInstanceResponse,
NetworkInstanceRunningInfoMap, RetainNetworkInstanceRequest,
RetainNetworkInstanceResponse, RunNetworkInstanceRequest, RunNetworkInstanceResponse,
ValidateConfigRequest, ValidateConfigResponse, WebClientService,
},
},
rpc_service::instance_manage::InstanceManageRpcService,
};
pub struct Controller {
token: String,
hostname: String,
manager: NetworkInstanceManager,
manager: Arc<NetworkInstanceManager>,
}
impl Controller {
pub fn new(token: String, hostname: String) -> Self {
pub fn new(token: String, hostname: String, manager: Arc<NetworkInstanceManager>) -> Self {
Controller {
token,
hostname,
manager: NetworkInstanceManager::new(),
manager,
}
}
@@ -40,117 +31,8 @@ impl Controller {
pub fn hostname(&self) -> String {
self.hostname.clone()
}
}
#[async_trait::async_trait]
impl WebClientService for Controller {
type Controller = BaseController;
async fn validate_config(
&self,
_: BaseController,
req: ValidateConfigRequest,
) -> Result<ValidateConfigResponse, rpc_types::error::Error> {
let toml_config = req.config.unwrap_or_default().gen_config()?.dump();
Ok(ValidateConfigResponse { toml_config })
}
async fn run_network_instance(
&self,
_: BaseController,
req: RunNetworkInstanceRequest,
) -> Result<RunNetworkInstanceResponse, rpc_types::error::Error> {
if req.config.is_none() {
return Err(anyhow::anyhow!("config is required").into());
}
let cfg = req.config.unwrap().gen_config()?;
let id = cfg.get_id();
if let Some(inst_id) = req.inst_id {
cfg.set_id(inst_id.into());
}
self.manager.run_network_instance(cfg, ConfigSource::Web)?;
println!("instance {} started", id);
Ok(RunNetworkInstanceResponse {
inst_id: Some(id.into()),
})
}
async fn retain_network_instance(
&self,
_: BaseController,
req: RetainNetworkInstanceRequest,
) -> Result<RetainNetworkInstanceResponse, rpc_types::error::Error> {
let remain = self
.manager
.retain_network_instance(req.inst_ids.into_iter().map(Into::into).collect())?;
println!("instance {:?} retained", remain);
Ok(RetainNetworkInstanceResponse {
remain_inst_ids: remain.iter().map(|item| (*item).into()).collect(),
})
}
async fn collect_network_info(
&self,
_: BaseController,
req: CollectNetworkInfoRequest,
) -> Result<CollectNetworkInfoResponse, rpc_types::error::Error> {
let mut ret = NetworkInstanceRunningInfoMap {
map: self
.manager
.collect_network_infos()?
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect(),
};
let include_inst_ids = req
.inst_ids
.iter()
.cloned()
.map(|id| id.to_string())
.collect::<Vec<_>>();
if !include_inst_ids.is_empty() {
let mut to_remove = Vec::new();
for (k, _) in ret.map.iter() {
if !include_inst_ids.contains(k) {
to_remove.push(k.clone());
}
}
for k in to_remove {
ret.map.remove(&k);
}
}
Ok(CollectNetworkInfoResponse { info: Some(ret) })
}
// rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {}
async fn list_network_instance(
&self,
_: BaseController,
_: ListNetworkInstanceRequest,
) -> Result<ListNetworkInstanceResponse, rpc_types::error::Error> {
Ok(ListNetworkInstanceResponse {
inst_ids: self
.manager
.list_network_instance_ids()
.into_iter()
.map(Into::into)
.collect(),
})
}
// rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {}
async fn delete_network_instance(
&self,
_: BaseController,
req: DeleteNetworkInstanceRequest,
) -> Result<DeleteNetworkInstanceResponse, rpc_types::error::Error> {
let remain_inst_ids = self
.manager
.delete_network_instance(req.inst_ids.into_iter().map(Into::into).collect())?;
println!("instance {:?} retained", remain_inst_ids);
Ok(DeleteNetworkInstanceResponse {
remain_inst_ids: remain_inst_ids.into_iter().map(Into::into).collect(),
})
pub fn get_rpc_service(&self) -> InstanceManageRpcService {
InstanceManageRpcService::new(self.manager.clone())
}
}

View File

@@ -1,6 +1,9 @@
use std::sync::Arc;
use crate::{common::scoped_task::ScopedTask, tunnel::TunnelConnector};
use crate::{
common::scoped_task::ScopedTask, instance_manager::NetworkInstanceManager,
tunnel::TunnelConnector,
};
pub mod controller;
pub mod session;
@@ -15,10 +18,12 @@ impl WebClient {
connector: T,
token: S,
hostname: H,
manager: Arc<NetworkInstanceManager>,
) -> Self {
let controller = Arc::new(controller::Controller::new(
token.to_string(),
hostname.to_string(),
manager,
));
let controller_clone = controller.clone();

View File

@@ -9,12 +9,10 @@ use tokio::{
use crate::{
common::{constants::EASYTIER_VERSION, get_machine_id},
proto::{
api::manage::WebClientServiceServer,
rpc_impl::bidirect::BidirectRpcManager,
rpc_types::controller::BaseController,
web::{
HeartbeatRequest, HeartbeatResponse, WebClientServiceServer,
WebServerServiceClientFactory,
},
web::{HeartbeatRequest, HeartbeatResponse, WebServerServiceClientFactory},
},
tunnel::Tunnel,
};
@@ -41,10 +39,10 @@ impl Session {
let rpc_mgr = BidirectRpcManager::new();
rpc_mgr.run_with_tunnel(tunnel);
rpc_mgr
.rpc_server()
.registry()
.register(WebClientServiceServer::new(controller.clone()), "");
rpc_mgr.rpc_server().registry().register(
WebClientServiceServer::new(controller.get_rpc_service()),
"",
);
let mut tasks: JoinSet<()> = JoinSet::new();
let heartbeat_ctx =