bridgev2: move commands to subpackage

This commit is contained in:
Tulir Asokan 2024-06-29 11:50:43 +03:00
commit 5782506e9e
14 changed files with 182 additions and 152 deletions

View file

@ -24,6 +24,10 @@ import (
var ErrNotLoggedIn = errors.New("not logged in")
type CommandProcessor interface {
Handle(ctx context.Context, roomID id.RoomID, eventID id.EventID, user *User, message string, replyTo id.EventID)
}
type Bridge struct {
ID networkid.BridgeID
DB *database.Database
@ -32,7 +36,7 @@ type Bridge struct {
Matrix MatrixConnector
Bot MatrixAPI
Network NetworkConnector
Commands *CommandProcessor
Commands CommandProcessor
Config *bridgeconfig.BridgeConfig
DisappearLoop *DisappearLoop
@ -45,7 +49,15 @@ type Bridge struct {
cacheLock sync.Mutex
}
func NewBridge(bridgeID networkid.BridgeID, db *dbutil.Database, log zerolog.Logger, cfg *bridgeconfig.BridgeConfig, matrix MatrixConnector, network NetworkConnector) *Bridge {
func NewBridge(
bridgeID networkid.BridgeID,
db *dbutil.Database,
log zerolog.Logger,
cfg *bridgeconfig.BridgeConfig,
matrix MatrixConnector,
network NetworkConnector,
newCommandProcessor func(*Bridge) CommandProcessor,
) *Bridge {
br := &Bridge{
ID: bridgeID,
DB: database.New(bridgeID, db),
@ -64,7 +76,7 @@ func NewBridge(bridgeID networkid.BridgeID, db *dbutil.Database, log zerolog.Log
if br.Config == nil {
br.Config = &bridgeconfig.BridgeConfig{CommandPrefix: "!bridge"}
}
br.Commands = NewProcessor(br)
br.Commands = newCommandProcessor(br)
br.Matrix.Init(br)
br.Bot = br.Matrix.BotIntent()
br.Network.Init(br)

View file

@ -1,41 +0,0 @@
// Copyright (c) 2022 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
var CommandHelp = &FullHandler{
Func: func(ce *CommandEvent) {
ce.Reply(FormatHelp(ce))
},
Name: "help",
Help: HelpMeta{
Section: HelpSectionGeneral,
Description: "Show this help message.",
},
}
var CommandCancel = &FullHandler{
Func: func(ce *CommandEvent) {
state := ce.User.CommandState.Swap(nil)
if state != nil {
action := state.Action
if action == "" {
action = "Unknown action"
}
if state.Cancel != nil {
state.Cancel()
}
ce.Reply("%s cancelled.", action)
} else {
ce.Reply("No ongoing command.")
}
},
Name: "cancel",
Help: HelpMeta{
Section: HelpSectionGeneral,
Description: "Cancel an ongoing action.",
},
}

View file

@ -4,22 +4,23 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
package commands
import (
"strings"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
)
var CommandRegisterPush = &FullHandler{
Func: func(ce *CommandEvent) {
Func: func(ce *Event) {
if len(ce.Args) < 3 {
ce.Reply("Usage: `$cmdprefix debug-register-push <login ID> <push type> <push token>`\n\nYour logins:\n\n%s", ce.User.GetFormattedUserLogins())
return
}
pushType := PushTypeFromString(ce.Args[1])
if pushType == PushTypeUnknown {
pushType := bridgev2.PushTypeFromString(ce.Args[1])
if pushType == bridgev2.PushTypeUnknown {
ce.Reply("Unknown push type `%s`. Allowed types: `web`, `apns`, `fcm`", ce.Args[1])
return
}
@ -28,7 +29,7 @@ var CommandRegisterPush = &FullHandler{
ce.Reply("Login `%s` not found", ce.Args[0])
return
}
pushable, ok := login.Client.(PushableNetworkAPI)
pushable, ok := login.Client.(bridgev2.PushableNetworkAPI)
if !ok {
ce.Reply("This network connector does not support push registration")
return

View file

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
package commands
import (
"context"
@ -14,22 +14,24 @@ import (
"github.com/rs/zerolog"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/format"
"maunium.net/go/mautrix/id"
)
// CommandEvent stores all data which might be used to handle commands
type CommandEvent struct {
Bot MatrixAPI
Bridge *Bridge
Portal *Portal
Processor *CommandProcessor
// Event stores all data which might be used to handle commands
type Event struct {
Bot bridgev2.MatrixAPI
Bridge *bridgev2.Bridge
Portal *bridgev2.Portal
Processor *Processor
Handler MinimalCommandHandler
RoomID id.RoomID
EventID id.EventID
User *User
User *bridgev2.User
Command string
Args []string
RawArgs string
@ -39,7 +41,7 @@ type CommandEvent struct {
}
// Reply sends a reply to command as notice, with optional string formatting and automatic $cmdprefix replacement.
func (ce *CommandEvent) Reply(msg string, args ...any) {
func (ce *Event) Reply(msg string, args ...any) {
msg = strings.ReplaceAll(msg, "$cmdprefix ", ce.Bridge.Config.CommandPrefix+" ")
if len(args) > 0 {
msg = fmt.Sprintf(msg, args...)
@ -49,7 +51,7 @@ func (ce *CommandEvent) Reply(msg string, args ...any) {
// ReplyAdvanced sends a reply to command as notice. It allows using HTML and disabling markdown,
// but doesn't have built-in string formatting.
func (ce *CommandEvent) ReplyAdvanced(msg string, allowMarkdown, allowHTML bool) {
func (ce *Event) ReplyAdvanced(msg string, allowMarkdown, allowHTML bool) {
content := format.RenderMarkdown(msg, allowMarkdown, allowHTML)
content.MsgType = event.MsgNotice
_, err := ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventMessage, &event.Content{Parsed: content}, time.Now())
@ -59,7 +61,7 @@ func (ce *CommandEvent) ReplyAdvanced(msg string, allowMarkdown, allowHTML bool)
}
// React sends a reaction to the command.
func (ce *CommandEvent) React(key string) {
func (ce *Event) React(key string) {
_, err := ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventReaction, &event.Content{
Parsed: &event.ReactionEventContent{
RelatesTo: event.RelatesTo{
@ -75,7 +77,7 @@ func (ce *CommandEvent) React(key string) {
}
// Redact redacts the command.
func (ce *CommandEvent) Redact(req ...mautrix.ReqRedact) {
func (ce *Event) Redact(req ...mautrix.ReqRedact) {
_, err := ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventRedaction, &event.Content{
Parsed: &event.RedactionEventContent{
Redacts: ce.EventID,
@ -87,7 +89,7 @@ func (ce *CommandEvent) Redact(req ...mautrix.ReqRedact) {
}
// MarkRead marks the command event as read.
func (ce *CommandEvent) MarkRead() {
func (ce *Event) MarkRead() {
// TODO
//err := ce.Bot.SendReceipt(ce.Ctx, ce.RoomID, ce.EventID, event.ReceiptTypeRead, nil)
//if err != nil {

View file

@ -4,19 +4,19 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
package commands
import (
"maunium.net/go/mautrix/event"
)
type MinimalCommandHandler interface {
Run(*CommandEvent)
Run(*Event)
}
type MinimalCommandHandlerFunc func(*CommandEvent)
type MinimalCommandHandlerFunc func(*Event)
func (mhf MinimalCommandHandlerFunc) Run(ce *CommandEvent) {
func (mhf MinimalCommandHandlerFunc) Run(ce *Event) {
mhf(ce)
}
@ -38,7 +38,7 @@ type AliasedCommandHandler interface {
}
type FullHandler struct {
Func func(*CommandEvent)
Func func(*Event)
Name string
Aliases []string
@ -64,12 +64,12 @@ func (fh *FullHandler) GetAliases() []string {
return fh.Aliases
}
func (fh *FullHandler) ShowInHelp(ce *CommandEvent) bool {
func (fh *FullHandler) ShowInHelp(ce *Event) bool {
return true
//return !fh.RequiresAdmin || ce.User.GetPermissionLevel() >= bridgeconfig.PermissionLevelAdmin
}
func (fh *FullHandler) userHasRoomPermission(ce *CommandEvent) bool {
func (fh *FullHandler) userHasRoomPermission(ce *Event) bool {
return true
//levels, err := ce.MainIntent().PowerLevels(ce.Ctx, ce.RoomID)
//if err != nil {
@ -80,7 +80,7 @@ func (fh *FullHandler) userHasRoomPermission(ce *CommandEvent) bool {
//return levels.GetUserLevel(ce.User.GetMXID()) >= levels.GetEventLevel(fh.RequiresEventLevel)
}
func (fh *FullHandler) Run(ce *CommandEvent) {
func (fh *FullHandler) Run(ce *Event) {
//if fh.RequiresAdmin && ce.User.GetPermissionLevel() < bridgeconfig.PermissionLevelAdmin {
// ce.Reply("That command is limited to bridge administrators.")
//} else if fh.RequiresEventLevel.Type != "" && ce.User.GetPermissionLevel() < bridgeconfig.PermissionLevelAdmin && !fh.userHasRoomPermission(ce) {

View file

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
package commands
import (
"fmt"
@ -15,7 +15,7 @@ import (
type HelpfulHandler interface {
CommandHandler
GetHelp() HelpMeta
ShowInHelp(*CommandEvent) bool
ShowInHelp(*Event) bool
}
type HelpSection struct {
@ -78,7 +78,7 @@ func (h helpMetaList) Swap(i, j int) {
var _ sort.Interface = (helpSectionList)(nil)
var _ sort.Interface = (helpMetaList)(nil)
func FormatHelp(ce *CommandEvent) string {
func FormatHelp(ce *Event) string {
sections := make(map[HelpSection]helpMetaList)
for _, handler := range ce.Processor.handlers {
helpfulHandler, ok := handler.(HelpfulHandler)
@ -128,3 +128,14 @@ func FormatHelp(ce *CommandEvent) string {
}
return output.String()
}
var CommandHelp = &FullHandler{
Func: func(ce *Event) {
ce.Reply(FormatHelp(ce))
},
Name: "help",
Help: HelpMeta{
Section: HelpSectionGeneral,
Description: "Show this help message.",
},
}

View file

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
package commands
import (
"context"
@ -18,6 +18,8 @@ import (
"github.com/skip2/go-qrcode"
"golang.org/x/net/html"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
@ -33,7 +35,7 @@ var CommandLogin = &FullHandler{
},
}
func formatFlowsReply(flows []LoginFlow) string {
func formatFlowsReply(flows []bridgev2.LoginFlow) string {
var buf strings.Builder
for _, flow := range flows {
_, _ = fmt.Fprintf(&buf, "* `%s` - %s\n", flow.ID, flow.Description)
@ -41,7 +43,7 @@ func formatFlowsReply(flows []LoginFlow) string {
return buf.String()
}
func fnLogin(ce *CommandEvent) {
func fnLogin(ce *Event) {
flows := ce.Bridge.Network.GetLoginFlows()
var chosenFlowID string
if len(ce.Args) > 0 {
@ -77,14 +79,14 @@ func fnLogin(ce *CommandEvent) {
}
type userInputLoginCommandState struct {
Login LoginProcessUserInput
Login bridgev2.LoginProcessUserInput
Data map[string]string
RemainingFields []LoginInputDataField
RemainingFields []bridgev2.LoginInputDataField
}
func (uilcs *userInputLoginCommandState) promptNext(ce *CommandEvent) {
func (uilcs *userInputLoginCommandState) promptNext(ce *Event) {
// TODO reply prompting field
ce.User.CommandState.Store(&CommandState{
StoreCommandState(ce.User, &CommandState{
Next: MinimalCommandHandlerFunc(uilcs.submitNext),
Action: "Login",
Meta: uilcs,
@ -92,7 +94,7 @@ func (uilcs *userInputLoginCommandState) promptNext(ce *CommandEvent) {
})
}
func (uilcs *userInputLoginCommandState) submitNext(ce *CommandEvent) {
func (uilcs *userInputLoginCommandState) submitNext(ce *Event) {
field := uilcs.RemainingFields[0]
field.FillDefaultValidate()
var err error
@ -105,7 +107,7 @@ func (uilcs *userInputLoginCommandState) submitNext(ce *CommandEvent) {
uilcs.promptNext(ce)
return
}
ce.User.CommandState.Store(nil)
StoreCommandState(ce.User, nil)
if nextStep, err := uilcs.Login.SubmitUserInput(ce.Ctx, uilcs.Data); err != nil {
ce.Reply("Failed to submit input: %v", err)
} else {
@ -115,7 +117,7 @@ func (uilcs *userInputLoginCommandState) submitNext(ce *CommandEvent) {
const qrSizePx = 512
func sendQR(ce *CommandEvent, qr string, prevEventID *id.EventID) error {
func sendQR(ce *Event, qr string, prevEventID *id.EventID) error {
qrData, err := qrcode.Encode(qr, qrcode.Low, qrSizePx)
if err != nil {
return fmt.Errorf("failed to encode QR code: %w", err)
@ -153,25 +155,25 @@ const (
contextKeyPrevEventID contextKey = iota
)
func doLoginDisplayAndWait(ce *CommandEvent, login LoginProcessDisplayAndWait, step *LoginStep) {
func doLoginDisplayAndWait(ce *Event, login bridgev2.LoginProcessDisplayAndWait, step *bridgev2.LoginStep) {
prevEvent, ok := ce.Ctx.Value(contextKeyPrevEventID).(*id.EventID)
if !ok {
prevEvent = new(id.EventID)
ce.Ctx = context.WithValue(ce.Ctx, contextKeyPrevEventID, prevEvent)
}
switch step.DisplayAndWaitParams.Type {
case LoginDisplayTypeQR:
case bridgev2.LoginDisplayTypeQR:
err := sendQR(ce, step.DisplayAndWaitParams.Data, prevEvent)
if err != nil {
ce.Reply("Failed to send QR code: %v", err)
login.Cancel()
return
}
case LoginDisplayTypeEmoji:
case bridgev2.LoginDisplayTypeEmoji:
ce.ReplyAdvanced(step.DisplayAndWaitParams.Data, false, false)
case LoginDisplayTypeCode:
case bridgev2.LoginDisplayTypeCode:
ce.ReplyAdvanced(fmt.Sprintf("<code>%s</code>", html.EscapeString(step.DisplayAndWaitParams.Data)), false, true)
case LoginDisplayTypeNothing:
case bridgev2.LoginDisplayTypeNothing:
// Do nothing
default:
ce.Reply("Unsupported display type %q", step.DisplayAndWaitParams.Type)
@ -196,12 +198,12 @@ func doLoginDisplayAndWait(ce *CommandEvent, login LoginProcessDisplayAndWait, s
}
type cookieLoginCommandState struct {
Login LoginProcessCookies
Data *LoginCookiesParams
Login bridgev2.LoginProcessCookies
Data *bridgev2.LoginCookiesParams
}
func (clcs *cookieLoginCommandState) prompt(ce *CommandEvent) {
ce.User.CommandState.Store(&CommandState{
func (clcs *cookieLoginCommandState) prompt(ce *Event) {
StoreCommandState(ce.User, &CommandState{
Next: MinimalCommandHandlerFunc(clcs.submit),
Action: "Login",
Meta: clcs,
@ -220,7 +222,7 @@ func missingKeys(required []string, data map[string]string) (missing []string) {
return
}
func (clcs *cookieLoginCommandState) submit(ce *CommandEvent) {
func (clcs *cookieLoginCommandState) submit(ce *Event) {
ce.Redact()
cookies := make(map[string]string)
@ -260,7 +262,7 @@ func (clcs *cookieLoginCommandState) submit(ce *CommandEvent) {
ce.Reply("Missing required special keys: %+v", missingSpecial)
return
}
ce.User.CommandState.Store(nil)
StoreCommandState(ce.User, nil)
nextStep, err := clcs.Login.SubmitCookies(ce.Ctx, cookies)
if err != nil {
ce.Reply("Login failed: %v", err)
@ -268,24 +270,24 @@ func (clcs *cookieLoginCommandState) submit(ce *CommandEvent) {
doLoginStep(ce, clcs.Login, nextStep)
}
func doLoginStep(ce *CommandEvent, login LoginProcess, step *LoginStep) {
func doLoginStep(ce *Event, login bridgev2.LoginProcess, step *bridgev2.LoginStep) {
ce.Reply(step.Instructions)
switch step.Type {
case LoginStepTypeDisplayAndWait:
doLoginDisplayAndWait(ce, login.(LoginProcessDisplayAndWait), step)
case LoginStepTypeCookies:
case bridgev2.LoginStepTypeDisplayAndWait:
doLoginDisplayAndWait(ce, login.(bridgev2.LoginProcessDisplayAndWait), step)
case bridgev2.LoginStepTypeCookies:
(&cookieLoginCommandState{
Login: login.(LoginProcessCookies),
Login: login.(bridgev2.LoginProcessCookies),
Data: step.CookiesParams,
}).prompt(ce)
case LoginStepTypeUserInput:
case bridgev2.LoginStepTypeUserInput:
(&userInputLoginCommandState{
Login: login.(LoginProcessUserInput),
Login: login.(bridgev2.LoginProcessUserInput),
RemainingFields: step.UserInputParams.Fields,
Data: make(map[string]string),
}).promptNext(ce)
case LoginStepTypeComplete:
case bridgev2.LoginStepTypeComplete:
// Nothing to do other than instructions
default:
panic(fmt.Errorf("unknown login step type %q", step.Type))
@ -302,7 +304,7 @@ var CommandLogout = &FullHandler{
},
}
func fnLogout(ce *CommandEvent) {
func fnLogout(ce *Event) {
if len(ce.Args) == 0 {
ce.Reply("Usage: `$cmdprefix logout <login ID>`\n\nYour logins:\n\n%s", ce.User.GetFormattedUserLogins())
return
@ -328,7 +330,7 @@ var CommandSetPreferredLogin = &FullHandler{
RequiresPortal: true,
}
func fnSetPreferredLogin(ce *CommandEvent) {
func fnSetPreferredLogin(ce *Event) {
if len(ce.Args) == 0 {
ce.Reply("Usage: `$cmdprefix set-preferred-login <login ID>`\n\nYour logins:\n\n%s", ce.User.GetFormattedUserLogins())
return

View file

@ -4,32 +4,36 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
package commands
import (
"context"
"fmt"
"runtime/debug"
"strings"
"sync/atomic"
"unsafe"
"github.com/rs/zerolog"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridge/status"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
)
type CommandProcessor struct {
bridge *Bridge
type Processor struct {
bridge *bridgev2.Bridge
log *zerolog.Logger
handlers map[string]CommandHandler
aliases map[string]string
}
// NewProcessor creates a CommandProcessor
func NewProcessor(bridge *Bridge) *CommandProcessor {
proc := &CommandProcessor{
// NewProcessor creates a Processor
func NewProcessor(bridge *bridgev2.Bridge) bridgev2.CommandProcessor {
proc := &Processor{
bridge: bridge,
log: &bridge.Log,
@ -45,13 +49,13 @@ func NewProcessor(bridge *Bridge) *CommandProcessor {
return proc
}
func (proc *CommandProcessor) AddHandlers(handlers ...CommandHandler) {
func (proc *Processor) AddHandlers(handlers ...CommandHandler) {
for _, handler := range handlers {
proc.AddHandler(handler)
}
}
func (proc *CommandProcessor) AddHandler(handler CommandHandler) {
func (proc *Processor) AddHandler(handler CommandHandler) {
proc.handlers[handler.GetName()] = handler
aliased, ok := handler.(AliasedCommandHandler)
if ok {
@ -62,15 +66,15 @@ func (proc *CommandProcessor) AddHandler(handler CommandHandler) {
}
// Handle handles messages to the bridge
func (proc *CommandProcessor) Handle(ctx context.Context, roomID id.RoomID, eventID id.EventID, user *User, message string, replyTo id.EventID) {
func (proc *Processor) Handle(ctx context.Context, roomID id.RoomID, eventID id.EventID, user *bridgev2.User, message string, replyTo id.EventID) {
defer func() {
statusInfo := &MessageStatusEventInfo{
statusInfo := &bridgev2.MessageStatusEventInfo{
RoomID: roomID,
EventID: eventID,
EventType: event.EventMessage,
Sender: user.MXID,
}
ms := MessageStatus{
ms := bridgev2.MessageStatus{
Step: status.MsgStepCommand,
Status: event.MessageStatusSuccess,
}
@ -101,7 +105,7 @@ func (proc *CommandProcessor) Handle(ctx context.Context, roomID id.RoomID, even
if err != nil {
// :(
}
ce := &CommandEvent{
ce := &Event{
Bot: proc.bridge.Bot,
Bridge: proc.bridge,
Portal: portal,
@ -124,7 +128,7 @@ func (proc *CommandProcessor) Handle(ctx context.Context, roomID id.RoomID, even
var handler MinimalCommandHandler
handler, ok = proc.handlers[realCommand]
if !ok {
state := ce.User.CommandState.Load()
state := LoadCommandState(ce.User)
if state != nil && state.Next != nil {
ce.Command = ""
ce.RawArgs = message
@ -149,3 +153,38 @@ func (proc *CommandProcessor) Handle(ctx context.Context, roomID id.RoomID, even
handler.Run(ce)
}
}
func LoadCommandState(user *bridgev2.User) *CommandState {
return (*CommandState)(atomic.LoadPointer(&user.CommandState))
}
func StoreCommandState(user *bridgev2.User, cs *CommandState) {
atomic.StorePointer(&user.CommandState, unsafe.Pointer(cs))
}
func SwapCommandState(user *bridgev2.User, cs *CommandState) *CommandState {
return (*CommandState)(atomic.SwapPointer(&user.CommandState, unsafe.Pointer(cs)))
}
var CommandCancel = &FullHandler{
Func: func(ce *Event) {
state := SwapCommandState(ce.User, nil)
if state != nil {
action := state.Action
if action == "" {
action = "Unknown action"
}
if state.Cancel != nil {
state.Cancel()
}
ce.Reply("%s cancelled.", action)
} else {
ce.Reply("No ongoing command.")
}
},
Name: "cancel",
Help: HelpMeta{
Section: HelpSectionGeneral,
Description: "Cancel an ongoing action.",
},
}

View file

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package bridgev2
package commands
import (
"fmt"
@ -13,6 +13,8 @@ import (
"golang.org/x/net/html"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/id"
)
@ -39,7 +41,7 @@ var CommandStartChat = &FullHandler{
RequiresLogin: true,
}
func getClientForStartingChat[T IdentifierResolvingNetworkAPI](ce *CommandEvent, thing string) (*UserLogin, T, []string) {
func getClientForStartingChat[T bridgev2.IdentifierResolvingNetworkAPI](ce *Event, thing string) (*bridgev2.UserLogin, T, []string) {
remainingArgs := ce.Args[1:]
login := ce.Bridge.GetCachedUserLoginByID(networkid.UserLoginID(ce.Args[0]))
if login == nil || login.UserMXID != ce.User.MXID {
@ -53,8 +55,8 @@ func getClientForStartingChat[T IdentifierResolvingNetworkAPI](ce *CommandEvent,
return login, api, remainingArgs
}
func fnResolveIdentifier(ce *CommandEvent) {
login, api, identifierParts := getClientForStartingChat[IdentifierResolvingNetworkAPI](ce, "resolving identifiers")
func fnResolveIdentifier(ce *Event) {
login, api, identifierParts := getClientForStartingChat[bridgev2.IdentifierResolvingNetworkAPI](ce, "resolving identifiers")
if api == nil {
return
}
@ -125,7 +127,7 @@ func fnResolveIdentifier(ce *CommandEvent) {
}
var CommandDeletePortal = &FullHandler{
Func: func(ce *CommandEvent) {
Func: func(ce *Event) {
err := ce.Portal.Delete(ce.Ctx)
if err != nil {
ce.Reply("Failed to delete portal: %v", err)

View file

@ -9,12 +9,12 @@ package matrix
import (
"strconv"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/commands"
"maunium.net/go/mautrix/id"
)
var CommandDiscardMegolmSession = &bridgev2.FullHandler{
Func: func(ce *bridgev2.CommandEvent) {
var CommandDiscardMegolmSession = &commands.FullHandler{
Func: func(ce *commands.Event) {
matrix := ce.Bridge.Matrix.(*Connector)
if matrix.Crypto == nil {
ce.Reply("This bridge instance doesn't have end-to-bridge encryption enabled")
@ -25,14 +25,14 @@ var CommandDiscardMegolmSession = &bridgev2.FullHandler{
},
Name: "discard-megolm-session",
Aliases: []string{"discard-session"},
Help: bridgev2.HelpMeta{
Section: bridgev2.HelpSectionAdmin,
Help: commands.HelpMeta{
Section: commands.HelpSectionAdmin,
Description: "Discard the Megolm session in the room",
},
RequiresAdmin: true,
}
func fnSetPowerLevel(ce *bridgev2.CommandEvent) {
func fnSetPowerLevel(ce *commands.Event) {
var level int
var userID id.UserID
var err error
@ -65,12 +65,12 @@ func fnSetPowerLevel(ce *bridgev2.CommandEvent) {
}
}
var CommandSetPowerLevel = &bridgev2.FullHandler{
var CommandSetPowerLevel = &commands.FullHandler{
Func: fnSetPowerLevel,
Name: "set-pl",
Aliases: []string{"set-power-level"},
Help: bridgev2.HelpMeta{
Section: bridgev2.HelpSectionAdmin,
Help: commands.HelpMeta{
Section: commands.HelpSectionAdmin,
Description: "Change the power level in a portal room.",
Args: "[_user ID_] <_power level_>",
},

View file

@ -7,21 +7,21 @@
package matrix
import (
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/commands"
)
var CommandLoginMatrix = &bridgev2.FullHandler{
var CommandLoginMatrix = &commands.FullHandler{
Func: fnLoginMatrix,
Name: "login-matrix",
Help: bridgev2.HelpMeta{
Section: bridgev2.HelpSectionAuth,
Help: commands.HelpMeta{
Section: commands.HelpSectionAuth,
Description: "Enable double puppeting.",
Args: "<_access token_>",
},
RequiresLogin: true,
}
func fnLoginMatrix(ce *bridgev2.CommandEvent) {
func fnLoginMatrix(ce *commands.Event) {
if len(ce.Args) == 0 {
ce.Reply("**Usage:** `login-matrix <access token>`")
return
@ -34,16 +34,16 @@ func fnLoginMatrix(ce *bridgev2.CommandEvent) {
}
}
var CommandPingMatrix = &bridgev2.FullHandler{
var CommandPingMatrix = &commands.FullHandler{
Func: fnPingMatrix,
Name: "ping-matrix",
Help: bridgev2.HelpMeta{
Section: bridgev2.HelpSectionAuth,
Help: commands.HelpMeta{
Section: commands.HelpSectionAuth,
Description: "Ping the Matrix server with the double puppet.",
},
}
func fnPingMatrix(ce *bridgev2.CommandEvent) {
func fnPingMatrix(ce *commands.Event) {
intent := ce.User.DoublePuppet(ce.Ctx)
if intent == nil {
ce.Reply("You don't have double puppeting enabled.")
@ -62,17 +62,17 @@ func fnPingMatrix(ce *bridgev2.CommandEvent) {
}
}
var CommandLogoutMatrix = &bridgev2.FullHandler{
var CommandLogoutMatrix = &commands.FullHandler{
Func: fnLogoutMatrix,
Name: "logout-matrix",
Help: bridgev2.HelpMeta{
Section: bridgev2.HelpSectionAuth,
Help: commands.HelpMeta{
Section: commands.HelpSectionAuth,
Description: "Disable double puppeting.",
},
RequiresLogin: true,
}
func fnLogoutMatrix(ce *bridgev2.CommandEvent) {
func fnLogoutMatrix(ce *commands.Event) {
if ce.User.AccessToken == "" {
ce.Reply("You don't have double puppeting enabled.")
return

View file

@ -26,6 +26,7 @@ import (
"maunium.net/go/mautrix/bridge/status"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
"maunium.net/go/mautrix/bridgev2/commands"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
@ -117,7 +118,7 @@ func (br *Connector) Init(bridge *bridgev2.Bridge) {
br.EventProcessor.On(event.EphemeralEventTyping, br.handleEphemeralEvent)
br.Bot = br.AS.BotIntent()
br.Crypto = NewCryptoHelper(br)
br.Bridge.Commands.AddHandlers(
br.Bridge.Commands.(*commands.Processor).AddHandlers(
CommandDiscardMegolmSession, CommandSetPowerLevel,
CommandLoginMatrix, CommandPingMatrix, CommandLogoutMatrix,
)

View file

@ -31,6 +31,7 @@ import (
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
"maunium.net/go/mautrix/bridgev2/commands"
"maunium.net/go/mautrix/bridgev2/matrix"
)
@ -226,15 +227,15 @@ func (br *BridgeMain) Init() {
br.initDB()
br.Matrix = matrix.NewConnector(br.Config)
br.Matrix.IgnoreUnsupportedServer = *ignoreUnsupportedServer
br.Bridge = bridgev2.NewBridge("", br.DB, *br.Log, &br.Config.Bridge, br.Matrix, br.Connector)
br.Bridge = bridgev2.NewBridge("", br.DB, *br.Log, &br.Config.Bridge, br.Matrix, br.Connector, commands.NewProcessor)
br.Matrix.AS.DoublePuppetValue = br.Name
br.Bridge.Commands.AddHandler(&bridgev2.FullHandler{
Func: func(ce *bridgev2.CommandEvent) {
br.Bridge.Commands.(*commands.Processor).AddHandler(&commands.FullHandler{
Func: func(ce *commands.Event) {
ce.Reply("[%s](%s) %s (%s)", br.Name, br.URL, br.LinkifiedVersion, br.BuildTime.Format(time.RFC1123))
},
Name: "version",
Help: bridgev2.HelpMeta{
Section: bridgev2.HelpSectionGeneral,
Help: commands.HelpMeta{
Section: commands.HelpSectionGeneral,
Description: "Get the bridge version.",
},
})

View file

@ -11,7 +11,7 @@ import (
"fmt"
"strings"
"sync"
"sync/atomic"
"unsafe"
"github.com/rs/zerolog"
"golang.org/x/exp/maps"
@ -27,7 +27,7 @@ type User struct {
Bridge *Bridge
Log zerolog.Logger
CommandState atomic.Pointer[CommandState]
CommandState unsafe.Pointer
doublePuppetIntent MatrixAPI
doublePuppetInitialized bool