package topic import ( "context" "fmt" "log" "sync" "github.com/jackc/pgconn" ) type Database interface { Exec(ctx context.Context, query string, args ...interface{}) (pgconn.CommandTag, error) } type Topic struct { CreateTable func(ctx context.Context, db Database) error Store func(ctx context.Context, db Database, packet *Packet) error } var registry = struct { topics map[string]*Topic lock *sync.Mutex }{ topics: map[string]*Topic{}, lock: new(sync.Mutex), } func Register(topic string, handler *Topic) { registry.lock.Lock() defer registry.lock.Unlock() if _, ok := registry.topics[topic]; ok { panic(fmt.Sprintf("attempt to register pht '%s' that has already been registered", topic)) } registry.topics[topic] = handler } type Packet struct { Topic string Publisher string Received int64 // unix timestamp Payload []byte } // Setup ensures all the required tables are created. func Setup(ctx context.Context, db Database) error { registry.lock.Lock() defer registry.lock.Unlock() for key, topic := range registry.topics { log.Println("running CreateTable for", key) err := topic.CreateTable(ctx, db) if err != nil { return err } } return nil } func Publish(ctx context.Context, db Database, packet *Packet) error { topic, ok := registry.topics[packet.Topic] if !ok { return fmt.Errorf("topic: no handler for topic '%s' [%x]", packet.Topic, packet.Payload) } return topic.Store(ctx, db, packet) }