mirror of
https://mau.dev/mautrix/go.git
synced 2026-03-14 14:25:53 +01:00
bridgev2: move commands to subpackage
This commit is contained in:
parent
46b4ab4c9d
commit
5782506e9e
14 changed files with 182 additions and 152 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
},
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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.",
|
||||
},
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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.",
|
||||
},
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -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_>",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue