diff --git a/.gitignore b/.gitignore index 79dfd0477..143e3c3c5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ cbuild **/.DS_Store .test/ cmd/gf/main +cmd/gf/gf go.work diff --git a/cmd/gf/internal/cmd/cmd_gen.go b/cmd/gf/internal/cmd/cmd_gen.go index e87145074..0ad663770 100644 --- a/cmd/gf/internal/cmd/cmd_gen.go +++ b/cmd/gf/internal/cmd/cmd_gen.go @@ -11,6 +11,10 @@ var ( type cGen struct { g.Meta `name:"gen" brief:"{cGenBrief}" dc:"{cGenDc}"` + cGenDao + cGenPb + cGenPbEntity + cGenService } const ( diff --git a/cmd/gf/internal/cmd/cmd_gen_dao.go b/cmd/gf/internal/cmd/cmd_gen_dao.go index 5a1d67bfb..75f21fd87 100644 --- a/cmd/gf/internal/cmd/cmd_gen_dao.go +++ b/cmd/gf/internal/cmd/cmd_gen_dao.go @@ -138,6 +138,7 @@ func init() { } type ( + cGenDao struct{} cGenDaoInput struct { g.Meta `name:"dao" config:"{cGenDaoConfig}" usage:"{cGenDaoUsage}" brief:"{cGenDaoBrief}" eg:"{cGenDaoEg}" ad:"{cGenDaoAd}"` Path string `name:"path" short:"p" brief:"{cGenDaoBriefPath}" d:"internal"` @@ -170,7 +171,7 @@ type ( } ) -func (c cGen) Dao(ctx context.Context, in cGenDaoInput) (out *cGenDaoOutput, err error) { +func (c cGenDao) Dao(ctx context.Context, in cGenDaoInput) (out *cGenDaoOutput, err error) { if g.Cfg().Available(ctx) { v := g.Cfg().MustGet(ctx, cGenDaoConfig) if v.IsSlice() { diff --git a/cmd/gf/internal/cmd/cmd_gen_pb.go b/cmd/gf/internal/cmd/cmd_gen_pb.go index e62fdb29f..35babce43 100644 --- a/cmd/gf/internal/cmd/cmd_gen_pb.go +++ b/cmd/gf/internal/cmd/cmd_gen_pb.go @@ -13,13 +13,14 @@ import ( ) type ( + cGenPb struct{} cGenPbInput struct { g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"` } cGenPbOutput struct{} ) -func (c cGen) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) { +func (c cGenPb) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) { // Necessary check. if gproc.SearchBinary("protoc") == "" { mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first to proceed this command`) diff --git a/cmd/gf/internal/cmd/cmd_gen_pbentity.go b/cmd/gf/internal/cmd/cmd_gen_pbentity.go index 10cbfb27d..b07a1e522 100644 --- a/cmd/gf/internal/cmd/cmd_gen_pbentity.go +++ b/cmd/gf/internal/cmd/cmd_gen_pbentity.go @@ -19,6 +19,29 @@ import ( "github.com/olekukonko/tablewriter" ) +type ( + cGenPbEntity struct{} + cGenPbEntityInput struct { + g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"` + Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"` + Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"` + Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"` + Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"` + Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"` + RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"` + NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"` + JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"` + Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"` + } + cGenPbEntityOutput struct{} + + cGenPbEntityInternalInput struct { + cGenPbEntityInput + TableName string // TableName specifies the table name of the table. + NewTableName string // NewTableName specifies the prefix-stripped name of the table. + } +) + const ( cGenPbEntityConfig = `gfcli.gen.pbentity` cGenPbEntityBrief = `generate entity message files in protobuf3 format` @@ -83,28 +106,6 @@ set it to "none" to ignore json tag generating. ` ) -type ( - cGenPbEntityInput struct { - g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"` - Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"` - Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"` - Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"` - Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"` - Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"` - RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"` - NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"` - JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"` - Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"` - } - cGenPbEntityOutput struct{} - - cGenPbEntityInternalInput struct { - cGenPbEntityInput - TableName string // TableName specifies the table name of the table. - NewTableName string // NewTableName specifies the prefix-stripped name of the table. - } -) - func init() { gtag.Sets(g.MapStrStr{ `cGenPbEntityConfig`: cGenPbEntityConfig, @@ -124,7 +125,7 @@ func init() { }) } -func (c cGen) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) { +func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) { var ( config = g.Cfg() ) diff --git a/cmd/gf/internal/cmd/cmd_gen_service.go b/cmd/gf/internal/cmd/cmd_gen_service.go index e9e265bf8..82213da69 100644 --- a/cmd/gf/internal/cmd/cmd_gen_service.go +++ b/cmd/gf/internal/cmd/cmd_gen_service.go @@ -18,15 +18,16 @@ import ( ) type ( + cGenService struct{} cGenServiceInput struct { g.Meta `name:"service" config:"gfcli.gen.service" brief:"parse struct and associated functions from packages to generate service go file"` - SrcFolder string `short:"s" name:"srcFolder" brief:"source folder path to be parsed. default: internal/logic" d:"internal/logic"` - DstFolder string `short:"d" name:"dstFolder" brief:"destination folder path storing automatically generated go files. default: internal/service" d:"internal/service"` - WatchFile string `short:"w" name:"watchFile" brief:"used in file watcher, it generates service go files only if given file is under srcFolder"` - StPattern string `short:"a" name:"stPattern" brief:"regular expression matching struct name for generating service. default: s([A-Z]\\\w+)" d:"s([A-Z]\\w+)"` - Packages string `short:"p" name:"packages" brief:"produce go files only for given source packages, multiple packages joined with char ','"` - ImportPrefix string `short:"i" name:"importPrefix" brief:"custom import prefix to calculate import path for generated importing go file of logic"` - OverWrite bool `short:"o" name:"overwrite" brief:"overwrite service go files that already exist in generating folder. default: true" d:"true" orphan:"true"` + SrcFolder string `short:"s" name:"srcFolder" brief:"source folder path to be parsed. default: internal/logic" d:"internal/logic"` + DstFolder string `short:"d" name:"dstFolder" brief:"destination folder path storing automatically generated go files. default: internal/service" d:"internal/service"` + WatchFile string `short:"w" name:"watchFile" brief:"used in file watcher, it generates service go files only if given file is under srcFolder"` + StPattern string `short:"a" name:"stPattern" brief:"regular expression matching struct name for generating service. default: s([A-Z]\\\\w+)" d:"s([A-Z]\\w+)"` + Packages []string `short:"p" name:"packages" brief:"produce go files only for given source packages"` + ImportPrefix string `short:"i" name:"importPrefix" brief:"custom import prefix to calculate import path for generated importing go file of logic"` + OverWrite bool `short:"o" name:"overwrite" brief:"overwrite service go files that already exist in generating folder. default: true" d:"true" orphan:"true"` } cGenServiceOutput struct{} ) @@ -35,7 +36,7 @@ const ( genServiceFileLockSeconds = 10 ) -func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServiceOutput, err error) { +func (c cGenService) Service(ctx context.Context, in cGenServiceInput) (out *cGenServiceOutput, err error) { // File lock to avoid multiple processes. var ( flockFilePath = gfile.Temp("gf.cli.gen.service.lock") @@ -101,13 +102,12 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic } var ( - isDirty bool - files []string - fileContent string - matches [][]string - importSrcPackages []string - inputPackages = gstr.SplitAndTrim(in.Packages, ",") - dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder)) + isDirty bool + files []string + fileContent string + initImportSrcPackages []string + inputPackages = in.Packages + dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder)) ) srcFolders, err := gfile.ScanDir(in.SrcFolder, "*", false) if err != nil { @@ -125,56 +125,25 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic } var ( // StructName => FunctionDefinitions - srcPkgInterfaceMap = make(map[string]*garray.StrArray) - srcPkgInterfaceFuncArray *garray.StrArray - ok bool + srcPkgInterfaceMap = make(map[string]*garray.StrArray) + srcImportedPackages = garray.NewSortedStrArray().SetUnique(true) + ok bool ) for _, file := range files { fileContent = gfile.GetContents(file) - matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent) + // Calculate imported packages of source go files. + err = c.calculateImportedPackages(fileContent, srcImportedPackages) if err != nil { return nil, err } - for _, match := range matches { - var ( - structName string - structMatch []string - funcReceiver = gstr.Trim(match[1]) - receiverArray = gstr.SplitAndTrim(funcReceiver, " ") - functionHead = gstr.Trim(gstr.Replace(match[2], "\n", "")) - ) - if len(receiverArray) > 1 { - structName = receiverArray[1] - } else { - structName = receiverArray[0] - } - structName = gstr.Trim(structName, "*") - - // Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq) - functionHead = gstr.Replace(functionHead, `,)`, `)`) - functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead) - functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead) - if !gstr.IsLetterUpper(functionHead[0]) { - continue - } - if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil { - return nil, err - } - if len(structMatch) < 1 { - continue - } - structName = gstr.CaseCamel(structMatch[1]) - if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok { - srcPkgInterfaceMap[structName] = garray.NewStrArray() - srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName] - } - // Remove package name calls of `dstPackageName` in produced codes. - functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead) - srcPkgInterfaceFuncArray.Append(functionHead) + // Calculate functions and interfaces for service generating. + err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap, dstPackageName) + if err != nil { + return nil, err } } - importSrcPackages = append( - importSrcPackages, + initImportSrcPackages = append( + initImportSrcPackages, fmt.Sprintf(`%s/%s`, in.ImportPrefix, gfile.Basename(srcFolder)), ) // Ignore source packages if input packages given. @@ -186,7 +155,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic continue } // Generating go files for service. - if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, dstPackageName); err != nil { + if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, srcImportedPackages.Slice(), dstPackageName); err != nil { return } if ok { @@ -196,8 +165,8 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic if isDirty { // Generate initialization go file. - if len(importSrcPackages) > 0 { - if err = c.generateInitializationFile(in, importSrcPackages); err != nil { + if len(initImportSrcPackages) > 0 { + if err = c.generateInitializationFile(in, initImportSrcPackages); err != nil { return } } @@ -218,13 +187,86 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic return } -func (c cGen) generateServiceFiles( - in cGenServiceInput, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string, +func (c cGenService) calculateImportedPackages(fileContent string, srcImportedPackages *garray.SortedStrArray) (err error) { + var match []string + match, err = gregex.MatchString(`\s+import\s+\(([\s\S]+?)\)`, fileContent) + if err != nil { + return err + } + if len(match) < 2 { + return nil + } + importPart := gstr.Trim(match[1]) + srcImportedPackages.Append(gstr.SplitAndTrim(importPart, "\n")...) + return nil +} + +func (c cGenService) calculateInterfaceFunctions( + in cGenServiceInput, fileContent string, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string, +) (err error) { + var ( + ok bool + matches [][]string + srcPkgInterfaceFuncArray *garray.StrArray + ) + matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent) + if err != nil { + return err + } + for _, match := range matches { + var ( + structName string + structMatch []string + funcReceiver = gstr.Trim(match[1]) + receiverArray = gstr.SplitAndTrim(funcReceiver, " ") + functionHead = gstr.Trim(gstr.Replace(match[2], "\n", "")) + ) + if len(receiverArray) > 1 { + structName = receiverArray[1] + } else { + structName = receiverArray[0] + } + structName = gstr.Trim(structName, "*") + + // Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq) + functionHead = gstr.Replace(functionHead, `,)`, `)`) + functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead) + functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead) + if !gstr.IsLetterUpper(functionHead[0]) { + continue + } + if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil { + return err + } + if len(structMatch) < 1 { + continue + } + structName = gstr.CaseCamel(structMatch[1]) + if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok { + srcPkgInterfaceMap[structName] = garray.NewStrArray() + srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName] + } + // Remove package name calls of `dstPackageName` in produced codes. + functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead) + srcPkgInterfaceFuncArray.Append(functionHead) + } + return nil +} + +func (c cGenService) generateServiceFiles( + in cGenServiceInput, + srcPkgInterfaceMap map[string]*garray.StrArray, + srcImportedPackages []string, + dstPackageName string, ) (ok bool, err error) { + srcImportedPackagesContent := fmt.Sprintf( + "import (\n%s\n)", gstr.Join(srcImportedPackages, "\n"), + ) for structName, funcArray := range srcPkgInterfaceMap { var ( filePath = gfile.Join(in.DstFolder, gstr.ToLower(structName)+".go") generatedContent = gstr.ReplaceByMap(consts.TemplateGenServiceContent, g.MapStrStr{ + "{Imports}": srcImportedPackagesContent, "{StructName}": structName, "{PackageName}": dstPackageName, "{FuncDefinition}": funcArray.Join("\n\t"), @@ -250,7 +292,7 @@ func (c cGen) generateServiceFiles( } // isToGenerateServiceGoFile checks and returns whether the service content dirty. -func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool { +func (c cGenService) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool { if !utils.IsFileDoNotEdit(filePath) { mlog.Debugf(`ignore file as it is manually maintained: %s`, filePath) return false @@ -280,7 +322,7 @@ func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrAr return false } -func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages []string) (err error) { +func (c cGenService) generateInitializationFile(in cGenServiceInput, importSrcPackages []string) (err error) { var ( srcPackageName = gstr.ToLower(gfile.Basename(in.SrcFolder)) srcFilePath = gfile.Join(in.SrcFolder, srcPackageName+".go") @@ -306,7 +348,7 @@ func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages return nil } -func (c cGen) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error) { +func (c cGenService) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error) { return gfile.ReplaceDirFunc(func(path, content string) string { if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) { content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`) diff --git a/cmd/gf/internal/cmd/cmd_init.go b/cmd/gf/internal/cmd/cmd_init.go index 6f059f982..269bf6853 100644 --- a/cmd/gf/internal/cmd/cmd_init.go +++ b/cmd/gf/internal/cmd/cmd_init.go @@ -10,6 +10,7 @@ import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gcmd" "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/gproc" "github.com/gogf/gf/v2/os/gres" "github.com/gogf/gf/v2/util/gtag" ) @@ -48,7 +49,8 @@ func init() { type cInitInput struct { g.Meta `name:"init"` Name string `name:"NAME" arg:"true" v:"required" brief:"{cInitNameBrief}"` - Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"` + Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"` + Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"` } type cInitOutput struct{} @@ -89,6 +91,18 @@ func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err return } + // Update the GoFrame version. + if in.Update { + mlog.Print("update goframe...") + updateCommand := `go get -u github.com/gogf/gf/v2@latest` + if in.Name != "." { + updateCommand = fmt.Sprintf(`cd %s && %s`, in.Name, updateCommand) + } + if err = gproc.ShellRun(updateCommand); err != nil { + mlog.Fatal(err) + } + } + mlog.Print("initialization done! ") if !in.Mono { enjoyCommand := `gf run main.go` diff --git a/cmd/gf/internal/consts/consts_gen_service_template.go b/cmd/gf/internal/consts/consts_gen_service_template.go index 9ce3174cd..6cc9a286c 100644 --- a/cmd/gf/internal/consts/consts_gen_service_template.go +++ b/cmd/gf/internal/consts/consts_gen_service_template.go @@ -7,6 +7,8 @@ const TemplateGenServiceContent = ` package {PackageName} +{Imports} + type I{StructName} interface { {FuncDefinition} } diff --git a/cmd/gf/internal/packed/template-mono.go b/cmd/gf/internal/packed/template-mono.go index 86f35c665..5e8b9410c 100644 --- a/cmd/gf/internal/packed/template-mono.go +++ b/cmd/gf/internal/packed/template-mono.go @@ -3,7 +3,7 @@ package packed import "github.com/gogf/gf/v2/os/gres" func init() { - if err := gres.Add("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"); err != nil { + if err := gres.Add("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"); err != nil { panic("add binary content to resource manager failed: " + err.Error()) } } diff --git a/cmd/gf/internal/packed/template-single.go b/cmd/gf/internal/packed/template-single.go index 09638cff6..c2dd71394 100644 --- a/cmd/gf/internal/packed/template-single.go +++ b/cmd/gf/internal/packed/template-single.go @@ -3,7 +3,7 @@ package packed import "github.com/gogf/gf/v2/os/gres" func init() { - if err := gres.Add("H4sIAAAAAAAC/7R7BVRUW/v3oaRTSjqkG5FOCQlHBKUkh+4aukVKugQllVakpVu6U0E6JJUu6W/d97vXl/EqCr5/1tKz0Fm/ePZ+9tlzfmffk4ODxwWQACSg1QHyADjzQwYgA3YGFtbmYDsDFoiJpZG5ARurkYkd2M7O1kTX3s4AovQAAYB5tnpTt1+xta1Tjq2LmbWvS6ZTjg10R77Yfg8RHgBOT+/JISIN3OPgJwEAAB8AgJ8TEv2E0MTI0srW4BsZV1e9QiM7mtT0oXY7WRrtog6qTmFJviSOnF7bS3c/dle3ybk+syUF9w6MZdBoPgOuCMamyaQijv594hNQtjkaSttgn7eYCm72uzL9B/HBupnqrWkN7aEZS0z8kv5rIRv99fR7OGGIAy1bW8+5EaJx2nh5SPOf1qwSHuy0WEnzJXrC/eMqYr6TwxcAgIJzXRH+wBUIbGZgaGL+X08JStpWo9xYniXCTY+K4FBD0ooJd3Wo1aqHId7FCuFpCN4VSIQb17EzpEEpCS4mNYfW0RZ8WiUwW4/dPJ1rDzektVo2Vo63Z4iAKfiDBv7b6S/ccGsc+fZ5K8vjEroSgpDvOKcyb2UUZWNujAuVt1kW0OOVEg4qGqE85wnp8UjWPC2aPIRhtbMoV+zLVLQO0kEfJnmUYopqRM5aR5R6i62KP4xtTSqcfolGNrRq4pCIBZ7Xz3fItVM6lFKOsrTkzW2FaJl4HkywbiD9DTUiA5MHL29p6ZEWZ99+J2hqUBZQuO0xamkI7KDM27jNno7zlgsL7E0vBpjSOoPhq/alJNXlCA0YWkvIkT4QmykBfIKmu8wt+sgaQZrD2aR+xHmldOR2CelYb6ZwqR5lS/PI1lcOpJauHwu04ta4wXw49RV7gT0chlbjQXo1mwifTDTPX8bSq6vLqkoUUfTDi5Bx3Vs2aMVzT30LOZFTwvnhJlSL0KeUiUj9KCHSLgjaVC8dHjK25A7wmb4xFl+4ovgq32/wAXtiYx9XqOGIbOXqQ/wxJ+/42Oq9CSMG/azEoZx9M+qngNo6WpiYzqvOivckqWZa9ETJaa8YB/FjuuBolfu629oXvc1xF6ZiMgp9FiNUvCOjZcq8venKB4dhIFxOq651tepNeGuD+IqZ9yNsEDWe6T9Rih98av16oQbxeM+/bAZl1Ypu6xjuuQxquz5WlS+FNEjJ2vXdlSdIiHyPKV7ct+uPu21uzUN/Rdda+CtvGbhmre3BLDm7oEeBqkW5hSmSd/8DZEbWm1UC411P12q9fa6L4BYWmk2Ks+gfyIbfeXlqJ/BchLzh7nDaKpvLztJ8VRBdyEwJrGQ/hXkrqiwSmRcCiROlxwmyN1H0YBePbe/KO4r8XvLVcYGTrFOJm8ktE5/Vp/28myunlGk1Xt2MBiUOPDB/x8jcVe/niztjTwW6zYMjOiXvXcjCd0weVeHIrVEydBLCP2IYmyzwwTA2WT1GXWwK5SmD+6QA4Uh6eGjDibXrx0PsPnyW+JG4WydP9Co+NgZ5eZs9rzjsBy/qUhe9k92wJ91JRuq5QbNWtT6VJXwcq0vJ0UdbjAasFz4wQ+o/7fQmMKEplcF45Hdivae8T7wa0JMlMuaa7TbjJcSiqqlbqJOa2bRqYloMy0Iwtql8/whGabw9JUQtfwXZNu9DvNgK2/CNY0KLA22Yfxo7nArtKBAOAOQQz2vsaz9obEVJMQmQJCtI4ltnKypb9zgyyXaClJBkulhaZZhllKw72BSRujvlemTQZVlaF2C/LZNrT4zg6AEAoDqzoAD/4r36A16wtck3xr+Qzn7+50j4P0Zic+D4Jdi/y0H+UzA2YwNzcytWI6tvqOZdBXcfc6DBT5V7oHRcZQ7R6bxqBwbrZe/bJAQ882l89ZByglSBNi2Ubnx8yNnVCE9QCMD9bME7UR/61kkr7zBHrTeDwRglsyX8Sjw8TRniuhyBoHTOipqwzYFq/CzBF7vT691OX77wKbbWot8ySozA8KxvhLgGpc34QJ5vlEm4mKDevzawUSG26hu6fowZx0PBRBuh0U1WqE4TfUM9D8fkgJ7cRWgf+Z9hwXlIYv4aAICFc/3/qJhGVqwWVvrfbLd3yTN0yShJ9zC30YP65bp73sv3yMsPsP09Md6z/GdSzM3I9qiwD97gmpthlGVh7mJ+NxiRlKFtmHbPMM3ohdE7BKR/hI3c1R69AwCA8mWEQewtvgl7WyFTmiI9uicgkpwyz8qDLUaQUNwNwMBg4yHgGm27U4d4JZ8wO36AiFRkr3Yef1DnaxtLnTwN7MhGp7p7qL8ufFRxXVlcfSfzpZxiSl7HTJjA1xfCU+TIR54GKgbpD6oCWlqbHGI/GTbnLkSCxpqCn3SkNVO9hsh1lcye7p0eRUo37txWQ5TPZ9cksR9C+ZqRoVhsuRc1VRj/XCvn6YyiGr5p1WCs38f4YJ58coeQUb9GLhrLWCzH7RZS9zrMbX3+FrkUyYxFDLg5Qxe0LvGqiQE1JSRp7Cpb1z73+xnuPRE1TW4cQzFsolzSj9t6GDqG3JzwDn2uc9oWr+4NUbt/zJ0btroBnqxORe3Jef028Ilt+8n1AfLtq2rxhBM592TRH2O5N7kmzJ+oNiFKxZcf61YC2diCd4l55tPWKLSDQQ5L+w5+Dwpbj33J3vA9okw4IDTozxCO3KnbxgMPBrkGTISgj7kutiBjD3XkIreIrK7DeXgRrPvZ588m97GCKsremqVURSGI4EvErjk+qFAqvJ/J6vaQciOvPnnDvqcsmPCFY/aqN67FburT7aYkkQl+2775wFlRTkh3RlPBCU/Aqd8rGwFH5wP4UjCeT5irkF3POgK5zhMAFqDGEQ2k+UhDUADUAVSxoUlxTUn8QYNxxiuJ7OHtoBF8ytb+BofKZdWp5L16a4vNq9HDnre35spOdD62BI1agJy7Knj5LKpNarQKW2BNbaqpbvdtPnPtExp0FJGyTKb10SawP1wS34QTtHGqdHTL4vMX5zM7yG/wC2kc36jaKrlZVO1tNzotqUbPxXeCsqerXzM3ELLnlLCr0jfRVjTsc2giXoDSNKYcy5Hx3mKR7/OOcPvkK02lPROu04UwuvgDHe3ej8/sMNtnWyN4SUJZbEbFjFhTYfaejSubieWFuGobgUpyax/Pa/WGLdPej3xLQUo5Nf5YQGbRxQ6pjkuFyVh07Z7pGBqjoGaIduoSOVhby71B0byBs3tn2nbJPyAecSkFXcwy1dIbR4eZp7cb9MYjaF83VyaSWSiXZI/IvLSmusN91LU1sEEqn+JKCLeJsC/DK+W4Hb8TtBqKlQDy04kNcscjmGnEnf0OhuKo20NwRca3RMvNimQlfCOaZifSF0AvzL+M60eZBXLMrolpo0mpcDEOyelweTtFfGoB5R1rmDsUQeQVxEgzkvgsH8aIB20wVVbidbwArYHloiGOTEkTOh4S67LsV9sHHWLur8qNb6IrguJb4ixHuJKCrrqW6yuSIbfnx9bIuHOo4ZKFzKz2sCizpbss5+1Y50Wqk+In2NwefR989erHJ5x5JzOhEyu2KUz9th+FQM5ttkgUOpTiUV7qkbihAIFT0kLtshSkUzeweq7TRHlevJZJMp1xVODll1H1iWQf3zrJg1vDR3P3bCQa+5K7YI++guRcQBJZZczvTiKz7nQQv4tYIpPKkbamd8q8t4aSz8pKtJPcoIVmF1+1dq0Iqaf6RWjXY8q17HilENXaqa9v3g85BzbNF67O5nW+y9FNMflcs+u3uGSzPW+TwS4bs4XfRPM+1fXO1yGchE/87Q+mDfPe1Aj1bkmxKcF4hCzXer3CzDc/Lk3YEHcsTLmHDI8SvGCJFgCX2l6wapo2YMyQCN4c80lLC/5auY25vqFWju0dkEYowXKN+4WOqC45zFGKkMmRGnJ9HEb2upvaaBqXhnkfbrt+wTXlOLhA3LIDt2nQSfxIHqSjJJzMRWoDuacEls0/OiOv8VBKc11vqFRZb40MB7NVfMBhMu3+KYQTJzLAh0SSTagTwInoCXA/7urGX9Lr6kEP1fYPchba1XAsCYvTyd4K3cJsN4WMKE3EgGtpdydNavEP+fNXR5x2SVSWx0Q7l3YI+4U7LAcSDdf4lKom9dPQZxCOiI6Wcx6+8Zda2HPyJOA2mugxo+goJCJ/Tn3/8PWsfWYEzdIu7+ta2AEr/LzK427hTbpufQH7AqWcTXOpmigm13alnlnqjfGr2la7EXGnREd8n8n2EC2K1W9LVZVucynON9yCVLlGOYtVT9ijqug1yUWk1x2lQ5Z4yDXMqSlWxrPYuHki3hjo+9JbZBnnqe87IbPqhmMIWIs4pG8haLRIfmW28fgo2DHiutbS3EUwe9tsHKWDWt+OvRPC72N7TBiKpceIAetOBqEd9wBN1epMr9XV3B4mRTTM37G7NvdafoxnTxeb423Ivak5gjwyGtogENVETkae7y7qrjv7KUFBp1HUgCCobBwzuMK4o7gfbv5ht5Sn9vSTnh6xwiR162IHldMOnB3HKs+mTm4WlFhC8bzsY8Evp535dBCxZxVm/MIGbwa0Ru8k1vNDpPt1PWoW6j/UdoyAtO/UBR5ZcWh32oeWveDImhfmWq0ybaYvtyUQeCkYpyWNP33FDb9eWiWSbb7E/iQhPbKGOUZzMqOr0HHW8tqQSMXmQtoVqhtqYeprnWQBbslx2Rjhny0hheWpoXbvKLbdaQijMoamTtFO+GESr2TkyD2ifeH+kbjCdSLlox7FfBhTwshN8YDbobPPpzomwrk8FDBh+iqXFsJhJ3SHd6ZWpmhMrz6Lil6L7iBJojpIurMQ1Yt9zGfOYGe8G6VQnSm1tOu+c424h2NiJ3DdhONoKql3lfbDQBPqLY9KAleKzWmpfGIcHlLHnNnsRu3Cl3q8LbS1yO4cTjoYjXO4zf6d2w1PtAc7x0feihmge8luVyCX9wlndM3bbZ0mJTpYTvZ4HuzdvOXG1uSqdGdWgMhfRoBk0dVmG71sIW8CHRknvStR+75Z9j6bcm2ESGbmRzInx9VnT3FAJvjamGE2YlpBj5JCVKMwA6TdGu4L7jbyTYrVEHa0F7qUKmbH2I2yZga8eP1WmfVaR7pfCgK+7hZ6lF1hp4KnvKU/I8nAC3mPOhHPUos2GzuJkj5cLhi9pPZ6fNxR6mB9Yz+56bdlVx+8Q0pD+Eq23aSDEG49Ep0knYCgMN4W9sXSOiOS7oWQcbuLQsowf/FjlaU1zaK4sRdH8uuKVo/1yZRN+2UOrWsZLEQ4OnlZ45TBVsTlihKVbS/dsdxUVDhO79N6vHst3tFr0cO7bejeHyzkeuOzXAf3NCX+Nec7t0UJynm2/BiOSXZ1p1I2rdQHnDRk+fryBJgEScYaVqy1QSh5DnPpxHkPVzoavD0xX1UgbVHmZVfRHhgRBVuM+K9gZnpooZKGf9FVvP6Kw/dmKbgbmTmsgeVF+00ObMkq/gKBmL3G69u1mB4cgnxcwcokmM95WCJvJEFSH1Ob5FSZRXC0v7B0kxO+ztczv/ZIXUVTttHkqQjT8JBv1jDG+9fUCZEfcxeZYvnmIww+LOnERBkHipfGig/cw1+A0B6jofSpa7rpG3sK3wt6yOuznqFlup/QcmDDzDlu60NBLnBVzMustM1T1sCDWTBgtNVCbmj3dZr/LV5/oQah4CObu8SHKR8QbrT44eH06y2c/nX3tlbDMimmSUn0GMXDxLIdNdayMeShHZLKfxxyV+PaoVaINlEjpqmmX8FhWqEVXS38yE18n50Pr+298T4QH051qHpFweyjl/G4fR1+y+Qw2+m5R32MiDJ5eKcCTuPdO1dmQiXpwFFW9XU7oXnxcmuFNR9UCNubqS8MlQeZgyIq5rTdluWBA9tZi3t1e2HEpKUlMcgLCeWvaYq45TiRBsOpTrqTrcqGTBVpYCtrfCKn723rjZh8mr6XrbzZiozG2tRJelQ/i8pXVkNezdDgP3ql5yFemsKDtIlklg3k9Mb39LI6dD1S1YpVOdMkzVH2WQjHbmkq/eJdT5DwVcJ4ttfEtKtfMzDHD31ufH4HnfukoL34CP+5/ZgzB7G2Y4m4/e2+cpy1nYrPo/l7UTFZ1eYHfeiTR/ndpBicyy59oY8Il9wsiw49SCyZDvtkVYU5N10eBvenyXmGrTSsrlkFLN6Ik3D6QiSTZvbFzmhWF1Wc0GvXgxM/vfyeieem3PHEVu31IpEj9RBhBtmXijHqwq/zHluRc/jBebY/IjOgTkpAb9khY/na7RjO1sz5mTg37CSCdtRhHnBaLAU5CGbcF9CSXnnHESAdsPVsZ/pQqUMwradGCT59dF5k9aqWuygtAYlIArhk34wHT1SkubA8QlaveNfRMIoXmcCnBrKpurwwvFf9kiRbiYzxYUB3o9JyCALqyoOidfwUnIYsir0FBa+hdy09gUqegyDVHTB2DHiym9wENOiuWtW40sXFZKj70jxvtZiYgYij8na2hsgD089rjirYWPsGjIuPU04i93Rpk0lXfGZNvPFpdt/S51U767u4WXHlJI7bwgSmPpCce7I5expKU0HhyWFfLLAYWjxJ6jBRgrJTM3T3ecSXLt3q8aAE3/DCqJcfXgt8cgva110VM5ZM5+3aht9idkvwZmkjw7GyWFIbtQjTLBTDnMbWkpI/Ra6w0hRx4xgWzHnIHK+Y5+t4OxYZlyIL8sxsaau5YICT4+lTQ7khypc1Mu4393WTrFZJcnN09cRvj9GMN6uJ3WEZFMjTkU50yTAc+/LSQf4rhO40a/TZM6TaxPiak0lXsVYYHB0fCtSN/tvPqMQBuG73RKvH5gSHiqjIML1V4S3s41JLzSnpfo/8nnYYuZl5596vX8Bb7nlP4YVlG067RGMIRw7B9uI6dinhCxnCd6xlwKR7mq80UdzrCDGJQnjPR10UPFOW8vDQ+XpW7T1xgB2JUpozQKPwrT/7lXCH46El28N7mBXYXQesMp/Edee6a1KLDeXUysZNwc6PiqpAjcPLn9lM5eu0Vyn5deyuffJNQsVEj1iEpEYpiEkOjSrwWzXXYaer297JUwk6dR07XN3vsXkPeXocNsoxBTyWxoEt80HbhgtE5yNEyCs2QHX0kdnNfflpJl2vbbfimiuTWhT1tZ05Xgee/ELZk2EFkaczAAK9BBVOf0dvqtBkKthHY1Py9QJueVh+4STIzjilJG+Y+Gocj5K1ZYymCelHuvg4rjiqE1/crVkc3Hy5fjhcuIbelu3RIbyHvCMZJjFHfmC1rYLx9g+wTh/BmCX7+ZMZuGIdx/Nj2NpX50AoMKLUANCkaCwDCb8Oxw0rtn4QsvgBbbUXBSXoXQ4Wj5vMl2fOJUrqC0fNeO/h2mafVkXAH2TW4sFiUSBJx90a40zhACl42fHt2tN/IdKAlVQb/JrhZVMV3F3cNP9kLPMO+kOpXXEnfpCvE/GbZFkxUUo0hjrFMRwIWOIKCWnh1+KoFR630hqkBVj18p4kxfrrvCtcdybeFOF2YFdpanxoMen1PSJQJOzFoobPSv9cwb5OGLNVbwZv+14i0I8EEfFLDlpEDYj4mUGCgfDBW6aSaIeH9mPY4xYj++W4PlhCp3RtNA2+1xfKYYi/Ju9JeFeAr+WpHFNfy1V6GCh/M6ohntt2hDaBu8Em25Yzm2ub/pg6xHOOd1xj36pN7haKLsBgiAx3xQcX7kVPlUey0F0XktC31c/JxKWvfmyOXqTsjOtk3aWMEB7BQ+W2b6RSOS3H3+vU9KJHq990voUjirHPdYL+MPkRBgWcNA7LNW7YYGKxEdfs7tM4fHgkGFGqUD85UU5CKkzfZ9unNDmrcjlzFClAEzPclK+XZC/dx3XJZX2yfCcCo2SkByMNtIl2MslGmb4SlEVxlYk6pN6d8nOf8l72VR8/ROoPv0XSJJROsQ07tFNwqJ5G/9U8HStcLtRApjHy+lTZ0BFoilXgkNKRz9JAfLn7y7CxAGUUX8Ek3i0w5uccO/TGRDr3nGLt9CRdrqb+zsh03klqGTa76kkqBE9ch6M3smBR/+geP4/GY3yGgKRUjNvT6QT3rneINW+Jfl2TowQo9OsyqWPJOvpJfHm7U3utIm4F+DDrUKhesWst0w9wmzpJuh8RIIGkEP5Qd8RRLXmXd+QUHfwImJIGOLqoDK8hgKeK6lIJSY4xXvXYEFKgfTTwYQibK2vFvHZEnJaUynNg3qAjA8boSwgyqaufpNoxpyYE+8R43cIl/crq9eiwMo0iI5kYYepW2DvKjNTSti+TUbrS68yE11W9A4I0GsuwDbXjpd1bo64sx3ODmZjMfZ4mDwRFekq4Wg64uBWNNuVea00x9SC1qJUF1wk9TsyIgTFUjaWiTqZuEBEWcRsqcqB/Lps1/XpEbe+xRo5Bf5pkB4YcStfMvEu6z3iaJylXbeZGHkkm5uimUCc2XPIs/8NCsdZ9EqRyCqcQITY9+QjrLyozagWCudmN0Zi+O3eXb6ZKLdim+LrojHcy1VrquvO6dxuuZQ+vZui1jaiHvy50E5fiOa4ydjMkfqAXiWP6IVi2p3uLfTXktN11/OGi2crV5oKhL1sN0rvHsp6rWbpFhv0OPUK8gk88VB0fJ5w4km2xba1vbhXD+2D1InlkEDeSyTxqNRpfhMw8LaXOJucg3+CMlPvItuK0lrPX3vQ8XrWbsfw1tjtuS+ARP+CmPj93r9/FkbTb8ePzwVQaTXyiElmwEP/czcp9C/vH2/b5QVNx2vUqxRWsNcEK4ZJItlgsfFjlaFLCts+HFt8MJ7LDnwRmpbXod8x9uNqDMS5hBHFV34ftz73DLeCYyHg6U8+mO1aEQi0BjtOiwrhdt0fRvK7UqU7xBMOJrjw49vOwikrzjBUT3rRkwFFk9iEJ/MJUynq/9rstTTSYgKQBSmSsUgmyup7l1pnSKtSObJ3BHDrVweobr4w9a9YwYxHxkqadhO77K3aWg4nx727dbDqlvjJJxm45F5+bZiZbcU1gDonnqWeMFW114bjcvjVBbJNs9Gdd7C+ZeR/kwaMfVg7dmm/h6xJRvbXju4N4HUF1yP3pfeSDeuuybN6uJsOyDT5NM7OOQMvspwIJN2ZLxl8cUzIm5oHXeWyTVaRw05KYntwWD7R5DEC+lrZRioph9F4v+lRFYVsdXs8leUJWTl5E14gLby3jL9wi+cwudXHLRlRDXJ5aQre4ZkS6qcYU3jpTZgghqyWKoUGa6zha0crs9HPhgXuip8cbftZ3YQTvT923tvgDYDFmjEY1/IQByicaJFWaAk/MRNJnc4o27z8pPlxPsrOQ4HjXV4UexZsgoGeMTp22jHhSQn+r53kg5RINnk6oPiyWU+fowmTfx8WkGph1jczgVmYuHjC7Ie3x8t6NIrhh0LAkvcbYWjIuZbC06K18O6Gpyge44Fjnldse+vjm7ETxkg8q0MfL/Z1wSwpsOVgiuja/OAkcWrq8XFE7Lac/Ep2CYz1dSCSZSloO1/TzClXt3PfS04JEaEe/elsTN8KCw5zYN7yURqxumWeBHCYTfEjlMyambp4rsBRbsTYZTu+wMJ7V7jDUrlFg8rKyiXokiqf+ruPcSuDm7TjyB7U39w9iP+1NsLShsx1AksIFJl9LmM0SWNt0VX6+29xZY71MiCdBR+ypZX0c3Xm0I2aofL3txI4HDiQraGZmuOc1E0ZEUPpZCa5sv4rXFQPc7cfjgXj6kYxWSzSqfDnXdllp0Vj5GGEQBT3DwjF+2mOmfGIsEl3h03++k417KcQx4pFhHj/eWK5WsEws0B7z+XqlsPuacyojDVam46mM5eZX6hwkEeTjo1kMbUbirYQTSr/rKbFI8AEY2Fdwv7rhs9N5k/bAKjX04msMaqNyCz5ysMEx86OuBoERJSn3FLOWTu98mhO91ZWWVD1Njrf2ej+nvk0ntKkZKxfgVCPFrilN/XJjRbAu6MOpoMxp9OGB8KTblKaD0uaNoNQobKcPaYZMA2HOX71oahixeWPjnq4fjFVTHFZsnzQemwghwKRQyNwI17gCI04VSkNNWCgfMk1vBSsyzpSbVhKGlVggtvmQjFv9hlhbTQ7og2b+CTVKsGfahm3CC7rctkfNYVeLm0ZeCQWlX8u1ffqyCZt+3JzhsT4BgXTsbNDgl5imljCjgcUVplsptp8MlCY636rn2HcwP/IfmqMyk+Hwqxy3I45H6BJXJxs89Us9AY255p5qz2aRX6OfYSCjqQcjLAizkDxQGF+uj4gPHCVZux/eDQlBuEHENbSfl0BQFKqr5cTXsbFZThK1PHH143JfZcjb2KbjRo3qDhYBdg86lWZt60/kjptzI7CRWBSiDTQElH7Imqz6kzFSIUTzCe75TGL8Y1ekHiKhzUk4LhKbn+io77jI59iWhuvKnL4aDKM7IZnBeqhIIn7/bUe4145wdbCV7nhlP3h43TA71kh0xYfDcA2pPNB7nZd7VYeGqDTvNKJZRKj7lPyfOKHzDckTWEIAoOM9LzT6UZ5tYmlnYGsJNr9EBkVyDhybnoX+JZIo6l9A/vXnbBplFy4WNMqO5dvTn0doV0ig4k2G7vrR14GNgSZdRPRpS2AWFyc1H3r00Z4uXzhJXNQzHnkr4QndcavP2BpxaWgmbRovo26V38FjU5JhiMbceXvSz0o3W5Qckty1X/T8Iy2XltBNLOVZ+WLWHpZywrX+7UkmvAEciyZ5mvAwY1gl/cI+c+MEPQnlwthNc2dq4WHRdRT1BI8eBrW4E1nKmo8+1F6y3OFEaVgiQTu8wkhWJNZkYk9Ny981oyLsB4+VaCvbUncylXe/Rx0z7Vs7FKjTLadokKs8rEYXsmtFa00o90e/hUuoXf+ZnKX0c3xara1W7N1rN7/se8RPpytlhDnntHbZdmBZ5GGC46hOCoLHV6tQyWMyAtwaC/UZh0WOXFC57C3w9w62EZuf+dPybO1IOWiY+Ou/Ybp6L0Ax4DNFk9LupjbwzwQqy5TJlIQBgBuw5404+bnDY2UJsYNcYtAZfo369+Xs0DNK3+m+e0deSbq7h4mVYf6/UWwdAVonHgAAmOdOXupfkNrZWpmbG9hewg7z7yH/IFoNLbBsYEeTMNpiUgUph8tK792FCexW48xmzCF6SuObEoLrd1qdn/hSHHEmwBFxM3BrkhXrIMEHEtwIHN/jRC3pzcIb0MQVTb3Fpj3rv+GcT+nf7dd9l61Ejycc/ZTWxw8nsReycj9AX3NpxU7xBQxty+fHjoEcs0wHFs9j30cm38L0UnLa5mQDxp8JlpBhVqbaRH3oICWn6XIeouYcX2dP7MQv7wXpdTw4TXGR0NWiK2q+FqfDakf8qp14YZp5byefm+A1TabsfHv1vTs5I2aaN1p66NJfgiMjrjKvE/8zODlXNrKmAACQgTlvcMjOK6GFlb6B+SXGhe6XoP95ZcnMwMD6G/q39wr+AkD45YpI82sKA0s7EzvnS8hn/V3sP3Zxbpdbg/XMDPT/113+/1H/vvyoy4G+VwwaXt+Wq60rpu+v/rLHKc6jhBjYOpjoGfyvnfwN+8eD8Fskf3DzZrkIPps+2OoSheK+KMcfV435YoyXMXXzghQX9PRvQoIfEFqATSyh9kHdHLnv2NGaN8qFJQcZrmkxV7vW1SHck9a8qiCg9BnAmVnNelN34i5yvBDN9qRNhhHlnn5uEB/meN+OxpexuxwqYrmCKRGd9zkP1IM2JVQHjfu4pg17e+HsyMnJNg7C7CW7HU4rvr4yvOaCBOgNHHVv1Qu96OBs1GQkwgQdZzQLjbshrfuofOvOZfnrrYEAAHQCF92NWoAtTQwNIHaXmNDk58D9dds1NDG6xGgz/Rr17wurM9jiv43IFayAAsuBJnEKCaRE7PWQvTuNB4v+WXY4Jk09jw3PscbQqVMuyIQS3jgH/NwbL+Y2gy+y8TjGyuH9Frk6x5XDlcQVVXqRCgt8ggN52s2S9sgKEARJddwzVmGUD576LjXVwZV/iq39CiPUEAAAz8tXR9/A2tzK+RI1Z/g1KpuZPcTOysLExeAS+KwXwWfTBUMus5wLX5jk73+1MLC0gx51u/Dqu/AcaD6Hgk1Vdcia8RhPImcYXaKKMFBbnujCjZTenjYqZhpmoLuRTJvBKi+oEWdwb81jz+Nunu5QMOLqSEw7/ivb3qfetrDBjEbwQ7m4brYF8baw0Ulq7rTsYp7UE+WdC/Wa6eFGCVen3mikhKzpptOzhRH3w6Bmbw2MoiX0k85gwR6FxjF2eTc6mQdm5p1SpUYOL8MqLu2uXXN41BG/nP4qmmZWS8R4I1r427vQZSG0vAUAANjAnFclsYtX6Z9fwXYmVpbQhWJuL0B/x46F0HuSsQ7LIetfBStUbSO82LGh+QlC5bvEIL2fFssj3JeYwTA47n/TAztoKT5ZdY3MpFTPA/xJjdFeZtomR9CYkdTSlW39+n3V/BwH7sUAI8vsO/V9mPhHDFS139aiJqS25r/aw+rcOSBwcXd/L/XQvvS7OFAa2NF8pzUzexFgl5Tf7sI+ill95wx/vwWnsHVf7lappUg/onx1DXbqQwJhy+1X7ngeVKEPRQUUVUB4uqsV4rwFrgONXKaTRMa87fv2QSRGd1RQJo10DXfz3+qCvu6o5sqZmrfO+c9HoXNFvw1HzTo8xXD/NpJvH/XmuQAAkHVuU3FeyKuVg4GtOdgZconu5b8UEZu+gYOBuZX1JTpZ5o8I/17HLcDW0GMqGPKfpr5yKNiUue3ITGorFyIhaYV9FbY7DGeN6joZGTb3kLOg3nN1lwhhRRaf2Qn3DByksOKq9K+NXQYcGOZ3MOgTfHUi4wvbDNJwlFjzirrGxpZPeIasumW/2gDsaeT9Jt2Af68BWtzUEniU2/P1SJq1XI/5GrxnC4umiBSLXBhbqMJBP50LT/EHEVX5BxgKWILZE90sg+NIHxxtar/tJugKN7HTAAA4OLdGsn9Wo5+tfPpdBX9NfPjecW0bESxZlZ5jv1UqPu8smiBV+IM9GgTHV7QbGKvXt9v0jPdQnhCWbmlpLas3Pe47GF1UC2aITxuELSNkisQHRXbcmyTuQMpV4T8+ePRqKGf8/qBzMEPdpoW475MDeZibH09vLzdH5bTQ/eNatHCJzx4AgKJzXYP+zPV5K1knyNRHFOv2hntiCpvOk8peFSQ1hEK20dqM3pMX2STWd0XQZk/2kriOxXlyaPyOufLUkqcedLwmXtNuftjSwtVgkKLZgdOwl9NYjJ+CkW0kny8trkP2vEUNjcun57rcrNym2GDjgMiXoUpebpDIIvHEe2+HQabUryxB+qpRPoT4b2zJ7kpso/xTjaP01qO/dl7Zf7AZsNIzu9RzD8Zfo7JJ/OcCdX7GFnVzT6m1Tf4Owwf5TobWTrlizg9FUzOKGaxTisoUgOCxtziJuxuJuODxcZalQGy29rNbZZ7hpUFGWH5dB08QEDRCWVlRJF817adLtr1aRHnwgn+n/vX2tpwiBHUbwrklyzRzFXK/88425OqNLazXooK5L+6J+H4KHjvCRVhB4WJ4fRiqM8xITw/vz3vF9964oWr4O8HWuS+oKBT5PDDfeivFMmz+JQAAarAX/WL4fQX+/4UVYnzmmMGgfHvngLwsc/fUjKIyUlsrszJ9t3RXm0Irs7J0jjSIlUUGpCAtC+pgk1WSbpPvvsuiKM3Y1SnTNwsLJ/rtRhdRpLghDgCA6IU33bYGECt7W73LbNBIz4FjM+HgtbzEPKL9Feb/yQOObwzW9rrmJnqXqMX1X6OyGdtZXObRFctvQv9xZWh/g8ja3N7I5DIDy/bb4H/sg/43qP5g2jNfAJ5NDwL5Hz1mOI/ij0vGehFCEwuw0WW+a/FcmOSPfTFdhNL0MkPFdTGGP3ZEeR7fP//xP7qB/wv3j9X/6HGWvZ2J+eWeilP8HO2PlWL+G/schTCwuHD/1Xj22DQZgPztc2mP/vr7N89mfw969tQyERSozU9Avzt//T3g2dOShFCAt2GAXx99/h7u7CHIa1BwFAjAbxy4/C/ej49O/v8fLGBF7NkP8KAPUv4cCR8KaebHSNAHKaFtnj1USA5lk+0K8NsHKb9HPXsiEB8aFRH41fHE78HOvg8ADdb6Y7CzRwrPKx4hVPEIKIDfeaHg53AkUHCG58B990IBtN2z6TU1lN3yX0B+/0LBeWLJocSqUgEXyMKh9Z6NqBmg9Ob+GvUHWfh5qqmhVFNTAxeMvaGVn81vmaGUu/8e8nmN8OMg+L/i664Dvx8LQ+s+u+LTQenGowEuHAufJ5kGSrLTr9H/lQj/XDkrlPLB38W+mAHoaS5MC1wgDIaWfjalhZ7m0b9G/UEYfJ5qCijViHTARZLfn1ccWrbWb8BerNgMULIbfgf/QgssC3T30wOXDn1/XiNuqBr5X5TjYgVjhjK0fzGy3/NzE8qPBgPwh3nv91xn41ECKK6uH3B9H/X+/t05nRH4nYD1d1eC7XPg/h2wQls+G1IyQVmWZQIuFbD+vm4cZuAC0efvtqrxr1F/GH3+HJ8VCr/1IvjfR5/f7Y7OBHzCUMVnYQH+V9Hn96RnczcxKNL7rMD/MEn8nvdsBiYAxcvBBvxPMr7zxpATagxJ2YE/S9p+TsQPReR3KaIfJG3QtTybKMlA1XLvjwh/lrR9z38225GF4ifmBP4vUqzvBZyNU0BQArBvAP9HgdLvL2zkXMAFYhxoZ2cDDUYoZ/a/Rv1RjPOvZxVn4oizm6iVR443gUukJL9/2yPiBn4n4vg5HCkUnMk5cN9HHD/fU9BC1bj6V5h/smMn5wEukG78HPU6FKr9r1G/Tzd+Xg0WqGr0/ib0xYpCCyWfjxe4eLDxcwNsUAZifhv8YhbooSzA8AGXyTR+dyutcwH47zKN391KN1yQ4mLVgt4/cfEDl48zfm6IB8rQ8wuTXMwSE5QlNAHgkknGz/1wQfmxvBjDxcxQQpmZOI/qByHGzy1A3764BYHLhBjnCSeAEp7wA4J/5xc/l0sBJXf552gXE4l5RuSpmJQQcE50gXDlr8+JA+JANiEABAv99dv/CwAA///bIvMUTVYAAA=="); err != nil { + if err := gres.Add("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"); err != nil { panic("add binary content to resource manager failed: " + err.Error()) } } diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index 721f354d1..7d523cc0e 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -331,9 +331,6 @@ var ( // in the field name as it conflicts with "db.table.field" pattern in SOME situations. regularFieldNameWithoutDotRegPattern = `^[\w\-]+$` - // tableFieldsMap caches the table information retrieved from database. - tableFieldsMap = gmap.New(true) - // allDryRun sets dry-run feature for all database connections. // It is commonly used for command options for convenience. allDryRun = false @@ -399,8 +396,7 @@ func doNewByNode(node ConfigNode, group string) (db DB, err error) { config: &node, } if v, ok := driverMap[node.Type]; ok { - c.db, err = v.New(c, &node) - if err != nil { + if c.db, err = v.New(c, &node); err != nil { return nil, err } return c.db, nil diff --git a/database/gdb/gdb_core_config.go b/database/gdb/gdb_core_config.go index 451a14926..bbc1021d1 100644 --- a/database/gdb/gdb_core_config.go +++ b/database/gdb/gdb_core_config.go @@ -13,6 +13,8 @@ import ( "github.com/gogf/gf/v2/os/gcache" "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" ) // Config is the configuration management object. @@ -72,6 +74,12 @@ func SetConfig(config Config) { defer instances.Clear() configs.Lock() defer configs.Unlock() + for k, nodes := range config { + for i, node := range nodes { + nodes[i] = parseConfigNode(node) + } + config[k] = nodes + } configs.config = config } @@ -80,6 +88,9 @@ func SetConfigGroup(group string, nodes ConfigGroup) { defer instances.Clear() configs.Lock() defer configs.Unlock() + for i, node := range nodes { + nodes[i] = parseConfigNode(node) + } configs.config[group] = nodes } @@ -88,7 +99,19 @@ func AddConfigNode(group string, node ConfigNode) { defer instances.Clear() configs.Lock() defer configs.Unlock() - configs.config[group] = append(configs.config[group], node) + configs.config[group] = append(configs.config[group], parseConfigNode(node)) +} + +// parseConfigNode parses `Link` configuration syntax. +func parseConfigNode(node ConfigNode) ConfigNode { + if node.Link != "" && node.Type == "" { + match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link) + if len(match) == 3 { + node.Type = gstr.Trim(match[1]) + node.Link = gstr.Trim(match[2]) + } + } + return node } // AddDefaultConfigNode adds one node configuration to configuration of default group. diff --git a/database/gredis/gredis_z_unit_test.go b/database/gredis/gredis_z_unit_test.go index 2671fbc97..5537a4c58 100644 --- a/database/gredis/gredis_z_unit_test.go +++ b/database/gredis/gredis_z_unit_test.go @@ -168,9 +168,13 @@ func Test_Error(t *testing.T) { _, err = conn.Do(ctx, "Subscribe", "gf") t.AssertNil(err) + time.Sleep(time.Second) + _, err = redis.Do(ctx, "PUBLISH", "gf", "test") t.AssertNil(err) + time.Sleep(time.Second) + v, err = conn.Receive(ctx) t.AssertNil(err) t.Assert(v.Val().(*gredis.Subscription).Channel, "gf") diff --git a/frame/gins/gins_database.go b/frame/gins/gins_database.go index d68b10a0c..66d1bb742 100644 --- a/frame/gins/gins_database.go +++ b/frame/gins/gins_database.go @@ -16,8 +16,6 @@ import ( "github.com/gogf/gf/v2/internal/consts" "github.com/gogf/gf/v2/internal/intlog" "github.com/gogf/gf/v2/os/gcfg" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gutil" ) @@ -173,13 +171,5 @@ func parseDBConfigNode(value interface{}) *gdb.ConfigNode { if _, v := gutil.MapPossibleItemByKey(nodeMap, "Link"); v != nil { node.Link = gconv.String(v) } - // Parse `Link` configuration syntax. - if node.Link != "" && node.Type == "" { - match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link) - if len(match) == 3 { - node.Type = gstr.Trim(match[1]) - node.Link = gstr.Trim(match[2]) - } - } return node } diff --git a/frame/gins/gins_server.go b/frame/gins/gins_server.go index 883eeeea7..e940649a2 100644 --- a/frame/gins/gins_server.go +++ b/frame/gins/gins_server.go @@ -83,6 +83,9 @@ func Server(name ...interface{}) *ghttp.Server { ctx, fmt.Sprintf(`%s.%s.%s`, configNodeName, instanceName, consts.ConfigNodeNameLogger), ).Map() + if len(serverLoggerConfigMap) == 0 && len(serverConfigMap) > 0 { + serverLoggerConfigMap = gconv.Map(serverConfigMap[consts.ConfigNodeNameLogger]) + } if len(serverLoggerConfigMap) > 0 { if err = server.Logger().SetConfigWithMap(serverLoggerConfigMap); err != nil { panic(err) diff --git a/net/gclient/gclient_request_obj.go b/net/gclient/gclient_request_obj.go index 4fa48bd3e..0ca897e5a 100644 --- a/net/gclient/gclient_request_obj.go +++ b/net/gclient/gclient_request_obj.go @@ -18,6 +18,7 @@ import ( "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gmeta" + "github.com/gogf/gf/v2/util/gutil" ) // DoRequestObj does HTTP request using standard request/response object. @@ -81,13 +82,14 @@ func (c *Client) DoRequestObj(ctx context.Context, req, res interface{}) error { // /user/{name} -> /order/john func (c *Client) handlePathForObjRequest(path string, req interface{}) string { if gstr.Contains(path, "{") { - requestParamsMap := gconv.MapStrStr(req) + requestParamsMap := gconv.Map(req) if len(requestParamsMap) > 0 { path, _ = gregex.ReplaceStringFuncMatch(`\{(\w+)\}`, path, func(match []string) string { - if v, ok := requestParamsMap[match[1]]; ok { - return v + foundKey, foundValue := gutil.MapPossibleItemByKey(requestParamsMap, match[1]) + if foundKey != "" { + return gconv.String(foundValue) } - return match[1] + return match[0] }) } } diff --git a/net/gclient/gclient_response.go b/net/gclient/gclient_response.go index 84fef34d8..27869aa85 100644 --- a/net/gclient/gclient_response.go +++ b/net/gclient/gclient_response.go @@ -7,6 +7,7 @@ package gclient import ( + "bytes" "io/ioutil" "net/http" @@ -69,6 +70,13 @@ func (r *Response) ReadAllString() string { return string(r.ReadAll()) } +// SetBodyContent overwrites response content with custom one. +func (r *Response) SetBodyContent(content []byte) { + buffer := bytes.NewBuffer(content) + r.Body = ioutil.NopCloser(buffer) + r.ContentLength = int64(buffer.Len()) +} + // Close closes the response when it will never be used. func (r *Response) Close() error { if r == nil || r.Response == nil { diff --git a/net/gclient/gclient_z_unit_request_obj_test.go b/net/gclient/gclient_z_unit_request_obj_test.go index 7c9d2da0e..cc0435f56 100644 --- a/net/gclient/gclient_z_unit_request_obj_test.go +++ b/net/gclient/gclient_z_unit_request_obj_test.go @@ -27,7 +27,8 @@ func Test_Client_DoRequestObj(t *testing.T) { Id int } type UserQueryReq struct { - g.Meta `path:"/user" method:"get"` + g.Meta `path:"/user/{id}" method:"get"` + Id int } type UserQueryRes struct { Id int @@ -36,8 +37,8 @@ func Test_Client_DoRequestObj(t *testing.T) { p, _ := gtcp.GetFreePort() s := g.Server(p) s.Group("/user", func(group *ghttp.RouterGroup) { - group.GET("/", func(r *ghttp.Request) { - r.Response.WriteJson(g.Map{"id": 1, "name": "john"}) + group.GET("/{id}", func(r *ghttp.Request) { + r.Response.WriteJson(g.Map{"id": r.Get("id").Int(), "name": "john"}) }) group.POST("/", func(r *ghttp.Request) { r.Response.WriteJson(g.Map{"id": r.Get("Id")}) @@ -68,7 +69,9 @@ func Test_Client_DoRequestObj(t *testing.T) { client := g.Client().SetPrefix(url).ContentJson() var ( queryRes *UserQueryRes - queryReq = UserQueryReq{} + queryReq = UserQueryReq{ + Id: 1, + } ) err := client.DoRequestObj(ctx, queryReq, &queryRes) t.AssertNil(err) diff --git a/net/gclient/gclient_z_unit_test.go b/net/gclient/gclient_z_unit_test.go index 410645449..599ce889c 100644 --- a/net/gclient/gclient_z_unit_test.go +++ b/net/gclient/gclient_z_unit_test.go @@ -640,3 +640,27 @@ func TestClient_RequestVar(t *testing.T) { t.AssertNE(users, nil) }) } + +func TestClient_SetBodyContent(t *testing.T) { + p, _ := gtcp.GetFreePort() + s := g.Server(p) + s.BindHandler("/", func(r *ghttp.Request) { + r.Response.Write("hello") + }) + s.SetPort(p) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + + time.Sleep(100 * time.Millisecond) + gtest.C(t, func(t *gtest.T) { + c := g.Client() + c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p)) + res, err := c.Get(ctx, "/") + t.AssertNil(err) + defer res.Close() + t.Assert(res.ReadAllString(), "hello") + res.SetBodyContent([]byte("world")) + t.Assert(res.ReadAllString(), "world") + }) +} diff --git a/net/ghttp/ghttp.go b/net/ghttp/ghttp.go index 66c1ae479..c48367245 100644 --- a/net/ghttp/ghttp.go +++ b/net/ghttp/ghttp.go @@ -117,21 +117,22 @@ const ( ) const ( - supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE" - defaultMethod = "ALL" - exceptionExit = "exit" - exceptionExitAll = "exit_all" - exceptionExitHook = "exit_hook" - routeCacheDuration = time.Hour - ctxKeyForRequest = "gHttpRequestObject" - contentTypeXml = "text/xml" - contentTypeHtml = "text/html" - contentTypeJson = "application/json" - swaggerUIPackedPath = "/goframe/swaggerui" - responseTraceIDHeader = "Trace-ID" - specialMethodNameInit = "Init" - specialMethodNameShut = "Shut" - specialMethodNameIndex = "Index" + supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE" + defaultMethod = "ALL" + exceptionExit = "exit" + exceptionExitAll = "exit_all" + exceptionExitHook = "exit_hook" + routeCacheDuration = time.Hour + ctxKeyForRequest = "gHttpRequestObject" + contentTypeXml = "text/xml" + contentTypeHtml = "text/html" + contentTypeJson = "application/json" + swaggerUIPackedPath = "/goframe/swaggerui" + responseTraceIDHeader = "Trace-ID" + specialMethodNameInit = "Init" + specialMethodNameShut = "Shut" + specialMethodNameIndex = "Index" + gracefulShutdownTimeout = 5 * time.Second ) var ( diff --git a/net/ghttp/ghttp_server_graceful.go b/net/ghttp/ghttp_server_graceful.go index 7d57cd53b..073f9f867 100644 --- a/net/ghttp/ghttp_server_graceful.go +++ b/net/ghttp/ghttp_server_graceful.go @@ -215,7 +215,9 @@ func (s *gracefulServer) shutdown(ctx context.Context) { if s.status == ServerStatusStopped { return } - if err := s.httpServer.Shutdown(context.Background()); err != nil { + timeoutCtx, cancelFunc := context.WithTimeout(ctx, gracefulShutdownTimeout) + defer cancelFunc() + if err := s.httpServer.Shutdown(timeoutCtx); err != nil { s.server.Logger().Errorf( ctx, "%d: %s server [%s] shutdown error: %v", diff --git a/net/gtcp/gtcp_func.go b/net/gtcp/gtcp_func.go index 78848cea8..bb30c47ca 100644 --- a/net/gtcp/gtcp_func.go +++ b/net/gtcp/gtcp_func.go @@ -196,7 +196,13 @@ func GetFreePort() (port int, err error) { ) } port = l.Addr().(*net.TCPAddr).Port - err = l.Close() + if err = l.Close(); err != nil { + err = gerror.Wrapf( + err, + `close listening failed for network "%s", address "%s", port "%d"`, + network, resolvedAddr.String(), port, + ) + } return } diff --git a/os/gcmd/gcmd.go b/os/gcmd/gcmd.go index d8a3a97e9..139b60c82 100644 --- a/os/gcmd/gcmd.go +++ b/os/gcmd/gcmd.go @@ -24,9 +24,10 @@ const ( ) const ( - helpOptionName = "help" - helpOptionNameShort = "h" - maxLineChars = 120 + helpOptionName = "help" + helpOptionNameShort = "h" + maxLineChars = 120 + tracingInstrumentName = "github.com/gogf/gf/v2/os/gcmd.Command" ) // Init does custom initialization. diff --git a/os/gcmd/gcmd_command_help.go b/os/gcmd/gcmd_command_help.go index 7f9ff472a..ab43641e9 100644 --- a/os/gcmd/gcmd_command_help.go +++ b/os/gcmd/gcmd_command_help.go @@ -11,12 +11,19 @@ import ( "bytes" "context" "fmt" + "io" + "os" "github.com/gogf/gf/v2/text/gstr" ) // Print prints help info to stdout for current command. func (c *Command) Print() { + c.PrintTo(os.Stdout) +} + +// PrintTo prints help info to custom io.Writer. +func (c *Command) PrintTo(writer io.Writer) { var ( prefix = gstr.Repeat(" ", 4) buffer = bytes.NewBuffer(nil) @@ -191,7 +198,7 @@ func (c *Command) Print() { } content := buffer.String() content = gstr.Replace(content, "\t", " ") - fmt.Println(content) + _, _ = writer.Write([]byte(content)) } type printLineBriefInput struct { diff --git a/os/gcmd/gcmd_command_run.go b/os/gcmd/gcmd_command_run.go index c267665dc..1826257b4 100644 --- a/os/gcmd/gcmd_command_run.go +++ b/os/gcmd/gcmd_command_run.go @@ -8,16 +8,24 @@ package gcmd import ( + "bytes" "context" "fmt" "os" + "github.com/gogf/gf/v2" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/net/gtrace" "github.com/gogf/gf/v2/os/gcfg" + "github.com/gogf/gf/v2/os/genv" + "github.com/gogf/gf/v2/os/glog" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gutil" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/trace" ) // Run calls custom function that bound to this command. @@ -34,18 +42,23 @@ func (c *Command) RunWithValue(ctx context.Context) (value interface{}) { var ( code = gerror.Code(err) detail = code.Detail() + buffer = bytes.NewBuffer(nil) ) if code.Code() == gcode.CodeNotFound.Code() { - fmt.Printf("ERROR: %s\n", gstr.Trim(err.Error())) + buffer.WriteString(fmt.Sprintf("ERROR: %s\n", gstr.Trim(err.Error()))) if lastCmd, ok := detail.(*Command); ok { - lastCmd.Print() + lastCmd.PrintTo(buffer) } else { - c.Print() + c.PrintTo(buffer) } } else { - fmt.Printf("%+v\n", err) + buffer.WriteString(fmt.Sprintf("%+v\n", err)) } - os.Exit(1) + if gtrace.GetTraceID(ctx) == "" { + fmt.Println(buffer.String()) + os.Exit(1) + } + glog.Stack(false).Fatal(ctx, buffer.String()) } return value } @@ -107,6 +120,24 @@ func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{}, } return nil, c.defaultHelpFunc(ctx, parser) } + // OpenTelemetry for command. + var ( + span trace.Span + tr = otel.GetTracerProvider().Tracer( + tracingInstrumentName, + trace.WithInstrumentationVersion(gf.VERSION), + ) + ) + ctx, span = tr.Start( + otel.GetTextMapPropagator().Extract( + ctx, + propagation.MapCarrier(genv.Map()), + ), + gstr.Join(os.Args, " "), + trace.WithSpanKind(trace.SpanKindServer), + ) + defer span.End() + span.SetAttributes(gtrace.CommonLabels()...) // Reparse the arguments for current command configuration. parser, err = c.reParse(ctx, parser) if err != nil { @@ -126,7 +157,7 @@ func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{}, return nil, c.defaultHelpFunc(ctx, parser) } -// reParse re-parses the arguments using option configuration of current command. +// reParse parses the arguments using option configuration of current command. func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error) { if len(c.Arguments) == 0 { return parser, nil diff --git a/os/gctx/gctx.go b/os/gctx/gctx.go index a81138379..e04066ae9 100644 --- a/os/gctx/gctx.go +++ b/os/gctx/gctx.go @@ -9,8 +9,12 @@ package gctx import ( "context" + "os" + "strings" "github.com/gogf/gf/v2/net/gtrace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" ) type ( @@ -18,13 +22,36 @@ type ( StrKey string // StrKey is a type for warps basic type string as context key. ) +var ( + // processCtx is the context initialized from process environment. + processCtx context.Context +) + +func init() { + // All environment key-value pairs. + m := make(map[string]string) + i := 0 + for _, s := range os.Environ() { + i = strings.IndexByte(s, '=') + m[s[0:i]] = s[i+1:] + } + // OpenTelemetry from environments. + processCtx = otel.GetTextMapPropagator().Extract( + context.Background(), + propagation.MapCarrier(m), + ) +} + // New creates and returns a context which contains context id. func New() context.Context { - return WithCtx(context.Background()) + return WithCtx(processCtx) } // WithCtx creates and returns a context containing context id upon given parent context `ctx`. func WithCtx(ctx context.Context) context.Context { + if CtxId(ctx) != "" { + return ctx + } if gtrace.IsUsingDefaultProvider() { var span *gtrace.Span ctx, span = gtrace.NewSpan(ctx, "gctx.WithCtx") diff --git a/os/gfile/gfile_cache.go b/os/gfile/gfile_cache.go index 526bec196..731cb1cef 100644 --- a/os/gfile/gfile_cache.go +++ b/os/gfile/gfile_cache.go @@ -10,6 +10,8 @@ import ( "context" "time" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/command" "github.com/gogf/gf/v2/internal/intlog" "github.com/gogf/gf/v2/os/gcache" @@ -17,22 +19,28 @@ import ( ) const ( - defaultCacheExpire = "1m" // defaultCacheExpire is the expire time for file content caching in seconds. + defaultCacheDuration = "1m" // defaultCacheExpire is the expire time for file content caching in seconds. commandEnvKeyForCache = "gf.gfile.cache" // commandEnvKeyForCache is the configuration key for command argument or environment configuring cache expire duration. ) var ( // Default expire time for file content caching. - cacheExpire = getCacheExpire() + cacheDuration = getCacheDuration() // internalCache is the memory cache for internal usage. internalCache = gcache.New() ) -func getCacheExpire() time.Duration { - d, err := time.ParseDuration(command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheExpire)) +func getCacheDuration() time.Duration { + cacheDurationConfigured := command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheDuration) + d, err := time.ParseDuration(cacheDurationConfigured) if err != nil { - panic(err) + panic(gerror.WrapCodef( + gcode.CodeInvalidConfiguration, + err, + `error parsing string "%s" to time duration`, + cacheDurationConfigured, + )) } return d } @@ -50,7 +58,7 @@ func GetContentsWithCache(path string, duration ...time.Duration) string { func GetBytesWithCache(path string, duration ...time.Duration) []byte { var ( ctx = context.Background() - expire = cacheExpire + expire = cacheDuration cacheKey = commandEnvKeyForCache + path ) diff --git a/os/gfsnotify/gfsnotify_watcher_loop.go b/os/gfsnotify/gfsnotify_watcher_loop.go index 7621ffb5e..5b6811b1b 100644 --- a/os/gfsnotify/gfsnotify_watcher_loop.go +++ b/os/gfsnotify/gfsnotify_watcher_loop.go @@ -120,7 +120,7 @@ func (w *Watcher) eventLoop() { } // Calling the callbacks in order. - for _, v := range callbacks { + for _, callback := range callbacks { go func(callback *Callback) { defer func() { if err := recover(); err != nil { @@ -133,7 +133,7 @@ func (w *Watcher) eventLoop() { } }() callback.Func(event) - }(v) + }(callback) } } else { break diff --git a/os/glog/glog.go b/os/glog/glog.go index fae74aff6..15c9a6576 100644 --- a/os/glog/glog.go +++ b/os/glog/glog.go @@ -8,8 +8,9 @@ package glog import ( - "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/internal/command" "github.com/gogf/gf/v2/os/grpool" + "github.com/gogf/gf/v2/util/gconv" ) const ( @@ -30,7 +31,7 @@ var ( ) func init() { - defaultDebug = gcmd.GetOptWithEnv(commandEnvKeyForDebug, true).Bool() + defaultDebug = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForDebug, "true")) SetDebug(defaultDebug) } diff --git a/os/glog/glog_logger_handler_json.go b/os/glog/glog_logger_handler_json.go index a35536b76..20b82c74e 100644 --- a/os/glog/glog_logger_handler_json.go +++ b/os/glog/glog_logger_handler_json.go @@ -14,15 +14,15 @@ import ( // HandlerOutputJson is the structure outputting logging content as single json. type HandlerOutputJson struct { - Time string // Formatted time string, like "2016-01-09 12:00:00". - TraceId string // Trace id, only available if tracing is enabled. - CtxStr string // The retrieved context value string from context, only available if Config.CtxKeys configured. - Level string // Formatted level string, like "DEBU", "ERRO", etc. Eg: ERRO - CallerFunc string // The source function name that calls logging, only available if F_CALLER_FN set. - CallerPath string // The source file path and its line number that calls logging, only available if F_FILE_SHORT or F_FILE_LONG set. - Prefix string // Custom prefix string for logging content. - Content string // Content is the main logging content, containing error stack string produced by logger. - Stack string // Stack string produced by logger, only available if Config.StStatus configured. + Time string `json:""` // Formatted time string, like "2016-01-09 12:00:00". + TraceId string `json:",omitempty"` // Trace id, only available if tracing is enabled. + CtxStr string `json:",omitempty"` // The retrieved context value string from context, only available if Config.CtxKeys configured. + Level string `json:""` // Formatted level string, like "DEBU", "ERRO", etc. Eg: ERRO + CallerFunc string `json:",omitempty"` // The source function name that calls logging, only available if F_CALLER_FN set. + CallerPath string `json:",omitempty"` // The source file path and its line number that calls logging, only available if F_FILE_SHORT or F_FILE_LONG set. + Prefix string `json:",omitempty"` // Custom prefix string for logging content. + Content string `json:""` // Content is the main logging content, containing error stack string produced by logger. + Stack string `json:",omitempty"` // Stack string produced by logger, only available if Config.StStatus configured. } // HandlerJson is a handler for output logging content as a single json string. @@ -43,5 +43,6 @@ func HandlerJson(ctx context.Context, in *HandlerInput) { panic(err) } in.Buffer.Write(jsonBytes) + in.Buffer.Write([]byte("\n")) in.Next(ctx) } diff --git a/os/gstructs/gstructs_tag.go b/os/gstructs/gstructs_tag.go index 8284fb16f..ae43ab011 100644 --- a/os/gstructs/gstructs_tag.go +++ b/os/gstructs/gstructs_tag.go @@ -62,7 +62,7 @@ func ParseTag(tag string) map[string]string { tag = tag[i+1:] value, err := strconv.Unquote(quotedValue) if err != nil { - panic(err) + panic(gerror.WrapCodef(gcode.CodeInvalidParameter, err, `error parsing tag "%s"`, tag)) } data[key] = gtag.Parse(value) } diff --git a/os/gtimer/gtimer.go b/os/gtimer/gtimer.go index bbe226d5e..3f6d801b4 100644 --- a/os/gtimer/gtimer.go +++ b/os/gtimer/gtimer.go @@ -25,6 +25,8 @@ import ( "time" "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/command" ) @@ -58,9 +60,13 @@ var ( ) func getDefaultInterval() time.Duration { - n, err := strconv.Atoi(command.GetOptWithEnv(commandEnvKeyForInterval, defaultTimerInterval)) + interval := command.GetOptWithEnv(commandEnvKeyForInterval, defaultTimerInterval) + n, err := strconv.Atoi(interval) if err != nil { - panic(err) + panic(gerror.WrapCodef( + gcode.CodeInvalidConfiguration, err, `error converting string "%s" to int number`, + interval, + )) } return time.Duration(n) * time.Millisecond } diff --git a/util/grand/grand_buffer.go b/util/grand/grand_buffer.go index 07861a515..4b101829a 100644 --- a/util/grand/grand_buffer.go +++ b/util/grand/grand_buffer.go @@ -8,6 +8,9 @@ package grand import ( "crypto/rand" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" ) const ( @@ -33,7 +36,7 @@ func asyncProducingRandomBufferBytesLoop() { for { buffer := make([]byte, 1024) if n, err := rand.Read(buffer); err != nil { - panic(err) + panic(gerror.WrapCode(gcode.CodeInternalError, err, `error reading random buffer from system`)) } else { // The random buffer from system is very expensive, // so fully reuse the random buffer by changing