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  }