Documentation
¶
Overview ¶
Package mattermost is a thin, hand-written client for the Mattermost API v4 (Time = Mattermost v4). It deliberately avoids the official MM SDK to keep the dependency surface small and to tolerate Time's extensions/divergences.
The package is a leaf: it depends only on the stdlib and gorilla/websocket and MUST NOT import internal/bot, internal/config, or internal/storage. The transport adapter that maps wire types onto the bot's neutral envelope lives in internal/bot/transport_mattermost.go.
Index ¶
- type Channel
- type Client
- func (c *Client) BotID() string
- func (c *Client) CreatePost(ctx context.Context, r CreatePostReq) (*Post, error)
- func (c *Client) Events() <-chan PostedEvent
- func (c *Client) GetChannel(ctx context.Context, channelID string) (*Channel, error)
- func (c *Client) GetFile(ctx context.Context, fileID string) ([]byte, error)
- func (c *Client) GetFileInfo(ctx context.Context, fileID string) (*FileInfo, error)
- func (c *Client) GetUser(ctx context.Context, userID string) (*User, error)
- func (c *Client) InvalidateUser(userID string)
- func (c *Client) MaxPostSize() int
- func (c *Client) Run(ctx context.Context)
- func (c *Client) SendTyping(ctx context.Context, channelID string) error
- func (c *Client) SetReaction(ctx context.Context, postID, emojiName string) error
- func (c *Client) UploadFile(ctx context.Context, channelID, filename, mimeType string, data []byte) (string, error)
- type Config
- type CreatePostReq
- type Embed
- type FileInfo
- type Post
- type PostMetadata
- type PostedEvent
- type User
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Channel ¶
type Channel struct {
ID string `json:"id"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
Type string `json:"type"`
}
Channel is the subset of /channels/{id} we read — the display name used to label a channel scope in the dashboard. Type is "D"/"O"/"P"/"G".
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to the Mattermost v4 REST API over a dedicated, proxy-aware HTTP client. The same proxy is reused for the WebSocket dialer (ws.go).
func NewClient ¶
NewClient builds the client and bootstraps the bot identity and message-size limit from the live server. It fails fast if /users/me is unreachable.
func (*Client) CreatePost ¶
CreatePost sends a post and returns the created post (with its server id).
func (*Client) Events ¶
func (c *Client) Events() <-chan PostedEvent
Events returns the channel of incoming "posted" events produced by Run.
func (*Client) GetChannel ¶
GetChannel fetches a channel by id, caching the result with a TTL — channel names change rarely, but the entry still expires so a rename is eventually reflected (and the cache cannot grow stale forever). Mirrors GetUser; used to label a channel scope by its display name.
func (*Client) GetFileInfo ¶
GetFileInfo fetches metadata for an attached file (name, mime, size, …).
func (*Client) GetUser ¶
GetUser fetches a user's profile by id, caching the result with a TTL — the WS ingestion looks profiles up once per inbound post, but auth_service (the SSO access anchor) flips at migration time, so the cache MUST expire. On a stale or missing entry the profile is re-read. Concurrency-safe (the parallel tool path never calls this, but the cache is guarded anyway).
func (*Client) InvalidateUser ¶
InvalidateUser drops the cached profile for userID so the next GetUser re-reads it from the server. The bot calls this when it denies a sender: an account that has just migrated to SSO then recovers on its very next message instead of waiting out the cache TTL.
func (*Client) MaxPostSize ¶
MaxPostSize returns the server's per-post size limit (read at startup).
func (*Client) Run ¶
Run connects, authenticates, and pumps "posted" events onto Events() until the context is cancelled. The WebSocket is live-only (no replay): on any drop it reconnects with exponential backoff. It closes the events channel exactly once, when ctx is done, so the ingestion consumer can range over it and exit cleanly.
func (*Client) SendTyping ¶
SendTyping posts a best-effort typing indicator to a channel.
func (*Client) SetReaction ¶
SetReaction adds an emoji reaction (by shortcode name) to a post.
func (*Client) UploadFile ¶
func (c *Client) UploadFile(ctx context.Context, channelID, filename, mimeType string, data []byte) (string, error)
UploadFile uploads one file to a channel via POST /api/v4/files (multipart), returning the new file id to attach to a post. The MIME type is set on the form part when known so the server records the right content type.
type Config ¶
type Config struct {
ServerURL string // e.g. https://time.example.com
BotToken string // bot account token; sent as "Authorization: Bearer <token>"
ProxyURL string // explicit per-client proxy (HTTP proxy); "" = direct
// ProfileCacheTTL bounds how long a cached user/channel profile is trusted
// before it is re-read from the server. It MUST be finite: auth_service (the
// SSO access anchor) flips at migration time, and an unbounded cache would
// keep serving the pre-migration value for the life of the process. 0 selects
// defaultProfileCacheTTL.
ProfileCacheTTL time.Duration
}
Config holds the connection settings for a Mattermost/Time server.
type CreatePostReq ¶
type CreatePostReq struct {
ChannelID string
Message string
RootID string
FileIDs []string
IdempotencyKey string
}
CreatePostReq is the caller-facing post-creation request.
type Embed ¶
type Embed struct {
Type string `json:"type"`
Data struct {
PostID string `json:"post_id"`
Post struct {
UserID string `json:"user_id"`
} `json:"post"`
} `json:"data"`
}
Embed is a post embed. For type=="quote", Data.Post is the quoted message.
type FileInfo ¶
type FileInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Extension string `json:"extension"`
Size int64 `json:"size"`
MimeType string `json:"mime_type"`
Width int `json:"width"`
Height int `json:"height"`
}
FileInfo is the subset of a Mattermost FileInfo we use for inbound attachments.
type Post ¶
type Post struct {
ID string `json:"id"`
UserID string `json:"user_id"`
ChannelID string `json:"channel_id"`
RootID string `json:"root_id"`
Message string `json:"message"`
Type string `json:"type"` // "" for user posts; non-empty for system posts
CreateAt int64 `json:"create_at"`
FileIDs []string `json:"file_ids,omitempty"` // attached file ids
Metadata PostMetadata `json:"metadata,omitempty"` // carries embedded FileInfo for attachments
}
Post is the subset of a Mattermost post we read/write.
func (Post) QuotedAuthorID ¶
QuotedAuthorID returns the author id of the first quoted post (reply-to), or "" if the post does not quote/reply to another message.
type PostMetadata ¶
type PostMetadata struct {
Files []FileInfo `json:"files,omitempty"`
Embeds []Embed `json:"embeds,omitempty"`
}
PostMetadata carries enriched post data: attached file info and embeds. A reply that quotes another message carries a "quote" embed whose nested post identifies the quoted author — the signal for reply-to-bot gating (verified present in the live WS event, not just REST).
type PostedEvent ¶
type PostedEvent struct {
Post Post
ChannelType string // "D" (DM) | "O" (open) | "P" (private) | "G" (group)
Mentions []string // user ids mentioned in the post (nil/empty if none)
}
PostedEvent is a parsed "posted" WebSocket event: the inner post plus the channel type (D/O/P/G) the event carried alongside it.
type User ¶
type User struct {
ID string `json:"id"`
Username string `json:"username"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Nickname string `json:"nickname"`
IsBot bool `json:"is_bot"`
AuthService string `json:"auth_service"`
AuthData string `json:"auth_data"`
Email string `json:"email"`
}
User is the subset of /users/{id} we read (identity + display name + the federated-identity fields used for principal resolution).
AuthService is the trust anchor: "" means a local Mattermost account (never linked to a principal — isolation), a non-empty value (e.g. "saml") means an externally-authenticated account. AuthData carries the external subject (the AD login for SAML); it is the join key, lowercased. Email is stored as a principal attribute only and is NEVER used to link identities (a local account can self-claim an email in a trusted-looking domain).