Skip to content

Commit

Permalink
Move api impls for rust/js to their own packages
Browse files Browse the repository at this point in the history
  • Loading branch information
kegsay committed Jan 10, 2024
1 parent 9873926 commit 7530c4d
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
js-sdk/node_modules
js-sdk/dist
internal/api/dist
internal/api/js/dist
__pycache__
2 changes: 1 addition & 1 deletion FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Internally, we use Vite to bundle JS SDK into a single page app, which has no UI

#### Add console logs

If you want to add console logging to the JS SDK, it is easiest to _modify the bundled output_ as it is not minified. To do this, `grep` for function names in `internal/api/dist/assests/index.....js` then use an editor to add `console.log` lines. These lines will appear in JS SDK log files.
If you want to add console logging to the JS SDK, it is easiest to _modify the bundled output_ as it is not minified. To do this, `grep` for function names in `internal/api/js/dist/assests/index.....js` then use an editor to add `console.log` lines. These lines will appear in JS SDK log files.

### Rust SDK FFI

Expand Down
8 changes: 4 additions & 4 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,15 @@ func CheckEventHasMembership(target, membership string) func(e Event) bool {
const ansiRedForeground = "\x1b[31m"
const ansiResetForeground = "\x1b[39m"

// errorf is a wrapper around t.Errorf which prints the failing error message in red.
func errorf(t *testing.T, format string, args ...any) {
// Errorf is a wrapper around t.Errorf which prints the failing error message in red.
func Errorf(t *testing.T, format string, args ...any) {
t.Helper()
format = ansiRedForeground + format + ansiResetForeground
t.Errorf(format, args...)
}

// fatalf is a wrapper around t.Fatalf which prints the failing error message in red.
func fatalf(t *testing.T, format string, args ...any) {
// Fatalf is a wrapper around t.Fatalf which prints the failing error message in red.
func Fatalf(t *testing.T, format string, args ...any) {
t.Helper()
format = ansiRedForeground + format + ansiResetForeground
t.Fatalf(format, args...)
Expand Down
48 changes: 26 additions & 22 deletions internal/api/js.go → internal/api/js/js.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package api
package js

import (
"context"
Expand All @@ -18,6 +18,7 @@ import (

"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/chromedp"
"github.com/matrix-org/complement-crypto/internal/api"
"github.com/matrix-org/complement-crypto/internal/chrome"
"github.com/matrix-org/complement/must"
"github.com/tidwall/gjson"
Expand Down Expand Up @@ -55,19 +56,19 @@ type JSClient struct {
ctx context.Context
cancel func()
baseJSURL string
listeners map[int32]func(roomID string, ev Event)
listeners map[int32]func(roomID string, ev api.Event)
listenerID atomic.Int32
userID string
}

func NewJSClient(t *testing.T, opts ClientCreationOpts) (Client, error) {
func NewJSClient(t *testing.T, opts api.ClientCreationOpts) (api.Client, error) {
// start a headless chrome
ctx, cancel := chromedp.NewContext(context.Background(), chromedp.WithBrowserOption(
chromedp.WithBrowserLogf(colorifyError), chromedp.WithBrowserErrorf(colorifyError), //chromedp.WithBrowserDebugf(log.Printf),
))

jsc := &JSClient{
listeners: make(map[int32]func(roomID string, ev Event)),
listeners: make(map[int32]func(roomID string, ev api.Event)),
userID: opts.UserID,
}
// Listen for console logs for debugging AND to communicate live updates
Expand Down Expand Up @@ -200,7 +201,7 @@ func NewJSClient(t *testing.T, opts ClientCreationOpts) (Client, error) {
jsc.ctx = ctx
jsc.cancel = cancel
jsc.baseJSURL = baseJSURL
return &LoggedClient{Client: jsc}, nil
return &api.LoggedClient{Client: jsc}, nil
}

// Close is called to clean up resources.
Expand All @@ -209,14 +210,14 @@ func NewJSClient(t *testing.T, opts ClientCreationOpts) (Client, error) {
// log messages.
func (c *JSClient) Close(t *testing.T) {
c.cancel()
c.listeners = make(map[int32]func(roomID string, ev Event))
c.listeners = make(map[int32]func(roomID string, ev api.Event))
}

func (c *JSClient) UserID() string {
return c.userID
}

func (c *JSClient) MustGetEvent(t *testing.T, roomID, eventID string) Event {
func (c *JSClient) MustGetEvent(t *testing.T, roomID, eventID string) api.Event {
t.Helper()
// serialised output (if encrypted):
// {
Expand All @@ -231,7 +232,7 @@ func (c *JSClient) MustGetEvent(t *testing.T, roomID, eventID string) Event {
})[0].toJSON());
`, roomID, eventID))
if !gjson.Valid(evSerialised) {
fatalf(t, "MustGetEvent(%s, %s) %s (js): invalid event, got %s", roomID, eventID, c.userID, evSerialised)
api.Fatalf(t, "MustGetEvent(%s, %s) %s (js): invalid event, got %s", roomID, eventID, c.userID, evSerialised)
}
result := gjson.Parse(evSerialised)
decryptedEvent := result.Get("decrypted")
Expand All @@ -240,7 +241,7 @@ func (c *JSClient) MustGetEvent(t *testing.T, roomID, eventID string) Event {
}
encryptedEvent := result.Get("encrypted")
//fmt.Printf("DECRYPTED: %s\nENCRYPTED: %s\n\n", decryptedEvent.Raw, encryptedEvent.Raw)
ev := Event{
ev := api.Event{
ID: decryptedEvent.Get("event_id").Str,
Text: decryptedEvent.Get("content.body").Str,
Sender: decryptedEvent.Get("sender").Str,
Expand Down Expand Up @@ -271,7 +272,7 @@ func (c *JSClient) StartSyncing(t *testing.T) (stopSyncing func()) {
};
window.__client.on("sync", fn);`, CONSOLE_LOG_CONTROL_STRING))
ch := make(chan struct{})
cancel := c.listenForUpdates(func(roomID string, ev Event) {
cancel := c.listenForUpdates(func(roomID string, ev api.Event) {
if roomID != "sync" {
return
}
Expand All @@ -280,7 +281,7 @@ func (c *JSClient) StartSyncing(t *testing.T) (stopSyncing func()) {
chrome.AwaitExecute(t, c.ctx, `window.__client.startClient({});`)
select {
case <-time.After(5 * time.Second):
fatalf(t, "[%s](js) took >5s to StartSyncing", c.userID)
api.Fatalf(t, "[%s](js) took >5s to StartSyncing", c.userID)
case <-ch:
}
cancel()
Expand Down Expand Up @@ -349,7 +350,7 @@ func (c *JSClient) MustBackupKeys(t *testing.T) (recoveryKey string) {
return recoveryKey.encodedPrivateKey;
})()`)
if err != nil {
fatalf(t, "MustBackupKeys: %s", err)
api.Fatalf(t, "MustBackupKeys: %s", err)
}
// the backup loop which sends keys will wait between 0-10s before uploading keys...
// See https://github.com/matrix-org/matrix-js-sdk/blob/49624d5d7308e772ebee84322886a39d2e866869/src/rust-crypto/backup.ts#L319
Expand Down Expand Up @@ -377,7 +378,7 @@ func (c *JSClient) MustLoadBackup(t *testing.T, recoveryKey string) {
})()`, recoveryKey))
}

func (c *JSClient) WaitUntilEventInRoom(t *testing.T, roomID string, checker func(e Event) bool) Waiter {
func (c *JSClient) WaitUntilEventInRoom(t *testing.T, roomID string, checker func(e api.Event) bool) api.Waiter {
t.Helper()
return &jsTimelineWaiter{
roomID: roomID,
Expand All @@ -393,11 +394,11 @@ func (c *JSClient) Logf(t *testing.T, format string, args ...interface{}) {
t.Logf(format, args...)
}

func (c *JSClient) Type() ClientTypeLang {
return ClientTypeJS
func (c *JSClient) Type() api.ClientTypeLang {
return api.ClientTypeJS
}

func (c *JSClient) listenForUpdates(callback func(roomID string, ev Event)) (cancel func()) {
func (c *JSClient) listenForUpdates(callback func(roomID string, ev api.Event)) (cancel func()) {
id := c.listenerID.Add(1)
c.listeners[id] = callback
return func() {
Expand All @@ -407,14 +408,14 @@ func (c *JSClient) listenForUpdates(callback func(roomID string, ev Event)) (can

type jsTimelineWaiter struct {
roomID string
checker func(e Event) bool
checker func(e api.Event) bool
client *JSClient
}

func (w *jsTimelineWaiter) Wait(t *testing.T, s time.Duration) {
t.Helper()
updates := make(chan bool, 3)
cancel := w.client.listenForUpdates(func(roomID string, ev Event) {
cancel := w.client.listenForUpdates(func(roomID string, ev api.Event) {
if w.roomID != roomID {
return
}
Expand All @@ -436,17 +437,20 @@ func (w *jsTimelineWaiter) Wait(t *testing.T, s time.Duration) {
for {
timeLeft := s - time.Since(start)
if timeLeft <= 0 {
fatalf(t, "%s (js): Wait[%s]: timed out", w.client.userID, w.roomID)
api.Fatalf(t, "%s (js): Wait[%s]: timed out", w.client.userID, w.roomID)
}
select {
case <-time.After(timeLeft):
fatalf(t, "%s (js): Wait[%s]: timed out", w.client.userID, w.roomID)
api.Fatalf(t, "%s (js): Wait[%s]: timed out", w.client.userID, w.roomID)
case <-updates:
return
}
}
}

const ansiRedForeground = "\x1b[31m"
const ansiResetForeground = "\x1b[39m"

func colorifyError(format string, args ...any) {
format = ansiRedForeground + time.Now().Format(time.RFC3339) + " " + format + ansiResetForeground
fmt.Printf(format, args...)
Expand All @@ -460,8 +464,8 @@ type JSEvent struct {
ID string `json:"event_id"`
}

func jsToEvent(j JSEvent) Event {
var ev Event
func jsToEvent(j JSEvent) api.Event {
var ev api.Event
ev.Sender = j.Sender
ev.ID = j.ID
switch j.Type {
Expand Down
41 changes: 21 additions & 20 deletions internal/api/rust.go → internal/api/rust/rust.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package api
package rust

import (
"fmt"
Expand All @@ -7,6 +7,7 @@ import (
"testing"
"time"

"github.com/matrix-org/complement-crypto/internal/api"
"github.com/matrix-org/complement-crypto/rust/matrix_sdk_ffi"
"github.com/matrix-org/complement/must"
"golang.org/x/exp/slices"
Expand All @@ -28,7 +29,7 @@ var zero uint32
type RustRoomInfo struct {
stream *matrix_sdk_ffi.TaskHandle
room *matrix_sdk_ffi.Room
timeline []*Event
timeline []*api.Event
}

type RustClient struct {
Expand All @@ -41,7 +42,7 @@ type RustClient struct {
userID string
}

func NewRustClient(t *testing.T, opts ClientCreationOpts, ssURL string) (Client, error) {
func NewRustClient(t *testing.T, opts api.ClientCreationOpts, ssURL string) (api.Client, error) {
t.Logf("NewRustClient[%s] creating...", opts.UserID)
ab := matrix_sdk_ffi.NewClientBuilder().HomeserverUrl(opts.BaseURL).SlidingSyncProxy(&ssURL)
client, err := ab.Build()
Expand All @@ -64,7 +65,7 @@ func NewRustClient(t *testing.T, opts ClientCreationOpts, ssURL string) (Client,
roomsMu: &sync.RWMutex{},
}
c.Logf(t, "NewRustClient[%s] created client", opts.UserID)
return &LoggedClient{Client: c}, nil
return &api.LoggedClient{Client: c}, nil
}

func (c *RustClient) Close(t *testing.T) {
Expand All @@ -80,16 +81,16 @@ func (c *RustClient) Close(t *testing.T) {
c.FFIClient.Destroy()
}

func (c *RustClient) MustGetEvent(t *testing.T, roomID, eventID string) Event {
func (c *RustClient) MustGetEvent(t *testing.T, roomID, eventID string) api.Event {
t.Helper()
room := c.findRoom(t, roomID)
timelineItem, err := room.Timeline().GetEventTimelineItemByEventId(eventID)
if err != nil {
fatalf(t, "MustGetEvent(rust) %s (%s, %s): %s", c.userID, roomID, eventID, err)
api.Fatalf(t, "MustGetEvent(rust) %s (%s, %s): %s", c.userID, roomID, eventID, err)
}
ev := eventTimelineItemToEvent(timelineItem)
if ev == nil {
fatalf(t, "MustGetEvent(rust) %s (%s, %s): found timeline item but failed to convert it to an Event", c.userID, roomID, eventID)
api.Fatalf(t, "MustGetEvent(rust) %s (%s, %s): found timeline item but failed to convert it to an Event", c.userID, roomID, eventID)
}
return *ev
}
Expand All @@ -113,7 +114,7 @@ func (c *RustClient) StartSyncing(t *testing.T) (stopSyncing func()) {
for !isSyncing {
select {
case <-time.After(5 * time.Second):
fatalf(t, "[%s](rust) timed out after 5s StartSyncing", c.userID)
api.Fatalf(t, "[%s](rust) timed out after 5s StartSyncing", c.userID)
case state := <-genericListener.ch:
fmt.Println(state)
switch state.(type) {
Expand Down Expand Up @@ -173,7 +174,7 @@ func (c *RustClient) MustLoadBackup(t *testing.T, recoveryKey string) {
must.NotError(t, "Recover", c.FFIClient.Encryption().Recover(recoveryKey))
}

func (c *RustClient) WaitUntilEventInRoom(t *testing.T, roomID string, checker func(Event) bool) Waiter {
func (c *RustClient) WaitUntilEventInRoom(t *testing.T, roomID string, checker func(api.Event) bool) api.Waiter {
t.Helper()
c.ensureListening(t, roomID)
return &timelineWaiter{
Expand All @@ -183,8 +184,8 @@ func (c *RustClient) WaitUntilEventInRoom(t *testing.T, roomID string, checker f
}
}

func (c *RustClient) Type() ClientTypeLang {
return ClientTypeRust
func (c *RustClient) Type() api.ClientTypeLang {
return api.ClientTypeRust
}

// SendMessage sends the given text as an m.room.message with msgtype:m.text into the given
Expand All @@ -193,7 +194,7 @@ func (c *RustClient) SendMessage(t *testing.T, roomID, text string) (eventID str
t.Helper()
eventID, err := c.TrySendMessage(t, roomID, text)
if err != nil {
fatalf(t, err.Error())
api.Fatalf(t, err.Error())
}
return eventID
}
Expand Down Expand Up @@ -316,7 +317,7 @@ func (c *RustClient) ensureListening(t *testing.T, roomID string) *matrix_sdk_ff
// we need a timeline listener before we can send messages
result := r.Timeline().AddListener(&timelineListener{fn: func(diff []*matrix_sdk_ffi.TimelineDiff) {
timeline := c.rooms[roomID].timeline
var newEvents []*Event
var newEvents []*api.Event
c.Logf(t, "[%s]AddTimelineListener[%s] TimelineDiff len=%d", c.userID, roomID, len(diff))
for _, d := range diff {
switch d.Change() {
Expand Down Expand Up @@ -378,7 +379,7 @@ func (c *RustClient) ensureListening(t *testing.T, roomID string) *matrix_sdk_ff
c.Logf(t, "TimelineDiff change: %+v", e)
}
}})
events := make([]*Event, len(result.Items))
events := make([]*api.Event, len(result.Items))
for i := range result.Items {
events[i] = timelineItemToEvent(result.Items[i])
}
Expand All @@ -403,7 +404,7 @@ func (c *RustClient) listenForUpdates(callback func(roomID string)) (cancel func

type timelineWaiter struct {
roomID string
checker func(e Event) bool
checker func(e api.Event) bool
client *RustClient
}

Expand Down Expand Up @@ -452,11 +453,11 @@ func (w *timelineWaiter) Wait(t *testing.T, s time.Duration) {
for {
timeLeft := s - time.Since(start)
if timeLeft <= 0 {
fatalf(t, "%s (rust): Wait[%s]: timed out", w.client.userID, w.roomID)
api.Fatalf(t, "%s (rust): Wait[%s]: timed out", w.client.userID, w.roomID)
}
select {
case <-time.After(timeLeft):
fatalf(t, "%s (rust): Wait[%s]: timed out", w.client.userID, w.roomID)
api.Fatalf(t, "%s (rust): Wait[%s]: timed out", w.client.userID, w.roomID)
case <-updates:
return
}
Expand All @@ -471,23 +472,23 @@ func (l *timelineListener) OnUpdate(diff []*matrix_sdk_ffi.TimelineDiff) {
l.fn(diff)
}

func timelineItemToEvent(item *matrix_sdk_ffi.TimelineItem) *Event {
func timelineItemToEvent(item *matrix_sdk_ffi.TimelineItem) *api.Event {
ev := item.AsEvent()
if ev == nil { // e.g day divider
return nil
}
return eventTimelineItemToEvent(*ev)
}

func eventTimelineItemToEvent(item *matrix_sdk_ffi.EventTimelineItem) *Event {
func eventTimelineItemToEvent(item *matrix_sdk_ffi.EventTimelineItem) *api.Event {
if item == nil {
return nil
}
eventID := ""
if item.EventId() != nil {
eventID = *item.EventId()
}
complementEvent := Event{
complementEvent := api.Event{
ID: eventID,
Sender: item.Sender(),
}
Expand Down
4 changes: 2 additions & 2 deletions rebuild_js_sdk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ then
fi

(cd js-sdk && yarn add $1 && yarn install && yarn build)
rm -rf ./internal/api/dist || echo 'no dist directory detected';
cp -r ./js-sdk/dist/. ./internal/api/dist
rm -rf ./internal/api/js/dist || echo 'no dist directory detected';
cp -r ./js-sdk/dist/. ./internal/api/js/dist
Loading

0 comments on commit 7530c4d

Please sign in to comment.