···
+
"github.com/bluesky-social/jetstream/pkg/client"
+
"github.com/bluesky-social/jetstream/pkg/models"
+
"github.com/sotangled/tangled/jetstream"
+
// Simple in-memory implementation of DB interface
+
func (m *MemoryDB) GetLastTimeUs() (int64, error) {
+
return time.Now().UnixMicro(), nil
+
return m.lastTimeUs, nil
+
func (m *MemoryDB) SaveLastTimeUs(ts int64) error {
+
func (m *MemoryDB) UpdateLastTimeUs(ts int64) error {
+
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
+
// Get query URL from flag
+
flag.StringVar(&queryURL, "query-url", "", "Jetstream query URL containing DIDs")
+
logger.Error("No query URL provided, use --query-url flag")
+
// Extract wantedDids parameters
+
didParams := strings.Split(queryURL, "&wantedDids=")
+
dids := make([]string, 0, len(didParams)-1)
+
for i, param := range didParams {
+
// Skip the first part (the base URL with cursor)
+
dids = append(dids, param)
+
collections := []string{"sh.tangled.publicKey", "sh.tangled.knot.member"}
+
// Create client configuration
+
cfg := client.DefaultClientConfig()
+
cfg.WebsocketURL = "wss://jetstream2.us-west.bsky.network/subscribe"
+
cfg.WantedCollections = collections
+
// Create jetstream client
+
jsClient, err := jetstream.NewJetstreamClient(
+
logger.Error("Failed to create jetstream client", "error", err)
+
jsClient.UpdateDids(dids)
+
// Create a context that will be canceled on SIGINT or SIGTERM
+
ctx, cancel := context.WithCancel(context.Background())
+
// Setup signal handling with a buffered channel
+
sigCh := make(chan os.Signal, 1)
+
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
+
// Process function for events
+
processFunc := func(ctx context.Context, event *models.Event) error {
+
// Log the event details
+
logger.Info("Received event",
+
"collection", event.Commit.Collection,
+
"rkey", event.Commit.RKey,
+
"time_us", event.TimeUS,
+
// Save the last time_us
+
if err := db.UpdateLastTimeUs(event.TimeUS); err != nil {
+
logger.Error("Failed to update last time_us", "error", err)
+
if err := jsClient.StartJetstream(ctx, processFunc); err != nil {
+
logger.Error("Failed to start jetstream", "error", err)
+
// Wait for signal instead of context.Done()
+
logger.Info("Received signal, shutting down", "signal", sig)
+
cancel() // Cancel context after receiving signal
+
// Shutdown gracefully with a timeout
+
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
+
done := make(chan struct{})
+
logger.Info("Jetstream client shut down gracefully")
+
case <-shutdownCtx.Done():
+
logger.Warn("Shutdown timed out, forcing exit")