176 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
 * Copyright 2025 coze-dev Authors
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
package entity
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"regexp"
 | 
						|
 | 
						|
	"github.com/coze-dev/coze-studio/backend/pkg/errorx"
 | 
						|
	"github.com/coze-dev/coze-studio/backend/types/errno"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	variableMetaSchemaTypeObject  = "object"
 | 
						|
	variableMetaSchemaTypeArray   = "list"
 | 
						|
	variableMetaSchemaTypeInteger = "integer"
 | 
						|
	variableMetaSchemaTypeString  = "string"
 | 
						|
	variableMetaSchemaTypeBoolean = "boolean"
 | 
						|
	variableMetaSchemaTypeNumber  = "float"
 | 
						|
)
 | 
						|
 | 
						|
type VariableMetaSchema struct {
 | 
						|
	Type        string          `json:"type,omitempty"`
 | 
						|
	Name        string          `json:"name,omitempty"`
 | 
						|
	Description string          `json:"description,omitempty"`
 | 
						|
	Readonly    bool            `json:"readonly,omitempty"`
 | 
						|
	Enable      bool            `json:"enable,omitempty"`
 | 
						|
	Schema      json.RawMessage `json:"schema,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
func NewVariableMetaSchema(schema []byte) (*VariableMetaSchema, error) {
 | 
						|
	schemaObj := &VariableMetaSchema{}
 | 
						|
	err := json.Unmarshal(schema, schemaObj)
 | 
						|
	if err != nil {
 | 
						|
		return nil, errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KVf("msg", "schema json invalid: %s \n json = %s", err.Error(), string(schema)))
 | 
						|
	}
 | 
						|
 | 
						|
	return schemaObj, nil
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) IsArrayType() bool {
 | 
						|
	return v.Type == variableMetaSchemaTypeArray
 | 
						|
}
 | 
						|
 | 
						|
// GetArrayType  e.g. schema = {"type":"int"}
 | 
						|
func (v *VariableMetaSchema) GetArrayType(schema []byte) (string, error) {
 | 
						|
	schemaObj, err := NewVariableMetaSchema(schema)
 | 
						|
	if err != nil {
 | 
						|
		return "", errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KVf("msg", "NewVariableMetaSchema failed, %v", err.Error()))
 | 
						|
	}
 | 
						|
 | 
						|
	if schemaObj.Type == "" {
 | 
						|
		return "", errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KVf("msg", "array type not found in %s", schema))
 | 
						|
	}
 | 
						|
 | 
						|
	return schemaObj.Type, nil
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) IsStringType() bool {
 | 
						|
	return v.Type == variableMetaSchemaTypeString
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) IsIntegerType() bool {
 | 
						|
	return v.Type == variableMetaSchemaTypeInteger
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) IsBooleanType() bool {
 | 
						|
	return v.Type == variableMetaSchemaTypeBoolean
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) IsNumberType() bool {
 | 
						|
	return v.Type == variableMetaSchemaTypeNumber
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) IsObjectType() bool {
 | 
						|
	return v.Type == variableMetaSchemaTypeObject
 | 
						|
}
 | 
						|
 | 
						|
// GetObjectProperties  e.g. schema = [{"name":"app_var_12_sdd","enable":true,"description":"s22","type":"string","readonly":false,"schema":""}]
 | 
						|
func (v *VariableMetaSchema) GetObjectProperties(schema []byte) (map[string]*VariableMetaSchema, error) {
 | 
						|
	schemas := make([]*VariableMetaSchema, 0)
 | 
						|
	err := json.Unmarshal(schema, &schemas)
 | 
						|
	if err != nil {
 | 
						|
		return nil, errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KV("msg", "schema array content json invalid"))
 | 
						|
	}
 | 
						|
 | 
						|
	properties := make(map[string]*VariableMetaSchema)
 | 
						|
	for _, schemaObj := range schemas {
 | 
						|
		properties[schemaObj.Name] = schemaObj
 | 
						|
	}
 | 
						|
 | 
						|
	return properties, nil
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) check(ctx context.Context) error {
 | 
						|
	return v.checkAppVariableSchema(ctx, v, "")
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) checkAppVariableSchema(ctx context.Context, schemaObj *VariableMetaSchema, schema string) (err error) {
 | 
						|
	if len(schema) == 0 && schemaObj == nil {
 | 
						|
		return errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KV("msg", "schema is nil"))
 | 
						|
	}
 | 
						|
 | 
						|
	if schemaObj == nil {
 | 
						|
		schemaObj, err = NewVariableMetaSchema([]byte(schema))
 | 
						|
		if err != nil {
 | 
						|
			return errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KVf("msg", "checkAppVariableSchema failed , %v", err.Error()))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if !schemaObj.nameValidate() {
 | 
						|
		return errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KVf("msg", "name(%s) is invalid", schemaObj.Name))
 | 
						|
	}
 | 
						|
 | 
						|
	if schemaObj.Type == variableMetaSchemaTypeObject {
 | 
						|
		return v.checkSchemaObj(ctx, schemaObj.Schema)
 | 
						|
	} else if schemaObj.Type == variableMetaSchemaTypeArray {
 | 
						|
		_, err := v.GetArrayType(schemaObj.Schema)
 | 
						|
		if err != nil {
 | 
						|
			return errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KVf("msg", "GetArrayType failed : %v", err.Error()))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) checkSchemaObj(ctx context.Context, schema []byte) error {
 | 
						|
	properties, err := v.GetObjectProperties(schema)
 | 
						|
	if err != nil {
 | 
						|
		return errorx.New(errno.ErrMemorySchemeInvalidCode, errorx.KVf("msg", "GetObjectProperties failed : %v", err.Error()))
 | 
						|
	}
 | 
						|
 | 
						|
	for _, schemaObj := range properties {
 | 
						|
		if err := v.checkAppVariableSchema(ctx, schemaObj, ""); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (v *VariableMetaSchema) nameValidate() bool {
 | 
						|
	identifier := v.Name
 | 
						|
 | 
						|
	reservedWords := map[string]bool{
 | 
						|
		"true": true, "false": true, "and": true, "AND": true,
 | 
						|
		"or": true, "OR": true, "not": true, "NOT": true,
 | 
						|
		"null": true, "nil": true, "If": true, "Switch": true,
 | 
						|
	}
 | 
						|
 | 
						|
	if reservedWords[identifier] {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	// Check if some of the following regular rules are met
 | 
						|
	pattern := `^[a-zA-Z_][a-zA-Z_$0-9]*$`
 | 
						|
	match, _ := regexp.MatchString(pattern, identifier)
 | 
						|
 | 
						|
	return match
 | 
						|
}
 |