#!/usr/bin/env bash
# Sends messages to server

RETRY=3
LOG="/var/log/hive-agent.log"

source /hive/bin/colors

if [[ -z "$RIG_CONF" || -z "$API_HOST_FILE" ]]; then #reread env variables as after upgrade this can be empty
	source /etc/environment
	export $(cat /etc/environment | grep -vE '^$|^#' | cut -d= -f1) #export all variables from file
fi

[[ ! -f $RIG_CONF ]] && echo -e "No config $RIG_CONF" && exit 1
source $RIG_CONF
[[ $DISABLE_CERT_CHECK -ne 0 ]] && insecure="--insecure" || insecure=

[[ -f "$API_HOST_FILE" ]] && source $API_HOST_FILE # fallback api host
HIVE_URL="$HIVE_HOST_URL/worker/api"

if [[ $1 == -f=* || $1 == --file=* ]]; then
	type="file"
	file="${1#*=}"
	[[ ! -e $file ]] && echo "File not found: \"$file\"" && exit 1
	data=`basename "$file"`
else
	type="$1"
	data="$2"
fi

#echo $#
if [[ -z $data || -z $type ]]; then
	echo "Usage: $0 success|danger|warning|info|file \"message\" [-i|--id=msgid] [-f|--file=path/name] [payload] [-v|--verbose] [-d|--debug]"
	echo "       $0 -f|--file=path/name"
	echo "Aliases: ok|error|err|warn|default"
	echo "payload is read from stdin"
	exit 1
fi

MSGCOLOR=$CYAN
[[ $type == "error" || $type == "err" ]] && type="danger" && MSGCOLOR=$RED
[[ $type == "warn" ]] && type="warning" && MSGCOLOR=$YELLOW
[[ $type == "ok" ]] && type="success" && MSGCOLOR=$GREEN


# sending blink command to octofan in case of errors
[[ `lsusb 2>/dev/null | grep -c 16c0:05dc` -ge 1 && $type == "danger" && -e $OCTOFAN ]] && $OCTOFAN blink_error

request=$(
echo "$payload_json" | jq -n \
--arg rig_id "$RIG_ID" \
--arg passwd "$RIG_PASSWD" \
--arg type "$type" \
--arg data "$data" \
'{
	"method": "message", "jsonrpc": "2.0", "id": 0,
	"params": {$rig_id, $passwd, $type, $data}
}'
)
#echo $request | jq .

id=
payload_json=
debug=
verbose=0

for i in "$@"; do
	case $i in
		-i=*|--id=*)
			id="${i#*=}"
			id_json=`jq --arg id "$id" -n '{"params": {$id}}'`
			request=`echo "$request $id_json" | jq -sc '.[0] * .[1]'`
		;;
		--meta=*)
			meta="${i#*=}"
			echo $meta | jq
			meta_json=`jq --argjson meta "$meta" -n '{"params": {$meta}}'`
			request=`echo "$request $meta_json" | jq -sc '.[0] * .[1]'`
		;;
		payload|--payload)
			#echo "With payload"
			# cleanup output from progress bars
			#payload=$(sed 's/\r$//; s/\r/\r\n/g' | grep -v $'\r' | cat -s)
			# check for empty payload
			#if [[ "$payload" =~ [^[:space:]]+ ]]; then
			#	payload_json=`echo -n "$payload" | jq -R -s '{"params": {"payload": .}}'` &&
			#		request=`echo "$request $payload_json" | jq -sc '.[0] * .[1]'`
			#fi
		;;
		-f=*|--file=*)
			[[ $type != "file" ]] && echo "Type \"file\" must be used" && exit 2
			file="${i#*=}"
			[[ ! -e $file ]] && echo "File not found: \"$file\"" && exit 1
			payload_json=`cat "$file" | gzip -9 --stdout | base64 -w 0 | jq -R -s '{"params": {"payload": .}}'` &&
				request=`echo "$request $payload_json" | jq -sc '.[0] * .[1]'`
		;;
		-v|--verbose)
			verbose=1
		;;
		-d|--debug)
			debug="-v"
		;;
		*)
			# unknown option
		;;
	esac
done

# autodetect payload
if [[ ! `readlink /dev/fd/0` =~  ^/dev/ ]]; then
	#echo "With payload"
	# cleanup output from progress bars
	payload=$(sed 's/\r$//; s/\r/\r\n/g' 2>/dev/null | grep -v $'\r' | cat -s)
	# check for empty payload
	if [[ "$payload" =~ [^[:space:]]+ ]]; then
		payload_json=`echo -n "$payload" | jq -R -s '{"params": {"payload": .}}'` &&
			request=`echo "$request $payload_json" | jq -sc '.[0] * .[1]'`
	fi
fi

#date
if [[ $verbose == 1 ]]; then
	echo "$request" | jq -c --arg pass "${RIG_PASSWD//?/*}" '.params.passwd=$pass | if .params.payload then .params.payload |= "[\(.|length) bytes]" else . end'
fi

# Show output and exit for debug
#echo $request | jq . && exit

echo "[`date`] > `echo $request | jq . -c`" >> $LOG

for(( try=0; try < RETRY; try++ )); do
	(( try > 0 )) && echo && sleep 2
	echo "${CYAN}> Sending ${WHITE}$type${CYAN}${payload_json:+ with payload} to ${BCYAN}$HIVE_HOST_URL${NOCOLOR}"
	if [[ $MSGPACK_ENABLE -ne 0 ]]; then
		tmpfile=$(mktemp)
		if [[ $? -ne 0 ]]; then
			MSGPACK_ENABLE=0 # fallback to old method
		else
			response=$(echo "$request" | json2msgpack -B 25 | curl $debug $insecure -L --data-binary @- -o $tmpfile \
					--connect-timeout 7 --max-time 15 --silent -w "%{content_type}\n%{http_code}\n" \
					-XPOST "${HIVE_URL}?id_rig=$RIG_ID&method=message" -H "Content-Type: application/x-msgpack")
			exitcode=$?
			httpcode=$(echo "$response" | tail -1)
			[[ "$response" =~ /x-msgpack ]] && response=$(msgpack2json -B -i $tmpfile 2>/dev/null) || MSGPACK_ENABLE=0
			rm -f $tmpfile
		fi
	fi
	if [[ $MSGPACK_ENABLE -eq 0 ]]; then
		response=$(echo "$request" | curl $debug $insecure -L --data @- --connect-timeout 7 --max-time 15 --silent \
				-w "\n%{http_code}\n" -XPOST "${HIVE_URL}?id_rig=$RIG_ID&method=message" -H "Content-Type: application/json")
		exitcode=$?
		httpcode=$(echo "$response" | tail -1)
		response=$(echo "$response" | head -n -1)
	fi
	if [[ $exitcode -ne 0 ]]; then
		echo "${RED}Error: ${BRED}$(human-curl-error $exitcode)${NOCOLOR}"
		echo "[`date`] < Error sending message (CURL $exitcode)" >> $LOG
		#exit $exitcode
		continue
	fi

	echo "[`date`] < $response (HTTP $httpcode)" >> $LOG

	error=
	parsed=`echo "$response" | jq -c -C '.' 2>/dev/null`
	if [[ $? -eq 0 && ! -z "$parsed" ]]; then
		error=`echo "$response" | jq -r 'if .error.message then .error.message else .error.code end' 2>/dev/null`
		if [[ $? -eq 0 && "$error" == "null" ]]; then
			echo "${BGREEN}OK${NOCOLOR}"
			[[ $verbose == 1 ]] && echo "$parsed"
			exit 0
		fi

		# do not retry in this case
		echo "${RED}Error: ${BRED}${error:-Unknown}${NOCOLOR}"
		[[ $verbose == 1 || -z "$error" ]] && echo "$parsed"
		exit 1
	else
		echo "${RED}Error: ${BRED}HTTP $httpcode${NOCOLOR}"
		# try to parse as HTML or get just first line
		error=`echo "$response" | grep -oP "<title>\K[^<]+"` || error="${GRAY}$(echo "$response" | head -1)${NOCOLOR}"
		[[ $verbose == 1 || -z "$error" ]] && echo "${response}" || echo "$error"
		continue
	fi
done

exit 1
