feat(serverembed): add server embed functionality and readme
Some checks failed
CI / Test (1.22) (push) Failing after -22m28s
CI / Test (1.23) (push) Failing after -22m28s
CI / Lint (push) Has been cancelled
CI / Build (push) Has been cancelled

This commit is contained in:
Hein
2026-02-20 16:39:43 +02:00
parent 3b6d0f81d2
commit 7d6f99b3b3
3 changed files with 149 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
package serverembed
import (
"embed"
)
//go:embed dist/** readme
var RootEmbedFS embed.FS

1
pkg/serverembed/readme Normal file
View File

@@ -0,0 +1 @@
# Server Embed File

View File

@@ -13,9 +13,11 @@ import (
"git.warky.dev/wdevs/whatshooked/pkg/handlers" "git.warky.dev/wdevs/whatshooked/pkg/handlers"
"git.warky.dev/wdevs/whatshooked/pkg/hooks" "git.warky.dev/wdevs/whatshooked/pkg/hooks"
"git.warky.dev/wdevs/whatshooked/pkg/logging" "git.warky.dev/wdevs/whatshooked/pkg/logging"
"git.warky.dev/wdevs/whatshooked/pkg/models"
"git.warky.dev/wdevs/whatshooked/pkg/storage" "git.warky.dev/wdevs/whatshooked/pkg/storage"
"git.warky.dev/wdevs/whatshooked/pkg/utils" "git.warky.dev/wdevs/whatshooked/pkg/utils"
"git.warky.dev/wdevs/whatshooked/pkg/whatsapp" "git.warky.dev/wdevs/whatshooked/pkg/whatsapp"
resolvespec_common "github.com/bitechdev/ResolveSpec/pkg/spectypes"
"go.mau.fi/whatsmeow/types" "go.mau.fi/whatsmeow/types"
) )
@@ -258,6 +260,137 @@ func (wh *WhatsHooked) loadHooksFromDatabase(ctx context.Context) error {
return nil return nil
} }
// syncConfigToDatabase upserts hooks and WhatsApp accounts from config.json into the
// database so that config-file entries are never silently ignored at startup. Existing
// rows (matched by ID) are updated to reflect any config changes; new rows are inserted.
// The admin user is used as the owner for all config-seeded rows.
func (wh *WhatsHooked) syncConfigToDatabase(ctx context.Context) error {
db := storage.GetDB()
if db == nil {
return nil
}
// Resolve the admin user ID to assign as owner of config-seeded rows.
userRepo := storage.NewUserRepository(db)
adminUser, err := userRepo.GetByUsername(ctx, "admin")
if err != nil || adminUser == nil {
logging.Warn("Admin user not found, skipping config sync", "error", err)
return nil
}
adminID := adminUser.ID.String()
now := time.Now()
// --- Sync hooks ---
if len(wh.config.Hooks) > 0 {
for _, h := range wh.config.Hooks {
if h.ID == "" {
logging.Warn("Skipping config hook with no ID", "name", h.Name)
continue
}
method := h.Method
if method == "" {
method = "POST"
}
// Serialize headers and events as JSON blobs.
headersJSON := ""
if len(h.Headers) > 0 {
if b, err := json.Marshal(h.Headers); err == nil {
headersJSON = string(b)
}
}
eventsJSON := ""
if len(h.Events) > 0 {
if b, err := json.Marshal(h.Events); err == nil {
eventsJSON = string(b)
}
}
row := models.ModelPublicHook{
ID: resolvespec_common.NewSqlString(h.ID),
Name: resolvespec_common.NewSqlString(h.Name),
URL: resolvespec_common.NewSqlString(h.URL),
Method: resolvespec_common.NewSqlString(method),
Description: resolvespec_common.NewSqlString(h.Description),
Headers: resolvespec_common.NewSqlString(headersJSON),
Events: resolvespec_common.NewSqlString(eventsJSON),
Active: h.Active,
AllowInsecure: h.AllowInsecure,
UserID: resolvespec_common.NewSqlString(adminID),
CreatedAt: resolvespec_common.NewSqlTimeStamp(now),
UpdatedAt: resolvespec_common.NewSqlTimeStamp(now),
}
_, err := db.NewInsert().
Model(&row).
On("CONFLICT (id) DO UPDATE").
Set("name = EXCLUDED.name").
Set("url = EXCLUDED.url").
Set("method = EXCLUDED.method").
Set("description = EXCLUDED.description").
Set("headers = EXCLUDED.headers").
Set("events = EXCLUDED.events").
Set("active = EXCLUDED.active").
Set("allow_insecure = EXCLUDED.allow_insecure").
Set("updated_at = EXCLUDED.updated_at").
Exec(ctx)
if err != nil {
logging.Error("Failed to sync hook from config", "hook_id", h.ID, "error", err)
} else {
logging.Info("Synced hook from config to database", "hook_id", h.ID, "name", h.Name)
}
}
}
// --- Sync WhatsApp accounts ---
if len(wh.config.WhatsApp) > 0 {
accountRepo := storage.NewWhatsAppAccountRepository(db)
_ = accountRepo // used via db directly for upsert
for _, wa := range wh.config.WhatsApp {
if wa.ID == "" {
logging.Warn("Skipping config WhatsApp account with no ID", "phone", wa.PhoneNumber)
continue
}
accountType := wa.Type
if accountType == "" {
accountType = "whatsmeow"
}
row := models.ModelPublicWhatsappAccount{
ID: resolvespec_common.NewSqlString(wa.ID),
AccountType: resolvespec_common.NewSqlString(accountType),
PhoneNumber: resolvespec_common.NewSqlString(wa.PhoneNumber),
SessionPath: resolvespec_common.NewSqlString(wa.SessionPath),
Active: !wa.Disabled,
UserID: resolvespec_common.NewSqlString(adminID),
CreatedAt: resolvespec_common.NewSqlTimeStamp(now),
UpdatedAt: resolvespec_common.NewSqlTimeStamp(now),
}
_, err := db.NewInsert().
Model(&row).
On("CONFLICT (id) DO UPDATE").
Set("account_type = EXCLUDED.account_type").
Set("phone_number = EXCLUDED.phone_number").
Set("session_path = EXCLUDED.session_path").
Set("active = EXCLUDED.active").
Set("updated_at = EXCLUDED.updated_at").
Exec(ctx)
if err != nil {
logging.Error("Failed to sync WhatsApp account from config", "account_id", wa.ID, "error", err)
} else {
logging.Info("Synced WhatsApp account from config to database", "account_id", wa.ID, "phone", wa.PhoneNumber)
}
}
}
return nil
}
// Handlers returns the HTTP handlers instance // Handlers returns the HTTP handlers instance
func (wh *WhatsHooked) Handlers() *handlers.Handlers { func (wh *WhatsHooked) Handlers() *handlers.Handlers {
return wh.handlers return wh.handlers
@@ -330,6 +463,13 @@ func (wh *WhatsHooked) StartAPIServer(ctx context.Context) error {
// Mark database as ready for account/hook loading // Mark database as ready for account/hook loading
wh.dbReady = true wh.dbReady = true
// Sync config.json hooks and accounts into the database so they are never silently ignored
logging.Info("Syncing config to database")
if err := wh.syncConfigToDatabase(ctx); err != nil {
logging.Error("Failed to sync config to database", "error", err)
// Non-fatal: continue with whatever is already in the database
}
// Load hooks from database // Load hooks from database
if err := wh.loadHooksFromDatabase(ctx); err != nil { if err := wh.loadHooksFromDatabase(ctx); err != nil {
logging.Error("Failed to load hooks from database", "error", err) logging.Error("Failed to load hooks from database", "error", err)