diff --git a/README.md b/README.md index 7f2639daf55af6e542d16abc50a2c6b84001cada..e73dc2d303b61554d0422c6cf970f138c8ddd56c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,55 @@ # GoSage -#### 介绍 +## 介绍 + go-sage框架,目前自用 + + + +## 参考示例 + +参考示例统一放在 ./examples 下 + + + +## Documents + +### App + +统一管理各类服务资源的处理器 + + + +#### 初始化创建示例 + +``` + +func main() { + logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) + + //log + logger := v1log.NewLog("exampleApp", logPath, nil) + + //创建一个http server + server1 := getHttpServer(logger) + + app, err := v1.NewApp( + "exampleApp", + v1.WithAppOpsLog(logger), //放入logger + v1.WithAppOpsServer(server1), //放入一个 server + ) + if err != nil { + logger.Fatal(fmt.Sprintf("new app error:%s", err)) + return + } + + err = app.Run() + if err != nil { + logger.Fatal("app running error: " + err.Error()) + } + +} +``` + + + diff --git a/examples/public/index.html b/examples/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..c2c7d3960a56a01e0470897ad4d9efb298edecd3 --- /dev/null +++ b/examples/public/index.html @@ -0,0 +1,15 @@ + + + + + Default Page + + +Hello World + + + + \ No newline at end of file diff --git a/examples/public/products/p1.html b/examples/public/products/p1.html new file mode 100644 index 0000000000000000000000000000000000000000..d231d2b0e4891dbe124f9cd9fdd3dea35f15d473 --- /dev/null +++ b/examples/public/products/p1.html @@ -0,0 +1,16 @@ + + + + + 产品-One + + +

产品One介绍

+返回 + + + \ No newline at end of file diff --git a/examples/public/products/p2.html b/examples/public/products/p2.html new file mode 100644 index 0000000000000000000000000000000000000000..abfed3452a8965d6881b16d3a40ca52d91e2290f --- /dev/null +++ b/examples/public/products/p2.html @@ -0,0 +1,16 @@ + + + + + 产品-Two + + +

产品Two介绍

+返回 + + + \ No newline at end of file diff --git a/examples/run_app.go b/examples/run_app.go index c373ebad31f1b330e1b866cd084dda890329acda..bbd9dd6b4c7a4ae94a6a40501aed7895e4f3e51f 100644 --- a/examples/run_app.go +++ b/examples/run_app.go @@ -2,26 +2,38 @@ package main import ( "fmt" + "gitee.com/scottq/go-framework/src/miscs" v1 "gitee.com/scottq/go-framework/src/v1" v1http "gitee.com/scottq/go-framework/src/v1/httpserver" + v1job "gitee.com/scottq/go-framework/src/v1/jobserver" v1log "gitee.com/scottq/go-framework/src/v1/log" "os" "path/filepath" + "time" ) func main() { logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) //log - logger := v1log.NewLog("exampleApp", logPath, nil) + logger := v1log.NewZapLog("exampleApp", logPath, nil) //创建一个http server server1 := getHttpServer(logger) + //创建 job server + job1 := getJobServer(logger) + scheduler := getJobScheduler(logger) + app, err := v1.NewApp( "exampleApp", v1.WithAppOpsLog(logger), + v1.WithAppOpsStopTimeout(time.Second*5), + v1.WithAppOpsVersion("1.0"), + v1.WithAppOpsServer(server1), //将其放入app中 + v1.WithAppOpsServer(job1), //将其放入app中 + v1.WithAppOpsServer(scheduler), //将其放入app中 ) if err != nil { logger.Fatal(fmt.Sprintf("new app error:%s", err)) @@ -48,3 +60,23 @@ func getHttpServer(logger v1log.ILog) *v1http.HttpServer { return httpServer } + +func getJobServer(logger v1log.ILog) *v1job.Job { + //创建一个job + job := v1job.NewJob("printX", func() { + logger.Info("job: " + time.Now().Format(miscs.TimeLayout)) + }) + job.SetCoNum(2) + job.AddLogger(logger) + return job +} + +func getJobScheduler(logger v1log.ILog) *v1job.JobScheduler { + job := v1job.NewJob("", func() { + logger.Info("job: " + time.Now().Format(miscs.TimeLayout)) + }) + + //创建一个scheduler + scheduler := v1job.NewJobScheduler("scheduler", time.Second*2, job) + return scheduler +} diff --git a/examples/run_app_stop.go b/examples/run_app_stop.go index 781e9c4b9c9421571e75fbb91dfaa54e097f4c33..fe2f3171099cd69a82b99bb685980732085cd4af 100644 --- a/examples/run_app_stop.go +++ b/examples/run_app_stop.go @@ -14,7 +14,7 @@ import ( func main() { logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) - logger := v1log.NewLog("exampleApp", logPath, nil) + logger := v1log.NewZapLog("exampleApp", logPath, nil) server1 := getHttpServer(logger, ":8080") server2 := getHttpServer(logger, ":8083") diff --git a/examples/run_httpserver.go b/examples/run_httpserver.go index b08da4c64212a344450e9c8f1b42d2b196519402..b5daa52dcc196986a9769a179f2fc2977c21bc20 100644 --- a/examples/run_httpserver.go +++ b/examples/run_httpserver.go @@ -4,6 +4,7 @@ import ( "fmt" v1http "gitee.com/scottq/go-framework/src/v1/httpserver" v1log "gitee.com/scottq/go-framework/src/v1/log" + "net/http" "os" "path/filepath" ) @@ -12,7 +13,7 @@ func main() { name := "example" logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) - logger := v1log.NewLog(name, logPath, nil) + logger := v1log.NewZapLog(name, logPath, nil) httpServer, err := v1http.NewHttpServer("", ":8080") if err != nil { logger.Error("run http server error:%s" + err.Error()) @@ -29,6 +30,7 @@ func main() { //使用json返回 httpServer.RouteGet("/v1/users", api.Users, nil) httpServer.RouteGet("/v1/exception", api.Exception, nil) + httpServer.RouteFiles("/static", http.Dir("public")) logger.Fatal(httpServer.Run().Error()) } diff --git a/examples/run_httpserver_forward.go b/examples/run_httpserver_forward.go new file mode 100644 index 0000000000000000000000000000000000000000..c0caef5fd103ff2960bdcee531ad81e464acbbc0 --- /dev/null +++ b/examples/run_httpserver_forward.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + v1http "gitee.com/scottq/go-framework/src/v1/httpserver" + v1log "gitee.com/scottq/go-framework/src/v1/log" + "os" + "path/filepath" + "time" +) + +func main() { + name := "example" + logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) + + logger := v1log.NewZapLog(name, logPath, nil) + httpServer, err := v1http.NewHttpServer("", ":28080") + if err != nil { + logger.Error("run http server error:%s" + err.Error()) + return + } + //添加logger + httpServer.AddLogger(logger) + + api := &ApiHandler{} + + //注册简单的路由 + httpServer.RouteGet("/v1", api.Index, nil) + + //使用json返回 + httpForward := v1http.NewHttpForwardHandler("127.0.0.1:8080/v1/users", time.Second) + httpForward.AddForwardRule(map[string]string{ + "/v2/users/*": "127.0.0.1:28080/v1/users", + "/v2/self": "127.0.0.1:28080/v1", + "/v2/file/*/index.html": "127.0.0.1:8080/static", + }) + + httpServer.RouteHandler("GET", "/v1/users/:uid", httpForward, []v1http.Middleware{ + ForwardMiddleware, + }) + httpServer.RouteHandler("GET", "/v2/*path", httpForward, []v1http.Middleware{ + ForwardMiddleware, + }) + + logger.Fatal(httpServer.Run().Error()) +} + +type ApiHandler struct { +} + +//http router +func (h *ApiHandler) Index(ctx *v1http.Ctx) { + ctx.Write([]byte("Hello World")) +} + +//中间件中设置 自定义response处理器 +var ForwardMiddleware v1http.Middleware = func(ctx *v1http.Ctx, next func(*v1http.Ctx)) { + next(ctx) + ctx.Write([]byte("\nforward: " + ctx.Param("uid"))) +} diff --git a/examples/run_httpserver_middleware.go b/examples/run_httpserver_middleware.go index 13d326b93133d0d1ec9cfa0054b58dd20ba0482e..ab17d3b4e93220e4793489fe2c2c41ff744f38d2 100644 --- a/examples/run_httpserver_middleware.go +++ b/examples/run_httpserver_middleware.go @@ -15,7 +15,7 @@ func main() { name := "example" logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) - logger := v1log.NewLog(name, logPath, nil) + logger := v1log.NewZapLog(name, logPath, nil) httpServer, err := v1http.NewHttpServer("", ":8080") if err != nil { logger.Error("run http server error:%s" + err.Error()) diff --git a/examples/run_httpserver_simple.go b/examples/run_httpserver_simple.go index a5056936abc4743b03647b39ebb3fdd78915e9ff..fb3603507184e15f29364c7f056a923a95dfef52 100644 --- a/examples/run_httpserver_simple.go +++ b/examples/run_httpserver_simple.go @@ -12,7 +12,7 @@ func main() { name := "example" logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) - logger := v1log.NewLog(name, logPath, nil) + logger := v1log.NewZapLog(name, logPath, nil) httpServer, err := v1http.NewHttpServer("", ":8080") if err != nil { logger.Error("run http server error:%s" + err.Error()) diff --git a/examples/run_job.go b/examples/run_job.go index 221b22d2c57848705dfe8dbee36de9dbec956c73..467dd6f0e60073bda227120a4207b26bd29ae27e 100644 --- a/examples/run_job.go +++ b/examples/run_job.go @@ -11,7 +11,7 @@ import ( func main() { name := "example" logPath := fmt.Sprintf("./runtime/logs/%s.log", filepath.Base(os.Args[0])) - logger := v1log.NewLog(name, logPath, nil) + logger := v1log.NewZapLog(name, logPath, nil) job := v1job.NewJob("printX", func() { for i := 0; i <= 10; i++ { diff --git a/src/v1/httpserver/http_forward.go b/src/v1/httpserver/http_forward.go new file mode 100644 index 0000000000000000000000000000000000000000..9aa8b59f55cfdfc6dca05321d0b8239602576af4 --- /dev/null +++ b/src/v1/httpserver/http_forward.go @@ -0,0 +1,108 @@ +package httpserver + +import ( + "io/ioutil" + "net/http" + "net/url" + "strings" + "time" +) + +//转发http的handler +type HttpForwardHandler struct { + forwardAddr string + forwardRules map[string]string + client http.Client +} + +func NewHttpForwardHandler(forward string, timeout time.Duration) *HttpForwardHandler { + if !strings.HasPrefix(forward, "http") { + forward = "http://" + forward + } + return &HttpForwardHandler{ + forwardAddr: forward, + forwardRules: map[string]string{}, + client: http.Client{Timeout: timeout,}, + } +} + +func (h *HttpForwardHandler) AddForwardRule(rule map[string]string) { + rules := h.forwardRules + for path, forwardAddr := range rule { + rules[path] = forwardAddr + } + + h.forwardRules = rules +} + +func (h *HttpForwardHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + + forwardReq, err := h.copyReq(r) + if err != nil { + panic(err) + } + + httpResp, err := h.client.Do(forwardReq) + if err != nil { + panic(err) + } + defer httpResp.Body.Close() + repBody, err := ioutil.ReadAll(httpResp.Body) + if err != nil { + panic(err) + } + + w.WriteHeader(httpResp.StatusCode) + w.Write(repBody) +} +func (h *HttpForwardHandler) getForwardAddr(request *http.Request) string { + uri := request.RequestURI + forwardAddr := h.forwardAddr + for path, addr := range h.forwardRules { + if path == uri { + forwardAddr = addr + } + + if pos := strings.Index(path, "*"); pos >= 0 { + prefix := path[:pos] + suffix := path[pos+1:] + if strings.HasPrefix(uri, prefix) && strings.HasSuffix(uri, suffix) { + forwardAddr = addr + } + } + } + + if !strings.HasPrefix(forwardAddr, "http") { + forwardAddr = "http://" + forwardAddr + } + + return forwardAddr +} +func (h *HttpForwardHandler) copyReq(request *http.Request) (*http.Request, error) { + // + forwardAddr := h.getForwardAddr(request) + + // + forwardUrl, err := url.Parse(forwardAddr) + if err != nil { + return nil, err + } + + request.ParseForm() + forwardUrl.RawQuery = request.Form.Encode() + + forwardMethod := request.Method + + forwardReq, err := http.NewRequest(forwardMethod, forwardUrl.String(), request.Body) + + if err != nil { + return nil, err + } + + for headerKey := range request.Header { + forwardReq.Header.Add(headerKey, request.Header.Get(headerKey)) + } + + forwardReq.Header.Add("ForwardSource", request.RequestURI) + return forwardReq, nil +} diff --git a/src/v1/httpserver/server_http.go b/src/v1/httpserver/server_http.go index dab6796282161af2cf846a98393e6dc739869c6e..e6f6854fa08ff8dcffb96f0df6c8f5534ec618b0 100644 --- a/src/v1/httpserver/server_http.go +++ b/src/v1/httpserver/server_http.go @@ -33,24 +33,36 @@ func NewHttpServer(name string, addr string) (*HttpServer, error) { return server, nil } +func (s *HttpServer) Router() *httprouter.Router { + return s.rHandler +} +func (s *HttpServer) RouteFiles(path string, f http.FileSystem) *HttpServer { + s.rHandler.ServeFiles(path+"/*filepath", f) + return s +} +func (s *HttpServer) RouteHandler(method, path string, f http.Handler, middleware []Middleware) *HttpServer { + s.addRouteHandler(method, path, f, middleware) + return s +} + func (s *HttpServer) RoutePost(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer { - s.addRouter(path, "post", f, middleware) + s.addRoute("post", path, f, middleware) return s } func (s *HttpServer) RouteGet(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer { - s.addRouter(path, "get", f, middleware) + s.addRoute("get", path, f, middleware) return s } func (s *HttpServer) RouteOptions(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer { - s.addRouter(path, "options", f, middleware) + s.addRoute("options", path, f, middleware) return s } func (s *HttpServer) RouteDelete(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer { - s.addRouter(path, "delete", f, middleware) + s.addRoute("delete", path, f, middleware) return s } func (s *HttpServer) RoutePut(path string, f HttpRouteFunc, middleware []Middleware) *HttpServer { - s.addRouter(path, "put", f, middleware) + s.addRoute("put", path, f, middleware) return s } @@ -60,12 +72,12 @@ func (s *HttpServer) DefaultRouteHealth() *HttpServer { ctx.Write([]byte("ok")) } - s.addRouter(HealthUrl, "get", healthF, nil) - s.addRouter(HealthUrl, "post", healthF, nil) + s.addRoute("get", HealthUrl, healthF, nil) + s.addRoute("post", HealthUrl, healthF, nil) return s } -func (s *HttpServer) addRouter(path, method string, f HttpRouteFunc, middleware []Middleware) *HttpServer { +func (s *HttpServer) addRoute(method, path string, f HttpRouteFunc, middleware []Middleware) *HttpServer { s.routers = append(s.routers, &Router{ Path: path, Method: method, @@ -74,6 +86,15 @@ func (s *HttpServer) addRouter(path, method string, f HttpRouteFunc, middleware }) return s } +func (s *HttpServer) addRouteHandler(method, path string, f http.Handler, middleware []Middleware) *HttpServer { + s.routers = append(s.routers, &Router{ + Path: path, + Method: method, + HttpHandler: f, + Middleware: middleware, + }) + return s +} func (s *HttpServer) initRouter() error { diff --git a/src/v1/httpserver/server_http_router.go b/src/v1/httpserver/server_http_router.go index 548153e041d37431df7761f04852796e2ea13a7f..3abe2b57335c4fccc60fb240afb6233e28657892 100644 --- a/src/v1/httpserver/server_http_router.go +++ b/src/v1/httpserver/server_http_router.go @@ -11,6 +11,8 @@ type Router struct { Method string RouteHandler HttpRouteFunc Middleware []Middleware + + HttpHandler http.Handler } func (r *Router) hash() string { @@ -18,27 +20,47 @@ func (r *Router) hash() string { } func (r *Router) invokeRegister(router *httprouter.Router) { - switch strings.ToUpper(r.Method) { - case "GET": - router.GET(r.Path, r.handler()) - case "POST": - router.POST(r.Path, r.handler()) - case "OPTIONS": - router.OPTIONS(r.Path, r.handler()) - case "DELETE": - router.DELETE(r.Path, r.handler()) - case "PUT": - router.PUT(r.Path, r.handler()) + handler := r.handler() + if handler != nil { + switch strings.ToUpper(r.Method) { + case "GET": + router.GET(r.Path, handler) + case "POST": + router.POST(r.Path, handler) + case "OPTIONS": + router.OPTIONS(r.Path, handler) + case "DELETE": + router.DELETE(r.Path, handler) + case "PUT": + router.PUT(r.Path, handler) + } } } func (r *Router) handler() func(http.ResponseWriter, *http.Request, httprouter.Params) { - return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { - ctx := NewCtx(writer, request) - ctx._setRouterParams(params) - handlerMiddleware(r.RouteHandler,r.Middleware)(ctx) + if r.HttpHandler != nil { + return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { + + ctx := NewCtx(writer, request) + ctx._setRouterParams(params) + + handlerMiddleware(func(ctx *Ctx) { + r.HttpHandler.ServeHTTP(writer, request) + }, r.Middleware)(ctx) + } } + + if r.RouteHandler != nil { + return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { + ctx := NewCtx(writer, request) + ctx._setRouterParams(params) + + handlerMiddleware(r.RouteHandler, r.Middleware)(ctx) + } + } + + return nil } type HttpRouteFunc = func(ctx *Ctx) diff --git a/src/v1/jobserver/job.go b/src/v1/jobserver/job.go index 12c975fc251ba57c1d3f6218349227000b6d3348..38ffaec3cd9dca3ea070fb7708e9be088f667c5e 100644 --- a/src/v1/jobserver/job.go +++ b/src/v1/jobserver/job.go @@ -1,12 +1,15 @@ package jobserver -import "sync" +import ( + "gitee.com/scottq/go-framework/src/v1/log" + "sync" +) type IJob interface { - Run() + Run() error } -type Task =func() +type Task = func() //job,负责单个任务的执行 type Job struct { @@ -14,8 +17,9 @@ type Job struct { coNum int64 sync.WaitGroup jobEntity Task -} + log.InvokeLog +} func NewJob(name string, f func()) *Job { return &Job{ @@ -29,15 +33,25 @@ func (j *Job) SetCoNum(num int64) { j.coNum = num } -func (j *Job) Run() { +func (j *Job) Name() string { + return j.name +} + +func (j *Job) Run() error { for i := int64(0); i < j.coNum; i++ { j.Add(1) go j.run() } j.Wait() + j.Info("job[%s] run end", j.Name()) + return nil } func (j *Job) run() { j.jobEntity() j.Done() } + +func (j *Job) Stop() error { + return nil +} diff --git a/src/v1/jobserver/job_runner.go b/src/v1/jobserver/job_runner.go index c7a2b70c1b94032c147dd97cc227ae796b404036..9cfd1ed1af98cdf1c298ad1039adf329ecd71eec 100644 --- a/src/v1/jobserver/job_runner.go +++ b/src/v1/jobserver/job_runner.go @@ -1,12 +1,18 @@ package jobserver -import "sync" +import ( + "fmt" + "gitee.com/scottq/go-framework/src/v1/log" + "sync" +) //JobRunner,负责并发处理某个任务 type JobRunner struct { name string sync.WaitGroup tasks []IJob + + log.InvokeLog } func NewJobRunner(name string) *JobRunner { @@ -16,28 +22,30 @@ func NewJobRunner(name string) *JobRunner { } } -func (job *JobRunner) Name() string { - return job.name +func (rn *JobRunner) Name() string { + return rn.name } -func (job *JobRunner) AddJob(j IJob) { - job.tasks = append(job.tasks, j) +func (rn *JobRunner) AddJob(j IJob) { + rn.tasks = append(rn.tasks, j) } -func (job *JobRunner) AddExecute(name string, f func()) { +func (rn *JobRunner) AddExecute(name string, f func()) { j := NewJob(name, f) - job.tasks = append(job.tasks, j) + rn.tasks = append(rn.tasks, j) } -func (job *JobRunner) Run() { - for i := 0; i < len(job.tasks); i++ { - job.Add(1) - go job.run(job.tasks[i]) +func (rn *JobRunner) Run()error { + for i := 0; i < len(rn.tasks); i++ { + rn.Add(1) + go rn.run(rn.tasks[i]) } - job.Wait() + rn.Wait() + rn.Info(fmt.Sprintf("jobRunner[%s] run end", rn.Name())) + return nil } -func (job *JobRunner) run(j IJob) { +func (rn *JobRunner) run(j IJob) { j.Run() - job.Done() + rn.Done() } diff --git a/src/v1/jobserver/job_schedule.go b/src/v1/jobserver/job_schedule.go index 9de596be7a67d9249891ada3427ba532300af4c4..8c7eebc6571bc90ed3ea11aa00a30979d24061ea 100644 --- a/src/v1/jobserver/job_schedule.go +++ b/src/v1/jobserver/job_schedule.go @@ -20,8 +20,13 @@ func NewJobScheduler(name string, interval time.Duration, f IJob) *JobScheduler } } -func (sch *JobScheduler) Run() { +func (sch *JobScheduler) Name() string { + return sch.name +} + +func (sch *JobScheduler) Run() error { sch.run() + return nil } func (sch *JobScheduler) run() { @@ -42,6 +47,7 @@ func (sch *JobScheduler) run() { } } -func (sch *JobScheduler) Stop() { +func (sch *JobScheduler) Stop() error { sch.stopCh <- 0 + return nil } diff --git a/src/v1/log/default_log.go b/src/v1/log/log_zap.go similarity index 97% rename from src/v1/log/default_log.go rename to src/v1/log/log_zap.go index 42bcb5b8451fd4ed974dc06d6827493241e8a4c8..e3b25d768ead3eadbf7437e5ddc5682c4babf7c9 100644 --- a/src/v1/log/default_log.go +++ b/src/v1/log/log_zap.go @@ -23,7 +23,7 @@ type LogConfig struct { DebugLevel string } -func NewLog(name string, logPath string, config *LogConfig) ILog { +func NewZapLog(name string, logPath string, config *LogConfig) ILog { if config == nil { config = &LogConfig{ MaxSize: 128, // 每个日志文件保存的大小 单位:M