Загрузка данных


#!/bin/zsh
# noteindex — SSH-туннель к https://noteindex.ru/ на macOS
# Использование: noteindex start | noteindex stop | noteindex status

VPS="91.218.115.87"
SSH_USER="user"
LOCAL_PORT=443
REMOTE="127.0.0.1:443"
HOSTS_LINE="127.0.0.1 noteindex.ru"
HOSTS_MARK="# noteindex-tunnel"
PID_FILE="${HOME}/.noteindex-tunnel.pid"
# Не использовать «ssh -N -L» — между -N и -L в процессе есть -f и -o
SSH_MATCH="${LOCAL_PORT}:${REMOTE} ${SSH_USER}@${VPS}"

hosts_has_entry() {
  grep -qE '^\s*127\.0\.0\.1\s+noteindex\.ru(\s|$)' /etc/hosts 2>/dev/null
}

hosts_add() {
  if hosts_has_entry; then
    echo "hosts: запись noteindex.ru уже есть"
    return 0
  fi
  echo "${HOSTS_LINE} ${HOSTS_MARK}" | sudo tee -a /etc/hosts >/dev/null
  echo "hosts: добавлено → 127.0.0.1 noteindex.ru"
}

hosts_remove() {
  if ! hosts_has_entry; then
    echo "hosts: записи noteindex.ru нет"
    return 0
  fi
  sudo sed -i '' '/noteindex\.ru/d' /etc/hosts
  echo "hosts: запись noteindex.ru удалена"
}

tunnel_pid() {
  sudo pgrep -f "${SSH_MATCH}" 2>/dev/null | head -1
}

tunnel_listening() {
  sudo lsof -nP -iTCP:"${LOCAL_PORT}" -sTCP:LISTEN 2>/dev/null | grep -q '[s]sh'
}

tunnel_running() {
  tunnel_listening || [[ -n "$(tunnel_pid)" ]]
}

cmd_start() {
  if tunnel_running; then
    echo "Туннель уже запущен (PID $(tunnel_pid))"
    hosts_add
    echo "Откройте: https://noteindex.ru/"
    return 0
  fi

  hosts_add

  echo "Запуск SSH-туннеля (sudo — пароль Mac; затем пароль root на VPS)…"
  if ! sudo ssh -N -f \
    -o ExitOnForwardFailure=yes \
    -o ServerAliveInterval=30 \
    -o ServerAliveCountMax=3 \
    -L "${LOCAL_PORT}:${REMOTE}" \
    "${SSH_USER}@${VPS}"; then
    echo "Ошибка: ssh не подключился. Проверьте пароль и: sudo route delete -host ${VPS}" >&2
    exit 1
  fi

  sleep 2
  pid="$(tunnel_pid)"

  if [[ -z "${pid}" ]] && tunnel_listening; then
    pid="$(sudo lsof -t -iTCP:"${LOCAL_PORT}" -sTCP:LISTEN 2>/dev/null | head -1)"
  fi

  if [[ -z "${pid}" ]]; then
    echo "Ошибка: туннель не слушает порт ${LOCAL_PORT}." >&2
    echo "Проверьте: sudo lsof -i :${LOCAL_PORT}" >&2
    exit 1
  fi

  echo "${pid}" > "${PID_FILE}"
  echo "Туннель запущен (PID ${pid})"
  echo "Откройте: https://noteindex.ru/"
  echo "Остановка: noteindex stop"
}

cmd_stop() {
  local pid=""

  if [[ -f "${PID_FILE}" ]]; then
    pid="$(cat "${PID_FILE}")"
    sudo kill "${pid}" 2>/dev/null || true
    rm -f "${PID_FILE}"
  fi

  while read -r p; do
    [[ -n "${p}" ]] && sudo kill "${p}" 2>/dev/null || true
  done < <(sudo pgrep -f "${SSH_MATCH}" 2>/dev/null || true)

  sleep 0.5
  if tunnel_running; then
    echo "Предупреждение: туннель ещё активен — noteindex stop ещё раз или Activity Monitor" >&2
  else
    echo "Туннель остановлен"
  fi

  hosts_remove
}

cmd_status() {
  if tunnel_running; then
    echo "Туннель: запущен (PID $(tunnel_pid))"
  else
    echo "Туннель: не запущен"
  fi

  if hosts_has_entry; then
    echo "hosts: 127.0.0.1 noteindex.ru — есть"
  else
    echo "hosts: записи noteindex.ru нет"
  fi
}

cmd_usage() {
  cat <<'EOF'
noteindex — SSH-туннель к https://noteindex.ru/ (macOS)

Использование:
  noteindex start   включить (/etc/hosts + туннель в фоне)
  noteindex stop    остановить туннель и убрать запись из hosts
  noteindex status  проверить туннель и hosts

Сокращения: start|up, stop|down|off

После start: https://noteindex.ru/
EOF
}

case "${1:-}" in
  start|up)
    cmd_start
    ;;
  stop|down|off)
    cmd_stop
    ;;
  status)
    cmd_status
    ;;
  help|-h|--help)
    cmd_usage
    ;;
  "")
    cmd_usage
    ;;
  *)
    echo "Неизвестная команда: ${1}" >&2
    echo "Справка: noteindex help" >&2
    exit 1
    ;;
esac