github.com/abolfazlbeh/zhycan@v0.0.0-20230819144214-24cf38237387/internal/http/fiber_wrapper.go (about) 1 package http 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "github.com/abolfazlbeh/zhycan/internal/config" 7 "github.com/abolfazlbeh/zhycan/internal/utils" 8 "github.com/gofiber/fiber/v2" 9 "github.com/gofiber/fiber/v2/middleware/favicon" 10 "github.com/gofiber/fiber/v2/middleware/logger" 11 "os" 12 "strings" 13 "time" 14 ) 15 16 // Mark: Definitions 17 18 // Server struct 19 type Server struct { 20 name string 21 config ServerConfig 22 app *fiber.App 23 versionGroups map[string]fiber.Router 24 groups map[string]fiber.Router 25 supportedMiddlewares []string 26 defaultRequestMethods []string 27 } 28 29 // init - Server Constructor - It initializes the server 30 func (s *Server) init(name string, serverConfig ServerConfig) error { 31 s.name = name 32 s.config = serverConfig 33 34 // Get application name from the config manager 35 appName := config.GetManager().GetName() 36 requestMethods := fiber.DefaultMethods 37 if s.config.Config.RequestMethods != nil { 38 if s.config.Config.RequestMethods[0] != "ALL" { 39 requestMethods = s.config.Config.RequestMethods 40 } 41 } 42 s.defaultRequestMethods = requestMethods 43 44 s.app = fiber.New(fiber.Config{ 45 Prefork: false, 46 ServerHeader: "Zhycan", 47 AppName: appName, 48 RequestMethods: requestMethods, 49 }) 50 51 if s.config.SupportStatic == true { 52 s.setupStatic() 53 } 54 55 s.groups = make(map[string]fiber.Router) 56 s.supportedMiddlewares = []string{ 57 "logger", 58 "favicon", 59 } 60 return nil 61 } 62 63 func (s *Server) createVersionGroups(versions []string) { 64 s.versionGroups = make(map[string]fiber.Router) 65 for _, item := range versions { 66 s.versionGroups[item] = s.app.Group(item) 67 } 68 } 69 70 func (s *Server) attachMiddlewares(orders []string) { 71 for _, item := range orders { 72 if utils.ArrayContains(&s.supportedMiddlewares, item) { 73 switch item { 74 case "logger": 75 key := fmt.Sprintf("middlewares.%s", item) 76 // read config 77 loggerCfg, err := config.GetManager().Get(s.name, key) 78 if err == nil { 79 jsonBody, err2 := json.Marshal(loggerCfg.(interface{})) 80 if err2 == nil { 81 var obj LoggerMiddlewareConfig 82 err := json.Unmarshal(jsonBody, &obj) 83 if err == nil { 84 // Everything is ok and let's go define logger config 85 loggerMiddlewareCfg := logger.Config{ 86 Next: nil, 87 Done: nil, 88 Format: obj.Format, 89 TimeFormat: obj.TimeFormat, 90 TimeZone: obj.TimeZone, 91 TimeInterval: time.Duration(obj.TimeInterval) * time.Millisecond, 92 } 93 if obj.Output == "stdout" { 94 loggerMiddlewareCfg.Output = os.Stdout 95 } 96 s.app.Use(logger.New(loggerMiddlewareCfg)) 97 break 98 } 99 } 100 } 101 s.app.Use(logger.New()) 102 103 case "favicon": 104 key := fmt.Sprintf("middlewares.%s", item) 105 // read config 106 loggerCfg, err := config.GetManager().Get(s.name, key) 107 if err == nil { 108 jsonBody, err2 := json.Marshal(loggerCfg.(interface{})) 109 if err2 == nil { 110 var obj FaviconMiddlewareConfig 111 err := json.Unmarshal(jsonBody, &obj) 112 if err != nil { 113 faviconMiddlewareCfg := favicon.Config{ 114 File: obj.File, 115 URL: obj.URL, 116 CacheControl: obj.CacheControl, 117 } 118 s.app.Use(favicon.New(faviconMiddlewareCfg)) 119 break 120 } 121 } 122 } 123 s.app.Use(favicon.New()) 124 } 125 } 126 } 127 } 128 129 func (s *Server) addGroup(keyName string, groupName string, router fiber.Router, f func(c *fiber.Ctx) error) { 130 if f == nil { 131 s.groups[keyName] = router.Group(groupName) 132 } else { 133 s.groups[keyName] = router.Group(groupName, f) 134 } 135 } 136 137 func (s *Server) setupStatic() { 138 s.app.Static(s.config.Static.Prefix, s.config.Static.Root, s.config.Static.Config) 139 } 140 141 // MARK: Public functions 142 143 // NewServer - create a new instance of Server and return it 144 func NewServer(name string, config ServerConfig) (*Server, error) { 145 server := &Server{} 146 err := server.init(name, config) 147 if err != nil { 148 return nil, NewCreateServerErr(err) 149 } 150 151 server.attachMiddlewares(config.Middlewares.Order) 152 server.createVersionGroups(config.Versions) 153 return server, nil 154 } 155 156 // Start - start the server and listen to provided address 157 func (s *Server) Start() error { 158 err := s.app.Listen(s.config.ListenAddress) 159 if err != nil { 160 return NewStartServerErr(s.config.ListenAddress, err) 161 } 162 return nil 163 } 164 165 // Stop - stop the server 166 func (s *Server) Stop() error { 167 err := s.app.Shutdown() 168 if err != nil { 169 return NewShutdownServerErr(err) 170 } 171 return nil 172 } 173 174 // AttachErrorHandler - attach a custom error handler to the server 175 func (s *Server) AttachErrorHandler(f func(ctx *fiber.Ctx, err error) error) { 176 oldConfig := s.app.Config() 177 oldConfig.ErrorHandler = f 178 s.app = fiber.New(oldConfig) 179 } 180 181 // AddRoute - add a route to the server 182 func (s *Server) AddRoute(method string, path string, f func(c *fiber.Ctx) error, routeName string, versions []string, groups []string) error { 183 // check that whether is acceptable to add this route method 184 if utils.ArrayContains(&s.defaultRequestMethods, method) { 185 groupsExist := false 186 if groups != nil { 187 if len(groups) > 0 { 188 groupsExist = true 189 } 190 } 191 192 versionsExist := false 193 if versions != nil { 194 if len(versions) > 0 { 195 versionsExist = true 196 } 197 } 198 199 if groupsExist { 200 for _, g := range groups { 201 if versionsExist { 202 for _, v := range versions { 203 if v == "all" { 204 for k := range s.versionGroups { 205 newKey := fmt.Sprintf("%s.%s", k, g) 206 if router, ok := s.groups[newKey]; ok { 207 router.Add(method, path, f) 208 if strings.TrimSpace(routeName) != "" { 209 //router.Name(routeName) 210 s.app.Name(routeName) 211 } 212 } 213 } 214 break 215 } else if v == "" { 216 if router, ok := s.groups[g]; ok { 217 router.Add(method, path, f) 218 if strings.TrimSpace(routeName) != "" { 219 //router.Name(routeName) 220 s.app.Name(routeName) 221 } 222 } 223 break 224 } else { 225 newKey := fmt.Sprintf("%s.%s", v, g) 226 if router, ok := s.groups[newKey]; ok { 227 router.Add(method, path, f) 228 if strings.TrimSpace(routeName) != "" { 229 s.app.Name(routeName) 230 //router.Name(routeName) 231 } 232 } 233 } 234 } 235 } else { 236 if savedGroup, ok := s.groups[g]; ok { 237 savedGroup.Add(method, path, f) 238 if strings.TrimSpace(routeName) != "" { 239 //savedGroup.Name(routeName) 240 s.app.Name(routeName) 241 242 } 243 } 244 } 245 } 246 } else { 247 if versionsExist { 248 for _, v := range versions { 249 if router, ok := s.versionGroups[v]; ok { 250 router.Add(method, path, f) 251 if strings.TrimSpace(routeName) != "" { 252 //router.Name(routeName) 253 s.app.Name(routeName) 254 } 255 } else { 256 if v == "all" { 257 for _, router1 := range s.versionGroups { 258 router1.Add(method, path, f) 259 if strings.TrimSpace(routeName) != "" { 260 //router1.Name(routeName) 261 s.app.Name(routeName) 262 } 263 } 264 break 265 } else if v == "" { 266 s.app.Add(method, path, f) 267 if strings.TrimSpace(routeName) != "" { 268 s.app.Name(routeName) 269 } 270 break 271 } 272 } 273 } 274 } else { 275 s.app.Add(method, path, f) 276 if strings.TrimSpace(routeName) != "" { 277 s.app.Name(routeName) 278 } 279 } 280 } 281 return nil 282 } 283 284 return NewNotSupportedHttpMethodErr(method) 285 } 286 287 // AddGroup - add a group to the server 288 func (s *Server) AddGroup(groupName string, f func(c *fiber.Ctx) error, groups ...string) error { 289 if len(groups) > 0 { 290 for _, g := range groups { 291 for key := range s.versionGroups { 292 gKey := fmt.Sprintf("%s.%s", key, g) 293 if r, ok := s.groups[gKey]; ok { 294 newKey := fmt.Sprintf("%s.%s.%s", key, g, groupName) 295 s.addGroup(newKey, groupName, r, f) 296 } else { 297 return NewGroupRouteNotExistErr(gKey) 298 } 299 } 300 301 newKey := fmt.Sprintf("%s.%s", g, groupName) 302 s.addGroup(newKey, groupName, s.app, f) 303 } 304 } else { 305 for key, item := range s.versionGroups { 306 newKey := fmt.Sprintf("%s.%s", key, groupName) 307 s.addGroup(newKey, groupName, item, f) 308 } 309 310 s.addGroup(groupName, groupName, s.app, f) 311 } 312 313 return nil 314 } 315 316 // GetRouteByName _ get route by its name 317 func (s *Server) GetRouteByName(name string) (*fiber.Route, error) { 318 route := s.app.GetRoute(name) 319 if route.Name != name { 320 return nil, NewGetRouteByNameErr(name) 321 } 322 return &route, nil 323 } 324 325 // AddRouteWithMultiHandlers - add a route to the server 326 func (s *Server) AddRouteWithMultiHandlers(method string, path string, f []func(c *fiber.Ctx) error, routeName string, versions []string, groups []string) error { 327 // check that whether is acceptable to add this route method 328 if utils.ArrayContains(&s.defaultRequestMethods, method) { 329 if len(groups) > 0 { 330 for _, g := range groups { 331 if len(versions) > 0 { 332 for _, v := range versions { 333 if v == "all" { 334 for k := range s.versionGroups { 335 newKey := fmt.Sprintf("%s.%s", k, g) 336 if router, ok := s.groups[newKey]; ok { 337 router.Add(method, path, f...) 338 if strings.TrimSpace(routeName) != "" { 339 //router.Name(routeName) 340 s.app.Name(routeName) 341 } 342 } 343 } 344 break 345 } else if v == "" { 346 if router, ok := s.groups[g]; ok { 347 router.Add(method, path, f...) 348 if strings.TrimSpace(routeName) != "" { 349 //router.Name(routeName) 350 s.app.Name(routeName) 351 } 352 } 353 break 354 } else { 355 newKey := fmt.Sprintf("%s.%s", v, g) 356 if router, ok := s.groups[newKey]; ok { 357 router.Add(method, path, f...) 358 if strings.TrimSpace(routeName) != "" { 359 s.app.Name(routeName) 360 //router.Name(routeName) 361 } 362 } 363 } 364 } 365 } else { 366 if savedGroup, ok := s.groups[g]; ok { 367 savedGroup.Add(method, path, f...) 368 if strings.TrimSpace(routeName) != "" { 369 //savedGroup.Name(routeName) 370 s.app.Name(routeName) 371 372 } 373 } 374 } 375 } 376 } else { 377 if len(versions) > 0 { 378 for _, v := range versions { 379 if router, ok := s.versionGroups[v]; ok { 380 router.Add(method, path, f...) 381 if strings.TrimSpace(routeName) != "" { 382 //router.Name(routeName) 383 s.app.Name(routeName) 384 } 385 } else { 386 if v == "all" { 387 for _, router1 := range s.versionGroups { 388 router1.Add(method, path, f...) 389 if strings.TrimSpace(routeName) != "" { 390 //router1.Name(routeName) 391 s.app.Name(routeName) 392 } 393 } 394 break 395 } else if v == "" { 396 s.app.Add(method, path, f...) 397 if strings.TrimSpace(routeName) != "" { 398 s.app.Name(routeName) 399 } 400 break 401 } 402 } 403 } 404 } else { 405 s.app.Add(method, path, f...) 406 if strings.TrimSpace(routeName) != "" { 407 s.app.Name(routeName) 408 } 409 } 410 } 411 return nil 412 } 413 414 return NewNotSupportedHttpMethodErr(method) 415 }