1
This commit is contained in:
		
						commit
						308a8afc62
					
				
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| .* | ||||
| !.gitignore | ||||
| go.sum | ||||
| build | ||||
| release | ||||
| node_modules | ||||
| package.json | ||||
							
								
								
									
										46
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| # ag - tools for apigo.cc/gojs | ||||
| 
 | ||||
| ## Install | ||||
| 
 | ||||
| ```shell | ||||
| go install apigo.cc/ag@latest | ||||
| ``` | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| ``` | ||||
| tools for apigo.cc/gojs | ||||
| 
 | ||||
| Usage: | ||||
|   ag [command] [...] | ||||
|   ag [short command] [...] | ||||
| 
 | ||||
| Commands: | ||||
|   init [i] [service|client]           init a new project for empty dir | ||||
|   build [b] [all|os arch]             build project | ||||
|   pack [p] [all|os arch]              pack project | ||||
|   run [r] [args...]                   run project | ||||
|   buildrun [rr] [args...]             build and run project | ||||
|   watch [w] [args...]                 run and watch project | ||||
|   buildwatch [ww] [args...]           build and run and watch project | ||||
|   test [t] [args...]                  test project | ||||
|   buildtest [tt] [args...]            build and test project | ||||
|   tidy [td]                           tidy project, run go mod tidy | ||||
|   check [ck]                          check go modules version | ||||
|   export [e]                          export typescript code for dev | ||||
|   tags []                             show git tags | ||||
|   add tag [t+] [version]              add git tag and push, if no new tag specified will use last tag +1 | ||||
|   commit [c+] comment                 commit git repo and push, comment is need | ||||
| 
 | ||||
| Examples: | ||||
|   ag init           init a new default project | ||||
|   ag init service   init a new service project | ||||
|   ag init client    init a new client project | ||||
|   ag init all       init a new project use all modules by apigo.cc/ag/all included | ||||
|   ag build          build project | ||||
|   ag build all      build project for all platforms | ||||
|   ag run            run project | ||||
|   ag test           test project | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
							
								
								
									
										18
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| module apigo.cc/ag | ||||
| 
 | ||||
| go 1.18 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/ssgo/httpclient v1.7.8 | ||||
| 	github.com/ssgo/tool v0.4.27 | ||||
| 	github.com/ssgo/u v1.7.9 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/ssgo/config v1.7.7 // indirect | ||||
| 	github.com/ssgo/log v1.7.7 // indirect | ||||
| 	github.com/ssgo/standard v1.7.7 // indirect | ||||
| 	golang.org/x/net v0.30.0 // indirect | ||||
| 	golang.org/x/text v0.19.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
							
								
								
									
										9
									
								
								templates/_cacheFiles.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								templates/_cacheFiles.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| package main | ||||
| 
 | ||||
| import "github.com/ssgo/u" | ||||
| 
 | ||||
| func init() { | ||||
| 	{{- range .Files}} | ||||
| 	u.LoadFilesToMemoryFromJson("{{.}}") | ||||
| 	{{- end}} | ||||
| } | ||||
							
								
								
									
										7
									
								
								templates/_gitignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								templates/_gitignore
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| .* | ||||
| !.gitignore | ||||
| go.sum | ||||
| build | ||||
| release | ||||
| node_modules | ||||
| package.json | ||||
							
								
								
									
										224
									
								
								templates/_main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								templates/_main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,224 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"apigo.cc/gojs" | ||||
| 	{{range $pkg, $ver := .Module}} | ||||
| 	_ "{{$pkg}}" | ||||
| 	{{- end}} | ||||
| 	{{range $pkg, $ver := .ExtraImport}} | ||||
| 	_ "{{$pkg}}" | ||||
| 	{{- end}} | ||||
| 	"github.com/ssgo/log" | ||||
| 	"github.com/ssgo/u" | ||||
| ) | ||||
| 
 | ||||
| var _mainFile = "{{.Main}}" | ||||
| var appName = "{{.Name}}" | ||||
| var appVersion = "{{.Version}}" | ||||
| var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`) | ||||
| 
 | ||||
| // TODO embed .CacheFiles | ||||
| 
 | ||||
| func init() { | ||||
| 	{{- range $alias, $pkg := .ModuleAlias }} | ||||
| 	gojs.Alias("{{$alias}}", "{{$pkg}}") | ||||
| 	{{- end}} | ||||
| } | ||||
| 
 | ||||
| func setSSKey(key, iv []byte) { | ||||
| 	gojs.SetSSKey(key, iv) | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	if appName == "" { | ||||
| 		appName = filepath.Base(os.Args[0]) | ||||
| 		appName = strings.TrimSuffix(appName, ".exe") | ||||
| 	} | ||||
| 
 | ||||
| 	if appVersion == "" { | ||||
| 		appVersion = "0.0.1" | ||||
| 	} | ||||
| 
 | ||||
| 	cmd := "" | ||||
| 	id := "" | ||||
| 	mainFile := _mainFile | ||||
| 	isWatch := false | ||||
| 	startArgs := make([]string, 0) | ||||
| 	mainArgs := make([]any, 0) | ||||
| 	for i := 1; i < len(os.Args); i++ { | ||||
| 		arg := os.Args[i] | ||||
| 		switch arg { | ||||
| 		case "--help", "-help", "-h": | ||||
| 			printUsage() | ||||
| 			return | ||||
| 		case "--version", "-version", "-v": | ||||
| 			fmt.Println(appName, appVersion) | ||||
| 			return | ||||
| 		case "--export", "-export": | ||||
| 			fmt.Println(u.Cyan(gojs.ExportForDev())) | ||||
| 			return | ||||
| 		case "start", "stop", "restart", "reload", "test": | ||||
| 			if len(mainArgs) == 0 && cmd == "" { | ||||
| 				cmd = arg | ||||
| 			} else { | ||||
| 				mainArgs = append(mainArgs, arg) | ||||
| 			} | ||||
| 		case "--env", "-env", "-e": | ||||
| 			i++ | ||||
| 			a := strings.SplitN(os.Args[i], "=", 2) | ||||
| 			os.Setenv(a[0], a[1]) | ||||
| 		case "-id": | ||||
| 			i++ | ||||
| 			id = strings.TrimSpace(os.Args[i]) | ||||
| 		case "-main": | ||||
| 			i++ | ||||
| 			mainFile = strings.TrimSpace(os.Args[i]) | ||||
| 			startArgs = append(startArgs, "-main", mainFile) | ||||
| 		case "-watch", "-w": | ||||
| 			isWatch = true | ||||
| 			startArgs = append(startArgs, arg) | ||||
| 		default: | ||||
| 			mainArgs = append(mainArgs, arg) | ||||
| 			startArgs = append(startArgs, arg) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if cmd != "test" { | ||||
| 		if !u.FileExists(mainFile) { | ||||
| 			log.DefaultLogger.Error("main file not found", "mainFile", mainFile) | ||||
| 			return | ||||
| 		} | ||||
| 		if id == "" { | ||||
| 			id = fmt.Sprintf("%s_%s_%s", appName, mainFile, appVersion) | ||||
| 		} | ||||
| 		id = idFixMatcher.ReplaceAllString(id, "_") | ||||
| 	} | ||||
| 
 | ||||
| 	homeDir, _ := os.UserHomeDir() | ||||
| 	pidFile := filepath.Join(homeDir, ".pids", id+".pid") | ||||
| 	pid := u.Int(u.ReadFileN(pidFile)) | ||||
| 	switch cmd { | ||||
| 	case "start": | ||||
| 		if pid > 0 && processIsExists(pid) { | ||||
| 			log.DefaultLogger.Info("process already started", "pid", pid) | ||||
| 		} else { | ||||
| 			startProcess(pidFile, startArgs) | ||||
| 		} | ||||
| 	case "stop": | ||||
| 		if pid > 0 { | ||||
| 			killProcess(pid, mainFile) | ||||
| 			_ = os.Remove(pidFile) | ||||
| 		} | ||||
| 	case "reload": | ||||
| 		if pid > 0 { | ||||
| 			kill(pid, syscall.Signal(0x1e)) | ||||
| 		} | ||||
| 	case "restart": | ||||
| 		if pid > 0 { | ||||
| 			killProcess(pid, mainFile) | ||||
| 			_ = os.Remove(pidFile) | ||||
| 		} | ||||
| 		startProcess(pidFile, startArgs) | ||||
| 	case "test": | ||||
| 		testPath := "." | ||||
| 		if u.FileExists("tests") { | ||||
| 			testPath = "tests" | ||||
| 		} | ||||
| 		for _, f := range u.ReadDirN(testPath) { | ||||
| 			if !f.IsDir && strings.HasSuffix(f.Name, "_test.js") { | ||||
| 				if r, err := gojs.RunFile(f.FullName, mainArgs...); err != nil { | ||||
| 					fmt.Println(u.BRed("test failed for "+f.FullName), err.Error()) | ||||
| 				} else { | ||||
| 					fmt.Println(u.Green("test passed for "+f.FullName), r) | ||||
| 				} | ||||
| 				gojs.WaitAll() | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		defer os.Remove(pidFile) | ||||
| 		if isWatch { | ||||
| 			gojs.WatchRun(mainFile, nil, nil, mainArgs...) | ||||
| 		} else { | ||||
| 			if r, err := gojs.RunFile(mainFile, mainArgs...); err != nil { | ||||
| 				log.DefaultLogger.Error("run failed for "+mainFile, "err", err.Error()) | ||||
| 			} else if r != nil { | ||||
| 				log.DefaultLogger.Error("run "+mainFile, "result", r) | ||||
| 			} | ||||
| 			gojs.WaitAll() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func startProcess(pidFile string, startArgs []string) { | ||||
| 	cmd := exec.Command(os.Args[0], startArgs...) | ||||
| 	cmd.Stdout = os.Stdout | ||||
| 	cmd.Stderr = os.Stderr | ||||
| 	if err := cmd.Start(); err == nil { | ||||
| 		u.WriteFile(pidFile, u.String(cmd.Process.Pid)) | ||||
| 		log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "pid", cmd.Process.Pid) | ||||
| 	} else { | ||||
| 		log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "err", err) | ||||
| 	} | ||||
| 	os.Exit(0) | ||||
| } | ||||
| 
 | ||||
| func kill(pid int, sig os.Signal) error { | ||||
| 	if proc, err := os.FindProcess(pid); err == nil { | ||||
| 		return proc.Signal(sig) | ||||
| 	} else { | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func killProcess(pid int, mainFile string) { | ||||
| 	if err := kill(pid, syscall.SIGTERM); err == nil { | ||||
| 		log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid) | ||||
| 		t1 := time.Now().UnixMilli() | ||||
| 		for i := 0; i < 100; i++ { | ||||
| 			if !processIsExists(pid) { | ||||
| 				log.DefaultLogger.Info("killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "usedTime", (time.Duration(time.Now().UnixMilli()-t1) * time.Millisecond).String()) | ||||
| 				return | ||||
| 			} | ||||
| 			time.Sleep(100 * time.Millisecond) | ||||
| 		} | ||||
| 		err := kill(pid, syscall.SIGKILL) | ||||
| 		if processIsExists(pid) { | ||||
| 			log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err) | ||||
| 		} else { | ||||
| 			log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func processIsExists(pid int) bool { | ||||
| 	if proc, err := os.FindProcess(pid); err == nil { | ||||
| 		if err2 := proc.Signal(syscall.Signal(0)); err2 == nil { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func printUsage() { | ||||
| 	fmt.Println(appName, appVersion) | ||||
| 	fmt.Println("Usage:") | ||||
| 	fmt.Println("  ", appName, "[-main mainFile] ...", "run script") | ||||
| 	fmt.Println("  ", appName, "-version|-v", "show version") | ||||
| 	fmt.Println("  ", appName, "-export", "export for development") | ||||
| 	fmt.Println("  ", appName, "-env|-e", "set env") | ||||
| 	fmt.Println("  ", appName, "start [-id id] [-main mainFile]", "start server") | ||||
| 	fmt.Println("  ", appName, "stop [-id id]", "stop server") | ||||
| 	fmt.Println("  ", appName, "restart [-id id] [-main mainFile]", "restart server") | ||||
| 	fmt.Println("  ", appName, "reload [-id id] [-main mainFile]", "reload config") | ||||
| 	fmt.Println("  ", appName, "test", "test *_test.js") | ||||
| 	fmt.Println("  ", appName, "help", "- show help") | ||||
| } | ||||
							
								
								
									
										35
									
								
								tests/apigo.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								tests/apigo.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| name: | ||||
| version: v0.0.1 | ||||
| main: main.js | ||||
| target: | ||||
|   darwin: amd64 arm64 | ||||
|   linux: amd64 arm64 | ||||
|   windows: amd64 | ||||
| module: | ||||
|   apigo.cc/gojs/console: latest | ||||
|   apigo.cc/gojs/util: latest | ||||
|   apigo.cc/gojs/log: latest | ||||
|   apigo.cc/gojs/file: latest | ||||
|   apigo.cc/gojs/http: latest | ||||
|   apigo.cc/gojs/db: latest | ||||
|   apigo.cc/gojs/client: latest | ||||
|   apigo.cc/gojs/service: latest | ||||
|   apigo.cc/ai/llm: latest | ||||
| modulealias: | ||||
| extraimport: | ||||
|   apigo.cc/ai/llm/openai: latest | ||||
|   apigo.cc/ai/llm/zhipu: latest | ||||
|   modernc.org/sqlite: latest | ||||
| cachefile: | ||||
| sskey: test | ||||
| cgoenable: false | ||||
| buildfrom: apigocc/gobuild | ||||
| buildenv: | ||||
|   linux: | ||||
|   darwin: | ||||
|   windows: | ||||
|     - CGO_CPPFLAGS="-I%cd%include" | ||||
| buildldflags: | ||||
|   linux: | ||||
|   darwin: | ||||
|   windows: | ||||
							
								
								
									
										1
									
								
								tests/cctools-port
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								tests/cctools-port
									
									
									
									
									
										Submodule
									
								
							| @ -0,0 +1 @@ | ||||
| Subproject commit a2724f04cafe3590fbc3d0beacc37293d83a2177 | ||||
							
								
								
									
										8
									
								
								tests/client_test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/client_test.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| import cli from 'client' | ||||
| 
 | ||||
| let w = cli.open({ | ||||
|     title: 'Hello', | ||||
|     html: '<div>Hello999</div>', | ||||
|     width: 800, | ||||
|     height: 600, | ||||
| }) | ||||
							
								
								
									
										69
									
								
								tests/go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								tests/go.mod
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| module tests | ||||
| 
 | ||||
| go 1.18 | ||||
| 
 | ||||
| require ( | ||||
| 	apigo.cc/ai/llm v0.0.2 | ||||
| 	apigo.cc/gojs v0.0.3 | ||||
| 	apigo.cc/gojs/client v0.0.1 | ||||
| 	apigo.cc/gojs/console v0.0.1 | ||||
| 	apigo.cc/gojs/db v0.0.1 | ||||
| 	apigo.cc/gojs/file v0.0.1 | ||||
| 	apigo.cc/gojs/http v0.0.3 | ||||
| 	apigo.cc/gojs/log v0.0.1 | ||||
| 	apigo.cc/gojs/service v0.0.1 | ||||
| 	apigo.cc/gojs/util v0.0.2 | ||||
| 	github.com/ssgo/log v1.7.7 | ||||
| 	github.com/ssgo/u v1.7.9 | ||||
| 	modernc.org/sqlite v1.33.1 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| 	filippo.io/edwards25519 v1.1.0 // indirect | ||||
| 	github.com/dlclark/regexp2 v1.11.4 // indirect | ||||
| 	github.com/dustin/go-humanize v1.0.1 // indirect | ||||
| 	github.com/fsnotify/fsnotify v1.7.0 // indirect | ||||
| 	github.com/go-ole/go-ole v1.3.0 // indirect | ||||
| 	github.com/go-resty/resty/v2 v2.15.2 // indirect | ||||
| 	github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect | ||||
| 	github.com/go-sql-driver/mysql v1.8.1 // indirect | ||||
| 	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect | ||||
| 	github.com/gomodule/redigo v1.9.2 // indirect | ||||
| 	github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect | ||||
| 	github.com/google/uuid v1.6.0 // indirect | ||||
| 	github.com/gorilla/websocket v1.5.3 // indirect | ||||
| 	github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect | ||||
| 	github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect | ||||
| 	github.com/mattn/go-isatty v0.0.20 // indirect | ||||
| 	github.com/mitchellh/mapstructure v1.5.0 // indirect | ||||
| 	github.com/ncruces/go-strftime v0.1.9 // indirect | ||||
| 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect | ||||
| 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | ||||
| 	github.com/sashabaranov/go-openai v1.32.0 // indirect | ||||
| 	github.com/shirou/gopsutil/v3 v3.24.5 // indirect | ||||
| 	github.com/shoenig/go-m1cpu v0.1.6 // indirect | ||||
| 	github.com/ssgo/config v1.7.7 // indirect | ||||
| 	github.com/ssgo/dao v0.1.5 // indirect | ||||
| 	github.com/ssgo/db v1.7.9 // indirect | ||||
| 	github.com/ssgo/discover v1.7.9 // indirect | ||||
| 	github.com/ssgo/httpclient v1.7.8 // indirect | ||||
| 	github.com/ssgo/redis v1.7.7 // indirect | ||||
| 	github.com/ssgo/s v1.7.17 // indirect | ||||
| 	github.com/ssgo/standard v1.7.7 // indirect | ||||
| 	github.com/ssgo/tool v0.4.27 // indirect | ||||
| 	github.com/tklauser/go-sysconf v0.3.14 // indirect | ||||
| 	github.com/tklauser/numcpus v0.8.0 // indirect | ||||
| 	github.com/webview/webview_go v0.0.0-20240831120633-6173450d4dd6 // indirect | ||||
| 	github.com/yankeguo/zhipu v0.1.2 // indirect | ||||
| 	github.com/yusufpapurcu/wmi v1.2.4 // indirect | ||||
| 	golang.org/x/net v0.30.0 // indirect | ||||
| 	golang.org/x/sys v0.26.0 // indirect | ||||
| 	golang.org/x/text v0.19.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| 	modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect | ||||
| 	modernc.org/libc v1.55.3 // indirect | ||||
| 	modernc.org/mathutil v1.6.0 // indirect | ||||
| 	modernc.org/memory v1.8.0 // indirect | ||||
| 	modernc.org/strutil v1.2.0 // indirect | ||||
| 	modernc.org/token v1.1.0 // indirect | ||||
| ) | ||||
							
								
								
									
										25
									
								
								tests/include/EventToken.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/include/EventToken.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| #ifndef WEBVIEW_COMPAT_EVENTTOKEN_H | ||||
| #define WEBVIEW_COMPAT_EVENTTOKEN_H | ||||
| #ifdef _WIN32 | ||||
| 
 | ||||
| // This compatibility header provides types used by MS WebView2. This header can
 | ||||
| // be used as an alternative to the "EventToken.h" header normally provided by
 | ||||
| // the Windows SDK. Depending on the MinGW distribution, this header may not be
 | ||||
| // present, or it may be present with the name "eventtoken.h". The letter casing
 | ||||
| // matters when cross-compiling on a system with case-sensitive file names.
 | ||||
| 
 | ||||
| #ifndef __eventtoken_h__ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| #include <cstdint> | ||||
| #else | ||||
| #include <stdint.h> | ||||
| #endif | ||||
| 
 | ||||
| typedef struct EventRegistrationToken { | ||||
|   int64_t value; | ||||
| } EventRegistrationToken; | ||||
| #endif // __eventtoken_h__
 | ||||
| 
 | ||||
| #endif // _WIN32
 | ||||
| #endif // WEBVIEW_COMPAT_EVENTTOKEN_H
 | ||||
							
								
								
									
										237
									
								
								tests/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								tests/main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,237 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"apigo.cc/gojs" | ||||
| 
 | ||||
| 	_ "apigo.cc/ai/llm" | ||||
| 	_ "apigo.cc/gojs/client" | ||||
| 	_ "apigo.cc/gojs/console" | ||||
| 	_ "apigo.cc/gojs/db" | ||||
| 	_ "apigo.cc/gojs/file" | ||||
| 	_ "apigo.cc/gojs/http" | ||||
| 	_ "apigo.cc/gojs/log" | ||||
| 	_ "apigo.cc/gojs/service" | ||||
| 	_ "apigo.cc/gojs/util" | ||||
| 
 | ||||
| 	_ "apigo.cc/ai/llm/openai" | ||||
| 	_ "apigo.cc/ai/llm/zhipu" | ||||
| 
 | ||||
| 	"github.com/ssgo/log" | ||||
| 	"github.com/ssgo/u" | ||||
| 	_ "modernc.org/sqlite" | ||||
| ) | ||||
| 
 | ||||
| var _mainFile = "main.js" | ||||
| var appName = "tests" | ||||
| var appVersion = "v0.0.1" | ||||
| var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`) | ||||
| 
 | ||||
| func init() { | ||||
| 	gojs.Alias("ai/llm", "apigo.cc/ai/llm") | ||||
| 	gojs.Alias("client", "apigo.cc/gojs/client") | ||||
| 	gojs.Alias("console", "apigo.cc/gojs/console") | ||||
| 	gojs.Alias("db", "apigo.cc/gojs/db") | ||||
| 	gojs.Alias("file", "apigo.cc/gojs/file") | ||||
| 	gojs.Alias("http", "apigo.cc/gojs/http") | ||||
| 	gojs.Alias("log", "apigo.cc/gojs/log") | ||||
| 	gojs.Alias("service", "apigo.cc/gojs/service") | ||||
| 	gojs.Alias("util", "apigo.cc/gojs/util") | ||||
| } | ||||
| 
 | ||||
| func setSSKey(key, iv []byte) { | ||||
| 	gojs.SetSSKey(key, iv) | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	if appName == "" { | ||||
| 		appName = filepath.Base(os.Args[0]) | ||||
| 		appName = strings.TrimSuffix(appName, ".exe") | ||||
| 	} | ||||
| 
 | ||||
| 	if appVersion == "" { | ||||
| 		appVersion = "0.0.1" | ||||
| 	} | ||||
| 
 | ||||
| 	cmd := "" | ||||
| 	id := "" | ||||
| 	mainFile := _mainFile | ||||
| 	isWatch := false | ||||
| 	startArgs := make([]string, 0) | ||||
| 	mainArgs := make([]any, 0) | ||||
| 	for i := 1; i < len(os.Args); i++ { | ||||
| 		arg := os.Args[i] | ||||
| 		switch arg { | ||||
| 		case "--help", "-help", "-h": | ||||
| 			printUsage() | ||||
| 			return | ||||
| 		case "--version", "-version", "-v": | ||||
| 			fmt.Println(appName, appVersion) | ||||
| 			return | ||||
| 		case "--export", "-export": | ||||
| 			fmt.Println(u.Cyan(gojs.ExportForDev())) | ||||
| 			return | ||||
| 		case "start", "stop", "restart", "reload", "test": | ||||
| 			if len(mainArgs) == 0 && cmd == "" { | ||||
| 				cmd = arg | ||||
| 			} else { | ||||
| 				mainArgs = append(mainArgs, arg) | ||||
| 			} | ||||
| 		case "--env", "-env", "-e": | ||||
| 			i++ | ||||
| 			a := strings.SplitN(os.Args[i], "=", 2) | ||||
| 			os.Setenv(a[0], a[1]) | ||||
| 		case "-id": | ||||
| 			i++ | ||||
| 			id = strings.TrimSpace(os.Args[i]) | ||||
| 		case "-main": | ||||
| 			i++ | ||||
| 			mainFile = strings.TrimSpace(os.Args[i]) | ||||
| 			startArgs = append(startArgs, "-main", mainFile) | ||||
| 		case "-watch", "-w": | ||||
| 			isWatch = true | ||||
| 			startArgs = append(startArgs, arg) | ||||
| 		default: | ||||
| 			mainArgs = append(mainArgs, arg) | ||||
| 			startArgs = append(startArgs, arg) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if cmd != "test" { | ||||
| 		if !u.FileExists(mainFile) { | ||||
| 			log.DefaultLogger.Error("main file not found", "mainFile", mainFile) | ||||
| 			return | ||||
| 		} | ||||
| 		if id == "" { | ||||
| 			id = fmt.Sprintf("%s_%s_%s", appName, mainFile, appVersion) | ||||
| 		} | ||||
| 		id = idFixMatcher.ReplaceAllString(id, "_") | ||||
| 	} | ||||
| 
 | ||||
| 	homeDir, _ := os.UserHomeDir() | ||||
| 	pidFile := filepath.Join(homeDir, ".pids", id+".pid") | ||||
| 	pid := u.Int(u.ReadFileN(pidFile)) | ||||
| 	switch cmd { | ||||
| 	case "start": | ||||
| 		if pid > 0 && processIsExists(pid) { | ||||
| 			log.DefaultLogger.Info("process already started", "pid", pid) | ||||
| 		} else { | ||||
| 			startProcess(pidFile, startArgs) | ||||
| 		} | ||||
| 	case "stop": | ||||
| 		if pid > 0 { | ||||
| 			killProcess(pid, mainFile) | ||||
| 			_ = os.Remove(pidFile) | ||||
| 		} | ||||
| 	case "reload": | ||||
| 		if pid > 0 { | ||||
| 			kill(pid, syscall.Signal(0x1e)) | ||||
| 		} | ||||
| 	case "restart": | ||||
| 		if pid > 0 { | ||||
| 			killProcess(pid, mainFile) | ||||
| 			_ = os.Remove(pidFile) | ||||
| 		} | ||||
| 		startProcess(pidFile, startArgs) | ||||
| 	case "test": | ||||
| 		testPath := "." | ||||
| 		if u.FileExists("tests") { | ||||
| 			testPath = "tests" | ||||
| 		} | ||||
| 		for _, f := range u.ReadDirN(testPath) { | ||||
| 			if !f.IsDir && strings.HasSuffix(f.Name, "_test.js") { | ||||
| 				if r, err := gojs.RunFile(f.FullName, mainArgs...); err != nil { | ||||
| 					fmt.Println(u.BRed("test failed for "+f.FullName), err.Error()) | ||||
| 				} else { | ||||
| 					fmt.Println(u.Green("test passed for "+f.FullName), r) | ||||
| 				} | ||||
| 				gojs.WaitAll() | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		defer os.Remove(pidFile) | ||||
| 		if isWatch { | ||||
| 			gojs.WatchRun(mainFile, nil, nil, mainArgs...) | ||||
| 		} else { | ||||
| 			if r, err := gojs.RunFile(mainFile, mainArgs...); err != nil { | ||||
| 				log.DefaultLogger.Error("run failed for "+mainFile, "err", err.Error()) | ||||
| 			} else if r != nil { | ||||
| 				log.DefaultLogger.Error("run "+mainFile, "result", r) | ||||
| 			} | ||||
| 			gojs.WaitAll() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func startProcess(pidFile string, startArgs []string) { | ||||
| 	cmd := exec.Command(os.Args[0], startArgs...) | ||||
| 	cmd.Stdout = os.Stdout | ||||
| 	cmd.Stderr = os.Stderr | ||||
| 	if err := cmd.Start(); err == nil { | ||||
| 		u.WriteFile(pidFile, u.String(cmd.Process.Pid)) | ||||
| 		log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "pid", cmd.Process.Pid) | ||||
| 	} else { | ||||
| 		log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "startArgs", startArgs, "err", err) | ||||
| 	} | ||||
| 	os.Exit(0) | ||||
| } | ||||
| 
 | ||||
| func kill(pid int, sig os.Signal) error { | ||||
| 	if proc, err := os.FindProcess(pid); err == nil { | ||||
| 		return proc.Signal(sig) | ||||
| 	} else { | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func killProcess(pid int, mainFile string) { | ||||
| 	if err := kill(pid, syscall.SIGTERM); err == nil { | ||||
| 		log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid) | ||||
| 		t1 := time.Now().UnixMilli() | ||||
| 		for i := 0; i < 100; i++ { | ||||
| 			if !processIsExists(pid) { | ||||
| 				log.DefaultLogger.Info("killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "usedTime", (time.Duration(time.Now().UnixMilli()-t1) * time.Millisecond).String()) | ||||
| 				return | ||||
| 			} | ||||
| 			time.Sleep(100 * time.Millisecond) | ||||
| 		} | ||||
| 		err := kill(pid, syscall.SIGKILL) | ||||
| 		if processIsExists(pid) { | ||||
| 			log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err) | ||||
| 		} else { | ||||
| 			log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func processIsExists(pid int) bool { | ||||
| 	if proc, err := os.FindProcess(pid); err == nil { | ||||
| 		if err2 := proc.Signal(syscall.Signal(0)); err2 == nil { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func printUsage() { | ||||
| 	fmt.Println(appName, appVersion) | ||||
| 	fmt.Println("Usage:") | ||||
| 	fmt.Println("  ", appName, "[-main mainFile] ...", "run script") | ||||
| 	fmt.Println("  ", appName, "-version|-v", "show version") | ||||
| 	fmt.Println("  ", appName, "-export", "export for development") | ||||
| 	fmt.Println("  ", appName, "-env|-e", "set env") | ||||
| 	fmt.Println("  ", appName, "start [-id id] [-main mainFile]", "start server") | ||||
| 	fmt.Println("  ", appName, "stop [-id id]", "stop server") | ||||
| 	fmt.Println("  ", appName, "restart [-id id] [-main mainFile]", "restart server") | ||||
| 	fmt.Println("  ", appName, "reload [-id id] [-main mainFile]", "reload config") | ||||
| 	fmt.Println("  ", appName, "test", "test *_test.js") | ||||
| 	fmt.Println("  ", appName, "help", "- show help") | ||||
| } | ||||
							
								
								
									
										8
									
								
								tests/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/main.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| import cli from 'client' | ||||
| 
 | ||||
| let w = cli.open({ | ||||
|     title: 'Hello', | ||||
|     html: '<div>Hello</div>', | ||||
|     width: 800, | ||||
|     height: 600, | ||||
| }) | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user