#!/bin/sh /etc/rc.common
#
# Copyright (C) 2019-2023 pexcn <pexcn97@gmail.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#

# shellcheck disable=SC2155,SC3043,SC2034

START=99

USE_PROCD=1
#PROCD_DEBUG=1

append_param() {
	local section="$1"
	local option="$2"
	local switch="$3"
	local default="$4"
	local _loctmp
	config_get _loctmp "$section" "$option" "$default"
	[ -n "$_loctmp" ] || return 0
	procd_append_param command "$switch" "$_loctmp"
}

append_bool() {
	local section="$1"
	local option="$2"
	local value="$3"
	local default="$4"
	local _loctmp
	config_get_bool _loctmp "$section" "$option" "$default"
	[ "$_loctmp" = 1 ] || return 0
	procd_append_param command "$value"
}

append_param_if_neq() {
	local section="$1"
	local option="$2"
	local switch="$3"
	local compare="$4"
	local _loctmp
	config_get _loctmp "$section" "$option"
	[ -n "$_loctmp" ] || return 0
	[ "$_loctmp" != "$compare" ] || return 0
	procd_append_param command "$switch" "$_loctmp"
}

append_param_with_val() {
	local section="$1"
	local option="$2"
	local switch="$3"
	local _loctmp
	config_get _loctmp "$section" "$option"
	[ -n "$_loctmp" ] || return 0
	[ "$_loctmp" != 0 ] || return 0
	if [ "$_loctmp" = 1 ]; then
		procd_append_param command "$switch"
	else
		procd_append_param command "$switch" "$_loctmp"
	fi
}

get_cpu_cores() {
	grep -c "^processor" /proc/cpuinfo
}

is_exist_ipset() {
	ipset list -n "$1" >/dev/null 2>&1
}

destroy_ipset() {
	ipset flush "$1" 2>/dev/null
	ipset destroy "$1" 2>/dev/null
}

create_chnroute_ipset() {
	local enable
	config_get_bool enable "$1" enable
	[ "$enable" = 1 ] || return 0

	config_foreach create_ipv4_ipset chinadns-ng
	config_foreach create_ipv6_ipset chinadns-ng
}

create_ipv4_ipset() {
	local ipset_name
	config_get ipset_name "$1" "ipset_name4" "chnroute"

	if is_exist_ipset "$ipset_name"; then
		ipset flush "$ipset_name"
	else
		ipset create "$ipset_name" hash:net hashsize 64 family inet
	fi

	ipset restore <<-EOF
		$(sed "s/^/add $ipset_name /" </etc/chinadns-ng/chnroute.txt)
	EOF
}

create_ipv6_ipset() {
	local ipset_name
	config_get ipset_name "$1" "ipset_name6" "chnroute6"

	if is_exist_ipset "$ipset_name"; then
		ipset flush "$ipset_name"
	else
		ipset create "$ipset_name" hash:net hashsize 64 family inet6
	fi

	ipset restore <<-EOF
		$(sed "s/^/add $ipset_name /" </etc/chinadns-ng/chnroute6.txt)
	EOF
}

destroy_chnroute_ipset() {
	# force destroy, even though does not exist or config file changed
	config_foreach destroy_ipv4_ipset chinadns-ng
	config_foreach destroy_ipv6_ipset chinadns-ng
}

destroy_ipv4_ipset() {
	local ipset_name
	config_get ipset_name "$1" "ipset_name4" "chnroute"
	destroy_ipset "$ipset_name"
}

destroy_ipv6_ipset() {
	local ipset_name
	config_get ipset_name "$1" "ipset_name6" "chnroute6"
	destroy_ipset "$ipset_name"
}

start_chinadns_ng() {
	local enable
	config_get_bool enable "$1" enable
	[ "$enable" = 1 ] || return 0

	local reuse_port instances="$(get_cpu_cores)"
	config_get_bool reuse_port "$1" reuse_port
	[ "$reuse_port" = 1 ] || instances=1

	for i in $(seq 1 "$instances"); do
		procd_open_instance
		procd_set_param respawn
		procd_set_param stdout 1
		procd_set_param stderr 1
		procd_set_param nice -5
		procd_set_param limits nofile="1048576 1048576"
		procd_set_param command /usr/bin/chinadns-ng
		append_param "$1" bind_addr "-b"
		append_param "$1" bind_port "-l"
		append_param "$1" china_dns "-c"
		append_param "$1" trust_dns "-t"
		append_param "$1" chnlist_file "-m"
		append_param "$1" gfwlist_file "-g"
		append_bool "$1" chnlist_first "-M"
		append_param_if_neq "$1" default_tag "-d" "none"
		append_param_with_val "$1" add_tagchn_ip "-a"
		append_param_with_val "$1" add_taggfw_ip "-A"
		append_param_if_neq "$1" ipset_name4 "-4" "chnroute"
		append_param_if_neq "$1" ipset_name6 "-6" "chnroute6"
		append_param_with_val "$1" no_ipv6 "-N"
		append_param_if_neq "$1" timeout_sec "-o" "5"
		append_param_if_neq "$1" repeat_times "-p" "1"
		append_bool "$1" noip_as_chnip "-n"
		append_bool "$1" reuse_port "-r"
		append_bool "$1" verbose "-v"
		procd_close_instance
	done
}

service_triggers() {
	procd_add_reload_trigger "chinadns-ng"
}

start_service() {
	config_load chinadns-ng
	config_foreach create_chnroute_ipset chinadns-ng
	config_foreach start_chinadns_ng chinadns-ng
}

stop_service() {
	config_load chinadns-ng
	config_foreach destroy_chnroute_ipset chinadns-ng
}

reload_service() {
	restart
}
