Skip to content

Commit eb7cd2d

Browse files
committed
feat: implement matrix adapter fetch.
1 parent 881d425 commit eb7cd2d

16 files changed

Lines changed: 618 additions & 84 deletions

internal/email/adapter_fetch.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (a *Adapter) fetchMessages(ctx context.Context, startUID uint32) ([]relay.M
5757
func (a *Adapter) getCursor(ctx context.Context) (uint32, uint32, error) {
5858
var uid, uidValidity uint32
5959
err := store.Client().WithTx(ctx, func(ctx context.Context, tx store.Tx) error {
60-
u, v, err := tx.Cursor(ctx, a.cfg.Username, a.cfg.Mailbox)
60+
u, v, err := tx.Email().Cursor(ctx, a.cfg.Username, a.cfg.Mailbox)
6161
if err != nil {
6262
return err
6363
}
@@ -71,7 +71,7 @@ func (a *Adapter) getCursor(ctx context.Context) (uint32, uint32, error) {
7171
// setCursor durably persists the given UID and UIDValidity to the store.
7272
func (a *Adapter) setCursor(ctx context.Context, uid, uidValidity uint32) error {
7373
return store.Client().WithTx(ctx, func(ctx context.Context, tx store.Tx) error {
74-
return tx.SetCursor(ctx, a.cfg.Username, a.cfg.Mailbox, uid, uidValidity)
74+
return tx.Email().SetCursor(ctx, a.cfg.Username, a.cfg.Mailbox, uid, uidValidity)
7575
})
7676
}
7777

internal/email/adapter_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func TestGetCursor(t *testing.T) {
6161
// Seed the cursor through the store directly, so the test exercises only the
6262
// read path.
6363
err := store.Client().WithTx(ctx, func(ctx context.Context, tx store.Tx) error {
64-
return tx.SetCursor(ctx, a.cfg.Username, a.cfg.Mailbox, wantUID, wantValidity)
64+
return tx.Email().SetCursor(ctx, a.cfg.Username, a.cfg.Mailbox, wantUID, wantValidity)
6565
})
6666
if err != nil {
6767
t.Fatalf("seed cursor: %v", err)
@@ -96,7 +96,7 @@ func TestSetCursor(t *testing.T) {
9696
var gotUID, gotValidity uint32
9797
err := store.Client().WithTx(ctx, func(ctx context.Context, tx store.Tx) error {
9898
var err error
99-
gotUID, gotValidity, err = tx.Cursor(ctx, a.cfg.Username, a.cfg.Mailbox)
99+
gotUID, gotValidity, err = tx.Email().Cursor(ctx, a.cfg.Username, a.cfg.Mailbox)
100100
return err
101101
})
102102
if err != nil {

internal/matrix/adapter.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import (
77
"bolte-bridge/internal/relay"
88
)
99

10-
// Adapter is the Matrix medium edge of the bridge. It owns the Client it talks
11-
// to outright: the transport is an implementation detail of this package, so
12-
// callers configure the adapter and never name the Client themselves.
13-
//
14-
// Its Fetch, Send, and Commit methods are not implemented yet.
10+
// Adapter is the Matrix medium edge of the bridge.
1511
type Adapter struct {
1612
client Client
13+
cfg Config
1714
}
1815

16+
// Compile-time assertion that Adapter satisfies core.Adapter.
17+
var _ core.Adapter = (*Adapter)(nil)
18+
1919
// NewAdapter builds an Adapter and the Client it owns from ctx and cfg,
2020
// reporting any configuration or initialization error from Client construction.
2121
func NewAdapter(ctx context.Context, cfg Config) (*Adapter, error) {
@@ -34,27 +34,24 @@ func (a *Adapter) Medium() relay.Medium {
3434
return relay.MediumMatrix
3535
}
3636

37-
// Fetch will fetch Matrix events past the committed sync token and translate
37+
// Fetch will fetch Matrix events past the committed EventID and translate
3838
// them into relay messages, advancing only the in-memory cursor.
39-
func (a *Adapter) Fetch(_ context.Context) ([]relay.Message, error) {
40-
return nil, nil
39+
func (a *Adapter) Fetch(ctx context.Context) ([]relay.Message, error) {
40+
return a.fetch(ctx)
4141
}
4242

4343
// Send will translate a routed message into a Matrix event, send it to the
44-
// configured room, and return the event ID assigned by the homeserver.
44+
// configured room, and return the EventID assigned by the homeserver.
4545
func (a *Adapter) Send(_ context.Context, _ relay.RoutedMessage) (string, error) {
4646
return "", nil
4747
}
4848

49-
// Commit will durably advance the Matrix sync token to cursor. An empty cursor
49+
// Commit will durably advance the Matrix EventID cursor. An empty cursor
5050
// commits everything returned by the preceding Fetch.
5151
func (a *Adapter) Commit(_ context.Context, _ string) error {
5252
return nil
5353
}
5454

55-
// Compile-time assertion that Adapter satisfies core.Adapter.
56-
var _ core.Adapter = (*Adapter)(nil)
57-
5855
// Close closes the underlying Matrix client.
5956
func (a *Adapter) Close(ctx context.Context) error {
6057
return a.client.Close(ctx)

internal/matrix/adapter_fetch.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package matrix
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"errors"
7+
8+
"bolte-bridge/internal/relay"
9+
"bolte-bridge/internal/store"
10+
)
11+
12+
func (a *Adapter) fetch(ctx context.Context) ([]relay.Message, error) {
13+
eventID, err := a.getCursor(ctx)
14+
switch {
15+
case errors.Is(err, sql.ErrNoRows):
16+
lastID, err := a.client.LastEvent(ctx)
17+
if err != nil {
18+
return nil, err
19+
}
20+
return nil, a.setCursor(ctx, lastID)
21+
case err != nil:
22+
return nil, err
23+
default:
24+
return a.fetchMessages(ctx, eventID)
25+
}
26+
}
27+
28+
// getCursor retrieves the current EventID from the store.
29+
func (a *Adapter) getCursor(ctx context.Context) (string, error) {
30+
var eventID string
31+
err := store.Client().WithTx(ctx, func(ctx context.Context, tx store.Tx) error {
32+
e, err := tx.Matrix().Cursor(ctx, a.cfg.ServerName, a.cfg.RoomID)
33+
if err != nil {
34+
return err
35+
}
36+
eventID = e
37+
return nil
38+
})
39+
return eventID, err
40+
}
41+
42+
// setCursor retrieves the current EventID from the store.
43+
func (a *Adapter) setCursor(ctx context.Context, eventID string) error {
44+
return store.Client().WithTx(ctx, func(ctx context.Context, tx store.Tx) error {
45+
return tx.Matrix().SetCursor(ctx, a.cfg.ServerName, a.cfg.RoomID, eventID)
46+
})
47+
}
48+
49+
func (a *Adapter) fetchMessages(ctx context.Context, eventID string) ([]relay.Message, error) {
50+
rawEvents, err := a.client.Fetch(ctx, eventID)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
return rawEventsToRelayMessages(rawEvents), nil
56+
}
57+
58+
func rawEventsToRelayMessages(
59+
rawEvents []RawEvent,
60+
) []relay.Message {
61+
messages := make([]relay.Message, len(rawEvents))
62+
63+
for i, raw := range rawEvents {
64+
messages[i] = rawEventToRelayMessage(raw)
65+
}
66+
return messages
67+
}
68+
69+
func rawEventToRelayMessage(raw RawEvent) relay.Message {
70+
return relay.Message{
71+
Sender: relay.Identity{Address: relay.Address{
72+
Mode: relay.MediumMatrix,
73+
ID: raw.Sender,
74+
}},
75+
MessageID: raw.EventID,
76+
ThreadID: raw.ReplyTo,
77+
Body: raw.Body,
78+
}
79+
}

0 commit comments

Comments
 (0)