github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/pubsub/pubsub.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Package pubsub implements the API for streaming pubsub messages between api
     5  // servers.
     6  package pubsub
     7  
     8  import (
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/api/base"
    12  	"github.com/juju/juju/apiserver/params"
    13  )
    14  
    15  // MessageWriter is the interface that allows sending pub/sub messges to the
    16  // server.
    17  type MessageWriter interface {
    18  	// ForwardMessage forwards the given message to the server.
    19  	ForwardMessage(*params.PubSubMessage) error
    20  	Close() error
    21  }
    22  
    23  // API provides access to the pubsub API.
    24  type API struct {
    25  	connector base.StreamConnector
    26  }
    27  
    28  // NewAPI creates a new client-side pubsub API.
    29  func NewAPI(connector base.StreamConnector) *API {
    30  	return &API{connector: connector}
    31  }
    32  
    33  // OpenMessageWriter returns a new message writer interface value which must
    34  // be closed when finished with.
    35  func (api *API) OpenMessageWriter() (MessageWriter, error) {
    36  	conn, err := api.connector.ConnectStream("/pubsub", nil)
    37  	if err != nil {
    38  		return nil, errors.Annotatef(err, "cannot connect to /pubsub")
    39  	}
    40  	messageWriter := &writer{conn}
    41  	go messageWriter.readLoop()
    42  	return messageWriter, nil
    43  }
    44  
    45  type writer struct {
    46  	conn base.Stream
    47  }
    48  
    49  // readLoop is necessary for the client to process websocket control messages.
    50  // Close() is safe to call concurrently.
    51  func (w *writer) readLoop() {
    52  	for {
    53  		if _, _, err := w.conn.NextReader(); err != nil {
    54  			w.conn.Close()
    55  			break
    56  		}
    57  	}
    58  }
    59  
    60  func (w *writer) ForwardMessage(m *params.PubSubMessage) error {
    61  	// Note: due to the fire-and-forget nature of the
    62  	// pubsub API, it is possible that when the
    63  	// connection dies, any messages that were "in-flight"
    64  	// will not be received on the server side.
    65  	if err := w.conn.WriteJSON(m); err != nil {
    66  		return errors.Annotatef(err, "cannot send pubsub message")
    67  	}
    68  	return nil
    69  }
    70  
    71  func (w *writer) Close() error {
    72  	return w.conn.Close()
    73  }