Очистить репозиторий перед переносом продукта
@@ -106,7 +106,9 @@ ESP32/**/*.a
|
|||||||
deploy/backup/archive/**
|
deploy/backup/archive/**
|
||||||
!deploy/backup/archive/.gitkeep
|
!deploy/backup/archive/.gitkeep
|
||||||
|
|
||||||
# Локальная дев-обвязка Claude (дев-сервер shine-UI, сессии, планы) — не коммитим
|
# Локальная дев-обвязка AI-агентов (сессии, планы, настройки) — не коммитим
|
||||||
|
.agents/
|
||||||
|
.codex/
|
||||||
.claude/
|
.claude/
|
||||||
# Рабочие бэкапы/превью-ассеты UI — не для репозитория
|
# Рабочие бэкапы/превью-ассеты UI — не для репозитория
|
||||||
*.bak.png
|
*.bak.png
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
- `far/` - дальнее будущее без понятного срока.
|
- `far/` - дальнее будущее без понятного срока.
|
||||||
- Если пользователь спрашивает, какие есть планы или что можно продолжить, нужно смотреть эти три папки и отвечать кратким списком по горизонтам.
|
- Если пользователь спрашивает, какие есть планы или что можно продолжить, нужно смотреть эти три папки и отвечать кратким списком по горизонтам.
|
||||||
- Файлы из `TODO/` не начинать реализовывать без явной команды пользователя.
|
- Файлы из `TODO/` не начинать реализовывать без явной команды пользователя.
|
||||||
- После реализации фичи, требующей ручной проверки, нужно добавить отдельный файл в `docs/Pending_Features/`.
|
|
||||||
|
|
||||||
## Центр задач и предложений
|
## Центр задач и предложений
|
||||||
- Сервис хранит простые задачи и предложения в `data/task_center/items.json`.
|
- Сервис хранит простые задачи и предложения в `data/task_center/items.json`.
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# Third-party notices
|
||||||
|
|
||||||
|
This file lists third-party components and assets used by SHiNE. It is a practical attribution file for repository publication; individual dependency artifacts may include additional license text in their own packages.
|
||||||
|
|
||||||
|
## Twemoji
|
||||||
|
|
||||||
|
SHiNE UI uses Twemoji graphics for emoji rendering in the chat emoji picker and emoji-only messages.
|
||||||
|
|
||||||
|
- Source: https://github.com/twitter/twemoji
|
||||||
|
- Graphics license: Creative Commons Attribution 4.0 International (CC BY 4.0)
|
||||||
|
- Code license: MIT
|
||||||
|
- License text: https://creativecommons.org/licenses/by/4.0/
|
||||||
|
|
||||||
|
Attribution:
|
||||||
|
|
||||||
|
Emoji graphics by Twemoji, licensed under CC BY 4.0.
|
||||||
|
|
||||||
|
Changes in SHiNE:
|
||||||
|
|
||||||
|
- Emoji are stored and sent as normal Unicode text.
|
||||||
|
- Twemoji SVG graphics are used only as a visual rendering layer in the web UI.
|
||||||
|
- The UI loads Twemoji SVG assets from the pinned `twitter/twemoji@14.0.2` package via jsDelivr.
|
||||||
|
|
||||||
|
## QR Code Generator
|
||||||
|
|
||||||
|
SHiNE UI includes `shine-UI/js/vendor-qrcode-generator.js`.
|
||||||
|
|
||||||
|
- Project: QR Code Generator for JavaScript
|
||||||
|
- Copyright: Kazuhiko Arase
|
||||||
|
- License: MIT
|
||||||
|
- Source: http://www.d-project.com/
|
||||||
|
|
||||||
|
## SHiNE project-owned visual assets
|
||||||
|
|
||||||
|
SHiNE logos, icons and generated visual assets in `shine-UI/assets/` and `shine-UI/img/` are project-owned assets, unless a specific file says otherwise.
|
||||||
|
|
||||||
|
## Solana JavaScript libraries
|
||||||
|
|
||||||
|
SHiNE UI and Solana tooling use Solana JavaScript libraries, including `@solana/web3.js`.
|
||||||
|
|
||||||
|
- Package: `@solana/web3.js`
|
||||||
|
- License: MIT
|
||||||
|
- Source: https://github.com/solana-foundation/solana-web3.js
|
||||||
|
|
||||||
|
Some Solana JavaScript dependency trees include additional packages under permissive licenses such as MIT, Apache-2.0, BSD, ISC, 0BSD and CC0-1.0.
|
||||||
|
|
||||||
|
Known stricter dependency:
|
||||||
|
|
||||||
|
- Package: `rpc-websockets`
|
||||||
|
- License: LGPL-3.0-only
|
||||||
|
- Used transitively through Solana JavaScript dependencies in `shine-solana/shine` and `SHiNE-browser-plugin-wallet`.
|
||||||
|
|
||||||
|
## Noble cryptography libraries
|
||||||
|
|
||||||
|
SHiNE browser wallet/vendor bundles include Noble cryptography code.
|
||||||
|
|
||||||
|
- Packages: `@noble/curves`, `@noble/hashes`
|
||||||
|
- License: MIT
|
||||||
|
- Source: https://github.com/paulmillr/noble-curves and https://github.com/paulmillr/noble-hashes
|
||||||
|
|
||||||
|
## Java server dependencies
|
||||||
|
|
||||||
|
The SHiNE Java server uses third-party dependencies from Maven Central, including:
|
||||||
|
|
||||||
|
- Eclipse Jetty (`org.eclipse.jetty:*`) - EPL-2.0 / Apache-2.0 family licensing
|
||||||
|
- Bouncy Castle (`org.bouncycastle:bcprov-jdk18on`) - Bouncy Castle permissive license
|
||||||
|
- Jackson (`com.fasterxml.jackson.core:jackson-databind`) - Apache-2.0
|
||||||
|
- Logback (`ch.qos.logback:logback-classic`) - EPL-1.0 / LGPL-2.1
|
||||||
|
- SLF4J (`org.slf4j:slf4j-api`) - MIT
|
||||||
|
- SQLite JDBC (`org.xerial:sqlite-jdbc`) - Apache-2.0
|
||||||
|
- Web Push Java library (`nl.martijndwars:web-push`) - Apache-2.0
|
||||||
|
- JUnit (`org.junit:*`) - EPL-2.0
|
||||||
|
|
||||||
|
## Gradle Wrapper
|
||||||
|
|
||||||
|
The repository includes Gradle wrapper scripts.
|
||||||
|
|
||||||
|
- License: Apache License 2.0
|
||||||
|
- Source: https://gradle.org/
|
||||||
|
|
||||||
|
## Espressif code snippets
|
||||||
|
|
||||||
|
The ESP32 prototype area includes Espressif audio codec helper files with SPDX/license headers.
|
||||||
|
|
||||||
|
- Files include `ESPRESSIF MIT License` and `SPDX-License-Identifier: Apache-2.0` notices.
|
||||||
|
- Original copyright notices are preserved in the source files.
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
# ESP32 как аппаратный кошелёк (device-сессия)
|
|
||||||
|
|
||||||
## Суть фичи
|
|
||||||
|
|
||||||
ESP32 становится аппаратным HSM (hardware security module): хранит ключи, постоянно подключён к SHiNE-серверу как device-сессия, подтверждает операции нажатием на экране. Другие устройства (браузер, телефон) взаимодействуют с ESP32 через сервер — без прямого соединения.
|
|
||||||
|
|
||||||
## Два ключевых сценария
|
|
||||||
|
|
||||||
### Сценарий 1 — Создание делегированной сессии
|
|
||||||
1. Браузер/телефон → сервер: «хочу делегированную сессию от имени пользователя X»
|
|
||||||
2. Сервер → ESP32 (device-сессия): «запрос на одобрение»
|
|
||||||
3. Пользователь нажимает «Да» на сенсорном экране ESP32
|
|
||||||
4. ESP32 → сервер: одобрено → сервер создаёт делегированную сессию для браузера
|
|
||||||
|
|
||||||
### Сценарий 2 — Подпись транзакции / блока
|
|
||||||
1. Браузер (через делегированную сессию) → сервер → ESP32: «подпиши вот это»
|
|
||||||
2. ESP32 показывает запрос на экране, пользователь подтверждает
|
|
||||||
3. ESP32 подписывает нужным ключом → ответ через сервер → браузер
|
|
||||||
|
|
||||||
## Что нужно сделать
|
|
||||||
|
|
||||||
### ESP32 (основная работа)
|
|
||||||
- [ ] Инициализация WiFi (SSID/пароль в NVS)
|
|
||||||
- [ ] WebSocket-клиент (`WebSocketsClient`) — постоянное соединение с сервером
|
|
||||||
- [ ] Авторизация на сервере: `AuthChallenge` → `CreateAuthSession` через `clientKey` (уже есть в NVS), сохранить `sessionId` в NVS
|
|
||||||
- [ ] Обработчик входящих WebSocket-событий: JSON-парсинг, диспетчер по типу
|
|
||||||
- [ ] Новые UI-экраны: «Разрешить сессию?» и «Подписать?» с кнопками Да/Нет
|
|
||||||
- [ ] Расширенное хранилище ключей в NVS (произвольные именованные ключи сверх базовых трёх)
|
|
||||||
- [ ] Переподключение при разрыве (reconnect loop)
|
|
||||||
|
|
||||||
### Сервер (минимальные изменения)
|
|
||||||
- [ ] Добавить поле `sessionType` (`USER` / `DEVICE`) в таблицу `active_sessions`
|
|
||||||
- [ ] Новая операция `DeviceApprovalRequest` — браузер запрашивает одобрение у device-сессии
|
|
||||||
- [ ] Новая операция `DeviceApprovalResponse` — ESP32 отвечает (одобрено/отклонено)
|
|
||||||
- [ ] Новые операции `SignRequest` / `SignResponse` — запрос подписи и ответ
|
|
||||||
- [ ] Роутинг: при получении запроса найти device-сессию через `ActiveConnectionsRegistry.getByLogin(login)` + фильтр по `sessionType=DEVICE`, переслать туда
|
|
||||||
|
|
||||||
### Клиент (отдельный этап)
|
|
||||||
- [ ] Браузерное расширение или UI: создание делегированной сессии, отправка `SignRequest`
|
|
||||||
|
|
||||||
## Что уже готово (переиспользуем)
|
|
||||||
|
|
||||||
- **Роутинг сообщений** — `SendDirectMessage` с `TARGET_ONE_SESSION` и `CallSignalToSession` уже умеют точечно доставлять в конкретный `sessionId`. Механизм готов, нужно добавить только новые op-коды поверх него.
|
|
||||||
- **Ed25519 на ESP32** — библиотека `<Ed25519.h>` уже используется в скетче. Подписи работают.
|
|
||||||
- **NVS** — уже хранит логин, мастер-секрет, 3 пары ключей. Расширяется легко.
|
|
||||||
- **`ActiveConnectionsRegistry`** — поиск по `login` и `sessionId` уже есть на сервере.
|
|
||||||
- **Аутентификация** — схема `AuthChallenge` → `CreateAuthSession` через Ed25519 уже полностью реализована.
|
|
||||||
|
|
||||||
## Оценка сложности
|
|
||||||
|
|
||||||
| Компонент | Сложность |
|
|
||||||
|---|---|
|
|
||||||
| ESP32: WiFi + WebSocket-клиент + авторизация | Средняя |
|
|
||||||
| ESP32: обработчик входящих + UI подтверждений | Средняя |
|
|
||||||
| Сервер: флаг sessionType + 4 новых op-а + роутинг | Низкая–средняя |
|
|
||||||
| Браузерное расширение | Высокая (отдельный этап) |
|
|
||||||
|
|
||||||
**Итого фазы ESP32 + сервер: ~1–1.5 недели.**
|
|
||||||
|
|
||||||
## С чего начинать
|
|
||||||
|
|
||||||
1. Серверная часть проще и быстрее — начать с добавления `sessionType` и `DeviceApprovalRequest/Response`.
|
|
||||||
2. Затем ESP32: WiFi → WebSocket → авторизация → обработчик входящих → UI.
|
|
||||||
3. Браузерное расширение — отдельная итерация после того как ESP32 + сервер работают.
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# TODO: Будущие доработки
|
|
||||||
|
|
||||||
## 1) Полный переход на `ReceiveOutcomingMessage`
|
|
||||||
- Сейчас в UI используется `ReceiveOutcomingMessage` с fallback на `SendMessagePair`.
|
|
||||||
- Fallback нужен только временно для совместимости со старыми серверами.
|
|
||||||
- После обновления всех серверов:
|
|
||||||
- убрать вызов `SendMessagePair` из UI,
|
|
||||||
- убрать регистрацию `SendMessagePair` на сервере (оставить только `ReceiveOutcomingMessage`).
|
|
||||||
|
|
||||||
## 2) Реальная мультисерверная доставка
|
|
||||||
- Сейчас фактически предполагается 1 сервер на пользователя.
|
|
||||||
- Нужно реализовать штатную мультисерверную схему:
|
|
||||||
- пересылка исходящих сообщений между серверами пользователя A,
|
|
||||||
- пересылка входящих сообщений между серверами пользователя B,
|
|
||||||
- дедупликация на уровне БД для затухания дублей.
|
|
||||||
|
|
||||||
## 3) Надёжная доставка при перезапуске сервера
|
|
||||||
- Сейчас возможен сценарий: запись уже сохранена в БД, но сервер не успел переслать дальше из-за перезапуска.
|
|
||||||
- Нужно добавить механизм «store + guaranteed forward»:
|
|
||||||
- очередь/аутбокс для межсерверной пересылки,
|
|
||||||
- фоновый ретрай до подтверждения отправки,
|
|
||||||
- корректная остановка (graceful shutdown) с дожатием критичных задач.
|
|
||||||
|
|
||||||
## 4) Политика идемпотентности
|
|
||||||
- Сохранить принцип: пара (`incoming`, `outgoing`) пишется одной транзакцией, либо обе, либо ни одной.
|
|
||||||
- Не допускать частичного состояния, при котором в БД есть только один блок пары.
|
|
||||||
|
|
||||||
## 5) Наблюдаемость и аналитика
|
|
||||||
- Добавить метрики по доставке:
|
|
||||||
- количество дублей,
|
|
||||||
- количество успешных вставок пар,
|
|
||||||
- доля доставок в WS/push,
|
|
||||||
- количество ретраев межсерверной пересылки.
|
|
||||||
|
|
||||||
## 6) Ограничение текущих звонков (важно)
|
|
||||||
- Сейчас звонки работают только в рамках одного сигнального сервера (или единого контура, где обе стороны уже подключены).
|
|
||||||
- Сценарий «пользователь A на своих серверах, пользователь B на других серверах» пока не поддержан.
|
|
||||||
- TODO на будущее:
|
|
||||||
- временная межсерверная авторизация/сессия для старта звонка,
|
|
||||||
- отправка сигнальных сообщений между разными серверами пользователей,
|
|
||||||
- аккуратное завершение временной сессии после установления/завершения звонка.
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# TODO: Звонки и межсерверность
|
|
||||||
|
|
||||||
## Текущее ограничение
|
|
||||||
- Текущая реализация звонков фактически работает в одном сигнальном контуре (один сервер/единый кластер, где обе стороны уже присутствуют).
|
|
||||||
- Если пользователь A подключён к серверу A, а пользователь B к серверу B (и между ними нет общего сигнального слоя), `CallInviteBroadcast`/`CallSignalToSession` не смогут полноценно провести звонок между ними.
|
|
||||||
|
|
||||||
## Почему так сейчас
|
|
||||||
- Сигналинг звонка привязан к активным сессиям и событиям на конкретном сервере.
|
|
||||||
- Выбор целевой сессии (`sessionId`) и обмен `OFFER/ANSWER/ICE` происходит в рамках текущего сигнального контура.
|
|
||||||
- Push решает только «разбудить/уведомить», но не заменяет межсерверный сигнальный канал.
|
|
||||||
|
|
||||||
## Что можно сделать дальше
|
|
||||||
- Добавить временное межсерверное подключение именно для старта и ведения звонка:
|
|
||||||
- инициатор получает short-lived access на сервер callee (или через доверенный межсерверный gateway),
|
|
||||||
- в рамках короткой сессии отправляет invite/signal для конкретного `callId`,
|
|
||||||
- после завершения звонка временная сессия закрывается автоматически.
|
|
||||||
|
|
||||||
## Что нужно доработать для этого
|
|
||||||
1. Межсерверная доверенная модель:
|
|
||||||
- подпись/верификация межсерверных вызовов,
|
|
||||||
- allowlist доверенных серверов и ротация ключей.
|
|
||||||
|
|
||||||
2. Короткоживущая «call-only» авторизация:
|
|
||||||
- отдельный тип токена/сессии с TTL (например 1–3 минуты),
|
|
||||||
- минимальные права только на `CallInviteBroadcast/CallSignalToSession`.
|
|
||||||
|
|
||||||
3. Маршрутизация сессий пользователя между серверами:
|
|
||||||
- где находится активная сессия callee,
|
|
||||||
- как доставлять `stop_call` и terminal-сигналы на все устройства callee.
|
|
||||||
|
|
||||||
4. Идемпотентность и дедупликация:
|
|
||||||
- защита от повторов межсерверных сигналов по `callId + eventId`,
|
|
||||||
- корректная обработка out-of-order событий.
|
|
||||||
|
|
||||||
5. Наблюдаемость:
|
|
||||||
- метрики межсерверной доставки сигналов,
|
|
||||||
- диагностика по стадиям звонка и причинам срыва.
|
|
||||||
|
|
||||||
## Временный рабочий подход (до межсерверности)
|
|
||||||
- Держать звонки в одном сигнальном контуре.
|
|
||||||
- Использовать WebPush как fallback-уведомление (`incoming_call`/`stop_call`) для офлайн-сессий.
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.331
|
client.version=1.2.332
|
||||||
server.version=1.2.303
|
server.version=1.2.304
|
||||||
|
|||||||
@@ -1,246 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
GITHUB_USER="ai5590"
|
|
||||||
TOKEN_VAR_NAME="GIT_AI5590_CLASSIC_API_KEY"
|
|
||||||
|
|
||||||
print_line() {
|
|
||||||
echo "------------------------------------------------------------"
|
|
||||||
}
|
|
||||||
|
|
||||||
abort() {
|
|
||||||
echo
|
|
||||||
echo "Ошибка: $1" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
require_command() {
|
|
||||||
command -v "$1" >/dev/null 2>&1 || abort "Не найдена команда '$1'. Установи её и запусти скрипт снова."
|
|
||||||
}
|
|
||||||
|
|
||||||
get_token() {
|
|
||||||
if [[ -z "${GIT_AI5590_CLASSIC_API_KEY:-}" ]]; then
|
|
||||||
abort "Не задана переменная окружения ${TOKEN_VAR_NAME}.
|
|
||||||
Перед запуском выполни:
|
|
||||||
export ${TOKEN_VAR_NAME}=\"ТВОЙ_GITHUB_TOKEN\""
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
show_intro() {
|
|
||||||
print_line
|
|
||||||
echo "Этот скрипт создаст новый репозиторий в GitHub в аккаунте '${GITHUB_USER}',"
|
|
||||||
echo "затем инициализирует git в текущей папке (если нужно),"
|
|
||||||
echo "добавит файлы, кроме самого этого скрипта, создаст первый commit и отправит проект в GitHub."
|
|
||||||
echo
|
|
||||||
echo "Скрипт работает с содержимым ТЕКУЩЕЙ папки:"
|
|
||||||
echo " $(pwd)"
|
|
||||||
echo
|
|
||||||
echo "Для авторизации используется переменная окружения:"
|
|
||||||
echo " ${TOKEN_VAR_NAME}"
|
|
||||||
print_line
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
ask_repo_name() {
|
|
||||||
local repo_name
|
|
||||||
read -r -p "Введите имя нового репозитория в GitHub: " repo_name
|
|
||||||
repo_name="$(echo "$repo_name" | xargs)"
|
|
||||||
|
|
||||||
[[ -n "$repo_name" ]] || abort "Имя репозитория не может быть пустым."
|
|
||||||
|
|
||||||
if [[ ! "$repo_name" =~ ^[A-Za-z0-9._-]+$ ]]; then
|
|
||||||
abort "Имя репозитория содержит недопустимые символы.
|
|
||||||
Разрешены: буквы, цифры, точка, дефис, подчёркивание."
|
|
||||||
fi
|
|
||||||
|
|
||||||
REPO_NAME="$repo_name"
|
|
||||||
}
|
|
||||||
|
|
||||||
ask_visibility() {
|
|
||||||
local answer
|
|
||||||
echo
|
|
||||||
read -r -p "Сделать репозиторий публичным? [y/N]: " answer
|
|
||||||
answer="${answer:-N}"
|
|
||||||
|
|
||||||
case "$answer" in
|
|
||||||
y|Y|yes|YES|да|Да|ДА)
|
|
||||||
REPO_PRIVATE="false"
|
|
||||||
REPO_VISIBILITY_TEXT="public"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
REPO_PRIVATE="true"
|
|
||||||
REPO_VISIBILITY_TEXT="private"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
ask_confirmation() {
|
|
||||||
echo
|
|
||||||
print_line
|
|
||||||
echo "Будет выполнено:"
|
|
||||||
echo "1. Создание GitHub-репозитория '${GITHUB_USER}/${REPO_NAME}' (${REPO_VISIBILITY_TEXT})"
|
|
||||||
echo "2. Подготовка git в текущей папке"
|
|
||||||
echo "3. Commit файлов из текущей папки, кроме самого этого скрипта"
|
|
||||||
echo "4. Push в ветку main"
|
|
||||||
print_line
|
|
||||||
echo
|
|
||||||
read -r -p "Продолжить? [y/N]: " confirm
|
|
||||||
confirm="${confirm:-N}"
|
|
||||||
|
|
||||||
case "$confirm" in
|
|
||||||
y|Y|yes|YES|да|Да|ДА) ;;
|
|
||||||
*) echo "Отменено пользователем."; exit 0 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
check_not_inside_wrong_git_repo() {
|
|
||||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
||||||
local top
|
|
||||||
top="$(git rev-parse --show-toplevel)"
|
|
||||||
if [[ "$top" != "$(pwd)" ]]; then
|
|
||||||
abort "Ты запустил скрипт внутри уже существующего git-репозитория, но не в его корне.
|
|
||||||
Корень репозитория:
|
|
||||||
$top
|
|
||||||
|
|
||||||
Либо перейди в корень этого репозитория, либо запусти скрипт в папке, которая не вложена в другой git-репозиторий."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
create_github_repo() {
|
|
||||||
echo
|
|
||||||
echo "Создаю репозиторий в GitHub..."
|
|
||||||
|
|
||||||
local http_code
|
|
||||||
local response_body_file
|
|
||||||
|
|
||||||
response_body_file="$(mktemp)"
|
|
||||||
|
|
||||||
http_code="$(
|
|
||||||
curl -sS \
|
|
||||||
-o "$response_body_file" \
|
|
||||||
-w "%{http_code}" \
|
|
||||||
-X POST "https://api.github.com/user/repos" \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "Authorization: Bearer ${GIT_AI5590_CLASSIC_API_KEY}" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
-d "$(cat <<JSON
|
|
||||||
{
|
|
||||||
"name": "${REPO_NAME}",
|
|
||||||
"private": ${REPO_PRIVATE},
|
|
||||||
"auto_init": false
|
|
||||||
}
|
|
||||||
JSON
|
|
||||||
)"
|
|
||||||
)"
|
|
||||||
|
|
||||||
if [[ "$http_code" != "201" ]]; then
|
|
||||||
echo
|
|
||||||
echo "GitHub API вернул ошибку. HTTP code: $http_code"
|
|
||||||
echo "Ответ сервера:"
|
|
||||||
cat "$response_body_file"
|
|
||||||
rm -f "$response_body_file"
|
|
||||||
abort "Не удалось создать репозиторий '${GITHUB_USER}/${REPO_NAME}'."
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f "$response_body_file"
|
|
||||||
echo "Репозиторий успешно создан: https://github.com/${GITHUB_USER}/${REPO_NAME}"
|
|
||||||
}
|
|
||||||
|
|
||||||
get_script_paths() {
|
|
||||||
SCRIPT_PATH="$(realpath "${BASH_SOURCE[0]}")"
|
|
||||||
PROJECT_PATH="$(pwd -P)"
|
|
||||||
|
|
||||||
SCRIPT_INSIDE_PROJECT="false"
|
|
||||||
SCRIPT_RELATIVE_PATH=""
|
|
||||||
|
|
||||||
case "$SCRIPT_PATH" in
|
|
||||||
"$PROJECT_PATH"/*)
|
|
||||||
SCRIPT_INSIDE_PROJECT="true"
|
|
||||||
SCRIPT_RELATIVE_PATH="${SCRIPT_PATH#$PROJECT_PATH/}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
SCRIPT_INSIDE_PROJECT="false"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
prepare_git_repo() {
|
|
||||||
echo
|
|
||||||
echo "Подготавливаю git в текущей папке..."
|
|
||||||
|
|
||||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
||||||
echo "Git уже инициализирован."
|
|
||||||
else
|
|
||||||
git init
|
|
||||||
echo "Git инициализирован."
|
|
||||||
fi
|
|
||||||
|
|
||||||
get_script_paths
|
|
||||||
|
|
||||||
if [[ "$SCRIPT_INSIDE_PROJECT" == "true" ]]; then
|
|
||||||
echo "Скрипт находится внутри проекта и будет исключён из commit:"
|
|
||||||
echo " $SCRIPT_RELATIVE_PATH"
|
|
||||||
git add . ":!$SCRIPT_RELATIVE_PATH"
|
|
||||||
else
|
|
||||||
git add .
|
|
||||||
fi
|
|
||||||
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "В staged нет изменений. Возможно, файлы уже были закоммичены ранее."
|
|
||||||
else
|
|
||||||
git commit -m "Initial commit"
|
|
||||||
echo "Создан commit: Initial commit"
|
|
||||||
fi
|
|
||||||
|
|
||||||
git branch -M main
|
|
||||||
|
|
||||||
local remote_url="https://${GITHUB_USER}:${GIT_AI5590_CLASSIC_API_KEY}@github.com/${GITHUB_USER}/${REPO_NAME}.git"
|
|
||||||
|
|
||||||
if git remote get-url origin >/dev/null 2>&1; then
|
|
||||||
echo "Remote 'origin' уже существует. Обновляю URL..."
|
|
||||||
git remote set-url origin "$remote_url"
|
|
||||||
else
|
|
||||||
git remote add origin "$remote_url"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
push_to_github() {
|
|
||||||
echo
|
|
||||||
echo "Отправляю проект в GitHub..."
|
|
||||||
|
|
||||||
git push -u origin main
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "Готово."
|
|
||||||
echo "Репозиторий: https://github.com/${GITHUB_USER}/${REPO_NAME}"
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup_remote_url() {
|
|
||||||
echo
|
|
||||||
echo "Убираю токен из remote URL, чтобы он не светился в git config..."
|
|
||||||
|
|
||||||
local safe_url="https://github.com/${GITHUB_USER}/${REPO_NAME}.git"
|
|
||||||
git remote set-url origin "$safe_url"
|
|
||||||
|
|
||||||
echo "Теперь origin = ${safe_url}"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
require_command git
|
|
||||||
require_command curl
|
|
||||||
require_command realpath
|
|
||||||
get_token
|
|
||||||
check_not_inside_wrong_git_repo
|
|
||||||
show_intro
|
|
||||||
ask_repo_name
|
|
||||||
ask_visibility
|
|
||||||
ask_confirmation
|
|
||||||
create_github_repo
|
|
||||||
prepare_git_repo
|
|
||||||
push_to_github
|
|
||||||
cleanup_remote_url
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# SHiNE TURN Server
|
|
||||||
|
|
||||||
This directory stores TURN setup scripts and operational instructions.
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
- Install and configure coturn for SHiNE calls.
|
|
||||||
- Keep repeatable setup scripts for new TURN nodes.
|
|
||||||
- Keep TURN-related config templates.
|
|
||||||
|
|
||||||
## Current production model
|
|
||||||
- Multiple TURN servers are supported by backend config section:
|
|
||||||
- `call.ice.turn.servers.1.*`
|
|
||||||
- `call.ice.turn.servers.2.*`
|
|
||||||
- ...
|
|
||||||
- Each server can use:
|
|
||||||
- REST auth (`sharedSecret`) for temporary credentials, or
|
|
||||||
- static `username`/`password` (fallback).
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# Third-party notices
|
|
||||||
|
|
||||||
## Telegram Animated Emojis
|
|
||||||
|
|
||||||
Animated emoji previews in SHiNE use the public catalog from Tarikul-Islam-Anik.
|
|
||||||
|
|
||||||
Source: https://github.com/Tarikul-Islam-Anik/Telegram-Animated-Emojis
|
|
||||||
|
|
||||||
The repository README states that the media files are sourced from Emojipedia and that rights to the Telegram media belong to Telegram.org. Review those rights before public distribution.
|
|
||||||
|
Before Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB |