Введён тип QueueStore с индексом accessKey→{queueName}. Мутации очередей идут через
AddQueue/RemoveQueue (create/delete/restore/config/seed/admin), подсчёт и список —
через CountTenantQueues/TenantQueueNames. Устранены O(total) скан-по-префиксу в
countTenantQueues, deleteTenant, listTenantQueues, createTenantQueue. API SyncQueues
(Queues, Lock) сохранён — остальной код не затронут.
124 lines
4.3 KiB
Go
124 lines
4.3 KiB
Go
// app/cmd/seed.go
|
||
// Автосид демо-данных при старте через SHARED_SQS_SEED_DEMO=true.
|
||
// Создаёт тенанта demo-service со случайными кредами (генерируются через
|
||
// tenant.Create → crypto/rand) с 5 очередями и демо-сообщениями.
|
||
//
|
||
// Тенант demo-service изолирован: видит только свои очереди, не имеет доступа к
|
||
// admin API и к очередям других тенантов. Креды генерируются случайно и печатаются
|
||
// в лог при старте (только при явном включении SHARED_SQS_SEED_DEMO).
|
||
package main
|
||
|
||
import (
|
||
"crypto/md5" //nolint:gosec — MD5 используется для SQS-совместимости, не для безопасности
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/google/uuid"
|
||
log "github.com/sirupsen/logrus"
|
||
|
||
"shared-sqs/app/models"
|
||
"shared-sqs/app/tenant"
|
||
)
|
||
|
||
const (
|
||
demoTenantName = "demo-service"
|
||
demoMaxQueues = 10
|
||
)
|
||
|
||
// seedDemoData создаёт тенанта demo-service с очередями и сообщениями.
|
||
// Вызывается при SHARED_SQS_SEED_DEMO=true при старте сервера.
|
||
// Креды генерируются случайно (tenant.Create) — никаких захардкоженных
|
||
// AccessKey/SecretKey в исходнике.
|
||
func seedDemoData(store *tenant.TenantStore) {
|
||
t, err := store.Create(demoTenantName, demoMaxQueues)
|
||
if err != nil {
|
||
log.Warnf("seed: не удалось создать demo-tenant: %v", err)
|
||
return
|
||
}
|
||
log.Infof("seed: создан тенант %s (AccessKey=%s, SecretKey=%s)", t.ID, t.AccessKey, t.SecretKey)
|
||
|
||
// Демо-очереди с набором сообщений
|
||
queues := []struct {
|
||
name string
|
||
msgs []string
|
||
}{
|
||
{
|
||
"orders",
|
||
[]string{
|
||
`{"order_id":"1001","amount":99.99,"status":"pending"}`,
|
||
`{"order_id":"1002","amount":14.50,"status":"completed"}`,
|
||
`{"order_id":"1003","amount":299.00,"status":"processing"}`,
|
||
},
|
||
},
|
||
{
|
||
"notifications",
|
||
[]string{
|
||
`{"to":"user@example.com","text":"Welcome to the service!"}`,
|
||
`{"to":"admin@example.com","text":"New user signed up"}`,
|
||
},
|
||
},
|
||
{
|
||
"emails",
|
||
[]string{
|
||
`{"subject":"Invoice #42","body":"See attachment","to":"billing@example.com"}`,
|
||
},
|
||
},
|
||
{
|
||
"uploads",
|
||
nil,
|
||
},
|
||
{
|
||
"user-events",
|
||
[]string{
|
||
`{"event":"login","user_id":"u-123","ts":1744000000}`,
|
||
`{"event":"logout","user_id":"u-123","ts":1744003600}`,
|
||
`{"event":"purchase","user_id":"u-456","item_id":"prod-7","ts":1744005000}`,
|
||
},
|
||
},
|
||
}
|
||
|
||
for _, q := range queues {
|
||
key := t.AccessKey + ":" + q.name
|
||
|
||
// URL и ARN формируем по тому же шаблону что gosqs/tenant_helpers.go:tenantQueueURL/tenantQueueARN
|
||
// Иначе AWS CLI получает пустой QueueUrl в ListQueues и не может работать с очередью.
|
||
env := models.CurrentEnvironment
|
||
var queueURL string
|
||
if env.Region != "" {
|
||
queueURL = "http://" + env.Region + "." + env.Host + ":" + env.Port + "/" + t.ID + "/" + q.name
|
||
} else {
|
||
queueURL = "http://" + env.Host + ":" + env.Port + "/" + t.ID + "/" + q.name
|
||
}
|
||
queueARN := "arn:aws:sqs:" + env.Region + ":" + t.ID + ":" + q.name
|
||
|
||
msgs := make([]models.SqsMessage, 0, len(q.msgs))
|
||
for _, body := range q.msgs {
|
||
//nolint:gosec — MD5 здесь для совместимости с AWS SQS протоколом
|
||
sum := md5.Sum([]byte(body)) //nolint:gosec
|
||
msgs = append(msgs, models.SqsMessage{
|
||
MessageBody: body,
|
||
Uuid: uuid.NewString(),
|
||
MD5OfMessageBody: fmt.Sprintf("%x", sum),
|
||
SentTime: time.Now(),
|
||
})
|
||
}
|
||
|
||
models.SyncQueues.Lock()
|
||
models.SyncQueues.AddQueue(key, &models.Queue{
|
||
Name: q.name,
|
||
URL: queueURL,
|
||
Arn: queueARN,
|
||
VisibilityTimeout: 30,
|
||
MaximumMessageSize: 262144,
|
||
MessageRetentionPeriod: 345600,
|
||
Messages: msgs,
|
||
Duplicates: make(map[string]time.Time),
|
||
})
|
||
models.SyncQueues.Unlock()
|
||
|
||
log.Infof("seed: очередь %s (%d сообщений)", q.name, len(q.msgs))
|
||
}
|
||
|
||
log.Infof("seed: демо-данные готовы — тенант %s, 5 очередей", t.Name)
|
||
}
|