github.com/pavlo67/common@v0.5.3/common/joiner/joiner_runtime/runtime.go (about) 1 package joiner_runtime 2 3 import ( 4 "fmt" 5 "log" 6 "reflect" 7 "sync" 8 9 "github.com/pkg/errors" 10 11 "github.com/pavlo67/common/common" 12 "github.com/pavlo67/common/common/joiner" 13 "github.com/pavlo67/common/common/logger" 14 ) 15 16 var _ joiner.Operator = &joinerRuntime{} 17 18 func New(options common.Map, l logger.Operator) joiner.Operator { 19 return &joinerRuntime{ 20 l: l, 21 options: options, 22 components: map[joiner.InterfaceKey]interface{}{}, 23 mutex: &sync.RWMutex{}, 24 } 25 } 26 27 type joinerRuntime struct { 28 l logger.Operator 29 options common.Map 30 components map[joiner.InterfaceKey]interface{} 31 mutex *sync.RWMutex 32 } 33 34 var ErrJoiningOnEmptyKey = errors.New("can't join on empty interface key") 35 var ErrJoiningNil = errors.New("can't join nil interface") 36 var ErrJoiningDuplicate = errors.New("can't join interface over joined before") 37 38 func (j *joinerRuntime) Join(intrfc interface{}, interfaceKey joiner.InterfaceKey) error { 39 if j == nil { 40 return fmt.Errorf("got nil on .Join(%s)", interfaceKey) 41 } 42 if interfaceKey == "" { 43 return errors.Wrapf(ErrJoiningNil, "on .Join(%s)", interfaceKey) 44 } 45 if intrfc == nil { 46 return errors.Wrapf(ErrJoiningNil, "on .Join(%s)", interfaceKey) 47 } 48 49 j.mutex.Lock() 50 defer j.mutex.Unlock() 51 52 if _, ok := j.components[interfaceKey]; ok { 53 return errors.Wrapf(ErrJoiningDuplicate, "on .Join(%s)", interfaceKey) 54 } 55 56 j.components[interfaceKey] = intrfc 57 58 if j.l != nil && !j.options.IsTrue("silent") { 59 j.l.Infof("joined (%T) as %s", intrfc, interfaceKey) 60 } 61 62 return nil 63 } 64 65 func (j *joinerRuntime) Interface(interfaceKey joiner.InterfaceKey) interface{} { 66 if j == nil { 67 log.Printf("on ActorKey.Component(%s): null ActorKey item", interfaceKey) 68 } 69 70 j.mutex.RLock() 71 defer j.mutex.RUnlock() 72 73 if intrfc, ok := j.components[interfaceKey]; ok { 74 return intrfc 75 } 76 77 return nil 78 } 79 80 func (j *joinerRuntime) InterfacesAll(ptrToInterface interface{}) []joiner.Component { 81 j.mutex.RLock() 82 defer j.mutex.RUnlock() 83 84 var components []joiner.Component 85 86 for key, intrfc := range j.components { 87 if CheckInterface(intrfc, ptrToInterface) { 88 components = append(components, joiner.Component{InterfaceKey: key, Interface: intrfc}) 89 } 90 } 91 92 return components 93 } 94 95 func CheckInterface(intrfc interface{}, ptrToInterface interface{}) bool { 96 defer func() { 97 recover() 98 }() 99 100 // ??? reflect.TypeOf(ptrToInterface).Elem() 101 // ??? if intrfc != nil 102 if reflect.TypeOf(intrfc).Implements(reflect.TypeOf(ptrToInterface).Elem()) { 103 return true 104 } 105 106 return false 107 } 108 109 func (j *joinerRuntime) CloseAll() { 110 if j == nil { 111 log.Print("on ActorKey.Close(): null ActorKey item") 112 return 113 } 114 115 closerComponents := j.InterfacesAll((*joiner.Closer)(nil)) 116 117 for _, closerComponent := range closerComponents { 118 if closer, _ := closerComponent.Interface.(joiner.Closer); closer != nil { 119 err := closer.Close() 120 if err != nil { 121 log.Print("on ActorKey.Close(): ", err) 122 } 123 } 124 } 125 126 }