git.zd.zone/hrpc/hrpc@v0.0.12/plugin/plugin.go (about)

     1  package plugin
     2  
     3  import (
     4  	"sync"
     5  
     6  	"git.zd.zone/hrpc/hrpc/uerror"
     7  )
     8  
     9  var (
    10  	ErrMissingPlugin = uerror.New(1001, "dependence check failed because missing plugins")
    11  	ErrDependsCycle  = uerror.New(1002, "depends cycle")
    12  )
    13  
    14  type Plugin interface {
    15  	Load() error
    16  	Name() string
    17  
    18  	DependsOn() []string
    19  }
    20  
    21  type plugin struct {
    22  	plugins        map[string]Plugin
    23  	orderedPlugins chan Plugin
    24  	statuses       map[string]bool
    25  
    26  	mu sync.RWMutex
    27  }
    28  
    29  var p = plugin{
    30  	plugins:  map[string]Plugin{},
    31  	statuses: map[string]bool{},
    32  }
    33  
    34  func Register(plugins ...Plugin) {
    35  	p.mu.Lock()
    36  	defer p.mu.Unlock()
    37  
    38  	for _, plugin := range plugins {
    39  		p.plugins[plugin.Name()] = plugin
    40  		p.statuses[plugin.Name()] = false
    41  	}
    42  }
    43  
    44  func Setup() error {
    45  	p.mu.Lock()
    46  	defer p.mu.Unlock()
    47  
    48  	p.orderedPlugins = make(chan Plugin, len(p.plugins))
    49  	for _, plugin := range p.plugins {
    50  		p.orderedPlugins <- plugin
    51  	}
    52  
    53  	num := len(p.orderedPlugins)
    54  	for num > 0 {
    55  		for i := 0; i < num; i++ {
    56  			plug := <-p.orderedPlugins
    57  			if plug.DependsOn() == nil || len(plug.DependsOn()) == 0 {
    58  				if err := plug.Load(); err != nil {
    59  					return err
    60  				}
    61  				p.statuses[plug.Name()] = true
    62  			} else {
    63  				allowed := true
    64  				for _, dependName := range plug.DependsOn() {
    65  					if !p.statuses[dependName] {
    66  						// has depends that unloaded
    67  						allowed = false
    68  						p.orderedPlugins <- plug
    69  						break
    70  					}
    71  				}
    72  				if allowed {
    73  					if err := plug.Load(); err != nil {
    74  						return err
    75  					}
    76  					p.statuses[plug.Name()] = true
    77  				}
    78  			}
    79  		}
    80  		if len(p.orderedPlugins) == num {
    81  			return ErrDependsCycle
    82  		}
    83  		num = len(p.orderedPlugins)
    84  	}
    85  	return nil
    86  }