Merge pull request #41 from vmax/feature/show-all-links
feature: support show_links = "*"
This commit is contained in:
@@ -316,6 +316,101 @@ pub struct ListenerConfig {
|
|||||||
pub announce_ip: Option<IpAddr>,
|
pub announce_ip: Option<IpAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============= ShowLink =============
|
||||||
|
|
||||||
|
/// Controls which users' proxy links are displayed at startup.
|
||||||
|
///
|
||||||
|
/// In TOML, this can be:
|
||||||
|
/// - `show_link = "*"` — show links for all users
|
||||||
|
/// - `show_link = ["a", "b"]` — show links for specific users
|
||||||
|
/// - omitted — show no links (default)
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ShowLink {
|
||||||
|
/// Don't show any links (default when omitted)
|
||||||
|
None,
|
||||||
|
/// Show links for all configured users
|
||||||
|
All,
|
||||||
|
/// Show links for specific users
|
||||||
|
Specific(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ShowLink {
|
||||||
|
fn default() -> Self {
|
||||||
|
ShowLink::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShowLink {
|
||||||
|
/// Returns true if no links should be shown
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
matches!(self, ShowLink::None) || matches!(self, ShowLink::Specific(v) if v.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve the list of user names to display, given all configured users
|
||||||
|
pub fn resolve_users<'a>(&'a self, all_users: &'a HashMap<String, String>) -> Vec<&'a String> {
|
||||||
|
match self {
|
||||||
|
ShowLink::None => vec![],
|
||||||
|
ShowLink::All => {
|
||||||
|
let mut names: Vec<&String> = all_users.keys().collect();
|
||||||
|
names.sort();
|
||||||
|
names
|
||||||
|
}
|
||||||
|
ShowLink::Specific(names) => names.iter().collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for ShowLink {
|
||||||
|
fn serialize<S: serde::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
|
||||||
|
match self {
|
||||||
|
ShowLink::None => Vec::<String>::new().serialize(serializer),
|
||||||
|
ShowLink::All => serializer.serialize_str("*"),
|
||||||
|
ShowLink::Specific(v) => v.serialize(serializer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for ShowLink {
|
||||||
|
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
|
||||||
|
use serde::de;
|
||||||
|
|
||||||
|
struct ShowLinkVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for ShowLinkVisitor {
|
||||||
|
type Value = ShowLink;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str(r#""*" or an array of user names"#)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E: de::Error>(self, v: &str) -> std::result::Result<ShowLink, E> {
|
||||||
|
if v == "*" {
|
||||||
|
Ok(ShowLink::All)
|
||||||
|
} else {
|
||||||
|
Err(de::Error::invalid_value(
|
||||||
|
de::Unexpected::Str(v),
|
||||||
|
&r#""*""#,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> std::result::Result<ShowLink, A::Error> {
|
||||||
|
let mut names = Vec::new();
|
||||||
|
while let Some(name) = seq.next_element::<String>()? {
|
||||||
|
names.push(name);
|
||||||
|
}
|
||||||
|
if names.is_empty() {
|
||||||
|
Ok(ShowLink::None)
|
||||||
|
} else {
|
||||||
|
Ok(ShowLink::Specific(names))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(ShowLinkVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============= Main Config =============
|
// ============= Main Config =============
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
@@ -339,7 +434,7 @@ pub struct ProxyConfig {
|
|||||||
pub upstreams: Vec<UpstreamConfig>,
|
pub upstreams: Vec<UpstreamConfig>,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub show_link: Vec<String>,
|
pub show_link: ShowLink,
|
||||||
|
|
||||||
/// DC address overrides for non-standard DCs (CDN, media, test, etc.)
|
/// DC address overrides for non-standard DCs (CDN, media, test, etc.)
|
||||||
/// Keys are DC indices as strings, values are "ip:port" addresses.
|
/// Keys are DC indices as strings, values are "ip:port" addresses.
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
if !config.show_link.is_empty() {
|
if !config.show_link.is_empty() {
|
||||||
info!("--- Proxy Links ({}) ---", public_ip);
|
info!("--- Proxy Links ({}) ---", public_ip);
|
||||||
for user_name in &config.show_link {
|
for user_name in config.show_link.resolve_users(&config.access.users) {
|
||||||
if let Some(secret) = config.access.users.get(user_name) {
|
if let Some(secret) = config.access.users.get(user_name) {
|
||||||
info!("User: {}", user_name);
|
info!("User: {}", user_name);
|
||||||
if config.general.modes.classic {
|
if config.general.modes.classic {
|
||||||
|
|||||||
Reference in New Issue
Block a user