bridgev2

package
v0.19.0-beta.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2024 License: MPL-2.0 Imports: 30 Imported by: 21

Documentation

Index

Constants

View Source
const PortalEventBuffer = 64

Variables

View Source
var (
	// Deprecated: this should be used as a placeholder that needs to be fixed
	HelpSectionUnclassified = HelpSection{"Unclassified", -1}

	HelpSectionGeneral = HelpSection{"General", 0}
	HelpSectionAuth    = HelpSection{"Authentication", 10}
	HelpSectionAdmin   = HelpSection{"Administration", 50}
)
View Source
var (
	ErrNoPortal                        error = WrapErrorInStatus(errors.New("room is not a portal")).WithIsCertain(true).WithSendNotice(false)
	ErrIgnoringReactionFromRelayedUser error = WrapErrorInStatus(errors.New("ignoring reaction event from relayed user")).WithIsCertain(true).WithSendNotice(false)
	ErrUnexpectedParsedContentType     error = WrapErrorInStatus(errors.New("unexpected parsed content type")).WithErrorAsMessage().WithIsCertain(true).WithSendNotice(true)
	ErrDatabaseError                   error = WrapErrorInStatus(errors.New("database error")).WithMessage("internal database error").WithIsCertain(true).WithSendNotice(true)
	ErrTargetMessageNotFound           error = WrapErrorInStatus(errors.New("target message not found")).WithErrorAsMessage().WithIsCertain(true).WithSendNotice(false)
)
View Source
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 Source
var CommandHelp = &FullHandler{
	Func: func(ce *CommandEvent) {
		ce.Reply(FormatHelp(ce))
	},
	Name: "help",
	Help: HelpMeta{
		Section:     HelpSectionGeneral,
		Description: "Show this help message.",
	},
}
View Source
var CommandLogin = &FullHandler{
	Func: fnLogin,
	Name: "login",
	Help: HelpMeta{
		Section:     HelpSectionAuth,
		Description: "Log into the bridge",
		Args:        "[_flow ID_]",
	},
}
View Source
var CommandLogout = &FullHandler{
	Func: fnLogout,
	Name: "logout",
	Help: HelpMeta{
		Section:     HelpSectionAuth,
		Description: "Log out of the bridge",
		Args:        "<_login ID_>",
	},
}
View Source
var CommandSetPreferredLogin = &FullHandler{
	Func:    fnSetPreferredLogin,
	Name:    "set-preferred-login",
	Aliases: []string{"prefer"},
	Help: HelpMeta{
		Section:     HelpSectionAuth,
		Description: "Set the preferred login ID for sending messages to this portal (only relevant when logged into multiple accounts via the bridge)",
		Args:        "<_login ID_>",
	},
	RequiresPortal: true,
}
View Source
var ErrNotLoggedIn = errors.New("not logged in")

Functions

func FormatHelp

func FormatHelp(ce *CommandEvent) string

Types

type AliasedCommandHandler

type AliasedCommandHandler interface {
	CommandHandler
	GetAliases() []string
}

type Avatar

type Avatar struct {
	ID     networkid.AvatarID
	Get    func(ctx context.Context) ([]byte, error)
	Remove bool
}

func (*Avatar) Reupload

func (a *Avatar) Reupload(ctx context.Context, intent MatrixAPI, currentHash [32]byte) (id.ContentURIString, [32]byte, error)

type Bridge

type Bridge struct {
	ID  networkid.BridgeID
	DB  *database.Database
	Log zerolog.Logger

	Matrix   MatrixConnector
	Bot      MatrixAPI
	Network  NetworkConnector
	Commands *CommandProcessor
	Config   *bridgeconfig.BridgeConfig
	// contains filtered or unexported fields
}

func NewBridge

func NewBridge(bridgeID networkid.BridgeID, db *dbutil.Database, log zerolog.Logger, cfg *bridgeconfig.BridgeConfig, matrix MatrixConnector, network NetworkConnector) *Bridge

func (*Bridge) GetAllUserLogins

func (br *Bridge) GetAllUserLogins(ctx context.Context) ([]*UserLogin, error)

func (*Bridge) GetCachedUserLoginByID

func (br *Bridge) GetCachedUserLoginByID(id networkid.UserLoginID) *UserLogin

func (*Bridge) GetExistingPortalByID

func (br *Bridge) GetExistingPortalByID(ctx context.Context, id networkid.PortalKey) (*Portal, error)

func (*Bridge) GetExistingUserByMXID

func (br *Bridge) GetExistingUserByMXID(ctx context.Context, userID id.UserID) (*User, error)

func (*Bridge) GetGhostByID

func (br *Bridge) GetGhostByID(ctx context.Context, id networkid.UserID) (*Ghost, error)

func (*Bridge) GetGhostByMXID

func (br *Bridge) GetGhostByMXID(ctx context.Context, mxid id.UserID) (*Ghost, error)

func (*Bridge) GetPortalByID

func (br *Bridge) GetPortalByID(ctx context.Context, id networkid.PortalKey) (*Portal, error)

func (*Bridge) GetPortalByMXID

func (br *Bridge) GetPortalByMXID(ctx context.Context, mxid id.RoomID) (*Portal, error)

func (*Bridge) GetUserByMXID

func (br *Bridge) GetUserByMXID(ctx context.Context, userID id.UserID) (*User, error)

func (*Bridge) GetUserLoginsInPortal

func (br *Bridge) GetUserLoginsInPortal(ctx context.Context, portal networkid.PortalKey) ([]*UserLogin, error)

func (*Bridge) NewBridgeStateQueue

func (br *Bridge) NewBridgeStateQueue(user status.BridgeStateFiller) *BridgeStateQueue

func (*Bridge) QueueMatrixEvent

func (br *Bridge) QueueMatrixEvent(ctx context.Context, evt *event.Event)

func (*Bridge) QueueRemoteEvent

func (br *Bridge) QueueRemoteEvent(login *UserLogin, evt RemoteEvent)

func (*Bridge) SendGlobalBridgeState

func (br *Bridge) SendGlobalBridgeState(state status.BridgeState)

func (*Bridge) Start

func (br *Bridge) Start() error

type BridgeName

type BridgeName struct {
	// The displayname of the network, e.g. `Discord`
	DisplayName string
	// The URL to the website of the network, e.g. `https://discord.com`
	NetworkURL string
	// The icon of the network as a mxc:// URI
	NetworkIcon id.ContentURIString
	// An identifier uniquely identifying the network, e.g. `discord`
	NetworkID string
	// An identifier uniquely identifying the bridge software, e.g. `discordgo`
	BeeperBridgeType string
	// The default appservice port to use in the example config, defaults to 8080 if unset
	DefaultPort uint16
	// The default command prefix to use in the example config, defaults to NetworkID if unset. Must include the ! prefix.
	DefaultCommandPrefix string
}

BridgeName contains information about the network that a connector bridges to.

func (BridgeName) AsBridgeInfoSection

func (bn BridgeName) AsBridgeInfoSection() event.BridgeInfoSection

type BridgeStateQueue

type BridgeStateQueue struct {
	// contains filtered or unexported fields
}

func (*BridgeStateQueue) GetPrev

func (bsq *BridgeStateQueue) GetPrev() status.BridgeState

func (*BridgeStateQueue) Send

func (bsq *BridgeStateQueue) Send(state status.BridgeState)

func (*BridgeStateQueue) SetPrev

func (bsq *BridgeStateQueue) SetPrev(prev status.BridgeState)

type CommandEvent

type CommandEvent struct {
	Bot       MatrixAPI
	Bridge    *Bridge
	Portal    *Portal
	Processor *CommandProcessor
	Handler   MinimalCommandHandler
	RoomID    id.RoomID
	EventID   id.EventID
	User      *User
	Command   string
	Args      []string
	RawArgs   string
	ReplyTo   id.EventID
	Ctx       context.Context
	Log       *zerolog.Logger
}

CommandEvent stores all data which might be used to handle commands

func (*CommandEvent) MarkRead

func (ce *CommandEvent) MarkRead()

MarkRead marks the command event as read.

func (*CommandEvent) React

func (ce *CommandEvent) React(key string)

React sends a reaction to the command.

func (*CommandEvent) Redact

func (ce *CommandEvent) Redact(req ...mautrix.ReqRedact)

Redact redacts the command.

func (*CommandEvent) Reply

func (ce *CommandEvent) Reply(msg string, args ...any)

Reply sends a reply to command as notice, with optional string formatting and automatic $cmdprefix replacement.

func (*CommandEvent) ReplyAdvanced

func (ce *CommandEvent) ReplyAdvanced(msg string, allowMarkdown, allowHTML bool)

ReplyAdvanced sends a reply to command as notice. It allows using HTML and disabling markdown, but doesn't have built-in string formatting.

type CommandHandler

type CommandHandler interface {
	MinimalCommandHandler
	GetName() string
}

type CommandProcessor

type CommandProcessor struct {
	// contains filtered or unexported fields
}

func NewProcessor

func NewProcessor(bridge *Bridge) *CommandProcessor

NewProcessor creates a CommandProcessor

func (*CommandProcessor) AddHandler

func (proc *CommandProcessor) AddHandler(handler CommandHandler)

func (*CommandProcessor) AddHandlers

func (proc *CommandProcessor) AddHandlers(handlers ...CommandHandler)

func (*CommandProcessor) Handle

func (proc *CommandProcessor) Handle(ctx context.Context, roomID id.RoomID, eventID id.EventID, user *User, message string, replyTo id.EventID)

Handle handles messages to the bridge

type CommandState

type CommandState struct {
	Next   MinimalCommandHandler
	Action string
	Meta   any
	Cancel func()
}

type ConfigValidatingNetwork

type ConfigValidatingNetwork interface {
	NetworkConnector
	ValidateConfig() error
}

ConfigValidatingNetwork is an optional interface that network connectors can implement to validate config fields before the bridge is started.

When the ValidateConfig method is called, the config data will already be unmarshaled into the object returned by [NetworkConnector.GetConfig].

This mechanism is usually used to refuse bridge startup if a mandatory field has an invalid value.

type ConvertedEdit

type ConvertedEdit struct {
	ModifiedParts []*ConvertedEditPart
	DeletedParts  []*database.Message
}

type ConvertedEditPart

type ConvertedEditPart struct {
	Part *database.Message

	Type event.Type
	// The Content and Extra fields will be put inside `m.new_content` automatically.
	// SetEdit must NOT be called by the network connector.
	Content *event.MessageEventContent
	Extra   map[string]any
	// TopLevelExtra can be used to specify custom fields at the top level of the content rather than inside `m.new_content`.
	TopLevelExtra map[string]any
}

type ConvertedMessage

type ConvertedMessage struct {
	ReplyTo    *networkid.MessageOptionalPartID
	ThreadRoot *networkid.MessageOptionalPartID
	Parts      []*ConvertedMessagePart
}

type ConvertedMessagePart

type ConvertedMessagePart struct {
	ID         networkid.PartID
	Type       event.Type
	Content    *event.MessageEventContent
	Extra      map[string]any
	DBMetadata map[string]any
}

type DBUpgradeError

type DBUpgradeError struct {
	Err     error
	Section string
}

func (DBUpgradeError) Error

func (e DBUpgradeError) Error() string

func (DBUpgradeError) Unwrap

func (e DBUpgradeError) Unwrap() error

type EventSender

type EventSender struct {
	IsFromMe    bool
	SenderLogin networkid.UserLoginID
	Sender      networkid.UserID
}

type FullHandler

type FullHandler struct {
	Func func(*CommandEvent)

	Name    string
	Aliases []string
	Help    HelpMeta

	RequiresAdmin  bool
	RequiresPortal bool
	RequiresLogin  bool

	RequiresEventLevel event.Type
}

func (*FullHandler) GetAliases

func (fh *FullHandler) GetAliases() []string

func (*FullHandler) GetHelp

func (fh *FullHandler) GetHelp() HelpMeta

func (*FullHandler) GetName

func (fh *FullHandler) GetName() string

func (*FullHandler) Run

func (fh *FullHandler) Run(ce *CommandEvent)

func (*FullHandler) ShowInHelp

func (fh *FullHandler) ShowInHelp(ce *CommandEvent) bool

type Ghost

type Ghost struct {
	*database.Ghost
	Bridge *Bridge
	Log    zerolog.Logger
	Intent MatrixAPI
	MXID   id.UserID
}

func (*Ghost) IntentFor

func (ghost *Ghost) IntentFor(portal *Portal) MatrixAPI

func (*Ghost) UpdateAvatar

func (ghost *Ghost) UpdateAvatar(ctx context.Context, avatar *Avatar) bool

func (*Ghost) UpdateContactInfo

func (ghost *Ghost) UpdateContactInfo(ctx context.Context, identifiers []string, isBot *bool) bool

func (*Ghost) UpdateInfo

func (ghost *Ghost) UpdateInfo(ctx context.Context, info *UserInfo)

func (*Ghost) UpdateInfoIfNecessary

func (ghost *Ghost) UpdateInfoIfNecessary(ctx context.Context, source *UserLogin)

func (*Ghost) UpdateName

func (ghost *Ghost) UpdateName(ctx context.Context, name string) bool

type HelpMeta

type HelpMeta struct {
	Command     string
	Section     HelpSection
	Description string
	Args        string
}

func (*HelpMeta) String

func (hm *HelpMeta) String() string

type HelpSection

type HelpSection struct {
	Name  string
	Order int
}

type HelpfulHandler

type HelpfulHandler interface {
	CommandHandler
	GetHelp() HelpMeta
	ShowInHelp(*CommandEvent) bool
}

type LoginCompleteParams

type LoginCompleteParams struct {
	UserLoginID networkid.UserLoginID `json:"user_login_id"`
}

type LoginCookiesParams

type LoginCookiesParams struct {
	URL       string `json:"url"`
	UserAgent string `json:"user_agent,omitempty"`

	CookieDomain     string   `json:"cookie_domain,omitempty"`
	CookieKeys       []string `json:"cookie_keys,omitempty"`
	LocalStorageKeys []string `json:"local_storage_keys,omitempty"`
	SpecialKeys      []string `json:"special_keys,omitempty"`
	SpecialExtractJS string   `json:"special_extract_js,omitempty"`
}

type LoginDisplayAndWaitParams

type LoginDisplayAndWaitParams struct {
	// The type of thing to display (QR, emoji or text code)
	Type LoginDisplayType `json:"type"`
	// The thing to display (raw data for QR, unicode emoji for emoji, plain string for code)
	Data string `json:"data"`
	// An image containing the thing to display. If present, this is recommended over using data directly.
	// For emojis, the URL to the canonical image representation of the emoji
	ImageURL string `json:"image_url,omitempty"`
}

type LoginDisplayType

type LoginDisplayType string
const (
	LoginDisplayTypeQR    LoginDisplayType = "qr"
	LoginDisplayTypeEmoji LoginDisplayType = "emoji"
	LoginDisplayTypeCode  LoginDisplayType = "code"
)

type LoginFlow

type LoginFlow struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	ID          string `json:"id"`
}

type LoginInputDataField

type LoginInputDataField struct {
	// The type of input field as a hint for the client.
	Type LoginInputFieldType `json:"type"`
	// The ID of the field to be used as the key in the map that is submitted to the connector.
	ID string `json:"id"`
	// The name of the field shown to the user.
	Name string `json:"name"`
	// The description of the field shown to the user.
	Description string `json:"description"`
	// A regex pattern that the client can use to validate input client-side.
	Pattern string `json:"pattern,omitempty"`
	// A function that validates the input and optionally cleans it up before it's submitted to the connector.
	Validate func(string) (string, error) `json:"-"`
}

func (*LoginInputDataField) FillDefaultValidate

func (f *LoginInputDataField) FillDefaultValidate()

type LoginInputFieldType

type LoginInputFieldType string
const (
	LoginInputFieldTypeUsername    LoginInputFieldType = "username"
	LoginInputFieldTypePassword    LoginInputFieldType = "password"
	LoginInputFieldTypePhoneNumber LoginInputFieldType = "phone_number"
	LoginInputFieldTypeEmail       LoginInputFieldType = "email"
	LoginInputFieldType2FACode     LoginInputFieldType = "2fa_code"
)

type LoginProcess

type LoginProcess interface {
	// Start starts the process and returns the first step.
	//
	// For example, a network using QR login may connect to the network, fetch a QR code,
	// and return a DisplayAndWait-type step.
	//
	// This will only ever be called once.
	Start(ctx context.Context) (*LoginStep, error)
	// Cancel stops the login process and cleans up any resources.
	// No other methods will be called after cancel.
	//
	// Cancel will not be called if any other method returned an error:
	// errors are always treated as fatal and the process is assumed to be automatically cancelled.
	Cancel()
}

LoginProcess represents a single occurrence of a user logging into the remote network.

type LoginProcessCookies

type LoginProcessCookies interface {
	LoginProcess
	SubmitCookies(ctx context.Context, cookies map[string]string) (*LoginStep, error)
}

type LoginProcessDisplayAndWait

type LoginProcessDisplayAndWait interface {
	LoginProcess
	Wait(ctx context.Context) (*LoginStep, error)
}

type LoginProcessUserInput

type LoginProcessUserInput interface {
	LoginProcess
	SubmitUserInput(ctx context.Context, input map[string]string) (*LoginStep, error)
}

type LoginStep

type LoginStep struct {
	// The type of login step
	Type LoginStepType `json:"type"`
	// A unique ID for this step. The ID should be same for every login using the same flow,
	// but it should be different for different bridges and step types.
	//
	// For example, Telegram's QR scan followed by a 2-factor password
	// might use the IDs `fi.mau.telegram.qr` and `fi.mau.telegram.2fa_password`.
	StepID string `json:"step_id"`
	// Instructions contains human-readable instructions for completing the login step.
	Instructions string `json:"instructions"`

	DisplayAndWaitParams *LoginDisplayAndWaitParams `json:"display_and_wait"`
	CookiesParams        *LoginCookiesParams        `json:"cookies"`
	UserInputParams      *LoginUserInputParams      `json:"user_input"`
	CompleteParams       *LoginCompleteParams       `json:"complete"`
}

type LoginStepType

type LoginStepType string
const (
	LoginStepTypeUserInput      LoginStepType = "user_input"
	LoginStepTypeCookies        LoginStepType = "cookies"
	LoginStepTypeDisplayAndWait LoginStepType = "display_and_wait"
	LoginStepTypeComplete       LoginStepType = "complete"
)

type LoginSubmit

type LoginSubmit struct {
}

type LoginUserInputParams

type LoginUserInputParams struct {
	// The fields that the user needs to fill in.
	Fields []LoginInputDataField `json:"fields"`
}

type MatrixAPI

type MatrixAPI interface {
	GetMXID() id.UserID

	SendMessage(ctx context.Context, roomID id.RoomID, eventType event.Type, content *event.Content, ts time.Time) (*mautrix.RespSendEvent, error)
	SendState(ctx context.Context, roomID id.RoomID, eventType event.Type, stateKey string, content *event.Content, ts time.Time) (*mautrix.RespSendEvent, error)
	MarkRead(ctx context.Context, roomID id.RoomID, eventID id.EventID, ts time.Time) error
	DownloadMedia(ctx context.Context, uri id.ContentURIString, file *event.EncryptedFileInfo) ([]byte, error)
	UploadMedia(ctx context.Context, roomID id.RoomID, data []byte, fileName, mimeType string) (url id.ContentURIString, file *event.EncryptedFileInfo, err error)

	SetDisplayName(ctx context.Context, name string) error
	SetAvatarURL(ctx context.Context, avatarURL id.ContentURIString) error
	SetExtraProfileMeta(ctx context.Context, data any) error

	CreateRoom(ctx context.Context, req *mautrix.ReqCreateRoom) (id.RoomID, error)
	DeleteRoom(ctx context.Context, roomID id.RoomID) error
	InviteUser(ctx context.Context, roomID id.RoomID, userID id.UserID) error
	EnsureJoined(ctx context.Context, roomID id.RoomID) error
}

type MatrixConnector

type MatrixConnector interface {
	Init(*Bridge)
	Start(ctx context.Context) error

	ParseGhostMXID(userID id.UserID) (networkid.UserID, bool)
	FormatGhostMXID(userID networkid.UserID) id.UserID

	GhostIntent(userID id.UserID) MatrixAPI
	NewUserIntent(ctx context.Context, userID id.UserID, accessToken string) (MatrixAPI, string, error)
	BotIntent() MatrixAPI

	SendBridgeStatus(ctx context.Context, state *status.BridgeState) error
	SendMessageStatus(ctx context.Context, status *MessageStatus, evt *MessageStatusEventInfo)

	GetMembers(ctx context.Context, roomID id.RoomID) (map[id.UserID]*event.MemberEventContent, error)
	GetMemberInfo(ctx context.Context, roomID id.RoomID, userID id.UserID) (*event.MemberEventContent, error)

	ServerName() string
}

type MatrixEdit

type MatrixEdit struct {
	MatrixEventBase[*event.MessageEventContent]
	EditTarget *database.Message
}

type MatrixEventBase

type MatrixEventBase[ContentType any] struct {
	// The raw event being bridged.
	Event *event.Event
	// The parsed content struct of the event. Custom fields can be found in Event.Content.Raw.
	Content ContentType
	// The room where the event happened.
	Portal *Portal

	// The original sender user ID. Only present in case the event is being relayed (and Sender is not the same user).
	OrigSender *OrigSender
}

type MatrixMessage

type MatrixMessage struct {
	MatrixEventBase[*event.MessageEventContent]
	ThreadRoot *database.Message
	ReplyTo    *database.Message
}

type MatrixMessageRemove

type MatrixMessageRemove struct {
	MatrixEventBase[*event.RedactionEventContent]
	TargetMessage *database.Message
}

type MatrixReaction

type MatrixReaction struct {
	MatrixEventBase[*event.ReactionEventContent]
	TargetMessage *database.Message
	PreHandleResp *MatrixReactionPreResponse

	// When MaxReactions is >0 in the pre-response, this is the list of previous reactions that should be preserved.
	ExistingReactionsToKeep []*database.Reaction
}

type MatrixReactionPreResponse

type MatrixReactionPreResponse struct {
	SenderID     networkid.UserID
	EmojiID      networkid.EmojiID
	Emoji        string
	MaxReactions int
}

type MatrixReactionRemove

type MatrixReactionRemove struct {
	MatrixEventBase[*event.RedactionEventContent]
	TargetReaction *database.Reaction
}

type MatrixReadReceipt

type MatrixReadReceipt struct {
	Portal *Portal
	// The event ID that the receipt is targeting
	EventID id.EventID
	// The exact message that was read. This may be nil if the event ID isn't a message.
	ExactMessage *database.Message
	// The timestamp that the user has read up to. This is either the timestamp of the message
	// (if one is present) or the timestamp of the receipt.
	ReadUpTo time.Time
	// The ReadUpTo timestamp of the previous message
	LastRead time.Time
	// The receipt metadata.
	Receipt event.ReadReceipt
}

type MatrixTyping

type MatrixTyping struct{}

type MaxFileSizeingNetwork

type MaxFileSizeingNetwork interface {
	NetworkConnector
	SetMaxFileSize(maxSize int64)
}

MaxFileSizeingNetwork is an optional interface that network connectors can implement to find out the maximum file size that can be uploaded to Matrix.

The SetMaxFileSize will be called asynchronously soon after startup. Before the function is called, the connector may assume a default limit of 50 MiB.

type MessageStatus

type MessageStatus struct {
	Step     status.MessageCheckpointStep
	RetryNum int

	Status        event.MessageStatus
	ErrorReason   event.MessageStatusReason
	DeliveredTo   []id.UserID
	InternalError error  // Internal error to be tracked in message checkpoints
	Message       string // Human-readable message shown to users

	ErrorAsMessage bool
	IsCertain      bool
	SendNotice     bool
	DisableMSS     bool
}

func WrapErrorInStatus

func WrapErrorInStatus(err error) MessageStatus

func (MessageStatus) Error

func (ms MessageStatus) Error() string

func (*MessageStatus) ToCheckpoint

func (*MessageStatus) ToMSSEvent

func (*MessageStatus) ToNoticeEvent

func (MessageStatus) Unwrap

func (ms MessageStatus) Unwrap() error

func (MessageStatus) WithErrorAsMessage

func (ms MessageStatus) WithErrorAsMessage() MessageStatus

func (MessageStatus) WithErrorReason

func (ms MessageStatus) WithErrorReason(reason event.MessageStatusReason) MessageStatus

func (MessageStatus) WithIsCertain

func (ms MessageStatus) WithIsCertain(certain bool) MessageStatus

func (MessageStatus) WithMessage

func (ms MessageStatus) WithMessage(msg string) MessageStatus

func (MessageStatus) WithSendNotice

func (ms MessageStatus) WithSendNotice(send bool) MessageStatus

func (MessageStatus) WithStatus

func (ms MessageStatus) WithStatus(status event.MessageStatus) MessageStatus

func (MessageStatus) WithStep

type MessageStatusEventInfo

type MessageStatusEventInfo struct {
	RoomID      id.RoomID
	EventID     id.EventID
	EventType   event.Type
	MessageType event.MessageType
	Sender      id.UserID
	ThreadRoot  id.EventID
}

func StatusEventInfoFromEvent

func StatusEventInfoFromEvent(evt *event.Event) *MessageStatusEventInfo

type MinimalCommandHandler

type MinimalCommandHandler interface {
	Run(*CommandEvent)
}

type MinimalCommandHandlerFunc

type MinimalCommandHandlerFunc func(*CommandEvent)

func (MinimalCommandHandlerFunc) Run

type NetworkAPI

type NetworkAPI interface {
	Connect(ctx context.Context) error
	IsLoggedIn() bool
	LogoutRemote(ctx context.Context)

	IsThisUser(ctx context.Context, userID networkid.UserID) bool
	GetChatInfo(ctx context.Context, portal *Portal) (*PortalInfo, error)
	GetUserInfo(ctx context.Context, ghost *Ghost) (*UserInfo, error)

	HandleMatrixMessage(ctx context.Context, msg *MatrixMessage) (message *database.Message, err error)
	HandleMatrixEdit(ctx context.Context, msg *MatrixEdit) error
	PreHandleMatrixReaction(ctx context.Context, msg *MatrixReaction) (MatrixReactionPreResponse, error)
	HandleMatrixReaction(ctx context.Context, msg *MatrixReaction) (reaction *database.Reaction, err error)
	HandleMatrixReactionRemove(ctx context.Context, msg *MatrixReactionRemove) error
	HandleMatrixMessageRemove(ctx context.Context, msg *MatrixMessageRemove) error
	HandleMatrixReadReceipt(ctx context.Context, msg *MatrixReadReceipt) error
}

NetworkAPI is an interface representing a remote network client for a single user login.

type NetworkConnector

type NetworkConnector interface {
	// Init is called when the bridge is initialized. The connector should store the bridge instance for later use.
	// This should not do any network calls or other blocking operations.
	Init(*Bridge)
	// Start is called when the bridge is starting.
	// The connector should do any non-user-specific startup actions necessary.
	// User logins will be loaded separately, so the connector should not load them here.
	Start(context.Context) error
	// LoadUserLogin is called when a UserLogin is loaded from the database in order to fill the [UserLogin.Client] field.
	//
	// This is called within the bridge's global cache lock, so it must not do any slow operations,
	// such as connecting to the network. Instead, connecting should happen when [NetworkAPI.Connect] is called later.
	LoadUserLogin(ctx context.Context, login *UserLogin) error

	GetName() BridgeName
	// GetConfig returns all the parts of the network connector's config file. Specifically:
	// - example: a string containing an example config file
	// - data: an interface to unmarshal the actual config into
	// - upgrader: a config upgrader to ensure all fields are present and to do any migrations from old configs
	GetConfig() (example string, data any, upgrader configupgrade.Upgrader)

	// GetLoginFlows returns a list of login flows that the network supports.
	GetLoginFlows() []LoginFlow
	// CreateLogin is called when a user wants to log in to the network.
	//
	// This should generally not do any work, it should just return a LoginProcess that remembers
	// the user and will execute the requested flow. The actual work should start when [LoginProcess.Start] is called.
	CreateLogin(ctx context.Context, user *User, flowID string) (LoginProcess, error)
}

NetworkConnector is the main interface that a network connector must implement.

type OrigSender

type OrigSender struct {
	User *User
	event.MemberEventContent
}

type Portal

type Portal struct {
	*database.Portal
	Bridge *Bridge
	Log    zerolog.Logger
	Parent *Portal
	Relay  *UserLogin
	// contains filtered or unexported fields
}

func (*Portal) CreateMatrixRoom

func (portal *Portal) CreateMatrixRoom(ctx context.Context, source *UserLogin) error

func (*Portal) FindPreferredLogin

func (portal *Portal) FindPreferredLogin(ctx context.Context, user *User, allowRelay bool) (*UserLogin, *database.UserPortal, error)

func (*Portal) GetTopLevelParent

func (portal *Portal) GetTopLevelParent() *Portal

func (*Portal) SyncParticipants

func (portal *Portal) SyncParticipants(ctx context.Context, members []networkid.UserID, source *UserLogin) ([]id.UserID, []id.UserID, error)

func (*Portal) UpdateAvatar

func (portal *Portal) UpdateAvatar(ctx context.Context, avatar *Avatar, sender *Ghost, ts time.Time) bool

func (*Portal) UpdateBridgeInfo

func (portal *Portal) UpdateBridgeInfo(ctx context.Context)

func (*Portal) UpdateInfo

func (portal *Portal) UpdateInfo(ctx context.Context, info *PortalInfo, sender *Ghost, ts time.Time)

func (*Portal) UpdateName

func (portal *Portal) UpdateName(ctx context.Context, name string, sender *Ghost, ts time.Time) bool

func (*Portal) UpdateTopic

func (portal *Portal) UpdateTopic(ctx context.Context, topic string, sender *Ghost, ts time.Time) bool

type PortalInfo

type PortalInfo struct {
	Name   *string
	Topic  *string
	Avatar *Avatar

	Members []networkid.UserID

	IsDirectChat *bool
	IsSpace      *bool
}

type RemoteEdit

type RemoteEdit interface {
	RemoteEventWithTargetMessage
	ConvertEdit(ctx context.Context, portal *Portal, intent MatrixAPI, existing []*database.Message) (*ConvertedEdit, error)
}

type RemoteEvent

type RemoteEvent interface {
	GetType() RemoteEventType
	GetPortalKey() networkid.PortalKey
	AddLogContext(c zerolog.Context) zerolog.Context
	GetSender() EventSender
}

RemoteEvent represents a single event from the remote network, such as a message or a reaction.

When a NetworkAPI receives an event from the remote network, it should convert it into a RemoteEvent and pass it to the bridge for processing using Bridge.QueueRemoteEvent.

type RemoteEventThatMayCreatePortal

type RemoteEventThatMayCreatePortal interface {
	RemoteEvent
	ShouldCreatePortal() bool
}

type RemoteEventType

type RemoteEventType int
const (
	RemoteEventUnknown RemoteEventType = iota
	RemoteEventMessage
	RemoteEventEdit
	RemoteEventReaction
	RemoteEventReactionRemove
	RemoteEventMessageRemove
	RemoteEventReadReceipt
	RemoteEventDeliveryReceipt
	RemoteEventTyping
)

type RemoteEventWithTargetMessage

type RemoteEventWithTargetMessage interface {
	RemoteEvent
	GetTargetMessage() networkid.MessageID
}

type RemoteEventWithTargetPart

type RemoteEventWithTargetPart interface {
	RemoteEventWithTargetMessage
	GetTargetMessagePart() networkid.PartID
}

type RemoteEventWithTimestamp

type RemoteEventWithTimestamp interface {
	RemoteEvent
	GetTimestamp() time.Time
}

type RemoteMessage

type RemoteMessage interface {
	RemoteEvent
	GetID() networkid.MessageID
	ConvertMessage(ctx context.Context, portal *Portal, intent MatrixAPI) (*ConvertedMessage, error)
}

type RemoteMessageRemove

type RemoteMessageRemove interface {
	RemoteEventWithTargetMessage
}

type RemoteReaction

type RemoteReaction interface {
	RemoteEventWithTargetMessage
	GetReactionEmoji() (string, networkid.EmojiID)
}

type RemoteReactionRemove

type RemoteReactionRemove interface {
	RemoteEventWithTargetMessage
	GetRemovedEmojiID() networkid.EmojiID
}

type RemoteReactionWithMeta

type RemoteReactionWithMeta interface {
	RemoteReaction
	GetReactionDBMetadata() map[string]any
}

type RemoteReceipt

type RemoteReceipt interface {
	RemoteEvent
	GetLastReceiptTarget() networkid.MessageID
	GetReceiptTargets() []networkid.MessageID
}

type RemoteTyping

type RemoteTyping interface {
	RemoteEvent
	GetTimeout() time.Duration
}

type SimpleRemoteEvent

type SimpleRemoteEvent[T any] struct {
	Type         RemoteEventType
	LogContext   func(c zerolog.Context) zerolog.Context
	PortalKey    networkid.PortalKey
	Data         T
	CreatePortal bool

	ID             networkid.MessageID
	Sender         EventSender
	TargetMessage  networkid.MessageID
	EmojiID        networkid.EmojiID
	Emoji          string
	ReactionDBMeta map[string]any
	Timestamp      time.Time

	ConvertMessageFunc func(ctx context.Context, portal *Portal, intent MatrixAPI, data T) (*ConvertedMessage, error)
	ConvertEditFunc    func(ctx context.Context, portal *Portal, intent MatrixAPI, existing []*database.Message, data T) (*ConvertedEdit, error)
}

SimpleRemoteEvent is a simple implementation of RemoteEvent that can be used with struct fields and some callbacks.

func (*SimpleRemoteEvent[T]) AddLogContext

func (sre *SimpleRemoteEvent[T]) AddLogContext(c zerolog.Context) zerolog.Context

func (*SimpleRemoteEvent[T]) ConvertEdit

func (sre *SimpleRemoteEvent[T]) ConvertEdit(ctx context.Context, portal *Portal, intent MatrixAPI, existing []*database.Message) (*ConvertedEdit, error)

func (*SimpleRemoteEvent[T]) ConvertMessage

func (sre *SimpleRemoteEvent[T]) ConvertMessage(ctx context.Context, portal *Portal, intent MatrixAPI) (*ConvertedMessage, error)

func (*SimpleRemoteEvent[T]) GetID

func (sre *SimpleRemoteEvent[T]) GetID() networkid.MessageID

func (*SimpleRemoteEvent[T]) GetPortalKey

func (sre *SimpleRemoteEvent[T]) GetPortalKey() networkid.PortalKey

func (*SimpleRemoteEvent[T]) GetReactionDBMetadata

func (sre *SimpleRemoteEvent[T]) GetReactionDBMetadata() map[string]any

func (*SimpleRemoteEvent[T]) GetReactionEmoji

func (sre *SimpleRemoteEvent[T]) GetReactionEmoji() (string, networkid.EmojiID)

func (*SimpleRemoteEvent[T]) GetRemovedEmojiID

func (sre *SimpleRemoteEvent[T]) GetRemovedEmojiID() networkid.EmojiID

func (*SimpleRemoteEvent[T]) GetSender

func (sre *SimpleRemoteEvent[T]) GetSender() EventSender

func (*SimpleRemoteEvent[T]) GetTargetMessage

func (sre *SimpleRemoteEvent[T]) GetTargetMessage() networkid.MessageID

func (*SimpleRemoteEvent[T]) GetTimestamp

func (sre *SimpleRemoteEvent[T]) GetTimestamp() time.Time

func (*SimpleRemoteEvent[T]) GetType

func (sre *SimpleRemoteEvent[T]) GetType() RemoteEventType

func (*SimpleRemoteEvent[T]) ShouldCreatePortal

func (sre *SimpleRemoteEvent[T]) ShouldCreatePortal() bool

type User

type User struct {
	*database.User
	Bridge *Bridge
	Log    zerolog.Logger

	CommandState atomic.Pointer[CommandState]
	// contains filtered or unexported fields
}

func (*User) DoublePuppet

func (user *User) DoublePuppet(ctx context.Context) MatrixAPI

func (*User) LoginDoublePuppet

func (user *User) LoginDoublePuppet(ctx context.Context, token string) error

func (*User) LogoutDoublePuppet

func (user *User) LogoutDoublePuppet(ctx context.Context)

func (*User) NewLogin

func (user *User) NewLogin(ctx context.Context, data *database.UserLogin, client NetworkAPI) (*UserLogin, error)

func (*User) Save

func (user *User) Save(ctx context.Context) error

type UserInfo

type UserInfo struct {
	Identifiers []string
	Name        *string
	Avatar      *Avatar
	IsBot       *bool
}

type UserLogin

type UserLogin struct {
	*database.UserLogin
	Bridge *Bridge
	User   *User
	Log    zerolog.Logger

	Client      NetworkAPI
	BridgeState *BridgeStateQueue
}

func (*UserLogin) GetMXID

func (ul *UserLogin) GetMXID() id.UserID

func (*UserLogin) GetRemoteID

func (ul *UserLogin) GetRemoteID() string

func (*UserLogin) GetRemoteName

func (ul *UserLogin) GetRemoteName() string

func (*UserLogin) Logout

func (ul *UserLogin) Logout(ctx context.Context)

func (*UserLogin) MarkAsPreferredIn

func (ul *UserLogin) MarkAsPreferredIn(ctx context.Context, portal *Portal) error

func (*UserLogin) Save

func (ul *UserLogin) Save(ctx context.Context) error

Directories

Path Synopsis
mxmain
Package mxmain contains initialization code for a single-network Matrix bridge using the bridgev2 package.
Package mxmain contains initialization code for a single-network Matrix bridge using the bridgev2 package.
Package networkid contains string types used to represent different kinds of identifiers on remote networks.
Package networkid contains string types used to represent different kinds of identifiers on remote networks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL