整体优化
This commit is contained in:
1 parent
df5d781c2c
commit
04e2945df2
27 files changed
+417
-417
No files matched your search
+7
-9
@@ -8,7 +8,7 @@ SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service"
|
||||
OPENRC_FILE="/etc/init.d/$SERVICE_NAME"
|
||||
|
||||
usage() {
|
||||
echo "Usage: agent.sh -e ENDPOINT -t TOKEN -s SERVER_ID [-i 60]"
|
||||
echo "Usage: agent.sh -e ENDPOINT -t TOKEN [-i 60]"
|
||||
echo " agent.sh --uninstall"
|
||||
echo " agent.sh --status"
|
||||
}
|
||||
@@ -66,7 +66,6 @@ install_agent() {
|
||||
[ "$(id -u)" -eq 0 ] || { echo "Run install as root" >&2; exit 1; }
|
||||
ensure_curl
|
||||
command -v sha256sum >/dev/null || { echo "sha256sum is required" >&2; exit 1; }
|
||||
server_id=""
|
||||
token=""
|
||||
endpoint=""
|
||||
interval=60
|
||||
@@ -74,7 +73,7 @@ install_agent() {
|
||||
while [ "$#" -gt 0 ]; do
|
||||
option="$1"
|
||||
case "$option" in
|
||||
-s|-t|-e|-i)
|
||||
-t|-e|-i)
|
||||
[ "$#" -ge 2 ] || { echo "Missing value for $option" >&2; usage; exit 1; }
|
||||
value="$2"
|
||||
shift 2
|
||||
@@ -82,16 +81,15 @@ install_agent() {
|
||||
*) echo "Unknown argument: $option" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
case "$option" in
|
||||
-s) [ -z "$server_id" ] || { echo "Duplicate argument: $option" >&2; exit 1; }; server_id="$value" ;;
|
||||
-t) [ -z "$token" ] || { echo "Duplicate argument: $option" >&2; exit 1; }; token="$value" ;;
|
||||
-e) [ -z "$endpoint" ] || { echo "Duplicate argument: $option" >&2; exit 1; }; endpoint="$value" ;;
|
||||
-i) [ "$interval_set" = false ] || { echo "Duplicate argument: $option" >&2; exit 1; }; interval="$value"; interval_set=true ;;
|
||||
esac
|
||||
done
|
||||
[ -n "$server_id" ] && [ -n "$token" ] && [ -n "$endpoint" ] || { usage; exit 1; }
|
||||
[ -n "$token" ] && [ -n "$endpoint" ] || { usage; exit 1; }
|
||||
endpoint=${endpoint%/}
|
||||
[ ${#server_id} -le 160 ] && [ ${#token} -le 512 ] && [ ${#endpoint} -le 2048 ] || { echo "Install argument is too long" >&2; exit 1; }
|
||||
safe_value "$server_id" && safe_value "$token" && safe_value "$endpoint" || { echo "Invalid install argument" >&2; exit 1; }
|
||||
[ ${#token} -le 512 ] && [ ${#endpoint} -le 2048 ] || { echo "Install argument is too long" >&2; exit 1; }
|
||||
safe_value "$token" && safe_value "$endpoint" || { echo "Invalid install argument" >&2; exit 1; }
|
||||
case "$endpoint" in
|
||||
https://?*|http://localhost|http://localhost/*|http://localhost:*|http://127.0.0.1|http://127.0.0.1/*|http://127.0.0.1:*) ;;
|
||||
*) echo "Worker URL must use HTTPS; HTTP is only allowed for loopback development" >&2; exit 1 ;;
|
||||
@@ -171,7 +169,7 @@ install_agent() {
|
||||
'' \
|
||||
'[Service]' \
|
||||
'Type=simple' \
|
||||
"ExecStart=$AGENT_FILE -e $endpoint -t $token -s $server_id -i $interval" \
|
||||
"ExecStart=$AGENT_FILE -e $endpoint -t $token -i $interval" \
|
||||
'Restart=always' \
|
||||
'RestartSec=10' \
|
||||
'NoNewPrivileges=true' \
|
||||
@@ -194,7 +192,7 @@ install_agent() {
|
||||
'#!/sbin/openrc-run' \
|
||||
"name=\"$SERVICE_NAME\"" \
|
||||
"command=\"$AGENT_FILE\"" \
|
||||
"command_args=\"-e $endpoint -t $token -s $server_id -i $interval\"" \
|
||||
"command_args=\"-e $endpoint -t $token -i $interval\"" \
|
||||
"command_user=\"root\"" \
|
||||
"supervisor=\"supervise-daemon\"" \
|
||||
"respawn_delay=10" \
|
||||
|
||||
@@ -27,7 +27,7 @@ if [ "${1:-}" = "--status" ]; then
|
||||
fi
|
||||
|
||||
[ "${1:-}" != "-h" ] && [ "${1:-}" != "--help" ] && [ "$#" -gt 0 ] || {
|
||||
echo "Usage: install-macos.sh -e ENDPOINT -t TOKEN -s SERVER_ID [-i 60]"
|
||||
echo "Usage: install-macos.sh -e ENDPOINT -t TOKEN [-i 60]"
|
||||
echo " install-macos.sh --uninstall|--status"
|
||||
exit 0
|
||||
}
|
||||
@@ -35,7 +35,6 @@ fi
|
||||
[ "$(uname -m)" = "arm64" ] || { echo "Only Apple Silicon (arm64) is supported" >&2; exit 1; }
|
||||
command -v curl >/dev/null || { echo "curl is required" >&2; exit 1; }
|
||||
command -v shasum >/dev/null || { echo "shasum is required" >&2; exit 1; }
|
||||
server_id=""
|
||||
token=""
|
||||
endpoint=""
|
||||
interval=60
|
||||
@@ -43,7 +42,7 @@ interval_set=false
|
||||
while [ "$#" -gt 0 ]; do
|
||||
option="$1"
|
||||
case "$option" in
|
||||
-s|-t|-e|-i)
|
||||
-t|-e|-i)
|
||||
[ "$#" -ge 2 ] || { echo "Missing value for $option" >&2; exit 1; }
|
||||
value="$2"
|
||||
shift 2
|
||||
@@ -51,16 +50,15 @@ while [ "$#" -gt 0 ]; do
|
||||
*) echo "Unknown argument: $option" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$option" in
|
||||
-s) [ -z "$server_id" ] || { echo "Duplicate argument: $option" >&2; exit 1; }; server_id="$value" ;;
|
||||
-t) [ -z "$token" ] || { echo "Duplicate argument: $option" >&2; exit 1; }; token="$value" ;;
|
||||
-e) [ -z "$endpoint" ] || { echo "Duplicate argument: $option" >&2; exit 1; }; endpoint="$value" ;;
|
||||
-i) [ "$interval_set" = false ] || { echo "Duplicate argument: $option" >&2; exit 1; }; interval="$value"; interval_set=true ;;
|
||||
esac
|
||||
done
|
||||
[ -n "$server_id" ] && [ -n "$token" ] && [ -n "$endpoint" ] || { echo "Missing required argument" >&2; exit 1; }
|
||||
[ -n "$token" ] && [ -n "$endpoint" ] || { echo "Missing required argument" >&2; exit 1; }
|
||||
endpoint=${endpoint%/}
|
||||
[ ${#server_id} -le 160 ] && [ ${#token} -le 512 ] && [ ${#endpoint} -le 2048 ] || { echo "Install argument is too long" >&2; exit 1; }
|
||||
safe_value "$server_id" && safe_value "$token" && safe_value "$endpoint" || { echo "Invalid argument" >&2; exit 1; }
|
||||
[ ${#token} -le 512 ] && [ ${#endpoint} -le 2048 ] || { echo "Install argument is too long" >&2; exit 1; }
|
||||
safe_value "$token" && safe_value "$endpoint" || { echo "Invalid argument" >&2; exit 1; }
|
||||
case "$endpoint" in
|
||||
https://?*|http://localhost|http://localhost/*|http://localhost:*|http://127.0.0.1|http://127.0.0.1/*|http://127.0.0.1:*) ;;
|
||||
*) echo "Worker URL must use HTTPS; HTTP is only allowed for loopback development" >&2; exit 1 ;;
|
||||
@@ -117,7 +115,7 @@ cat > "$PLIST_FILE" <<EOF
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0"><dict>
|
||||
<key>Label</key><string>$LABEL</string>
|
||||
<key>ProgramArguments</key><array><string>$AGENT_FILE</string><string>-e</string><string>$endpoint</string><string>-t</string><string>$token</string><string>-s</string><string>$server_id</string><string>-i</string><string>$interval</string></array>
|
||||
<key>ProgramArguments</key><array><string>$AGENT_FILE</string><string>-e</string><string>$endpoint</string><string>-t</string><string>$token</string><string>-i</string><string>$interval</string></array>
|
||||
<key>KeepAlive</key><true/><key>RunAtLoad</key><true/>
|
||||
<key>StandardOutPath</key><string>/var/log/nodeflare-agent.log</string>
|
||||
<key>StandardErrorPath</key><string>/var/log/nodeflare-agent.log</string>
|
||||
|
||||
+2
-5
@@ -1,6 +1,5 @@
|
||||
[CmdletBinding(DefaultParameterSetName = "Install")]
|
||||
param(
|
||||
[Parameter(ParameterSetName = "Install", Mandatory = $true)][Alias("s")][string]$ServerId,
|
||||
[Parameter(ParameterSetName = "Install", Mandatory = $true)][Alias("t")][string]$Token,
|
||||
[Parameter(ParameterSetName = "Install", Mandatory = $true)][Alias("e")][string]$Endpoint,
|
||||
[Parameter(ParameterSetName = "Install")][Alias("i")][ValidateRange(15, 3600)][int]$Interval = 60,
|
||||
@@ -65,12 +64,10 @@ $NativeArchitecture = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW
|
||||
if ($NativeArchitecture -ne "AMD64") {
|
||||
throw "Only Windows x86_64 is supported"
|
||||
}
|
||||
Assert-Safe "ServerId" $ServerId
|
||||
Assert-Safe "Token" $Token
|
||||
Assert-Endpoint $Endpoint
|
||||
$ServerIdLength = $ServerId.Length
|
||||
$TokenLength = $Token.Length
|
||||
if ($ServerIdLength -gt 160 -or $TokenLength -gt 512) {
|
||||
if ($TokenLength -gt 512) {
|
||||
throw "Install argument is too long"
|
||||
}
|
||||
$Endpoint = $Endpoint.TrimEnd('/')
|
||||
@@ -112,7 +109,7 @@ try {
|
||||
Remove-Item -LiteralPath $Temporary -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
$TaskArguments = "-e $Endpoint -t $Token -s $ServerId -i $Interval"
|
||||
$TaskArguments = "-e $Endpoint -t $Token -i $Interval"
|
||||
$TaskAction = New-ScheduledTaskAction -Execute $AgentFile -Argument $TaskArguments
|
||||
$Trigger = New-ScheduledTaskTrigger -AtStartup
|
||||
$Settings = New-ScheduledTaskSettingsSet -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit (New-TimeSpan -Days 3650)
|
||||
|
||||
+36
-42
@@ -46,7 +46,6 @@ type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RuntimeConfig {
|
||||
server_id: String,
|
||||
token: String,
|
||||
endpoint: String,
|
||||
report_interval: u64,
|
||||
@@ -65,9 +64,6 @@ struct CliOptions {
|
||||
/// Agent token
|
||||
#[arg(short = 't', value_name = "TOKEN")]
|
||||
token: String,
|
||||
/// Server ID
|
||||
#[arg(short = 's', value_name = "ID")]
|
||||
server_id: String,
|
||||
/// Initial report interval in seconds (15-3600)
|
||||
#[arg(short = 'i', value_name = "SECONDS", default_value_t = 60)]
|
||||
interval: u64,
|
||||
@@ -86,6 +82,7 @@ struct LatencyTask {
|
||||
name: String,
|
||||
task_type: String,
|
||||
target: String,
|
||||
port: Option<i64>,
|
||||
interval_seconds: u64,
|
||||
}
|
||||
|
||||
@@ -194,7 +191,6 @@ struct SubmitResult {
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct ReportBatch<'a> {
|
||||
server_id: &'a str,
|
||||
samples: &'a [Report],
|
||||
}
|
||||
|
||||
@@ -561,7 +557,7 @@ fn resolve_public_probe_address(host: &str, port: u16) -> Option<SocketAddr> {
|
||||
.copied()
|
||||
}
|
||||
|
||||
fn parse_probe_target(value: &str) -> Option<(String, u16)> {
|
||||
fn parse_probe_target(value: &str, port: Option<u16>) -> Option<(String, u16)> {
|
||||
let raw = value.trim();
|
||||
if raw.is_empty()
|
||||
|| raw.len() > 60
|
||||
@@ -569,14 +565,12 @@ fn parse_probe_target(value: &str) -> Option<(String, u16)> {
|
||||
|| raw
|
||||
.chars()
|
||||
.any(|character| character.is_whitespace() || "/@?#\\[]".contains(character))
|
||||
|| raw.matches(':').count() > 1
|
||||
|| raw.contains(':')
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let (host, port) = raw.split_once(':').map_or((raw, 443), |(host, port)| {
|
||||
(host, port.parse::<u16>().unwrap_or(0))
|
||||
});
|
||||
(port > 0 && valid_probe_host(host)).then(|| (host.to_ascii_lowercase(), port))
|
||||
let port = port.unwrap_or(443);
|
||||
(port > 0 && valid_probe_host(raw)).then(|| (raw.to_ascii_lowercase(), port))
|
||||
}
|
||||
|
||||
fn median(values: &mut [f64]) -> f64 {
|
||||
@@ -589,11 +583,14 @@ fn median(values: &mut [f64]) -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
fn tcp_latency_probe(target: &str) -> (f64, f64) {
|
||||
fn tcp_latency_probe(target: &str, port: Option<i64>) -> (f64, f64) {
|
||||
if target.trim().is_empty() {
|
||||
return (-1.0, -1.0);
|
||||
}
|
||||
let Some((host, port)) = parse_probe_target(target) else {
|
||||
let Some(port) = port.and_then(|value| u16::try_from(value).ok()) else {
|
||||
return (-1.0, 100.0);
|
||||
};
|
||||
let Some((host, port)) = parse_probe_target(target, Some(port)) else {
|
||||
return (-1.0, 100.0);
|
||||
};
|
||||
let Some(address) = resolve_public_probe_address(&host, port) else {
|
||||
@@ -635,10 +632,7 @@ fn ping_latency(output: &str) -> Option<f64> {
|
||||
|
||||
fn icmp_latency_probe(target: &str) -> (f64, f64) {
|
||||
let host = target.trim();
|
||||
if host.contains(':') {
|
||||
return (-1.0, 100.0);
|
||||
}
|
||||
let Some((host, _)) = parse_probe_target(host) else {
|
||||
let Some((host, _)) = parse_probe_target(host, None) else {
|
||||
return (-1.0, 100.0);
|
||||
};
|
||||
let Some(address) = resolve_public_probe_address(&host, 443) else {
|
||||
@@ -683,7 +677,7 @@ fn unix_timestamp() -> i64 {
|
||||
|
||||
fn execute_latency_task(task: LatencyTask) -> LatencyResult {
|
||||
let (latency_ms, packet_loss) = match task.task_type.as_str() {
|
||||
"tcp" => tcp_latency_probe(&task.target),
|
||||
"tcp" => tcp_latency_probe(&task.target, task.port),
|
||||
"icmp" => icmp_latency_probe(&task.target),
|
||||
_ => (-1.0, 100.0),
|
||||
};
|
||||
@@ -1121,17 +1115,10 @@ fn runtime_config(options: &CliOptions) -> Result<RuntimeConfig> {
|
||||
if !(15..=3600).contains(&interval) {
|
||||
return Err("interval must be between 15 and 3600 seconds".into());
|
||||
}
|
||||
let server_id = options.server_id.clone();
|
||||
let token = options.token.clone();
|
||||
let endpoint = options.endpoint.clone();
|
||||
if server_id.is_empty()
|
||||
|| token.is_empty()
|
||||
|| server_id.len() > 160
|
||||
|| token.len() > 512
|
||||
|| server_id.chars().any(char::is_whitespace)
|
||||
|| token.chars().any(char::is_whitespace)
|
||||
{
|
||||
return Err("server ID or token is invalid".into());
|
||||
if token.is_empty() || token.len() > 512 || token.chars().any(char::is_whitespace) {
|
||||
return Err("token is invalid".into());
|
||||
}
|
||||
if !valid_endpoint(&endpoint) {
|
||||
return Err(
|
||||
@@ -1139,7 +1126,6 @@ fn runtime_config(options: &CliOptions) -> Result<RuntimeConfig> {
|
||||
);
|
||||
}
|
||||
Ok(RuntimeConfig {
|
||||
server_id,
|
||||
token,
|
||||
endpoint: endpoint.trim_end_matches('/').to_string(),
|
||||
report_interval: interval,
|
||||
@@ -1156,10 +1142,7 @@ fn submit(
|
||||
reports: &[Report],
|
||||
config_hash: &str,
|
||||
) -> Result<SubmitResult> {
|
||||
let batch = ReportBatch {
|
||||
server_id: &config.server_id,
|
||||
samples: reports,
|
||||
};
|
||||
let batch = ReportBatch { samples: reports };
|
||||
let mut response = agent
|
||||
.post(&format!("{}/api/agent/report", config.endpoint))
|
||||
.header("Authorization", format!("Bearer {}", config.token))
|
||||
@@ -1210,9 +1193,10 @@ fn sanitize_latency_tasks(tasks: &[LatencyTask]) -> Vec<LatencyTask> {
|
||||
&& (1..=80).contains(&task.name.trim().chars().count())
|
||||
&& (30..=3600).contains(&task.interval_seconds)
|
||||
&& matches!(task.task_type.as_str(), "tcp" | "icmp")
|
||||
&& parse_probe_target(&task.target).is_some_and(|(_, port)| {
|
||||
task.task_type == "tcp" || (port == 443 && !task.target.contains(':'))
|
||||
})
|
||||
&& ((task.task_type == "tcp"
|
||||
&& task.port.is_some_and(|port| (1..=65535).contains(&port)))
|
||||
|| (task.task_type == "icmp" && task.port.is_none()))
|
||||
&& parse_probe_target(&task.target, None).is_some()
|
||||
&& seen.insert(task.id.clone())
|
||||
})
|
||||
.take(MAX_LATENCY_TASKS)
|
||||
@@ -1717,8 +1701,6 @@ mod tests {
|
||||
"https://monitor.example.com",
|
||||
"-t",
|
||||
"secret",
|
||||
"-s",
|
||||
"server-a",
|
||||
"-i",
|
||||
"60",
|
||||
"--once",
|
||||
@@ -1726,11 +1708,20 @@ mod tests {
|
||||
.unwrap();
|
||||
assert_eq!(parsed.endpoint, "https://monitor.example.com");
|
||||
assert_eq!(parsed.token, "secret");
|
||||
assert_eq!(parsed.server_id, "server-a");
|
||||
assert_eq!(parsed.interval, 60);
|
||||
assert!(parsed.once);
|
||||
assert!(CliOptions::try_parse_from(["nodeflare", "-t"]).is_err());
|
||||
assert!(CliOptions::try_parse_from(["nodeflare", "-t", "first", "-t", "second"]).is_err());
|
||||
assert!(CliOptions::try_parse_from([
|
||||
"nodeflare",
|
||||
"-e",
|
||||
"https://monitor.example.com",
|
||||
"-t",
|
||||
"secret",
|
||||
"-s",
|
||||
"server-a",
|
||||
])
|
||||
.is_err());
|
||||
assert!(CliOptions::try_parse_from(["nodeflare", "--once", "--collect"]).is_err());
|
||||
}
|
||||
|
||||
@@ -1740,7 +1731,8 @@ mod tests {
|
||||
id: "task-1".to_string(),
|
||||
name: "Cloudflare".to_string(),
|
||||
task_type: "tcp".to_string(),
|
||||
target: "1.1.1.1:443".to_string(),
|
||||
target: "1.1.1.1".to_string(),
|
||||
port: Some(443),
|
||||
interval_seconds: 60,
|
||||
};
|
||||
let mut tasks = vec![valid.clone(), valid];
|
||||
@@ -1749,6 +1741,7 @@ mod tests {
|
||||
name: "Bad".to_string(),
|
||||
task_type: "http".to_string(),
|
||||
target: "https://example.com".to_string(),
|
||||
port: Some(443),
|
||||
interval_seconds: 1,
|
||||
});
|
||||
for index in 2..=MAX_LATENCY_TASKS + 10 {
|
||||
@@ -1757,6 +1750,7 @@ mod tests {
|
||||
name: format!("Task {index}"),
|
||||
task_type: "icmp".to_string(),
|
||||
target: "1.1.1.1".to_string(),
|
||||
port: None,
|
||||
interval_seconds: 60,
|
||||
});
|
||||
}
|
||||
@@ -1844,11 +1838,11 @@ mod tests {
|
||||
#[test]
|
||||
fn parses_probe_targets() {
|
||||
assert_eq!(
|
||||
parse_probe_target("Example.COM"),
|
||||
parse_probe_target("Example.COM", None),
|
||||
Some(("example.com".to_string(), 443))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_probe_target("1.1.1.1:8080"),
|
||||
parse_probe_target("1.1.1.1", Some(8080)),
|
||||
Some(("1.1.1.1".to_string(), 8080))
|
||||
);
|
||||
for target in [
|
||||
@@ -1865,7 +1859,7 @@ mod tests {
|
||||
"[::1]:443",
|
||||
"bad host",
|
||||
] {
|
||||
assert_eq!(parse_probe_target(target), None, "target: {target}");
|
||||
assert_eq!(parse_probe_target(target, None), None, "target: {target}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user