func (r *ProtocolLXD) GetEvents() (*EventListener, error) {
	// Prevent anything else from interacting with the listeners
	r.eventListenersLock.Lock()
	defer r.eventListenersLock.Unlock()

	// Setup a new listener
	listener := EventListener{
		r:        r,
		chActive: make(chan bool),
	}

	if r.eventListeners != nil {
		// There is an existing Go routine setup, so just add another target
		r.eventListeners = append(r.eventListeners, &listener)
		return &listener, nil
	}

	// Initialize the list if needed
	r.eventListeners = []*EventListener{}

	// Setup a new connection with LXD
	url, err := r.setQueryAttributes("/events")
	if err != nil {
		return nil, err
	}

	conn, err := r.websocket(url)
	if err != nil {
		return nil, err
	}

	// Add the listener
	r.eventListeners = append(r.eventListeners, &listener)

	// Spawn a watcher that will close the websocket connection after all
	// listeners are gone.
	stopCh := make(chan struct{}, 0)
	go func() {
		for {
			select {
			case <-time.After(time.Minute):
			case <-stopCh:
				break
			}

			r.eventListenersLock.Lock()
			if len(r.eventListeners) == 0 {
				// We don't need the connection anymore, disconnect
				conn.Close()

				r.eventListeners = nil
				r.eventListenersLock.Unlock()
				break
			}
			r.eventListenersLock.Unlock()
		}
	}()

	// Spawn the listener
	go func() {
		for {
			_, data, err := conn.ReadMessage()
			if err != nil {
				// Prevent anything else from interacting with the listeners
				r.eventListenersLock.Lock()
				defer r.eventListenersLock.Unlock()

				// Tell all the current listeners about the failure
				for _, listener := range r.eventListeners {
					listener.err = err
					listener.disconnected = true
					close(listener.chActive)
				}

				// And remove them all from the list
				r.eventListeners = nil

				conn.Close()
				close(stopCh)

				return
			}

			// Attempt to unpack the message
			event := api.Event{}
			err = json.Unmarshal(data, &event)
			if err != nil {
				continue
			}

			// Extract the message type
			if event.Type == "" {
				continue
			}

			// Send the message to all handlers
			r.eventListenersLock.Lock()
			for _, listener := range r.eventListeners {
				listener.targetsLock.Lock()
				for _, target := range listener.targets {
					if target.types != nil && !shared.StringInSlice(event.Type, target.types) {
						continue
					}

					go target.function(event)
				}
				listener.targetsLock.Unlock()
			}
			r.eventListenersLock.Unlock()
		}
	}()

	return &listener, nil
}
func (r *ProtocolLXD) GetEvents() (*EventListener, error) {
	
	r.eventListenersLock.Lock()
	defer r.eventListenersLock.Unlock()

	
	listener := EventListener{
		r:        r,
		chActive: make(chan bool),
	}

	if r.eventListeners != nil {
		
		r.eventListeners = append(r.eventListeners, &listener)
		return &listener, nil
	}

	
	r.eventListeners = []*EventListener{}

	
	url, err := r.setQueryAttributes("/events")
	if err != nil {
		return nil, err
	}

	conn, err := r.websocket(url)
	if err != nil {
		return nil, err
	}

	
	r.eventListeners = append(r.eventListeners, &listener)

	
	
	stopCh := make(chan struct{}, 0)
	go func() {
		for {
			select {
			case <-time.After(time.Minute):
			case <-stopCh:
				break
			}

			r.eventListenersLock.Lock()
			if len(r.eventListeners) == 0 {
				
				conn.Close()

				r.eventListeners = nil
				r.eventListenersLock.Unlock()
				break
			}
			r.eventListenersLock.Unlock()
		}
	}()

	
	go func() {
		for {
			_, data, err := conn.ReadMessage()
			if err != nil {
				
				r.eventListenersLock.Lock()
				defer r.eventListenersLock.Unlock()

				
				for _, listener := range r.eventListeners {
					listener.err = err
					listener.disconnected = true
					close(listener.chActive)
				}

				
				r.eventListeners = nil

				conn.Close()
				close(stopCh)

				return
			}

			
			event := api.Event{}
			err = json.Unmarshal(data, &event)
			if err != nil {
				continue
			}

			
			if event.Type == "" {
				continue
			}

			
			r.eventListenersLock.Lock()
			for _, listener := range r.eventListeners {
				listener.targetsLock.Lock()
				for _, target := range listener.targets {
					if target.types != nil && !shared.StringInSlice(event.Type, target.types) {
						continue
					}

					go target.function(event)
				}
				listener.targetsLock.Unlock()
			}
			r.eventListenersLock.Unlock()
		}
	}()

	return &listener, nil
}
func ( r * ProtocolLXD ) GetEvents ( ) ( * EventListener , error ) { // Prevent anything else from interacting with the listeners r . eventListenersLock . Lock ( ) defer r . eventListenersLock . Unlock ( ) // Setup a new listener listener := EventListener { r : r , chActive : make ( chan bool ) , } if r . eventListeners != nil { // There is an existing Go routine setup, so just add another target r . eventListeners = append ( r . eventListeners , & listener ) return & listener , nil } // Initialize the list if needed r . eventListeners = [ ] * EventListener { } // Setup a new connection with LXD url , err := r . setQueryAttributes ( " " ) if err != nil { return nil , err } conn , err := r . websocket ( url ) if err != nil { return nil , err } // Add the listener r . eventListeners = append ( r . eventListeners , & listener ) // Spawn a watcher that will close the websocket connection after all // listeners are gone. stopCh := make ( chan struct { } , 0 ) go func ( ) { for { select { case <- time . After ( time . Minute ) : case <- stopCh : break } r . eventListenersLock . Lock ( ) if len ( r . eventListeners ) == 0 { // We don't need the connection anymore, disconnect conn . Close ( ) r . eventListeners = nil r . eventListenersLock . Unlock ( ) break } r . eventListenersLock . Unlock ( ) } } ( ) // Spawn the listener go func ( ) { for { _ , data , err := conn . ReadMessage ( ) if err != nil { // Prevent anything else from interacting with the listeners r . eventListenersLock . Lock ( ) defer r . eventListenersLock . Unlock ( ) // Tell all the current listeners about the failure for _ , listener := range r . eventListeners { listener . err = err listener . disconnected = true close ( listener . chActive ) } // And remove them all from the list r . eventListeners = nil conn . Close ( ) close ( stopCh ) return } // Attempt to unpack the message event := api . Event { } err = json . Unmarshal ( data , & event ) if err != nil { continue } // Extract the message type if event . Type == " " { continue } // Send the message to all handlers r . eventListenersLock . Lock ( ) for _ , listener := range r . eventListeners { listener . targetsLock . Lock ( ) for _ , target := range listener . targets { if target . types != nil && ! shared . StringInSlice ( event . Type , target . types ) { continue } go target . function ( event ) } listener . targetsLock . Unlock ( ) } r . eventListenersLock . Unlock ( ) } } ( ) return & listener , nil }
// Event handling functions
// GetEvents connects to the LXD monitoring interface
Event handling functions GetEvents connects to the LXD monitoring interface