mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-10 16:57:51 +08:00
🌈 Sync 2026-08-11 02:29:57
This commit is contained in:
1 parent
f8bdc4459f
commit
412c262edf
73 files changed
+9791
-5915
No files matched your search
@@ -22,19 +22,19 @@ module YAML
|
||||
end
|
||||
|
||||
def self.load_file(filename, *args, **kwargs)
|
||||
yaml_content = File.read(filename, mode: "r:bom|utf-8")
|
||||
|
||||
secret = nil
|
||||
if kwargs.key?(:secret)
|
||||
secret = kwargs.delete(:secret)
|
||||
end
|
||||
|
||||
if yaml_content.include?("BEGIN AGE ENCRYPTED FILE")
|
||||
header = File.binread(filename, 512).to_s
|
||||
|
||||
if header.include?("BEGIN AGE ENCRYPTED FILE")
|
||||
yaml_content = File.read(filename, mode: "r:bom|utf-8")
|
||||
if secret && secret.to_s.strip != ""
|
||||
decrypted = decrypt_content_with_secret(secret.to_s, yaml_content)
|
||||
if decrypted && !decrypted.empty? && !decrypted.include?("BEGIN AGE ENCRYPTED FILE")
|
||||
processed = fix_short_id_quotes(decrypted)
|
||||
return load(processed, *args, **kwargs)
|
||||
return fix_and_load(decrypted, *args, **kwargs)
|
||||
else
|
||||
raise "Decrypted content empty or still encrypted: [#{filename}]"
|
||||
end
|
||||
@@ -46,8 +46,7 @@ module YAML
|
||||
begin
|
||||
decrypted = decrypt_content_with_secret(sec, yaml_content)
|
||||
if decrypted && !decrypted.empty? && !decrypted.include?("BEGIN AGE ENCRYPTED FILE")
|
||||
processed = fix_short_id_quotes(decrypted)
|
||||
return load(processed, *args, **kwargs)
|
||||
return fix_and_load(decrypted, *args, **kwargs)
|
||||
end
|
||||
rescue => e
|
||||
last_error = e.message
|
||||
@@ -58,13 +57,51 @@ module YAML
|
||||
raise "Encrypted file: decryption failed for [#{filename}]: [#{detail}]"
|
||||
end
|
||||
|
||||
processed_content = fix_short_id_quotes(yaml_content)
|
||||
load(processed_content, *args, **kwargs)
|
||||
base64, short_id, protocol_param = File.open(filename, "r:bom|utf-8") do |io|
|
||||
scan_for_fixes(io)
|
||||
end
|
||||
|
||||
if base64 || protocol_param
|
||||
fix_and_load(File.read(filename, mode: "r:bom|utf-8"), *args, **kwargs)
|
||||
elsif short_id
|
||||
fixed = File.open(filename, "r:bom|utf-8") { |io| fix_short_id_text(io) }
|
||||
begin
|
||||
load(fixed, *args, **kwargs)
|
||||
rescue => e
|
||||
raise "fix short-id values type failed: #{e.message}"
|
||||
end
|
||||
else
|
||||
result = File.open(filename, "r:bom|utf-8") do |io|
|
||||
load(io, *args, **kwargs)
|
||||
end
|
||||
if result.nil? || result == false
|
||||
result = fix_and_load(File.read(filename, mode: "r:bom|utf-8"), *args, **kwargs)
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
def self.dump(obj, io = nil, **options)
|
||||
yaml_content = original_dump(obj, **options)
|
||||
processed = fix_short_id_quotes(yaml_content)
|
||||
if obj.nil? || obj == false
|
||||
target = ""
|
||||
if io.is_a?(String)
|
||||
target = " [#{io}]"
|
||||
elsif io && io.respond_to?(:path)
|
||||
target = " [#{io.path}]"
|
||||
elsif options.key?(:filename)
|
||||
target = " [#{options[:filename]}]"
|
||||
end
|
||||
raise "YAML.dump: refusing to write nil/false config content#{target} (previous load may have failed)"
|
||||
end
|
||||
|
||||
if io.is_a?(String)
|
||||
dump_to_path(obj, io, **options)
|
||||
else
|
||||
dump_to_io(obj, io, **options)
|
||||
end
|
||||
end
|
||||
|
||||
def self.dump_to_io(obj, io = nil, **options)
|
||||
public_key = nil
|
||||
fname = nil
|
||||
if options.key?(:public)
|
||||
@@ -86,7 +123,11 @@ module YAML
|
||||
end
|
||||
end
|
||||
|
||||
needs_fix = contains_short_id?(obj)
|
||||
|
||||
if public_key && public_key.to_s.strip != ""
|
||||
yaml_content = original_dump(obj, **options)
|
||||
processed = needs_fix ? fix_short_id_quotes(yaml_content) : yaml_content
|
||||
begin
|
||||
encrypted = encrypt_content_with_public(public_key.to_s, processed)
|
||||
if encrypted && !encrypted.empty?
|
||||
@@ -108,15 +149,40 @@ module YAML
|
||||
end
|
||||
|
||||
if io.nil?
|
||||
processed
|
||||
yaml_content = original_dump(obj, **options)
|
||||
needs_fix ? fix_short_id_quotes(yaml_content) : yaml_content
|
||||
elsif io.respond_to?(:write)
|
||||
io.write(processed)
|
||||
if needs_fix
|
||||
fix_short_id_text(original_dump(obj, **options), io)
|
||||
else
|
||||
original_dump(obj, io, **options)
|
||||
end
|
||||
io
|
||||
else
|
||||
processed
|
||||
yaml_content = original_dump(obj, **options)
|
||||
needs_fix ? fix_short_id_quotes(yaml_content) : yaml_content
|
||||
end
|
||||
end
|
||||
|
||||
def self.dump_to_path(obj, path, **options)
|
||||
real = File.symlink?(path) ? File.realpath(path) : path
|
||||
dir = File.dirname(real)
|
||||
tmp = File.join(dir, ".#{File.basename(real)}.tmp#{Process.pid}.#{rand(1000)}")
|
||||
mode = File.exist?(real) ? File.stat(real).mode & 07777 : nil
|
||||
begin
|
||||
File.open(tmp, 'w') { |f| dump_to_io(obj, f, **options.merge(filename: real)) }
|
||||
File.chmod(mode, tmp) if mode
|
||||
File.rename(tmp, real)
|
||||
rescue Exception
|
||||
begin
|
||||
File.unlink(tmp) if File.exist?(tmp)
|
||||
rescue
|
||||
end
|
||||
raise
|
||||
end
|
||||
path
|
||||
end
|
||||
|
||||
def self.popen_stream(cmd, input, chunk_size: 64 * 1024)
|
||||
output = String.new
|
||||
IO.popen(cmd, 'r+', err: [:child, :out]) do |io|
|
||||
@@ -229,75 +295,162 @@ module YAML
|
||||
# Input: short-id: "1600e237" -> Output: short-id: "1600e237"
|
||||
# Input: short-id: null -> Output: short-id: ""
|
||||
|
||||
def self.fix_short_id_quotes(yaml_content)
|
||||
def self.fix_and_load(yaml_content, *args, **kwargs)
|
||||
yaml_content = decode64(yaml_content)
|
||||
|
||||
return yaml_content unless yaml_content.include?('short-id:')
|
||||
# Fix bare protocol-param values that break YAML parsing (e.g. "1.2.3.4:8080#test")
|
||||
yaml_content.gsub!(/^(\s*protocol-param:\s+)([^\s"'][^"\n\r]*[#:][^"\n\r]*)$/, '\1"\2"')
|
||||
return load(yaml_content, *args, **kwargs) unless yaml_content.include?('short-id:')
|
||||
|
||||
begin
|
||||
stream = Psych.parse_stream(yaml_content)
|
||||
|
||||
traverse = lambda do |node|
|
||||
case node
|
||||
when Psych::Nodes::Mapping
|
||||
children = node.children || []
|
||||
i = 0
|
||||
while i < children.length
|
||||
key = children[i]
|
||||
val = children[i + 1]
|
||||
if key.is_a?(Psych::Nodes::Scalar) && key.value == 'short-id'
|
||||
if val.is_a?(Psych::Nodes::Scalar)
|
||||
is_null_scalar = (val.tag == 'tag:yaml.org,2002:null') || (val.tag == '!!null') || (val.value =~ /^\s*(~|null|NULL|Null)\s*$/)
|
||||
unless is_null_scalar
|
||||
val.tag = nil
|
||||
val.style = defined?(Psych::Nodes::Scalar::DOUBLE_QUOTED) ? Psych::Nodes::Scalar::DOUBLE_QUOTED : 2
|
||||
end
|
||||
elsif val.is_a?(Psych::Nodes::Sequence)
|
||||
val.children.each do |child|
|
||||
if child.is_a?(Psych::Nodes::Scalar)
|
||||
is_null_child = (child.tag == 'tag:yaml.org,2002:null') || (child.tag == '!!null') || (child.value =~ /^\s*(~|null|NULL|Null)\s*$/)
|
||||
unless is_null_child
|
||||
child.tag = nil
|
||||
child.style = defined?(Psych::Nodes::Scalar::DOUBLE_QUOTED) ? Psych::Nodes::Scalar::DOUBLE_QUOTED : 2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
traverse.call(key) if key.respond_to?(:children)
|
||||
traverse.call(val) if val.respond_to?(:children)
|
||||
end
|
||||
i += 2
|
||||
end
|
||||
when Psych::Nodes::Sequence
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
when Psych::Nodes::Document, Psych::Nodes::Stream
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
else
|
||||
if node.respond_to?(:children)
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
stream.children.each do |doc_node|
|
||||
if doc_node.is_a?(Psych::Nodes::Document)
|
||||
traverse.call(doc_node.root) if doc_node.root
|
||||
end
|
||||
end
|
||||
|
||||
if stream.respond_to?(:to_yaml)
|
||||
processed_yaml = stream.to_yaml
|
||||
processed_yaml = processed_yaml.gsub(/^([ \t]*short-id:\s*)!\s*/, "\\1")
|
||||
processed_yaml
|
||||
else
|
||||
yaml_content
|
||||
end
|
||||
load(fix_short_id_text(yaml_content), *args, **kwargs)
|
||||
rescue => e
|
||||
raise "fix short-id values type failed: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.quote_short_id_scalar(value)
|
||||
v = value.strip
|
||||
return value if v.empty?
|
||||
return '""' if v =~ /\A(?:~|null|NULL|Null)\z/
|
||||
if v.start_with?("'")
|
||||
if (m = v.match(/\A'((?:[^']|'')*)'(\s+#.*)?\z/))
|
||||
inner = m[1].gsub("''", "'")
|
||||
return "\"#{inner.gsub(/["\\]/) { |c| "\\#{c}" }}\"#{m[2]}"
|
||||
end
|
||||
return value
|
||||
end
|
||||
return value if v.start_with?('"')
|
||||
return value if v =~ /[:{}\[\],|>]/
|
||||
if (m = v.match(/\A(\S+)(\s+#.*)?\z/))
|
||||
"\"#{m[1].gsub('"', '\\"')}\"#{m[2]}"
|
||||
else
|
||||
"\"#{v.gsub('"', '\\"')}\""
|
||||
end
|
||||
end
|
||||
|
||||
def self.fix_short_id_text(yaml_content, output = nil)
|
||||
out = output || String.new
|
||||
in_seq = false
|
||||
seq_indent = -1
|
||||
in_block = false
|
||||
block_indent = -1
|
||||
pending = nil
|
||||
|
||||
yaml_content.each_line do |line|
|
||||
if in_block
|
||||
if line.strip.empty? || (line =~ /^(\s*)/ && Regexp.last_match(1).length > block_indent)
|
||||
out << line
|
||||
next
|
||||
else
|
||||
in_block = false
|
||||
end
|
||||
end
|
||||
|
||||
if pending
|
||||
if (m = line.match(/^(\s*)-(\s*)(.*?)(\r?\n)?\z/)) && m[1].length >= seq_indent
|
||||
out << pending
|
||||
in_seq = true
|
||||
else
|
||||
out << pending.sub(/^(\s*)short-id:.*?(\r?\n)?\z/, '\1short-id: ""\2')
|
||||
in_seq = false
|
||||
end
|
||||
pending = nil
|
||||
end
|
||||
|
||||
if (m = line.match(/^(\s*)short-id:(\s*)(.*?)(\r?\n)?\z/))
|
||||
indent = m[1]
|
||||
rest = m[3].to_s.strip
|
||||
if rest.empty? || rest.start_with?('#')
|
||||
in_seq = true
|
||||
seq_indent = indent.length
|
||||
pending = line
|
||||
else
|
||||
in_seq = false
|
||||
out << indent + "short-id:" + m[2] + quote_short_id_scalar(rest) + m[4].to_s
|
||||
end
|
||||
elsif (m = line.match(/^(\s*)[^:\s][^:]*:\s*[|>](\s*.*)?$/))
|
||||
in_block = true
|
||||
in_seq = false
|
||||
block_indent = m[1].length
|
||||
out << line
|
||||
elsif line.strip.empty?
|
||||
out << line
|
||||
elsif in_seq && (m = line.match(/^(\s*)-(\s*)(.*?)(\r?\n)?\z/)) && m[1].length >= seq_indent
|
||||
out << m[1] + "-" + m[2] + quote_short_id_scalar(m[3]) + m[4].to_s
|
||||
else
|
||||
in_seq = false
|
||||
out << line
|
||||
end
|
||||
end
|
||||
|
||||
if pending
|
||||
out << pending.sub(/^(\s*)short-id:.*?(\r?\n)?\z/, '\1short-id: ""\2')
|
||||
end
|
||||
|
||||
out
|
||||
end
|
||||
|
||||
def self.fix_short_id_quotes(yaml_content)
|
||||
begin
|
||||
fix_short_id_text(yaml_content)
|
||||
rescue => e
|
||||
raise "fix short-id values type failed: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.scan_for_fixes(io)
|
||||
base64 = false
|
||||
short_id = false
|
||||
protocol_param = false
|
||||
first_nonempty_seen = false
|
||||
buffer = String.new
|
||||
chunk_size = 64 * 1024
|
||||
|
||||
while (chunk = io.read(chunk_size))
|
||||
buffer << chunk
|
||||
|
||||
unless first_nonempty_seen
|
||||
if (idx = buffer.index("\n"))
|
||||
stripped = buffer[0...idx].strip
|
||||
if !stripped.empty?
|
||||
first_nonempty_seen = true
|
||||
base64 = stripped.match?(/\A[A-Za-z0-9+\/=]+\z/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
short_id ||= buffer.include?('short-id:')
|
||||
protocol_param ||= buffer.include?('protocol-param:')
|
||||
|
||||
if first_nonempty_seen && buffer.bytesize > chunk_size + 4096
|
||||
buffer = buffer[-4096, 4096]
|
||||
end
|
||||
|
||||
break if base64 || short_id || protocol_param
|
||||
end
|
||||
|
||||
unless first_nonempty_seen
|
||||
stripped = buffer.strip
|
||||
base64 = !stripped.empty? && stripped.match?(/\A[A-Za-z0-9+\/=]+\z/)
|
||||
end
|
||||
|
||||
[base64, short_id, protocol_param]
|
||||
end
|
||||
|
||||
def self.contains_short_id?(obj, depth = 0)
|
||||
return false if depth > 64
|
||||
case obj
|
||||
when Hash
|
||||
return true if obj.key?('short-id') || obj.key?(:"short-id")
|
||||
obj.each_value { |v| return true if contains_short_id?(v, depth + 1) }
|
||||
false
|
||||
when Array
|
||||
obj.any? { |v| contains_short_id?(v, depth + 1) }
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def self.overwrite(base, override)
|
||||
return override if base.nil?
|
||||
return base if override.nil?
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 884>"/tmp/lock/openclash_clash_version.lock" 2>/dev/null
|
||||
flock -x 884 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 884 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_clash_version.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
|
||||
DOWNLOAD_FILE="/tmp/clash_last_version"
|
||||
RELEASE_BRANCH=$(uci_get_config "release_branch" || echo "master")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
CORE_TYPE=$(uci_get_config "core_type")
|
||||
OIX_TOKEN=$(uci_get_config "oix_token")
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
github_address_mod="$1"
|
||||
fi
|
||||
|
||||
if [ "$CORE_TYPE" = "Oix" ] || [ -n "$OIX_TOKEN" ]; then
|
||||
OIX_VERSION_URL="https://github.com/vernesong/mihomo-oix/releases/download/Pre-Alpha/version.txt"
|
||||
OIX_VERSION_P_URL="https://dl.dler.io/mihomo-oix/version.txt?tag=Pre-Alpha"
|
||||
if [ "$github_address_mod" != "0" ] && [ "$github_address_mod" != "https://cdn.jsdelivr.net/" ] && [ "$github_address_mod" != "https://fastly.jsdelivr.net/" ] && [ "$github_address_mod" != "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}${OIX_VERSION_URL}"
|
||||
else
|
||||
DOWNLOAD_URL="$OIX_VERSION_P_URL"
|
||||
fi
|
||||
else
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/vernesong/OpenClash@core/${RELEASE_BRANCH}/core_version"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://raw.githubusercontent.com/vernesong/OpenClash/core/${RELEASE_BRANCH}/core_version"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://raw.githubusercontent.com/vernesong/OpenClash/core/${RELEASE_BRANCH}/core_version"
|
||||
fi
|
||||
fi
|
||||
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "$DOWNLOAD_FILE" "$DOWNLOAD_FILE"
|
||||
del_lock
|
||||
@@ -6,7 +6,7 @@ LOG_FILE="/tmp/openclash.log"
|
||||
LOG_OUT()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Info] ${1}" >> $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Info] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
@@ -14,7 +14,7 @@ LOG_OUT()
|
||||
LOG_TIP()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Tip] ${1}" >> $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Tip] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
@@ -22,7 +22,7 @@ LOG_TIP()
|
||||
LOG_WARN()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Warning] ${1}" >> $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Warning] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
@@ -30,7 +30,7 @@ LOG_WARN()
|
||||
LOG_ERROR()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Error] ${1}" >> $START_LOG
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Error] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
@@ -48,14 +48,3 @@ LOG_WATCHDOG()
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S") [Watchdog] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
LOG_ALERT()
|
||||
{
|
||||
echo -e "$(tail -n 20 $LOG_FILE |grep -E 'level=fatal|level=error' |awk 'END {print}')" > $START_LOG
|
||||
sleep 3
|
||||
}
|
||||
|
||||
SLOG_CLEAN()
|
||||
{
|
||||
echo "##FINISH##" > $START_LOG
|
||||
}
|
||||
@@ -67,6 +67,24 @@ config_test()
|
||||
fi
|
||||
}
|
||||
|
||||
yaml_sub_validate()
|
||||
{
|
||||
rm -f /tmp/yaml_sub_status 2>/dev/null
|
||||
ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
begin
|
||||
Value = YAML.load_file('$CFG_FILE')
|
||||
unless Value.key?('proxies') || Value.key?('proxy-providers')
|
||||
File.open('/tmp/yaml_sub_status', 'w') { |f| f.puts 'NO_CONTENT' }
|
||||
end
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Unable To Parse Config File,【' + e.message + '】')
|
||||
system 'rm -rf ${CFG_FILE} 2>/dev/null'
|
||||
end
|
||||
" 2>/dev/null >> $LOG_FILE
|
||||
YAML_SUB_STATUS=$(cat /tmp/yaml_sub_status 2>/dev/null)
|
||||
rm -f /tmp/yaml_sub_status 2>/dev/null
|
||||
}
|
||||
|
||||
config_download()
|
||||
{
|
||||
LOG_TIP "Config File【$name】Downloading User-Agent【$sub_ua】..."
|
||||
@@ -152,7 +170,7 @@ config_cus_up()
|
||||
YAML.LOG_ERROR('Filter Proxies Failed,【' + e.message + '】');
|
||||
ensure
|
||||
begin
|
||||
File.open('$CFG_FILE','w') {|f| YAML.dump(Value, f)};
|
||||
YAML.dump(Value, '$CFG_FILE');
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Write file failed:【%s】' % [e.message])
|
||||
end
|
||||
@@ -222,8 +240,6 @@ config_download_direct()
|
||||
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "$CFG_FILE" ]; then
|
||||
#prevent ruby unexpected error
|
||||
sed -i -E 's/protocol-param: ([^,'"'"'"''}( *#)\n\r]+)/protocol-param: "\1"/g' "$CFG_FILE" 2>/dev/null
|
||||
sed -i '/^ \{0,\}enhanced-mode:/d' "$CFG_FILE" >/dev/null 2>&1
|
||||
config_test
|
||||
if [ $? -ne 0 ]; then
|
||||
LOG_ERROR "Config File Tested Failed, Please Check The Log Infos!"
|
||||
@@ -231,14 +247,7 @@ config_download_direct()
|
||||
config_error
|
||||
return
|
||||
fi
|
||||
ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
begin
|
||||
YAML.load_file('$CFG_FILE');
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Unable To Parse Config File,【' + e.message + '】');
|
||||
system 'rm -rf ${CFG_FILE} 2>/dev/null'
|
||||
end
|
||||
" 2>/dev/null >> $LOG_FILE
|
||||
yaml_sub_validate
|
||||
if [ $? -ne 0 ]; then
|
||||
LOG_ERROR "Ruby Works Abnormally, Please Check The Ruby Library Depends!"
|
||||
only_download=1
|
||||
@@ -248,7 +257,7 @@ config_download_direct()
|
||||
LOG_OUT "Config File Format Validation Failed..."
|
||||
change_dns
|
||||
config_error
|
||||
elif ! "$(ruby_read "$CFG_FILE" ".key?('proxies')")" && ! "$(ruby_read "$CFG_FILE" ".key?('proxy-providers')")" ; then
|
||||
elif [ "$YAML_SUB_STATUS" = "NO_CONTENT" ]; then
|
||||
LOG_ERROR "Updated Config【$name】Has No Proxy Field, Update Exit..."
|
||||
change_dns
|
||||
config_error
|
||||
@@ -434,7 +443,6 @@ sub_info_get()
|
||||
config_download
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "$CFG_FILE" ]; then
|
||||
#prevent ruby unexpected error
|
||||
sed -i -E 's/protocol-param: ([^,'"'"'"''}( *#)\n\r]+)/protocol-param: "\1"/g' "$CFG_FILE" 2>/dev/null
|
||||
config_test
|
||||
if [ $? -ne 0 ]; then
|
||||
LOG_ERROR "Config File Tested Failed, Please Check The Log Infos!"
|
||||
@@ -442,14 +450,7 @@ sub_info_get()
|
||||
config_download_direct
|
||||
return
|
||||
fi
|
||||
ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
begin
|
||||
YAML.load_file('$CFG_FILE');
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Unable To Parse Config File,【' + e.message + '】');
|
||||
system 'rm -rf ${CFG_FILE} 2>/dev/null'
|
||||
end
|
||||
" 2>/dev/null >> $LOG_FILE
|
||||
yaml_sub_validate
|
||||
if [ $? -ne 0 ]; then
|
||||
LOG_ERROR "Ruby Works Abnormally, Please Check The Ruby Library Depends!"
|
||||
only_download=1
|
||||
@@ -457,7 +458,7 @@ sub_info_get()
|
||||
elif [ ! -f "$CFG_FILE" ]; then
|
||||
LOG_OUT "Config File Format Validation Failed, Trying To Download Without Agent..."
|
||||
config_download_direct
|
||||
elif ! "$(ruby_read "$CFG_FILE" ".key?('proxies')")" && ! "$(ruby_read "$CFG_FILE" ".key?('proxy-providers')")" ; then
|
||||
elif [ "$YAML_SUB_STATUS" = "NO_CONTENT" ]; then
|
||||
LOG_ERROR "Updated Config【$name】Has No Proxy Field, Trying To Download Without Agent..."
|
||||
config_download_direct
|
||||
else
|
||||
@@ -474,6 +475,5 @@ sub_info_get()
|
||||
#分别获取订阅信息进行处理
|
||||
config_load "openclash"
|
||||
config_foreach sub_info_get "config_subscribe" "$1"
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -115,6 +115,5 @@ fi
|
||||
|
||||
rm -rf /tmp/china_ip*_route* >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -19,40 +19,54 @@ set_lock
|
||||
inc_job_counter
|
||||
|
||||
restart=0
|
||||
UPDATE_SUCCESS=0
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
if [ "$github_address_mod" = "0" ] && [ -z "$(echo $2 2>/dev/null |grep -E 'http|one_key_update')" ] && [ -z "$(echo $3 2>/dev/null |grep 'http')" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
DIRECT_CORE_URL=""
|
||||
if [ -n "$2" ] && echo "$2" | grep -qE '^https?://'; then
|
||||
DIRECT_CORE_URL="$2"
|
||||
fi
|
||||
if [ -n "$3" ] && [ "$2" = "one_key_update" ]; then
|
||||
github_address_mod="$3"
|
||||
if [ "$github_address_mod" = "0" ] && [ -z "$DIRECT_CORE_URL" ] && [ -z "$(echo $2 2>/dev/null |grep -E 'http|one_key_update')" ] && [ -z "$(echo $3 2>/dev/null |grep 'http')" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - GitHub Address Proxy Options"
|
||||
fi
|
||||
if [ -n "$2" ] && [ "$2" = "one_key_update" ] && [ -z "$3" ]; then
|
||||
github_address_mod=0
|
||||
fi
|
||||
if [ -n "$2" ] && [ "$2" != "one_key_update" ]; then
|
||||
github_address_mod="$2"
|
||||
if [ -z "$DIRECT_CORE_URL" ]; then
|
||||
if [ -n "$3" ] && [ "$2" = "one_key_update" ]; then
|
||||
github_address_mod="$3"
|
||||
fi
|
||||
if [ -n "$2" ] && [ "$2" = "one_key_update" ] && [ -z "$3" ]; then
|
||||
github_address_mod=0
|
||||
fi
|
||||
if [ -n "$2" ] && [ "$2" != "one_key_update" ]; then
|
||||
github_address_mod="$2"
|
||||
fi
|
||||
if echo "$github_address_mod" | grep -q "raw\.githubusercontent\.com"; then
|
||||
github_address_mod=0
|
||||
fi
|
||||
fi
|
||||
CORE_TYPE="$1"
|
||||
C_CORE_TYPE=$(uci_get_config "core_type")
|
||||
SMART_ENABLE=$(uci_get_config "smart_enable" || echo 0)
|
||||
OIX_TOKEN=$(uci_get_config "oix_token")
|
||||
[ "$SMART_ENABLE" -eq 1 ] && CORE_TYPE="Smart"
|
||||
[ "$CORE_TYPE" = "Oix" ] || [ -n "$OIX_TOKEN" ] && CORE_TYPE="Oix"
|
||||
[ -n "$OIX_TOKEN" ] && CORE_TYPE="Oix"
|
||||
[ -z "$CORE_TYPE" ] && CORE_TYPE="Meta"
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
CPU_MODEL=$(uci_get_config "core_version")
|
||||
RELEASE_BRANCH=$(uci_get_config "release_branch" || echo "master")
|
||||
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
/usr/share/openclash/clash_version.sh "$github_address_mod" 2>/dev/null
|
||||
else
|
||||
/usr/share/openclash/clash_version.sh 2>/dev/null
|
||||
fi
|
||||
if [ ! -f "/tmp/clash_last_version" ]; then
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Version Check Error, Please Try Again Later..."
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
exit 0
|
||||
if [ -z "$DIRECT_CORE_URL" ]; then
|
||||
lua /usr/share/openclash/openclash_version.lua "$github_address_mod" 2>/dev/null
|
||||
if [ "$CORE_TYPE" = "Oix" ]; then
|
||||
CORE_LV=$(jsonfilter -i /tmp/openclash_version_history.json -e "@.oix.ver" 2>/dev/null)
|
||||
elif [ "$CORE_TYPE" = "Smart" ]; then
|
||||
CORE_LV=$(jsonfilter -i /tmp/openclash_version_history.json -e "@.${RELEASE_BRANCH}.latest.core_smart" 2>/dev/null)
|
||||
else
|
||||
CORE_LV=$(jsonfilter -i /tmp/openclash_version_history.json -e "@.${RELEASE_BRANCH}.latest.core_meta" 2>/dev/null)
|
||||
fi
|
||||
if [ -z "$CORE_LV" ]; then
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Version Check Error, Please Try Again Later..."
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
@@ -70,23 +84,23 @@ TMP_FILE="${TARGET_CORE_PATH}.new.$$"
|
||||
if [ "$CORE_TYPE" = "Oix" ]; then
|
||||
CORE_URL_PATH=""
|
||||
DOWNLOAD_FILE="/tmp/clash_meta.gz"
|
||||
CORE_LV=$(sed -n 1p /tmp/clash_last_version 2>/dev/null)
|
||||
elif [ "$CORE_TYPE" = "Smart" ]; then
|
||||
CORE_URL_PATH="$RELEASE_BRANCH/smart"
|
||||
DOWNLOAD_FILE="/tmp/clash_meta.tar.gz"
|
||||
CORE_LV=$(sed -n 2p /tmp/clash_last_version 2>/dev/null)
|
||||
else
|
||||
CORE_URL_PATH="$RELEASE_BRANCH/meta"
|
||||
DOWNLOAD_FILE="/tmp/clash_meta.tar.gz"
|
||||
CORE_LV=$(sed -n 1p /tmp/clash_last_version 2>/dev/null)
|
||||
fi
|
||||
|
||||
[ "$C_CORE_TYPE" != "$CORE_TYPE" ] || [ -z "$C_CORE_TYPE" ] && restart=1
|
||||
|
||||
if [ "$CORE_CV" != "$CORE_LV" ] || [ -z "$CORE_CV" ]; then
|
||||
if [ -n "$DIRECT_CORE_URL" ] || [ "$CORE_CV" != "$CORE_LV" ] || [ -z "$CORE_CV" ]; then
|
||||
if [ "$CPU_MODEL" != 0 ]; then
|
||||
LOG_TIP "【$CORE_TYPE】Core Downloading, Please Try to Download and Upload Manually If Fails"
|
||||
if [ "$CORE_TYPE" = "Oix" ]; then
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Downloading, Please Try to Download and Upload Manually If Fails"
|
||||
# If $2 is a full download URL, use it directly
|
||||
if [ -n "$2" ] && echo "$2" | grep -qE '^https?://'; then
|
||||
DOWNLOAD_URL="$2"
|
||||
elif [ "$CORE_TYPE" = "Oix" ]; then
|
||||
OIX_CORE_URL="https://github.com/vernesong/mihomo-oix/releases/download/Pre-Alpha/mihomo-${CPU_MODEL}-${CORE_LV}.gz"
|
||||
OIX_CORE_P_URL="https://dl.dler.io/mihomo-oix/mihomo-${CPU_MODEL}-${CORE_LV}.gz?tag=Pre-Alpha"
|
||||
if [ "$github_address_mod" != "0" ] && [ "$github_address_mod" != "https://cdn.jsdelivr.net/" ] && [ "$github_address_mod" != "https://fastly.jsdelivr.net/" ] && [ "$github_address_mod" != "https://testingcf.jsdelivr.net/" ]; then
|
||||
@@ -118,91 +132,85 @@ if [ "$CORE_CV" != "$CORE_LV" ] || [ -z "$CORE_CV" ]; then
|
||||
DOWNLOAD_RESULT=$?
|
||||
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ]; then
|
||||
gzip -t "$DOWNLOAD_FILE" >/dev/null 2>&1
|
||||
gzip_test_err=$(gzip -t "$DOWNLOAD_FILE" 2>&1)
|
||||
|
||||
if [ "$?" -eq 0 ]; then
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Download Successful, Start Update..."
|
||||
extract_success=true
|
||||
extract_err=""
|
||||
[ -s "$DOWNLOAD_FILE" ] && {
|
||||
if [ "$CORE_TYPE" = "Oix" ]; then
|
||||
gzip -dc "$DOWNLOAD_FILE" > "$TMP_FILE" 2>/dev/null || extract_success=false
|
||||
extract_err=$(gzip -dc "$DOWNLOAD_FILE" > "$TMP_FILE" 2>&1) || extract_success=false
|
||||
else
|
||||
tar zxvfo "$DOWNLOAD_FILE" -C /tmp >/dev/null 2>&1 || extract_success=false
|
||||
mv /tmp/clash "$TMP_FILE" >/dev/null 2>&1 || extract_success=false
|
||||
extract_err=$(tar zxvfo "$DOWNLOAD_FILE" -C /tmp 2>&1) || extract_success=false
|
||||
[ "$extract_success" = "true" ] && { extract_err=$(mv /tmp/clash "$TMP_FILE" 2>&1) || extract_success=false; }
|
||||
fi
|
||||
rm -rf "$DOWNLOAD_FILE" >/dev/null 2>&1
|
||||
chmod 4755 "$TMP_FILE" >/dev/null 2>&1 || extract_success=false
|
||||
"$TMP_FILE" -v >/dev/null 2>&1 || extract_success=false
|
||||
[ "$extract_success" = "true" ] && { extract_err=$(chmod 4755 "$TMP_FILE" 2>&1) || extract_success=false; }
|
||||
[ "$extract_success" = "true" ] && { extract_err=$("$TMP_FILE" -v 2>&1) || extract_success=false; }
|
||||
}
|
||||
|
||||
if [ "$extract_success" != "true" ]; then
|
||||
if [ "$retry_count" -lt "$max_retries" ]; then
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Update Failed..."
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Update Failed:【$(echo "$extract_err" | tr '\n' ' ' | head -c 300)】..."
|
||||
rm -rf "$TMP_FILE" >/dev/null 2>&1
|
||||
sleep 2
|
||||
continue
|
||||
else
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Update Failed, Please Make Sure Enough Flash Memory Space or Selected Correct Core Platform And Try Again!"
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Update Failed:【$(echo "$extract_err" | tr '\n' ' ' | head -c 300)】..."
|
||||
rm -rf "$TMP_FILE" >/dev/null 2>&1
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
exit 0
|
||||
break
|
||||
fi
|
||||
fi
|
||||
|
||||
mv -f "$TMP_FILE" "$TARGET_CORE_PATH" >/dev/null 2>&1
|
||||
mv_err=$(mv -f "$TMP_FILE" "$TARGET_CORE_PATH" 2>&1)
|
||||
|
||||
if [ "$?" == "0" ]; then
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Update Successful!"
|
||||
SLOG_CLEAN
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Update Successful"
|
||||
UPDATE_SUCCESS=1
|
||||
restart=1
|
||||
break
|
||||
else
|
||||
if [ "$retry_count" -lt "$max_retries" ]; then
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Update Failed..."
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Move Failed:【$(echo "$mv_err" | tr '\n' ' ' | head -c 300)】"
|
||||
sleep 2
|
||||
continue
|
||||
else
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Update Failed, Please Make Sure Enough Flash Memory Space And Try Again!"
|
||||
SLOG_CLEAN
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Move Failed:【$(echo "$mv_err" | tr '\n' ' ' | head -c 300)】"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ "$retry_count" -lt "$max_retries" ]; then
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Update Failed..."
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Verification Failed:【$(echo "$gzip_test_err" | tr '\n' ' ' | head -c 300)】"
|
||||
sleep 2
|
||||
continue
|
||||
else
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Update Failed, Please Check The Network or Try Again Later!"
|
||||
SLOG_CLEAN
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Verification Failed:【$(echo "$gzip_test_err" | tr '\n' ' ' | head -c 300)】"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Has Not Been Updated, Stop Continuing Operation!"
|
||||
SLOG_CLEAN
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Has Not Been Updated, Stop Continuing Operation"
|
||||
else
|
||||
if [ "$retry_count" -lt "$max_retries" ]; then
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Download Failed..."
|
||||
LOG_ERROR "【$retry_count/$max_retries】【"$CORE_TYPE"】Core Download Failed, Please Check The Network or Try Again Later..."
|
||||
sleep 2
|
||||
continue
|
||||
else
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Download Failed, Please Check The Network or Try Again Later!"
|
||||
SLOG_CLEAN
|
||||
LOG_ERROR "【"$CORE_TYPE"】Core Download Failed, Please Check The Network or Try Again Later"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
LOG_WARN "No Compiled Version Selected, Please Select In Update Page And Try Again!"
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
else
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Has Not Been Updated, Stop Continuing Operation!"
|
||||
SLOG_CLEAN
|
||||
LOG_TIP "【"$CORE_TYPE"】Core Has Not Been Updated, Stop Continuing Operation"
|
||||
fi
|
||||
|
||||
rm -rf "$TMP_FILE" >/dev/null 2>&1
|
||||
[ "$UPDATE_SUCCESS" = "1" ] && restart=1 || restart=0
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -54,7 +54,7 @@ EOF
|
||||
if [ "$SHOW_DOWNLOAD_PROGRESS" = "1" ] || [ "$SHOW_DOWNLOAD_PROGRESS" = "true" ]; then
|
||||
TEMP_LOG="/tmp/curl_log_$$"
|
||||
|
||||
LOG_OUT "Downloading:【$(basename "$DOWNLOAD_PATH") - 0%】"
|
||||
LOG_OUT "Downloading:【$(basename "$DOWNLOAD_PATH") - 0%】..."
|
||||
|
||||
(
|
||||
if [ -n "$SECRET_KEY" ] && [ -n "$ETAG_HEADER" ]; then
|
||||
@@ -101,7 +101,7 @@ EOF
|
||||
|
||||
if [ -n "$PROGRESS" ] && [ "$PROGRESS" -ne "$LAST_PROGRESS" ]; then
|
||||
if [ "$PROGRESS" -gt "$LAST_PROGRESS" ]; then
|
||||
LOG_OUT "Downloading:【$(basename "$DOWNLOAD_PATH") - ${PROGRESS}%】"
|
||||
LOG_OUT "Downloading:【$(basename "$DOWNLOAD_PATH") - ${PROGRESS}%】..."
|
||||
LAST_PROGRESS="$PROGRESS"
|
||||
fi
|
||||
fi
|
||||
@@ -114,7 +114,7 @@ EOF
|
||||
HTTP_CODE=$(grep -i "^HTTP" "$HEADER_TMP" 2>/dev/null | tail -1 | cut -d' ' -f2)
|
||||
|
||||
if [ "$EXIR_CODE" -eq 0 ] && [ "$LAST_PROGRESS" -ne 100 ]; then
|
||||
LOG_OUT "Downloading:【$(basename "$DOWNLOAD_PATH") - 100%】"
|
||||
LOG_OUT "Downloading:【$(basename "$DOWNLOAD_PATH") - 100%】..."
|
||||
fi
|
||||
|
||||
if [ "$EXIR_CODE" -ne 0 ]; then
|
||||
@@ -132,7 +132,6 @@ EOF
|
||||
OUTPUT=$(DOWNLOAD_FAILURE_OUTPUT "$EXIR_CODE" "$HTTP_CODE" "${OUTPUT:-}")
|
||||
LOG_OUT "【${DOWNLOAD_PATH}】Download Failed:【${OUTPUT}】"
|
||||
rm -f "$HEADER_TMP" "$DOWNLOAD_TMP"
|
||||
SLOG_CLEAN
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
@@ -188,7 +187,6 @@ EOF
|
||||
OUTPUT=$(DOWNLOAD_FAILURE_OUTPUT "$EXIR_CODE" "$HTTP_CODE" "$OUTPUT")
|
||||
LOG_OUT "【${DOWNLOAD_PATH}】Download Failed:【${OUTPUT}】"
|
||||
rm -f "$HEADER_TMP" "$DOWNLOAD_TMP"
|
||||
SLOG_CLEAN
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
@@ -196,7 +194,6 @@ EOF
|
||||
if ! mv -f "$DOWNLOAD_TMP" "$DOWNLOAD_PATH"; then
|
||||
LOG_OUT "【${DOWNLOAD_PATH}】Download Failed:【Unable to save download file】"
|
||||
rm -f "$HEADER_TMP" "$DOWNLOAD_TMP"
|
||||
SLOG_CLEAN
|
||||
return 1
|
||||
fi
|
||||
NEW_ETAG=$(grep -i "^etag:" "$HEADER_TMP" 2>/dev/null | tail -1 | cut -d' ' -f2- | tr -d '\r\n' | sed 's/^"//;s/"$//')
|
||||
|
||||
@@ -794,7 +794,9 @@ EOF
|
||||
|
||||
sed -i -E 's/(([0-9]{1,3}\.){2})[0-9]{1,3}\.[0-9]{1,3}/\1*\.*/g' "$DEBUG_LOG" 2>/dev/null
|
||||
|
||||
sed -i -E 's/(:[0-9a-fA-F]{1,4}){3}/:*:*:*/' "$DEBUG_LOG" 2>/dev/null
|
||||
sed -i -E 's/::[0-9a-fA-F]{1,4}:(([0-9]{1,3}\.){3}[0-9]{1,3})/::*:\1/g' "$DEBUG_LOG" 2>/dev/null
|
||||
sed -i -E 's/([0-9a-fA-F]{1,4}):[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){3}/\1:*:*:*:*\2/g' "$DEBUG_LOG" 2>/dev/null
|
||||
sed -i -E 's/([0-9a-fA-F]{1,4})(:[0-9a-fA-F]{1,4}){0,5}::([0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4})*)?/\1:*::*/g' "$DEBUG_LOG" 2>/dev/null
|
||||
|
||||
sed -i 's/Downloading URL【[^】]*】/Downloading URL【*】/g' "$DEBUG_LOG" 2>/dev/null
|
||||
|
||||
|
||||
@@ -9,16 +9,6 @@ local json = require "luci.jsonc"
|
||||
local datatype = require "luci.cbi.datatypes"
|
||||
local addr = arg[1]
|
||||
|
||||
local function s(e)
|
||||
local t=0
|
||||
local a={' KB',' MB',' GB',' TB',' PB'}
|
||||
repeat
|
||||
e=e/1024
|
||||
t=t+1
|
||||
until(e<=1024)
|
||||
return string.format("%.1f",e)..a[t]
|
||||
end
|
||||
|
||||
local function debug_getcon()
|
||||
local info, ip, host, diag_info
|
||||
ip = fs.lanip()
|
||||
@@ -30,6 +20,7 @@ local function debug_getcon()
|
||||
info = json.parse(info)
|
||||
end
|
||||
if info then
|
||||
local conn_lines = {}
|
||||
for i = 1, #(info.connections) do
|
||||
if info.connections[i].metadata.host == "" then
|
||||
host = "Empty"
|
||||
@@ -37,13 +28,20 @@ local function debug_getcon()
|
||||
host = info.connections[i].metadata.host
|
||||
end
|
||||
if not addr then
|
||||
luci.sys.exec(string.format('echo "%s. SourceIP:【%s】 - Host:【%s】 - DestinationIP:【%s】 - Network:【%s】 - RulePayload:【%s】 - Lastchain:【%s】" >> /tmp/openclash_debug.log', i, (info.connections[i].metadata.sourceIP), host, (info.connections[i].metadata.destinationIP), (info.connections[i].metadata.network), (info.connections[i].rulePayload),(info.connections[i].chains[1])))
|
||||
conn_lines[#conn_lines + 1] = string.format("%d. SourceIP:【%s】 - Host:【%s】 - DestinationIP:【%s】 - Network:【%s】 - RulePayload:【%s】 - Lastchain:【%s】\n",
|
||||
i,
|
||||
tostring(info.connections[i].metadata.sourceIP),
|
||||
tostring(host),
|
||||
tostring(info.connections[i].metadata.destinationIP),
|
||||
tostring(info.connections[i].metadata.network),
|
||||
tostring(info.connections[i].rulePayload),
|
||||
tostring(info.connections[i].chains and info.connections[i].chains[1]))
|
||||
else
|
||||
if datatype.hostname(addr) and string.lower(addr) == host or datatype.ipaddr(addr) and addr == (info.connections[i].metadata.destinationIP) then
|
||||
print("id: "..(info.connections[i].id))
|
||||
print("start: "..(info.connections[i].start))
|
||||
print("download: "..s(info.connections[i].download))
|
||||
print("upload: "..s(info.connections[i].upload))
|
||||
print("download: "..fs.filesize(info.connections[i].download))
|
||||
print("upload: "..fs.filesize(info.connections[i].upload))
|
||||
print("rule: "..(info.connections[i].rule))
|
||||
print("rulePayload: "..(info.connections[i].rulePayload))
|
||||
print("chains: ")
|
||||
@@ -62,6 +60,10 @@ local function debug_getcon()
|
||||
end
|
||||
end
|
||||
end
|
||||
if not addr and #conn_lines > 0 then
|
||||
local existing = fs.readfile("/tmp/openclash_debug.log") or ""
|
||||
fs.writefile("/tmp/openclash_debug.log", existing .. table.concat(conn_lines))
|
||||
end
|
||||
end
|
||||
end
|
||||
os.exit(0)
|
||||
|
||||
@@ -57,7 +57,7 @@ EOF
|
||||
}
|
||||
|
||||
log_unzip_error() {
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Unzip Error!" && SLOG_CLEAN
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Unzip Error!"
|
||||
cleanup_dashboard_tmp
|
||||
del_lock
|
||||
exit 2
|
||||
@@ -121,7 +121,7 @@ EOF
|
||||
fi
|
||||
if mv "$NEW_FILE_DIR" "$TARGET_FILE_DIR" >/dev/null 2>&1 && validate_dashboard_dir "$TARGET_FILE_DIR"; then
|
||||
cleanup_dashboard_tmp
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Download Successful!" && SLOG_CLEAN
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Download Successful!"
|
||||
del_lock
|
||||
exit 0
|
||||
else
|
||||
@@ -137,7 +137,7 @@ EOF
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
if validate_dashboard_dir "$UNPACK_FILE_DIR"; then
|
||||
cleanup_dashboard_tmp
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Download Successful!" && SLOG_CLEAN
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Download Successful!"
|
||||
del_lock
|
||||
exit 0
|
||||
else
|
||||
@@ -145,7 +145,7 @@ EOF
|
||||
fi
|
||||
else
|
||||
cleanup_dashboard_tmp
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Download Error!" && SLOG_CLEAN
|
||||
LOG_OUT "Control Panel【$DASH_NAME - $DASH_TYPE】Download Error!"
|
||||
del_lock
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -174,6 +174,5 @@ case "$1" in
|
||||
;;
|
||||
esac
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -56,6 +56,5 @@ fi
|
||||
|
||||
rm -rf /tmp/Model.bin >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -14,23 +14,29 @@ del_lock() {
|
||||
rm -rf "/tmp/lock/openclash_update.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
early_exit() {
|
||||
dec_job_counter_and_restart "0"
|
||||
del_lock
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
if [ -n "$1" ] && [ "$1" != "one_key_update" ]; then
|
||||
/usr/share/openclash/openclash_version.sh "$1" 2>/dev/null
|
||||
elif [ -n "$2" ]; then
|
||||
/usr/share/openclash/openclash_version.sh "$2" 2>/dev/null
|
||||
else
|
||||
/usr/share/openclash/openclash_version.sh 2>/dev/null
|
||||
RELEASE_BRANCH=$(uci_get_config "release_branch" || echo "master")
|
||||
|
||||
PLUGIN_DIRECT=0
|
||||
if [ -n "$3" ] && echo "$3" | grep -qE '^https?://'; then
|
||||
PLUGIN_DIRECT=1
|
||||
fi
|
||||
|
||||
if [ ! -f "/tmp/openclash_last_version" ]; then
|
||||
lua /usr/share/openclash/openclash_version.lua "$2" 2>/dev/null
|
||||
|
||||
PLUGIN_LATEST=$(jsonfilter -i /tmp/openclash_version_history.json -e "@.${RELEASE_BRANCH}.latest.plugin" 2>/dev/null)
|
||||
|
||||
if [ "$PLUGIN_DIRECT" -eq 0 ] && [ -z "$PLUGIN_LATEST" ]; then
|
||||
LOG_ERROR "Failed to get version information, please try again later..."
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "0"
|
||||
del_lock
|
||||
exit 0
|
||||
early_exit
|
||||
fi
|
||||
|
||||
version_compare() {
|
||||
@@ -59,7 +65,7 @@ run_with_timeout() {
|
||||
(
|
||||
sleep "$timeout_sec"
|
||||
kill $_pid 2>/dev/null
|
||||
sleep 0.5
|
||||
sleep 1
|
||||
kill -9 $_pid 2>/dev/null
|
||||
) &
|
||||
local _watchdog=$!
|
||||
@@ -70,36 +76,65 @@ run_with_timeout() {
|
||||
return $_ret
|
||||
}
|
||||
|
||||
LAST_OPVER="/tmp/openclash_last_version"
|
||||
LAST_VER=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n")
|
||||
LAST_VER=$(echo "$PLUGIN_LATEST" |sed "s/^v//g" |tr -d "\n")
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
OP_CV=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
OP_CV=$(rm -f /lib/apk/db/lock && apk list luci-app-openclash 2>/dev/null|grep "installed" | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
fi
|
||||
OP_LV=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n")
|
||||
RELEASE_BRANCH=$(uci_get_config "release_branch" || echo "master")
|
||||
OP_LV="$LAST_VER"
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
|
||||
#一键更新
|
||||
if [ "$1" = "one_key_update" ]; then
|
||||
if [ "$github_address_mod" = "0" ] && [ -z "$2" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
fi
|
||||
if [ -n "$2" ]; then
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" "$2" >/dev/null 2>&1
|
||||
github_address_mod="$2"
|
||||
else
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" >/dev/null 2>&1
|
||||
github_address_mod=0
|
||||
fi
|
||||
if [ "$PLUGIN_DIRECT" -eq 0 ]; then
|
||||
if [ "$github_address_mod" = "0" ] && [ -z "$2" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - GitHub Address Proxy Options"
|
||||
fi
|
||||
if [ -n "$2" ]; then
|
||||
github_address_mod="$2"
|
||||
else
|
||||
github_address_mod=0
|
||||
fi
|
||||
if echo "$github_address_mod" | grep -q "raw\.githubusercontent\.com"; then
|
||||
github_address_mod=0
|
||||
fi
|
||||
fi
|
||||
elif [ "$1" = "plugin_update" ]; then
|
||||
if [ "$PLUGIN_DIRECT" -eq 0 ]; then
|
||||
if [ "$github_address_mod" = "0" ] && [ -z "$2" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - GitHub Address Proxy Options"
|
||||
fi
|
||||
if [ -n "$2" ]; then
|
||||
github_address_mod="$2"
|
||||
fi
|
||||
if echo "$github_address_mod" | grep -q "raw\.githubusercontent\.com"; then
|
||||
github_address_mod=0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ "$github_address_mod" = "0" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - GitHub Address Proxy Options"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [ -f "$LAST_OPVER" ]; then
|
||||
if [ "$PLUGIN_DIRECT" -eq 1 ]; then
|
||||
# Direct download URL (historical version / downgrade) — skip version compare
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
DOWNLOAD_URL="$3"
|
||||
DOWNLOAD_PATH="/tmp/openclash.ipk"
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
DOWNLOAD_URL="$3"
|
||||
DOWNLOAD_PATH="/tmp/openclash.apk"
|
||||
fi
|
||||
LAST_VER=$(echo "$DOWNLOAD_URL" | grep -oE 'luci-app-openclash[_-][0-9]+(\.[0-9]+)*' | head -1 | sed 's/^luci-app-openclash[_-]//')
|
||||
LOG_TIP "Start downloading【OpenClash - v$LAST_VER】..."
|
||||
elif [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [ -n "$PLUGIN_LATEST" ]; then
|
||||
LOG_TIP "Start downloading【OpenClash - v$LAST_VER】..."
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
@@ -128,6 +163,16 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
DOWNLOAD_PATH="/tmp/openclash.apk"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ -z "$PLUGIN_LATEST" ] || [ -z "$OP_CV" ] || [ -z "$OP_LV" ]; then
|
||||
LOG_ERROR "Failed to get version information, please try again later..."
|
||||
else
|
||||
LOG_TIP "OpenClash has not been updated, stop continuing!"
|
||||
fi
|
||||
early_exit
|
||||
fi
|
||||
|
||||
if [ -n "$DOWNLOAD_URL" ]; then
|
||||
|
||||
retry_count=0
|
||||
max_retries=3
|
||||
@@ -154,22 +199,25 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
max_update_retry=2
|
||||
while [ $update_retry -lt $max_update_retry ]; do
|
||||
update_retry=$((update_retry + 1))
|
||||
run_with_timeout 30 opkg update >/dev/null 2>&1
|
||||
opkg_update_err=$(run_with_timeout 30 opkg update 2>&1)
|
||||
opkg_ret=$?
|
||||
rm -f /var/lock/opkg.lock
|
||||
if [ $opkg_ret -eq 0 ]; then
|
||||
break
|
||||
fi
|
||||
if [ $update_retry -lt $max_update_retry ]; then
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】opkg update failed or timed out, retrying..."
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】opkg update failed or timed out:【$(echo "$opkg_update_err" | tr '\n' ' ' | head -c 300)】, retrying..."
|
||||
sleep 2
|
||||
else
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】opkg update failed, trying pre update test..."
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】opkg update failed:【$(echo "$opkg_update_err" | tr '\n' ' ' | head -c 300)】, trying pre update test..."
|
||||
fi
|
||||
done
|
||||
if [ -s "/tmp/openclash.ipk" ]; then
|
||||
if [ -n "$(opkg install /tmp/openclash.ipk --noaction 2>/dev/null |grep 'Upgrading luci-app-openclash on root' 2>/dev/null)" ]; then
|
||||
opkg_test_err=$(opkg --force-downgrade install /tmp/openclash.ipk --noaction 2>&1)
|
||||
if [ -n "$(echo "$opkg_test_err" | grep -E '(Upgrading|Downgrading) luci-app-openclash on root')" ]; then
|
||||
pre_test_success=true
|
||||
else
|
||||
LOG_ERROR "【$retry_count/$max_retries】【OpenClash - v$LAST_VER】Pre update test failed:【$(echo "$opkg_test_err" | tr '\n' ' ' | head -c 500)】..."
|
||||
fi
|
||||
fi
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
@@ -177,23 +225,25 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
max_update_retry=2
|
||||
while [ $update_retry -lt $max_update_retry ]; do
|
||||
update_retry=$((update_retry + 1))
|
||||
run_with_timeout 30 apk update >/dev/null 2>&1
|
||||
apk_update_err=$(run_with_timeout 30 apk update 2>&1)
|
||||
apk_ret=$?
|
||||
rm -f /lib/apk/db/lock
|
||||
if [ $apk_ret -eq 0 ]; then
|
||||
break
|
||||
fi
|
||||
if [ $update_retry -lt $max_update_retry ]; then
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】apk update failed or timed out, retrying..."
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】apk update failed or timed out:【$(echo "$apk_update_err" | tr '\n' ' ' | head -c 300)】, retrying..."
|
||||
sleep 2
|
||||
else
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】apk update failed, trying pre update test..."
|
||||
LOG_ERROR "【$update_retry/$max_update_retry】【OpenClash - v$LAST_VER】apk update failed:【$(echo "$apk_update_err" | tr '\n' ' ' | head -c 300)】, trying pre update test..."
|
||||
fi
|
||||
done
|
||||
if [ -s "/tmp/openclash.apk" ]; then
|
||||
apk add -s -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk >/dev/null 2>&1
|
||||
apk_test_err=$(apk add -s -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk 2>&1)
|
||||
if [ $? -eq 0 ]; then
|
||||
pre_test_success=true
|
||||
else
|
||||
LOG_ERROR "【$retry_count/$max_retries】【OpenClash - v$LAST_VER】Pre update test failed:【$(echo "$apk_test_err" | tr '\n' ' ' | head -c 500)】..."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -208,14 +258,11 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
continue
|
||||
else
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.ipk, please try to update manually with【opkg install /tmp/openclash.ipk】"
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.ipk, please try to update manually with【opkg --force-downgrade install /tmp/openclash.ipk】"
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】"
|
||||
fi
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "0"
|
||||
del_lock
|
||||
exit 0
|
||||
early_exit
|
||||
fi
|
||||
fi
|
||||
else
|
||||
@@ -227,10 +274,7 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Download Failed after 3 attempts, please check the network or try again later!"
|
||||
rm -rf /tmp/openclash.ipk >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash.apk >/dev/null 2>&1
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
exit 0
|
||||
early_exit
|
||||
fi
|
||||
fi
|
||||
done
|
||||
@@ -299,9 +343,9 @@ install_missing_packages() {
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
retry_count=$((retry_count + 1))
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
opkg install "$pkg"
|
||||
pkg_err=$(opkg install "$pkg" 2>&1)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
apk add "$pkg"
|
||||
pkg_err=$(apk add "$pkg" 2>&1)
|
||||
fi
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
@@ -309,7 +353,7 @@ install_missing_packages() {
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
sleep 2
|
||||
else
|
||||
LOG_ERROR "【$pkg】failed to install, please try to install it manually..."
|
||||
LOG_ERROR "【$pkg】failed to install:【$(echo "$pkg_err" | tr '\n' ' ' | head -c 300)】, please try to install it manually..."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
@@ -333,14 +377,16 @@ while [ $install_retry_count -lt $max_install_retries ]; do
|
||||
installed_before="$installed_before $pkg"
|
||||
fi
|
||||
done
|
||||
opkg install /tmp/openclash.ipk
|
||||
opkg --force-downgrade install /tmp/openclash.ipk >/dev/null 2>&1
|
||||
install_err=$(cat /tmp/openclash_install.log 2>/dev/null)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
for pkg in $packages_to_check; do
|
||||
if apk list "$pkg" |grep "installed" >/dev/null 2>&1; then
|
||||
installed_before="$installed_before $pkg"
|
||||
fi
|
||||
done
|
||||
apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk
|
||||
apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk >/tmp/openclash_install.log 2>&1
|
||||
install_err=$(cat /tmp/openclash_install.log 2>/dev/null)
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
@@ -350,7 +396,7 @@ while [ $install_retry_count -lt $max_install_retries ]; do
|
||||
install_missing_packages "$installed_before"
|
||||
break
|
||||
else
|
||||
LOG_ERROR "【$install_retry_count/$max_install_retries】Installation failed..."
|
||||
LOG_ERROR "【$install_retry_count/$max_install_retries】Installation failed:【$(echo "$install_err" | tr '\n' ' ' | head -c 500)】..."
|
||||
if [ $install_retry_count -lt $max_install_retries ]; then
|
||||
sleep 3
|
||||
fi
|
||||
@@ -365,13 +411,12 @@ if [ "$install_success" = true ]; then
|
||||
fi
|
||||
else
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
LOG_ERROR "OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.ipk, please try to update manually with【opkg install /tmp/openclash.ipk】"
|
||||
LOG_ERROR "OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.ipk, please try to update manually with【opkg --force-downgrade install /tmp/openclash.ipk】【$(echo "$install_err" | tr '\n' ' ' | head -c 500)】"
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
LOG_ERROR "OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】"
|
||||
LOG_ERROR "OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】【$(echo "$install_err" | tr '\n' ' ' | head -c 500)】"
|
||||
fi
|
||||
fi
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
del_update_lock
|
||||
EOF
|
||||
chmod 4755 /tmp/openclash_update.sh
|
||||
@@ -379,10 +424,7 @@ EOF
|
||||
if [ ! -f "/tmp/openclash_update.sh" ] || [ ! -s "/tmp/openclash_update.sh" ] || [ ! -x "/tmp/openclash_update.sh" ]; then
|
||||
LOG_ERROR "Failed to create update script!"
|
||||
rm -rf /tmp/openclash_update.sh
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
exit 1
|
||||
early_exit 1
|
||||
fi
|
||||
|
||||
retry_count=0
|
||||
@@ -413,14 +455,6 @@ EOF
|
||||
fi
|
||||
|
||||
(sleep 15; rm -f /tmp/openclash_update.sh) &
|
||||
else
|
||||
if [ ! -f "$LAST_OPVER" ] || [ -z "$OP_CV" ] || [ -z "$OP_LV" ]; then
|
||||
LOG_ERROR "Failed to get version information, please try again later..."
|
||||
else
|
||||
LOG_TIP "OpenClash has not been updated, stop continuing!"
|
||||
fi
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
|
||||
del_lock
|
||||
@@ -0,0 +1,644 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
require "nixio"
|
||||
require "luci.model.uci"
|
||||
local fs = require "luci.openclash"
|
||||
local json = require "luci.jsonc"
|
||||
|
||||
local M = {}
|
||||
|
||||
local VERSION_CACHE_FILE = "/tmp/openclash_version_history.json"
|
||||
local CDN_CACHE_FILE = "/tmp/openclash_cdn_info.json"
|
||||
|
||||
local function trim(s)
|
||||
if not s then return "" end
|
||||
return (s:gsub("^%s+", ""):gsub("%s+$", ""))
|
||||
end
|
||||
|
||||
function M.is_valid_version(s)
|
||||
if not s or s == "" then return false end
|
||||
s = trim(s)
|
||||
if s == "" then return false end
|
||||
if s:match("^<") then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
function M.is_oix_mode()
|
||||
local oix_token = fs.uci_get_config("config", "oix_token") or ""
|
||||
return oix_token ~= ""
|
||||
end
|
||||
|
||||
function try_read(fd, maxlen)
|
||||
local pfds = {
|
||||
{ fd = fd, events = nixio.poll_flags("in", "hup", "err") }
|
||||
}
|
||||
local nfds = nixio.poll(pfds, 0)
|
||||
if nfds and nfds > 0 then
|
||||
local buf = fd:read(maxlen or 4096)
|
||||
if buf and #buf > 0 then
|
||||
return buf
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function read_json(path)
|
||||
if not fs.access(path) then return nil end
|
||||
local raw = fs.readfile(path)
|
||||
if not raw or raw == "" then return nil end
|
||||
local ok, parsed = pcall(json.parse, raw)
|
||||
if ok and parsed and type(parsed) == "table" then
|
||||
return parsed
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function write_json(path, data)
|
||||
local tmp = path .. ".tmp"
|
||||
fs.writefile(tmp, json.stringify(data))
|
||||
os.rename(tmp, path)
|
||||
end
|
||||
|
||||
local function read_version_cache()
|
||||
return read_json(VERSION_CACHE_FILE)
|
||||
end
|
||||
|
||||
local function update_version_cache(updater)
|
||||
local parsed = read_version_cache() or {}
|
||||
updater(parsed)
|
||||
write_json(VERSION_CACHE_FILE, parsed)
|
||||
end
|
||||
|
||||
local DEFAULT_CDN_LIST = {
|
||||
"https://ghfast.top/",
|
||||
"https://github.dpik.top/",
|
||||
"https://gh-proxy.com/",
|
||||
"https://git.yylx.win/"
|
||||
}
|
||||
|
||||
local function cdn_list()
|
||||
local list = fs.cdn_list()
|
||||
if #list > 0 then return list end
|
||||
return DEFAULT_CDN_LIST
|
||||
end
|
||||
|
||||
local function raw_url(path)
|
||||
return "https://raw.githubusercontent.com/vernesong/OpenClash/" .. path
|
||||
end
|
||||
|
||||
local function build_fetch_urls(mod, path)
|
||||
if mod == "0" or mod == "" then
|
||||
local urls = { raw_url(path) }
|
||||
for _, cdn in ipairs(cdn_list()) do
|
||||
urls[#urls + 1] = cdn .. raw_url(path)
|
||||
end
|
||||
return urls
|
||||
end
|
||||
if mod == "https://cdn.jsdelivr.net/" or mod == "https://fastly.jsdelivr.net/" or mod == "https://testingcf.jsdelivr.net/" then
|
||||
return { mod .. "gh/vernesong/OpenClash@" .. path }
|
||||
end
|
||||
return { mod .. raw_url(path) }
|
||||
end
|
||||
|
||||
local function fork_curl(url, timeout)
|
||||
local fdi, fdo = nixio.pipe()
|
||||
if not fdi or not fdo then return nil end
|
||||
local cmd = string.format('curl -sL -m %d "%s" 2>/dev/null', timeout or 5, url)
|
||||
local child = nixio.fork()
|
||||
if child > 0 then
|
||||
fdo:close()
|
||||
return { pid = child, fdi = fdi, buf = "", done = false }
|
||||
elseif child == 0 then
|
||||
nixio.dup(fdo, nixio.stdout)
|
||||
fdi:close()
|
||||
fdo:close()
|
||||
nixio.exec("/bin/sh", "-c", cmd)
|
||||
else
|
||||
if fdi then fdi:close() end
|
||||
if fdo then fdo:close() end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local MAX_URL_BATCH = 3
|
||||
|
||||
local function try_fetch(urls, validator)
|
||||
if not urls or #urls == 0 then return "" end
|
||||
local timeout = (#urls > 1) and 5 or 10
|
||||
local delay = 50000000
|
||||
local max_wait = 100
|
||||
local jobs = {}
|
||||
local active = 0
|
||||
local idx = 1
|
||||
local function launch_batch()
|
||||
local n = 0
|
||||
while idx <= #urls and n < MAX_URL_BATCH do
|
||||
local job = fork_curl(urls[idx], timeout)
|
||||
if job then
|
||||
jobs[#jobs + 1] = job
|
||||
active = active + 1
|
||||
end
|
||||
idx = idx + 1
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
launch_batch()
|
||||
for _ = 1, max_wait do
|
||||
local winner = ""
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then
|
||||
local ok_r, buf = pcall(try_read, job.fdi, 4096)
|
||||
if ok_r and buf then job.buf = job.buf .. buf end
|
||||
local ok_w, wpid = pcall(nixio.waitpid, job.pid, "nohang")
|
||||
if ok_w and wpid then
|
||||
while true do
|
||||
local ok_b, b = pcall(try_read, job.fdi, 4096)
|
||||
if not ok_b or not b then break end
|
||||
job.buf = job.buf .. b
|
||||
end
|
||||
pcall(job.fdi.close, job.fdi)
|
||||
job.done = true
|
||||
active = active - 1
|
||||
if winner == "" and job.buf ~= "" and (not validator or validator(job.buf)) then
|
||||
winner = job.buf
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if winner ~= "" then
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then
|
||||
pcall(job.fdi.close, job.fdi)
|
||||
nixio.kill(job.pid, 9)
|
||||
end
|
||||
end
|
||||
return trim(winner)
|
||||
end
|
||||
if active == 0 then
|
||||
if idx <= #urls then
|
||||
launch_batch()
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
nixio.nanosleep(0, delay)
|
||||
delay = math.min(delay * 2, 200000000)
|
||||
end
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then
|
||||
pcall(job.fdi.close, job.fdi)
|
||||
nixio.kill(job.pid, 9)
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function M.prepare_oix_cdn_data(force)
|
||||
if not M.is_oix_mode() then
|
||||
return false, "", ""
|
||||
end
|
||||
|
||||
local parsed = read_version_cache()
|
||||
if parsed and parsed.oix and parsed.oix.cached_at then
|
||||
local age = os.time() - parsed.oix.cached_at
|
||||
local ttl = parsed.oix.cache_ttl or 300
|
||||
if age < 5 or (not force and age < ttl) then
|
||||
return true, parsed.oix.ver or "", parsed.oix.error or ""
|
||||
end
|
||||
end
|
||||
|
||||
local function fork_oix_version(url)
|
||||
local fdi, fdo = nixio.pipe()
|
||||
if not fdi or not fdo then return nil end
|
||||
local cmd = string.format('curl -sL -m 3 --connect-timeout 3 "%s" 2>/dev/null', url)
|
||||
local child = nixio.fork()
|
||||
if child > 0 then
|
||||
fdo:close()
|
||||
return { pid = child, fdi = fdi, buf = "" }
|
||||
elseif child == 0 then
|
||||
nixio.dup(fdo, nixio.stdout)
|
||||
fdi:close()
|
||||
fdo:close()
|
||||
nixio.exec("/bin/sh", "-c", cmd)
|
||||
else
|
||||
if fdi then fdi:close() end
|
||||
if fdo then fdo:close() end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local jobs = {}
|
||||
local dl_job = fork_oix_version("https://dl.dler.io/mihomo-oix/version.txt?tag=Pre-Alpha")
|
||||
if dl_job then jobs[#jobs + 1] = dl_job end
|
||||
local gh_job = fork_oix_version("https://github.com/vernesong/mihomo-oix/releases/download/Pre-Alpha/version.txt")
|
||||
if gh_job then jobs[#jobs + 1] = gh_job end
|
||||
|
||||
if #jobs == 0 then
|
||||
return true, "", "error"
|
||||
end
|
||||
|
||||
local ver = ""
|
||||
local delay = 50000000
|
||||
local max_wait = 40
|
||||
for _ = 1, max_wait do
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then
|
||||
local ok_r, buf = pcall(try_read, job.fdi, 4096)
|
||||
if ok_r and buf then job.buf = job.buf .. buf end
|
||||
local ok_w, wpid = pcall(nixio.waitpid, job.pid, "nohang")
|
||||
if ok_w and wpid then
|
||||
while true do
|
||||
local ok_b, b = pcall(try_read, job.fdi, 4096)
|
||||
if not ok_b or not b then break end
|
||||
job.buf = job.buf .. b
|
||||
end
|
||||
pcall(job.fdi.close, job.fdi)
|
||||
job.done = true
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, job in ipairs(jobs) do
|
||||
if job.done and ver == "" then
|
||||
local candidate = trim(job.buf:gsub("[\n\r]+", ""))
|
||||
if M.is_valid_version(candidate) then
|
||||
ver = candidate
|
||||
end
|
||||
end
|
||||
end
|
||||
if ver ~= "" then
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then
|
||||
pcall(job.fdi.close, job.fdi)
|
||||
nixio.kill(job.pid, 9)
|
||||
end
|
||||
end
|
||||
update_version_cache(function(p) p.oix = { ver = ver, error = "", cache_ttl = 300, cached_at = os.time() } end)
|
||||
return true, ver, ""
|
||||
end
|
||||
local all_done = true
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then all_done = false break end
|
||||
end
|
||||
if all_done then break end
|
||||
nixio.nanosleep(0, delay)
|
||||
delay = math.min(delay * 2, 200000000)
|
||||
end
|
||||
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then
|
||||
pcall(job.fdi.close, job.fdi)
|
||||
nixio.kill(job.pid, 9)
|
||||
end
|
||||
end
|
||||
|
||||
update_version_cache(function(p) p.oix = { ver = "", error = "error", cache_ttl = 5, cached_at = os.time() } end)
|
||||
return true, "", "error"
|
||||
end
|
||||
|
||||
local function fork_file_fetch(sha, file_path, mod)
|
||||
local urls = build_fetch_urls(mod, sha .. "/" .. file_path)
|
||||
if #urls == 0 then return nil end
|
||||
return { children = {}, idx = 1, buf = "", done = false, launched = false, sha = sha, urls = urls }
|
||||
end
|
||||
|
||||
local function launch_file_batch(job)
|
||||
local timeout = (#job.urls > 1) and 5 or 10
|
||||
local n = 0
|
||||
while job.idx <= #job.urls and n < MAX_URL_BATCH do
|
||||
local child = fork_curl(job.urls[job.idx], timeout)
|
||||
if child then job.children[#job.children + 1] = child end
|
||||
job.idx = job.idx + 1
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function collect_fork_results(jobs, max_jobs)
|
||||
local results = {}
|
||||
local active = 0
|
||||
local delay = 50000000
|
||||
local max_iter = 250
|
||||
|
||||
for _ = 1, max_iter do
|
||||
while active < max_jobs do
|
||||
local launched = false
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.launched then
|
||||
job.launched = true
|
||||
active = active + 1
|
||||
launched = true
|
||||
launch_file_batch(job)
|
||||
if #job.children == 0 then
|
||||
job.done = true
|
||||
active = active - 1
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
if not launched then break end
|
||||
end
|
||||
|
||||
for _, job in ipairs(jobs) do
|
||||
if job.launched and not job.done then
|
||||
local winner = ""
|
||||
local all_children_done = true
|
||||
for _, child in ipairs(job.children) do
|
||||
if not child.done then
|
||||
all_children_done = false
|
||||
local ok_r, buf = pcall(try_read, child.fdi, 4096)
|
||||
if ok_r and buf then child.buf = child.buf .. buf end
|
||||
local ok_w, wpid = pcall(nixio.waitpid, child.pid, "nohang")
|
||||
if ok_w and wpid then
|
||||
while true do
|
||||
local ok_b, b = pcall(try_read, child.fdi, 4096)
|
||||
if not ok_b or not b then break end
|
||||
child.buf = child.buf .. b
|
||||
end
|
||||
pcall(child.fdi.close, child.fdi)
|
||||
child.done = true
|
||||
if winner == "" and child.buf ~= "" then
|
||||
winner = child.buf
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if winner ~= "" then
|
||||
for _, child in ipairs(job.children) do
|
||||
if not child.done then
|
||||
pcall(child.fdi.close, child.fdi)
|
||||
nixio.kill(child.pid, 9)
|
||||
end
|
||||
end
|
||||
job.done = true
|
||||
active = active - 1
|
||||
results[job.sha] = trim(winner)
|
||||
elseif all_children_done then
|
||||
if job.idx <= #job.urls then
|
||||
launch_file_batch(job)
|
||||
else
|
||||
job.done = true
|
||||
active = active - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local all_done = true
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then all_done = false break end
|
||||
end
|
||||
if all_done then break end
|
||||
|
||||
nixio.nanosleep(0, delay)
|
||||
delay = math.min(delay * 2, 200000000)
|
||||
end
|
||||
|
||||
for _, job in ipairs(jobs) do
|
||||
if not job.done then
|
||||
if job.children then
|
||||
for _, child in ipairs(job.children) do
|
||||
if not child.done then
|
||||
pcall(child.fdi.close, child.fdi)
|
||||
nixio.kill(child.pid, 9)
|
||||
end
|
||||
end
|
||||
end
|
||||
job.done = true
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
end
|
||||
|
||||
local function html_unescape(s)
|
||||
if not s then return "" end
|
||||
s = s:gsub("&", "&")
|
||||
s = s:gsub("<", "<")
|
||||
s = s:gsub(">", ">")
|
||||
s = s:gsub(""", '"')
|
||||
s = s:gsub("'", "'")
|
||||
s = s:gsub("'", "'")
|
||||
return s
|
||||
end
|
||||
|
||||
local function build_feed_urls(mod, path)
|
||||
local feed = "https://github.com/vernesong/OpenClash/commits/" .. path .. ".atom"
|
||||
if mod == "0" or mod == "" then
|
||||
local urls = { feed }
|
||||
for _, cdn in ipairs(cdn_list()) do
|
||||
urls[#urls + 1] = cdn .. feed
|
||||
end
|
||||
return urls
|
||||
end
|
||||
if mod == "https://cdn.jsdelivr.net/" or mod == "https://fastly.jsdelivr.net/" or mod == "https://testingcf.jsdelivr.net/" then
|
||||
return { feed }
|
||||
end
|
||||
return { mod .. feed, feed }
|
||||
end
|
||||
|
||||
local function fetch_commit_feed(mod, path)
|
||||
return try_fetch(build_feed_urls(mod, path), function(buf)
|
||||
return buf:match("<entry") ~= nil
|
||||
end)
|
||||
end
|
||||
|
||||
local function parse_commit_feed(raw, max_count)
|
||||
local commits = {}
|
||||
if raw and raw ~= "" then
|
||||
local n = 0
|
||||
for entry in raw:gmatch("<entry>(.-)</entry>") do
|
||||
n = n + 1
|
||||
if n > max_count then break end
|
||||
local sha = entry:match("<id>[^<]*/([0-9a-f]+)</id>")
|
||||
if sha then
|
||||
local date = entry:match("<updated>(.-)</updated>") or ""
|
||||
local title = entry:match("<title>(.-)</title>") or ""
|
||||
title = trim(title)
|
||||
commits[#commits + 1] = { sha = sha, date = date, message = html_unescape(title) }
|
||||
end
|
||||
end
|
||||
end
|
||||
return commits
|
||||
end
|
||||
|
||||
function M.fetch_version_history(branch, force, cdn, latest_only)
|
||||
local result = { plugin = {}, core_meta = {}, core_smart = {}, latest = nil, error = nil, oix_ver = "" }
|
||||
local cur_oix = M.is_oix_mode()
|
||||
local skip_core = cur_oix
|
||||
local github_address_mod = fs.uci_get_config("config", "github_address_mod") or "0"
|
||||
if cdn and cdn ~= "" then
|
||||
github_address_mod = cdn
|
||||
if github_address_mod:match("raw%.githubusercontent%.com") then
|
||||
github_address_mod = "0"
|
||||
end
|
||||
end
|
||||
|
||||
if not force then
|
||||
local parsed = read_version_cache()
|
||||
if parsed and parsed[branch] and parsed[branch].cached_at then
|
||||
local blk = parsed[branch]
|
||||
local ttl = blk.cache_ttl or 300
|
||||
if os.time() - blk.cached_at < ttl and blk.oix == cur_oix then
|
||||
if latest_only then
|
||||
local lt = blk.latest
|
||||
if lt and lt.plugin and lt.plugin ~= "" and (cur_oix or (lt.core_meta and lt.core_meta ~= "")) then
|
||||
return blk
|
||||
end
|
||||
elseif blk.plugin and #blk.plugin > 0 then
|
||||
return blk
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if latest_only then
|
||||
local plugin_latest = ""
|
||||
local core_meta_latest = ""
|
||||
local core_smart_latest = ""
|
||||
|
||||
local plugin_raw = try_fetch(build_fetch_urls(github_address_mod, "package/" .. branch .. "/version"))
|
||||
if plugin_raw and plugin_raw ~= "" then
|
||||
plugin_latest = trim(plugin_raw:match("^[^\n\r]*") or "")
|
||||
end
|
||||
|
||||
if not cur_oix then
|
||||
local core_raw = try_fetch(build_fetch_urls(github_address_mod, "core/" .. branch .. "/core_version"))
|
||||
if core_raw and core_raw ~= "" then
|
||||
core_meta_latest = trim(core_raw:match("^[^\n\r]*") or "")
|
||||
local after = core_raw:match("[\n\r]+(.*)")
|
||||
if after then
|
||||
core_smart_latest = trim(after:match("^[^\n\r]*") or "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
result.latest = { plugin = plugin_latest, core_meta = core_meta_latest, core_smart = core_smart_latest }
|
||||
if plugin_latest == "" then
|
||||
result.error = "network_error"
|
||||
end
|
||||
if cur_oix then
|
||||
M.prepare_oix_cdn_data(force)
|
||||
end
|
||||
result.cache_ttl = (plugin_latest == "") and 5 or 300
|
||||
result.cached_at = os.time()
|
||||
result.oix = cur_oix
|
||||
|
||||
update_version_cache(function(parsed)
|
||||
local blk = parsed[branch] or {}
|
||||
blk.latest = result.latest
|
||||
blk.error = result.error
|
||||
blk.cache_ttl = result.cache_ttl
|
||||
blk.cached_at = result.cached_at
|
||||
blk.oix = cur_oix
|
||||
blk.plugin = nil
|
||||
blk.core_meta = nil
|
||||
blk.core_smart = nil
|
||||
blk.oix_ver = nil
|
||||
parsed[branch] = blk
|
||||
end)
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local plugin_feed = fetch_commit_feed(github_address_mod, "package/" .. branch .. "/version")
|
||||
local plugin_commits = parse_commit_feed(plugin_feed, 5)
|
||||
if #plugin_commits > 0 then
|
||||
local file_jobs = {}
|
||||
for _, c in ipairs(plugin_commits) do
|
||||
local job = fork_file_fetch(c.sha, branch .. "/version", github_address_mod)
|
||||
if job then file_jobs[#file_jobs + 1] = job end
|
||||
end
|
||||
|
||||
local file_results = collect_fork_results(file_jobs, 2)
|
||||
|
||||
for _, c in ipairs(plugin_commits) do
|
||||
local raw = file_results[c.sha]
|
||||
local ver
|
||||
if raw and raw ~= "" then
|
||||
ver = trim(raw:match("^[^\n\r]*") or "")
|
||||
if not M.is_valid_version(ver) then ver = nil end
|
||||
end
|
||||
result.plugin[#result.plugin + 1] = {
|
||||
version = ver,
|
||||
date = c.date,
|
||||
sha = c.sha,
|
||||
message = c.message
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if not skip_core then
|
||||
local core_feed = fetch_commit_feed(github_address_mod, "core/" .. branch .. "/core_version")
|
||||
local core_commits = parse_commit_feed(core_feed, 5)
|
||||
if #core_commits > 0 then
|
||||
local file_jobs = {}
|
||||
for _, c in ipairs(core_commits) do
|
||||
local job = fork_file_fetch(c.sha, branch .. "/core_version", github_address_mod)
|
||||
if job then file_jobs[#file_jobs + 1] = job end
|
||||
end
|
||||
|
||||
local file_results = collect_fork_results(file_jobs, 2)
|
||||
|
||||
for _, c in ipairs(core_commits) do
|
||||
local content = file_results[c.sha]
|
||||
if content and content ~= "" then
|
||||
local meta_ver = content:match("^[^\n\r]*")
|
||||
local after_first = content:match("[\n\r]+(.*)")
|
||||
local smart_ver = after_first and after_first:match("^[^\n\r]*") or nil
|
||||
if meta_ver then
|
||||
meta_ver = trim(meta_ver)
|
||||
if M.is_valid_version(meta_ver) then
|
||||
result.core_meta[#result.core_meta + 1] = { version = meta_ver, date = c.date, sha = c.sha }
|
||||
end
|
||||
end
|
||||
if smart_ver then
|
||||
smart_ver = trim(smart_ver)
|
||||
if M.is_valid_version(smart_ver) then
|
||||
result.core_smart[#result.core_smart + 1] = { version = smart_ver, date = c.date, sha = c.sha }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
result.latest = {
|
||||
plugin = (result.plugin[1] and result.plugin[1].version) or "",
|
||||
core_meta = (result.core_meta[1] and result.core_meta[1].version) or "",
|
||||
core_smart = (result.core_smart[1] and result.core_smart[1].version) or ""
|
||||
}
|
||||
|
||||
if cur_oix then
|
||||
local _, oix_ver = M.prepare_oix_cdn_data(force)
|
||||
if oix_ver and oix_ver ~= "" then
|
||||
result.oix_ver = oix_ver
|
||||
end
|
||||
end
|
||||
|
||||
local cache_ttl = 300
|
||||
if #result.plugin == 0 then
|
||||
if not plugin_feed or plugin_feed == "" then
|
||||
result.error = "network_error"
|
||||
cache_ttl = 5
|
||||
else
|
||||
result.error = "parse_error"
|
||||
cache_ttl = 5
|
||||
end
|
||||
end
|
||||
|
||||
result.cache_ttl = cache_ttl
|
||||
result.cached_at = os.time()
|
||||
result.oix = cur_oix
|
||||
|
||||
update_version_cache(function(parsed)
|
||||
parsed[branch] = result
|
||||
end)
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
if arg and arg[0] and arg[0]:match("openclash_version%.lua$") then
|
||||
local branch = fs.uci_get_config("config", "release_branch") or "master"
|
||||
M.fetch_version_history(branch, arg[2], arg[1], arg[3] ~= "0")
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 869>"/tmp/lock/openclash_version.lock" 2>/dev/null
|
||||
flock -x 869 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 869 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_version.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
|
||||
version_compare() {
|
||||
local current_ver="$1"
|
||||
local latest_ver="$2"
|
||||
|
||||
if echo "1.0.0" | sort -V >/dev/null 2>&1; then
|
||||
if [ "$(printf '%s\n%s\n' "$current_ver" "$latest_ver" | sort -V | head -n1)" = "$current_ver" ] && [ "$current_ver" != "$latest_ver" ]; then
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
local cv_num=$(echo "$current_ver" | awk -F '.' '{print $2$3}' 2>/dev/null)
|
||||
local lv_num=$(echo "$latest_ver" | awk -F '.' '{print $2$3}' 2>/dev/null)
|
||||
if [ -n "$cv_num" ] && [ -n "$lv_num" ] && [ "$(expr "$lv_num" \> "$cv_num")" -eq 1 ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
DOWNLOAD_FILE="/tmp/openclash_last_version"
|
||||
RELEASE_BRANCH=$(uci_get_config "release_branch" || echo "master")
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
OP_CV=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
OP_CV=$(rm -f /lib/apk/db/lock && apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
fi
|
||||
OP_LV=$(sed -n 1p "$DOWNLOAD_FILE" 2>/dev/null |sed "s/^v//g" |tr -d "\n")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
if [ -n "$1" ]; then
|
||||
github_address_mod="$1"
|
||||
fi
|
||||
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/vernesong/OpenClash@package/${RELEASE_BRANCH}/version"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://raw.githubusercontent.com/vernesong/OpenClash/package/${RELEASE_BRANCH}/version"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://raw.githubusercontent.com/vernesong/OpenClash/package/${RELEASE_BRANCH}/version"
|
||||
fi
|
||||
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "$DOWNLOAD_FILE" "$DOWNLOAD_FILE"
|
||||
|
||||
if [ "$?" -eq 0 ]; then
|
||||
OP_LV=$(sed -n 1p $DOWNLOAD_FILE 2>/dev/null |awk -F 'v' '{print $2}' |awk -F '.' '{print $2$3}' 2>/dev/null)
|
||||
if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [ -f "$DOWNLOAD_FILE" ]; then
|
||||
sed -i '/^https:/,$d' $DOWNLOAD_FILE
|
||||
fi
|
||||
fi
|
||||
|
||||
del_lock
|
||||
@@ -244,7 +244,7 @@ fi
|
||||
LOG_WATCHDOG "Setting Firewall For Rules Order..."
|
||||
/etc/init.d/openclash reload "firewall"
|
||||
let FIREWALL_RELOAD++
|
||||
elif [ -n "$(ip tuntap list |grep utun)" ] && [ -z "$(ip route list table 354)" ]; then
|
||||
elif [ -n "$(ip link show utun 2>/dev/null)" ] && [ -z "$(ip route list table 354)" ]; then
|
||||
## 路由表检查
|
||||
LOG_WATCHDOG "Setting Firewall For IP Rules Table Recreate..."
|
||||
/etc/init.d/openclash reload "firewall"
|
||||
@@ -470,6 +470,5 @@ fi
|
||||
LOG_ERROR "Streaming Unlock Could not Work Because of Router-Self Proxy Disabled, Exiting..."
|
||||
fi
|
||||
|
||||
SLOG_CLEAN
|
||||
sleep 60
|
||||
done 2>/dev/null
|
||||
@@ -0,0 +1,13 @@
|
||||
# CDN proxy address list (one URL per line, "#" starts a comment)
|
||||
# Comment out a line with "#" to temporarily disable it
|
||||
https://ghfast.top/
|
||||
https://git.yylx.win/
|
||||
https://cdn.akaere.online/
|
||||
https://gh-proxy.com/
|
||||
https://gh.jasonzeng.dev/
|
||||
https://ghproxy.monkeyray.net/
|
||||
https://down.mxw.xx.kg/
|
||||
https://github.tbap.top/
|
||||
https://ghm.078465.xyz/
|
||||
https://gh.monlor.com/
|
||||
https://gh.idayer.com/
|
||||
@@ -35,6 +35,10 @@ ACL4SSR 规则 WithChinaIp WithGFW,ACL4SSR_WithChinaIp_WithGFW.ini,https://raw.g
|
||||
ACL4SSR 规则 WithGFW,ACL4SSR_WithGFW.ini,https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_WithGFW.ini
|
||||
eHpo1 规则,ehpo1_main.ini,https://gist.githubusercontent.com/tindy2013/1fa08640a9088ac8652dbd40c5d2715b/raw/ehpo1_main.ini
|
||||
Aethersailor 规则 标准版 Custom_Clash,Custom_Clash.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash.ini
|
||||
Aethersailor 规则 标准版 故障转移,Custom_Clash_Fallback.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash_Fallback.ini
|
||||
Aethersailor 规则 轻量版 Custom_Clash_Lite,Custom_Clash_Lite.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash_Lite.ini
|
||||
Aethersailor 规则 轻量版 故障转移,Custom_Clash_Lite_Fallback.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash_Lite_Fallback.ini
|
||||
Aethersailor 规则 极简版(GFW) Custom_Clash_GFW,Custom_Clash_GFW.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash_GFW.ini
|
||||
Aethersailor 规则 极简版(GFW) 故障转移,Custom_Clash_GFW_Fallback.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash_GFW_Fallback.ini
|
||||
Aethersailor 规则 重度分流版 Custom_Clash_Full,Custom_Clash_Full.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash_Full.ini
|
||||
Aethersailor 规则 重度分流版 故障转移,Custom_Clash_Full_Fallback.ini,https://raw.githubusercontent.com/Aethersailor/Custom_OpenClash_Rules/refs/heads/main/cfg/Custom_Clash_Full_Fallback.ini
|
||||
@@ -92,7 +92,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); Value$2=$3; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); Value$2=$3; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$3') then Value_1 = YAML.load_file('$3'); if not '$4'.empty? then Value$2=Value_1['$4']; else Value$2=Value_1 end else if not '$4'.empty? then Value.delete('$4'); end; end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$3') then Value_1 = YAML.load_file('$3'); if not '$4'.empty? then Value$2=Value_1['$4']; else Value$2=Value_1 end else if not '$4'.empty? then Value.delete('$4'); end; end; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$3') then Value_1 = YAML.load_file('$3'); if not Value$2 then Value$2 = {}; end; if Value_1$4 && Value_1$4.is_a?(Hash) then Value$2.merge!(Value_1$4) end end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$3') then Value_1 = YAML.load_file('$3'); if not Value$2 then Value$2 = {}; end; if Value_1$4 && Value_1$4.is_a?(Hash) then Value$2.merge!(Value_1$4) end end; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 then Value$2=Value$2.uniq; end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 then Value$2=Value$2.uniq; end; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 then Value$2 = {}; end; Value$2.merge!({$3}); File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 then Value$2 = {}; end; Value$2.merge!({$3}); YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$4') then Value_1 = YAML.load_file('$4'); if not Value$2 or Value$2.nil? then Value$2 = []; end; if Value_1$5 && Value_1$5.is_a?(Array) then idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; Value_1$5.reverse.each{|x| Value$2.insert(idx,x); idx += 1}; Value$2=Value$2.uniq end end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$4') then Value_1 = YAML.load_file('$4'); if not Value$2 or Value$2.nil? then Value$2 = []; end; if Value_1$5 && Value_1$5.is_a?(Array) then idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; Value_1$5.reverse.each{|x| Value$2.insert(idx,x); idx += 1}; Value$2=Value$2.uniq end end; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$3') then Value_1 = YAML.load_file('$3'); if not Value$2 or Value$2.nil? then Value$2 = []; end; if Value_1$4 && Value_1$4.is_a?(Array) then Value$2=(Value_1$4+Value$2).uniq else Value$2=Value$2.uniq end end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if File::exist?('$3') then Value_1 = YAML.load_file('$3'); if not Value$2 or Value$2.nil? then Value$2 = []; end; if Value_1$4 && Value_1$4.is_a?(Array) then Value$2=(Value_1$4+Value$2).uniq else Value$2=Value$2.uniq end end; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 or Value$2.nil? then Value$2 = []; end; idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; Value$2=Value$2.insert(idx,'$4').uniq; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 or Value$2.nil? then Value$2 = []; end; idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; Value$2=Value$2.insert(idx,'$4').uniq; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 or Value$2.nil? then Value$2 = []; end; idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; Value$2=Value$2.insert(idx,$4).uniq; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 or Value$2.nil? then Value$2 = []; end; idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; Value$2=Value$2.insert(idx,$4).uniq; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 or Value$2.nil? then Value$2 = []; end; if $4.is_a?(Array) then idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; $4.reverse.each{|x| Value$2=Value$2.insert(idx,x); idx += 1}; Value$2=Value$2.uniq end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if not Value$2 or Value$2.nil? then Value$2 = []; end; if $4.is_a?(Array) then idx = [$3.to_i, 0].max; idx = [idx, Value$2.length].min; $4.reverse.each{|x| Value$2=Value$2.insert(idx,x); idx += 1}; Value$2=Value$2.uniq end; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -247,9 +247,9 @@ if openclash_custom_overwrite; then
|
||||
return
|
||||
fi
|
||||
if [ -z "$2" ]; then
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); Value.delete('$3'); File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); Value.delete('$3'); YAML.dump(Value, '$1')"
|
||||
else
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 then if Value$2.is_a?(Hash) then Value$2.delete('$3') elsif Value$2.is_a?(Array) then Value$2.delete('$3') end end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 then if Value$2.is_a?(Hash) then Value$2.delete('$3') elsif Value$2.is_a?(Array) then Value$2.delete('$3') end end; YAML.dump(Value, '$1')"
|
||||
fi
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
@@ -265,7 +265,7 @@ if openclash_custom_overwrite; then
|
||||
write_ruby_part "$RUBY_YAML_PARSE"
|
||||
return
|
||||
fi
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 && Value$2.is_a?(Hash) then if Value$2['$3'] && Value$2['$3'].is_a?(Hash) then Value$2['$3']$4 = '$5' end end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 && Value$2.is_a?(Hash) then if Value$2['$3'] && Value$2['$3'].is_a?(Hash) then Value$2['$3']$4 = '$5' end end; YAML.dump(Value, '$1')"
|
||||
run_ruby_part "$RUBY_YAML_PARSE"
|
||||
}
|
||||
|
||||
@@ -288,9 +288,9 @@ if openclash_custom_overwrite; then
|
||||
return
|
||||
fi
|
||||
if [ -n "$3" ] && [ -n "$4" ] && [ -n "$5" ] && [ -n "$6" ]; then
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 && Value$2.is_a?(Array) then Value$2.map!{|x| if x.is_a?(Hash) && x$3 == '$4' then x$5='$6' end; x}; Value$2.uniq! end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 && Value$2.is_a?(Array) then Value$2.map!{|x| if x.is_a?(Hash) && x$3 == '$4' then x$5='$6' end; x}; Value$2.uniq! end; YAML.dump(Value, '$1')"
|
||||
elif [ -z "$3" ] && [ -n "$4" ] && [ -z "$5" ] && [ -n "$6" ]; then
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 && Value$2.is_a?(Array) then Value$2.map!{|x| if x == '$4' then '$6' else x end}; Value$2.uniq! end; File.open('$1','w') {|f| YAML.dump(Value, f)}"
|
||||
RUBY_YAML_PARSE="Value = YAML.load_file('$1'); if Value$2 && Value$2.is_a?(Array) then Value$2.map!{|x| if x == '$4' then '$6' else x end}; Value$2.uniq! end; YAML.dump(Value, '$1')"
|
||||
else
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -166,6 +166,7 @@ sys_dns_append()
|
||||
PROXY_GROUPS=$(ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
begin
|
||||
Value = YAML.load_file('$CONFIG_FILE')
|
||||
File.open('/tmp/yaml_change_marshal', 'wb') { |f| Marshal.dump(Value, f) }
|
||||
if Value.key?('proxy-groups') && Value['proxy-groups'].is_a?(Array)
|
||||
Value['proxy-groups'].each { |x| puts x['name'] if x.key?('name') }
|
||||
end
|
||||
@@ -328,7 +329,15 @@ end
|
||||
|
||||
begin
|
||||
config_file = '$5'
|
||||
Value = YAML.load_file(config_file)
|
||||
if File.exist?('/tmp/yaml_change_marshal')
|
||||
begin
|
||||
Value = Marshal.load(File.open('/tmp/yaml_change_marshal', 'rb') { |f| f.read })
|
||||
rescue
|
||||
Value = YAML.load_file(config_file)
|
||||
end
|
||||
else
|
||||
Value = YAML.load_file(config_file)
|
||||
end
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Load File Failed,【%s】' % [e.message])
|
||||
exit
|
||||
@@ -811,9 +820,10 @@ rescue Exception => e
|
||||
YAML.LOG_ERROR('Config File Overwrite Failed,【%s】' % [e.message])
|
||||
ensure
|
||||
begin
|
||||
File.open(config_file, 'w') { |f| YAML.dump(Value, f) }
|
||||
YAML.dump(Value, config_file)
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Write file failed:【%s】' % [e.message])
|
||||
end
|
||||
File.delete('/tmp/yaml_change_marshal') rescue nil
|
||||
end
|
||||
" 2>/dev/null >> $LOG_FILE
|
||||
@@ -1617,5 +1617,4 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
" >> $LOG_FILE
|
||||
|
||||
LOG_OUT "Config File【$CONFIG_NAME】Read Successful!"
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
@@ -1852,12 +1852,33 @@ rm -rf $servers_name
|
||||
|
||||
|
||||
LOG_OUT "Proxies, Proxy-providers, Groups Edited Successful, Updating Config File【$CONFIG_NAME】..."
|
||||
config_hash=$(ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "Value = YAML.load_file('$CONFIG_FILE'); puts Value" 2>/dev/null)
|
||||
if [ "$config_hash" != "false" ] && [ -n "$config_hash" ]; then
|
||||
ruby_cover "$CONFIG_FILE" "['proxies']" "$SERVER_FILE" "proxies"
|
||||
ruby_cover "$CONFIG_FILE" "['proxy-providers']" "$PROXY_PROVIDER_FILE" "proxy-providers"
|
||||
ruby_cover "$CONFIG_FILE" "['proxy-groups']" "/tmp/yaml_groups.yaml" "proxy-groups"
|
||||
else
|
||||
config_hash=$(ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
begin
|
||||
Value = YAML.load_file('$CONFIG_FILE')
|
||||
{
|
||||
'proxies' => '$SERVER_FILE',
|
||||
'proxy-providers' => '$PROXY_PROVIDER_FILE',
|
||||
'proxy-groups' => '/tmp/yaml_groups.yaml'
|
||||
}.each do |key, src_file|
|
||||
begin
|
||||
if File.exist?(src_file)
|
||||
src = YAML.load_file(src_file)
|
||||
Value[key] = src[key]
|
||||
else
|
||||
Value.delete(key)
|
||||
end
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Merge [' + key + '] Failed: ' + e.message)
|
||||
end
|
||||
end
|
||||
YAML.dump(Value, '$CONFIG_FILE')
|
||||
puts 'OK'
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Update Config File Failed: ' + e.message)
|
||||
end
|
||||
" 2>/dev/null)
|
||||
|
||||
if [ "$config_hash" != "OK" ]; then
|
||||
cat "$SERVER_FILE" "$PROXY_PROVIDER_FILE" "/tmp/yaml_groups.yaml" > "$CONFIG_FILE" 2>/dev/null
|
||||
fi
|
||||
|
||||
@@ -1868,5 +1889,4 @@ rm -rf /tmp/Proxy_Server 2>/dev/null
|
||||
rm -rf /tmp/Proxy_Provider 2>/dev/null
|
||||
|
||||
LOG_OUT "Config File【$CONFIG_NAME】Write Successful!"
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
@@ -387,27 +387,29 @@ yml_other_set()
|
||||
|
||||
# smart auto switch
|
||||
begin
|
||||
if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1' or '${14}' != '0') and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if '${8}' == '1' and ['url-test', 'load-balance'].include?(group['type']) then
|
||||
group['type'] = 'smart';
|
||||
group['uselightgbm'] = true if '${12}' == '1';
|
||||
group['collectdata'] = true if '${9}' == '1';
|
||||
group['sample-rate'] = '${10}'.to_f if '${9}' == '1';
|
||||
end;
|
||||
if '${9}' == '1' and group['type'] == 'smart' then
|
||||
group['collectdata'] = true;
|
||||
group['sample-rate'] = '${10}'.to_f;
|
||||
end;
|
||||
if '${11}' != '0' and group['type'] == 'smart' then
|
||||
group['policy-priority'] = '${11}';
|
||||
end;
|
||||
if '${12}' == '1' and group['type'] == 'smart' then
|
||||
group['uselightgbm'] = true;
|
||||
end;
|
||||
if '${13}' == '1' and group['type'] == 'smart' then
|
||||
group['prefer-asn'] = true;
|
||||
if group['type'] == 'smart' then
|
||||
if '${9}' == '1' then
|
||||
group['collectdata'] = true;
|
||||
group['sample-rate'] = '${10}'.to_f;
|
||||
end;
|
||||
if '${11}' != '0'then
|
||||
group['policy-priority'] = '${11}';
|
||||
end;
|
||||
if '${12}' == '1' then
|
||||
group['uselightgbm'] = true;
|
||||
end;
|
||||
if '${13}' == '1' then
|
||||
group['prefer-asn'] = true;
|
||||
end;
|
||||
if '${14}' != '0' then
|
||||
group['tolerance'] = '${14}'.to_i;
|
||||
end;
|
||||
end;
|
||||
};
|
||||
};
|
||||
@@ -425,11 +427,11 @@ yml_other_set()
|
||||
YAML.LOG_ERROR('Config File Overwrite Failed,【%s】' % [e.message])
|
||||
ensure
|
||||
begin
|
||||
File.open('$2','w') {|f| YAML.dump(Value, f)};
|
||||
YAML.dump(Value, '$2');
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Write file failed:【%s】' % [e.message])
|
||||
end
|
||||
end" 2>/dev/null >> $LOG_FILE
|
||||
}
|
||||
|
||||
yml_other_set "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}"
|
||||
yml_other_set "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}" "${14}"
|
||||
Reference in new issue
Block a user