From 9faaa4f0dc23d9001ccd1010a9a51f56ba8d2f9f Mon Sep 17 00:00:00 2001 From: "Brint E. Kriebel" Date: Tue, 20 Dec 2022 22:37:57 -0800 Subject: [PATCH] Add support for edited statuses ActivityPub supports "status.update" for editing statuses. These should be made available for streams. --- cmd/mstdn/cmd_stream.go | 13 ++++++++++++- mastodon_test.go | 1 + streaming.go | 13 +++++++++++++ streaming_test.go | 16 ++++++++++++++++ streaming_ws.go | 6 ++++++ streaming_ws_test.go | 26 ++++++++++++++++++-------- 6 files changed, 66 insertions(+), 9 deletions(-) diff --git a/cmd/mstdn/cmd_stream.go b/cmd/mstdn/cmd_stream.go index a0caa41..03995a3 100644 --- a/cmd/mstdn/cmd_stream.go +++ b/cmd/mstdn/cmd_stream.go @@ -87,7 +87,16 @@ func cmdStream(c *cli.Context) error { if asJSON { json.NewEncoder(c.App.Writer).Encode(e) } else if asSimpleJSON { - if t, ok := e.(*mastodon.UpdateEvent); ok { + switch t := e.(type) { + case *mastodon.UpdateEvent: + json.NewEncoder(c.App.Writer).Encode(&SimpleJSON{ + ID: t.Status.ID, + Username: t.Status.Account.Username, + Acct: t.Status.Account.Acct, + Avatar: t.Status.Account.AvatarStatic, + Content: textContent(t.Status.Content), + }) + case *mastodon.UpdateEditEvent: json.NewEncoder(c.App.Writer).Encode(&SimpleJSON{ ID: t.Status.ID, Username: t.Status.Account.Username, @@ -102,6 +111,8 @@ func cmdStream(c *cli.Context) error { switch t := e.(type) { case *mastodon.UpdateEvent: s.displayStatus(c.App.Writer, t.Status) + case *mastodon.UpdateEditEvent: + s.displayStatus(c.App.Writer, t.Status) case *mastodon.NotificationEvent: // TODO s.displayStatus(c.App.Writer, t.Notification.Status) case *mastodon.ErrorEvent: diff --git a/mastodon_test.go b/mastodon_test.go index a8978b5..5d14a44 100644 --- a/mastodon_test.go +++ b/mastodon_test.go @@ -592,6 +592,7 @@ func TestGetTimelineHomeWithCancel(t *testing.T) { func TestForTheCoverages(t *testing.T) { (*UpdateEvent)(nil).event() + (*UpdateEditEvent)(nil).event() (*NotificationEvent)(nil).event() (*DeleteEvent)(nil).event() (*ErrorEvent)(nil).event() diff --git a/streaming.go b/streaming.go index 2439d67..b109f6c 100644 --- a/streaming.go +++ b/streaming.go @@ -20,6 +20,13 @@ type UpdateEvent struct { func (e *UpdateEvent) event() {} +// UpdateEditEvent is a struct for passing status edit event to app. +type UpdateEditEvent struct { + Status *Status `json:"status"` +} + +func (e *UpdateEditEvent) event() {} + // NotificationEvent is a struct for passing notification event to app. type NotificationEvent struct { Notification *Notification `json:"notification"` @@ -81,6 +88,12 @@ func handleReader(q chan Event, r io.Reader) error { if err == nil { q <- &UpdateEvent{&status} } + case "status.update": + var status Status + err = json.Unmarshal([]byte(token[1]), &status) + if err == nil { + q <- &UpdateEditEvent{&status} + } case "notification": var notification Notification err = json.Unmarshal([]byte(token[1]), ¬ification) diff --git a/streaming_test.go b/streaming_test.go index 8bfe835..a9e90d9 100644 --- a/streaming_test.go +++ b/streaming_test.go @@ -28,6 +28,8 @@ event: notification data: {"type": "mention"} event: delete data: 1234567 +event: status.update +data: {"content": "foo"} :thump `, largeContent)) var wg sync.WaitGroup @@ -51,6 +53,14 @@ data: 1234567 } else { t.Fatalf("bad update content: %q", event.Status.Content) } + case *UpdateEditEvent: + if event.Status.Content == "foo" { + passUpdate = true + } else if event.Status.Content == largeContent { + passUpdateLarge = true + } else { + t.Fatalf("bad update content: %q", event.Status.Content) + } case *NotificationEvent: passNotification = true if event.Notification.Type != "mention" { @@ -125,6 +135,12 @@ data: {"content": "foo"} if event.Status.Content != "foo" { t.Fatalf("want %q but %q", "foo", event.Status.Content) } + case *UpdateEditEvent: + cnt++ + passUpdate = true + if event.Status.Content != "foo" { + t.Fatalf("want %q but %q", "foo", event.Status.Content) + } } } if cnt != 1 { diff --git a/streaming_ws.go b/streaming_ws.go index bd42bf9..5658bbf 100644 --- a/streaming_ws.go +++ b/streaming_ws.go @@ -127,6 +127,12 @@ func (c *WSClient) handleWS(ctx context.Context, rawurl string, q chan Event) er if err == nil { q <- &UpdateEvent{Status: &status} } + case "status.update": + var status Status + err = json.Unmarshal([]byte(s.Payload.(string)), &status) + if err == nil { + q <- &UpdateEditEvent{Status: &status} + } case "notification": var notification Notification err = json.Unmarshal([]byte(s.Payload.(string)), ¬ification) diff --git a/streaming_ws_test.go b/streaming_ws_test.go index 41fa1d5..7e78890 100644 --- a/streaming_ws_test.go +++ b/streaming_ws_test.go @@ -80,6 +80,13 @@ func wsMock(w http.ResponseWriter, r *http.Request) { return } + err = conn.WriteMessage(websocket.TextMessage, + []byte(`{"event":"status.update","payload":"{\"content\":\"bar\"}"}`)) + if err != nil { + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + err = conn.WriteMessage(websocket.TextMessage, []byte(`{"event":"notification","payload":"{\"id\":123}"}`)) if err != nil { @@ -112,20 +119,20 @@ func wsTest(t *testing.T, q chan Event, cancel func()) { for e := range q { events = append(events, e) } - if len(events) != 6 { - t.Fatalf("result should be four: %d", len(events)) + if len(events) != 7 { + t.Fatalf("result should be seven: %d", len(events)) } if events[0].(*UpdateEvent).Status.Content != "foo" { t.Fatalf("want %q but %q", "foo", events[0].(*UpdateEvent).Status.Content) } - if events[1].(*NotificationEvent).Notification.ID != "123" { - t.Fatalf("want %q but %q", "123", events[1].(*NotificationEvent).Notification.ID) + if events[1].(*UpdateEditEvent).Status.Content != "bar" { + t.Fatalf("want %q but %q", "bar", events[1].(*UpdateEditEvent).Status.Content) } - if events[2].(*DeleteEvent).ID != "1234567" { - t.Fatalf("want %q but %q", "1234567", events[2].(*DeleteEvent).ID) + if events[2].(*NotificationEvent).Notification.ID != "123" { + t.Fatalf("want %q but %q", "123", events[2].(*NotificationEvent).Notification.ID) } - if errorEvent, ok := events[3].(*ErrorEvent); !ok { - t.Fatalf("should be fail: %v", errorEvent.err) + if events[3].(*DeleteEvent).ID != "1234567" { + t.Fatalf("want %q but %q", "1234567", events[3].(*DeleteEvent).ID) } if errorEvent, ok := events[4].(*ErrorEvent); !ok { t.Fatalf("should be fail: %v", errorEvent.err) @@ -133,6 +140,9 @@ func wsTest(t *testing.T, q chan Event, cancel func()) { if errorEvent, ok := events[5].(*ErrorEvent); !ok { t.Fatalf("should be fail: %v", errorEvent.err) } + if errorEvent, ok := events[6].(*ErrorEvent); !ok { + t.Fatalf("should be fail: %v", errorEvent.err) + } } func TestStreamingWS(t *testing.T) {