#!/bin/bash

#####

NOVNC=/opt/noVNC/utils/launch.sh
VNCSERVER=/usr/bin/tigervncserver
VNCPASSWD=/usr/bin/vncpasswd
PWGEN=/usr/bin/pwgen
KILL=/bin/kill
KILLALL=/usr/bin/killall
SCREEN=/usr/bin/screen
NC=/usr/bin/nc
RM=/bin/rm
CAT=/bin/cat
CHMOD=/bin/chmod
MKDIR=/bin/mkdir
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/local/games:/usr/lib/go/bin:./

#####

##
LABS_WEBSITE=labs.eif.urjc.es
##

## FUNCIONES

function killVncServers {
        USER=$1
        pkill -U $USER -f gnome-session
        pkill -U $USER -f xfce4-session
        pkill -U $USER -f SCREEN
        pkill -U $USER -f vncserver
        pkill -U $USER -f screen
        pkill -U $USER -f Xtigervnc
}

function launchVncServer {
        tmpfile=`mktemp`
        $VNCSERVER -interface `hostname -f` -localhost no 1> $tmpfile 2> $tmpfile
        HOST=`cat $tmpfile | grep ^New | cut -d' ' -f4 | sed s/\'/''/g | cut -d: -f1`
        VNCPORT=`cat $tmpfile | grep ^New | cut -d' ' -f4 | sed s/\'/''/g | cut -d: -f2`
        PORT=`echo $VNCPORT+5901-1|bc`
        echo $HOST:$PORT
}

# Comprueba si un puerto TCP local esta libre (nadie escuchando en el).
function port_free {
        [ -z "$(ss -ltnH "sport = :$1")" ]
}

function launchnoVncServer {

        local vnchost=$1 vncport=$2
        local novncport=""

        # Cerramos servidores previos
        for process in `ps aux | grep ^$LOGNAME | grep -v grep | grep '/usr/bin/websockify --web /opt/noVNC/utils/' | awk '{print $2}'`; do
                $KILL -9 $process 1> /dev/null 2> /dev/null
        done

        sleep 2

        # Seccion critica: un unico elegir-y-lanzar a la vez en el host.
        # Mantenemos el lock hasta confirmar que websockify ha bindeado de verdad,
        # de modo que la siguiente invocacion ya vea el puerto ocupado.
        exec 9>/tmp/vncweb-ports.lock
        flock 9

        for port in `seq 8000 8100`; do
                port_free "$port" || continue

                $SCREEN -d -m $NOVNC --listen "$port" --vnc "$vnchost:$vncport"

                # Esperamos a que el puerto quede realmente ocupado (max ~3s)
                # ANTES de soltar el lock. Si no bindea (carrera perdida o fallo
                # del propio websockify), probamos con el siguiente.
                for _ in `seq 1 15`; do
                        if ! port_free "$port"; then
                                novncport=$port
                                break 2
                        fi
                        sleep 0.2
                done
        done

        flock -u 9
        exec 9>&-

        if [ -z "$novncport" ]; then
                echo "Lo sentimos, no hay puertos libres. Habla con los Tecnicos de Laboratorio: soporte-lab@gsyc.urjc.es" >&2
                echo "" >&2
                exit 2
        fi

        echo "$novncport"

}

function apacheConfig {
        SHORT=$3
        CONF="/tmp/novnc-$HOSTNAME-$LOGNAME-$2.conf"
        echo "RewriteEngine On" >> $CONF
        echo "Redirect permanent /$SHORT /novnc/$LOGNAME/$HOSTNAME/$2/vnc.html?host=labs.eif.urjc.es&port=443&path=ws-$LOGNAME-$HOSTNAME-$2" >> $CONF
        echo "ProxyPass /novnc/$LOGNAME/$HOSTNAME/$2/ http://$1:$2/" >> $CONF
        echo "ProxyPassReverse /novnc/$LOGNAME/$HOSTNAME/$2/ http://$1:$2/" >> $CONF
        echo "ProxyPass /ws-$LOGNAME-$HOSTNAME-$2 ws://$HOSTNAME:$2 retry=3" >> $CONF
        echo "ProxyPassReverse /ws-$LOGNAME-$HOSTNAME-$2 ws://$HOSTNAME:$2 retry=3" >> $CONF
        echo "RedirectMatch permanent /novnc/$LOGNAME/$HOSTNAME/$2$ /novnc/$LOGNAME/$HOSTNAME/$2" >> $CONF
        echo $CONF
}

## FIN FUNCIONES

###

# Parseo de argumentos. -q/--quiet => solo se imprime la URL por stdout.
QUIET=0
while [ $# -gt 0 ]; do
        case "$1" in
                -q|--quiet) QUIET=1 ;;
                *) ;; # ignoramos otros argumentos
        esac
        shift
done

###

if [ "$QUIET" -eq 0 ]; then
        echo ""
        echo "Creando escritorio. Espera un momentín..."
        echo ""
fi

###

if [ ! -f $HOME/.vnc/passwd ];
then
        if [ "$QUIET" -eq 1 ]; then
                echo "ERROR: fichero de contraseña vnc no encontrado" >&2
        else
                echo "ERROR: no existe el fichero de contraseña VNC ($HOME/.vnc/passwd)." >&2
                echo "Es necesario crearlo antes de lanzar el escritorio. Puedes generarlo con:" >&2
                echo "    $VNCPASSWD" >&2
                echo "" >&2
                echo "Ante cualquier duda, escríbenos en leif.laboratorios.soporte@urjc.es." >&2
        fi
        exit 3
else
        $CHMOD 600 $HOME/.vnc/passwd
fi

# Comprobamos si existiera algun proceso Xtighvncserver en la maquina a nombre del usuario.
killVncServers $LOGNAME

# Lanzamos primero un servidor vncserver. Si hubiera alguno corriendo, lo cerramos
SERVER=`launchVncServer $GEOMETRY $xstartup`

VSERVER=`echo $SERVER | cut -d: -f1`
VPORT=`echo $SERVER | cut -d: -f2`

PORT=`launchnoVncServer $VSERVER $VPORT`

SHORT=`$PWGEN -N 1 -C 12`

conf_file=`apacheConfig $VSERVER $PORT $SHORT`

# Subimos configuracion a servidor labs.eif.urjc.es
file=`basename $conf_file`
cd /tmp/ && echo put $file | /usr/bin/tftp $LABS_WEBSITE 1> /dev/null 2> /dev/null

if [ "$?" == "0" ];
then
        if [ "$QUIET" -eq 1 ]; then
                echo "https://$LABS_WEBSITE/$SHORT"
        else
                echo "Tu escritorio remoto vncWeb se ha creado correctamente. Copia y pega en el navegador esta URL:"
                echo "https://$LABS_WEBSITE/$SHORT"
                echo ""
                echo "Recuerda que la sesión permanecerá abierta mientras que no se reinicie este PC."
                echo ""
                echo "Ante cualquier duda, escríbenos en leif.laboratorios.soporte@urjc.es. ¡Saludos!"
                echo ""
        fi
else
        if [ "$QUIET" -eq 1 ]; then
                echo "Error creando el escritorio remoto." >&2
        else
                echo "Parece que se produjo un problema creando tu escritorio :-("
                echo ""
                echo "Si este problema persiste, por favor, escribe a los técnicos de laboratorio: soporte-lab@gsyc.urjc.es."
                echo ""
        fi
fi

# Borramos fichero temporal
$RM $conf_file
