github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/providers/component-protocol/protocol/component.go (about) 1 // Copyright (c) 2021 Terminus, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package protocol 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/sirupsen/logrus" 22 23 "github.com/erda-project/erda-infra/providers/component-protocol/cptype" 24 ) 25 26 // CompRenderSpec . 27 type CompRenderSpec struct { 28 // Scenario key 29 Scenario string `json:"scenario"` 30 // CompName is component name 31 CompName string `json:"name"` 32 // RenderC used to created component 33 RenderC RenderCreator 34 // Creator used to create component instance 35 Creator ComponentCreator 36 } 37 38 func ensureRender(spec *CompRenderSpec) { 39 if spec.RenderC != nil { 40 return 41 } 42 if spec.Creator == nil { 43 panic(fmt.Errorf("no RenderCreator or ComponentCreator specified when register, scenario: %s, comp: %s", spec.Scenario, spec.CompName)) 44 } 45 spec.RenderC = convertToRenderC(spec.Creator) 46 } 47 48 // ComponentCreator . 49 type ComponentCreator func() cptype.IComponent 50 51 func convertToRenderC(creator ComponentCreator) RenderCreator { 52 return func() CompRender { return FRAMEWORK{IC: creator()} } 53 } 54 55 // RenderCreator . 56 type RenderCreator func() CompRender 57 58 // CompRender . 59 type CompRender interface { 60 Render(ctx context.Context, c *cptype.Component, scenario cptype.Scenario, event cptype.ComponentEvent, gs *cptype.GlobalStateData) error 61 } 62 63 // MustRegisterComponent . 64 func MustRegisterComponent(r *CompRenderSpec) { 65 if err := RegisterComponent(r); err != nil { 66 logrus.Errorf("failed to register component render, scenario: %s, component: %s, err: %s", r.Scenario, r.CompName, err) 67 panic(err) 68 } 69 logrus.Infof("register component render success, scenario: %s, component: %s", r.Scenario, r.CompName) 70 } 71 72 // RegisterComponent register a component under scenario 73 func RegisterComponent(r *CompRenderSpec) error { 74 ensureRender(r) 75 if r == nil { 76 return fmt.Errorf("register request is empty") 77 } 78 if r.Scenario == "" { 79 // use default scenario 80 r.Scenario = cptype.DefaultComponentNamespace 81 } 82 if r.CompName == "" { 83 return fmt.Errorf("component name is empty") 84 } 85 86 // if scenario not exit, create it 87 if _, ok := ScenarioRenders[r.Scenario]; !ok { 88 s := make(ScenarioRender) 89 ScenarioRenders[r.Scenario] = &s 90 } 91 // if compName key not exist, create it and the CompRenderSpec 92 s := ScenarioRenders[r.Scenario] 93 if _, ok := (*s)[r.CompName]; !ok { 94 (*s)[r.CompName] = r 95 } 96 return nil 97 } 98 99 type emptyComp struct{} 100 101 // Render . 102 func (ca *emptyComp) Render(ctx context.Context, c *cptype.Component, scenario cptype.Scenario, event cptype.ComponentEvent, gs *cptype.GlobalStateData) error { 103 return nil 104 } 105 106 var emptyRenderFunc = func() CompRender { return &emptyComp{} } 107 108 // getCompRender . 109 func getCompRender(ctx context.Context, r ScenarioRender, compName, typ string) (*CompRenderSpec, error) { 110 if len(r) == 0 { 111 return nil, fmt.Errorf(i18n(ctx, "scenario.render.is.empty")) 112 } 113 if compName == "" { 114 return nil, fmt.Errorf(i18n(ctx, "component.name.is.empty")) 115 } 116 compName, _ = getCompNameAndInstanceName(compName) 117 var c *CompRenderSpec 118 if _, ok := r[compName]; !ok { 119 // component not exist 120 return nil, fmt.Errorf(i18n(ctx, "${component %s missing renderCreator}", compName)) 121 } 122 c = r[compName] 123 if c == nil { 124 return nil, fmt.Errorf(i18n(ctx, "component.render.is.empty")) 125 } 126 return c, nil 127 } 128 129 // protoCompStateRending . 130 func protoCompStateRending(ctx context.Context, p *cptype.ComponentProtocol, r cptype.RendingItem) error { 131 if p == nil { 132 return fmt.Errorf(i18n(ctx, "protocol.empty")) 133 } 134 pc, err := getProtoComp(ctx, p, r.Name) 135 if err != nil { 136 logrus.Errorf("failed to get protocol component, err: %v", err) 137 return err 138 } 139 // inParams 140 inParams := ctx.Value(cptype.GlobalInnerKeyCtxSDK).(*cptype.SDK).InParams 141 for _, state := range r.State { 142 // parse state bound info 143 stateFrom, stateFromKey, err := parseStateBound(state.Value) 144 if err != nil { 145 logrus.Errorf("failed to parse component state bound, component: %s, state bound: %#v", pc.Name, state) 146 return err 147 } 148 var stateFromValue interface{} 149 switch stateFrom { 150 case cptype.InParamsStateBindingKey: // {{ inParams.key }} 表示从 inParams 绑定 151 stateFromValue = getProtoInParamsValue(inParams, stateFromKey) 152 default: // 否则,从其他组件 state 绑定 153 // get bound key value 154 stateFromValue, err = getProtoCompStateValue(ctx, p, stateFrom, stateFromKey) 155 if err != nil { 156 logrus.Errorf("failed to get component state value, toComponent: %s, fromComponent: %s, key: %s", r.Name, stateFrom, stateFromKey) 157 return err 158 } 159 } 160 // set component state value 161 err = setCompStateValueFromComps(pc, state.Name, stateFromValue) 162 if err != nil { 163 logrus.Errorf("failed to set component state, component: %s, state key: %s, value: %#v", pc.Name, state.Name, stateFromValue) 164 return err 165 } 166 } 167 return nil 168 }