diff --git a/env.yml b/env.yml new file mode 100644 index 0000000..52be3b2 --- /dev/null +++ b/env.yml @@ -0,0 +1,6 @@ +test: + aaa: 111 + bbb: + - 2 + ccc: + c2: "A-8ubk1BEEeytkVuyO9F6w==" diff --git a/file.go b/file.go index 27bb2d2..1ed7179 100644 --- a/file.go +++ b/file.go @@ -2,11 +2,17 @@ package file import ( _ "embed" + "encoding/base64" + "encoding/json" "os" + "path/filepath" + "regexp" + "strings" "apigo.cc/gojs" "apigo.cc/gojs/goja" "github.com/ssgo/u" + "gopkg.in/yaml.v3" ) //go:embed file.ts @@ -15,6 +21,19 @@ var fileTS string //go:embed README.md var fileMD string +var envConfigs map[string]map[string]any +var encryptdMatcher = regexp.MustCompile(`"([\w-=]+)"`) + +var confAes = u.NewAes([]byte("?GQ$0K0GgLdO=f+~L68PLm$uhKr4'=tV"), []byte("VFs7@sK61cj^f?HZ")) +var keysIsSet = false + +func SetSSKey(key, iv []byte) { + if !keysIsSet { + confAes = u.NewAes(key, iv) + keysIsSet = true + } +} + func init() { obj := map[string]any{ "exists": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { @@ -106,13 +125,106 @@ func init() { } return nil }, + "searchFile": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { + args := gojs.MakeArgs(&argsIn, vm).Check(1) + filename := args.Str(0) + searchPath := args.Str(1) + findFile := "" + if searchPath != "" { + findFile = searchFile(searchPath, filename) + } else { + findFile = searchFileFromCurrent(vm, filename) + } + return vm.ToValue(findFile) + }, + "loadConfig": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { + if envConfigs == nil { + envConfigs = map[string]map[string]any{} + envFile := searchFileFromCurrent(vm, "env.yml") + if envFile == "" { + envFile = searchFileFromCurrent(vm, "env.json") + } + if envFile != "" { + u.LoadX(envFile, &envConfigs) + } + } + + args := gojs.MakeArgs(&argsIn, vm).Check(1) + confName := args.Str(0) + conf := map[string]any{} + confFile := searchFileFromCurrent(vm, confName+".yml") + if confFile == "" { + confFile = searchFileFromCurrent(vm, confName+".json") + } + if confFile != "" { + u.LoadX(confFile, &conf) + } + if envConf, ok := envConfigs[confName]; ok { + u.Convert(envConf, &conf) + } + + decTimes := 0 + confStr := encryptdMatcher.ReplaceAllStringFunc(u.Json(conf), func(str string) string { + if buf, err := base64.URLEncoding.DecodeString(str[1 : len(str)-1]); err == nil { + if buf1, err1 := confAes.DecryptBytes(buf); err1 == nil && len(buf1) > 0 { + decTimes++ + return "\"" + string(buf1) + "\"" + } + } + return str + }) + if decTimes > 0 { + u.UnJson(confStr, &conf) + } + + return vm.ToValue(conf) + }, + "save": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { + args := gojs.MakeArgs(&argsIn, vm).Check(2) + filename := args.Str(0) + var data []byte + var err error + if strings.HasSuffix(filename, ".yml") || strings.HasSuffix(filename, ".yaml") { + data, err = yaml.Marshal(args.Any(1)) + } else { + data, err = json.Marshal(args.Any(1)) + } + if err == nil { + if err = u.WriteFileBytes(gojs.FindPath(vm, filename), data); err != nil { + panic(vm.NewGoError(err)) + } + return nil + } else { + panic(vm.NewGoError(err)) + } + }, + "load": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { + args := gojs.MakeArgs(&argsIn, vm).Check(1) + filename := args.Str(0) + if data, err := u.ReadFileBytes(gojs.FindPath(vm, filename)); err == nil { + var r any + if strings.HasSuffix(filename, ".yml") || strings.HasSuffix(filename, ".yaml") { + err = yaml.Unmarshal(data, &r) + } else { + err = json.Unmarshal(data, &r) + } + if err == nil { + return vm.ToValue(r) + } else { + panic(vm.NewGoError(err)) + } + } else { + panic(vm.NewGoError(err)) + } + }, } gojs.Register("apigo.cc/gojs/file", gojs.Module{ - Object: obj, - Desc: "file api by https://github.com/ssgo/u", - TsCode: fileTS, - Example: fileMD, + Object: obj, + Desc: "file api by https://github.com/ssgo/u", + TsCode: fileTS, + Example: fileMD, + SetSSKey: SetSSKey, }) } @@ -125,3 +237,36 @@ func makeFileInfo(info *u.FileInfo) map[string]any { "modTime": info.ModTime.UnixMilli(), } } + +func searchFile(searchPath, name string) string { + searched := map[string]bool{} + return _searchFile(searchPath, name, &searched) +} + +func searchFileFromCurrent(vm *goja.Runtime, name string) string { + searched := map[string]bool{} + startPath := u.String(vm.GoData["startPath"]) + filename := _searchFile(startPath, name, &searched) + if filename == "" { + currentPath, _ := os.Getwd() + filename = _searchFile(currentPath, name, &searched) + } + return filename +} + +func _searchFile(checkPath, name string, searched *map[string]bool) string { + for { + if !(*searched)[checkPath] { + (*searched)[checkPath] = true + filename := filepath.Join(checkPath, name) + if u.FileExists(filename) { + return filename + } + } + oldPath := checkPath + checkPath = filepath.Dir(oldPath) + if oldPath == checkPath { + return "" + } + } +} diff --git a/file.ts b/file.ts index 765ef3f..745ba1a 100644 --- a/file.ts +++ b/file.ts @@ -12,7 +12,11 @@ export default { remove, rename, copy, - cache + cache, + load, + save, + searchFile, + loadConfig } function exists(filename: string): boolean { return false } @@ -27,6 +31,10 @@ function remove(filename: string): void { } function rename(from: string, to: string): void { } function copy(from: string, to: string): void { } function cache(filename: string, isCompress: boolean): void { } +function load(filename: string): any { return null } +function save(filename: string, data: any) { } +function searchFile(filename: string, searchPath?: string): string { return '' } +function loadConfig(name: string): any { return null } interface FileInfo { name: string diff --git a/file_test.go b/file_test.go index 672b40a..970620c 100644 --- a/file_test.go +++ b/file_test.go @@ -27,3 +27,21 @@ func TestHash(t *testing.T) { fmt.Println(u.BGreen("test succeess")) } } + +func TestConfig(t *testing.T) { + r, err := gojs.Run(` + import file from 'apigo.cc/gojs/file' + let t = file.loadConfig('test') + if (t.aaa != 111) return 'failed to load config, aaa != 111' + if (t.bbb.length !== 2 || t.bbb[0] !== 1 || t.bbb[1] !== 2) return 'failed to load config, bbb != [1,2]' + if (t.ccc.c1 !== 111 || t.ccc.c2 !== "222") return 'failed to load config, ccc != [111,"222"]' + return true + `, "") + if err != nil { + t.Fatal(err) + } + if r != true { + t.Fatal(r) + } + fmt.Println(u.Green("ecdsa test passed")) +} diff --git a/go.mod b/go.mod index e990687..8732376 100644 --- a/go.mod +++ b/go.mod @@ -1,22 +1,22 @@ module apigo.cc/gojs/file -go 1.18 +go 1.23.0 require ( - apigo.cc/gojs v0.0.8 - github.com/ssgo/u v1.7.13 + apigo.cc/gojs v0.0.15 + github.com/ssgo/u v1.7.19 + gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/dlclark/regexp2 v1.11.4 // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect - github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect github.com/ssgo/config v1.7.9 // indirect github.com/ssgo/log v1.7.7 // indirect github.com/ssgo/standard v1.7.7 // indirect - github.com/ssgo/tool v0.4.27 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + github.com/ssgo/tool v0.4.29 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect ) diff --git a/test.yml b/test.yml new file mode 100644 index 0000000..c53e7ba --- /dev/null +++ b/test.yml @@ -0,0 +1,5 @@ +aaa: 11 +bbb: + - 1 +ccc: + c1: 111