github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/realtime/realtime.go (about)

     1  package realtime
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/cozy/cozy-stack/pkg/config/config"
     7  	"github.com/cozy/cozy-stack/pkg/prefixer"
     8  )
     9  
    10  // Basic data events
    11  const (
    12  	EventCreate = "CREATED"
    13  	EventUpdate = "UPDATED"
    14  	EventDelete = "DELETED"
    15  	EventNotify = "NOTIFIED"
    16  )
    17  
    18  // Doc is an interface for a object with DocType, ID
    19  type Doc interface {
    20  	ID() string
    21  	DocType() string
    22  }
    23  
    24  // Event is the basic message structure manipulated by the realtime package
    25  type Event struct {
    26  	Cluster int    `json:"cluster,omitempty"`
    27  	Domain  string `json:"domain"`
    28  	Prefix  string `json:"prefix,omitempty"`
    29  	Verb    string `json:"verb"`
    30  	Doc     Doc    `json:"doc"`
    31  	OldDoc  Doc    `json:"old,omitempty"`
    32  }
    33  
    34  func newEvent(db prefixer.Prefixer, verb string, doc Doc, oldDoc Doc) *Event {
    35  	return &Event{
    36  		Cluster: db.DBCluster(),
    37  		Domain:  db.DomainName(),
    38  		Prefix:  db.DBPrefix(),
    39  		Verb:    verb,
    40  		Doc:     doc,
    41  		OldDoc:  oldDoc,
    42  	}
    43  }
    44  
    45  // DBCluster implements the prefixer.Prefixer interface.
    46  func (e *Event) DBCluster() int {
    47  	return e.Cluster
    48  }
    49  
    50  // DBPrefix implements the prefixer.Prefixer interface.
    51  func (e *Event) DBPrefix() string {
    52  	if e.Prefix != "" {
    53  		return e.Prefix
    54  	}
    55  	return e.Domain
    56  }
    57  
    58  // DomainName implements the prefixer.Prefixer interface.
    59  func (e *Event) DomainName() string {
    60  	return e.Domain
    61  }
    62  
    63  // The following API is inspired by https://github.com/gocontrib/pubsub
    64  
    65  // Hub is an object which recive events and calls appropriate listener
    66  type Hub interface {
    67  	// Emit is used by publishers when an event occurs
    68  	Publish(db prefixer.Prefixer, verb string, doc Doc, oldDoc Doc)
    69  
    70  	// Subscriber creates a Subscriber that can subscribe to several
    71  	// doctypes. Call its Close method to Unsubscribe.
    72  	Subscriber(prefixer.Prefixer) *Subscriber
    73  
    74  	// SubscribeFirehose adds a listener for all events that happened in this
    75  	// cozy-stack process.
    76  	SubscribeFirehose() *Subscriber
    77  
    78  	subscribe(sub *Subscriber, key string)
    79  	unsubscribe(sub *Subscriber, key string)
    80  	watch(sub *Subscriber, key, id string)
    81  	unwatch(sub *Subscriber, key, id string)
    82  	close(sub *Subscriber)
    83  }
    84  
    85  var globalHubMu sync.Mutex
    86  var globalHub Hub
    87  
    88  // GetHub returns the global hub
    89  func GetHub() Hub {
    90  	globalHubMu.Lock()
    91  	defer globalHubMu.Unlock()
    92  	if globalHub != nil {
    93  		return globalHub
    94  	}
    95  	cli := config.GetConfig().Realtime
    96  	if cli == nil {
    97  		globalHub = newMemHub()
    98  	} else {
    99  		globalHub = newRedisHub(cli)
   100  	}
   101  	return globalHub
   102  }