diff --git a/maubot.go b/app/bot.go
similarity index 92%
rename from maubot.go
rename to app/bot.go
index f59f45b..0315777 100644
--- a/maubot.go
+++ b/app/bot.go
@@ -14,15 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-package maubot
+package app
import (
"net/http"
"os"
+ "maubot.xyz"
"maubot.xyz/config"
"maubot.xyz/database"
- "maubot.xyz/interfaces"
"maubot.xyz/matrix"
log "maunium.net/go/maulogger"
)
@@ -31,7 +31,7 @@ type Bot struct {
Config *config.MainConfig
Database *database.Database
Clients map[string]*matrix.Client
- PluginCreators map[string]*interfaces.PluginCreator
+ PluginCreators map[string]*maubot.PluginCreator
Plugins map[string]*PluginWrapper
Server *http.Server
}
@@ -41,7 +41,7 @@ func New(config *config.MainConfig) *Bot {
Config: config,
Clients: make(map[string]*matrix.Client),
Plugins: make(map[string]*PluginWrapper),
- PluginCreators: make(map[string]*interfaces.PluginCreator),
+ PluginCreators: make(map[string]*maubot.PluginCreator),
}
}
diff --git a/http.go b/app/http.go
similarity index 99%
rename from http.go
rename to app/http.go
index fe96a47..baf784a 100644
--- a/http.go
+++ b/app/http.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-package maubot
+package app
import (
"context"
diff --git a/app/matrix.go b/app/matrix.go
new file mode 100644
index 0000000..8a9e631
--- /dev/null
+++ b/app/matrix.go
@@ -0,0 +1,54 @@
+// maubot - A plugin-based Matrix bot system written in Go.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package app
+
+import (
+ "os"
+
+ "maubot.xyz/matrix"
+ log "maunium.net/go/maulogger"
+)
+
+func (bot *Bot) initClients() {
+ log.Debugln("Initializing Matrix clients")
+ clients := bot.Database.MatrixClient.GetAll()
+ for _, client := range clients {
+ mxClient, err := matrix.NewClient(client)
+ if err != nil {
+ log.Fatalf("Failed to create client to %s as %s: %v\n", client.Homeserver, client.UserID, err)
+ os.Exit(3)
+ }
+ log.Debugln("Initialized user", client.UserID, "with homeserver", client.Homeserver)
+ bot.Clients[client.UserID] = mxClient
+ }
+}
+
+func (bot *Bot) startClients() {
+ log.Debugln("Starting Matrix syncer")
+ for _, client := range bot.Clients {
+ if client.DB.Sync {
+ client.Sync()
+ }
+ }
+}
+
+func (bot *Bot) stopClients() {
+ log.Debugln("Stopping Matrix syncers")
+ for _, client := range bot.Clients {
+ client.StopSync()
+ }
+}
diff --git a/app/pluginloader.go b/app/pluginloader.go
new file mode 100644
index 0000000..aff9856
--- /dev/null
+++ b/app/pluginloader.go
@@ -0,0 +1,81 @@
+// maubot - A plugin-based Matrix bot system written in Go.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package app
+
+import (
+ "fmt"
+ "plugin"
+
+ "maubot.xyz"
+ "maubot.xyz/database"
+)
+
+type PluginWrapper struct {
+ maubot.Plugin
+ Creator *maubot.PluginCreator
+ DB *database.Plugin
+}
+
+func LoadPlugin(path string) (*maubot.PluginCreator, error) {
+ rawPlugin, err := plugin.Open(path)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open: %v", err)
+ }
+
+ pluginCreatorSymbol, err := rawPlugin.Lookup("Plugin")
+ if err == nil {
+ pluginCreator, ok := pluginCreatorSymbol.(*maubot.PluginCreator)
+ if ok {
+ pluginCreator.Path = path
+ return pluginCreator, nil
+ }
+ }
+
+ pluginCreatorFuncSymbol, err := rawPlugin.Lookup("Create")
+ if err != nil {
+ return nil, fmt.Errorf("symbol \"Create\" not found: %v", err)
+ }
+ pluginCreatorFunc, ok := pluginCreatorFuncSymbol.(maubot.PluginCreatorFunc)
+ if !ok {
+ return nil, fmt.Errorf("symbol \"Create\" does not implement maubot.PluginCreator")
+ }
+
+ nameSymbol, err := rawPlugin.Lookup("Name")
+ if err != nil {
+ return nil, fmt.Errorf("symbol \"Name\" not found: %v", err)
+ }
+ name, ok := nameSymbol.(string)
+ if !ok {
+ return nil, fmt.Errorf("symbol \"Name\" is not a string")
+ }
+
+ versionSymbol, err := rawPlugin.Lookup("Version")
+ if err != nil {
+ return nil, fmt.Errorf("symbol \"Version\" not found: %v", err)
+ }
+ version, ok := versionSymbol.(string)
+ if !ok {
+ return nil, fmt.Errorf("symbol \"Version\" is not a string")
+ }
+
+ return &maubot.PluginCreator{
+ Create: pluginCreatorFunc,
+ Name: name,
+ Version: version,
+ Path: path,
+ }, nil
+}
diff --git a/plugins.go b/app/plugins.go
similarity index 99%
rename from plugins.go
rename to app/plugins.go
index 42f6f82..d53e09b 100644
--- a/plugins.go
+++ b/app/plugins.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-package maubot
+package app
import (
"io/ioutil"
diff --git a/cmd/maubot/main.go b/cmd/maubot/main.go
index 3d8e739..fa76fb4 100644
--- a/cmd/maubot/main.go
+++ b/cmd/maubot/main.go
@@ -23,7 +23,7 @@ import (
"syscall"
_ "github.com/mattn/go-sqlite3"
- "maubot.xyz"
+ "maubot.xyz/app"
"maubot.xyz/config"
flag "maunium.net/go/mauflag"
log "maunium.net/go/maulogger"
@@ -55,7 +55,7 @@ func main() {
cfg.Logging.Configure(log.DefaultLogger)
log.Debugln("Logger configured")
- bot := maubot.New(cfg)
+ bot := app.New(cfg)
bot.Init()
bot.Start()
diff --git a/interfaces/interfaces.go b/interfaces/interfaces.go
deleted file mode 100644
index c4ccea8..0000000
--- a/interfaces/interfaces.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package interfaces
-
-type Plugin interface {
- Start()
- Stop()
-}
-
-type EventHandler func(*Event) bool
-
-type MatrixClient interface {
- AddEventHandler(string, EventHandler)
-}
-
-type EventFuncs interface {
- Reply(text string) (string, error)
- SendMessage(text string) (string, error)
- SendEvent(content map[string]interface{}) (string, error)
-}
-
-type Event struct {
- EventFuncs
-
- StateKey string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
- Sender string `json:"sender"` // The user ID of the sender of the event
- Type string `json:"type"` // The event type
- Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
- ID string `json:"event_id"` // The unique ID of this event
- RoomID string `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
- Content map[string]interface{} `json:"content"` // The JSON content of the event.
- Redacts string `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
- Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
-}
-
-type Unsigned struct {
- PrevContent map[string]interface{} `json:"prev_content,omitempty"`
- PrevSender string `json:"prev_sender,omitempty"`
- ReplacesState string `json:"replaces_state,omitempty"`
- Age int64 `json:"age"`
-}
-
-type PluginCreatorFunc func(client MatrixClient) Plugin
-
-type PluginCreator struct {
- Create PluginCreatorFunc
- Name string
- Version string
- Path string
-}
diff --git a/matrix.go b/matrix.go
index c65a545..2d9a12b 100644
--- a/matrix.go
+++ b/matrix.go
@@ -16,39 +16,109 @@
package maubot
-import (
- "os"
+type EventType string
+type MessageType string
- "maubot.xyz/matrix"
- log "maunium.net/go/maulogger"
+// State events
+const (
+ StateAliases EventType = "m.room.aliases"
+ StateCanonicalAlias = "m.room.canonical_alias"
+ StateCreate = "m.room.create"
+ StateJoinRules = "m.room.join_rules"
+ StateMember = "m.room.member"
+ StatePowerLevels = "m.room.power_levels"
+ StateRoomName = "m.room.name"
+ StateTopic = "m.room.topic"
+ StateRoomAvatar = "m.room.avatar"
+ StatePinnedEvents = "m.room.pinned_events"
)
-func (bot *Bot) initClients() {
- log.Debugln("Initializing Matrix clients")
- clients := bot.Database.MatrixClient.GetAll()
- for _, client := range clients {
- mxClient, err := matrix.NewClient(client)
- if err != nil {
- log.Fatalf("Failed to create client to %s as %s: %v\n", client.Homeserver, client.UserID, err)
- os.Exit(3)
- }
- log.Debugln("Initialized user", client.UserID, "with homeserver", client.Homeserver)
- bot.Clients[client.UserID] = mxClient
- }
+// Message events
+const (
+ EventRedaction EventType = "m.room.redaction"
+ EventMessage = "m.room.message"
+ EventSticker = "m.sticker"
+)
+
+// Msgtypes
+const (
+ MsgText MessageType = "m.text"
+ MsgEmote = "m.emote"
+ MsgNotice = "m.notice"
+ MsgImage = "m.image"
+ MsgLocation = "m.location"
+ MsgVideo = "m.video"
+ MsgAudio = "m.audio"
+)
+
+const FormatHTML = "org.matrix.custom.html"
+
+type EventHandler func(*Event) bool
+
+type MatrixClient interface {
+ AddEventHandler(EventType, EventHandler)
}
-func (bot *Bot) startClients() {
- log.Debugln("Starting Matrix syncer")
- for _, client := range bot.Clients {
- if client.DB.Sync {
- client.Sync()
- }
- }
+type EventFuncs interface {
+ Reply(string) (string, error)
+ ReplyContent(Content) (string, error)
+ SendMessage(string) (string, error)
+ SendContent(Content) (string, error)
+ SendRawEvent(EventType, interface{}) (string, error)
}
-func (bot *Bot) stopClients() {
- log.Debugln("Stopping Matrix syncers")
- for _, client := range bot.Clients {
- client.StopSync()
- }
+type Event struct {
+ EventFuncs
+
+ StateKey string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
+ Sender string `json:"sender"` // The user ID of the sender of the event
+ Type EventType `json:"type"` // The event type
+ Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
+ ID string `json:"event_id"` // The unique ID of this event
+ RoomID string `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
+ Content Content `json:"content"`
+ Redacts string `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
+ Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
+}
+
+type Unsigned struct {
+ PrevContent Content `json:"prev_content,omitempty"`
+ PrevSender string `json:"prev_sender,omitempty"`
+ ReplacesState string `json:"replaces_state,omitempty"`
+ Age int64 `json:"age"`
+}
+
+type Content struct {
+ Raw map[string]interface{} `json:"-"`
+
+ MsgType MessageType `json:"msgtype"`
+ Body string `json:"body"`
+ Format string `json:"format"`
+ FormattedBody string `json:"formatted_body"`
+
+ Info FileInfo `json:"info"`
+ URL string `json:"url"`
+
+ Membership string `json:"membership"`
+
+ RelatesTo RelatesTo `json:"m.relates_to"`
+}
+
+type FileInfo struct {
+ MimeType string `json:"mimetype"`
+ ThumbnailInfo *FileInfo `json:"thumbnail_info"`
+ ThumbnailURL string `json:"thumbnail_url"`
+ Height int `json:"h"`
+ Width int `json:"w"`
+ Size int `json:"size"`
+}
+
+type RelatesTo struct {
+ InReplyTo InReplyTo `json:"m.in_reply_to"`
+}
+
+type InReplyTo struct {
+ EventID string `json:"event_id"`
+ // Not required, just for future-proofing
+ RoomID string `json:"room_id"`
}
diff --git a/matrix/event.go b/matrix/event.go
index f86b602..f418bee 100644
--- a/matrix/event.go
+++ b/matrix/event.go
@@ -17,7 +17,9 @@
package matrix
import (
- "maubot.xyz/interfaces"
+ "encoding/json"
+
+ "maubot.xyz"
"maunium.net/go/gomatrix"
)
@@ -26,43 +28,64 @@ type Event struct {
Client *Client
}
-func (evt *Event) Interface() *interfaces.Event {
+func roundtripContent(rawContent map[string]interface{}) (content maubot.Content) {
+ if len(rawContent) == 0 {
+ content.Raw = rawContent
+ return
+ }
+ data, _ := json.Marshal(&rawContent)
+ json.Unmarshal(data, &content)
+ content.Raw = rawContent
+ return
+}
+
+func (evt *Event) Interface() *maubot.Event {
var stateKey string
if evt.StateKey != nil {
stateKey = *evt.StateKey
}
- return &interfaces.Event{
+ mbEvent := &maubot.Event{
EventFuncs: evt,
StateKey: stateKey,
Sender: evt.Sender,
- Type: evt.Type,
+ Type: maubot.EventType(evt.Type),
Timestamp: evt.Timestamp,
ID: evt.ID,
RoomID: evt.RoomID,
- Content: evt.Content,
+ Content: roundtripContent(evt.Content),
Redacts: evt.Redacts,
- Unsigned: interfaces.Unsigned{
- PrevContent: evt.Unsigned.PrevContent,
+ Unsigned: maubot.Unsigned{
+ PrevContent: roundtripContent(evt.Unsigned.PrevContent),
PrevSender: evt.Unsigned.PrevSender,
ReplacesState: evt.Unsigned.ReplacesState,
Age: evt.Unsigned.Age,
},
}
+ RemoveReplyFallback(mbEvent)
+ return mbEvent
}
func (evt *Event) Reply(text string) (string, error) {
- return evt.SendEvent(
+ return evt.SendRawEvent(maubot.EventMessage,
SetReply(
RenderMarkdown(text),
evt.Event))
}
-func (evt *Event) SendMessage(text string) (string, error) {
- return evt.SendEvent(RenderMarkdown(text))
+func (evt *Event) ReplyContent(content maubot.Content) (string, error) {
+ return evt.SendRawEvent(maubot.EventMessage, SetReply(content, evt.Event))
}
-func (evt *Event) SendEvent(content map[string]interface{}) (string, error) {
- resp, err := evt.Client.SendMessageEvent(evt.RoomID, "m.room.message", content)
+func (evt *Event) SendMessage(text string) (string, error) {
+ return evt.SendRawEvent(maubot.EventMessage, RenderMarkdown(text))
+}
+
+func (evt *Event) SendContent(content maubot.Content) (string, error) {
+ return evt.SendRawEvent(maubot.EventMessage, content)
+}
+
+func (evt *Event) SendRawEvent(evtType maubot.EventType, content interface{}) (string, error) {
+ resp, err := evt.Client.SendMessageEvent(evt.RoomID, string(evtType), content)
if err != nil {
return "", err
}
diff --git a/matrix/htmlutil.go b/matrix/htmlutil.go
index 565008f..9c235fd 100644
--- a/matrix/htmlutil.go
+++ b/matrix/htmlutil.go
@@ -19,9 +19,10 @@ package matrix
import (
"strings"
"gopkg.in/russross/blackfriday.v2"
+ "maubot.xyz"
)
-func RenderMarkdown(text string) map[string]interface{} {
+func RenderMarkdown(text string) maubot.Content {
parser := blackfriday.New(
blackfriday.WithExtensions(blackfriday.NoIntraEmphasis |
blackfriday.Tables |
@@ -43,10 +44,10 @@ func RenderMarkdown(text string) map[string]interface{} {
renderer.RenderFooter(&buf, ast)
htmlBody := buf.String()
- return map[string]interface{}{
- "formatted_body": htmlBody,
- "format": "org.matrix.custom.html",
- "msgtype": "m.text",
- "body": HTMLToText(htmlBody),
+ return maubot.Content{
+ FormattedBody: htmlBody,
+ Format: maubot.FormatHTML,
+ MsgType: maubot.MsgText,
+ Body: HTMLToText(htmlBody),
}
}
diff --git a/matrix/matrix.go b/matrix/matrix.go
index 790f8c0..a276d37 100644
--- a/matrix/matrix.go
+++ b/matrix/matrix.go
@@ -17,14 +17,15 @@
package matrix
import (
+ "maubot.xyz"
"maubot.xyz/database"
- "maubot.xyz/interfaces"
"maunium.net/go/gomatrix"
log "maunium.net/go/maulogger"
)
type Client struct {
*gomatrix.Client
+ syncer *MaubotSyncer
DB *database.MatrixClient
}
@@ -40,9 +41,10 @@ func NewClient(db *database.MatrixClient) (*Client, error) {
DB: db,
}
- client.Syncer = NewMaubotSyncer(client, client.Store)
+ client.syncer = NewMaubotSyncer(client, client.Store)
+ client.Client.Syncer = client.syncer
- client.AddEventHandler(gomatrix.StateMember, client.onJoin)
+ client.AddEventHandler(maubot.StateMember, client.onJoin)
return client, nil
}
@@ -50,19 +52,19 @@ func NewClient(db *database.MatrixClient) (*Client, error) {
func (client *Client) ParseEvent(evt *gomatrix.Event) *Event {
return &Event{
Client: client,
- Event: evt,
+ Event: evt,
}
}
-func (client *Client) AddEventHandler(evt string, handler interfaces.EventHandler) {
- client.Syncer.(*MaubotSyncer).OnEventType(evt, handler)
+func (client *Client) AddEventHandler(evt maubot.EventType, handler maubot.EventHandler) {
+ client.syncer.OnEventType(evt, handler)
}
-func (client *Client) onJoin(evt *interfaces.Event) bool {
+func (client *Client) onJoin(evt *maubot.Event) bool {
if !client.DB.AutoJoinRooms || evt.StateKey != client.DB.UserID {
return true
}
- if membership, _ := evt.Content["membership"].(string); membership == "invite" {
+ if evt.Content.Membership == "invite" {
client.JoinRoom(evt.RoomID)
return false
}
diff --git a/matrix/replyutil.go b/matrix/replyutil.go
index 3f4c2c0..6009dfc 100644
--- a/matrix/replyutil.go
+++ b/matrix/replyutil.go
@@ -17,11 +17,13 @@
package matrix
import (
+ "fmt"
"regexp"
"strings"
- "fmt"
- "maunium.net/go/gomatrix"
+
"golang.org/x/net/html"
+ "maubot.xyz"
+ "maunium.net/go/gomatrix"
)
var HTMLReplyFallbackRegex = regexp.MustCompile(`^[\s\S]+?`)
@@ -42,13 +44,13 @@ func TrimReplyFallbackText(text string) string {
return strings.Join(lines, "\n")
}
-func RemoveReplyFallback(evt *gomatrix.Event) {
- if format, ok := evt.Content["format"].(string); ok && format == "org.matrix.custom.html" {
- htmlBody, _ := evt.Content["formatted_body"].(string)
- evt.Content["formatted_body"] = TrimReplyFallbackHTML(htmlBody)
+func RemoveReplyFallback(evt *maubot.Event) {
+ if len(evt.Content.RelatesTo.InReplyTo.EventID) > 0 {
+ if evt.Content.Format == maubot.FormatHTML {
+ evt.Content.FormattedBody = TrimReplyFallbackHTML(evt.Content.FormattedBody)
+ }
+ evt.Content.Body = TrimReplyFallbackText(evt.Content.Body)
}
- plainBody, _ := evt.Content["body"].(string)
- evt.Content["body"] = TrimReplyFallbackText(plainBody)
}
const ReplyFormat = `
@@ -86,22 +88,18 @@ func ReplyFallbackText(evt *gomatrix.Event) string {
return fallbackText.String()
}
-func SetReply(content map[string]interface{}, inReplyTo *gomatrix.Event) map[string]interface{} {
- content["m.relates_to"] = map[string]interface{}{
- "m.in_reply_to": map[string]interface{}{
- "event_id": inReplyTo.ID,
- "room_id": inReplyTo.RoomID,
- },
+func SetReply(content maubot.Content, inReplyTo *gomatrix.Event) maubot.Content {
+ content.RelatesTo.InReplyTo.EventID = inReplyTo.ID
+ content.RelatesTo.InReplyTo.RoomID = inReplyTo.RoomID
+
+ if content.MsgType == maubot.MsgText || content.MsgType == maubot.MsgNotice {
+ if len(content.FormattedBody) == 0 || content.Format != maubot.FormatHTML {
+ content.FormattedBody = html.EscapeString(content.Body)
+ content.Format = maubot.FormatHTML
+ }
+ content.FormattedBody = ReplyFallbackHTML(inReplyTo) + content.FormattedBody
+ content.Body = ReplyFallbackText(inReplyTo) + content.Body
}
- body, _ := content["body"].(string)
- content["body"] = ReplyFallbackText(inReplyTo) + body
-
- htmlBody, ok := content["formatted_body"].(string)
- if !ok {
- htmlBody = html.EscapeString(body)
- content["format"] = "org.matrix.custom.html"
- }
- content["formatted_body"] = ReplyFallbackHTML(inReplyTo) + htmlBody
return content
}
diff --git a/matrix/sync.go b/matrix/sync.go
index 44c28f7..b8fd06c 100644
--- a/matrix/sync.go
+++ b/matrix/sync.go
@@ -6,14 +6,14 @@ import (
"runtime/debug"
"time"
- "maubot.xyz/interfaces"
+ "maubot.xyz"
"maunium.net/go/gomatrix"
)
type MaubotSyncer struct {
Client *Client
Store gomatrix.Storer
- listeners map[string][]interfaces.EventHandler
+ listeners map[maubot.EventType][]maubot.EventHandler
}
// NewDefaultSyncer returns an instantiated DefaultSyncer
@@ -21,7 +21,7 @@ func NewMaubotSyncer(client *Client, store gomatrix.Storer) *MaubotSyncer {
return &MaubotSyncer{
Client: client,
Store: store,
- listeners: make(map[string][]interfaces.EventHandler),
+ listeners: make(map[maubot.EventType][]maubot.EventHandler),
}
}
@@ -73,10 +73,10 @@ func (s *MaubotSyncer) ProcessResponse(res *gomatrix.RespSync, since string) (er
// OnEventType allows callers to be notified when there are new events for the given event type.
// There are no duplicate checks.
-func (s *MaubotSyncer) OnEventType(eventType string, callback interfaces.EventHandler) {
+func (s *MaubotSyncer) OnEventType(eventType maubot.EventType, callback maubot.EventHandler) {
_, exists := s.listeners[eventType]
if !exists {
- s.listeners[eventType] = []interfaces.EventHandler{}
+ s.listeners[eventType] = []maubot.EventHandler{}
}
s.listeners[eventType] = append(s.listeners[eventType], callback)
}
@@ -130,7 +130,7 @@ func (s *MaubotSyncer) getOrCreateRoom(roomID string) *gomatrix.Room {
func (s *MaubotSyncer) notifyListeners(mxEvent *gomatrix.Event) {
event := s.Client.ParseEvent(mxEvent)
- listeners, exists := s.listeners[event.Type]
+ listeners, exists := s.listeners[maubot.EventType(event.Type)]
if !exists {
return
}
diff --git a/plugin.go b/plugin.go
index e6af4c8..1fe0cd3 100644
--- a/plugin.go
+++ b/plugin.go
@@ -16,66 +16,16 @@
package maubot
-import (
- "fmt"
- "plugin"
-
- "maubot.xyz/database"
- "maubot.xyz/interfaces"
-)
-
-type PluginWrapper struct {
- interfaces.Plugin
- Creator *interfaces.PluginCreator
- DB *database.Plugin
+type Plugin interface {
+ Start()
+ Stop()
}
-func LoadPlugin(path string) (*interfaces.PluginCreator, error) {
- rawPlugin, err := plugin.Open(path)
- if err != nil {
- return nil, fmt.Errorf("failed to open: %v", err)
- }
+type PluginCreatorFunc func(client MatrixClient) Plugin
- pluginCreatorSymbol, err := rawPlugin.Lookup("Plugin")
- if err == nil {
- pluginCreator, ok := pluginCreatorSymbol.(*interfaces.PluginCreator)
- if ok {
- pluginCreator.Path = path
- return pluginCreator, nil
- }
- }
-
- pluginCreatorFuncSymbol, err := rawPlugin.Lookup("Create")
- if err != nil {
- return nil, fmt.Errorf("symbol \"Create\" not found: %v", err)
- }
- pluginCreatorFunc, ok := pluginCreatorFuncSymbol.(interfaces.PluginCreatorFunc)
- if !ok {
- return nil, fmt.Errorf("symbol \"Create\" does not implement maubot.PluginCreator")
- }
-
- nameSymbol, err := rawPlugin.Lookup("Name")
- if err != nil {
- return nil, fmt.Errorf("symbol \"Name\" not found: %v", err)
- }
- name, ok := nameSymbol.(string)
- if !ok {
- return nil, fmt.Errorf("symbol \"Name\" is not a string")
- }
-
- versionSymbol, err := rawPlugin.Lookup("Version")
- if err != nil {
- return nil, fmt.Errorf("symbol \"Version\" not found: %v", err)
- }
- version, ok := versionSymbol.(string)
- if !ok {
- return nil, fmt.Errorf("symbol \"Version\" is not a string")
- }
-
- return &interfaces.PluginCreator{
- Create: pluginCreatorFunc,
- Name: name,
- Version: version,
- Path: path,
- }, nil
+type PluginCreator struct {
+ Create PluginCreatorFunc
+ Name string
+ Version string
+ Path string
}