diff --git a/.gitignore b/.gitignore index 8d9017e..95fa36d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .env -*.sql -docker-compose.yml.local \ No newline at end of file +.vscode +letsencrypt \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 7bf9808..ee3464b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM php:7.2.5-fpm-alpine3.7 as build -#FROM php:7.4.4-fpm-alpine3.11 as build + RUN apk update \ && apk add --no-cache libpng-dev zeromq-dev git \ $PHPIZE_DEPS \ @@ -9,27 +9,17 @@ RUN apk update \ COPY pathfinder /app WORKDIR /app +RUN composer self-update 1.6.3 RUN composer install -#FROM trafex/alpine-nginx-php7:latest FROM trafex/alpine-nginx-php7:ba1dd422 -#USER root RUN apk update && apk add --no-cache busybox-suid sudo php7-redis php7-pdo php7-pdo_mysql php7-fileinfo shadow gettext bash apache2-utils -#RUN usermod -u 1000 nobody -#RUN groupmod -g 1000 nobody COPY static/nginx/nginx.conf /etc/nginx/templateNginx.conf COPY static/nginx/site.conf /etc/nginx/sites_enabled/templateSite.conf # Configure PHP-FPM COPY static/php/fpm-pool.conf /etc/php7/php-fpm.d/zzz_custom.conf -#COPY static/php/php.ini /etc/php7/conf.d/zzz_custom.ini - -# DEBUG -RUN apk add php7-xdebug --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ -COPY static/php/xdebug.ini /etc/php7/conf.d/xdebug.ini -COPY static/php/error_reporting.ini /etc/php7/conf.d/error_reporting.ini -RUN echo "zend_extension=/usr/lib/php7/modules/xdebug.so" >> /etc/php7/php.ini COPY static/php/php.ini /etc/zzz_custom.ini # configure cron @@ -37,17 +27,16 @@ COPY static/crontab.txt /var/crontab.txt # Configure supervisord COPY static/supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY static/entrypoint.sh / -#RUN apk add sudo php7-redis php7-pdo php7-pdo_mysql + WORKDIR /var/www/html COPY --chown=nobody --from=build /app pathfinder -##RUN chown -R nobody:nobody /var/www/html/pathfinder RUN chmod 0766 pathfinder/logs pathfinder/tmp/ && rm index.php && touch /etc/nginx/.setup_pass && chmod +x /entrypoint.sh COPY static/pathfinder/routes.ini /var/www/html/pathfinder/app/ COPY static/pathfinder/environment.ini /var/www/html/pathfinder/app/templateEnvironment.ini -#USER nobody + WORKDIR /var/www/html EXPOSE 80 -#ENTRYPOINT ["sh", "-c", "source /.env && /entrypoint.sh", "-s"] + ENTRYPOINT ["/entrypoint.sh"] CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] diff --git a/config/pathfinder/pathfinder.ini b/config/pathfinder/pathfinder.ini index 0b5ebd9..446d428 100644 --- a/config/pathfinder/pathfinder.ini +++ b/config/pathfinder/pathfinder.ini @@ -75,7 +75,7 @@ MODE_MAINTENANCE = 0 ; that other characters from the "switch character" menu have access to ; Syntax 0 | 1 ; Default 0 -SESSION_SHARING = 1 +SESSION_SHARING = 0 ; Login restrictions (white lists) ; Login/registration can be restricted to specific groups. @@ -84,7 +84,7 @@ SESSION_SHARING = 1 ; Syntax: String (comma separated) ; Default: CHARACTER = -CORPORATION = +CORPORATION = 98581604 ALLIANCE = [PATHFINDER.CHARACTER] diff --git a/config/pathfinder/plugin.ini b/config/pathfinder/plugin.ini index 694c48a..ccc892b 100644 --- a/config/pathfinder/plugin.ini +++ b/config/pathfinder/plugin.ini @@ -4,3 +4,4 @@ MODULES_ENABLED = 1 [PLUGIN.MODULES] DEMO = ./app/ui/module/demo EMPTY = ./app/ui/module/empty +ZKILLTEST = ./app/ui/module/global_killboard diff --git a/development/.env.development b/development/.env.development new file mode 100644 index 0000000..8699b57 --- /dev/null +++ b/development/.env.development @@ -0,0 +1,9 @@ +CONTAINER_NAME="pfdev" +DOMAIN="localhost" +SERVER_NAME="PFDEV" +APP_PASSWORD="DEVPASSWORD" +MYSQL_PASSWORD="PASSWORD" +CCP_SSO_CLIENT_ID="" +CCP_SSO_SECRET_KEY="" +CCP_ESI_SCOPES="esi-location.read_online.v1,esi-location.read_location.v1,esi-location.read_ship_type.v1,esi-ui.write_waypoint.v1,esi-ui.open_window.v1,esi-universe.read_structures.v1,esi-corporations.read_corporation_membership.v1,esi-clones.read_clones.v1,esi-characters.read_corporation_roles.v1" +XDEBUG_CONFIG="remote_host=host.docker.internal remote_port=9000 remote_enable=1" diff --git a/development/Dockerfile.development b/development/Dockerfile.development new file mode 100644 index 0000000..090f40f --- /dev/null +++ b/development/Dockerfile.development @@ -0,0 +1,49 @@ +FROM php:7.2.5-fpm-alpine3.7 as build + +RUN apk update \ + && apk add --no-cache libpng-dev zeromq-dev git \ + $PHPIZE_DEPS \ + && docker-php-ext-install gd && docker-php-ext-install pdo_mysql && pecl install redis && docker-php-ext-enable redis && pecl install channel://pecl.php.net/zmq-1.1.3 && docker-php-ext-enable zmq \ + && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +COPY pathfinder /app +WORKDIR /app + +RUN composer self-update 1.6.3 +RUN composer install + +FROM trafex/alpine-nginx-php7:ba1dd422 +RUN apk update && apk add --no-cache busybox-suid sudo php7-redis php7-pdo php7-pdo_mysql php7-fileinfo shadow gettext bash apache2-utils + +COPY static/nginx/nginx.conf /etc/nginx/templateNginx.conf +COPY static/nginx/site.conf /etc/nginx/sites_enabled/templateSite.conf + +# Configure PHP-FPM +COPY static/php/fpm-pool.conf /etc/php7/php-fpm.d/zzz_custom.conf + +# DEBUG +RUN apk add php7-xdebug --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ +COPY static/php/xdebug.ini /etc/php7/conf.d/xdebug.ini +COPY static/php/error_reporting.ini /etc/php7/conf.d/error_reporting.ini +RUN echo "zend_extension=/usr/lib/php7/modules/xdebug.so" >> /etc/php7/php.ini + +COPY static/php/php.ini /etc/zzz_custom.ini +# configure cron +COPY static/crontab.txt /var/crontab.txt +# Configure supervisord +COPY static/supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY static/entrypoint.sh / + +WORKDIR /var/www/html +COPY --chown=nobody --from=build /app pathfinder + + +RUN chmod 0766 pathfinder/logs pathfinder/tmp/ && rm index.php && touch /etc/nginx/.setup_pass && chmod +x /entrypoint.sh +COPY static/pathfinder/routes.ini /var/www/html/pathfinder/app/ +COPY static/pathfinder/environment.ini /var/www/html/pathfinder/app/templateEnvironment.ini + +WORKDIR /var/www/html +EXPOSE 80 + +ENTRYPOINT ["/entrypoint.sh"] +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] diff --git a/development/development.sh b/development/development.sh new file mode 100755 index 0000000..5afa009 --- /dev/null +++ b/development/development.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +mv ./docker-compose.yml ./docker-compose.production.yml +mv ./Dockerfile ./Dockerfile.production +cp ./deployment/docker-compose.development.yml ./docker-compose.yml +cp ./deployment/Dockerfile.development ./Dockerfile +mkdir -p .vscode && cp ./deployment/launch.json ./.vscode/launch.json +echo "path=\"$(pwd)\"" > ./.env +cat ./deployment/.env.development >> ./.env \ No newline at end of file diff --git a/development/docker-compose.development.yml b/development/docker-compose.development.yml new file mode 100644 index 0000000..f6c4232 --- /dev/null +++ b/development/docker-compose.development.yml @@ -0,0 +1,101 @@ +version: "3.8" + +services: + pfdb: + image: bianjp/mariadb-alpine:latest + environment: + MYSQL_ROOT_PASSWORD: $MYSQL_PASSWORD + container_name: "$CONTAINER_NAME-db" + networks: + pf: + aliases: + - "${CONTAINER_NAME}db" + volumes: + - db_data:/var/lib/mysql + - $path/pathfinder/export/sql/eve_universe.sql.zip:/eve_universe.sql.zip + restart: always + pf-redis: + image: redis:6.2.5-alpine3.14 + container_name: "$CONTAINER_NAME-redis" + command: ["redis-server", "--appendonly", "yes"] + hostname: redis + volumes: + - redis_data:/data + networks: + pf: + aliases: + - "$CONTAINER_NAME-redis" + logging: + driver: none + restart: always + pf-socket: + image: composer:composer@sha256:d374b2e1f715621e9d9929575d6b35b11cf4a6dc237d4a08f2e6d1611f534675 + container_name: "$CONTAINER_NAME-socket" + command: ["sh","-c","composer install && php cmd.php --tcpHost 0.0.0.0"] + hostname: socket + volumes: + - ${path}/websocket:/app + networks: + pf: + aliases: + - "$CONTAINER_NAME-socket" + restart: always + pf: + container_name: ${CONTAINER_NAME} + hostname: "pathfinder" + build: '.' + env_file: + - .env + labels: + - "traefik.enable=true" + - "traefik.docker.network=web" + - "traefik.http.services.pf.loadbalancer.server.port=80" + - "traefik.http.routers.pf.rule=Host(`${DOMAIN}`)" + - "traefik.http.routers.pf.entrypoints=web" + - "traefik.http.routers.pf-secure.rule=Host(`${DOMAIN}`)" + - "traefik.http.routers.pf-secure.entrypoints=websecure" + - "traefik.http.routers.pf-secure.tls=true" + - "traefik.http.middlewares.redirecthttps.redirectscheme.scheme=https" + - "traefik.http.routers.pf.middlewares=redirecthttps" + networks: + - pf + - web + healthcheck: + disable: true + volumes: + - ${path}/config/pathfinder/config.ini:/var/www/html/pathfinder/app/templateConfig.ini + - ${path}/config/pathfinder/pathfinder.ini:/var/www/html/pathfinder/app/pathfinder.ini + - ${path}/config/pathfinder/plugin.ini:/var/www/html/pathfinder/app/plugin.ini + depends_on: + - pfdb + - pf-redis + - pf-socket + restart: always + traefik: + image: "traefik:v2.3" + container_name: "traefik" + command: + - "--log.level=ERROR" + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + ports: + - "80:80" + - "443:443" + - "8080:8080" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + networks: + - web + restart: always + +volumes: + data: + db_data: + redis_data: +networks: + pf: + web: + external: true diff --git a/.vscode/launch.json b/development/launch.json similarity index 100% rename from .vscode/launch.json rename to development/launch.json diff --git a/docker-compose.yml b/docker-compose.yml index b1c6781..c45c7ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,7 @@ services: - $path/pathfinder/export/sql/eve_universe.sql.zip:/eve_universe.sql.zip restart: always pf-redis: - image: redis:latest + image: redis:6.2.5-alpine3.14 container_name: "$CONTAINER_NAME-redis" command: ["redis-server", "--appendonly", "yes"] hostname: redis @@ -46,29 +46,64 @@ services: build: '.' env_file: - .env - # labels: - # caddy: map.goryn.wtf - # caddy.reverse_proxy: "{{upstreams 80}}" + labels: + - "traefik.enable=true" + - "traefik.docker.network=web" + - "traefik.http.services.pf.loadbalancer.server.port=80" + - "traefik.http.routers.pf.rule=Host(`${DOMAIN}`)" + - "traefik.http.routers.pf.entrypoints=web" + - "traefik.http.routers.pf-secure.rule=Host(`${DOMAIN}`)" + - "traefik.http.routers.pf-secure.entrypoints=websecure" + - "traefik.http.routers.pf-secure.tls=true" + - "traefik.http.routers.pf-secure.tls.certresolver=letsencrypt" + - "traefik.http.middlewares.redirecthttps.redirectscheme.scheme=https" + - "traefik.http.routers.pf.middlewares=redirecthttps" networks: - pf - # - caddy - ports: - - 80:80 - - 8030:8030 + - web healthcheck: disable: true volumes: - ${path}/config/pathfinder/config.ini:/var/www/html/pathfinder/app/templateConfig.ini - ${path}/config/pathfinder/pathfinder.ini:/var/www/html/pathfinder/app/pathfinder.ini - - ${path}/config/pathfinder/plugins.ini:/var/www/html/pathfinder/app/plugins.ini + - ${path}/config/pathfinder/plugin.ini:/var/www/html/pathfinder/app/plugin.ini depends_on: - - pfdb + - pfdb - pf-redis - pf-socket restart: always + traefik: + image: "traefik:v2.3" + container_name: "traefik" + command: + - "--log.level=ERROR" + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true" + - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" + # Remove below line when ready for production + - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" + - "--certificatesresolvers.letsencrypt.acme.email=MYEMAIL@someemailprobablygmail.com" + - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" + ports: + - "80:80" + - "443:443" + - "8080:8080" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + - "./letsencrypt:/letsencrypt" + networks: + - web + restart: always volumes: + data: db_data: redis_data: networks: pf: + web: + external: true diff --git a/pathfinder b/pathfinder deleted file mode 160000 index c3afe9c..0000000 --- a/pathfinder +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c3afe9ce73bf4bfb484ed5ae02eb29b5a8427f5b diff --git a/static/menu.sh b/static/menu.sh deleted file mode 100644 index b1d8061..0000000 --- a/static/menu.sh +++ /dev/null @@ -1,451 +0,0 @@ -#!/bin/bash - -## -# Pure BASH interactive CLI/TUI menu (single and multi-select/checkboxes) -# -# Author: Markus Geiger -# Last revised 2011-09-11 -# -# ATTENTION! TO BE REFACTORED! FIRST DRAFT! -# -# Demo -# -# - ASCIINEMA -# https://asciinema.org/a/Y4hLxnN20JtAlrn3hsC6dCRn8 -# -# Inspired by -# -# - https://serverfault.com/questions/144939/multi-select-menu-in-bash-script -# - Copyright (C) 2017 Ingo Hollmann - All Rights Reserved -# https://www.bughunter2k.de/blog/cursor-controlled-selectmenu-in-bash -# -# Notes -# -# - This is a hacky first implementation for my shell tools/dotfiles (ZSH) -# - Intention is to use it for CLI wizards (my aim is NOT a full blown curses TUI window interface) -# - I concerted TPUT to ANSII-sequences to spare command executions (e.g. `tput ed | xxd`) -# reference: http://linuxcommand.org/lc3_adv_tput.php -# -# Permission to copy and modify is granted under the Creative Commons Attribution 4.0 license -# - -# Strict bash scripting (not yet) -# set -euo pipefail -o errtrace - - -# Templates for ui_widget_select -declare -xr UI_WIDGET_SELECT_TPL_SELECTED='\e[33m → %s \e[39m' -declare -xr UI_WIDGET_SELECT_TPL_DEFAULT=" \e[37m%s %s\e[39m" -declare -xr UI_WIDGET_MULTISELECT_TPL_SELECTED="\e[33m → %s %s\e[39m" -declare -xr UI_WIDGET_MULTISELECT_TPL_DEFAULT=" \e[37m%s %s\e[39m" -declare -xr UI_WIDGET_TPL_CHECKED="▣" -declare -xr UI_WIDGET_TPL_UNCHECKED="□" - -# We use env variable to pass results since no interactive output from subshells and we don't wanna go hacky! -declare -xg UI_WIDGET_RC=-1 - - -## -# Get type of a BASH variable (BASH ≥v4.0) -# -# Notes -# - if references are encountered it will automatically try -# to resolve them unless '-f' is passed! -# - resolving functions can be seen as bonus since they also -# use `declare` (but with -fF). this behavior should be removed! -# - bad indicates bad referencing which normally shouldn't occur! -# - types are shorthand and associative arrays map to "map" for convenience -# -# argument -# -f (optional) force resolvement of first hit -# Variable name -# -# stdout -# (nil|number|array|map|reference) -# -# stderr -# - -# -# return -# 0 - always -typeof() { - # __ref: avoid local to overwrite global var declaration and therefore emmit wrong results! - local type="" resolve_ref=true __ref="" signature=() - if [[ "$1" == "-f" ]]; then - # do not resolve reference - resolve_ref=false; shift; - fi - __ref="$1" - while [[ -z "${type}" ]] || ( ${resolve_ref} && [[ "${type}" == *n* ]] ); do - IFS=$'\x20\x0a\x3d\x22' && signature=($(declare -p "$__ref" 2>/dev/null || echo "na")) - if [[ ! "${signature}" == "na" ]]; then - type="${signature[1]}" # could be -xn! - fi - if [[ -z "${__ref}" ]] || [[ "${type}" == "na" ]] || [[ "${type}" == "" ]]; then - printf "nil" - return 0 - elif [[ "${type}" == *n* ]]; then - __ref="${signature[4]}" - fi - done - case "$type" in - *i*) printf "number";; - *a*) printf "array";; - *A*) printf "map";; - *n*) printf "reference";; - *) printf "string";; - esac -} - - -## -# Removes a value from an array -# -# alternatives -# array=( "${array[@]/$delete}" -# -# arguments -# arg1 value -# arg* list or stdin -# -# stdout -# list with space seperator -array_without_value() { - local args=() value="${1}" s - shift - for s in "${@}"; do - if [ "${value}" != "${s}" ]; then - args+=("${s}") - fi - done - echo "${args[@]}" -} - - -## -# check if a value is in an array -# -# alternatives -# array=( "${array[@]/$delete}" -# -# arguments -# arg1 value -# arg* list or stdin -# -# stdout -# list with space seperator -array_contains_value() { - local e match="$1" - shift - for e; do [[ "$e" == "$match" ]] && return 0; done - return 1 -} - -## -# BASH only string to hex -# -# stdout -# hex squence -str2hex_echo() { - # USAGE: hex_repr=$(str2hex_echo "ABC") - # returns "0x410x420x43" - local str=${1:-$(cat -)} - local fmt="" - local chr - local -i i - printf "0x" - for i in `seq 0 $((${#str}-1))`; do - chr=${str:i:1} - printf "%x" "'${chr}" - done -} - -## -# Read key and map to human readable output -# -# notes -# output prefix (concated by `-`) -# c ctrl key -# a alt key -# c-a ctrl+alt key -# use F if you mean shift! -# uppercase `f` for `c+a` combination is not possible! -# -# arguments -# -d for debugging keycodes (hex output via xxd) -# -l lowercase all chars -# -l timeout -# -# stdout -# mapped key code like in notes -ui_key_input() { - local key - local ord - local debug=0 - local lowercase=0 - local prefix='' - local args=() - local opt - - while (( "$#" )); do - opt="${1}" - shift - case "${opt}" in - "-d") debug=1;; - "-l") lowercase=1;; - "-t") args+=(-t $1); shift;; - esac - done - IFS= read ${args[@]} -rsn1 key 2>/dev/null >&2 - read -sN1 -t 0.0001 k1; read -sN1 -t 0.0001 k2; read -sN1 -t 0.0001 k3 - key+="${k1}${k2}${k3}" - if [[ "${debug}" -eq 1 ]]; then echo -n "${key}" | str2hex_echo; echo -n " : " ;fi; - case "${key}" in - '') key=enter;; - ' ') key=space;; - $'\x1b') key=esc;; - $'\x1b\x5b\x36\x7e') key=pgdown;; - $'\x1b\x5b\x33\x7e') key=erase;; - $'\x7f') key=backspace;; - $'\e[A'|$'\e0A '|$'\e[D'|$'\e0D') key=up;; - $'\e[B'|$'\e0B'|$'\e[C'|$'\e0C') key=down;; - $'\e[1~'|$'\e0H'|$'\e[H') key=home;; - $'\e[4~'|$'\e0F'|$'\e[F') key=end;; - $'\e') key=enter;; - $'\e'?) prefix="a-"; key="${key:1:1}";; - esac - - # only lowercase if we have a single letter - # ctrl key is hidden within char code (no o) - if [[ "${#key}" == 1 ]]; then - ord=$(LC_CTYPE=C printf '%d' "'${key}") - if [[ "${ord}" -lt 32 ]]; then - prefix="c-${prefix}" - # ord=$(([##16] ord + 0x60)) - # let "ord = [##16] ${ord} + 0x60" - ord="$(printf "%X" $((ord + 0x60)))" - key="$(printf "\x${ord}")" - fi - if [[ "${lowercase}" -eq 1 ]]; then - key="${key,,}" - fi - fi - - echo "${prefix}${key}" -} - -## -# UI Widget Select -# -# arguments -# -i <[menu-item(s)] …> menu items -# -m activate multi-select mode (checkboxes) -# -k <[key(s)] …> keys for menu items (if none given indexes are used) -# -s <[selected-keys(s)] …> selected keys (index or key) -# if keys are used selection needs to be keys -# -c clear complete menu on exit -# -l clear menu and leave selections -# -# env -# UI_WIDGET_RC will be selected index or -1 of nothing was selected -# -# stdout -# menu display - don't use subshell since we need interactive shell and use tput! -# -# stderr -# sometimes (trying to clean up) -# -# return -# 0 success -# -1 cancelled -ui_widget_select() { - local menu=() keys=() selection=() selection_index=() - local cur=0 oldcur=0 collect="item" select="one" - local sel="" marg="" drawn=false ref v="" - local opt_clearonexit=false opt_leaveonexit=false - export UI_WIDGET_RC=-1 - while (( "$#" )); do - opt="${1}"; shift - case "${opt}" in - -k) collect="key";; - -i) collect="item";; - -s) collect="selection";; - -m) select="multi";; - -l) opt_clearonexit=true; opt_leaveonexit=true;; - -c) opt_clearonexit=true;; - *) - if [[ "${collect}" == "selection" ]]; then - selection+=("${opt}") - elif [[ "${collect}" == "key" ]]; then - keys+=("${opt}") - else - menu+=("$opt") - fi;; - esac - done - - # sanity check - if [[ "${#menu[@]}" -eq 0 ]]; then - >&2 echo "no menu items given" - return 1 - fi - - if [[ "${#keys[@]}" -gt 0 ]]; then - # if keys are used - # sanity check - if [[ "${#keys[@]}" -gt 0 ]] && [[ "${#keys[@]}" != "${#menu[@]}" ]]; then - >&2 echo "number of keys do not match menu options!" - return 1 - fi - # map keys to indexes - selection_index=() - for sel in "${selection[@]}"; do - for ((i=0;i<${#keys[@]};i++)); do - if [[ "${keys[i]}" == "${sel}" ]]; then - selection_index+=("$i") - fi - done - done - else - # if no keys are used assign by indexes - selection_index=(${selection[@]}) - fi - - clear_menu() { - local str="" - for i in "${menu[@]}"; do str+="\e[2K\r\e[1A"; done - echo -en "${str}" - } - - ## - # draws menu in three different states - # - initial: draw every line as intenden - # - update: only draw updated lines and skip existing - # - exit: only draw selected lines - draw_menu() { - local mode="${initial:-$1}" check=false check_tpl="" str="" msg="" tpl_selected="" tpl_default="" marg=() - - if ${drawn} && [[ "$mode" != "exit" ]]; then - # reset position - str+="\r\e[2K" - for i in "${menu[@]}"; do str+="\e[1A"; done - # str+="${TPUT_ED}" - fi - if [[ "$select" == "one" ]]; then - tpl_selected="$UI_WIDGET_SELECT_TPL_SELECTED" - tpl_default="$UI_WIDGET_SELECT_TPL_DEFAULT" - else - tpl_selected="$UI_WIDGET_MULTISELECT_TPL_SELECTED" - tpl_default="$UI_WIDGET_MULTISELECT_TPL_DEFAULT" - fi - - for ((i=0;i<${#menu[@]};i++)); do - check=false - if [[ "$select" == "one" ]]; then - # single selection - marg=("${menu[${i}]}") - if [[ ${cur} == ${i} ]]; then - check=true - fi - else - # multi-select - check_tpl="$UI_WIDGET_TPL_UNCHECKED"; - if array_contains_value "$i" "${selection_index[@]}"; then - check_tpl="$UI_WIDGET_TPL_CHECKED"; check=true - fi - marg=("${check_tpl}" "${menu[${i}]}") - fi - if [[ "${mode}" != "exit" ]] && [[ ${cur} == ${i} ]]; then - str+="$(printf "\e[2K${tpl_selected}" "${marg[@]}")\n"; - elif ([[ "${mode}" != "exit" ]] && ([[ "${oldcur}" == "${i}" ]] || [[ "${mode}" == "initial" ]])) || (${check} && [[ "${mode}" == "exit" ]]); then - str+="$(printf "\e[2K${tpl_default}" "${marg[@]}")\n"; - elif [[ "${mode}" -eq "update" ]] && [[ "${mode}" != "exit" ]]; then - str+="\e[1B\r" - fi - done - echo -en "${str}" - export drawn=true - } - - # initial draw - draw_menu initial - - # action loop - while true; do - oldcur=${cur} - key=$(ui_key_input) - case "${key}" in - up|left|i|j) ((cur > 0)) && ((cur--));; - down|right|k|l) ((cur < ${#menu[@]}-1)) && ((cur++));; - home) cur=0;; - pgup) let cur-=5; if [[ "${cur}" -lt 0 ]]; then cur=0; fi;; - pgdown) let cur+=5; if [[ "${cur}" -gt $((${#menu[@]}-1)) ]]; then cur=$((${#menu[@]}-1)); fi;; - end) ((cur=${#menu[@]}-1));; - space) - if [[ "$select" == "one" ]]; then - continue - fi - if ! array_contains_value "$cur" "${selection_index[@]}"; then - selection_index+=("$cur") - else - selection_index=($(array_without_value "$cur" "${selection_index[@]}")) - fi - ;; - enter) - if [[ "${select}" == "multi" ]]; then - export UI_WIDGET_RC=() - for i in ${selection_index[@]}; do - if [[ "${#keys[@]}" -gt 0 ]]; then - export UI_WIDGET_RC+=("${keys[${i}]}") - else - export UI_WIDGET_RC+=("${i}") - fi - done - else - if [[ "${#keys[@]}" -gt 0 ]]; then - export UI_WIDGET_RC="${keys[${cur}]}"; - else - export UI_WIDGET_RC=${cur}; - fi - fi - if $opt_clearonexit; then clear_menu; fi - if $opt_leaveonexit; then draw_menu exit; fi - return - ;; - [1-9]) - let "cur = ${key}" - if [[ ${#menu[@]} -gt 9 ]]; then - echo -n "${key}" - sleep 1 - key="$(ui_key_input -t 0.5 )" - if [[ "$key" =~ [0-9] ]]; then - let "cur = cur * 10 + ${key}" - elif [[ "$key" != "enter" ]]; then - echo -en "\e[2K\r$key invalid input!" - sleep 1 - fi - fi - let "cur = cur - 1" - if [[ ${cur} -gt ${#menu[@]}-1 ]]; then - echo -en "\e[2K\rinvalid index!" - sleep 1 - cur="${oldcur}" - fi - echo -en "\e[2K\r" - ;; - esc|q|$'\e') - if $opt_clearonexit; then clear_menu; fi - return 1;; - esac - - # Redraw menu - draw_menu update - done -} - - - - - - - diff --git a/websocket b/websocket deleted file mode 160000 index f6b4f5a..0000000 --- a/websocket +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f6b4f5ae309e21ad793197a77b5d095a33cfc9f1