diff --git a/Abstractions/Configuration.go b/Abstractions/Configuration.go index 263ab548..6147bc77 100644 --- a/Abstractions/Configuration.go +++ b/Abstractions/Configuration.go @@ -1,6 +1,7 @@ package Abstractions import ( + "fmt" "github.com/spf13/viper" ) @@ -10,11 +11,36 @@ type Configuration struct { } func NewConfiguration(configContext *ConfigurationContext) *Configuration { - v := viper.New() + defaultConfig := viper.New() + defaultConfig.AddConfigPath(".") + defaultConfig.SetConfigName(configContext.configName) + defaultConfig.SetConfigType(configContext.configType) + if err := defaultConfig.ReadInConfig(); err != nil { + return nil + } + + profile := defaultConfig.Get("application.profile") + var profileConfig *viper.Viper + if profile != nil { + profileConfig = viper.New() + profileConfig.AddConfigPath(".") + configContext.profile = profile.(string) + profileConfig.SetConfigName(configContext.configName + "_" + configContext.profile) + profileConfig.SetConfigType(configContext.configType) + configs := defaultConfig.AllSettings() + // 将default中的配置全部以默认配置写入 + for k, v := range configs { + profileConfig.Set(k, v) + } + + if err := profileConfig.ReadInConfig(); err != nil { + profileConfig = defaultConfig + } + } return &Configuration{ context: configContext, - config: v, + config: profileConfig, } } @@ -22,10 +48,24 @@ func (c *Configuration) Get(name string) interface{} { return c.config.Get(name) } -func (c *Configuration) GetSection(name string) *Configuration { +func (c *Configuration) GetSection(name string) IConfiguration { section := c.config.Sub(name) + section.SetConfigName(c.context.configName + "_" + c.context.profile) + configs := c.config.AllSettings() + // 将default中的配置全部以默认配置写入 + for k, v := range configs { + section.Set(k, v) + } + if section != nil { return &Configuration{config: section} } return nil } + +func (c *Configuration) Unmarshal(obj interface{}) { + err := c.config.Unmarshal(obj) + if err != nil { + fmt.Println("unmarshal config is failed, err:", err) + } +} diff --git a/Abstractions/ConfigurationBuilder.go b/Abstractions/ConfigurationBuilder.go index 02d45c22..d55e5e5d 100644 --- a/Abstractions/ConfigurationBuilder.go +++ b/Abstractions/ConfigurationBuilder.go @@ -5,6 +5,7 @@ type ConfigurationContext struct { enableEnv bool configType string configName string + profile string } type ConfigurationBuilder struct { @@ -15,26 +16,30 @@ func NewConfigurationBuilder() *ConfigurationBuilder { return &ConfigurationBuilder{context: &ConfigurationContext{}} } -func (builder *ConfigurationBuilder) AddFlagArgs() { +func (builder *ConfigurationBuilder) AddFlagArgs() *ConfigurationBuilder { builder.context.enableFlag = true + return builder } -func (builder *ConfigurationBuilder) AddEnvironment() { +func (builder *ConfigurationBuilder) AddEnvironment() *ConfigurationBuilder { builder.context.enableEnv = true + return builder } -func (builder *ConfigurationBuilder) AddYamlFile(name string) { +func (builder *ConfigurationBuilder) AddYamlFile(name string) *ConfigurationBuilder { if builder.context.configType == "" { builder.context.configType = "yaml" builder.context.configName = name } + return builder } -func (builder *ConfigurationBuilder) AddJsonFile(name string) { +func (builder *ConfigurationBuilder) AddJsonFile(name string) *ConfigurationBuilder { if builder.context.configType == "" { builder.context.configType = "json" builder.context.configName = name } + return builder } func (builder *ConfigurationBuilder) Build() *Configuration { diff --git a/Abstractions/HostBuildContext.go b/Abstractions/HostBuildContext.go index da6ab3c1..a1338f8e 100644 --- a/Abstractions/HostBuildContext.go +++ b/Abstractions/HostBuildContext.go @@ -1,6 +1,7 @@ package Abstractions import ( + "github.com/yoyofx/yoyogo/Abstractions/configs" "github.com/yoyofx/yoyogo/DependencyInjection" "github.com/yoyofx/yoyogo/WebFramework/Context" ) @@ -9,6 +10,9 @@ type HostBuildContext struct { RequestDelegate interface{} ApplicationCycle *ApplicationLife HostingEnvironment *Context.HostEnvironment + Configuration IConfiguration + HostConfiguration *configs.HostConfig ApplicationServicesDef *DependencyInjection.ServiceCollection ApplicationServices DependencyInjection.IServiceProvider + HostServices DependencyInjection.IServiceProvider } diff --git a/Abstractions/HostBuilder.go b/Abstractions/HostBuilder.go index 11c2e868..a65fde46 100644 --- a/Abstractions/HostBuilder.go +++ b/Abstractions/HostBuilder.go @@ -2,7 +2,8 @@ package Abstractions import ( "fmt" - "github.com/yoyofx/yoyogo" + YoyoGo "github.com/yoyofx/yoyogo" + "github.com/yoyofx/yoyogo/Abstractions/configs" "github.com/yoyofx/yoyogo/DependencyInjection" "github.com/yoyofx/yoyogo/WebFramework/Context" "net" @@ -32,6 +33,17 @@ func (host *HostBuilder) Configure(configure interface{}) *HostBuilder { return host } +func (host *HostBuilder) UseConfiguration(configuration IConfiguration) *HostBuilder { + host.Context.Configuration = configuration + section := host.Context.Configuration.GetSection("application") + if section != nil { + config := &configs.HostConfig{} + section.Unmarshal(config) + host.Context.HostConfiguration = config + } + return host +} + // ConfigureServices configure function by ServiceCollection of DI. func (host *HostBuilder) ConfigureServices(configure func(*DependencyInjection.ServiceCollection)) *HostBuilder { host.servicesConfigures = append(host.servicesConfigures, configure) @@ -76,10 +88,21 @@ func RunningHostEnvironmentSetting(hostEnv *Context.HostEnvironment) { } //buildingHostEnvironmentSetting build each configuration by init , such as file or env or args ... -func buildingHostEnvironmentSetting(hostEnv *Context.HostEnvironment) { - hostEnv.ApplicationName = "app" +func buildingHostEnvironmentSetting(context *HostBuildContext) { + hostEnv := context.HostingEnvironment hostEnv.Version = YoyoGo.Version hostEnv.Addr = DetectAddress("") + config := context.HostConfiguration + if config != nil { + hostEnv.ApplicationName = config.Name + if config.Server.Address != "" { + hostEnv.Addr = config.Server.Address + } + if config.Profile != "" { + hostEnv.Profile = config.Profile + } + } + hostEnv.Port = strings.Replace(hostEnv.Addr, ":", "", -1) hostEnv.Args = os.Args @@ -93,7 +116,7 @@ func buildingHostEnvironmentSetting(hostEnv *Context.HostEnvironment) { func (host *HostBuilder) Build() IServiceHost { services := DependencyInjection.NewServiceCollection() - buildingHostEnvironmentSetting(host.Context.HostingEnvironment) + buildingHostEnvironmentSetting(host.Context) host.Context.ApplicationCycle = NewApplicationLife() innerConfigures(host.Context, services) @@ -101,7 +124,7 @@ func (host *HostBuilder) Build() IServiceHost { configure(services) } - applicationBuilder := host.Decorator.OverrideNewApplicationBuilder() + applicationBuilder := host.Decorator.OverrideNewApplicationBuilder(host.Context) for _, configure := range host.configures { //configure(applicationBuilder) @@ -110,6 +133,7 @@ func (host *HostBuilder) Build() IServiceHost { host.Context.ApplicationServicesDef = services applicationBuilder.SetHostBuildContext(host.Context) + host.Context.HostServices = services.Build() //serviceProvider host.Context.RequestDelegate = applicationBuilder.Build() // ServeHTTP(w http.ResponseWriter, r *http.Request) host.Context.ApplicationServices = services.Build() //serviceProvider diff --git a/Abstractions/IConfiguration.go b/Abstractions/IConfiguration.go index a84ea314..23279a14 100644 --- a/Abstractions/IConfiguration.go +++ b/Abstractions/IConfiguration.go @@ -1,4 +1,7 @@ package Abstractions type IConfiguration interface { + Get(name string) interface{} + GetSection(name string) IConfiguration + Unmarshal(interface{}) } diff --git a/Abstractions/IHostBuilderDecorator.go b/Abstractions/IHostBuilderDecorator.go index 330433e9..7795815c 100644 --- a/Abstractions/IHostBuilderDecorator.go +++ b/Abstractions/IHostBuilderDecorator.go @@ -6,7 +6,7 @@ type IHostBuilderDecorator interface { // OverrideConfigure is configure function by application builder. OverrideConfigure(configureFunc interface{}, builder IApplicationBuilder) // OverrideNewApplicationBuilder create application builder. - OverrideNewApplicationBuilder() IApplicationBuilder + OverrideNewApplicationBuilder(context *HostBuildContext) IApplicationBuilder // OverrideNewHost Create IServiceHost. OverrideNewHost(server IServer, context *HostBuildContext) IServiceHost } diff --git a/Abstractions/IServiceHost.go b/Abstractions/IServiceHost.go index ac9ab260..3a73a425 100644 --- a/Abstractions/IServiceHost.go +++ b/Abstractions/IServiceHost.go @@ -30,6 +30,7 @@ func PrintLogo(l *log.Logger, env *Context.HostEnvironment) { l.Printf("machine host ip : %s", ConsoleColors.Blue(env.Host)) l.Printf("listening on port : %s", ConsoleColors.Blue(env.Port)) l.Printf("application running pid : %s", ConsoleColors.Blue(strconv.Itoa(env.PID))) + l.Printf("application name : %s", ConsoleColors.Blue(env.ApplicationName)) l.Printf("application environment : %s", ConsoleColors.Blue(env.Profile)) l.Printf("application exec path : %s", ConsoleColors.Yellow(Utils.GetCurrentDirectory())) l.Printf("running in %s mode , change (Dev,Test,Prod) mode by HostBuilder.SetEnvironment .", ConsoleColors.Blue(env.Profile)) diff --git a/Abstractions/configs/HostConfig.go b/Abstractions/configs/HostConfig.go new file mode 100644 index 00000000..04a73fe2 --- /dev/null +++ b/Abstractions/configs/HostConfig.go @@ -0,0 +1,8 @@ +package configs + +type HostConfig struct { + Name string `mapstructure:"name"` + Metadata string `mapstructure:"metadata"` + Profile string `mapstructure:"profile"` + Server ServerConfig `mapstructure:"server"` +} diff --git a/Abstractions/configs/ServerConfig.go b/Abstractions/configs/ServerConfig.go new file mode 100644 index 00000000..af2a316a --- /dev/null +++ b/Abstractions/configs/ServerConfig.go @@ -0,0 +1,13 @@ +package configs + +type ServerConfig struct { + ServerType string `mapstructure:"type"` + Address string `mapstructure:"address"` + MaxRequestSize string `mapstructure:"max_request_size"` + Static StaticConfig `mapstructure:"static"` +} + +type StaticConfig struct { + Patten string `mapstructure:"patten"` + WebRoot string `mapstructure:"webroot"` +} diff --git a/Examples/SimpleWeb/config.yml b/Examples/SimpleWeb/config.yml new file mode 100644 index 00000000..2e241b9b --- /dev/null +++ b/Examples/SimpleWeb/config.yml @@ -0,0 +1,11 @@ +application: + name: demo1 + metadata: "hello world" + profile: "dev" + server: + type: "fasthttp" + address: ":8080" + max_request_size: 2096157 + static: + patten: "/" + webroot: "./Static" diff --git a/Examples/SimpleWeb/config_dev.yml b/Examples/SimpleWeb/config_dev.yml new file mode 100644 index 00000000..1797bcf9 --- /dev/null +++ b/Examples/SimpleWeb/config_dev.yml @@ -0,0 +1,4 @@ +application: + name: demo_dev + server: + address: ":8080" \ No newline at end of file diff --git a/Examples/SimpleWeb/config_prod.yml b/Examples/SimpleWeb/config_prod.yml new file mode 100644 index 00000000..fbee0564 --- /dev/null +++ b/Examples/SimpleWeb/config_prod.yml @@ -0,0 +1,4 @@ +application: + name: demo_prod + server: + address: ":8081" \ No newline at end of file diff --git a/Examples/SimpleWeb/main.go b/Examples/SimpleWeb/main.go index 1d89d26c..966d4301 100644 --- a/Examples/SimpleWeb/main.go +++ b/Examples/SimpleWeb/main.go @@ -13,8 +13,18 @@ import ( "github.com/yoyofx/yoyogo/WebFramework/Router" ) -func main() { +func SimpleDemo() { + YoyoGo.CreateDefaultBuilder(func(router Router.IRouterBuilder) { + Endpoints.UsePrometheus(router) + + router.GET("/info", func(ctx *Context.HttpContext) { + ctx.JSON(200, Context.M{"info": "ok"}) + }) + }).Build().Run() +} +func main() { + //SimpleDemo() //webHost := YoyoGo.CreateDefaultBuilder(registerEndpointRouterConfig).Build() webHost := CreateCustomBuilder().Build() webHost.Run() @@ -22,11 +32,12 @@ func main() { //* Create the builder of Web host func CreateCustomBuilder() *Abstractions.HostBuilder { + configuration := Abstractions.NewConfigurationBuilder().AddYamlFile("config").Build() + return YoyoGo.NewWebHostBuilder(). - SetEnvironment(Context.Prod). - UseFastHttp(). + UseConfiguration(configuration). Configure(func(app *YoyoGo.WebApplicationBuilder) { - app.UseStatic("Static") + app.UseStaticAssets() app.UseEndpoints(registerEndpointRouterConfig) app.UseMvc(func(builder *Mvc.ControllerBuilder) { builder.AddController(contollers.NewUserController) @@ -45,6 +56,8 @@ func CreateCustomBuilder() *Abstractions.HostBuilder { func registerEndpointRouterConfig(router Router.IRouterBuilder) { Endpoints.UseHealth(router) Endpoints.UseViz(router) + Endpoints.UsePrometheus(router) + //Endpoints.UsePprof(router) router.GET("/error", func(ctx *Context.HttpContext) { panic("http get error") diff --git a/Test/yoyogo tests.postman_collection.json b/Test/yoyogo tests.postman_collection.json new file mode 100644 index 00000000..7515e865 --- /dev/null +++ b/Test/yoyogo tests.postman_collection.json @@ -0,0 +1,350 @@ +{ + "id": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "name": "yoyogo tests", + "description": "", + "order": [ + "227012c2-8e71-eb7a-9880-23084f5e9d00", + "e1f59685-61a4-b46b-6223-ba44793d518e", + "35fe21aa-e471-312a-a17e-178a254d4193" + ], + "folders": [ + { + "name": "Endpoint", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "order": [ + "391dd094-a03e-ec74-beec-02e215cc566f", + "4d2c1d88-1678-f67a-1e40-c888e5c3ab86" + ], + "owner": "5959537", + "folders_order": [], + "id": "19b0323b-a98f-c39f-7380-2e27c3daeb4c" + }, + { + "name": "Mvc", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "order": [ + "c846e43f-889c-842f-5418-e939755675b1", + "5cca23a4-3731-e656-3eff-06e0f41ed4ed", + "69884fda-1355-e242-1153-6066510a30da", + "f7e7b06a-9e95-43df-7a05-ec28fe943548", + "dfc843b1-a121-8784-dd98-381809221e80" + ], + "owner": "5959537", + "folders_order": [], + "id": "9cd2afdb-c74f-c541-11b6-b93fd3d6e398" + } + ], + "folders_order": [ + "9cd2afdb-c74f-c541-11b6-b93fd3d6e398", + "19b0323b-a98f-c39f-7380-2e27c3daeb4c" + ], + "timestamp": 1576554457088, + "owner": "5959537", + "public": false, + "requests": [ + { + "id": "227012c2-8e71-eb7a-9880-23084f5e9d00", + "headers": "Content-Type: application/json\n", + "headerData": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "", + "enabled": true + } + ], + "url": "http://localhost:8080/info/1?q1=1231232", + "queryParams": [ + { + "key": "q1", + "value": "1231232", + "equals": true, + "description": "", + "enabled": true + } + ], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "POST", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1596702194494, + "name": "post /info/:id (params binding)", + "description": "Post /info/:id querystring is q1 body { username: \"xxx\" }", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [], + "rawModeData": "{\n\t\"username\":\"zl\"\n}" + }, + { + "id": "35fe21aa-e471-312a-a17e-178a254d4193", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/info", + "queryParams": [], + "pathVariables": {}, + "pathVariableData": [], + "preRequestScript": null, + "method": "GET", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "data": null, + "dataMode": "params", + "name": "get /info", + "description": "get /info", + "descriptionFormat": "html", + "time": 1576555356196, + "version": 2, + "responses": [], + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "collection_id": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b" + }, + { + "id": "391dd094-a03e-ec74-beec-02e215cc566f", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/actuator/health", + "folder": "19b0323b-a98f-c39f-7380-2e27c3daeb4c", + "queryParams": [], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "GET", + "data": null, + "dataMode": "params", + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1596108641756, + "name": "http://localhost:8080/actuator/health", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [] + }, + { + "id": "4d2c1d88-1678-f67a-1e40-c888e5c3ab86", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/actuator/graph?type=viz", + "folder": "19b0323b-a98f-c39f-7380-2e27c3daeb4c", + "queryParams": [ + { + "key": "type", + "value": "viz", + "equals": true, + "description": "", + "enabled": true + } + ], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "GET", + "data": null, + "dataMode": "params", + "version": 2, + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1596700088448, + "name": "http://localhost:8080/actuator/graph?type=viz", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [] + }, + { + "id": "5cca23a4-3731-e656-3eff-06e0f41ed4ed", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/v1/user/GetInfo", + "folder": "9cd2afdb-c74f-c541-11b6-b93fd3d6e398", + "queryParams": [], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "GET", + "data": null, + "dataMode": "params", + "version": 2, + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1595401401008, + "name": "http://localhost:8080/user/GetInfo", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [] + }, + { + "id": "69884fda-1355-e242-1153-6066510a30da", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/v1/user/getinfo", + "folder": "9cd2afdb-c74f-c541-11b6-b93fd3d6e398", + "queryParams": [], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "GET", + "data": null, + "dataMode": "params", + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1596700075950, + "name": "http://localhost:8080/v1/user/info", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [] + }, + { + "id": "c846e43f-889c-842f-5418-e939755675b1", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/v1/usercontroller/Register?UserName=max&Password=123", + "folder": "9cd2afdb-c74f-c541-11b6-b93fd3d6e398", + "queryParams": [ + { + "key": "UserName", + "value": "max", + "equals": true, + "description": "", + "enabled": true + }, + { + "key": "Password", + "value": "123", + "equals": true, + "description": "", + "enabled": true + } + ], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "GET", + "data": null, + "dataMode": "params", + "version": 2, + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1596687312986, + "name": "get c:user/a:register (MVC)", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [] + }, + { + "id": "dfc843b1-a121-8784-dd98-381809221e80", + "headers": "//Content-Type: application/x-www-form-urlencoded\n", + "headerData": [ + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "description": "", + "enabled": false + } + ], + "url": "http://localhost:8080/v1/user/postuserinfo", + "queryParams": [], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "POST", + "data": [ + { + "key": "UserName", + "value": "zl", + "description": "", + "type": "text", + "enabled": true + }, + { + "key": "Password", + "value": "123", + "description": "", + "type": "text", + "enabled": true + } + ], + "dataMode": "params", + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1596687452826, + "name": "http://localhost:8080/v1/user/postuserinfo", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [] + }, + { + "id": "e1f59685-61a4-b46b-6223-ba44793d518e", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/v1/api/info", + "queryParams": [], + "pathVariables": {}, + "pathVariableData": [], + "preRequestScript": null, + "method": "GET", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "data": null, + "dataMode": "params", + "name": "get /v1/api/info (group)", + "description": "group by /v1/api/info", + "descriptionFormat": "html", + "time": 1576554471503, + "version": 2, + "responses": [], + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "collection_id": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b" + }, + { + "id": "f7e7b06a-9e95-43df-7a05-ec28fe943548", + "headers": "", + "headerData": [], + "url": "http://localhost:8080/v1/user/getusername?UserName=max&Password=123", + "folder": "9cd2afdb-c74f-c541-11b6-b93fd3d6e398", + "queryParams": [ + { + "key": "UserName", + "value": "max", + "equals": true, + "description": "", + "enabled": true + }, + { + "key": "Password", + "value": "123", + "equals": true, + "description": "", + "enabled": true + } + ], + "preRequestScript": null, + "pathVariables": {}, + "pathVariableData": [], + "method": "GET", + "data": null, + "dataMode": "params", + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1596687436432, + "name": "http://localhost:8080/v1/user/username?username=max&password=123", + "description": "", + "collectionId": "5487971b-3ddd-4a84-d6b6-b23d3591ce8b", + "responses": [] + } + ] +} \ No newline at end of file diff --git a/WebFramework/Adpter.go b/WebFramework/Adpter.go new file mode 100644 index 00000000..f99f0a73 --- /dev/null +++ b/WebFramework/Adpter.go @@ -0,0 +1,20 @@ +package YoyoGo + +import ( + "github.com/yoyofx/yoyogo/WebFramework/Context" + "net/http" +) + +type HandlerFunc = func(ctx *Context.HttpContext) + +func WarpHandlerFunc(h func(w http.ResponseWriter, r *http.Request)) HandlerFunc { + return func(c *Context.HttpContext) { + h(c.Output.GetWriter(), c.Input.GetReader()) + } +} + +func WarpHttpHandlerFunc(h http.Handler) HandlerFunc { + return func(c *Context.HttpContext) { + h.ServeHTTP(c.Output.GetWriter(), c.Input.GetReader()) + } +} diff --git a/WebFramework/Endpoints/HealthEndpoint.go b/WebFramework/Endpoints/health_endpoint.go similarity index 100% rename from WebFramework/Endpoints/HealthEndpoint.go rename to WebFramework/Endpoints/health_endpoint.go diff --git a/WebFramework/Endpoints/pprof_endpoint.go b/WebFramework/Endpoints/pprof_endpoint.go new file mode 100644 index 00000000..0eac44c2 --- /dev/null +++ b/WebFramework/Endpoints/pprof_endpoint.go @@ -0,0 +1,38 @@ +package Endpoints + +import ( + "github.com/yoyofx/yoyogo/WebFramework" + "github.com/yoyofx/yoyogo/WebFramework/Context" + "github.com/yoyofx/yoyogo/WebFramework/Router" + "net/http" + "net/http/pprof" +) + +type pprofHandler struct { + Path string + HandlerFunc YoyoGo.HandlerFunc +} + +var debupApi = []pprofHandler{ + {"/debug/pprof/", WarpHandlerFunc(pprof.Index)}, + {"/debug/pprof/cmdline", WarpHandlerFunc(pprof.Cmdline)}, + {"/debug/pprof/profile", WarpHandlerFunc(pprof.Profile)}, + {"/debug/pprof/symbol", WarpHandlerFunc(pprof.Symbol)}, + {"/debug/pprof/trace", WarpHandlerFunc(pprof.Trace)}, +} + +func WarpHandlerFunc(h func(w http.ResponseWriter, r *http.Request)) YoyoGo.HandlerFunc { + return func(c *Context.HttpContext) { + if c.Input.Path() == "/debug/pprof/" { + c.Output.Header(Context.HeaderContentType, Context.MIMETextHTML) + } + c.Output.SetStatus(200) + h(c.Output.GetWriter(), c.Input.GetReader()) + } +} + +func UsePprof(router Router.IRouterBuilder) { + for _, item := range debupApi { + router.GET(item.Path, item.HandlerFunc) + } +} diff --git a/WebFramework/Endpoints/prometheus_endpoint.go b/WebFramework/Endpoints/prometheus_endpoint.go new file mode 100644 index 00000000..9ca3cb14 --- /dev/null +++ b/WebFramework/Endpoints/prometheus_endpoint.go @@ -0,0 +1,11 @@ +package Endpoints + +import ( + "github.com/prometheus/client_golang/prometheus/promhttp" + YoyoGo "github.com/yoyofx/yoyogo/WebFramework" + "github.com/yoyofx/yoyogo/WebFramework/Router" +) + +func UsePrometheus(router Router.IRouterBuilder) { + router.GET("/actuator/metrics", YoyoGo.WarpHttpHandlerFunc(promhttp.Handler())) +} diff --git a/WebFramework/Endpoints/VizEndpoint.go b/WebFramework/Endpoints/viz_endpoint.go similarity index 100% rename from WebFramework/Endpoints/VizEndpoint.go rename to WebFramework/Endpoints/viz_endpoint.go diff --git a/WebFramework/Middleware.go b/WebFramework/Middleware.go index bbbed70c..e725cf18 100644 --- a/WebFramework/Middleware.go +++ b/WebFramework/Middleware.go @@ -11,9 +11,9 @@ type Handler interface { type NextFunc func(ctx *Context.HttpContext) -type HandlerFunc func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) +type MiddlewareHandlerFunc func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) -func (h HandlerFunc) Inovke(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { +func (h MiddlewareHandlerFunc) Inovke(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { h(ctx, next) } @@ -36,14 +36,14 @@ func (m middleware) Invoke(ctx *Context.HttpContext) { } func wrap(handler http.Handler) Handler { - return HandlerFunc(func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { + return MiddlewareHandlerFunc(func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { handler.ServeHTTP(ctx.Output.GetWriter(), ctx.Input.GetReader()) next(ctx) }) } func wrapFunc(handlerFunc http.HandlerFunc) Handler { - return HandlerFunc(func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { + return MiddlewareHandlerFunc(func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { handlerFunc(ctx.Output.GetWriter(), ctx.Input.GetReader()) next(ctx) }) @@ -51,7 +51,7 @@ func wrapFunc(handlerFunc http.HandlerFunc) Handler { func voidMiddleware() middleware { return newMiddleware( - HandlerFunc(func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { + MiddlewareHandlerFunc(func(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { if ctx.Output.Status() == 0 { ctx.Output.SetStatus(404) } diff --git a/WebFramework/Middleware/StaticMiddleware.go b/WebFramework/Middleware/StaticMiddleware.go index 77780dfe..c76e354a 100644 --- a/WebFramework/Middleware/StaticMiddleware.go +++ b/WebFramework/Middleware/StaticMiddleware.go @@ -1,34 +1,63 @@ package Middleware import ( + "github.com/yoyofx/yoyogo/Abstractions" "github.com/yoyofx/yoyogo/WebFramework/Context" "net/http" "os" "strings" ) +type StaticOption struct { + IsPrefix bool + WebRoot string + VirtualPath string +} + type Static struct { - IsPrefix bool - VirualPath string + Option *StaticOption } -func NewStatic(path string) *Static { - return &Static{VirualPath: path, IsPrefix: false} +func NewStatic(patten string, path string) *Static { + option := &StaticOption{ + IsPrefix: false, + WebRoot: "", + VirtualPath: patten, + } + if path != "" { + option.IsPrefix = true + option.WebRoot = path + } + return &Static{option} } -func (s *Static) SetPrefix() { - s.IsPrefix = true +func NewStaticWithConfig(configuration Abstractions.IConfiguration) *Static { + if configuration != nil { + config := configuration.GetSection("application.server.static") + patten := config.Get("patten").(string) + path := config.Get("webroot").(string) + return NewStatic(patten, path) + } else { + return NewStatic("/", "./Static") + } } func (s *Static) Inovke(ctx *Context.HttpContext, next func(ctx *Context.HttpContext)) { - if (ctx.Input.Request.Method != "GET" && ctx.Input.Request.Method != "HEAD") || (s.IsPrefix && !strings.Contains(ctx.Input.Request.URL.Path, s.VirualPath)) { + if (ctx.Input.Request.Method != "GET" && ctx.Input.Request.Method != "HEAD") || (s.Option.IsPrefix && !strings.Contains(ctx.Input.Request.URL.Path, s.Option.VirtualPath)) { next(ctx) return } - prefixPath := "/" + s.VirualPath - webrootPath := "." + "/" + s.VirualPath - requestFilePath := webrootPath + ctx.Input.Request.URL.Path + webrootPath := s.Option.WebRoot + prefixPath := s.Option.VirtualPath + if webrootPath == "" { + webrootPath = "." + "/" + s.Option.VirtualPath + } + virtualPath := s.Option.VirtualPath + if virtualPath != "" { + virtualPath += "/" + } + requestFilePath := webrootPath + strings.Replace(ctx.Input.Request.URL.Path, virtualPath, "", 20) exist, err := pathExists(requestFilePath) if !exist || err != nil { @@ -39,7 +68,7 @@ func (s *Static) Inovke(ctx *Context.HttpContext, next func(ctx *Context.HttpCon staticHandle := http.FileServer(http.Dir(webrootPath)) if ctx.Input.Request.URL.Path != "/favicon.ico" { - if s.IsPrefix { + if s.Option.IsPrefix { staticHandle = http.StripPrefix(prefixPath, staticHandle) } } diff --git a/WebFramework/Mvc/MvcRouteTemplate.go b/WebFramework/Mvc/MvcRouteTemplate.go index 0a7db726..ef16df1c 100644 --- a/WebFramework/Mvc/MvcRouteTemplate.go +++ b/WebFramework/Mvc/MvcRouteTemplate.go @@ -4,6 +4,7 @@ import "strings" type RouteTemplate struct { Template string + TemplateSplits []string ControllerName string ActionName string controllerIndex int @@ -19,6 +20,7 @@ func NewRouteTemplate(temp string) RouteTemplate { controllerIndex: findIndex("{controller}", templateSplits), actionIndex: findIndex("{action}", templateSplits), pathLen: len(templateSplits), + TemplateSplits: templateSplits, } } @@ -31,6 +33,15 @@ func (template *RouteTemplate) Match(pathComponents []string) bool { } template.ActionName = strings.ToLower(pathComponents[template.GetActionIndex()]) + + for index, item := range pathComponents { + if index != template.GetControllerIndex() && index != template.GetActionIndex() { + if item != template.TemplateSplits[index] { + return false + } + } + } + return true } return false diff --git a/WebFramework/WebApplicationBuilder.go b/WebFramework/WebApplicationBuilder.go index 74f68aef..e4ec13af 100644 --- a/WebFramework/WebApplicationBuilder.go +++ b/WebFramework/WebApplicationBuilder.go @@ -33,16 +33,20 @@ func CreateDefaultBuilder(routerConfig func(router Router.IRouterBuilder)) *Abst return NewWebHostBuilder(). UseServer(DefaultHttpServer(YoyoGo.DefaultAddress)). Configure(func(app *WebApplicationBuilder) { - app.UseStatic("Static") + app.UseStatic("/Static", "./Static") app.UseEndpoints(routerConfig) }) } +func CreateBlankWebBuilder() *WebHostBuilder { + return NewWebHostBuilder() +} + // create application builder when combo all handlers to middleware func New(handlers ...Handler) *WebApplicationBuilder { return &WebApplicationBuilder{ - handlers: handlers, - middleware: build(handlers), + handlers: handlers, + //middleware: build(handlers), } } @@ -97,7 +101,7 @@ func (this *WebApplicationBuilder) Build() interface{} { if this.hostContext == nil { panic("hostContext is nil! please set.") } - + //this.hostContext.HostingEnvironment this.middleware = build(this.handlers) this.buildEndPoints() this.buildMvc(this.hostContext.ApplicationServicesDef) @@ -117,8 +121,12 @@ func (app *WebApplicationBuilder) UseMiddleware(handler Handler) { } // apply static middleware in builder -func (app *WebApplicationBuilder) UseStatic(path string) { - app.UseMiddleware(Middleware.NewStatic("Static")) +func (app *WebApplicationBuilder) UseStatic(patten string, path string) { + app.UseMiddleware(Middleware.NewStatic(patten, path)) +} + +func (app *WebApplicationBuilder) UseStaticAssets() { + app.UseMiddleware(Middleware.NewStaticWithConfig(app.hostContext.Configuration)) } // apply handler middleware in builder @@ -132,7 +140,7 @@ func (app *WebApplicationBuilder) UseHandlerFunc(handlerFunc func(rw http.Respon } // apply handler func middleware in builder -func (app *WebApplicationBuilder) UseFunc(handlerFunc HandlerFunc) { +func (app *WebApplicationBuilder) UseFunc(handlerFunc MiddlewareHandlerFunc) { app.UseMiddleware(handlerFunc) } diff --git a/WebFramework/WebHostBuilder.go b/WebFramework/WebHostBuilder.go index 701c21e4..a7c6ce7a 100644 --- a/WebFramework/WebHostBuilder.go +++ b/WebFramework/WebHostBuilder.go @@ -10,12 +10,14 @@ type WebHostBuilder struct { } func NewWebHostBuilder() *WebHostBuilder { - return &WebHostBuilder{ + builder := &WebHostBuilder{ Abstractions.HostBuilder{ Context: &Abstractions.HostBuildContext{HostingEnvironment: &Context.HostEnvironment{}}, Decorator: NewWebHostBuilderDecorator(), }, } + + return builder } // SetEnvironment set value(Dev,Test,Prod) by environment diff --git a/WebFramework/WebHostBuilderDecorator.go b/WebFramework/WebHostBuilderDecorator.go index f516baf4..5ed28157 100644 --- a/WebFramework/WebHostBuilderDecorator.go +++ b/WebFramework/WebHostBuilderDecorator.go @@ -1,6 +1,9 @@ package YoyoGo -import "github.com/yoyofx/yoyogo/Abstractions" +import ( + YoyoGo "github.com/yoyofx/yoyogo" + "github.com/yoyofx/yoyogo/Abstractions" +) type WebHostBuilderDecorator struct { } @@ -12,12 +15,28 @@ func (decorator WebHostBuilderDecorator) OverrideConfigure(configureFunc interfa } // OverrideNewApplicationBuilder create web application builder. -func (decorator WebHostBuilderDecorator) OverrideNewApplicationBuilder() Abstractions.IApplicationBuilder { - return NewWebApplicationBuilder() +func (decorator WebHostBuilderDecorator) OverrideNewApplicationBuilder(context *Abstractions.HostBuildContext) Abstractions.IApplicationBuilder { + applicationBuilder := NewWebApplicationBuilder() + applicationBuilder.SetHostBuildContext(context) + return applicationBuilder } // OverrideNewHost Create WebHost. func (decorator WebHostBuilderDecorator) OverrideNewHost(server Abstractions.IServer, context *Abstractions.HostBuildContext) Abstractions.IServiceHost { + if server == nil && context.HostConfiguration != nil { + section := context.Configuration.GetSection("application.server") + if section != nil { + serverType := section.Get("type").(string) + address := section.Get("address").(string) + if serverType == "fasthttp" { + server = NewFastHttp(address) + } else if serverType == "http" { + server = DefaultHttpServer(address) + } + } + } else { + server = NewFastHttp(YoyoGo.DefaultAddress) + } return NewWebHost(server, context) } diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 00000000..3af6d9fa --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,6 @@ +package cmd + +// tools +func main() { + +} diff --git a/go.mod b/go.mod index 7d70fdb6..d2bceec4 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,8 @@ require ( github.com/golang/protobuf v1.4.2 github.com/magiconair/properties v1.8.1 github.com/pkg/errors v0.8.1 - github.com/spf13/viper v1.7.0 + github.com/prometheus/client_golang v0.9.3 + github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.6.1 github.com/ugorji/go/codec v1.1.7 github.com/valyala/fasthttp v1.14.0 diff --git a/go.sum b/go.sum index 51fdd5f7..ea145e64 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= @@ -131,6 +132,7 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -155,12 +157,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -184,6 +190,8 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=