Skip to content

Commit

Permalink
Add backfill stress test support
Browse files Browse the repository at this point in the history
  • Loading branch information
hifi committed Aug 5, 2024
1 parent e9a030a commit 908ba98
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 60 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.db*
*.yaml
*.log
!example-config.yaml
67 changes: 67 additions & 0 deletions pkg/connector/backfill.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package connector

import (
"context"
"fmt"
"math/rand"
"time"

"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/event"
)

var _ bridgev2.BackfillingNetworkAPI = (*DummyClient)(nil)

func (dc *DummyClient) FetchMessages(ctx context.Context, fetchParams bridgev2.FetchMessagesParams) (resp *bridgev2.FetchMessagesResponse, err error) {
resp = &bridgev2.FetchMessagesResponse{}

if !dc.UserLogin.Bridge.Config.Backfill.Enabled {
return
} else if fetchParams.Portal == nil {
return
} else if time.Now().After(dc.Connector.Started.Add(dc.Connector.Config.Automation.Backfill.Timelimit)) {
return
}

tsMassage := -time.Second
if fetchParams.Forward {
tsMassage *= -1
}
nextTs := time.Now()
if fetchParams.AnchorMessage != nil {
nextTs = fetchParams.AnchorMessage.Timestamp.Add(tsMassage)
}

for i := 0; i < fetchParams.Count; i++ {
sender := stablePortalUserIDByIndex(fetchParams.Portal.ID, rand.Intn(dc.Connector.Config.Automation.Portals.Members))
_, err := dc.UserLogin.Bridge.GetGhostByID(ctx, sender)
if err != nil {
return nil, fmt.Errorf("failed to get ghost by id: %w", err)
}

msg := bridgev2.BackfillMessage{
ID: randomMessageID(),
ConvertedMessage: &bridgev2.ConvertedMessage{
Parts: []*bridgev2.ConvertedMessagePart{
{
Type: event.EventMessage,
Content: &event.MessageEventContent{
Body: string(sender),
},
},
},
},
Timestamp: nextTs,
Sender: bridgev2.EventSender{
Sender: sender,
},
}

resp.Messages = append(resp.Messages, &msg)
nextTs = msg.Timestamp.Add(tsMassage)
}

// always claim we have more until timelimit is hit
resp.HasMore = true
return
}
11 changes: 1 addition & 10 deletions pkg/connector/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package connector
import (
"context"
"fmt"
"strings"

"go.mau.fi/util/ptr"
"go.mau.fi/util/random"

"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/database"
Expand All @@ -16,14 +14,7 @@ import (

type DummyClient struct {
UserLogin *bridgev2.UserLogin
}

func randomPortalID() networkid.PortalID {
return networkid.PortalID(strings.ToLower(random.String(32)))
}

func randomUserID() networkid.UserID {
return networkid.UserID(strings.ToLower(random.String(32)))
Connector *DummyConnector
}

var _ bridgev2.NetworkAPI = (*DummyClient)(nil)
Expand Down
50 changes: 2 additions & 48 deletions pkg/connector/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ package connector
import (
"strconv"

"go.mau.fi/util/ptr"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/commands"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/event"
)

Expand All @@ -17,57 +14,14 @@ var AllCommands = []commands.CommandHandler{
}

var DummyHelpsection = commands.HelpSection{
Name: "Dummy",
Name: "Dummy",
Order: 99,
}

var NewRoomCommand = &commands.FullHandler{
Func: func(e *commands.Event) {
login := e.User.GetDefaultLogin()
portalID := randomPortalID()
portalKey := networkid.PortalKey{
ID: portalID,
Receiver: login.ID,
}

portal, err := e.Bridge.GetPortalByKey(e.Ctx, portalKey)
if err != nil {
e.Reply(err.Error())
return
}

chatInfo := bridgev2.ChatInfo{
Members: &bridgev2.ChatMemberList{
Members: []bridgev2.ChatMember{
{
EventSender: bridgev2.EventSender{
IsFromMe: true,
Sender: networkid.UserID(login.ID),
},
Membership: event.MembershipJoin,
PowerLevel: ptr.Ptr(100),
},
},
},
}

for i := 0; i < 10; i++ {
userID := randomUserID()
_, err := e.Bridge.GetGhostByID(e.Ctx, userID)
if err != nil {
e.Reply(err.Error())
return
}

chatInfo.Members.Members = append(chatInfo.Members.Members, bridgev2.ChatMember{
EventSender: bridgev2.EventSender{
Sender: userID,
},
Membership: event.MembershipJoin,
})
}

err = portal.CreateMatrixRoom(e.Ctx, login, &chatInfo)
portal, err := generatePortal(e.Ctx, e.Bridge, login, 1)
if err != nil {
e.Reply(err.Error())
return
Expand Down
103 changes: 101 additions & 2 deletions pkg/connector/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,37 @@ package connector

import (
"context"
_ "embed"
"time"

"go.mau.fi/util/configupgrade"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/commands"
"maunium.net/go/mautrix/bridgev2/database"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/id"
)

type DummyConnector struct {
br *bridgev2.Bridge
br *bridgev2.Bridge
Started time.Time

Config Config
}

type Config struct {
Automation struct {
OpenManagementRoom bool `yaml:"open_management_room"`
Login bool `yaml:"login"`
Portals struct {
Count int `yaml:"count"`
Members int `yaml:"members"`
Messages int `yaml:"messages"`
} `yaml:"portals"`
Backfill struct {
Timelimit time.Duration `yaml:"timelimit"`
} `yaml:"backfill"`
} `yaml:"automation"`
}

var _ bridgev2.NetworkConnector = (*DummyConnector)(nil)
Expand All @@ -20,7 +42,71 @@ func (dc *DummyConnector) Init(bridge *bridgev2.Bridge) {
bridge.Commands.(*commands.Processor).AddHandlers(AllCommands...)
}

func (dc *DummyConnector) startupAutomation(ctx context.Context) error {
portals, err := dc.br.DB.Portal.GetAll(ctx)
if err != nil {
return err
}

for userID, perm := range dc.br.Config.Permissions {
// only do things for admins
if !perm.Admin {
continue
}

log := dc.br.Log.With().Str("phase", "automation").Str("user_id", userID).Logger()
log.Info().Msg("Doing startup automation for user")

// FIXME: t check if this is a valid mxid and not a pattern
user, err := dc.br.GetUserByMXID(ctx, id.UserID(userID))
if err != nil {
log.Warn().Err(err).Msg("Couldn't find user by mxid, skipping")
continue
}

if dc.Config.Automation.OpenManagementRoom {
if roomID, err := user.GetManagementRoom(ctx); err != nil {
log.Warn().Err(err).Msg("Failed to open management room")
} else {
log.Info().Stringer("room_id", roomID).Msg("Opened management room")
}
}

// if we have a defaut login, do not create a new one
login := user.GetDefaultLogin()
if login == nil {
log.Info().Msg("Logging in to dummy network")
login, err = user.NewLogin(ctx, &database.UserLogin{
ID: networkid.UserLoginID(userID),
BridgeID: networkid.BridgeID(userID),
RemoteName: userID,
}, nil)
if err != nil {
return err
}
}

log.Info().Int("portals", dc.Config.Automation.Portals.Count).Msg("Ensuring portals")
for i := len(portals); i < dc.Config.Automation.Portals.Count; i++ {
_, err = generatePortal(ctx, dc.br, login, dc.Config.Automation.Portals.Members)
if err != nil {
return err
}
}
}

return nil
}

func (dc *DummyConnector) Start(ctx context.Context) error {
dc.Started = time.Now()

go func() {
err := dc.startupAutomation(context.Background())
if err != nil {
dc.br.Log.Err(err).Msg("Startup automation failed")
}
}()
return nil
}

Expand All @@ -42,13 +128,26 @@ func (dc *DummyConnector) GetDBMetaTypes() database.MetaTypes {
return database.MetaTypes{}
}

//go:embed example-config.yaml
var ExampleConfig string

func upgradeConfig(helper configupgrade.Helper) {
helper.Copy(configupgrade.Bool, "automation", "open_management_room")
helper.Copy(configupgrade.Bool, "automation", "login")
helper.Copy(configupgrade.Int, "automation", "portals", "count")
helper.Copy(configupgrade.Int, "automation", "portals", "members")
helper.Copy(configupgrade.Int, "automation", "portals", "messages")
helper.Copy(configupgrade.Str, "automation", "backfill", "timelimit")
}

func (dc *DummyConnector) GetConfig() (example string, data any, upgrader configupgrade.Upgrader) {
return "", nil, configupgrade.NoopUpgrader
return ExampleConfig, &dc.Config, configupgrade.SimpleUpgrader(upgradeConfig)
}

func (dc *DummyConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error {
login.Client = &DummyClient{
UserLogin: login,
Connector: dc,
}
return nil
}
Expand Down
20 changes: 20 additions & 0 deletions pkg/connector/example-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Automation options
automation:
# Open management room for admins
open_management_room: false
# Login admins automatically
login: false

# Portal automation for admins
portals:
# How many portals to create
count: 0
# How many members are initially in a portal
members: 0
# How many messages are initially sent to the portal
messages: 0

# Backfill automation
backfill:
# How long to do first startup infinite backfill
timelimit: 0s
Loading

0 comments on commit 908ba98

Please sign in to comment.