#!/bin/bash /etc/ikcommon
Include interface.sh,iproute.sh,errcode.sh

EXECUTOR=/usr/sbin/netspeedtest
PID_FILE=/var/run/netspeedtest.pid
LOG_FILE=/tmp/iktmp/netspeedtest.log
LOCK_DIR=/var/run/netspeedtest.lock

register_module_urls()
{
	echo "url=advanced-service/netspeedtest-config name=netspeedtest get=data,status,interface post= put=save delete= post_require_body=1"
}

boot()
{
	init
}

init()
{
	local res=$(sql_config_get_list $IK_DB_CONFIG "select * from netspeedtest where id=1 and enabled='yes'")
	__lock || return 1
	if [ "$res" ]; then
		local $res
		__service_start >/dev/null 2>&1
	else
		__service_stop >/dev/null 2>&1
	fi
	local ret=$?
	__unlock
	return $ret
}

__lock()
{
	mkdir -p /var/run
	local i
	for i in 1 2 3 4 5; do
		if mkdir "$LOCK_DIR" 2>/dev/null; then
			echo $$ > "$LOCK_DIR/pid"
			return 0
		fi
		local lock_pid=$(cat "$LOCK_DIR/pid" 2>/dev/null)
		if [ -z "$lock_pid" ] || ! kill -0 "$lock_pid" 2>/dev/null; then
			rm -rf "$LOCK_DIR"
			continue
		fi
		sleep 1
	done
	return 1
}

__unlock()
{
	rm -rf "$LOCK_DIR"
}

__is_running()
{
	[ -s "$PID_FILE" ] || return 1
	local pid=$(cat "$PID_FILE" 2>/dev/null)
	[ "$pid" ] || return 1
	kill -0 "$pid" 2>/dev/null || return 1
	[ "$(readlink -f /proc/$pid/exe 2>/dev/null)" = "$EXECUTOR" ]
}

__service_stop()
{
	if __is_running; then
		local pid=$(cat "$PID_FILE" 2>/dev/null)
		kill "$pid" 2>/dev/null
		local i
		for i in 1 2 3 4 5; do
			kill -0 "$pid" 2>/dev/null || break
			sleep 1
		done
		kill -9 "$pid" 2>/dev/null
	fi
	rm -f "$PID_FILE"
}

__service_start()
{
	__service_stop
	mkdir -p /var/run /tmp/iktmp

	local bind_ip=""
	local mark=""
	if [ "$interface" != "auto" ]; then
		mark=$(iproute_get_markid "$interface")
	fi

	ipset_add DROP_T_PORTS_WAN_IN "$port"
	"$EXECUTOR" serve \
		--port "$port" \
		--user "$username" \
		--password "$password" \
		--interface "$interface" \
		--bind-ip "$bind_ip" \
		--mark "$mark" > "$LOG_FILE" 2>&1 &
	echo $! > "$PID_FILE"

	local i
	for i in 1 2 3; do
		sleep 1
		__is_running && return 0
	done
	rm -f "$PID_FILE"
	ipset_del DROP_T_PORTS_WAN_IN "$port"
	return 1
}

__check_param()
{
	check_varl \
		'enabled	== "yes" or == "no"' \
		'port		ikports' \
		'username	length >= 1 and length <= 32' \
		'password	length <= 64' \
		'interface	ifname or == "auto"'
}

save()
{
	if ! errmsg=$(__check_param); then
		outputErrorLog "errcode_param_error" "$errmsg"
		return 1
	fi
	local res=$(sql_config_get_list $IK_DB_CONFIG "select * from netspeedtest where id=1" prefix=old_)
	[ "$res" ] || return 1
	local $res
	[ "$password" ] || password="$old_password"
	if [ "$enabled" = "yes" -a -z "$password" ]; then
		outputErrorLog "errcode_param_error" "password is required when enabled"
		return 1
	fi

	if [ "$enabled" = "yes" ] && ! errmsg=$($IK_DIR_SCRIPT/utils/check_services_port.sh check_services_port tcplist=$port exclude=netspeedtest 2>/dev/null); then
		outputErrorLog "errcode_param_error" "$errmsg"
		return 1
	fi

	local sql_param="enabled:str port:int username:str password:str interface:str"
	if SqlMsg=$(sql_config_update $IK_DB_CONFIG netspeedtest "id=1" $sql_param); then
		if ! NewOldVarl enabled port username password interface; then
			if ! __lock; then
				outputErrorLog "errcode_conf_param_error" "netspeedtest is busy"
				return 1
			fi
			ipset_del DROP_T_PORTS_WAN_IN "$old_port"
			if [ "$enabled" = "yes" ]; then
				__service_start >/dev/null 2>&1
			else
				__service_stop >/dev/null 2>&1
			fi
			local service_ret=$?
			__unlock
			if [ "$service_ret" != "0" ]; then
				enabled="$old_enabled"
				port="$old_port"
				username="$old_username"
				password="$old_password"
				interface="$old_interface"
				sql_config_update $IK_DB_CONFIG netspeedtest "id=1" $sql_param >/dev/null 2>&1
				outputErrorLog "errcode_conf_param_error" "netspeedtest failed to start"
				return 1
			fi
		fi
	else
		outputErrorLog "errcode_db_error" "$SqlMsg"
		return 1
	fi
}

start()
{
	local res=$(sql_config_get_list $IK_DB_CONFIG "select * from netspeedtest where id=1")
	[ "$res" ] || return 1
	local $res
	if [ "$enabled" != "yes" ]; then
		outputErrorLog "errcode_conf_param_error" "enabled is no"
		return 1
	fi
	if ! __lock; then
		outputErrorLog "errcode_conf_param_error" "netspeedtest is busy"
		return 1
	fi
	__service_start
	local ret=$?
	__unlock
	return $ret
}

stop()
{
	local port=$(sqlite3 $IK_DB_CONFIG "select port from netspeedtest where id=1")
	__lock || return 1
	__service_stop
	[ "$port" ] && ipset_del DROP_T_PORTS_WAN_IN "$port"
	local ret=$?
	__unlock
	return $ret
}

restart()
{
	local res=$(sql_config_get_list $IK_DB_CONFIG "select * from netspeedtest where id=1")
	[ "$res" ] || return 1
	local $res
	[ "$enabled" = "yes" ] || return 1
	__lock || return 1
	__service_start
	local ret=$?
	__unlock
	return $ret
}

show()
{
	Show __json_result__
}

__show_data()
{
	local data=$(sql_config_get_json $IK_DB_CONFIG "select id,enabled,port,username,interface,case when password='' then 0 else 1 end as password_set from netspeedtest where id=1")
	json_append __json_result__ data:json
}

__show_status()
{
	local running=0
	__is_running && running=1
	local port=$(sqlite3 $IK_DB_CONFIG "select port from netspeedtest where id=1")
	local host=$(interface_get_ipaddr lan1 2>/dev/null)
	[ "$host" ] || host="<router-ip>"
	local url="http://${host}:${port}/"
	json_append __json_result__ running:int url:str
}

__show_interface()
{
	local interface=$(interface_get_ifname_comment_json wan,vpn auto)
	json_append __json_result__ interface:json
}
