36a485ea26
Backend extends MatrixService with Start()/Stop()/ListRooms()/LoadTimeline()/
SendText()/SendMarkdown(). On login the service initialises the crypto store
(cryptohelper, Olm/Megolm via goolm build tag) and a sync loop that fans
events out through Wails events ("matrix:event", "matrix:error"). Pickle
key is 32 random bytes hex-encoded in the OS keyring alongside the access
token, so the crypto SQLite store survives restarts.
Vendors 4 fresh helpers from fn_registry/functions/infra/:
matrix_crypto_init.go (//go:build goolm || libolm)
matrix_sync_service.go
matrix_message_send.go
matrix_room_list.go
Plus the existing 3 (mas_oidc_loopback, keyring_token_store, matrix_client_init).
go-sqlite3 driver pulled explicitly via sqlite_driver.go.
Frontend rewires HomeScreen as a 3-zone AppShell (sidebar / timeline /
composer). useMatrixRooms polls + reacts to the sync stream; useMatrixTimeline
loads the last 50 events of the selected room and appends live ones. New
components: RoomList, Timeline, EventBubble, Composer. Composer supports
plain text (default) and a markdown toggle; Enter sends, Shift+Enter newline.
wails.json now passes "build:tags": "goolm" by default. Tested with
wails build -tags goolm on linux/amd64 and windows/amd64.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 lines
1.6 KiB
Go
60 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func userStoreDir(userID string) string {
|
|
cfg, err := os.UserConfigDir()
|
|
if err != nil {
|
|
cfg = filepath.Join(os.Getenv("HOME"), ".config")
|
|
}
|
|
slug := strings.NewReplacer("@", "", ":", "_", "/", "_").Replace(userID)
|
|
return filepath.Join(cfg, "matrix_client_pc", slug)
|
|
}
|
|
|
|
// whoami issues GET /_matrix/client/v3/account/whoami against the homeserver with the
|
|
// provided access_token and returns (user_id, device_id, err). It's used before
|
|
// MatrixClientInit because mautrix.NewClient wants user_id up front.
|
|
func whoami(ctx context.Context, homeserver, accessToken string) (string, string, error) {
|
|
if ctx == nil {
|
|
ctx = context.Background()
|
|
}
|
|
u, err := url.JoinPath(homeserver, "/_matrix/client/v3/account/whoami")
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("joinpath: %w", err)
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
cl := &http.Client{Timeout: 15 * time.Second}
|
|
resp, err := cl.Do(req)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
if resp.StatusCode != 200 {
|
|
return "", "", fmt.Errorf("whoami: %s: %s", resp.Status, body)
|
|
}
|
|
var out struct {
|
|
UserID string `json:"user_id"`
|
|
DeviceID string `json:"device_id"`
|
|
}
|
|
if err := json.Unmarshal(body, &out); err != nil {
|
|
return "", "", fmt.Errorf("whoami parse: %w", err)
|
|
}
|
|
return out.UserID, out.DeviceID, nil
|
|
}
|