240 lines
6.3 KiB
Go
240 lines
6.3 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"time"
|
|
|
|
"github.com/d1nch8g/jules/database"
|
|
"github.com/d1nch8g/jules/engine/actions"
|
|
"github.com/d1nch8g/jules/engine/jtime"
|
|
"github.com/d1nch8g/jules/engine/prompt"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func (e *Engine) validateActions(ctx context.Context, actionSlice []any, promptCtx prompt.Context) error {
|
|
var errs []error
|
|
|
|
for _, actionAny := range actionSlice {
|
|
switch action := actionAny.(type) {
|
|
case actions.AddContact:
|
|
_, err := e.Database.Users().Get(ctx, uuid.MustParse(action.UUID), database.UserLookupByContactCode)
|
|
if err != nil {
|
|
if errors.Is(err, database.ErrNotFound) {
|
|
errs = append(errs, fmt.Errorf("user with requested uuid %s not present in database, uuid might be wrong", action.UUID))
|
|
} else {
|
|
errs = append(errs, errors.New("unexpected db occured"))
|
|
}
|
|
}
|
|
|
|
case actions.AddNotification:
|
|
if action.Target == "self" {
|
|
continue
|
|
}
|
|
found := slices.ContainsFunc(promptCtx.Contacts, func(c database.Contact) bool {
|
|
return c.Name == action.Target
|
|
})
|
|
if !found {
|
|
errs = append(errs, fmt.Errorf("contact target %s is invalid, provide exact name", action.Target))
|
|
}
|
|
|
|
case actions.BindChat:
|
|
_, err := e.Database.Users().Get(ctx, uuid.MustParse(action.UUID), database.UserLookupByBindCode)
|
|
if err != nil {
|
|
if errors.Is(err, database.ErrNotFound) {
|
|
errs = append(errs, fmt.Errorf("user with requested uuid %s not present in database, uuid might be wrong", action.UUID))
|
|
} else {
|
|
errs = append(errs, errors.New("unexpected db occured"))
|
|
}
|
|
}
|
|
|
|
case actions.Message:
|
|
found := slices.ContainsFunc(promptCtx.Chats, func(c database.Chat) bool {
|
|
return action.Platform == c.Platform
|
|
})
|
|
if !found {
|
|
errs = append(errs, fmt.Errorf("message is invalid, platform %s might not connected for user", action.Platform))
|
|
}
|
|
|
|
case actions.SetChat:
|
|
found := slices.ContainsFunc(promptCtx.Chats, func(c database.Chat) bool {
|
|
return action.Chat == c.Platform
|
|
})
|
|
if !found {
|
|
errs = append(errs, fmt.Errorf("chat %s might not connected for user, not found", action.Chat))
|
|
}
|
|
}
|
|
}
|
|
|
|
return errors.Join(errs...)
|
|
}
|
|
|
|
func (e *Engine) runActions(ctx context.Context, actionSlice []any, user *database.User, promptCtx *prompt.Context) error {
|
|
for _, actionAny := range actionSlice {
|
|
switch action := actionAny.(type) {
|
|
case actions.BindChat:
|
|
targetUser, err := e.Database.Users().Get(ctx, uuid.MustParse(action.UUID), database.UserLookupByBindCode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = e.Database.Users().Delete(ctx, user.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var errs []error
|
|
|
|
for _, chat := range promptCtx.Chats {
|
|
errs = append(errs, e.Database.Chats().Attach(ctx, targetUser.ID, chat.Platform, chat.Identifier))
|
|
}
|
|
|
|
for _, contact := range promptCtx.Contacts {
|
|
errs = append(errs, e.Database.Contacts().Add(ctx, &database.Contact{
|
|
OwnerID: targetUser.ID,
|
|
TargetID: contact.TargetID,
|
|
Name: contact.Name,
|
|
}))
|
|
}
|
|
|
|
for _, fact := range promptCtx.Facts {
|
|
errs = append(errs, e.Database.Facts().Add(ctx, targetUser.ID, fact.Value))
|
|
}
|
|
|
|
for _, notif := range promptCtx.IncomingNotifications {
|
|
if notif.InitiatorID == user.ID {
|
|
notif.InitiatorID = targetUser.ID
|
|
}
|
|
errs = append(errs, e.Database.Notifications().Push(ctx, &database.Notification{
|
|
ID: notif.ID,
|
|
UserID: targetUser.ID,
|
|
InitiatorID: notif.InitiatorID,
|
|
ScheduledAt: notif.ScheduledAt,
|
|
Content: notif.Content,
|
|
}))
|
|
}
|
|
|
|
for _, notif := range promptCtx.OutgoingNotificaions {
|
|
errs = append(errs, e.Database.Notifications().Push(ctx, &database.Notification{
|
|
ID: notif.ID,
|
|
UserID: notif.UserID,
|
|
InitiatorID: targetUser.ID,
|
|
ScheduledAt: notif.ScheduledAt,
|
|
Content: notif.Content,
|
|
}))
|
|
}
|
|
|
|
if err = errors.Join(errs...); err != nil {
|
|
return err
|
|
}
|
|
|
|
user = targetUser
|
|
|
|
case actions.Message:
|
|
var platformID string
|
|
for _, chat := range promptCtx.Chats {
|
|
if action.Platform == chat.Platform {
|
|
platformID = chat.Identifier
|
|
}
|
|
}
|
|
|
|
if err := e.Chats[action.Platform].Send(ctx, platformID, action.Text); err != nil {
|
|
return err
|
|
}
|
|
|
|
case actions.Wait:
|
|
time.Sleep(time.Duration(action.Ms) * time.Millisecond)
|
|
|
|
case actions.UpdateLang:
|
|
user.Language = action.Lang
|
|
if err := e.Database.Users().Update(ctx, user); err != nil {
|
|
return err
|
|
}
|
|
|
|
case actions.UpdateTZ:
|
|
user.Timezone = action.TZ
|
|
if err := e.Database.Users().Update(ctx, user); err != nil {
|
|
return err
|
|
}
|
|
|
|
case actions.SetChat:
|
|
user.PreferredChat = action.Chat
|
|
if err := e.Database.Users().Update(ctx, user); err != nil {
|
|
return err
|
|
}
|
|
|
|
case actions.AddFact:
|
|
if err := e.Database.Facts().Add(ctx, user.ID, action.Value); err != nil {
|
|
return err
|
|
}
|
|
|
|
case actions.RemoveFact:
|
|
if err := e.Database.Facts().Delete(ctx, user.ID, action.Value); err != nil {
|
|
if errors.Is(err, database.ErrNotFound) {
|
|
continue
|
|
}
|
|
return err
|
|
}
|
|
|
|
case actions.AddContact:
|
|
contactUser, err := e.Database.Users().Get(ctx, uuid.MustParse(action.UUID), database.UserLookupByContactCode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = e.Database.Contacts().Add(ctx, &database.Contact{
|
|
OwnerID: user.ID,
|
|
TargetID: contactUser.ID,
|
|
Name: action.Name,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
case actions.AddNotification:
|
|
t, _ := jtime.ToUTC(action.Time, user.Timezone)
|
|
initiatorID := user.ID
|
|
if action.Target != "self" {
|
|
for _, contact := range promptCtx.Contacts {
|
|
initiatorID = contact.TargetID
|
|
}
|
|
}
|
|
|
|
err := e.Database.Notifications().Push(ctx, &database.Notification{
|
|
ID: uuid.New(),
|
|
UserID: user.ID,
|
|
InitiatorID: initiatorID,
|
|
ScheduledAt: t,
|
|
Content: action.Content,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
case actions.RemoveNotification:
|
|
err := e.Database.Notifications().Delete(ctx, uuid.MustParse(action.UUID))
|
|
if err != nil {
|
|
if errors.Is(err, database.ErrNotFound) {
|
|
continue
|
|
}
|
|
}
|
|
|
|
case actions.Search:
|
|
// TODO: currently not supported
|
|
}
|
|
|
|
err := e.Database.Actions().Log(ctx, &database.Action{
|
|
UserID: user.ID,
|
|
ExecutedAt: time.Now(),
|
|
Payload: actions.Raw(actionAny),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|