github.com/nibnait/go-learn@v0.0.0-20220227013611-dfa47ea6d2da/src/test/chapter/ch7/43_microkernel/agent.go (about)

     1  package microkernel
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"sync"
     9  )
    10  
    11  const (
    12  	Waiting = iota
    13  	Running
    14  )
    15  
    16  var WrongStateError = errors.New("can not take the operation in the current state")
    17  
    18  type CollectorsError struct {
    19  	CollectorErrors []error
    20  }
    21  
    22  func (ce CollectorsError) Error() string {
    23  	var strs []string
    24  	for _, err := range ce.CollectorErrors {
    25  		strs = append(strs, err.Error())
    26  	}
    27  	return strings.Join(strs, ";")
    28  }
    29  
    30  type Event struct {
    31  	Source  string
    32  	Content string
    33  }
    34  
    35  type EventReceiver interface {
    36  	OnEvent(evt Event)
    37  }
    38  
    39  type Collector interface {
    40  	Init(evtReceiver EventReceiver) error
    41  	Start(agtCtx context.Context) error
    42  	Stop() error
    43  	Destory() error
    44  }
    45  
    46  type Agent struct {
    47  	collectors map[string]Collector
    48  	evtBuf     chan Event
    49  	cancel     context.CancelFunc
    50  	ctx        context.Context
    51  	state      int
    52  }
    53  
    54  func (agt *Agent) EventProcessGroutine() {
    55  	var evtSeg [10]Event
    56  	for {
    57  		for i := 0; i < 10; i++ {
    58  			select {
    59  			case evtSeg[i] = <-agt.evtBuf:
    60  			case <-agt.ctx.Done():
    61  				return
    62  			}
    63  		}
    64  		fmt.Println(evtSeg)
    65  	}
    66  
    67  }
    68  
    69  func NewAgent(sizeEvtBuf int) *Agent {
    70  	agt := Agent{
    71  		collectors: map[string]Collector{},
    72  		evtBuf:     make(chan Event, sizeEvtBuf),
    73  		state:      Waiting,
    74  	}
    75  
    76  	return &agt
    77  }
    78  
    79  func (agt *Agent) RegisterCollector(name string, collector Collector) error {
    80  	if agt.state != Waiting {
    81  		return WrongStateError
    82  	}
    83  	agt.collectors[name] = collector
    84  	return collector.Init(agt)
    85  }
    86  
    87  func (agt *Agent) startCollectors() error {
    88  	var err error
    89  	var errs CollectorsError
    90  	var mutex sync.Mutex
    91  
    92  	for name, collector := range agt.collectors {
    93  		go func(name string, collector Collector, ctx context.Context) {
    94  			defer func() {
    95  				mutex.Unlock()
    96  			}()
    97  			err = collector.Start(ctx)
    98  			mutex.Lock()
    99  			if err != nil {
   100  				errs.CollectorErrors = append(errs.CollectorErrors,
   101  					errors.New(name+":"+err.Error()))
   102  			}
   103  		}(name, collector, agt.ctx)
   104  	}
   105  	if len(errs.CollectorErrors) == 0 {
   106  		return nil
   107  	}
   108  	return errs
   109  }
   110  
   111  func (agt *Agent) stopCollectors() error {
   112  	var err error
   113  	var errs CollectorsError
   114  	for name, collector := range agt.collectors {
   115  		if err = collector.Stop(); err != nil {
   116  			errs.CollectorErrors = append(errs.CollectorErrors,
   117  				errors.New(name+":"+err.Error()))
   118  		}
   119  	}
   120  	if len(errs.CollectorErrors) == 0 {
   121  		return nil
   122  	}
   123  
   124  	return errs
   125  }
   126  
   127  func (agt *Agent) destoryCollectors() error {
   128  	var err error
   129  	var errs CollectorsError
   130  	for name, collector := range agt.collectors {
   131  		if err = collector.Destory(); err != nil {
   132  			errs.CollectorErrors = append(errs.CollectorErrors,
   133  				errors.New(name+":"+err.Error()))
   134  		}
   135  	}
   136  	if len(errs.CollectorErrors) == 0 {
   137  		return nil
   138  	}
   139  	return errs
   140  }
   141  
   142  func (agt *Agent) Start() error {
   143  	if agt.state != Waiting {
   144  		return WrongStateError
   145  	}
   146  	agt.state = Running
   147  	agt.ctx, agt.cancel = context.WithCancel(context.Background())
   148  	go agt.EventProcessGroutine()
   149  	return agt.startCollectors()
   150  }
   151  
   152  func (agt *Agent) Stop() error {
   153  	if agt.state != Running {
   154  		return WrongStateError
   155  	}
   156  	agt.state = Waiting
   157  	agt.cancel()
   158  	return agt.stopCollectors()
   159  }
   160  
   161  func (agt *Agent) Destory() error {
   162  	if agt.state != Waiting {
   163  		return WrongStateError
   164  	}
   165  	return agt.destoryCollectors()
   166  }
   167  
   168  func (agt *Agent) OnEvent(evt Event) {
   169  	agt.evtBuf <- evt
   170  }