mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-23 03:29:58 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edc0107fc8 | ||
|
|
00957e5f9d | ||
|
|
bfa3383aaa | ||
|
|
73bea01f40 | ||
|
|
0378191783 | ||
|
|
d5fa6a608d |
@@ -42,4 +42,7 @@ EXPOSE 11011/tcp
|
||||
# wss
|
||||
EXPOSE 11012/tcp
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=5 \
|
||||
CMD ["/usr/local/bin/easytier-cli", "--rpc-portal", "127.0.0.1:15888", "--output", "json", "node", "info"]
|
||||
|
||||
ENTRYPOINT ["/sbin/tini", "--", "easytier-core"]
|
||||
|
||||
Generated
+1
-1
@@ -4623,7 +4623,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kcp-sys"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/EasyTier/kcp-sys?rev=94964794caaed5d388463137da59b97499619e5f#94964794caaed5d388463137da59b97499619e5f"
|
||||
source = "git+https://github.com/EasyTier/kcp-sys?rev=d7427c22d764deb1860a7d37acc446ed5033464c#d7427c22d764deb1860a7d37acc446ed5033464c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto_impl",
|
||||
|
||||
@@ -99,7 +99,7 @@ while true; do
|
||||
# 启动后的扫尾工作
|
||||
if pgrep -f "${EASYTIER}" >/dev/null; then
|
||||
|
||||
if ! ip rule show | grep -q "lookup main"; then
|
||||
if ! ip rule show | grep -qE '^[0-9]+:[[:space:]]+from all lookup main$'; then
|
||||
ip rule add from all lookup main
|
||||
fi
|
||||
|
||||
@@ -109,4 +109,4 @@ while true; do
|
||||
fi
|
||||
|
||||
sleep 10s
|
||||
done
|
||||
done
|
||||
|
||||
+54
-25
@@ -156,6 +156,17 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
@@ -655,6 +666,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.3.1"
|
||||
@@ -1181,7 +1201,6 @@ dependencies = [
|
||||
"derivative",
|
||||
"derive_builder",
|
||||
"derive_more",
|
||||
"easytier-rpc-build",
|
||||
"encoding",
|
||||
"flume",
|
||||
"forwarded-header-value",
|
||||
@@ -1205,6 +1224,7 @@ dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"kcp-sys",
|
||||
"machine-uid",
|
||||
"moka",
|
||||
"multimap",
|
||||
"natpmp",
|
||||
"netlink-packet-core",
|
||||
@@ -1222,6 +1242,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"pnet",
|
||||
"prefix-trie",
|
||||
"proc-macro2",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"prost-reflect",
|
||||
@@ -1231,6 +1252,7 @@ dependencies = [
|
||||
"prost-wkt-types",
|
||||
"quinn",
|
||||
"quinn-plaintext",
|
||||
"quote",
|
||||
"rand 0.8.5",
|
||||
"rcgen",
|
||||
"regex",
|
||||
@@ -1263,7 +1285,6 @@ dependencies = [
|
||||
"tokio-util",
|
||||
"tokio-websockets",
|
||||
"toml",
|
||||
"tonic-build",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tun-easytier",
|
||||
@@ -1311,14 +1332,6 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "easytier-rpc-build"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"prost-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
@@ -1469,6 +1482,27 @@ dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
@@ -2561,7 +2595,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kcp-sys"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/EasyTier/kcp-sys?rev=94964794caaed5d388463137da59b97499619e5f#94964794caaed5d388463137da59b97499619e5f"
|
||||
source = "git+https://github.com/EasyTier/kcp-sys?rev=d7427c22d764deb1860a7d37acc446ed5033464c#d7427c22d764deb1860a7d37acc446ed5033464c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto_impl",
|
||||
@@ -2817,9 +2851,12 @@ version = "0.12.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"event-listener",
|
||||
"futures-util",
|
||||
"loom",
|
||||
"parking_lot",
|
||||
"portable-atomic",
|
||||
@@ -3236,6 +3273,12 @@ dependencies = [
|
||||
"unicode-width 0.1.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.4"
|
||||
@@ -4991,20 +5034,6 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "tonic-build"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11"
|
||||
dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"prost-build",
|
||||
"prost-types",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::config::types::stored_config::{StoredConfigList, StoredConfigMeta};
|
||||
use ohos_hilog_binding::{hilog_debug, hilog_error};
|
||||
use rusqlite::{Connection, OptionalExtension, params};
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Mutex;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
@@ -101,6 +101,110 @@ fn load_meta_record(conn: &Connection, config_id: &str) -> Option<StoredConfigMe
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn validate_snapshot_schema(conn: &Connection) -> bool {
|
||||
let has_stored_configs = conn
|
||||
.query_row(
|
||||
"SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'stored_configs'",
|
||||
[],
|
||||
|row| row.get::<_, i64>(0),
|
||||
)
|
||||
.optional()
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_some();
|
||||
let has_stored_fields = conn
|
||||
.query_row(
|
||||
"SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'stored_config_fields'",
|
||||
[],
|
||||
|row| row.get::<_, i64>(0),
|
||||
)
|
||||
.optional()
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_some();
|
||||
has_stored_configs && has_stored_fields
|
||||
}
|
||||
|
||||
fn copy_snapshot_tables(src: &Connection, dst: &mut Connection) -> rusqlite::Result<()> {
|
||||
let mut meta_rows = Vec::<StoredConfigMetaRecord>::new();
|
||||
{
|
||||
let mut stmt = src.prepare(
|
||||
"SELECT config_id, display_name, created_at, updated_at, favorite, temporary
|
||||
FROM stored_configs",
|
||||
)?;
|
||||
let rows = stmt.query_map([], row_to_meta)?;
|
||||
for row in rows {
|
||||
meta_rows.push(row?);
|
||||
}
|
||||
}
|
||||
|
||||
let mut field_rows = Vec::<(String, String, String, String)>::new();
|
||||
{
|
||||
let mut stmt = src.prepare(
|
||||
"SELECT config_id, field_name, field_json, updated_at
|
||||
FROM stored_config_fields",
|
||||
)?;
|
||||
let rows = stmt.query_map([], |row| {
|
||||
Ok((
|
||||
row.get::<_, String>(0)?,
|
||||
row.get::<_, String>(1)?,
|
||||
row.get::<_, String>(2)?,
|
||||
row.get::<_, String>(3)?,
|
||||
))
|
||||
})?;
|
||||
for row in rows {
|
||||
field_rows.push(row?);
|
||||
}
|
||||
}
|
||||
|
||||
let tx = dst.unchecked_transaction()?;
|
||||
tx.execute("DELETE FROM stored_config_fields", [])?;
|
||||
tx.execute("DELETE FROM stored_configs", [])?;
|
||||
|
||||
for row in meta_rows {
|
||||
tx.execute(
|
||||
"INSERT INTO stored_configs (
|
||||
config_id, display_name, created_at, updated_at, favorite, temporary
|
||||
) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
|
||||
params![
|
||||
row.config_id,
|
||||
row.display_name,
|
||||
row.created_at,
|
||||
row.updated_at,
|
||||
if row.favorite { 1 } else { 0 },
|
||||
if row.temporary { 1 } else { 0 }
|
||||
],
|
||||
)?;
|
||||
}
|
||||
|
||||
for (config_id, field_name, field_json, updated_at) in field_rows {
|
||||
tx.execute(
|
||||
"INSERT INTO stored_config_fields (config_id, field_name, field_json, updated_at)
|
||||
VALUES (?1, ?2, ?3, ?4)",
|
||||
params![config_id, field_name, field_json, updated_at],
|
||||
)?;
|
||||
}
|
||||
|
||||
tx.commit()
|
||||
}
|
||||
|
||||
fn ensure_parent_dir(path: &Path) -> bool {
|
||||
match path.parent() {
|
||||
Some(parent) => match std::fs::create_dir_all(parent) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
hilog_error!(
|
||||
"[Rust] failed to create snapshot parent {}: {}",
|
||||
parent.display(),
|
||||
e
|
||||
);
|
||||
false
|
||||
}
|
||||
},
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_meta(record: StoredConfigMetaRecord) -> StoredConfigMeta {
|
||||
StoredConfigMeta {
|
||||
config_id: record.config_id,
|
||||
@@ -142,6 +246,79 @@ pub fn init_config_meta_store(root_dir: String) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn export_config_store_snapshot(target_path: String) -> bool {
|
||||
let target = PathBuf::from(target_path);
|
||||
if !ensure_parent_dir(&target) {
|
||||
return false;
|
||||
}
|
||||
let Some(src) = open_db() else {
|
||||
return false;
|
||||
};
|
||||
let mut dst = match Connection::open(&target) {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => {
|
||||
hilog_error!(
|
||||
"[Rust] failed to open snapshot target {}: {}",
|
||||
target.display(),
|
||||
e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
if let Err(e) = init_schema(&dst) {
|
||||
hilog_error!(
|
||||
"[Rust] failed to init snapshot schema {}: {}",
|
||||
target.display(),
|
||||
e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
match copy_snapshot_tables(&src, &mut dst) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
hilog_error!(
|
||||
"[Rust] failed to export snapshot {}: {}",
|
||||
target.display(),
|
||||
e
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import_config_store_snapshot(source_path: String) -> bool {
|
||||
let source = PathBuf::from(source_path);
|
||||
let src = match Connection::open(&source) {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => {
|
||||
hilog_error!(
|
||||
"[Rust] failed to open snapshot source {}: {}",
|
||||
source.display(),
|
||||
e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
if !validate_snapshot_schema(&src) {
|
||||
hilog_error!("[Rust] invalid snapshot schema {}", source.display());
|
||||
return false;
|
||||
}
|
||||
let Some(mut dst) = open_db() else {
|
||||
return false;
|
||||
};
|
||||
match copy_snapshot_tables(&src, &mut dst) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
hilog_error!(
|
||||
"[Rust] failed to import snapshot {}: {}",
|
||||
source.display(),
|
||||
e
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_config_meta_entries() -> StoredConfigList {
|
||||
let Some(conn) = open_db() else {
|
||||
return StoredConfigList { configs: vec![] };
|
||||
|
||||
@@ -44,3 +44,11 @@ pub(crate) fn import_toml(toml_text: String, display_name: Option<String>) -> Op
|
||||
pub(crate) fn export_toml(config_id: String) -> Option<String> {
|
||||
config::repository::export_config_toml(&config_id).map(|ret| ret.toml_text)
|
||||
}
|
||||
|
||||
pub(crate) fn export_config_store_snapshot(target_path: String) -> bool {
|
||||
config::storage::config_meta::export_config_store_snapshot(target_path)
|
||||
}
|
||||
|
||||
pub(crate) fn import_config_store_snapshot(source_path: String) -> bool {
|
||||
config::storage::config_meta::import_config_store_snapshot(source_path)
|
||||
}
|
||||
|
||||
@@ -363,6 +363,16 @@ pub fn export_toml(config_id: String) -> Option<String> {
|
||||
exports::config_api::export_toml(config_id)
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn export_config_store_snapshot(target_path: String) -> bool {
|
||||
exports::config_api::export_config_store_snapshot(target_path)
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn import_config_store_snapshot(source_path: String) -> bool {
|
||||
exports::config_api::import_config_store_snapshot(source_path)
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn start_kernel(config_id: String) -> bool {
|
||||
exports::runtime_api::start_kernel(config_id, start_kernel_with_config_id)
|
||||
|
||||
@@ -53,6 +53,7 @@ clap = { version = "4.4.8", features = [
|
||||
"unicode",
|
||||
"derive",
|
||||
"wrap_help",
|
||||
"env",
|
||||
] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
@@ -41,23 +41,32 @@ rust_i18n::i18n!("locales", fallback = "en");
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "easytier-web", author, version = EASYTIER_VERSION , about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short, long, default_value = "et.db", help = t!("cli.db").to_string())]
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
env = "ET_WEB_DB",
|
||||
default_value = "et.db",
|
||||
help = t!("cli.db").to_string()
|
||||
)]
|
||||
db: String,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_WEB_CONSOLE_LOG_LEVEL",
|
||||
help = t!("cli.console_log_level").to_string(),
|
||||
)]
|
||||
console_log_level: Option<String>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_WEB_FILE_LOG_LEVEL",
|
||||
help = t!("cli.file_log_level").to_string(),
|
||||
)]
|
||||
file_log_level: Option<String>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_WEB_FILE_LOG_DIR",
|
||||
help = t!("cli.file_log_dir").to_string(),
|
||||
)]
|
||||
file_log_dir: Option<String>,
|
||||
@@ -65,6 +74,7 @@ struct Cli {
|
||||
#[arg(
|
||||
long,
|
||||
short='c',
|
||||
env = "ET_CONFIG_SERVER_PORT",
|
||||
default_value = "22020",
|
||||
help = t!("cli.config_server_port").to_string(),
|
||||
)]
|
||||
@@ -73,6 +83,7 @@ struct Cli {
|
||||
#[arg(
|
||||
long,
|
||||
short='p',
|
||||
env = "ET_CONFIG_SERVER_PROTOCOL",
|
||||
default_value = "udp",
|
||||
help = t!("cli.config_server_protocol").to_string(),
|
||||
)]
|
||||
@@ -81,6 +92,7 @@ struct Cli {
|
||||
#[arg(
|
||||
long,
|
||||
short='a',
|
||||
env = "ET_API_SERVER_PORT",
|
||||
default_value = "11211",
|
||||
help = t!("cli.api_server_port").to_string(),
|
||||
)]
|
||||
@@ -88,6 +100,7 @@ struct Cli {
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_API_SERVER_ADDR",
|
||||
default_value = "0.0.0.0",
|
||||
help = t!("cli.api_server_addr").to_string(),
|
||||
)]
|
||||
@@ -95,6 +108,7 @@ struct Cli {
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_GEOIP_DB",
|
||||
help = t!("cli.geoip_db").to_string(),
|
||||
)]
|
||||
geoip_db: Option<String>,
|
||||
@@ -103,6 +117,7 @@ struct Cli {
|
||||
#[arg(
|
||||
long,
|
||||
short='l',
|
||||
env = "ET_WEB_SERVER_PORT",
|
||||
help = t!("cli.web_server_port").to_string(),
|
||||
)]
|
||||
web_server_port: Option<u16>,
|
||||
@@ -110,6 +125,7 @@ struct Cli {
|
||||
#[cfg(feature = "embed")]
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_WEB_SERVER_ADDR",
|
||||
default_value = "0.0.0.0",
|
||||
help = t!("cli.web_server_addr").to_string(),
|
||||
)]
|
||||
@@ -118,6 +134,7 @@ struct Cli {
|
||||
#[cfg(feature = "embed")]
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_NO_WEB",
|
||||
help = t!("cli.no_web").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
@@ -126,6 +143,7 @@ struct Cli {
|
||||
#[cfg(feature = "embed")]
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_API_HOST",
|
||||
help = t!("cli.api_host").to_string()
|
||||
)]
|
||||
api_host: Option<url::Url>,
|
||||
@@ -144,35 +162,45 @@ struct Cli {
|
||||
pub struct WebhookOptions {
|
||||
/// Base URL of the webhook endpoint for token validation and event delivery.
|
||||
/// When set, incoming tokens are validated via this webhook before local fallback.
|
||||
#[arg(long)]
|
||||
#[arg(long, env = "ET_WEBHOOK_URL")]
|
||||
pub webhook_url: Option<String>,
|
||||
|
||||
/// Shared secret used to authenticate outbound webhook calls.
|
||||
#[arg(long)]
|
||||
#[arg(long, env = "ET_WEBHOOK_SECRET", hide_env_values = true)]
|
||||
pub webhook_secret: Option<String>,
|
||||
|
||||
/// Token for X-Internal-Auth header. When set, API requests with this header
|
||||
/// bypass session authentication.
|
||||
#[arg(long)]
|
||||
#[arg(long, env = "ET_INTERNAL_AUTH_TOKEN", hide_env_values = true)]
|
||||
pub internal_auth_token: Option<String>,
|
||||
|
||||
/// Stable identifier for this easytier-web instance when routing webhook callbacks.
|
||||
#[arg(long)]
|
||||
#[arg(long, env = "ET_WEB_INSTANCE_ID")]
|
||||
pub web_instance_id: Option<String>,
|
||||
|
||||
/// Reachable base URL for this easytier-web instance's internal REST API.
|
||||
#[arg(long)]
|
||||
#[arg(long, env = "ET_WEB_INSTANCE_API_BASE_URL")]
|
||||
pub web_instance_api_base_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, clap::Args)]
|
||||
pub struct FeatureFlags {
|
||||
/// Whether user registration via the web UI is disabled.
|
||||
#[arg(long, default_value = "false", help = t!("cli.disable_registration").to_string())]
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_DISABLE_REGISTRATION",
|
||||
default_value = "false",
|
||||
help = t!("cli.disable_registration").to_string()
|
||||
)]
|
||||
pub disable_registration: bool,
|
||||
|
||||
/// Whether to auto-create users when they connect via heartbeat with an unknown token.
|
||||
#[arg(long, default_value = "false", help = t!("cli.allow_auto_create_user").to_string())]
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_ALLOW_AUTO_CREATE_USER",
|
||||
default_value = "false",
|
||||
help = t!("cli.allow_auto_create_user").to_string()
|
||||
)]
|
||||
pub allow_auto_create_user: bool,
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ service-manager = { git = "https://github.com/EasyTier/service-manager-rs.git",
|
||||
|
||||
zstd = { version = "0.13", optional = true }
|
||||
|
||||
kcp-sys = { git = "https://github.com/EasyTier/kcp-sys", rev = "94964794caaed5d388463137da59b97499619e5f", optional = true }
|
||||
kcp-sys = { git = "https://github.com/EasyTier/kcp-sys", rev = "d7427c22d764deb1860a7d37acc446ed5033464c", optional = true }
|
||||
|
||||
prost-reflect = { version = "0.14.5", default-features = false, features = [
|
||||
"derive",
|
||||
|
||||
Reference in New Issue
Block a user