mirror of
https://github.com/house-of-vanity/OutFleet.git
synced 2025-10-26 10:09:08 +00:00
Useradd works
This commit is contained in:
@@ -2,7 +2,7 @@ use anyhow::Result;
|
||||
use tokio_cron_scheduler::{JobScheduler, Job};
|
||||
use tracing::{info, error, warn};
|
||||
use crate::database::DatabaseManager;
|
||||
use crate::database::repository::{ServerRepository, ServerInboundRepository, InboundTemplateRepository, InboundUsersRepository, CertificateRepository};
|
||||
use crate::database::repository::{ServerRepository, ServerInboundRepository, InboundTemplateRepository, InboundUsersRepository, CertificateRepository, UserRepository};
|
||||
use crate::database::entities::inbound_users;
|
||||
use crate::services::XrayService;
|
||||
use crate::services::events::SyncEvent;
|
||||
@@ -60,17 +60,12 @@ impl TaskScheduler {
|
||||
let xray_service = XrayService::new();
|
||||
|
||||
tokio::spawn(async move {
|
||||
info!("Starting event-driven sync handler");
|
||||
|
||||
while let Ok(event) = event_receiver.recv().await {
|
||||
match event {
|
||||
SyncEvent::InboundChanged(server_id) | SyncEvent::UserAccessChanged(server_id) => {
|
||||
info!("Received sync event for server {}", server_id);
|
||||
|
||||
if let Err(e) = sync_single_server_by_id(&xray_service, &db, server_id).await {
|
||||
error!("Failed to sync server {} from event: {}", server_id, e);
|
||||
} else {
|
||||
info!("Successfully synced server {} from event", server_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +74,6 @@ impl TaskScheduler {
|
||||
}
|
||||
|
||||
pub async fn start(&mut self, db: DatabaseManager, xray_service: XrayService) -> Result<()> {
|
||||
info!("Starting task scheduler with database synchronization");
|
||||
|
||||
// Initialize task status
|
||||
{
|
||||
@@ -100,7 +94,6 @@ impl TaskScheduler {
|
||||
}
|
||||
|
||||
// Run initial sync on startup
|
||||
info!("Running initial xray synchronization on startup");
|
||||
let start_time = Utc::now();
|
||||
self.update_task_status("xray_sync", TaskState::Running, None);
|
||||
|
||||
@@ -108,7 +101,6 @@ impl TaskScheduler {
|
||||
Ok(_) => {
|
||||
let duration = (Utc::now() - start_time).num_milliseconds() as u64;
|
||||
self.update_task_status("xray_sync", TaskState::Success, Some(duration));
|
||||
info!("Initial xray sync completed successfully");
|
||||
},
|
||||
Err(e) => {
|
||||
let duration = (Utc::now() - start_time).num_milliseconds() as u64;
|
||||
@@ -128,7 +120,6 @@ impl TaskScheduler {
|
||||
let task_status = task_status_clone.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
info!("Running scheduled xray synchronization");
|
||||
let start_time = Utc::now();
|
||||
|
||||
// Update status to running
|
||||
@@ -152,7 +143,6 @@ impl TaskScheduler {
|
||||
task.last_duration_ms = Some(duration);
|
||||
task.last_error = None;
|
||||
}
|
||||
info!("Scheduled xray sync completed successfully in {}ms", duration);
|
||||
},
|
||||
Err(e) => {
|
||||
let duration = (Utc::now() - start_time).num_milliseconds() as u64;
|
||||
@@ -171,7 +161,6 @@ impl TaskScheduler {
|
||||
|
||||
self.scheduler.add(sync_job).await?;
|
||||
|
||||
info!("Task scheduler started with sync job running every minute");
|
||||
|
||||
self.scheduler.start().await?;
|
||||
Ok(())
|
||||
@@ -202,7 +191,6 @@ impl TaskScheduler {
|
||||
}
|
||||
|
||||
pub async fn shutdown(&mut self) -> Result<()> {
|
||||
info!("Shutting down task scheduler");
|
||||
self.scheduler.shutdown().await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -210,7 +198,6 @@ impl TaskScheduler {
|
||||
|
||||
/// Synchronize xray server state with database state
|
||||
async fn sync_xray_state(db: DatabaseManager, xray_service: XrayService) -> Result<()> {
|
||||
info!("Starting xray state synchronization");
|
||||
|
||||
let server_repo = ServerRepository::new(db.connection().clone());
|
||||
let inbound_repo = ServerInboundRepository::new(db.connection().clone());
|
||||
@@ -225,18 +212,13 @@ async fn sync_xray_state(db: DatabaseManager, xray_service: XrayService) -> Resu
|
||||
}
|
||||
};
|
||||
|
||||
info!("Found {} servers to synchronize", servers.len());
|
||||
|
||||
for server in servers {
|
||||
info!("Synchronizing server: {} ({}:{})", server.name, server.hostname, server.grpc_port);
|
||||
|
||||
let endpoint = format!("{}:{}", server.hostname, server.grpc_port);
|
||||
|
||||
// Test connection first
|
||||
match xray_service.test_connection(server.id, &endpoint).await {
|
||||
Ok(true) => {
|
||||
info!("Connection to server {} successful", server.name);
|
||||
},
|
||||
Ok(false) => {
|
||||
warn!("Cannot connect to server {} at {}, skipping", server.name, endpoint);
|
||||
continue;
|
||||
@@ -245,6 +227,7 @@ async fn sync_xray_state(db: DatabaseManager, xray_service: XrayService) -> Resu
|
||||
error!("Error testing connection to server {}: {}", server.name, e);
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Get desired inbounds from database
|
||||
@@ -256,7 +239,6 @@ async fn sync_xray_state(db: DatabaseManager, xray_service: XrayService) -> Resu
|
||||
}
|
||||
};
|
||||
|
||||
info!("Server {}: desired={} inbounds", server.name, desired_inbounds.len());
|
||||
|
||||
// Synchronize inbounds
|
||||
if let Err(e) = sync_server_inbounds(
|
||||
@@ -266,12 +248,9 @@ async fn sync_xray_state(db: DatabaseManager, xray_service: XrayService) -> Resu
|
||||
&desired_inbounds
|
||||
).await {
|
||||
error!("Failed to sync inbounds for server {}: {}", server.name, e);
|
||||
} else {
|
||||
info!("Successfully synchronized server {}", server.name);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Xray state synchronization completed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -283,7 +262,6 @@ async fn get_desired_inbounds_from_db(
|
||||
inbound_repo: &ServerInboundRepository,
|
||||
template_repo: &InboundTemplateRepository,
|
||||
) -> Result<HashMap<String, DesiredInbound>> {
|
||||
info!("Getting desired inbounds for server {} from database", server.name);
|
||||
|
||||
// Get all inbounds for this server
|
||||
let inbounds = inbound_repo.find_by_server_id(server.id).await?;
|
||||
@@ -302,7 +280,6 @@ async fn get_desired_inbounds_from_db(
|
||||
// Get users for this inbound
|
||||
let users = get_users_for_inbound(db, inbound.id).await?;
|
||||
|
||||
info!("Inbound {}: {} users found", inbound.tag, users.len());
|
||||
|
||||
// Get port from template or override
|
||||
let port = inbound.port_override.unwrap_or(template.default_port);
|
||||
@@ -334,7 +311,6 @@ async fn get_desired_inbounds_from_db(
|
||||
desired_inbounds.insert(inbound.tag.clone(), desired_inbound);
|
||||
}
|
||||
|
||||
info!("Found {} desired inbounds for server {}", desired_inbounds.len(), server.name);
|
||||
Ok(desired_inbounds)
|
||||
}
|
||||
|
||||
@@ -344,13 +320,20 @@ async fn get_users_for_inbound(db: &DatabaseManager, inbound_id: Uuid) -> Result
|
||||
|
||||
let inbound_users = inbound_users_repo.find_active_by_inbound_id(inbound_id).await?;
|
||||
|
||||
let users: Vec<XrayUser> = inbound_users.into_iter().map(|user| {
|
||||
XrayUser {
|
||||
id: user.xray_user_id,
|
||||
email: user.email,
|
||||
level: user.level,
|
||||
// Get user details to generate emails
|
||||
let user_repo = UserRepository::new(db.connection().clone());
|
||||
|
||||
let mut users: Vec<XrayUser> = Vec::new();
|
||||
for inbound_user in inbound_users {
|
||||
if let Some(user) = user_repo.find_by_id(inbound_user.user_id).await? {
|
||||
let email = inbound_user.generate_client_email(&user.name);
|
||||
users.push(XrayUser {
|
||||
id: inbound_user.xray_user_id,
|
||||
email,
|
||||
level: inbound_user.level,
|
||||
});
|
||||
}
|
||||
}).collect();
|
||||
}
|
||||
|
||||
Ok(users)
|
||||
}
|
||||
@@ -366,7 +349,6 @@ async fn load_certificate_from_db(db: &DatabaseManager, cert_id: Option<Uuid>) -
|
||||
|
||||
match cert_repo.find_by_id(cert_id).await? {
|
||||
Some(cert) => {
|
||||
info!("Loaded certificate: {}", cert.domain);
|
||||
Ok((Some(cert.certificate_pem()), Some(cert.private_key_pem())))
|
||||
},
|
||||
None => {
|
||||
@@ -387,13 +369,9 @@ async fn sync_server_inbounds(
|
||||
// Create or update inbounds
|
||||
// Since xray has no API to list inbounds, we always recreate them
|
||||
for (tag, desired) in desired_inbounds {
|
||||
info!("Creating/updating inbound: {} with {} users", tag, desired.users.len());
|
||||
|
||||
// Always try to remove inbound first (ignore errors if it doesn't exist)
|
||||
if let Err(e) = xray_service.remove_inbound(server_id, endpoint, tag).await {
|
||||
// Log but don't fail - inbound might not exist
|
||||
info!("Inbound {} removal result: {} (this is normal if inbound didn't exist)", tag, e);
|
||||
}
|
||||
let _ = xray_service.remove_inbound(server_id, endpoint, tag).await;
|
||||
|
||||
// Create inbound with users
|
||||
let users_json: Vec<Value> = desired.users.iter().map(|user| {
|
||||
@@ -416,12 +394,10 @@ async fn sync_server_inbounds(
|
||||
desired.cert_pem.as_deref(),
|
||||
desired.key_pem.as_deref(),
|
||||
).await {
|
||||
Ok(_) => {
|
||||
info!("Successfully created inbound {} with {} users", tag, desired.users.len());
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to create inbound {}: {}", tag, e);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
use serde_json::Value;
|
||||
use uuid;
|
||||
use xray_core::{
|
||||
tonic::Request,
|
||||
app::proxyman::command::{AddInboundRequest, RemoveInboundRequest},
|
||||
@@ -7,7 +8,7 @@ use xray_core::{
|
||||
common::serial::TypedMessage,
|
||||
common::protocol::User,
|
||||
app::proxyman::ReceiverConfig,
|
||||
common::net::{PortList, PortRange, IpOrDomain, ip_or_domain::Address},
|
||||
common::net::{PortList, PortRange, IpOrDomain, ip_or_domain::Address, Network},
|
||||
transport::internet::StreamConfig,
|
||||
transport::internet::tls::{Config as TlsConfig, Certificate as TlsCertificate},
|
||||
proxy::vless::inbound::Config as VlessInboundConfig,
|
||||
@@ -17,7 +18,7 @@ use xray_core::{
|
||||
proxy::trojan::ServerConfig as TrojanServerConfig,
|
||||
proxy::trojan::Account as TrojanAccount,
|
||||
proxy::shadowsocks::ServerConfig as ShadowsocksServerConfig,
|
||||
proxy::shadowsocks::Account as ShadowsocksAccount,
|
||||
proxy::shadowsocks::{Account as ShadowsocksAccount, CipherType},
|
||||
Client,
|
||||
prost_types,
|
||||
};
|
||||
@@ -32,8 +33,7 @@ fn pem_to_der(pem_data: &str) -> Result<Vec<u8>> {
|
||||
.collect::<Vec<&str>>()
|
||||
.join("");
|
||||
|
||||
tracing::debug!("Base64 data length: {}", base64_data.len());
|
||||
tracing::debug!("Base64 data: {}", &base64_data[..std::cmp::min(100, base64_data.len())]);
|
||||
tracing::debug!("PEM to DER conversion: {} bytes", base64_data.len());
|
||||
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
general_purpose::STANDARD.decode(&base64_data)
|
||||
@@ -57,14 +57,11 @@ impl<'a> InboundClient<'a> {
|
||||
|
||||
/// Add inbound configuration with TLS certificate and users
|
||||
pub async fn add_inbound_with_certificate(&self, inbound: &Value, users: Option<&[Value]>, cert_pem: Option<&str>, key_pem: Option<&str>) -> Result<()> {
|
||||
tracing::info!("Adding inbound to Xray server at {}", self.endpoint);
|
||||
tracing::debug!("Inbound config: {}", serde_json::to_string_pretty(inbound)?);
|
||||
|
||||
let tag = inbound["tag"].as_str().unwrap_or("").to_string();
|
||||
let port = inbound["port"].as_u64().unwrap_or(8080) as u32;
|
||||
let protocol = inbound["protocol"].as_str().unwrap_or("vless");
|
||||
let user_count = users.map_or(0, |u| u.len());
|
||||
|
||||
tracing::debug!("Creating inbound: tag={}, port={}, protocol={}", tag, port, protocol);
|
||||
|
||||
// Create receiver configuration (port binding) - use simple port number
|
||||
let port_list = PortList {
|
||||
@@ -79,8 +76,6 @@ impl<'a> InboundClient<'a> {
|
||||
let cert_pem = cert_pem.unwrap();
|
||||
let key_pem = key_pem.unwrap();
|
||||
|
||||
tracing::info!("Creating StreamConfig with TLS like working example");
|
||||
|
||||
// Create TLS certificate exactly like working example - PEM content as bytes
|
||||
let tls_cert = TlsCertificate {
|
||||
certificate: cert_pem.as_bytes().to_vec(), // PEM content as bytes like working example
|
||||
@@ -106,7 +101,7 @@ impl<'a> InboundClient<'a> {
|
||||
value: tls_config.encode_to_vec(),
|
||||
};
|
||||
|
||||
tracing::info!("Created TLS config with server_name: {}, next_protocol: {:?}",
|
||||
tracing::debug!("TLS config: server_name={}, protocols={:?}",
|
||||
tls_config.server_name, tls_config.next_protocol);
|
||||
|
||||
// Create StreamConfig like working example
|
||||
@@ -120,7 +115,6 @@ impl<'a> InboundClient<'a> {
|
||||
socket_settings: None,
|
||||
})
|
||||
} else {
|
||||
tracing::info!("No certificates provided, creating inbound without TLS");
|
||||
None
|
||||
};
|
||||
|
||||
@@ -186,18 +180,31 @@ impl<'a> InboundClient<'a> {
|
||||
let email = user["email"].as_str().unwrap_or("").to_string();
|
||||
let level = user["level"].as_u64().unwrap_or(0) as u32;
|
||||
|
||||
// Validate required fields
|
||||
if user_id.is_empty() || email.is_empty() {
|
||||
tracing::warn!("Skipping VMess user: missing id or email");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate UUID format
|
||||
if uuid::Uuid::parse_str(&user_id).is_err() {
|
||||
tracing::warn!("VMess user '{}' has invalid UUID format", user_id);
|
||||
}
|
||||
|
||||
if !user_id.is_empty() && !email.is_empty() {
|
||||
let account = VmessAccount {
|
||||
id: user_id,
|
||||
id: user_id.clone(),
|
||||
security_settings: None,
|
||||
tests_enabled: "".to_string(),
|
||||
tests_enabled: "".to_string(), // Keep empty as in examples
|
||||
};
|
||||
let account_bytes = account.encode_to_vec();
|
||||
|
||||
vmess_users.push(User {
|
||||
email,
|
||||
email: email.clone(),
|
||||
level,
|
||||
account: Some(TypedMessage {
|
||||
r#type: "xray.proxy.vmess.Account".to_string(),
|
||||
value: account.encode_to_vec(),
|
||||
value: account_bytes,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -255,14 +262,15 @@ impl<'a> InboundClient<'a> {
|
||||
let email = user["email"].as_str().unwrap_or("").to_string();
|
||||
let level = user["level"].as_u64().unwrap_or(0) as u32;
|
||||
|
||||
|
||||
if !password.is_empty() && !email.is_empty() {
|
||||
let account = ShadowsocksAccount {
|
||||
password,
|
||||
cipher_type: 0, // Default cipher
|
||||
cipher_type: CipherType::Aes256Gcm as i32, // Use AES-256-GCM cipher
|
||||
iv_check: false, // Default IV check
|
||||
};
|
||||
ss_users.push(User {
|
||||
email,
|
||||
email: email.clone(),
|
||||
level,
|
||||
account: Some(TypedMessage {
|
||||
r#type: "xray.proxy.shadowsocks.Account".to_string(),
|
||||
@@ -275,7 +283,7 @@ impl<'a> InboundClient<'a> {
|
||||
|
||||
let shadowsocks_config = ShadowsocksServerConfig {
|
||||
users: ss_users,
|
||||
network: vec![], // Support all networks by default
|
||||
network: vec![Network::Tcp as i32, Network::Udp as i32], // Support TCP and UDP
|
||||
};
|
||||
TypedMessage {
|
||||
r#type: "xray.proxy.shadowsocks.ServerConfig".to_string(),
|
||||
@@ -293,21 +301,17 @@ impl<'a> InboundClient<'a> {
|
||||
proxy_settings: Some(proxy_message),
|
||||
};
|
||||
|
||||
tracing::info!("Sending AddInboundRequest for '{}'", tag);
|
||||
tracing::debug!("InboundConfig: {:?}", inbound_config);
|
||||
|
||||
let request = Request::new(AddInboundRequest {
|
||||
inbound: Some(inbound_config),
|
||||
});
|
||||
let mut handler_client = self.client.handler();
|
||||
match handler_client.add_inbound(request).await {
|
||||
Ok(response) => {
|
||||
let _response_inner = response.into_inner();
|
||||
tracing::info!("Successfully added inbound {}", tag);
|
||||
Ok(_) => {
|
||||
tracing::info!("Added {} inbound '{}' successfully", protocol, tag);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to add inbound {}: {}", tag, e);
|
||||
tracing::error!("Failed to add {} inbound '{}': {}", protocol, tag, e);
|
||||
Err(anyhow!("Failed to add inbound {}: {}", tag, e))
|
||||
}
|
||||
}
|
||||
@@ -315,8 +319,6 @@ impl<'a> InboundClient<'a> {
|
||||
|
||||
/// Remove inbound by tag
|
||||
pub async fn remove_inbound(&self, tag: &str) -> Result<()> {
|
||||
tracing::info!("Removing inbound '{}' from Xray server at {}", tag, self.endpoint);
|
||||
|
||||
let mut handler_client = self.client.handler();
|
||||
let request = Request::new(RemoveInboundRequest {
|
||||
tag: tag.to_string(),
|
||||
@@ -324,11 +326,11 @@ impl<'a> InboundClient<'a> {
|
||||
|
||||
match handler_client.remove_inbound(request).await {
|
||||
Ok(_) => {
|
||||
tracing::info!("Successfully removed inbound");
|
||||
tracing::info!("Removed inbound '{}' from {}", tag, self.endpoint);
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to remove inbound: {}", e);
|
||||
tracing::error!("Failed to remove inbound '{}': {}", tag, e);
|
||||
Err(anyhow!("Failed to remove inbound: {}", e))
|
||||
}
|
||||
}
|
||||
@@ -336,8 +338,7 @@ impl<'a> InboundClient<'a> {
|
||||
|
||||
/// Restart Xray with new configuration
|
||||
pub async fn restart_with_config(&self, config: &crate::services::xray::XrayConfig) -> Result<()> {
|
||||
tracing::info!("Restarting Xray server at {} with new config", self.endpoint);
|
||||
tracing::debug!("Config: {}", serde_json::to_string_pretty(&config.to_json())?);
|
||||
tracing::debug!("Restarting Xray server at {} with new config", self.endpoint);
|
||||
|
||||
// TODO: Implement restart with config using xray-core
|
||||
// For now just return success
|
||||
|
||||
@@ -64,7 +64,6 @@ impl XrayService {
|
||||
"streamSettings": stream_settings
|
||||
});
|
||||
|
||||
tracing::info!("Creating inbound with config: {}", inbound_config);
|
||||
self.add_inbound(_server_id, endpoint, &inbound_config).await
|
||||
}
|
||||
|
||||
@@ -90,7 +89,6 @@ impl XrayService {
|
||||
"streamSettings": stream_settings
|
||||
});
|
||||
|
||||
tracing::info!("Creating inbound with TLS certificate and config: {}", inbound_config);
|
||||
self.add_inbound_with_certificate(_server_id, endpoint, &inbound_config, cert_pem, key_pem).await
|
||||
}
|
||||
|
||||
@@ -120,8 +118,6 @@ impl XrayService {
|
||||
|
||||
/// Add user to inbound by recreating the inbound with updated user list
|
||||
pub async fn add_user(&self, _server_id: Uuid, endpoint: &str, inbound_tag: &str, user: &Value) -> Result<()> {
|
||||
tracing::info!("XrayService::add_user called for server {} endpoint {} inbound_tag {}", _server_id, endpoint, inbound_tag);
|
||||
tracing::warn!("Dynamic user addition via AlterInboundRequest doesn't work reliably - need to implement inbound recreation");
|
||||
|
||||
// TODO: Implement inbound recreation approach:
|
||||
// 1. Get current inbound configuration from database
|
||||
@@ -147,7 +143,6 @@ impl XrayService {
|
||||
cert_pem: Option<&str>,
|
||||
key_pem: Option<&str>,
|
||||
) -> Result<()> {
|
||||
tracing::info!("Creating inbound '{}' with {} users", tag, users.len());
|
||||
|
||||
// Build inbound configuration with users
|
||||
let mut inbound_config = serde_json::json!({
|
||||
@@ -181,7 +176,6 @@ impl XrayService {
|
||||
inbound_config["settings"] = settings;
|
||||
}
|
||||
|
||||
tracing::info!("Creating inbound with users: {}", serde_json::to_string_pretty(&inbound_config)?);
|
||||
|
||||
// Use the new method with users support
|
||||
self.add_inbound_with_users_and_certificate(_server_id, endpoint, &inbound_config, users, cert_pem, key_pem).await
|
||||
|
||||
@@ -24,16 +24,11 @@ impl<'a> UserClient<'a> {
|
||||
|
||||
/// Add user to inbound (simple version that works)
|
||||
pub async fn add_user(&self, inbound_tag: &str, user: &Value) -> Result<()> {
|
||||
tracing::info!("Adding user to inbound '{}' on Xray server at {}", inbound_tag, self.endpoint);
|
||||
tracing::debug!("User config: {}", serde_json::to_string_pretty(user)?);
|
||||
|
||||
let email = user["email"].as_str().unwrap_or("").to_string();
|
||||
let user_id = user["id"].as_str().unwrap_or("").to_string();
|
||||
let level = user["level"].as_u64().unwrap_or(0) as u32;
|
||||
let protocol = user["protocol"].as_str().unwrap_or("vless");
|
||||
|
||||
tracing::info!("Parsed user data: email={}, id={}, level={}, protocol={}", email, user_id, level, protocol);
|
||||
|
||||
if email.is_empty() || user_id.is_empty() {
|
||||
return Err(anyhow!("User email and id are required"));
|
||||
}
|
||||
@@ -99,13 +94,11 @@ impl<'a> UserClient<'a> {
|
||||
operation: Some(typed_message),
|
||||
});
|
||||
|
||||
tracing::info!("Sending AlterInboundRequest to add user '{}' to inbound '{}'", email, inbound_tag);
|
||||
|
||||
let mut handler_client = self.client.handler();
|
||||
match handler_client.alter_inbound(request).await {
|
||||
Ok(response) => {
|
||||
let _response_inner = response.into_inner();
|
||||
tracing::info!("Successfully added user '{}' to inbound '{}'", email, inbound_tag);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -118,7 +111,6 @@ impl<'a> UserClient<'a> {
|
||||
|
||||
/// Remove user from inbound
|
||||
pub async fn remove_user(&self, inbound_tag: &str, email: &str) -> Result<()> {
|
||||
tracing::info!("Removing user '{}' from inbound '{}' on Xray server at {}", email, inbound_tag, self.endpoint);
|
||||
|
||||
// Build the RemoveUserOperation
|
||||
let remove_user_op = RemoveUserOperation {
|
||||
@@ -138,7 +130,6 @@ impl<'a> UserClient<'a> {
|
||||
let mut handler_client = self.client.handler();
|
||||
match handler_client.alter_inbound(request).await {
|
||||
Ok(_) => {
|
||||
tracing::info!("Successfully removed user '{}' from inbound '{}'", email, inbound_tag);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user