Fix deployment issues and add threads, numbered watchlist, search URL encoding
- Fix SQLite connection string (drop query param, use explicit PRAGMA) - Register sqlite3-fk-wal driver for mautrix cryptohelper (pure Go, no CGO) - Fetch DeviceID via /whoami when using bare access token - Log cross-signing results at Warn/Info instead of Debug - Post deals into Matrix threads: Game Deals, DLC Deals, Epic Free Games - Add numbered watchlist; !extend and !unwatch accept list numbers - URL-encode search queries for multi-word !search commands - Add GetConfig/SetConfig helpers for persistent thread event IDs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -124,6 +124,15 @@ func New(cfg ClientConfig) (*Client, error) {
|
||||
c.client = client
|
||||
}
|
||||
|
||||
// Ensure DeviceID is set (required by cryptohelper)
|
||||
if c.client.DeviceID == "" {
|
||||
resp, err := c.client.Whoami(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("whoami failed (needed for device ID): %w", err)
|
||||
}
|
||||
c.client.DeviceID = resp.DeviceID
|
||||
}
|
||||
|
||||
// Set up E2EE
|
||||
if cfg.CryptoDBPath != "" {
|
||||
ch, err := cryptohelper.NewCryptoHelper(c.client, []byte("pastel_pickle_key"), cfg.CryptoDBPath)
|
||||
@@ -176,15 +185,21 @@ func (c *Client) bootstrapCrossSigning() {
|
||||
}
|
||||
}, "")
|
||||
if err != nil {
|
||||
slog.Debug("cross-signing: key upload skipped (may already exist)", "error", err)
|
||||
slog.Warn("cross-signing: key upload failed (may already exist)", "error", err)
|
||||
} else {
|
||||
slog.Info("cross-signing: keys uploaded")
|
||||
}
|
||||
|
||||
if err := mach.SignOwnDevice(context.Background(), mach.OwnIdentity()); err != nil {
|
||||
slog.Debug("cross-signing: sign own device skipped", "error", err)
|
||||
slog.Warn("cross-signing: sign own device failed", "error", err)
|
||||
} else {
|
||||
slog.Info("cross-signing: own device signed")
|
||||
}
|
||||
|
||||
if err := mach.SignOwnMasterKey(context.Background()); err != nil {
|
||||
slog.Debug("cross-signing: sign master key skipped", "error", err)
|
||||
slog.Warn("cross-signing: sign master key failed", "error", err)
|
||||
} else {
|
||||
slog.Info("cross-signing: master key signed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +264,7 @@ func (c *Client) JoinedRooms() ([]string, error) {
|
||||
return rooms, nil
|
||||
}
|
||||
|
||||
// SendDeal sends a formatted deal message to a room.
|
||||
// SendDeal sends a formatted deal message to a room (top-level, no thread).
|
||||
func (c *Client) SendDeal(roomID, plainText, html string) error {
|
||||
content := &event.MessageEventContent{
|
||||
MsgType: event.MsgText,
|
||||
@@ -264,6 +279,43 @@ func (c *Client) SendDeal(roomID, plainText, html string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateThread sends a root message and returns its event ID for use as a thread root.
|
||||
func (c *Client) CreateThread(roomID, text string) (string, error) {
|
||||
content := &event.MessageEventContent{
|
||||
MsgType: event.MsgText,
|
||||
Body: text,
|
||||
}
|
||||
resp, err := c.client.SendMessageEvent(context.Background(), id.RoomID(roomID), event.EventMessage, content)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create thread: %w", err)
|
||||
}
|
||||
return resp.EventID.String(), nil
|
||||
}
|
||||
|
||||
// SendDealInThread sends a formatted deal message as a reply in a thread.
|
||||
func (c *Client) SendDealInThread(roomID, threadEventID, plainText, html string) error {
|
||||
evtID := id.EventID(threadEventID)
|
||||
content := &event.MessageEventContent{
|
||||
MsgType: event.MsgText,
|
||||
Body: plainText,
|
||||
Format: event.FormatHTML,
|
||||
FormattedBody: html,
|
||||
RelatesTo: &event.RelatesTo{
|
||||
Type: event.RelThread,
|
||||
EventID: evtID,
|
||||
InReplyTo: &event.InReplyTo{
|
||||
EventID: evtID,
|
||||
},
|
||||
IsFallingBack: true,
|
||||
},
|
||||
}
|
||||
_, err := c.client.SendMessageEvent(context.Background(), id.RoomID(roomID), event.EventMessage, content)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send threaded deal: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendNotice sends a notice message to a room (non-highlighting).
|
||||
func (c *Client) SendNotice(roomID, text string) error {
|
||||
content := &event.MessageEventContent{
|
||||
|
||||
36
internal/matrix/sqlitedriver.go
Normal file
36
internal/matrix/sqlitedriver.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package matrix
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
|
||||
sqlite "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
type fkWALDriver struct {
|
||||
inner *sqlite.Driver
|
||||
}
|
||||
|
||||
func (d *fkWALDriver) Open(name string) (driver.Conn, error) {
|
||||
conn, err := d.inner.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
execer := conn.(driver.Execer)
|
||||
for _, pragma := range []string{
|
||||
"PRAGMA foreign_keys = ON",
|
||||
"PRAGMA journal_mode = WAL",
|
||||
"PRAGMA synchronous = NORMAL",
|
||||
"PRAGMA busy_timeout = 5000",
|
||||
} {
|
||||
if _, err := execer.Exec(pragma, nil); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
sql.Register("sqlite3-fk-wal", &fkWALDriver{inner: &sqlite.Driver{}})
|
||||
}
|
||||
Reference in New Issue
Block a user