func (op *remoteOperation) CancelTarget() error {
	if op.targetOp == nil {
		return fmt.Errorf("No associated target operation")
	}
	return op.targetOp.Cancel()
}
CancelTarget attempts to cancel the target operation
package lxd
import (
	"encoding/json"
	"fmt"
	"sync"
	"github.com/gorilla/websocket"
	"github.com/lxc/lxd/shared/api"
)
type operation struct {
	api.Operation
	r            *ProtocolLXD
	listener     *EventListener
	handlerReady bool
	handlerLock  sync.Mutex
	chActive chan bool
}
func (op *operation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	err := op.setupListener()
	if err != nil {
		return nil, err
	}
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()
	if op.StatusCode.IsFinal() {
		return nil, nil
	}
	wrapped := func(data interface{}) {
		newOp := op.extractOperation(data)
		if newOp == nil {
			return
		}
		function(*newOp)
	}
	return op.listener.AddHandler([]string{"operation"}, wrapped)
}
func (op *operation) Cancel() error {
	return op.r.DeleteOperation(op.ID)
}
func (op *operation) Get() api.Operation {
	return op.Operation
}
func (op *operation) GetWebsocket(secret string) (*websocket.Conn, error) {
	return op.r.GetOperationWebsocket(op.ID, secret)
}
func (op *operation) RemoveHandler(target *EventTarget) error {
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()
	if op.listener == nil {
		return nil
	}
	return op.listener.RemoveHandler(target)
}
func (op *operation) Refresh() error {
	if op.handlerReady {
		return nil
	}
	newOp, _, err := op.r.GetOperation(op.ID)
	if err != nil {
		return err
	}
	op.Operation = *newOp
	return nil
}
func (op *operation) Wait() error {
	if op.StatusCode.IsFinal() {
		if op.Err != "" {
			return fmt.Errorf(op.Err)
		}
		return nil
	}
	err := op.setupListener()
	if err != nil {
		return err
	}
	<-op.chActive
	if op.Err != "" {
		return fmt.Errorf(op.Err)
	}
	return nil
}
func (op *operation) setupListener() error {
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()
	if op.handlerReady {
		return nil
	}
	if op.listener == nil {
		listener, err := op.r.GetEvents()
		if err != nil {
			return err
		}
		op.listener = listener
	}
	chReady := make(chan bool)
	_, err := op.listener.AddHandler([]string{"operation"}, func(data interface{}) {
		<-chReady
		newOp := op.extractOperation(data)
		if newOp == nil {
			return
		}
		op.handlerLock.Lock()
		defer op.handlerLock.Unlock()
		if op.listener == nil {
			return
		}
		op.Operation = *newOp
		if op.StatusCode.IsFinal() {
			op.listener.Disconnect()
			op.listener = nil
			close(op.chActive)
			return
		}
	})
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)
		return err
	}
	go func() {
		<-chReady
		op.handlerLock.Lock()
		listener := op.listener
		if listener == nil {
			op.handlerLock.Unlock()
			return
		}
		op.handlerLock.Unlock()
		select {
		case <-listener.chActive:
			op.handlerLock.Lock()
			if op.listener != nil {
				op.Err = fmt.Sprintf("%v", listener.err)
				close(op.chActive)
			}
			op.handlerLock.Unlock()
		case <-op.chActive:
			return
		}
	}()
	err = op.Refresh()
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)
		return err
	}
	if op.StatusCode.IsFinal() {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		op.handlerReady = true
		close(chReady)
		if op.Err != "" {
			return fmt.Errorf(op.Err)
		}
		return nil
	}
	op.handlerReady = true
	close(chReady)
	return nil
}
func (op *operation) extractOperation(data interface{}) *api.Operation {
	meta, ok := data.(map[string]interface{})["metadata"]
	if !ok {
		return nil
	}
	encoded, err := json.Marshal(meta)
	if err != nil {
		return nil
	}
	newOp := api.Operation{}
	err = json.Unmarshal(encoded, &newOp)
	if err != nil {
		return nil
	}
	if newOp.ID != op.ID {
		return nil
	}
	return &newOp
}
type remoteOperation struct {
	targetOp Operation
	handlers []func(api.Operation)
	chDone chan bool
	chPost chan bool
	err    error
}
func (op *remoteOperation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	var err error
	var target *EventTarget
	if op.targetOp != nil {
		target, err = op.targetOp.AddHandler(function)
		if err != nil {
			return nil, err
		}
	} else {
		target = &EventTarget{
			function: func(interface{}) { function(api.Operation{}) },
			types:    []string{"operation"},
		}
	}
	op.handlers = append(op.handlers, function)
	return target, nil
}