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 }