feat(serverembed): add server embed functionality and readme
This commit is contained in:
8
pkg/serverembed/frontend.go
Normal file
8
pkg/serverembed/frontend.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package serverembed
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed dist/** readme
|
||||||
|
var RootEmbedFS embed.FS
|
||||||
1
pkg/serverembed/readme
Normal file
1
pkg/serverembed/readme
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Server Embed 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)
|
||||||
|
|||||||
Reference in New Issue
Block a user