github.com/polarismesh/polaris@v1.17.8/config/utils.go (about) 1 /* 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package config 19 20 import ( 21 "archive/zip" 22 "bytes" 23 "crypto/md5" 24 "encoding/hex" 25 "encoding/json" 26 "errors" 27 "fmt" 28 "path" 29 "regexp" 30 "strconv" 31 "strings" 32 "unicode/utf8" 33 34 "github.com/golang/protobuf/ptypes/wrappers" 35 apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage" 36 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 37 38 api "github.com/polarismesh/polaris/common/api/v1" 39 "github.com/polarismesh/polaris/common/model" 40 "github.com/polarismesh/polaris/common/utils" 41 ) 42 43 var ( 44 regSourceName = regexp.MustCompile(`^[\dA-Za-z-.:_]+$`) 45 regFileName = regexp.MustCompile(`^[\dA-Za-z-./:_]+$`) 46 ) 47 48 // CheckResourceName 检查资源名称 49 func CheckResourceName(name *wrappers.StringValue) error { 50 if name == nil { 51 return errors.New(utils.NilErrString) 52 } 53 54 if name.GetValue() == "" { 55 return errors.New(utils.EmptyErrString) 56 } 57 58 if ok := regSourceName.MatchString(name.GetValue()); !ok { 59 return errors.New("name contains invalid character") 60 } 61 62 return nil 63 } 64 65 // CheckFileName 校验文件名 66 func CheckFileName(name *wrappers.StringValue) error { 67 if name == nil { 68 return errors.New(utils.NilErrString) 69 } 70 71 if name.GetValue() == "" { 72 return errors.New(utils.EmptyErrString) 73 } 74 75 if ok := regFileName.MatchString(name.GetValue()); !ok { 76 return errors.New("name contains invalid character") 77 } 78 79 return nil 80 } 81 82 // CalMd5 计算md5值 83 func CalMd5(content string) string { 84 h := md5.New() 85 h.Write([]byte(content)) 86 return hex.EncodeToString(h.Sum(nil)) 87 } 88 89 // CheckContentLength 校验文件内容长度 90 func CheckContentLength(content string, max int) error { 91 if utf8.RuneCountInString(content) > max { 92 return fmt.Errorf("content length too long. max length =%d", max) 93 } 94 95 return nil 96 } 97 98 // GenConfigFileResponse 为客户端生成响应对象 99 func GenConfigFileResponse(namespace, group, fileName, content, md5str string, 100 version uint64) *apiconfig.ConfigClientResponse { 101 configFile := &apiconfig.ClientConfigFileInfo{ 102 Namespace: utils.NewStringValue(namespace), 103 Group: utils.NewStringValue(group), 104 FileName: utils.NewStringValue(fileName), 105 Content: utils.NewStringValue(content), 106 Version: utils.NewUInt64Value(version), 107 Md5: utils.NewStringValue(md5str), 108 } 109 return api.NewConfigClientResponse(apimodel.Code_ExecuteSuccess, configFile) 110 } 111 112 type kv struct { 113 Key string 114 Value string 115 } 116 117 // ToTagJsonStr 把 Tags 转化成 Json 字符串 118 func ToTagJsonStr(tags []*apiconfig.ConfigFileTag) string { 119 if len(tags) == 0 { 120 return "[]" 121 } 122 kvs := make([]kv, 0, len(tags)) 123 for _, tag := range tags { 124 kvs = append(kvs, kv{ 125 Key: tag.Key.GetValue(), 126 Value: tag.Value.GetValue(), 127 }) 128 } 129 130 ret, err := json.Marshal(kvs) 131 if err != nil { 132 return "[]" 133 } 134 return string(ret) 135 } 136 137 // FromTagJson 从 Tags Json 字符串里反序列化出 Tags 138 func FromTagJson(tagStr string) []*apiconfig.ConfigFileTag { 139 if tagStr == "" { 140 return nil 141 } 142 143 kvs := make([]kv, 0, 10) 144 err := json.Unmarshal([]byte(tagStr), &kvs) 145 if err != nil { 146 return nil 147 } 148 149 tags := make([]*apiconfig.ConfigFileTag, 0, len(kvs)) 150 for _, val := range kvs { 151 tags = append(tags, &apiconfig.ConfigFileTag{ 152 Key: utils.NewStringValue(val.Key), 153 Value: utils.NewStringValue(val.Value), 154 }) 155 } 156 157 return tags 158 } 159 160 // GenReleaseName 生成发布名称,规则是 filename-${三位自增长序列} 161 func GenReleaseName(oldReleaseName, fileName string) string { 162 if oldReleaseName == "" { 163 return fileName + "-001" 164 } 165 166 nameInfo := strings.Split(oldReleaseName, "-") 167 if len(nameInfo) != 2 { 168 return oldReleaseName 169 } 170 171 if fileName != nameInfo[0] { 172 return oldReleaseName 173 } 174 175 num, err := strconv.ParseInt(nameInfo[1], 10, 64) 176 if err != nil { 177 return oldReleaseName 178 } 179 180 return fileName + "-" + strings.ReplaceAll(fmt.Sprintf("%3d", num+1), " ", "0") 181 } 182 183 func CompressConfigFiles(files []*model.ConfigFile, 184 fileID2Tags map[uint64][]*model.ConfigFileTag, isExportGroup bool) (*bytes.Buffer, error) { 185 var buf bytes.Buffer 186 w := zip.NewWriter(&buf) 187 defer w.Close() 188 189 var configFileMetas = make(map[string]*utils.ConfigFileMeta) 190 for _, file := range files { 191 fileName := file.Name 192 if isExportGroup { 193 fileName = path.Join(file.Group, file.Name) 194 } 195 196 configFileMetas[fileName] = &utils.ConfigFileMeta{ 197 Tags: make(map[string]string), 198 Comment: file.Comment, 199 } 200 for _, tag := range fileID2Tags[file.Id] { 201 configFileMetas[fileName].Tags[tag.Key] = tag.Value 202 } 203 f, err := w.Create(fileName) 204 if err != nil { 205 return nil, err 206 } 207 if _, err := f.Write([]byte(file.Content)); err != nil { 208 return nil, err 209 } 210 } 211 // 生成配置元文件 212 f, err := w.Create(utils.ConfigFileMetaFileName) 213 if err != nil { 214 return nil, err 215 } 216 data, err := json.MarshalIndent(configFileMetas, "", "\t") 217 if err != nil { 218 return nil, err 219 } 220 if _, err := f.Write(data); err != nil { 221 return nil, err 222 } 223 return &buf, nil 224 }