Флаг --daily ставит cron, который раз в сутки заново качает launcher со свежим токеном. Снять: --remove-daily. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -93,9 +93,10 @@ vps-tracker/
|
||||
## Статус блокировок (censorcheck)
|
||||
|
||||
Ручная проверка с VPS: `curl -fsSL https://vt.shnt.top/cc | bash` (тот же контейнер, Traefik dual Host).
|
||||
Раз в сутки: `curl -fsSL https://vt.shnt.top/cc | bash -s -- --daily` (cron, свежий HMAC-токен на каждый запуск).
|
||||
|
||||
- **Vendor:** `apps/api/scripts/censorcheck/censorcheck.sh` (pin SHA `12c5839`, MIT)
|
||||
- **Launcher:** `GET /cc` минтит HMAC ingest-токен (TTL 20 мин); по `/etc/os-release` ставит `jq`/`dig`/`column` без prompt; прогресс-бар в stderr; `GET /cc/vendor` — скрипт (LF)
|
||||
- **Launcher:** `GET /cc` минтит HMAC ingest-токен (TTL 20 мин); по `/etc/os-release` ставит `jq`/`dig`/`column` без prompt; прогресс-бар в stderr; `GET /cc/vendor` — скрипт (LF); `--daily` / `--remove-daily`
|
||||
- **Ingest:** `POST /api/integrations/censorcheck/runs` (без portal JWT)
|
||||
- **UI:** `/blocking` — текущие прогоны и история, группировка VPS / сервис
|
||||
- Env: `CENSORCHECK_INGEST_SECRET`, `CENSORCHECK_PUBLIC_URL`, `VPS_LAUNCHER_DOMAIN`
|
||||
@@ -103,9 +104,10 @@ vps-tracker/
|
||||
## GeoIP (ipregion)
|
||||
|
||||
Ручная проверка с VPS: `curl -fsSL https://vt.shnt.top/ic | bash`.
|
||||
Раз в сутки: `curl -fsSL https://vt.shnt.top/ic | bash -s -- --daily`.
|
||||
|
||||
- **Vendor:** `apps/api/scripts/ipregion/ipregion.sh` (pin SHA `7d1c25c`, MIT, [vernette/ipregion](https://github.com/vernette/ipregion))
|
||||
- **Launcher:** `GET /ic` минтит HMAC ingest-токен (тот же `CENSORCHECK_INGEST_SECRET`); `GET /ic/vendor` — pinned скрипт (LF)
|
||||
- **Launcher:** `GET /ic` минтит HMAC ingest-токен (тот же `CENSORCHECK_INGEST_SECRET`); `GET /ic/vendor` — pinned скрипт (LF); `--daily` / `--remove-daily`
|
||||
- **Ingest:** `POST /api/integrations/ipregion/runs` (без portal JWT)
|
||||
- **UI:** `/geo` — матрица ISO-стран VPS × сервисы (primary / custom / cdn)
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ set -euo pipefail
|
||||
|
||||
VT_API_URL="${VT_API_URL:-__VT_API_URL__}"
|
||||
VT_INGEST_TOKEN="${VT_INGEST_TOKEN:-__VT_INGEST_TOKEN__}"
|
||||
LAUNCHER_VERSION="5"
|
||||
LAUNCHER_VERSION="6"
|
||||
VENDOR_SHA="12c5839"
|
||||
DAILY_SLUG="vt-censorcheck"
|
||||
DAILY_PATH="/cc"
|
||||
|
||||
OS_ID="unknown"
|
||||
OS_LIKE=""
|
||||
@@ -247,6 +249,102 @@ detect_hoster() {
|
||||
return 1
|
||||
}
|
||||
|
||||
show_launcher_help() {
|
||||
cat <<EOF
|
||||
Использование:
|
||||
curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash
|
||||
curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --daily
|
||||
curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --remove-daily
|
||||
|
||||
--daily выполнить проверку и поставить cron раз в сутки
|
||||
--remove-daily убрать ежедневный cron
|
||||
EOF
|
||||
}
|
||||
|
||||
daily_run_cmd() {
|
||||
local url="${VT_API_URL}${DAILY_PATH}"
|
||||
local curl_bin bash_bin flock_bin
|
||||
curl_bin="$(command -v curl)"
|
||||
bash_bin="$(command -v bash)"
|
||||
flock_bin="$(command -v flock || true)"
|
||||
if [ -n "$flock_bin" ]; then
|
||||
printf "%s -n /tmp/%s.lock -c '%s -fsSL --max-time 180 %s | %s'" \
|
||||
"$flock_bin" "$DAILY_SLUG" "$curl_bin" "$url" "$bash_bin"
|
||||
else
|
||||
printf '%s -fsSL --max-time 180 %s | %s' "$curl_bin" "$url" "$bash_bin"
|
||||
fi
|
||||
}
|
||||
|
||||
daily_slot() {
|
||||
local seed n
|
||||
seed="$(hostname -f 2>/dev/null || hostname 2>/dev/null || cat /etc/hostname 2>/dev/null || echo vt)"
|
||||
n="$(printf '%s' "$seed" | cksum | awk '{print $1}')"
|
||||
DAILY_MINUTE=$((n % 60))
|
||||
DAILY_HOUR=$((3 + (n / 60) % 4))
|
||||
}
|
||||
|
||||
remove_daily() {
|
||||
local prefix="" removed=0
|
||||
if [ -e "/etc/cron.d/${DAILY_SLUG}" ]; then
|
||||
if prefix="$(root_prefix)"; then
|
||||
# shellcheck disable=SC2086
|
||||
$prefix rm -f "/etc/cron.d/${DAILY_SLUG}"
|
||||
removed=1
|
||||
fi
|
||||
fi
|
||||
if command -v crontab >/dev/null 2>&1; then
|
||||
local current
|
||||
current="$(crontab -l 2>/dev/null || true)"
|
||||
if printf '%s\n' "$current" | grep -qF "vps-tracker:${DAILY_SLUG}"; then
|
||||
printf '%s\n' "$current" | grep -vF "vps-tracker:${DAILY_SLUG}" | crontab -
|
||||
removed=1
|
||||
fi
|
||||
fi
|
||||
if [ "$removed" -eq 1 ]; then
|
||||
log "Ежедневная проверка снята (${DAILY_SLUG})"
|
||||
else
|
||||
log "Ежедневная проверка не была установлена"
|
||||
fi
|
||||
}
|
||||
|
||||
install_daily() {
|
||||
daily_slot
|
||||
local run line prefix=""
|
||||
local marker="# vps-tracker:${DAILY_SLUG}"
|
||||
run="$(daily_run_cmd)"
|
||||
|
||||
if [ -d /etc/cron.d ] && prefix="$(root_prefix)"; then
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
cat >"$tmp" <<EOF
|
||||
# Managed by VPS Tracker launcher. ${marker}
|
||||
SHELL=/bin/bash
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
MAILTO=""
|
||||
${DAILY_MINUTE} ${DAILY_HOUR} * * * root ${run} >>/var/log/${DAILY_SLUG}.log 2>&1
|
||||
EOF
|
||||
# shellcheck disable=SC2086
|
||||
$prefix cp "$tmp" "/etc/cron.d/${DAILY_SLUG}"
|
||||
# shellcheck disable=SC2086
|
||||
$prefix chmod 644 "/etc/cron.d/${DAILY_SLUG}"
|
||||
rm -f "$tmp"
|
||||
log "Ежедневная проверка: каждый день в ${DAILY_HOUR}:$(printf '%02d' "$DAILY_MINUTE") (/etc/cron.d/${DAILY_SLUG})"
|
||||
log "Снять: curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --remove-daily"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! command -v crontab >/dev/null 2>&1; then
|
||||
die "Нет cron (ни /etc/cron.d, ни crontab). Установите пакет cron и повторите --daily"
|
||||
fi
|
||||
line="${DAILY_MINUTE} ${DAILY_HOUR} * * * ${run} >>/tmp/${DAILY_SLUG}.log 2>&1 ${marker}"
|
||||
{
|
||||
(crontab -l 2>/dev/null || true) | grep -vF "vps-tracker:${DAILY_SLUG}" || true
|
||||
printf '%s\n' "$line"
|
||||
} | crontab -
|
||||
log "Ежедневная проверка: каждый день в ${DAILY_HOUR}:$(printf '%02d' "$DAILY_MINUTE") (crontab)"
|
||||
log "Снять: curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --remove-daily"
|
||||
}
|
||||
|
||||
write_vendor() {
|
||||
local dest="$1"
|
||||
if [ -n "${CENSORCHECK_VENDOR_B64:-}" ]; then
|
||||
@@ -273,6 +371,22 @@ VT_API_URL="${VT_API_URL%/}"
|
||||
[ -n "$VT_API_URL" ] || die "VT_API_URL пуст"
|
||||
[ -n "$VT_INGEST_TOKEN" ] || die "VT_INGEST_TOKEN пуст"
|
||||
|
||||
DAILY_INSTALL=0
|
||||
DAILY_REMOVE=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--daily|--install-daily) DAILY_INSTALL=1 ;;
|
||||
--remove-daily|--uninstall-daily) DAILY_REMOVE=1 ;;
|
||||
-h|--help) show_launcher_help; exit 0 ;;
|
||||
*) die "Неизвестный аргумент: $arg. См. --help" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$DAILY_REMOVE" -eq 1 ]; then
|
||||
remove_daily
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMPDIR="$(mktemp -d /tmp/vt-censorcheck.XXXXXX)"
|
||||
cleanup() { rm -rf "$TMPDIR"; }
|
||||
trap 'cleanup; exit 130' INT
|
||||
@@ -336,6 +450,9 @@ set -e
|
||||
if [ "$POST_EXIT" -ne 0 ]; then
|
||||
cp "$PAYLOAD" "$FALLBACK"
|
||||
log "API недоступен (curl exit ${POST_EXIT}). JSON сохранён: ${FALLBACK}" >&2
|
||||
if [ "$DAILY_INSTALL" -eq 1 ]; then
|
||||
install_daily
|
||||
fi
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@@ -345,9 +462,15 @@ if [ -z "$CHECK_ID" ]; then
|
||||
cp "$PAYLOAD" "$FALLBACK"
|
||||
log "Некорректный ответ API. JSON сохранён: ${FALLBACK}" >&2
|
||||
log "$RESP" >&2
|
||||
if [ "$DAILY_INSTALL" -eq 1 ]; then
|
||||
install_daily
|
||||
fi
|
||||
exit 2
|
||||
fi
|
||||
|
||||
log "Check ID: ${CHECK_ID}"
|
||||
log "VPS: ${MATCHED}"
|
||||
if [ "$DAILY_INSTALL" -eq 1 ]; then
|
||||
install_daily
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -5,8 +5,10 @@ set -euo pipefail
|
||||
|
||||
VT_API_URL="${VT_API_URL:-__VT_API_URL__}"
|
||||
VT_INGEST_TOKEN="${VT_INGEST_TOKEN:-__VT_INGEST_TOKEN__}"
|
||||
LAUNCHER_VERSION="1"
|
||||
LAUNCHER_VERSION="2"
|
||||
VENDOR_SHA="7d1c25c"
|
||||
DAILY_SLUG="vt-ipregion"
|
||||
DAILY_PATH="/ic"
|
||||
|
||||
OS_ID="unknown"
|
||||
OS_LIKE=""
|
||||
@@ -247,6 +249,102 @@ detect_hoster() {
|
||||
return 1
|
||||
}
|
||||
|
||||
show_launcher_help() {
|
||||
cat <<EOF
|
||||
Использование:
|
||||
curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash
|
||||
curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --daily
|
||||
curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --remove-daily
|
||||
|
||||
--daily выполнить проверку и поставить cron раз в сутки
|
||||
--remove-daily убрать ежедневный cron
|
||||
EOF
|
||||
}
|
||||
|
||||
daily_run_cmd() {
|
||||
local url="${VT_API_URL}${DAILY_PATH}"
|
||||
local curl_bin bash_bin flock_bin
|
||||
curl_bin="$(command -v curl)"
|
||||
bash_bin="$(command -v bash)"
|
||||
flock_bin="$(command -v flock || true)"
|
||||
if [ -n "$flock_bin" ]; then
|
||||
printf "%s -n /tmp/%s.lock -c '%s -fsSL --max-time 180 %s | %s'" \
|
||||
"$flock_bin" "$DAILY_SLUG" "$curl_bin" "$url" "$bash_bin"
|
||||
else
|
||||
printf '%s -fsSL --max-time 180 %s | %s' "$curl_bin" "$url" "$bash_bin"
|
||||
fi
|
||||
}
|
||||
|
||||
daily_slot() {
|
||||
local seed n
|
||||
seed="$(hostname -f 2>/dev/null || hostname 2>/dev/null || cat /etc/hostname 2>/dev/null || echo vt)"
|
||||
n="$(printf '%s' "$seed" | cksum | awk '{print $1}')"
|
||||
DAILY_MINUTE=$((n % 60))
|
||||
DAILY_HOUR=$((3 + (n / 60) % 4))
|
||||
}
|
||||
|
||||
remove_daily() {
|
||||
local prefix="" removed=0
|
||||
if [ -e "/etc/cron.d/${DAILY_SLUG}" ]; then
|
||||
if prefix="$(root_prefix)"; then
|
||||
# shellcheck disable=SC2086
|
||||
$prefix rm -f "/etc/cron.d/${DAILY_SLUG}"
|
||||
removed=1
|
||||
fi
|
||||
fi
|
||||
if command -v crontab >/dev/null 2>&1; then
|
||||
local current
|
||||
current="$(crontab -l 2>/dev/null || true)"
|
||||
if printf '%s\n' "$current" | grep -qF "vps-tracker:${DAILY_SLUG}"; then
|
||||
printf '%s\n' "$current" | grep -vF "vps-tracker:${DAILY_SLUG}" | crontab -
|
||||
removed=1
|
||||
fi
|
||||
fi
|
||||
if [ "$removed" -eq 1 ]; then
|
||||
log "Ежедневная проверка снята (${DAILY_SLUG})"
|
||||
else
|
||||
log "Ежедневная проверка не была установлена"
|
||||
fi
|
||||
}
|
||||
|
||||
install_daily() {
|
||||
daily_slot
|
||||
local run line prefix=""
|
||||
local marker="# vps-tracker:${DAILY_SLUG}"
|
||||
run="$(daily_run_cmd)"
|
||||
|
||||
if [ -d /etc/cron.d ] && prefix="$(root_prefix)"; then
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
cat >"$tmp" <<EOF
|
||||
# Managed by VPS Tracker launcher. ${marker}
|
||||
SHELL=/bin/bash
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
MAILTO=""
|
||||
${DAILY_MINUTE} ${DAILY_HOUR} * * * root ${run} >>/var/log/${DAILY_SLUG}.log 2>&1
|
||||
EOF
|
||||
# shellcheck disable=SC2086
|
||||
$prefix cp "$tmp" "/etc/cron.d/${DAILY_SLUG}"
|
||||
# shellcheck disable=SC2086
|
||||
$prefix chmod 644 "/etc/cron.d/${DAILY_SLUG}"
|
||||
rm -f "$tmp"
|
||||
log "Ежедневная проверка: каждый день в ${DAILY_HOUR}:$(printf '%02d' "$DAILY_MINUTE") (/etc/cron.d/${DAILY_SLUG})"
|
||||
log "Снять: curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --remove-daily"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! command -v crontab >/dev/null 2>&1; then
|
||||
die "Нет cron (ни /etc/cron.d, ни crontab). Установите пакет cron и повторите --daily"
|
||||
fi
|
||||
line="${DAILY_MINUTE} ${DAILY_HOUR} * * * ${run} >>/tmp/${DAILY_SLUG}.log 2>&1 ${marker}"
|
||||
{
|
||||
(crontab -l 2>/dev/null || true) | grep -vF "vps-tracker:${DAILY_SLUG}" || true
|
||||
printf '%s\n' "$line"
|
||||
} | crontab -
|
||||
log "Ежедневная проверка: каждый день в ${DAILY_HOUR}:$(printf '%02d' "$DAILY_MINUTE") (crontab)"
|
||||
log "Снять: curl -fsSL ${VT_API_URL}${DAILY_PATH} | bash -s -- --remove-daily"
|
||||
}
|
||||
|
||||
write_vendor() {
|
||||
local dest="$1"
|
||||
if [ -n "${IPREGION_VENDOR_B64:-}" ]; then
|
||||
@@ -273,6 +371,22 @@ VT_API_URL="${VT_API_URL%/}"
|
||||
[ -n "$VT_API_URL" ] || die "VT_API_URL пуст"
|
||||
[ -n "$VT_INGEST_TOKEN" ] || die "VT_INGEST_TOKEN пуст"
|
||||
|
||||
DAILY_INSTALL=0
|
||||
DAILY_REMOVE=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--daily|--install-daily) DAILY_INSTALL=1 ;;
|
||||
--remove-daily|--uninstall-daily) DAILY_REMOVE=1 ;;
|
||||
-h|--help) show_launcher_help; exit 0 ;;
|
||||
*) die "Неизвестный аргумент: $arg. См. --help" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$DAILY_REMOVE" -eq 1 ]; then
|
||||
remove_daily
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMPDIR="$(mktemp -d /tmp/vt-ipregion.XXXXXX)"
|
||||
cleanup() { rm -rf "$TMPDIR"; }
|
||||
trap 'cleanup; exit 130' INT
|
||||
@@ -339,6 +453,9 @@ set -e
|
||||
if [ "$POST_EXIT" -ne 0 ]; then
|
||||
cp "$PAYLOAD" "$FALLBACK"
|
||||
log "API недоступен (curl exit ${POST_EXIT}). JSON сохранён: ${FALLBACK}" >&2
|
||||
if [ "$DAILY_INSTALL" -eq 1 ]; then
|
||||
install_daily
|
||||
fi
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@@ -348,9 +465,15 @@ if [ -z "$CHECK_ID" ]; then
|
||||
cp "$PAYLOAD" "$FALLBACK"
|
||||
log "Некорректный ответ API. JSON сохранён: ${FALLBACK}" >&2
|
||||
log "$RESP" >&2
|
||||
if [ "$DAILY_INSTALL" -eq 1 ]; then
|
||||
install_daily
|
||||
fi
|
||||
exit 2
|
||||
fi
|
||||
|
||||
log "Check ID: ${CHECK_ID}"
|
||||
log "VPS: ${MATCHED}"
|
||||
if [ "$DAILY_INSTALL" -eq 1 ]; then
|
||||
install_daily
|
||||
fi
|
||||
exit 0
|
||||
|
||||
@@ -33,6 +33,11 @@ describe('GET /cc launcher', () => {
|
||||
expect(res.body).toContain('/etc/os-release')
|
||||
expect(res.body).toContain('apt-get install -y -qq')
|
||||
expect(res.body).toContain('Проверяю сайты')
|
||||
expect(res.body).toContain('--daily')
|
||||
expect(res.body).toContain('--remove-daily')
|
||||
expect(res.body).toContain('DAILY_SLUG="vt-censorcheck"')
|
||||
expect(res.body).toContain('vps-tracker:${DAILY_SLUG}')
|
||||
expect(res.body).toContain('/etc/cron.d')
|
||||
expect(res.body).not.toContain('2>/tmp/vt-censorcheck-err')
|
||||
expect(res.body).not.toContain('\r')
|
||||
expect(res.body).not.toContain('__VT_API_URL__')
|
||||
@@ -80,6 +85,10 @@ describe('GET /ic launcher', () => {
|
||||
expect(res.body).toContain('/api/integrations/ipregion/runs')
|
||||
expect(res.body).toContain('/ic/vendor')
|
||||
expect(res.body).toContain('7d1c25c')
|
||||
expect(res.body).toContain('--daily')
|
||||
expect(res.body).toContain('--remove-daily')
|
||||
expect(res.body).toContain('DAILY_SLUG="vt-ipregion"')
|
||||
expect(res.body).toContain('vps-tracker:${DAILY_SLUG}')
|
||||
expect(res.body).not.toContain('\r')
|
||||
expect(res.body).not.toContain('__VT_API_URL__')
|
||||
expect(res.body).not.toContain('__VT_INGEST_TOKEN__')
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useMemo, useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import {
|
||||
BanIcon,
|
||||
CalendarClockIcon,
|
||||
CopyIcon,
|
||||
GlobeIcon,
|
||||
ServerIcon,
|
||||
@@ -38,6 +39,7 @@ import { filterCensorcheckRuns, serviceMatrixRows } from './blocking-filters'
|
||||
import {
|
||||
CENSORCHECK_STATUS_LABELS,
|
||||
LAUNCHER_CMD,
|
||||
LAUNCHER_CMD_DAILY,
|
||||
formatCheckedAt,
|
||||
type CensorcheckRunDto,
|
||||
} from './types'
|
||||
@@ -143,14 +145,24 @@ export function BlockingPage() {
|
||||
const blocked = filtered.reduce((sum, row) => sum + row.summary.blocked, 0)
|
||||
|
||||
const copyLauncher = (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => void copyText(LAUNCHER_CMD, 'Команда скопирована')}
|
||||
>
|
||||
<CopyIcon data-icon="inline-start" />
|
||||
Скопировать команду
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => void copyText(LAUNCHER_CMD, 'Команда скопирована')}
|
||||
>
|
||||
<CopyIcon data-icon="inline-start" />
|
||||
Скопировать команду
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => void copyText(LAUNCHER_CMD_DAILY, 'Команда для ежедневного запуска скопирована')}
|
||||
>
|
||||
<CalendarClockIcon data-icon="inline-start" />
|
||||
Раз в день
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -57,6 +57,7 @@ export const CENSORCHECK_STATUS_LABELS: Record<string, string> = {
|
||||
}
|
||||
|
||||
export const LAUNCHER_CMD = 'curl -fsSL https://vt.shnt.top/cc | bash'
|
||||
export const LAUNCHER_CMD_DAILY = 'curl -fsSL https://vt.shnt.top/cc | bash -s -- --daily'
|
||||
|
||||
export function formatVpsResources(vcpu: number, ramGb: number, diskGb: number): string {
|
||||
return `${vcpu} vCPU / ${ramGb} GB / ${diskGb} GB`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import {
|
||||
CalendarClockIcon,
|
||||
CopyIcon,
|
||||
GlobeIcon,
|
||||
MapPinIcon,
|
||||
@@ -43,6 +44,7 @@ import {
|
||||
import {
|
||||
IPREGION_STATUS_LABELS,
|
||||
LAUNCHER_CMD,
|
||||
LAUNCHER_CMD_DAILY,
|
||||
formatCheckedAt,
|
||||
type IpregionRunDto,
|
||||
} from './types'
|
||||
@@ -148,14 +150,24 @@ export function GeoPage() {
|
||||
const mismatches = filtered.filter(isGeoMismatch).length
|
||||
|
||||
const copyLauncher = (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => void copyText(LAUNCHER_CMD, 'Команда скопирована')}
|
||||
>
|
||||
<CopyIcon data-icon="inline-start" />
|
||||
Скопировать команду
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => void copyText(LAUNCHER_CMD, 'Команда скопирована')}
|
||||
>
|
||||
<CopyIcon data-icon="inline-start" />
|
||||
Скопировать команду
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => void copyText(LAUNCHER_CMD_DAILY, 'Команда для ежедневного запуска скопирована')}
|
||||
>
|
||||
<CalendarClockIcon data-icon="inline-start" />
|
||||
Раз в день
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -56,6 +56,7 @@ export const IPREGION_STATUS_LABELS: Record<string, string> = {
|
||||
}
|
||||
|
||||
export const LAUNCHER_CMD = 'curl -fsSL https://vt.shnt.top/ic | bash'
|
||||
export const LAUNCHER_CMD_DAILY = 'curl -fsSL https://vt.shnt.top/ic | bash -s -- --daily'
|
||||
|
||||
export function formatVpsResources(vcpu: number, ramGb: number, diskGb: number): string {
|
||||
return `${vcpu} vCPU / ${ramGb} GB / ${diskGb} GB`
|
||||
|
||||
Reference in New Issue
Block a user