github.com/TIBCOSoftware/flogo-lib@v0.5.9/engine/channels/channels.go (about)

     1  package channels
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/TIBCOSoftware/flogo-lib/logger"
     8  	"strings"
     9  	"strconv"
    10  )
    11  
    12  var channels = make(map[string]*channelImpl)
    13  var active bool
    14  
    15  type Channel interface {
    16  	RegisterCallback(callback OnMessage) error
    17  	Publish(msg interface{})
    18  	PublishNoWait(msg interface{}) bool
    19  }
    20  
    21  type OnMessage func(msg interface{})
    22  
    23  // Creates a new channel, channels have to be created before the engine starts
    24  func New(name string, bufferSize int) (Channel, error) {
    25  
    26  	if active {
    27  		return nil, errors.New("cannot create channel after engine has been started")
    28  	}
    29  
    30  	if _, dup := channels[name]; dup {
    31  		return nil, errors.New("channel already exists: " + name)
    32  	}
    33  
    34  	channel := &channelImpl{name: name, ch: make(chan interface{}, bufferSize)}
    35  	channels[name] = channel
    36  
    37  	return channel, nil
    38  
    39  }
    40  
    41  // Count returns the number of channels
    42  func Count() int {
    43  	return len(channels)
    44  }
    45  
    46  // Get gets the named channel
    47  func Get(name string) Channel {
    48  	return channels[name]
    49  }
    50  
    51  func Start() error {
    52  	active = true
    53  
    54  	var started []*channelImpl
    55  
    56  	for _, channel := range channels {
    57  		err := channel.Start()
    58  		if err != nil {
    59  			for _, startedChannel := range started {
    60  				startedChannel.Stop()
    61  			}
    62  			return fmt.Errorf("failed to start channel '%s', error: %s", channel.name, err.Error())
    63  		}
    64  		logger.Debugf("Started Engine Channel: %s", channel.name)
    65  		started = append(started, channel)
    66  	}
    67  
    68  	return nil
    69  }
    70  
    71  func Stop() error {
    72  	for _, channel := range channels {
    73  		err := channel.Stop()
    74  		if err != nil {
    75  			logger.Warnf("error stopping channel '%s', error: %s", channel.name, err.Error())
    76  		}
    77  	}
    78  
    79  	active = false
    80  
    81  	return nil
    82  }
    83  
    84  type channelImpl struct {
    85  	name      string
    86  	callbacks []OnMessage
    87  	ch        chan interface{}
    88  	active    bool
    89  }
    90  
    91  func (c *channelImpl) Start() error {
    92  	c.active = true
    93  	go c.processEvents()
    94  
    95  	return nil
    96  }
    97  
    98  func (c *channelImpl) Stop() error {
    99  	close(c.ch)
   100  	c.active = false
   101  
   102  	return nil
   103  }
   104  
   105  func (c *channelImpl) RegisterCallback(callback OnMessage) error {
   106  
   107  	if c.active {
   108  		return errors.New("cannot add listener after channel has been started")
   109  	}
   110  
   111  	c.callbacks = append(c.callbacks, callback)
   112  	return nil
   113  }
   114  
   115  func (c *channelImpl) Publish(msg interface{}) {
   116  	c.ch <- msg
   117  }
   118  
   119  func (c *channelImpl) PublishNoWait(msg interface{}) bool {
   120  
   121  	sent := false
   122  	select {
   123  	case c.ch <- msg:
   124  		sent = true
   125  	default:
   126  		sent = false
   127  	}
   128  
   129  	return sent
   130  }
   131  
   132  func (c *channelImpl) processEvents() {
   133  
   134  	for {
   135  		select {
   136  		case val, ok := <-c.ch:
   137  			if !ok {
   138  				//channel closed, so return
   139  				return
   140  			}
   141  
   142  			for _, callback := range c.callbacks {
   143  				go callback(val)
   144  			}
   145  		}
   146  	}
   147  }
   148  
   149  // Decode decodes the channel descriptor
   150  func Decode(channelDescriptor string) (string, int){
   151  	idx := strings.Index(channelDescriptor,":")
   152  	buffSize := 0
   153  	chanName := channelDescriptor
   154  
   155  	if idx > 0 {
   156  		bSize, err:= strconv.Atoi(channelDescriptor[idx+1:])
   157  		if err != nil {
   158  			logger.Warnf("invalid channel buffer size '%s', defaulting to buffer size of %d", channelDescriptor[idx+1:], buffSize)
   159  		} else {
   160  			buffSize = bSize
   161  		}
   162  
   163  		chanName = channelDescriptor[:idx]
   164  	}
   165  
   166  	return chanName, buffSize
   167  }