Рефакторинг кода: дедупликация ucode, исправления shellcheck и глобальное улучшение install.sh

This commit is contained in:
Dushnilin
2026-07-13 22:38:24 +03:00
parent 970ca5c3fe
commit f017d01a52
40 changed files with 455 additions and 971 deletions
+1
View File
@@ -4,6 +4,7 @@ fe-app-tachyon/node_modules
fe-app-tachyon/.yarn/ fe-app-tachyon/.yarn/
fe-app-tachyon/.env fe-app-tachyon/.env
.DS_Store .DS_Store
shellcheck-v0.10.0/
AGENTS.md AGENTS.md
sandbox/ sandbox/
+4 -2
View File
@@ -747,6 +747,7 @@ build_apk_package() {
sudo chown "$(id -u):$(id -g)" "$output_file" sudo chown "$(id -u):$(id -g)" "$output_file"
sudo rm -rf "$temp_root" "$temp_scripts" sudo rm -rf "$temp_root" "$temp_scripts"
elif have_unshare_root; then elif have_unshare_root; then
# shellcheck disable=SC2048,SC2086
unshare -r sh -c " unshare -r sh -c "
chown -R 0:0 '$temp_root' '$temp_scripts' chown -R 0:0 '$temp_root' '$temp_scripts'
'$apk_bin' mkpkg \ '$apk_bin' mkpkg \
@@ -761,7 +762,7 @@ build_apk_package() {
-I 'maintainer:${maintainer}' \ -I 'maintainer:${maintainer}' \
-I 'url:${PROJECT_URL}' \ -I 'url:${PROJECT_URL}' \
-I 'depends:${depends}' \ -I 'depends:${depends}' \
'${extra_args[@]}' \ ${extra_args[*]} \
-s pre-install:'$temp_scripts/${script_prefix}-pre-install.sh' \ -s pre-install:'$temp_scripts/${script_prefix}-pre-install.sh' \
-s post-install:'$temp_scripts/${script_prefix}-post-install.sh' \ -s post-install:'$temp_scripts/${script_prefix}-post-install.sh' \
-s pre-deinstall:'$temp_scripts/${script_prefix}-pre-deinstall.sh' \ -s pre-deinstall:'$temp_scripts/${script_prefix}-pre-deinstall.sh' \
@@ -770,6 +771,7 @@ build_apk_package() {
" "
else else
stderr_file="$(mktemp)" stderr_file="$(mktemp)"
# shellcheck disable=SC2048,SC2086
if ! fakeroot sh -c " if ! fakeroot sh -c "
chown -R 0:0 '$temp_root' '$temp_scripts' chown -R 0:0 '$temp_root' '$temp_scripts'
'$apk_bin' mkpkg \ '$apk_bin' mkpkg \
@@ -784,7 +786,7 @@ build_apk_package() {
-I 'maintainer:${maintainer}' \ -I 'maintainer:${maintainer}' \
-I 'url:${PROJECT_URL}' \ -I 'url:${PROJECT_URL}' \
-I 'depends:${depends}' \ -I 'depends:${depends}' \
'${extra_args[@]}' \ ${extra_args[*]} \
-s pre-install:'$temp_scripts/${script_prefix}-pre-install.sh' \ -s pre-install:'$temp_scripts/${script_prefix}-pre-install.sh' \
-s post-install:'$temp_scripts/${script_prefix}-post-install.sh' \ -s post-install:'$temp_scripts/${script_prefix}-post-install.sh' \
-s pre-deinstall:'$temp_scripts/${script_prefix}-pre-deinstall.sh' \ -s pre-deinstall:'$temp_scripts/${script_prefix}-pre-deinstall.sh' \
+178 -17
View File
@@ -1,6 +1,8 @@
#!/bin/sh #!/bin/sh
# shellcheck shell=dash # shellcheck shell=dash
INSTALLER_VERSION="2.0.0"
REPO_OWNER="Dushnilin" REPO_OWNER="Dushnilin"
REPO_NAME="tachyon" REPO_NAME="tachyon"
@@ -12,6 +14,9 @@ DOWNLOAD_TIMEOUT_SECONDS=600
PKG_IS_APK=0 PKG_IS_APK=0
FETCHER="" FETCHER=""
TMP_DIR="" TMP_DIR=""
LOCK_FILE="/tmp/tachyon.install.lock"
LOG_FILE="/tmp/tachyon-install.log"
START_TIME=""
TACHYON_WAS_ENABLED=0 TACHYON_WAS_ENABLED=0
TACHYON_WAS_RUNNING=0 TACHYON_WAS_RUNNING=0
TACHYON_LEGACY_DETECTED=0 TACHYON_LEGACY_DETECTED=0
@@ -20,6 +25,12 @@ TACHYON_I18N_REQUESTED=0
INSTALLER_LANG="en" INSTALLER_LANG="en"
SING_BOX_INSTALL_VARIANT="" SING_BOX_INSTALL_VARIANT=""
# Runtime flags (see parse_args)
ASSUME_YES=0
DRY_RUN=0
VERBOSE=0
QUIET=0
TACHYON_RELEASE_JSON="" TACHYON_RELEASE_JSON=""
TACHYON_RELEASE_TAG="" TACHYON_RELEASE_TAG=""
TACHYON_BACKEND_URL="" TACHYON_BACKEND_URL=""
@@ -39,22 +50,51 @@ LEGACY_CONFIG_BACKUP=""
command -v apk >/dev/null 2>&1 && PKG_IS_APK=1 command -v apk >/dev/null 2>&1 && PKG_IS_APK=1
log_line() {
# Append a timestamped line to the log file, best-effort (never fatal).
[ -n "$LOG_FILE" ] || return 0
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo '----------------')" "$1" >>"$LOG_FILE" 2>/dev/null || true
}
msg() { msg() {
log_line "INFO $1"
[ "$QUIET" -eq 1 ] && return 0
printf '\033[32;1m%s\033[0m\n' "$1" printf '\033[32;1m%s\033[0m\n' "$1"
} }
warn() { warn() {
printf '\033[33;1m%s\033[0m\n' "$1" log_line "WARN $1"
printf '\033[33;1m%s\033[0m\n' "$1" >&2
} }
fail() { fail() {
log_line "FAIL $1"
printf '\033[31;1m%s\033[0m\n' "$1" >&2 printf '\033[31;1m%s\033[0m\n' "$1" >&2
printf '\033[31;1m%s\033[0m\n' "See $LOG_FILE for details." >&2
exit 1 exit 1
} }
debug() {
log_line "DEBUG $1"
[ "$VERBOSE" -eq 1 ] || return 0
printf '\033[36m[debug] %s\033[0m\n' "$1"
}
step() {
# Announce a top-level installation stage, numbered for clarity.
step_no="$1"
step_total="$2"
step_text="$3"
log_line "STEP [$step_no/$step_total] $step_text"
[ "$QUIET" -eq 1 ] && return 0
printf '\033[34;1m[%s/%s]\033[0m \033[1m%s\033[0m\n' "$step_no" "$step_total" "$step_text"
}
usage() { usage() {
cat <<EOF cat <<EOF
Usage: $0 Tachyon installer v${INSTALLER_VERSION}
Usage: $0 [options]
Installs or updates Tachyon packages: Installs or updates Tachyon packages:
- tachyon - tachyon
@@ -64,6 +104,17 @@ Installs or updates Tachyon packages:
Can also install or switch sing-box variant: Can also install or switch sing-box variant:
- stable sing-box from OpenWrt feeds - stable sing-box from OpenWrt feeds
- sing-box-extended from GitHub OpenWrt packages (for xHTTP support) - sing-box-extended from GitHub OpenWrt packages (for xHTTP support)
Options:
-y, --yes Assume "yes"/default answer for every interactive prompt
-n, --dry-run Resolve versions and show planned actions, but don't
download, install, remove, or modify anything on disk
-v, --verbose Print extra diagnostic detail while installing
-q, --quiet Suppress informational output (errors/warnings still show)
--version Print the installer version and exit
-h, --help Show this help text and exit
Log file: $LOG_FILE
EOF EOF
} }
@@ -74,16 +125,57 @@ parse_args() {
usage usage
exit 0 exit 0
;; ;;
--version)
printf 'tachyon-installer %s\n' "$INSTALLER_VERSION"
exit 0
;;
-y|--yes)
ASSUME_YES=1
;;
-n|--dry-run)
DRY_RUN=1
;;
-v|--verbose)
VERBOSE=1
;;
-q|--quiet)
QUIET=1
;;
*) *)
fail "Unknown installer option: $1" fail "Unknown installer option: $1 (see --help)"
;; ;;
esac esac
shift shift
done done
if [ "$VERBOSE" -eq 1 ] && [ "$QUIET" -eq 1 ]; then
fail "--verbose and --quiet cannot be used together"
fi
}
acquire_lock() {
# Guard against two copies of the installer running at once, which could
# corrupt package state or UCI config. Stale locks (dead PID) are reclaimed.
if [ -f "$LOCK_FILE" ]; then
existing_pid="$(cat "$LOCK_FILE" 2>/dev/null || true)"
if [ -n "$existing_pid" ] && kill -0 "$existing_pid" 2>/dev/null; then
fail "Another instance of the installer appears to be running (pid $existing_pid). Remove $LOCK_FILE if this is incorrect."
fi
debug "Removing stale lock file from pid $existing_pid"
rm -f "$LOCK_FILE"
fi
printf '%s' "$$" >"$LOCK_FILE" 2>/dev/null || true
}
release_lock() {
[ -f "$LOCK_FILE" ] || return 0
lock_pid="$(cat "$LOCK_FILE" 2>/dev/null || true)"
[ "$lock_pid" = "$$" ] && rm -f "$LOCK_FILE"
} }
cleanup() { cleanup() {
[ -n "$TMP_DIR" ] && rm -rf "$TMP_DIR" [ -n "$TMP_DIR" ] && rm -rf "$TMP_DIR"
release_lock
} }
read_openwrt_release_value() { read_openwrt_release_value() {
@@ -617,7 +709,7 @@ function installer_confirm_remove_https_dns_proxy() {
warn("Detected conflicting package: https-dns-proxy\n"); warn("Detected conflicting package: https-dns-proxy\n");
if (run("[ ! -t 0 ]")) { if (truthy(env("TACHYON_INSTALLER_ASSUME_YES", "0")) || run("[ ! -t 0 ]")) {
warn("Remove the conflicting https-dns-proxy package and continue?: 1 (yes, non-interactive)\n"); warn("Remove the conflicting https-dns-proxy package and continue?: 1 (yes, non-interactive)\n");
return true; return true;
} }
@@ -1111,6 +1203,7 @@ install_json_ucode() {
TACHYON_INSTALLER_LEGACY_BRAND="$LEGACY_BRAND" \ TACHYON_INSTALLER_LEGACY_BRAND="$LEGACY_BRAND" \
TACHYON_INSTALLER_LEGACY_BACKEND="$LEGACY_BACKEND_PACKAGE" \ TACHYON_INSTALLER_LEGACY_BACKEND="$LEGACY_BACKEND_PACKAGE" \
TACHYON_INSTALLER_LEGACY_CONFIG_ALT="$LEGACY_CONFIG_PACKAGE_ALT" \ TACHYON_INSTALLER_LEGACY_CONFIG_ALT="$LEGACY_CONFIG_PACKAGE_ALT" \
TACHYON_INSTALLER_ASSUME_YES="$ASSUME_YES" \
ucode "$(install_json_helper_path)" "$@" ucode "$(install_json_helper_path)" "$@"
} }
@@ -1170,6 +1263,11 @@ pkg_is_installed() {
} }
pkg_list_update() { pkg_list_update() {
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would update package lists ($([ "$PKG_IS_APK" -eq 1 ] && echo apk || echo opkg))"
return 0
fi
if [ "$PKG_IS_APK" -eq 1 ]; then if [ "$PKG_IS_APK" -eq 1 ]; then
apk update </dev/null apk update </dev/null
else else
@@ -1180,6 +1278,11 @@ pkg_list_update() {
pkg_install_name() { pkg_install_name() {
pkg_name="$1" pkg_name="$1"
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would install package: $pkg_name"
return 0
fi
if [ "$PKG_IS_APK" -eq 1 ]; then if [ "$PKG_IS_APK" -eq 1 ]; then
apk add "$pkg_name" </dev/null apk add "$pkg_name" </dev/null
else else
@@ -1188,6 +1291,11 @@ pkg_install_name() {
} }
pkg_install_files() { pkg_install_files() {
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would install downloaded package file(s): $*"
return 0
fi
if [ "$PKG_IS_APK" -eq 1 ]; then if [ "$PKG_IS_APK" -eq 1 ]; then
apk add --allow-untrusted "$@" </dev/null apk add --allow-untrusted "$@" </dev/null
else else
@@ -1361,7 +1469,7 @@ numbered_yes_no_prompt() {
prompt_text="$1" prompt_text="$1"
answer="" answer=""
if [ ! -t 0 ]; then if [ "$ASSUME_YES" -eq 1 ] || [ ! -t 0 ]; then
msg "$prompt_text: 1 ($(installer_text yes), non-interactive)" msg "$prompt_text: 1 ($(installer_text yes), non-interactive)"
return 0 return 0
fi fi
@@ -1502,7 +1610,7 @@ select_sing_box_installation() {
return 0 return 0
fi fi
if [ ! -t 0 ]; then if [ "$ASSUME_YES" -eq 1 ] || [ ! -t 0 ]; then
SING_BOX_INSTALL_VARIANT="stable" SING_BOX_INSTALL_VARIANT="stable"
msg "$(installer_text sing_box_prompt): $default_choice ($(installer_text sing_box_stable), non-interactive)" msg "$(installer_text sing_box_prompt): $default_choice ($(installer_text sing_box_stable), non-interactive)"
return 0 return 0
@@ -1552,6 +1660,11 @@ install_selected_sing_box() {
;; ;;
esac esac
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would install sing-box variant: $SING_BOX_INSTALL_VARIANT"
return 0
fi
[ -x /usr/bin/tachyon ] || fail "tachyon backend must be installed before sing-box component action" [ -x /usr/bin/tachyon ] || fail "tachyon backend must be installed before sing-box component action"
msg "Installing selected sing-box variant through Tachyon ucode backend" msg "Installing selected sing-box variant through Tachyon ucode backend"
if ! /usr/bin/tachyon component_action sing_box "$action" >"$output_file" 2>&1; then if ! /usr/bin/tachyon component_action sing_box "$action" >"$output_file" 2>&1; then
@@ -1561,6 +1674,11 @@ install_selected_sing_box() {
} }
cleanup_legacy_installation() { cleanup_legacy_installation() {
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would stop/disable and remove legacy or conflicting packages"
return 0
fi
state_file="$TMP_DIR/install-state.env" state_file="$TMP_DIR/install-state.env"
install_json_ucode installer-cleanup-legacy >"$state_file" || install_json_ucode installer-cleanup-legacy >"$state_file" ||
@@ -1655,6 +1773,11 @@ download_tachyon_packages() {
TACHYON_I18N_FILE="" TACHYON_I18N_FILE=""
TACHYON_SHA256_FILE="$TMP_DIR/sha256sums.txt" TACHYON_SHA256_FILE="$TMP_DIR/sha256sums.txt"
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would download and verify: $TACHYON_BACKEND_NAME, $TACHYON_APP_NAME${TACHYON_I18N_REQUESTED:+$([ "$TACHYON_I18N_REQUESTED" -eq 1 ] && printf ', luci-i18n-tachyon-ru package')}"
return 0
fi
download_with_retry "$TACHYON_SHA256_URL" "$TACHYON_SHA256_FILE" "sha256sums.txt" || fail "Failed to download sha256sums.txt" download_with_retry "$TACHYON_SHA256_URL" "$TACHYON_SHA256_FILE" "sha256sums.txt" || fail "Failed to download sha256sums.txt"
download_with_retry "$TACHYON_BACKEND_URL" "$TACHYON_BACKEND_FILE" "$TACHYON_BACKEND_NAME" || fail "Failed to download $TACHYON_BACKEND_NAME" download_with_retry "$TACHYON_BACKEND_URL" "$TACHYON_BACKEND_FILE" "$TACHYON_BACKEND_NAME" || fail "Failed to download $TACHYON_BACKEND_NAME"
@@ -1692,6 +1815,11 @@ install_backend_package() {
migrate_legacy_configuration() { migrate_legacy_configuration() {
[ "$TACHYON_LEGACY_DETECTED" -eq 1 ] || return 0 [ "$TACHYON_LEGACY_DETECTED" -eq 1 ] || return 0
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would migrate the legacy configuration to Tachyon"
return 0
fi
if [ -n "$LEGACY_CONFIG_BACKUP" ]; then if [ -n "$LEGACY_CONFIG_BACKUP" ]; then
cp "$LEGACY_CONFIG_BACKUP" /etc/config/tachyon || cp "$LEGACY_CONFIG_BACKUP" /etc/config/tachyon ||
fail "Failed to restore the legacy configuration for migration" fail "Failed to restore the legacy configuration for migration"
@@ -1727,21 +1855,37 @@ install_ui_packages() {
} }
post_install() { post_install() {
if [ "$DRY_RUN" -eq 1 ]; then
msg "[dry-run] would run post-install cleanup and (re)start the Tachyon service"
return 0
fi
TACHYON_WAS_ENABLED="$TACHYON_WAS_ENABLED" TACHYON_WAS_RUNNING="$TACHYON_WAS_RUNNING" \ TACHYON_WAS_ENABLED="$TACHYON_WAS_ENABLED" TACHYON_WAS_RUNNING="$TACHYON_WAS_RUNNING" \
install_json_ucode installer-post-install || install_json_ucode installer-post-install ||
fail "Failed to complete Tachyon post-install actions" fail "Failed to complete Tachyon post-install actions"
} }
TOTAL_STEPS=10
main() { main() {
trap cleanup EXIT HUP INT TERM trap cleanup EXIT HUP INT TERM
parse_args "$@" parse_args "$@"
START_TIME="$(date +%s 2>/dev/null || echo 0)"
: >"$LOG_FILE" 2>/dev/null || true
log_line "Tachyon installer v${INSTALLER_VERSION} starting (args: $*)"
acquire_lock
check_root check_root
init_tmp_dir init_tmp_dir
detect_fetcher detect_fetcher
check_system check_system
msg "Updating package lists..." if [ "$DRY_RUN" -eq 1 ]; then
warn "Dry-run mode: no packages, files, or configuration will be changed."
fi
step 1 "$TOTAL_STEPS" "Updating package lists"
pkg_list_update || fail "Failed to update package lists" pkg_list_update || fail "Failed to update package lists"
ensure_bootstrap_ucode_runtime ensure_bootstrap_ucode_runtime
@@ -1753,33 +1897,50 @@ main() {
msg "$(installer_text install_start)" msg "$(installer_text install_start)"
msg "$(installer_text resolving_release)" step 2 "$TOTAL_STEPS" "$(installer_text resolving_release)"
resolve_tachyon_release resolve_tachyon_release
debug "Resolved release tag: $TACHYON_RELEASE_TAG"
msg "$(installer_text downloading_packages)" step 3 "$TOTAL_STEPS" "$(installer_text downloading_packages)"
download_tachyon_packages download_tachyon_packages
msg "$(installer_text cleaning_legacy)" step 4 "$TOTAL_STEPS" "$(installer_text cleaning_legacy)"
cleanup_legacy_installation cleanup_legacy_installation
msg "$(installer_text installing_backend)" step 5 "$TOTAL_STEPS" "$(installer_text installing_backend)"
install_backend_package install_backend_package
msg "$(installer_text migrating_config)" step 6 "$TOTAL_STEPS" "$(installer_text migrating_config)"
migrate_legacy_configuration migrate_legacy_configuration
msg "$(installer_text installing_ui)" step 7 "$TOTAL_STEPS" "$(installer_text installing_ui)"
install_ui_packages install_ui_packages
msg "$(installer_text installing_singbox)" step 8 "$TOTAL_STEPS" "$(installer_text installing_singbox)"
install_selected_sing_box install_selected_sing_box
msg "$(installer_text running_postinstall)" step 9 "$TOTAL_STEPS" "$(installer_text running_postinstall)"
post_install post_install
msg "Tachyon $TACHYON_PACKAGE_VERSION has been installed successfully" step 10 "$TOTAL_STEPS" "Done"
print_summary
}
print_summary() {
end_time="$(date +%s 2>/dev/null || echo 0)"
elapsed=$((end_time - START_TIME))
[ "$elapsed" -ge 0 ] 2>/dev/null || elapsed=0
printf '\n'
if [ "$DRY_RUN" -eq 1 ]; then
msg "Dry run complete in ${elapsed}s — no changes were made."
else
msg "Tachyon $TACHYON_PACKAGE_VERSION has been installed successfully (${elapsed}s)"
fi
msg "Source release: ${REPO_OWNER}/${REPO_NAME}@${TACHYON_RELEASE_TAG}" msg "Source release: ${REPO_OWNER}/${REPO_NAME}@${TACHYON_RELEASE_TAG}"
[ "$TACHYON_LEGACY_DETECTED" -eq 1 ] && msg "Legacy installation migrated and removed."
msg "Full log: $LOG_FILE"
warn "Open LuCI and review your rules before enabling Tachyon" warn "Open LuCI and review your rules before enabling Tachyon"
} }
main "$@" main "$@"
+9 -33
View File
@@ -27,17 +27,20 @@ let common = require("core.common");
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let command_output_from_args = common.command_output_from_args;
let command_exists = common.command_exists;
let command_from_args = common.command_from_args;
let write_json = common.write_json;
let command_output = common.command_output;
function arg_bool(value) { function arg_bool(value) {
value = lc(as_string(value)); value = lc(as_string(value));
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_env(assignments) { function command_env(assignments) {
let parts = []; let parts = [];
@@ -46,42 +49,15 @@ function command_env(assignments) {
return join(" ", parts); return join(" ", parts);
} }
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success(command) { function command_success(command) {
return command_status("(" + command + ") >/dev/null 2>&1") == 0; return command_status("(" + command + ") >/dev/null 2>&1") == 0;
} }
function command_success_from_args(args) {
return command_success(command_from_args(args));
}
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_exists(name) {
return command_success_from_args([ "command", "-v", name ]);
}
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function write_file(path, value) { function write_file(path, value) {
return fs.writefile(as_string(path), as_string(value)) != null; return fs.writefile(as_string(path), as_string(value)) != null;
+9 -40
View File
@@ -2,45 +2,20 @@
let fs = require("fs"); let fs = require("fs");
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let write_json = common.write_json;
let read_json_file = common.read_json_file;
let object_or_empty = common.object_or_empty;
let read_stdin = common.read_stdin;
let array_or_empty = common.array_or_empty;
let read_stdin_json = common.read_stdin_json;
function read_json_file(path) {
let data = fs.readfile(path);
if (data == null)
return null;
try {
return json(data);
}
catch (e) {
return null;
}
}
function read_stdin() {
let input = fs.open("/dev/stdin", "r");
if (!input)
return "";
let data = input.read("all");
input.close();
return data == null ? "" : data;
}
function read_stdin_json() {
let data = read_stdin();
try {
return json(data);
}
catch (e) {
return null;
}
}
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function stdin_contains_ci(needle) { function stdin_contains_ci(needle) {
needle = lc(as_string(needle)); needle = lc(as_string(needle));
@@ -84,13 +59,7 @@ function object_get_default(key, fallback) {
print(as_string(fallback), "\n"); print(as_string(fallback), "\n");
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function str_contains(haystack, needle) { function str_contains(haystack, needle) {
return index(as_string(haystack), as_string(needle)) >= 0; return index(as_string(haystack), as_string(needle)) >= 0;
+12 -54
View File
@@ -55,6 +55,18 @@ const SB_SERVICE_MIXED_INBOUND_PORT = getenv("SB_SERVICE_MIXED_INBOUND_PORT") ||
const SB_VARIANT_STATE_FILE = getenv("SB_VARIANT_STATE_FILE") || "/etc/tachyon/sing-box-variant"; const SB_VARIANT_STATE_FILE = getenv("SB_VARIANT_STATE_FILE") || "/etc/tachyon/sing-box-variant";
const GITHUB_RAW_URL = getenv("GITHUB_RAW_URL") || "https://raw.githubusercontent.com/itdoginfo/allow-domains/main"; const GITHUB_RAW_URL = getenv("GITHUB_RAW_URL") || "https://raw.githubusercontent.com/itdoginfo/allow-domains/main";
const BUILTIN_SUBNET_URLS = { const BUILTIN_SUBNET_URLS = {
let option = common.option;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let bool_option = common.bool_option;
let command_output_from_args = common.command_output_from_args;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let write_json = common.write_json;
let array_or_empty = common.array_or_empty;
let command_output = common.command_output;
twitter: getenv("SUBNETS_TWITTER") || GITHUB_RAW_URL + "/Subnets/IPv4/twitter.lst", twitter: getenv("SUBNETS_TWITTER") || GITHUB_RAW_URL + "/Subnets/IPv4/twitter.lst",
meta: getenv("SUBNETS_META") || GITHUB_RAW_URL + "/Subnets/IPv4/meta.lst", meta: getenv("SUBNETS_META") || GITHUB_RAW_URL + "/Subnets/IPv4/meta.lst",
discord: getenv("SUBNETS_DISCORD") || GITHUB_RAW_URL + "/Subnets/IPv4/discord.lst", discord: getenv("SUBNETS_DISCORD") || GITHUB_RAW_URL + "/Subnets/IPv4/discord.lst",
@@ -88,14 +100,6 @@ let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
let read_stdin = common.read_stdin; let read_stdin = common.read_stdin;
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_env(assignments) { function command_env(assignments) {
let parts = []; let parts = [];
@@ -106,18 +110,6 @@ function command_env(assignments) {
return join(" ", parts); return join(" ", parts);
} }
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function file_md5(path) { function file_md5(path) {
path = as_string(path); path = as_string(path);
@@ -128,22 +120,12 @@ function file_md5(path) {
return length(fields) > 0 ? as_string(fields[0]) : ""; return length(fields) > 0 ? as_string(fields[0]) : "";
} }
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success(command) { function command_success(command) {
return command_status(command + " >/dev/null 2>&1") == 0; return command_status(command + " >/dev/null 2>&1") == 0;
} }
function command_success_from_args(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function now_seconds() { function now_seconds() {
return int(clock()[0]); return int(clock()[0]);
@@ -160,9 +142,6 @@ function log_message(message, level) {
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function json_text(value) { function json_text(value) {
return sprintf("%J", value) + "\n"; return sprintf("%J", value) + "\n";
@@ -226,9 +205,6 @@ function arg_number(value) {
return int(value); return int(value);
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function text_first_chars(value, max_chars) { function text_first_chars(value, max_chars) {
value = as_string(value); value = as_string(value);
@@ -252,26 +228,8 @@ function file_last_nonblank_line_value(path, fallback, max_chars) {
return text_first_chars(result, max_chars); return text_first_chars(result, max_chars);
} }
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return fallback;
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function bool_option(section, key, fallback) {
let value = object_or_empty(section)[key];
return value == null ? !!fallback : arg_bool(value);
}
function section_name(section) { function section_name(section) {
return as_string(object_or_empty(section)[".name"]); return as_string(object_or_empty(section)[".name"]);
+4 -3
View File
@@ -9,9 +9,10 @@ const PUNYCODE_INITIAL_BIAS = 72;
const PUNYCODE_INITIAL_N = 128; const PUNYCODE_INITIAL_N = 128;
const PUNYCODE_DELIMITER = "-"; const PUNYCODE_DELIMITER = "-";
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
}
function ascii_lower(value) { function ascii_lower(value) {
let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+3 -12
View File
@@ -36,6 +36,9 @@ const APPLIED_MIGRATIONS_OPTION = "applied_migrations";
const SERVER_COUNTRY_METHOD_FLAG_EMOJI = "flag_emoji"; const SERVER_COUNTRY_METHOD_FLAG_EMOJI = "flag_emoji";
const SERVER_COUNTRY_METHOD_COUNTRY_IS = "country_is"; const SERVER_COUNTRY_METHOD_COUNTRY_IS = "country_is";
const CHILD_ITEM_TYPES = [ const CHILD_ITEM_TYPES = [
let command_output = common.command_output;
"subscription_url", "subscription_url",
"section_interface", "section_interface",
"urltest" "urltest"
@@ -43,18 +46,6 @@ const CHILD_ITEM_TYPES = [
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return replace(as_string(data), /[\r\n]+$/g, "");
}
function run(command) { function run(command) {
return system(command) == 0; return system(command) == 0;
+4 -3
View File
@@ -3,9 +3,10 @@
let ip = require("core.ip"); let ip = require("core.ip");
let domain_config = require("config.domain"); let domain_config = require("config.domain");
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
}
function strip_list_comment(line) { function strip_list_comment(line) {
line = replace(as_string(line), /[[:space:]]*\/\/.*$/, ""); line = replace(as_string(line), /[[:space:]]*\/\/.*$/, "");
+4 -6
View File
@@ -34,6 +34,10 @@ let command_output_from_args = common.command_output_from_args;
let command_trimmed_output_from_args = common.command_trimmed_output_from_args; let command_trimmed_output_from_args = common.command_trimmed_output_from_args;
let command_exists = common.command_exists; let command_exists = common.command_exists;
let object_or_empty = common.object_or_empty;
let array_or_empty = common.array_or_empty;
function string_starts_with(value, prefix) { function string_starts_with(value, prefix) {
value = as_string(value); value = as_string(value);
prefix = as_string(prefix); prefix = as_string(prefix);
@@ -73,13 +77,7 @@ function list_has_value(values, needle) {
return false; return false;
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function contains(values, needle) { function contains(values, needle) {
for (let value in array_or_empty(values)) for (let value in array_or_empty(values))
+4 -3
View File
@@ -1,8 +1,9 @@
#!/usr/bin/env ucode #!/usr/bin/env ucode
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
}
function str_last_index(value, needle) { function str_last_index(value, needle) {
value = as_string(value); value = as_string(value);
+5 -20
View File
@@ -6,32 +6,17 @@ let common = require("core.common");
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
function command_from_args(args) { let command_exists = common.command_exists;
let parts = []; let command_from_args = common.command_from_args;
for (let arg in args) let command_output = common.command_output;
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_success(args) { function command_success(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0; return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
} }
function command_output(args) {
let pipe = fs.popen(command_from_args(args), "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_exists(name) {
return command_success([ "command", "-v", name ]);
}
function apk_installed(package_name) { function apk_installed(package_name) {
return command_exists("apk") && command_success([ "apk", "info", "-e", as_string(package_name) ]); return command_exists("apk") && command_success([ "apk", "info", "-e", as_string(package_name) ]);
+15 -60
View File
@@ -64,6 +64,21 @@ let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
let option = common.option;
let list_option = common.list_option;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let bool_option = common.bool_option;
let read_stdin = common.read_stdin;
let command_output_from_args = common.command_output_from_args;
let command_exists = common.command_exists;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let write_json = common.write_json;
let array_or_empty = common.array_or_empty;
let command_output = common.command_output;
function arg_number(value) { function arg_number(value) {
value = as_string(value); value = as_string(value);
return value == "" || match(value, /[^0-9-]/) != null ? 0 : int(value, 10); return value == "" || match(value, /[^0-9-]/) != null ? 0 : int(value, 10);
@@ -74,21 +89,12 @@ function arg_bool(value) {
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function normalize_status(status) { function normalize_status(status) {
status = int(status); status = int(status);
return status > 255 ? int(status / 256) : status; return status > 255 ? int(status / 256) : status;
} }
function command_status(command) {
return normalize_status(system(command));
}
function command_capture(command) { function command_capture(command) {
let pipe = fs.popen(command, "r"); let pipe = fs.popen(command, "r");
@@ -100,26 +106,13 @@ function command_capture(command) {
return { status, output: data == null ? "" : as_string(data) }; return { status, output: data == null ? "" : as_string(data) };
} }
function command_output(command) {
let result = command_capture(command);
return result.status == 0 ? result.output : "";
}
function command_success(command) { function command_success(command) {
return command_status(command + " >/dev/null 2>&1") == 0; return command_status(command + " >/dev/null 2>&1") == 0;
} }
function command_output_from_args(args) {
return command_output(command_from_args(args) + " 2>/dev/null");
}
function command_success_from_args(args) {
return command_success(command_from_args(args));
}
function command_exists(name) {
return command_success_from_args([ "command", "-v", as_string(name) ]);
}
function module_args(module_path, args) { function module_args(module_path, args) {
let result = [ "ucode", "-L", LIB_DIR, module_path ]; let result = [ "ucode", "-L", LIB_DIR, module_path ];
@@ -187,18 +180,7 @@ function status_success(args, input) {
return status_capture(args, input).status == 0; return status_capture(args, input).status == 0;
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function read_stdin() {
let input = fs.open("/dev/stdin", "r");
if (!input)
return "";
let data = input.read("all");
input.close();
return data == null ? "" : as_string(data);
}
@@ -211,37 +193,10 @@ function parse_json_or_null(value) {
} }
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return as_string(fallback);
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function list_option(section, key) {
let value = object_or_empty(section)[key];
if (type(value) == "array")
return value;
if (as_string(value) != "")
return [ as_string(value) ];
return [];
}
function bool_option(section, key, fallback) {
return arg_bool(option(section, key, fallback ? "1" : "0"));
}
function settings() { function settings() {
return object_or_empty(uci_core.get_all(CONFIG_NAME, "settings")); return object_or_empty(uci_core.get_all(CONFIG_NAME, "settings"));
+11 -43
View File
@@ -3,9 +3,17 @@
let fs = require("fs"); let fs = require("fs");
let core_ip = require("core.ip"); let core_ip = require("core.ip");
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let write_json = common.write_json;
let read_json_file = common.read_json_file;
let write_json_file = common.write_json_file;
let object_or_empty = common.object_or_empty;
let read_stdin = common.read_stdin;
let array_or_empty = common.array_or_empty;
let read_stdin_json = common.read_stdin_json;
function url_encode(value) { function url_encode(value) {
value = as_string(value); value = as_string(value);
@@ -23,45 +31,14 @@ function url_encode(value) {
print("\n"); print("\n");
} }
function read_stdin() {
let input = fs.open("/dev/stdin", "r");
if (!input)
return "";
let data = input.read("all");
input.close();
return data == null ? "" : data;
}
function read_stdin_json() {
try {
return json(read_stdin());
}
catch (e) {
return null;
}
}
function proxy_response_is_retryable_error() { function proxy_response_is_retryable_error() {
let response = read_stdin(); let response = read_stdin();
return index(response, "<html") == 0 || index(response, "403 Forbidden") >= 0; return index(response, "<html") == 0 || index(response, "403 Forbidden") >= 0;
} }
function read_json_file(path) {
let data = fs.readfile(path);
if (data == null)
return null;
try {
return json(data);
}
catch (e) {
return null;
}
}
function write_json_file(path, value) {
return fs.writefile(path, sprintf("%J", value) + "\n");
}
function parse_json_object(value) { function parse_json_object(value) {
try { try {
@@ -605,13 +582,7 @@ function object_value(object, key) {
return type(object) == "object" && object[key] != null ? as_string(object[key]) : ""; return type(object) == "object" && object[key] != null ? as_string(object[key]) : "";
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function str_startswith(value, prefix) { function str_startswith(value, prefix) {
value = as_string(value); value = as_string(value);
@@ -942,9 +913,6 @@ function print_line(value) {
print(value, "\n"); print(value, "\n");
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function stdin_json() { function stdin_json() {
let value = read_stdin_json(); let value = read_stdin_json();
+11 -66
View File
@@ -15,26 +15,23 @@ let list_option = common.list_option;
let bool_option = common.bool_option; let bool_option = common.bool_option;
let as_string = common.as_string; let as_string = common.as_string;
let write_compact_string_array = common.write_compact_string_array;
let run_args = common.run_args;
let read_stdin = common.read_stdin;
let command_output_from_args = common.command_output_from_args;
let csv_to_json_array = common.csv_to_json_array;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let write_json = common.write_json;
let option = common.option;
function arg_bool(value) { function arg_bool(value) {
value = lc(as_string(value)); value = lc(as_string(value));
return value == "1" || value == "true" || value == "yes"; return value == "1" || value == "true" || value == "yes";
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return fallback;
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function uci_section(section_name) { function uci_section(section_name) {
return object_or_empty(uci_core.get_all(CONFIG_NAME, section_name)); return object_or_empty(uci_core.get_all(CONFIG_NAME, section_name));
@@ -48,28 +45,8 @@ function uci_settings() {
return uci_section("settings"); return uci_section("settings");
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function write_compact_string_array(values) {
print("[");
for (let i = 0; i < length(values); i++) {
if (i > 0)
print(",");
print(sprintf("%J", as_string(values[i])));
}
print("]\n");
}
function read_stdin() {
let input = fs.open("/dev/stdin", "r");
if (!input)
return "";
let data = input.read("all");
input.close();
return data == null ? "" : data;
}
function write_text_file(path, text) { function write_text_file(path, text) {
let result = fs.writefile(path, as_string(text)); let result = fs.writefile(path, as_string(text));
@@ -98,35 +75,12 @@ function unlink_file(path) {
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function run_args(args) {
return system(command_from_args(args)) == 0;
}
function run_args_quiet(args) { function run_args_quiet(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0; return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
} }
function command_output_from_args(args) {
let pipe = fs.popen(command_from_args(args), "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function log_debug(message) { function log_debug(message) {
run_args([ "logger", "-t", "tachyon", "[debug] " + as_string(message) ]); run_args([ "logger", "-t", "tachyon", "[debug] " + as_string(message) ]);
@@ -175,15 +129,6 @@ function text_list_to_csv(value, separator_mode) {
print_csv(text_list_values(value, separator_mode)); print_csv(text_list_values(value, separator_mode));
} }
function csv_to_json_array(value) {
value = as_string(value);
if (value == "") {
print("[]\n");
return;
}
write_compact_string_array(split(value, ","));
}
function csv_list_contains(value, needle) { function csv_list_contains(value, needle) {
needle = as_string(needle); needle = as_string(needle);
@@ -25,84 +25,43 @@ let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
let option = common.option;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let bool_option = common.bool_option;
let command_output_from_args = common.command_output_from_args;
let command_exists = common.command_exists;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let write_json = common.write_json;
let array_or_empty = common.array_or_empty;
let command_output = common.command_output;
function bool_value(value) { function bool_value(value) {
value = lc(as_string(value)); value = lc(as_string(value));
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success(command) { function command_success(command) {
return command_status(command + " >/dev/null 2>&1") == 0; return command_status(command + " >/dev/null 2>&1") == 0;
} }
function command_success_from_args(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_exists(name) {
return command_success_from_args([ "command", "-v", name ]);
}
function log_message(message, level) { function log_message(message, level) {
level = as_string(level || "info"); level = as_string(level || "info");
command_success_from_args([ "logger", "-t", "tachyon", "[" + level + "] " + as_string(message) ]); command_success_from_args([ "logger", "-t", "tachyon", "[" + level + "] " + as_string(message) ]);
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return fallback;
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function bool_option(section, key, fallback) {
let value = object_or_empty(section)[key];
return value == null ? !!fallback : bool_value(value);
}
function section_name(section) { function section_name(section) {
return as_string(object_or_empty(section)[".name"]); return as_string(object_or_empty(section)[".name"]);
@@ -1,17 +1,16 @@
#!/usr/bin/env ucode #!/usr/bin/env ucode
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let write_json = common.write_json;
function bool_arg(value) { function bool_arg(value) {
value = as_string(value); value = as_string(value);
return value == "1" || value == "true"; return value == "1" || value == "true";
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function normalize_strategy_whitespace(value) { function normalize_strategy_whitespace(value) {
value = replace(as_string(value), /[\t\r\n]/g, " "); value = replace(as_string(value), /[\t\r\n]/g, " ");
@@ -2,14 +2,12 @@
let fs = require("fs"); let fs = require("fs");
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let read_stdin = common.read_stdin;
function read_stdin() {
let data = fs.readfile("/dev/stdin");
return data == null ? "" : data;
}
function strip_trailing_cr(line) { function strip_trailing_cr(line) {
line = as_string(line); line = as_string(line);
@@ -15,54 +15,34 @@ let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
let option = common.option;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let bool_option = common.bool_option;
let command_output_from_args = common.command_output_from_args;
let command_exists = common.command_exists;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let write_json = common.write_json;
let array_or_empty = common.array_or_empty;
let command_output = common.command_output;
function bool_value(value) { function bool_value(value) {
value = lc(as_string(value)); value = lc(as_string(value));
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success(command) { function command_success(command) {
return command_status(command + " >/dev/null 2>&1") == 0; return command_status(command + " >/dev/null 2>&1") == 0;
} }
function command_success_from_args(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_exists(name) {
return command_success_from_args([ "command", "-v", name ]);
}
function module_command(args) { function module_command(args) {
let command_args = [ "ucode", "-L", LIB_DIR ]; let command_args = [ "ucode", "-L", LIB_DIR ];
@@ -80,30 +60,9 @@ function log_message(message, level) {
command_success_from_args([ "logger", "-t", "tachyon", "[" + level + "] " + as_string(message) ]); command_success_from_args([ "logger", "-t", "tachyon", "[" + level + "] " + as_string(message) ]);
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return fallback;
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function bool_option(section, key, fallback) {
let value = object_or_empty(section)[key];
return value == null ? !!fallback : bool_value(value);
}
function section_name(section) { function section_name(section) {
return as_string(object_or_empty(section)[".name"]); return as_string(object_or_empty(section)[".name"]);
@@ -1,12 +1,11 @@
#!/usr/bin/env ucode #!/usr/bin/env ucode
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let write_json = common.write_json;
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function normalize_strategy_whitespace(value) { function normalize_strategy_whitespace(value) {
value = replace(as_string(value), /[\t\r\n]/g, " "); value = replace(as_string(value), /[\t\r\n]/g, " ");
+5 -11
View File
@@ -5,18 +5,12 @@ let uci_core = require("core.uci");
const CONFIG_NAME = getenv("TACHYON_CONFIG_NAME") || "tachyon"; const CONFIG_NAME = getenv("TACHYON_CONFIG_NAME") || "tachyon";
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let read_stdin = common.read_stdin;
function read_stdin() {
let input = fs.open("/dev/stdin", "r");
if (!input)
return "";
let data = input.read("all");
input.close();
return data == null ? "" : data;
}
function hex_digit_value(value) { function hex_digit_value(value) {
let pos = index("0123456789abcdef", lc(as_string(value))); let pos = index("0123456789abcdef", lc(as_string(value)));
+8 -29
View File
@@ -2,9 +2,14 @@
let fs = require("fs"); let fs = require("fs");
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let write_json = common.write_json;
let read_json_file = common.read_json_file;
let read_stdin = common.read_stdin;
let array_or_empty = common.array_or_empty;
function int_arg(value) { function int_arg(value) {
value = as_string(value); value = as_string(value);
@@ -16,35 +21,9 @@ function bool_arg(value) {
return value == "1" || value == "true"; return value == "1" || value == "true";
} }
function read_stdin() {
let input = fs.open("/dev/stdin", "r");
if (!input)
return "";
let data = input.read("all");
input.close();
return data == null ? "" : data;
}
function read_json_file(path) {
let data = fs.readfile(path);
if (data == null)
return null;
try {
return json(data);
}
catch (e) {
return null;
}
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function first_field(line) { function first_field(line) {
let fields = split(trim(as_string(line)), /[ \t\r\n]+/); let fields = split(trim(as_string(line)), /[ \t\r\n]+/);
+8 -16
View File
@@ -4,9 +4,14 @@ let fs = require("fs");
let ip = require("core.ip"); let ip = require("core.ip");
let domain_config = require("config.domain"); let domain_config = require("config.domain");
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
} let read_json_file = common.read_json_file;
let write_json_file = common.write_json_file;
let object_or_empty = common.object_or_empty;
let array_or_empty = common.array_or_empty;
function json_decode_text(text) { function json_decode_text(text) {
try { try {
@@ -17,10 +22,6 @@ function json_decode_text(text) {
} }
} }
function read_json_file(path) {
let data = fs.readfile(path);
return data == null ? null : json_decode_text(data);
}
function write_text_file(path, text) { function write_text_file(path, text) {
let result = fs.writefile(path, text); let result = fs.writefile(path, text);
@@ -31,13 +32,7 @@ function write_text_file(path, text) {
return true; return true;
} }
function write_json_file(path, value) {
return write_text_file(path, sprintf("%J", value) + "\n");
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function array_from_value(value) { function array_from_value(value) {
if (value == null) if (value == null)
@@ -47,9 +42,6 @@ function array_from_value(value) {
return [ value ]; return [ value ];
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function trim_string(value) { function trim_string(value) {
let text = as_string(value); let text = as_string(value);
+6 -22
View File
@@ -12,6 +12,12 @@ let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
let read_stdin = common.read_stdin;
let write_json = common.write_json;
let array_or_empty = common.array_or_empty;
let read_stdin_json = common.read_stdin_json;
function ascii_lower(value) { function ascii_lower(value) {
let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let lower = "abcdefghijklmnopqrstuvwxyz"; let lower = "abcdefghijklmnopqrstuvwxyz";
@@ -20,9 +26,6 @@ function ascii_lower(value) {
}); });
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function run(command) { function run(command) {
return system(command) == 0; return system(command) == 0;
@@ -105,23 +108,7 @@ function server_set_option(section, option, value) {
function read_stdin() {
let input = fs.open("/dev/stdin", "r");
if (!input)
return "";
let data = input.read("all");
input.close();
return data == null ? "" : data;
}
function read_stdin_json() {
try {
return json(read_stdin());
}
catch (e) {
return null;
}
}
function stdin_first_nonempty_line() { function stdin_first_nonempty_line() {
for (let line in split(read_stdin(), "\n")) { for (let line in split(read_stdin(), "\n")) {
@@ -143,9 +130,6 @@ function shell_single_quote(value) {
print("'", replace(value, /'/g, "'\\''"), "'\n"); print("'", replace(value, /'/g, "'\\''"), "'\n");
} }
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function array_append_string(value) { function array_append_string(value) {
let result = array_or_empty(read_stdin_json()); let result = array_or_empty(read_stdin_json());
+9 -32
View File
@@ -8,6 +8,15 @@ let common = require("core.common");
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let option = common.option;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let command_output_from_args = common.command_output_from_args;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let command_output = common.command_output;
function constant_value(name, fallback) { function constant_value(name, fallback) {
let value = constants[name]; let value = constants[name];
return value == null ? as_string(fallback) : as_string(value); return value == null ? as_string(fallback) : as_string(value);
@@ -38,21 +47,12 @@ function shell_assignment(name, value) {
print(as_string(name), "=", shell_quote(value), "\n"); print(as_string(name), "=", shell_quote(value), "\n");
} }
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function normalize_status(status) { function normalize_status(status) {
status = int(status); status = int(status);
return status > 255 ? int(status / 256) : status; return status > 255 ? int(status / 256) : status;
} }
function command_status(command) {
return normalize_status(system(command));
}
function command_capture(command) { function command_capture(command) {
let pipe = fs.popen(command, "r"); let pipe = fs.popen(command, "r");
@@ -64,18 +64,8 @@ function command_capture(command) {
return { status, output: data == null ? "" : as_string(data) }; return { status, output: data == null ? "" : as_string(data) };
} }
function command_output(command) {
let result = command_capture(command);
return result.status == 0 ? result.output : "";
}
function command_output_from_args(args) {
return command_output(command_from_args(args) + " 2>/dev/null");
}
function command_success_from_args(args) {
return command_status(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_status_from_args(args) { function command_status_from_args(args) {
return command_status(command_from_args(args)); return command_status(command_from_args(args));
@@ -118,20 +108,7 @@ function bool_text(value) {
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return as_string(fallback);
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function file_exists(path) { function file_exists(path) {
return fs.stat(as_string(path)) != null; return fs.stat(as_string(path)) != null;
+10 -28
View File
@@ -9,6 +9,16 @@ let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let command_output_from_args = common.command_output_from_args;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let write_json = common.write_json;
let array_or_empty = common.array_or_empty;
let command_output = common.command_output;
function constant_value(name, fallback) { function constant_value(name, fallback) {
let value = constants[name]; let value = constants[name];
return value == null ? as_string(fallback) : as_string(value); return value == null ? as_string(fallback) : as_string(value);
@@ -124,21 +134,12 @@ let startup_config_fingerprint = "";
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function normalize_status(status) { function normalize_status(status) {
status = int(status); status = int(status);
return status > 255 ? int(status / 256) : status; return status > 255 ? int(status / 256) : status;
} }
function command_status(command) {
return normalize_status(system(command));
}
function command_capture(command) { function command_capture(command) {
let pipe = fs.popen(command, "r"); let pipe = fs.popen(command, "r");
@@ -150,16 +151,9 @@ function command_capture(command) {
return { status, output: data == null ? "" : as_string(data) }; return { status, output: data == null ? "" : as_string(data) };
} }
function command_output(command) {
let result = command_capture(command);
return result.status == 0 ? result.output : "";
}
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function command_success(command) { function command_success(command) {
return command_status(command + " >/dev/null 2>&1") == 0; return command_status(command + " >/dev/null 2>&1") == 0;
@@ -169,13 +163,7 @@ function command_status_from_args(args) {
return command_status(command_from_args(args)); return command_status(command_from_args(args));
} }
function command_output_from_args(args) {
return command_output(command_from_args(args) + " 2>/dev/null");
}
function command_success_from_args(args) {
return command_status(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function external_config_fingerprint() { function external_config_fingerprint() {
let data = fs.readfile(CONFIG_FILE); let data = fs.readfile(CONFIG_FILE);
@@ -208,13 +196,7 @@ function bool_text(value) {
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function string_array_contains(values, needle) { function string_array_contains(values, needle) {
needle = as_string(needle); needle = as_string(needle);
+4 -9
View File
@@ -7,6 +7,10 @@ let common = require("core.common");
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let command_success_from_args = common.command_success_from_args;
let command_from_args = common.command_from_args;
function env(name, fallback) { function env(name, fallback) {
let value = getenv(name); let value = getenv(name);
return value == null ? as_string(fallback) : as_string(value); return value == null ? as_string(fallback) : as_string(value);
@@ -23,21 +27,12 @@ const SING_BOX_CRONET = env("TACHYON_SING_BOX_CRONET", "/usr/lib/libcronet.so");
const SING_BOX_MANAGED_MARKER = env("SB_MANAGED_SERVICE_MARKER", "Tachyon managed sing-box service for binary variants"); const SING_BOX_MANAGED_MARKER = env("SB_MANAGED_SERVICE_MARKER", "Tachyon managed sing-box service for binary variants");
const PACKAGE_TEST_MODE = env("TACHYON_PACKAGE_TEST_MODE", "") != ""; const PACKAGE_TEST_MODE = env("TACHYON_PACKAGE_TEST_MODE", "") != "";
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function normalize_status(status) { function normalize_status(status) {
status = int(status); status = int(status);
return status > 255 ? int(status / 256) : status; return status > 255 ? int(status / 256) : status;
} }
function command_success_from_args(args) {
return normalize_status(system(command_from_args(args) + " >/dev/null 2>&1")) == 0;
}
function path_exists(path) { function path_exists(path) {
return fs.stat(as_string(path)) != null; return fs.stat(as_string(path)) != null;
+4 -3
View File
@@ -2,9 +2,10 @@
let fs = require("fs"); let fs = require("fs");
function as_string(value) { let common = require("core.common");
return value == null ? "" : "" + value; let as_string = common.as_string;
}
function arg_bool(value) { function arg_bool(value) {
return value === true || value == "true" || value == "1" || value == 1; return value === true || value == "true" || value == "1" || value == 1;
+12 -72
View File
@@ -20,24 +20,19 @@ let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
function read_stdin() { let list_option = common.list_option;
let input = fs.open("/dev/stdin", "r"); let command_success_from_args = common.command_success_from_args;
if (!input) let bool_option = common.bool_option;
return ""; let command_output_from_args = common.command_output_from_args;
let data = input.read("all"); let command_from_args = common.command_from_args;
input.close(); let command_trimmed_output_from_args = common.command_trimmed_output_from_args;
return data == null ? "" : data; let object_or_empty = common.object_or_empty;
} let read_stdin = common.read_stdin;
let read_stdin_json = common.read_stdin_json;
let option = common.option;
function read_stdin_json() {
let data = read_stdin();
try {
return json(data);
}
catch (e) {
return null;
}
}
function write_text_file(path, text) { function write_text_file(path, text) {
let result = fs.writefile(path, as_string(text)); let result = fs.writefile(path, as_string(text));
@@ -56,35 +51,9 @@ function unlink_file(path) {
} }
} }
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_output_from_args(args) {
let pipe = fs.popen(command_from_args(args), "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_trimmed_output_from_args(args) {
return replace(command_output_from_args(args), /[\r\n]+$/g, "");
}
function command_success_from_args(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function uci_get(path) { function uci_get(path) {
return uci_core.get(path); return uci_core.get(path);
@@ -94,9 +63,6 @@ function uci_exists(path) {
return uci_core.exists(path); return uci_core.exists(path);
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function file_first_line(path) { function file_first_line(path) {
let data = fs.readfile(path); let data = fs.readfile(path);
@@ -578,34 +544,8 @@ function arg_bool(value) {
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return fallback;
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function list_option(section, key, fallback) {
let value = object_or_empty(section)[key];
if (type(value) == "array")
return value;
value = trim(as_string(value));
if (value != "")
return split(value, /[ \t\r\n]+/);
fallback = as_string(fallback);
return fallback == "" ? [] : [ fallback ];
}
function bool_option(section, key, fallback) {
return arg_bool(option(section, key, fallback ? "1" : "0"));
}
function bool_value(value) { function bool_value(value) {
return arg_bool(value) ? "1" : "0"; return arg_bool(value) ? "1" : "0";
+5 -13
View File
@@ -11,22 +11,14 @@ const OFFSET_FILE = "/var/run/tachyon_telegram_offset";
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let command_status = common.command_status;
let command_success_from_args = common.command_success_from_args;
let command_from_args = common.command_from_args;
function command_from_args(args) {
let result = [];
for (let arg in args)
push(result, shell_quote(arg));
return join(" ", result);
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success_from_args(args) {
return command_status(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_capture(command) { function command_capture(command) {
let pipe = fs.popen(command, "r"); let pipe = fs.popen(command, "r");
+10 -44
View File
@@ -39,14 +39,16 @@ let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file; let read_json_file = common.read_json_file;
function read_stdin() { let write_json = common.write_json;
let input = fs.open("/dev/stdin", "r"); let command_status = common.command_status;
if (!input) let command_success_from_args = common.command_success_from_args;
return ""; let command_output_from_args = common.command_output_from_args;
let data = input.read("all"); let command_from_args = common.command_from_args;
input.close(); let object_or_empty = common.object_or_empty;
return data == null ? "" : data; let read_stdin = common.read_stdin;
} let command_output = common.command_output;
function parse_json_or_null(value) { function parse_json_or_null(value) {
try { try {
@@ -57,22 +59,11 @@ function parse_json_or_null(value) {
} }
} }
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function json_text(value) { function json_text(value) {
return sprintf("%J", value) + "\n"; return sprintf("%J", value) + "\n";
} }
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_env(assignments) { function command_env(assignments) {
let parts = []; let parts = [];
@@ -83,35 +74,13 @@ function command_env(assignments) {
return join(" ", parts); return join(" ", parts);
} }
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success(command) { function command_success(command) {
return command_status(command + " >/dev/null 2>&1") == 0; return command_status(command + " >/dev/null 2>&1") == 0;
} }
function command_success_from_args(args) {
return command_success(command_from_args(args));
}
function module_success(module_path, args) { function module_success(module_path, args) {
let command_args = [ "ucode", "-L", LIB_DIR, module_path ]; let command_args = [ "ucode", "-L", LIB_DIR, module_path ];
@@ -201,9 +170,6 @@ function unsigned_number(value) {
return int(value); return int(value);
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function path_basename(path) { function path_basename(path) {
let parts = split(as_string(path), "/"); let parts = split(as_string(path), "/");
+4 -3
View File
@@ -37,6 +37,10 @@ const BYEDPI_LISTEN_ADDRESS = "127.0.0.1";
const BYEDPI_PORT_BASE = 1080; const BYEDPI_PORT_BASE = 1080;
const RESERVED_TAGS = { const RESERVED_TAGS = {
let common = require("core.common");
let as_string = common.as_string;
[DNS_SERVER_TAG]: true, [DNS_SERVER_TAG]: true,
[FAKEIP_DNS_SERVER_TAG]: true, [FAKEIP_DNS_SERVER_TAG]: true,
[BOOTSTRAP_DNS_SERVER_TAG]: true, [BOOTSTRAP_DNS_SERVER_TAG]: true,
@@ -51,9 +55,6 @@ const RESERVED_TAGS = {
[BYPASS_OUTBOUND_TAG]: true [BYPASS_OUTBOUND_TAG]: true
}; };
function as_string(value) {
return value == null ? "" : "" + value;
}
function tag(base, postfix) { function tag(base, postfix) {
let candidate = as_string(base) + "-" + as_string(postfix); let candidate = as_string(base) + "-" + as_string(postfix);
+3 -16
View File
@@ -12,24 +12,11 @@ const COUNTRY_IS_BATCH_SIZE = 100;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
function command_from_args(args) { let command_output_from_args = common.command_output_from_args;
let parts = []; let command_from_args = common.command_from_args;
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_output_from_args(args) {
let pipe = fs.popen(command_from_args(args) + " 2>/dev/null", "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function remove_file(path) { function remove_file(path) {
if (as_string(path) != "") if (as_string(path) != "")
+6 -21
View File
@@ -18,30 +18,15 @@ const CHECK_DOMAIN = "example.com";
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
function command_from_args(args) { let command_status = common.command_status;
let result = []; let command_success_from_args = common.command_success_from_args;
for (let arg in args) let command_output_from_args = common.command_output_from_args;
push(result, shell_quote(arg)); let command_from_args = common.command_from_args;
return join(" ", result);
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success_from_args(args) {
return command_status(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_output_from_args(args) {
let pipe = fs.popen(command_from_args(args), "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
return status == 0 && data != null ? as_string(data) : "";
}
function settings() { function settings() {
return common.object_or_empty(uci_core.get_all(CONFIG_NAME, "settings")); return common.object_or_empty(uci_core.get_all(CONFIG_NAME, "settings"));
+6 -26
View File
@@ -18,37 +18,17 @@ const DIAGNOSTICS_UC = getenv("TACHYON_DIAGNOSTICS_UC") || LIB_DIR + "/diagnosti
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
function command_from_args(args) { let command_status = common.command_status;
let parts = []; let command_success_from_args = common.command_success_from_args;
for (let arg in args) let command_output_from_args = common.command_output_from_args;
push(parts, shell_quote(arg)); let command_from_args = common.command_from_args;
return join(" ", parts); let command_output = common.command_output;
}
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success_from_args(args) {
return command_status(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function ensure_dir(path) { function ensure_dir(path) {
return command_success_from_args([ "mkdir", "-p", path ]); return command_success_from_args([ "mkdir", "-p", path ]);
+3 -3
View File
@@ -7,9 +7,9 @@ let runtime_constants = require("singbox.constants");
let option = common.option; let option = common.option;
let bool_option = common.bool_option; let bool_option = common.bool_option;
function as_string(value) { let as_string = common.as_string;
return value == null ? "" : "" + value;
}
function bool_value(value) { function bool_value(value) {
return value === true || value == "1" || value == "true" || value == "yes" || value == "on"; return value === true || value == "1" || value == "true" || value == "yes" || value == "on";
+4 -3
View File
@@ -6,6 +6,10 @@ const SRS_SUPERCELL_URL = "https://raw.githubusercontent.com/ushan0v/sing-box-su
const SRS_GITHUB_URL = "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs"; const SRS_GITHUB_URL = "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs";
const COMMUNITY_SERVICES = { const COMMUNITY_SERVICES = {
let common = require("core.common");
let as_string = common.as_string;
russia_inside: true, russia_inside: true,
russia_outside: true, russia_outside: true,
ukraine_inside: true, ukraine_inside: true,
@@ -35,9 +39,6 @@ const COMMUNITY_SERVICES = {
github: true github: true
}; };
function as_string(value) {
return value == null ? "" : "" + value;
}
function is_community(name) { function is_community(name) {
return COMMUNITY_SERVICES[as_string(name)] === true; return COMMUNITY_SERVICES[as_string(name)] === true;
+12 -51
View File
@@ -41,12 +41,18 @@ const SB_MANAGED_SERVICE_MARKER = getenv("SB_MANAGED_SERVICE_MARKER") || "Tachyo
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
function command_from_args(args) { let option = common.option;
let parts = []; let command_status = common.command_status;
for (let arg in args) let command_success_from_args = common.command_success_from_args;
push(parts, shell_quote(arg)); let bool_option = common.bool_option;
return join(" ", parts); let command_output_from_args = common.command_output_from_args;
} let command_exists = common.command_exists;
let command_from_args = common.command_from_args;
let object_or_empty = common.object_or_empty;
let array_or_empty = common.array_or_empty;
let command_output = common.command_output;
function command_env(assignments) { function command_env(assignments) {
let parts = []; let parts = [];
@@ -55,38 +61,14 @@ function command_env(assignments) {
return join(" ", parts); return join(" ", parts);
} }
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_status(command) {
let status = int(system(command));
return status > 255 ? int(status / 256) : status;
}
function command_success(command) { function command_success(command) {
return command_status(command + " >/dev/null 2>&1") == 0; return command_status(command + " >/dev/null 2>&1") == 0;
} }
function command_success_from_args(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_exists(name) {
return command_success_from_args([ "command", "-v", name ]);
}
function write_file(path, value) { function write_file(path, value) {
return fs.writefile(as_string(path), as_string(value)) != null; return fs.writefile(as_string(path), as_string(value)) != null;
@@ -114,35 +96,14 @@ function file_first_line(path) {
return trim(newline >= 0 ? substr(data, 0, newline) : data); return trim(newline >= 0 ? substr(data, 0, newline) : data);
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return fallback;
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function arg_bool(value) { function arg_bool(value) {
value = lc(as_string(value)); value = lc(as_string(value));
return value == "true" || value == "1" || value == "yes" || value == "on"; return value == "true" || value == "1" || value == "yes" || value == "on";
} }
function bool_option(section, key, fallback) {
let value = object_or_empty(section)[key];
return value == null ? !!fallback : arg_bool(value);
}
function whitespace_items(value) { function whitespace_items(value) {
let result = []; let result = [];
+14 -64
View File
@@ -35,10 +35,20 @@ let common = require("core.common");
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
function read_stdin() { let command_output = common.command_output;
let data = fs.readfile("/dev/stdin"); let write_json = common.write_json;
return data == null ? "" : data; let list_option = common.list_option;
} let command_success_from_args = common.command_success_from_args;
let bool_option = common.bool_option;
let command_output_from_args = common.command_output_from_args;
let command_from_args = common.command_from_args;
let object_key_count = common.object_key_count;
let object_or_empty = common.object_or_empty;
let read_stdin = common.read_stdin;
let array_or_empty = common.array_or_empty;
let option = common.option;
function read_json(path) { function read_json(path) {
if (path == null || path == "" || path == "-") if (path == null || path == "" || path == "-")
@@ -60,9 +70,6 @@ function write_file(path, value) {
return fs.writefile(path, value) != null; return fs.writefile(path, value) != null;
} }
function write_json(path, value) {
return write_file(path, sprintf("%J", value) + "\n");
}
function write_stdout_json(value) { function write_stdout_json(value) {
print(sprintf("%J", value), "\n"); print(sprintf("%J", value), "\n");
@@ -131,21 +138,7 @@ function append_state_list_once(list, value) {
print(list, list != "" ? " " : "", value, "\n"); print(list, list != "" ? " " : "", value, "\n");
} }
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function option(section, key, fallback) {
if (fallback == null)
fallback = "";
let value = object_or_empty(section)[key];
if (value == null)
return fallback;
if (type(value) == "array")
return join(" ", value);
return as_string(value);
}
function bool_value(value, fallback) { function bool_value(value, fallback) {
if (value == null) if (value == null)
@@ -155,9 +148,6 @@ function bool_value(value, fallback) {
return value == "1" || value == "true" || value == "yes" || value == "on"; return value == "1" || value == "true" || value == "yes" || value == "on";
} }
function bool_option(section, key, fallback) {
return bool_value(object_or_empty(section)[key], fallback);
}
function unsigned_number(value) { function unsigned_number(value) {
value = as_string(value); value = as_string(value);
@@ -533,14 +523,6 @@ function files_equal(left, right) {
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_env(assignments) { function command_env(assignments) {
let parts = []; let parts = [];
@@ -562,26 +544,8 @@ function command_args_with(base, extra) {
return result; return result;
} }
function command_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_output_from_args(args) {
return command_output(command_from_args(args));
}
function command_success_from_args(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_status_from_args(args) { function command_status_from_args(args) {
let status = int(system(command_from_args(args))); let status = int(system(command_from_args(args)));
@@ -821,14 +785,6 @@ function uci_named_section(section_name_value) {
return object_or_empty(uci_core.get_all(CONFIG_NAME, section_name_value)); return object_or_empty(uci_core.get_all(CONFIG_NAME, section_name_value));
} }
function list_option(section, key) {
let value = object_or_empty(section)[key];
if (type(value) == "array")
return value;
if (as_string(value) != "")
return [ as_string(value) ];
return [];
}
function find_section(sections, name) { function find_section(sections, name) {
name = as_string(name); name = as_string(name);
@@ -1020,9 +976,6 @@ function is_array(value) {
return type(value) == "array"; return type(value) == "array";
} }
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function int_or_zero(value) { function int_or_zero(value) {
value = as_string(value); value = as_string(value);
@@ -1067,9 +1020,6 @@ function log_subscription_source_summary(section_name_value, source_index, norma
log_message(subscription_source_summary(section_name_value, source_index, normalized_path, result), "info"); log_message(subscription_source_summary(section_name_value, source_index, normalized_path, result), "info");
} }
function object_key_count(value) {
return type(value) == "object" ? length(keys(value)) : 0;
}
function valid_metadata_object(value) { function valid_metadata_object(value) {
return type(value) == "object" && object_key_count(value) > 1; return type(value) == "object" && object_key_count(value) > 1;
+7 -16
View File
@@ -6,6 +6,13 @@ let common = require("core.common");
let as_string = common.as_string; let as_string = common.as_string;
let shell_quote = common.shell_quote; let shell_quote = common.shell_quote;
let read_json_file = common.read_json_file;
let write_json_file = common.write_json_file;
let object_or_empty = common.object_or_empty;
let write_json = common.write_json;
let array_or_empty = common.array_or_empty;
function trim(value) { function trim(value) {
value = as_string(value); value = as_string(value);
let start = 0; let start = 0;
@@ -287,23 +294,13 @@ function read_file(path) {
return fs.readfile(path); return fs.readfile(path);
} }
function read_json_file(path) {
let data = read_file(path);
return data == null ? null : json_decode_text(data);
}
function validate_subscription(path) { function validate_subscription(path) {
let value = read_json_file(path); let value = read_json_file(path);
return type(value) == "object" && type(value.outbounds) == "array" && length(value.outbounds) > 0; return type(value) == "object" && type(value.outbounds) == "array" && length(value.outbounds) > 0;
} }
function write_json_file(path, value) {
return fs.writefile(path, sprintf("%J", value) + "\n");
}
function write_json(value) {
print(sprintf("%J", value), "\n");
}
function canonical_runtime_value(value) { function canonical_runtime_value(value) {
if (type(value) == "array") { if (type(value) == "array") {
@@ -350,13 +347,7 @@ function runtime_outbounds_equal(left_path, right_path) {
return sprintf("%J", left) == sprintf("%J", right); return sprintf("%J", left) == sprintf("%J", right);
} }
function array_or_empty(value) {
return type(value) == "array" ? value : [];
}
function object_or_empty(value) {
return type(value) == "object" ? value : {};
}
function base64_decode(value) { function base64_decode(value) {
value = as_string(value); value = as_string(value);