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 }