2022-02-27 06:57:13 +00:00
|
|
|
package topic
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"sync"
|
|
|
|
|
2022-02-27 10:10:21 +00:00
|
|
|
"git.wntrmute.dev/kyle/sensenet/config"
|
2022-02-27 06:57:13 +00:00
|
|
|
"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
|
2022-02-27 10:10:21 +00:00
|
|
|
log.Println("registered handler for topic", topic)
|
2022-02-27 06:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
2022-02-27 10:10:21 +00:00
|
|
|
log.Println("creating tables")
|
|
|
|
|
|
|
|
for _, topic := range registry.topics {
|
2022-02-27 06:57:13 +00:00
|
|
|
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)
|
|
|
|
}
|
2022-02-27 10:10:21 +00:00
|
|
|
|
|
|
|
func ValidateTopics(publishers map[string]*config.Publisher) bool {
|
|
|
|
valid := true
|
|
|
|
|
|
|
|
for _, pub := range publishers {
|
|
|
|
for _, topic := range pub.Topics {
|
|
|
|
if _, ok := registry.topics[topic]; !ok {
|
|
|
|
log.Printf("missing handler for topic %s", topic)
|
|
|
|
valid = valid && ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return valid
|
|
|
|
}
|