From af656fe8f5306792235d5562fe3564027ef104c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Fri, 14 Aug 2026 09:05:16 +0400 Subject: [PATCH] =?UTF-8?q?v0.1.27:=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=86=D0=B0-=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=B0=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=BA=D0=BE=D1=80=D0=BD=D0=B5=20/=20(=D0=B4=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D0=B9=D0=BD=20Nubes)=20+=20/static?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- app/router/router.go | 14 ++- app/ui/embed.go | 27 ++++- app/ui/index.html | 2 +- app/ui/info.html | 236 ++++++++++++++++++++++++++++++++++++++ app/ui/static/favicon.svg | 55 +++++++++ app/ui/static/logo.svg | 25 ++++ 7 files changed, 357 insertions(+), 4 deletions(-) create mode 100644 app/ui/info.html create mode 100644 app/ui/static/favicon.svg create mode 100755 app/ui/static/logo.svg diff --git a/Makefile b/Makefile index 4e0ce3a..a767e4d 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # Registry: Docker Hub (naeel/shared-sqs) IMAGE_REPO=naeel/shared-sqs -VERSION=v0.1.26 +VERSION=v0.1.27 LDFLAGS=-X shared-sqs/app/models.Version=$(VERSION) BINARY=shared-sqs diff --git a/app/router/router.go b/app/router/router.go index ed90466..2c63d9b 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -39,6 +39,9 @@ func New(tenantStore *tenant.TenantStore, adminToken string) http.Handler { // /health — публичный, без auth r.HandleFunc("/health", health).Methods("GET") + // /static — логотип, favicon для публичных страниц + r.PathPrefix("/static").Handler(ui.StaticHandler()).Methods("GET") + // /metrics — Prometheus endpoint для Victoria Metrics scrape r.Handle("/metrics", promhttp.Handler()).Methods("GET") @@ -58,7 +61,16 @@ func New(tenantStore *tenant.TenantStore, adminToken string) http.Handler { // r.NewRoute().Subrouter() с Use() некорректно работает в gorilla/mux v1.8.0 // при пустом prefix — ответы теряются. Поэтому используем явную обёртку. sqsAuth := auth.AuthMiddleware(tenantStore) - r.Handle("/", sqsAuth(http.HandlerFunc(actionHandler))).Methods("GET", "POST") + // Корень: GET без Action — публичная страница-описание сервиса; + // всё остальное (POST, или GET с Action/X-Amz-Target) — SQS API за tenant auth. + rootHandler := func(w http.ResponseWriter, req *http.Request) { + if req.Method == http.MethodGet && extractAction(req) == "" { + ui.InfoHandler(models.Version).ServeHTTP(w, req) + return + } + sqsAuth(http.HandlerFunc(actionHandler)).ServeHTTP(w, req) + } + r.HandleFunc("/", rootHandler).Methods("GET", "POST") r.Handle("/{account}", sqsAuth(http.HandlerFunc(actionHandler))).Methods("GET", "POST") r.Handle("/queue/{queueName}", sqsAuth(http.HandlerFunc(actionHandler))).Methods("GET", "POST") r.Handle("/{account}/{queueName}", sqsAuth(http.HandlerFunc(actionHandler))).Methods("GET", "POST") diff --git a/app/ui/embed.go b/app/ui/embed.go index ebd318d..3777766 100644 --- a/app/ui/embed.go +++ b/app/ui/embed.go @@ -5,13 +5,38 @@ package ui import ( "embed" + "io/fs" "net/http" + "strings" ) -//go:embed index.html +//go:embed index.html info.html static var content embed.FS // Handler — возвращает http.Handler, раздающий встроенный index.html func Handler() http.Handler { return http.FileServer(http.FS(content)) } + +// InfoHandler — публичная страница-описание сервиса (GET /) с подстановкой версии +func InfoHandler(version string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, err := content.ReadFile("info.html") + if err != nil { + http.Error(w, "info page unavailable", http.StatusInternalServerError) + return + } + html := strings.ReplaceAll(string(body), "{{VERSION}}", version) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + _, _ = w.Write([]byte(html)) + }) +} + +// StaticHandler — раздаёт /static/* (логотип, favicon) для публичных страниц +func StaticHandler() http.Handler { + sub, err := fs.Sub(content, "static") + if err != nil { + panic(err) + } + return http.StripPrefix("/static/", http.FileServer(http.FS(sub))) +} diff --git a/app/ui/index.html b/app/ui/index.html index b1d9002..ceab565 100644 --- a/app/ui/index.html +++ b/app/ui/index.html @@ -347,7 +347,7 @@ td.msg-expand { padding: 0 !important; border-bottom: 1px solid var(--border); }
Admin API: POST /admin/tenants (Bearer token)
Realm: iot-naeel · Persistence: Managed Redis
Версия:
-
Образ: naeel/shared-sqs:v0.1.26
+
Образ: naeel/shared-sqs:v0.1.27
Статус: тестирование
diff --git a/app/ui/info.html b/app/ui/info.html new file mode 100644 index 0000000..97b61f2 --- /dev/null +++ b/app/ui/info.html @@ -0,0 +1,236 @@ + + + + + +shared-sqs — очередь Nubes (SQS API) + + + + + +
+ nubes + Nubes + · очередь + + {{VERSION}} +
+ +
+ +
+ nubes +
+

shared-sqs тестирование

+

Multi-tenant очередь, совместимая с AWS SQS API. Каждый тенант получает изолированное пространство очередей.

+
+
+ +
+
Подключение
+
+
Endpoint
+
https://sqs.containerk8s.dev.nubes.ru
+
Протокол
+
AWS SQS Query / JSON, подпись AWS Signature V4
+
Регион
+
us-east-1
+
Аутентификация
+
Access Key / Secret Key тенанта (выдаются в консоли /ui)
+
Консоль
+
/ui — веб-интерфейс (вход по токену Nubes)
+
Health
+ +
Метрики
+
GET /metrics — Prometheus
+
Persistence
+
Managed Redis (realm iot-naeel)
+
+
+ +
+
Команды SQS API
+
+

Все команды отправляются на корень POST https://sqs.containerk8s.dev.nubes.ru/ с параметром Action.

+
+ + + + + + + + + + + + + + + + + + + + + + + +
ActionОписание
CreateQueueСоздать очередь
ListQueuesСписок очередей тенанта
GetQueueUrlURL очереди по имени
GetQueueAttributesАтрибуты очереди
SetQueueAttributesИзменить атрибуты очереди
SendMessageОтправить сообщение
SendMessageBatchОтправить до 10 сообщений разом
ReceiveMessageПолучить сообщения (long polling до 20с)
DeleteMessageУдалить сообщение
DeleteMessageBatchУдалить до 10 сообщений разом
ChangeMessageVisibilityИзменить таймаут видимости сообщения
ChangeMessageVisibilityBatchПакетно изменить таймаут видимости
PurgeQueueОчистить очередь
DeleteQueueУдалить очередь
TagQueueНазначить теги очереди
UntagQueueСнять теги с очереди
ListQueueTagsСписок тегов очереди
+
+
+
+ +
+
Примеры (AWS CLI)
+
+
Ключи тенанта
+
export AWS_ACCESS_KEY_ID=<Access Key из /ui>
+export AWS_SECRET_ACCESS_KEY=<Secret Key из /ui>
+
Создать очередь
+
aws sqs create-queue --queue-name demo \
+  --endpoint-url https://sqs.containerk8s.dev.nubes.ru \
+  --region us-east-1
+
Отправить сообщение (QueueUrl — из ответа create-queue)
+
aws sqs send-message --queue-url <QueueUrl> \
+  --message-body "hello nubes" \
+  --endpoint-url https://sqs.containerk8s.dev.nubes.ru \
+  --region us-east-1
+
Получить и удалить сообщение
+
aws sqs receive-message --queue-url <QueueUrl> \
+  --endpoint-url https://sqs.containerk8s.dev.nubes.ru --region us-east-1
+
+aws sqs delete-message --queue-url <QueueUrl> \
+  --receipt-handle <ReceiptHandle> \
+  --endpoint-url https://sqs.containerk8s.dev.nubes.ru --region us-east-1
+
+
+ + + +
+ + diff --git a/app/ui/static/favicon.svg b/app/ui/static/favicon.svg new file mode 100644 index 0000000..11a9ece --- /dev/null +++ b/app/ui/static/favicon.svg @@ -0,0 +1,55 @@ + + diff --git a/app/ui/static/logo.svg b/app/ui/static/logo.svg new file mode 100755 index 0000000..d76eef6 --- /dev/null +++ b/app/ui/static/logo.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + +