#!/bin/sh

. /etc/os-release
. /lib/functions/uci-defaults.sh

API=$(uci -q get ota.config.api_url)
WRLOCK=/var/lock/ota_background.lock

# armsr/armv8
[ "$OPENWRT_BOARD" = "armsr/armv8" ] && alias board_name="echo armsr,armv8"

# x86_64
[ $(uname -m) = "x86_64" ] && alias board_name="echo x86_64"

action=${1}
shift

sha256() {
    sha256sum $1 | cut -d' ' -f1
}

download() {
    read_json
    if [ -f /tmp/firmware.img ]; then
        echo "Checking existed firmware.img..." >> /tmp/firmware.img.progress
        if [ "`sha256 /tmp/firmware.img`" = "$FW_SHA256SUM" ]; then
            return 0;
        else
            echo "Check failed, redownload" >> /tmp/firmware.img.progress
            rm -f /tmp/firmware.img
        fi
    fi
    touch /tmp/firmware.img.progress
    fw_download_tool "$FW_URL" -o /tmp/firmware.img.part -k -L -4 > /tmp/firmware.img.progress 2>&1 &
    echo "$! $PPID" > /var/run/ota/download.pid
    while true; do
        progress=$(grep -c "100.00%" /tmp/firmware.img.progress)
        if [ "$progress" -ge "1" ]; then
            echo "Checking new firmware.img.part..." > /tmp/firmware.img.progress
            break
        fi
        sleep 1
    done
    if [ "`sha256 /tmp/firmware.img.part`" = "$FW_SHA256SUM" ]; then
        mv /tmp/firmware.img.part /tmp/firmware.img && echo $FW_SHA256SUM > /tmp/firmware.img.sha256sum
        rm -f /tmp/firmware.img.progress
        return 0
    else
        echo "Checksum failed!" >>/tmp/firmware.img.progress
        sleep 1
        rm -rf /tmp/firmware.img.part
        return 1
    fi
}

lock_download() {
    local lock="$WRLOCK"
    exec 200>$lock
    flock -n 200 || return
    download
    flock -u 200
}

# 0: found newer fw, 1: already newest fw, *: err
do_check() {
    url_check=$(curl -I -o /dev/null -s -w %{http_code} "$API")
    [ $url_check -ne 200 ] && exit 255
    curl -s "$API" > /var/run/ota/fw.json
    read_json
    NEW_VERSION=$(basename $FW_URL | awk -F- '{if (NF >= 3 && $3 ~ /^rc/) {print $2 "-" $3} else {print $2}}')
    if [ "$BUILD_DATE" -lt "$FW_BUILD_DATE" ]; then
        echo "<h3>Model:&nbsp;&nbsp;<font color=\"green\">$(board_name)</font><br/>Current Version:&nbsp;&nbsp;<font color=\"green\">$PRETTY_NAME</font><br/>Build Date:&nbsp;&nbsp;<font color=\"Orange\">$(date "+%Y-%m-%d %H:%M:%S" -d "@$BUILD_DATE")</font></h3>"
        echo "<h3>New Version:&nbsp;&nbsp;<font color=\"green\">OpenWrt $NEW_VERSION</font><br/>Build Date:&nbsp;&nbsp;<font color=\"green\">$(date "+%Y-%m-%d %H:%M:%S" -d "@$FW_BUILD_DATE")</font></h3>"
        return 0
    elif [ "$BUILD_DATE" -ge "$FW_BUILD_DATE" ]; then
        return 1
    else
        return 255
    fi
}

# async download
do_download(){
    [ ! -f "/var/run/ota/fw.json" ] && { echo "do check first" >&2 ; return 254; }
    lock_download &
    return 0
}

# 0: done, 1: downloading, 2: failed, *: err
do_progress() {
    read_json
    [ -f /tmp/firmware.img.sha256sum ] && [ "`cat /tmp/firmware.img.sha256sum`" = "$FW_SHA256SUM" ] && return 0
    [ -f /tmp/firmware.img.progress ] || { echo "download not in progress" >&2 ; return 254; }
    [ -f /tmp/firmware.img.part ] && { cat /tmp/firmware.img.progress | tr '\r' '\n' | tail -n1; return 1; }
    tail -1 /tmp/firmware.img.progress | grep -Fq 'Canceled!' && { echo "Canceled"; return 2; }
    tail -1 /tmp/firmware.img.progress | grep -Fq 'Checksum failed!' && { echo "Checksum failed!"; return 254; }
    grep -v '\r' /tmp/firmware.img.progress >&2
    return 1
}

do_cancel() {
    if [ -f /var/run/ota/download.pid ]; then
        local pid=`cat /var/run/ota/download.pid`
        if [ -n "$pid" ]; then
            kill -TERM $pid;
            while kill -9 $pid >/dev/null 2>&1; do
                if ! sleep 1; then
                    break
                fi
            done
            rm -rf /tmp/firmware.img* /var/lock/ota_background.lock /var/lock/ota_api.lock /var/run/ota/download.pid
            echo "" >> /tmp/firmware.img.progress
            echo "Canceled!" >> /tmp/firmware.img.progress
        fi
    fi
    return 0
}

read_json(){
    FW_BUILD_DATE=$(jsonfilter -i /var/run/ota/fw.json -e "@['$(board_name)'][0]['build_date']")
    FW_SHA256SUM=$(jsonfilter -i /var/run/ota/fw.json -e "@['$(board_name)'][0]['sha256sum']")
    FW_URL=$(jsonfilter -i /var/run/ota/fw.json -e "@['$(board_name)'][0]['url']")
}

ota_init(){
    mkdir -p /var/run/ota >/dev/null 2>&1 || true
}

usage() {
    echo "usage: ota sub-command"
    echo "where sub-command is one of:"
    echo "      check                  Check firmware upgrade"
    echo "      download               Download latest firmware"
    echo "      progress               Download progress"
    echo "      cancel                 Cancel download"
}

ota_init || exit 255

case $action in
    "check")
        do_check
    ;;
    "download")
        do_download
    ;;
    "progress")
        do_progress
    ;;
    "cancel")
        do_cancel
    ;;
    *)
        usage
    ;;
esac
