Alex
38a3f1bdb1
Mattermost assigns its own IDs to messages, thus when sending a message to Mattermost the event_seen key that has to be written must take into account that ID and not the one that we put in the event (which was the Matrix event ID) Note that for XMPP anything can be used as an ID, so using the Matrix event ID there worked, but it's actually not so good.
176 lines
5 KiB
Go
176 lines
5 KiB
Go
package connector
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
/*
|
|
A generic connector framework for instant messaging protocols.
|
|
|
|
Model:
|
|
|
|
- A connector represents a connection to an outgoing service (IRC, XMPP, etc)
|
|
It satisfies a generic interface representing the actions that can be called
|
|
(send messages, join room, etc)
|
|
|
|
- A handler represents a consumer of events happening on a connection
|
|
It satisfies a generic interface representing the events that can happend
|
|
(message received, rooms autojoined, etc)
|
|
|
|
- A connector implements a given protocol that has an identifier
|
|
Each protocol identifier determines a namespace for user identifiers
|
|
and room identifiers which are globally unique for all connections using
|
|
this protocol.
|
|
For instance, a user can have two IRC conections to different servers.
|
|
Internally used user names and room identifiers must contain
|
|
the server name to be able to differentiate.
|
|
*/
|
|
|
|
type UserID string
|
|
type RoomID string
|
|
|
|
type Connector interface {
|
|
// Set the handler that will receive events happening on this connection
|
|
SetHandler(handler Handler)
|
|
|
|
// Configure (or reconfigure) the connector and attempt to connect
|
|
Configure(conf Configuration) error
|
|
|
|
// Get the identifier of the protocol that is implemented by this connector
|
|
Protocol() string
|
|
|
|
// Get the user id of the connected user
|
|
User() UserID
|
|
|
|
// Set user information (nickname, picture, etc)
|
|
SetUserInfo(info *UserInfo) error
|
|
|
|
// Set room information (name, description, picture, etc)
|
|
SetRoomInfo(roomId RoomID, info *RoomInfo) error
|
|
|
|
// Try to join a channel
|
|
// If no error happens, it must fire a Handler.Joined event
|
|
Join(roomId RoomID) error
|
|
|
|
// Try to invite someone to a channel
|
|
// Or if roomId == "", just try adding them as friends
|
|
Invite(user UserID, roomId RoomID) error
|
|
|
|
// Leave a channel
|
|
Leave(roomId RoomID)
|
|
|
|
// Send an event. Returns the ID of the created remote message.
|
|
// This ID is used to deduplicate messages: if it comes back, it should have the same Id
|
|
// than the one returned here.
|
|
// For backends that do not implement IDs (e.g. IRC), an empty string is returned.
|
|
// (FIXME how to deduplicate IRC messages?)
|
|
// The event that is fed in this function may have its ID already set,
|
|
// in which case the backend is free to re-use the ID or select a new one.
|
|
Send(event *Event) (string, error)
|
|
|
|
// Close the connection
|
|
Close()
|
|
}
|
|
|
|
type Handler interface {
|
|
// Called when a room was joined (automatically or by call to Connector.Join)
|
|
Joined(roomId RoomID)
|
|
|
|
// Called when the user left a room
|
|
Left(roomId RoomID)
|
|
|
|
// Called when a user's info is updated (changed their nickname, status, etc)
|
|
// Can also be called with our own user ID when first loaded our user info
|
|
UserInfoUpdated(user UserID, info *UserInfo)
|
|
|
|
// Called when a room's info was updated,
|
|
// or the first tome a room's info is retreived
|
|
RoomInfoUpdated(roomId RoomID, author UserID, info *RoomInfo)
|
|
|
|
// Called when an event occurs in a room
|
|
// This must not be called for events authored by the user of the connection
|
|
Event(event *Event)
|
|
|
|
// These two functions enable the connector to access a simple key/value
|
|
// database to cache some information in order not to generate useless events.
|
|
// The connector should function when they are not implemented,
|
|
// in which case CacheGet always returns ""
|
|
CachePut(key string, value string)
|
|
CacheGet(key string) string
|
|
}
|
|
|
|
type EventType int
|
|
|
|
const (
|
|
EVENT_JOIN EventType = iota
|
|
EVENT_LEAVE
|
|
EVENT_MESSAGE
|
|
EVENT_ACTION
|
|
)
|
|
|
|
type Event struct {
|
|
Type EventType
|
|
|
|
// If non-empty, the event Id is used to deduplicate events in a channel
|
|
// This is usefull for backends that provide a backlog of channel messages
|
|
// when (re-)joining a room
|
|
Id string
|
|
|
|
// UserID of the user that sent the event
|
|
// If this is a direct message event, this event can only have been authored
|
|
// by the user we are talking to (and not by ourself)
|
|
Author UserID
|
|
|
|
// UserID of the targetted user in the case of a direct message,
|
|
// empty if targetting a room
|
|
Recipient UserID
|
|
|
|
// RoomID of the room where the event happenned or of the targetted room,
|
|
// or empty string if it happenned by direct message
|
|
Room RoomID
|
|
|
|
// Message text or action text
|
|
Text string
|
|
|
|
// Attached files such as images
|
|
Attachments []MediaObject
|
|
}
|
|
|
|
type UserInfo struct {
|
|
DisplayName string
|
|
|
|
// If non-empty, the Filename of the avatar object will be used by Easybridge
|
|
// to deduplicate the update events and prevent needless reuploads.
|
|
// Example strategy that works for the mattermost backend: use the update timestamp as fictious file name
|
|
Avatar MediaObject
|
|
}
|
|
|
|
type RoomInfo struct {
|
|
Name string
|
|
Topic string
|
|
|
|
// Same deduplication comment as for UserInfo.Avatar
|
|
Picture MediaObject
|
|
}
|
|
|
|
type MediaObject interface {
|
|
Filename() string
|
|
Size() int64
|
|
Mimetype() string
|
|
|
|
// Returns the size of an image if it is an image, otherwise nil
|
|
ImageSize() *ImageSize
|
|
|
|
// Read: must always be implemented
|
|
Read() (io.ReadCloser, error)
|
|
|
|
// URL(): not mandatory, may return an empty string
|
|
// If so, Read() is the only way to retrieve the object
|
|
URL() string
|
|
}
|
|
|
|
type ImageSize struct {
|
|
Width int
|
|
Height int
|
|
}
|