From bd3d33f6f357181591c4935dc05c27f52d201cea Mon Sep 17 00:00:00 2001 From: Natalie Bridgers Date: Wed, 30 Sep 2026 20:32:48 -0500 Subject: [PATCH] delete teleports when lookup fails --- pkg/atproto/firehose.go | 46 ++++++++++++++++------------- pkg/atproto/teleport_delete_test.go | 40 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 pkg/atproto/teleport_delete_test.go diff --git a/pkg/atproto/firehose.go b/pkg/atproto/firehose.go index bea2a5370..2b6cb25ba 100644 --- a/pkg/atproto/firehose.go +++ b/pkg/atproto/firehose.go @@ -774,26 +774,7 @@ func (atsync *ATProtoSynchronizer) handleIndexedOps(ctx context.Context, evt *in } if collection.String() == constants.PLACE_STREAM_LIVE_TELEPORT { - teleport, err := atsync.Model.GetTeleportByURI(uri) - if err != nil { - log.Error(ctx, "failed to get teleport before deleting", "err", err) - continue - } - err = atsync.Model.DeleteTeleport(ctx, uri) - if err != nil { - log.Error(ctx, "failed to delete teleport", "err", err) - continue - } - if teleport != nil { - cancelMsg := map[string]any{ - "$type": "place.stream.livestream#teleportCanceled", - "teleportUri": uri, - "cid": teleport.CID, - "reason": "deleted", - } - atsync.Bus.Publish(teleport.RepoDID, cancelMsg) - atsync.Bus.Publish(teleport.TargetDID, cancelMsg) - } + atsync.handleTeleportDelete(ctx, uri) } if collection.String() == constants.PLACE_STREAM_MODERATION_PERMISSION { @@ -924,6 +905,31 @@ func (atsync *ATProtoSynchronizer) handleIndexedOps(ctx context.Context, evt *in return complete } +func (atsync *ATProtoSynchronizer) handleTeleportDelete(ctx context.Context, uri string) { + teleport, err := atsync.Model.GetTeleportByURI(uri) + if err != nil { + log.Error(ctx, "failed to get teleport before deleting", "err", err, "uri", uri) + teleport = nil + } + + if err := atsync.Model.DeleteTeleport(ctx, uri); err != nil { + log.Error(ctx, "failed to delete teleport", "err", err, "uri", uri) + return + } + if teleport == nil { + return + } + + cancelMsg := map[string]any{ + "$type": "place.stream.livestream#teleportCanceled", + "teleportUri": uri, + "cid": teleport.CID, + "reason": "deleted", + } + atsync.Bus.Publish(teleport.RepoDID, cancelMsg) + atsync.Bus.Publish(teleport.TargetDID, cancelMsg) +} + // reviveRepo un-parks a repo we had written off. A commit event is proof the // account is back -- a deactivated, suspended, or deleted repo cannot write -- // so the terminal status goes away and the ordinary wedge logic (an empty diff --git a/pkg/atproto/teleport_delete_test.go b/pkg/atproto/teleport_delete_test.go new file mode 100644 index 000000000..3a53485ce --- /dev/null +++ b/pkg/atproto/teleport_delete_test.go @@ -0,0 +1,40 @@ +package atproto + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "stream.place/streamplace/pkg/model" +) + +func TestDeleteTeleportWhenLookupFails(t *testing.T) { + ctx := context.Background() + mod, err := model.MakeDB(":memory:") + require.NoError(t, err) + dbModel := mod.(*model.DBModel) + db, err := dbModel.DB.DB() + require.NoError(t, err) + defer db.Close() + + const uri = "at://did:plc:streamer/place.stream.live.teleport/1" + require.NoError(t, mod.CreateTeleport(ctx, &model.Teleport{ + URI: uri, + CID: "bafyreiteleport", + RepoDID: "did:plc:streamer", + TargetDID: "did:plc:target", + })) + + // The teleport lookup preloads its repo associations. Removing that table + // makes the lookup fail while leaving the teleports table available to delete. + require.NoError(t, dbModel.DB.Migrator().DropTable(&model.Repo{})) + _, err = mod.GetTeleportByURI(uri) + require.Error(t, err) + + atsync := &ATProtoSynchronizer{Model: mod} + atsync.handleTeleportDelete(ctx, uri) + + got, err := mod.GetTeleportByURI(uri) + require.NoError(t, err) + require.Nil(t, got) +} -- 2.54.0