1 /* 2 * Micro Service 3 * Package: gitlab.hexacode.org/go-libs/microservice 4 * Maintainer: Azzis Arswendo <azzis@hexacode.org> 5 * 6 * Copyright (C) 2023 Hexacode Teknologi Indonesia 7 * All Rights Reserved 8 */ 9 10 // Example: ./config.json 11 // 12 // ```json 13 // 14 // { 15 // "namespace": "api-registration", 16 // "server": { 17 // "port": 8080 18 // }, 19 // "templates": [ 20 // { 21 // "name": "registration", 22 // "path": "/", 23 // "file_path": "example/template.html" 24 // } 25 // ], 26 // "apis": [ 27 // { 28 // "name": "registration", 29 // "path": "/registration", 30 // "method": "POST", 31 // "content_type": "application/json", 32 // "response_type": "application/json", 33 // "callback": { 34 // "plugin": "plugin.so", 35 // "function": "Registration" 36 // }, 37 // "params": [ 38 // { 39 // "name": "username", 40 // "label": "Username", 41 // "placeholder": "Enter Username", 42 // "type": "username", 43 // "validate": "username", 44 // "required": true, 45 // "min": 5, 46 // "max": 32 47 // }, 48 // { 49 // "name": "fullname", 50 // "label": "Full Name", 51 // "placeholder": "Enter Full Name", 52 // "type": "name", 53 // "validate": "name", 54 // "required": true, 55 // "min": 5, 56 // "max": 32 57 // }, 58 // { 59 // "name": "email", 60 // "label": "Email Address", 61 // "placeholder": "Enter Email Address", 62 // "type": "email", 63 // "required": true, 64 // "min": 5, 65 // "max": 32 66 // }, 67 // { 68 // "name": "password", 69 // "label": "Password", 70 // "placeholder": "Enter Password", 71 // "type": "password", 72 // "required": true, 73 // "min": 8, 74 // "max": 120 75 // }, 76 // { 77 // "name": "confirm_password", 78 // "label": "Confirm Password", 79 // "placeholder": "Enter Confirm Password", 80 // "type": "password", 81 // "required": true, 82 // "min": 8, 83 // "max": 120 84 // } 85 // ] 86 // }, 87 // { 88 // "name": "verification", 89 // "path": "/verification/:id/:otp", 90 // "method": "GET", 91 // "content_type": "application/json", 92 // "response_type": "application/json", 93 // "callback": { 94 // "plugin": "plugin.so", 95 // "function": "Verification" 96 // }, 97 // "url_params": [ 98 // { 99 // "name": "id", 100 // "type": "textnumber", 101 // "required": true 102 // }, 103 // { 104 // "name": "otp", 105 // "type": "textnumber", 106 // "required": true 107 // } 108 // ] 109 // } 110 // ] 111 // } 112 // 113 // ``` 114 // 115 // Example: main.go 116 // 117 // ```go 118 // 119 // package main 120 // 121 // import ( 122 // "fmt" 123 // 124 // "gitlab.hexacode.org/go-libs/hctypes" 125 // "gitlab.hexacode.org/go-libs/microservice/config" 126 // ) 127 // 128 // func Registration(ctx *config.ConfigContext) (int, hctypes.Dict, *config.ReturnHTTP) { 129 // fmt.Println(ctx.Config.ToDict().ToColoredJson()) 130 // fmt.Println(ctx.ConfigApi.ToDict().ToColoredJson()) 131 // fmt.Println(ctx.URLParams.ToColoredJson()) 132 // fmt.Println(ctx.Params.ToColoredJson()) 133 // fmt.Println(ctx.Headers.ToColoredJson()) 134 // 135 // return 200, hctypes.Dict{ 136 // "id": 1, 137 // "otp": 123456, 138 // }, nil 139 // } 140 // 141 // func Verification(ctx *config.ConfigContext) (int, hctypes.Dict, *config.ReturnHTTP) { 142 // fmt.Println(ctx.Config.ToDict().ToColoredJson()) 143 // fmt.Println(ctx.ConfigApi.ToDict().ToColoredJson()) 144 // fmt.Println(ctx.URLParams.ToColoredJson()) 145 // fmt.Println(ctx.Params.ToColoredJson()) 146 // fmt.Println(ctx.Headers.ToColoredJson()) 147 // 148 // return 200, hctypes.Dict{ 149 // "success": true, 150 // "message": "OTP verified", 151 // }, nil 152 // } 153 // 154 // ``` 155 156 package config 157 158 import ( 159 "encoding/json" 160 "fmt" 161 "os" 162 "time" 163 164 "github.com/gin-gonic/gin" 165 "gitlab.hexacode.org/go-libs/hctypes" 166 "gitlab.hexacode.org/go-libs/requests" 167 ) 168 169 type Config struct { 170 Namespace string `json:"namespace,omitempty"` 171 Server ConfigServer `json:"server,omitempty"` 172 Templates []*ConfigTemplate `json:"templates,omitempty"` 173 APIs []*ConfigAPI `json:"apis,omitempty"` 174 Options hctypes.Dict `json:"options,omitempty"` 175 source hctypes.Buffer `json:"-"` 176 file string `json:"file,omitempty"` 177 router *gin.Engine `json:"-"` 178 } 179 180 type ReturnError struct { 181 Name string `json:"name,omitempty"` 182 Errors interface{} `json:"errors,omitempty"` 183 } 184 185 func LoadConfig() (*Config, error) { 186 var config *Config 187 188 filePath := "./config.json" 189 config = &Config{ 190 Namespace: "default", 191 Server: ConfigServer{ 192 Port: 8080, 193 }, 194 APIs: []*ConfigAPI{}, 195 } 196 197 content, err := os.ReadFile(filePath) 198 if err != nil { 199 panic(err) 200 return nil, err 201 } 202 203 config.file = filePath 204 config.source = hctypes.Buffer(content) 205 206 err = json.Unmarshal(content, &config) 207 if err != nil { 208 panic(err) 209 return nil, err 210 } 211 212 return config, nil 213 } 214 215 func (config *Config) ForPublic() *Config { 216 apis := []*ConfigAPI{} 217 for _, api := range config.APIs { 218 apis = append(apis, api.ForPublic()) 219 } 220 221 return &Config{ 222 Namespace: config.Namespace, 223 APIs: apis, 224 } 225 } 226 227 // Example: ./config.json 228 // 229 // ```json 230 // 231 // { 232 // "namespace": "api-registration", 233 // "server": { 234 // "port": 8080 235 // }, 236 // "templates": [ 237 // { 238 // "name": "registration", 239 // "path": "/", 240 // "file_path": "example/template.html" 241 // } 242 // ], 243 // "apis": [ 244 // { 245 // "name": "registration", 246 // "path": "/registration", 247 // "method": "POST", 248 // "content_type": "application/json", 249 // "response_type": "application/json", 250 // "callback": { 251 // "plugin": "plugin.so", 252 // "function": "Registration" 253 // }, 254 // "params": [ 255 // { 256 // "name": "username", 257 // "label": "Username", 258 // "placeholder": "Enter Username", 259 // "type": "username", 260 // "validate": "username", 261 // "required": true, 262 // "min": 5, 263 // "max": 32 264 // }, 265 // { 266 // "name": "fullname", 267 // "label": "Full Name", 268 // "placeholder": "Enter Full Name", 269 // "type": "name", 270 // "validate": "name", 271 // "required": true, 272 // "min": 5, 273 // "max": 32 274 // }, 275 // { 276 // "name": "email", 277 // "label": "Email Address", 278 // "placeholder": "Enter Email Address", 279 // "type": "email", 280 // "required": true, 281 // "min": 5, 282 // "max": 32 283 // }, 284 // { 285 // "name": "password", 286 // "label": "Password", 287 // "placeholder": "Enter Password", 288 // "type": "password", 289 // "required": true, 290 // "min": 8, 291 // "max": 120 292 // }, 293 // { 294 // "name": "confirm_password", 295 // "label": "Confirm Password", 296 // "placeholder": "Enter Confirm Password", 297 // "type": "password", 298 // "required": true, 299 // "min": 8, 300 // "max": 120 301 // } 302 // ] 303 // }, 304 // { 305 // "name": "verification", 306 // "path": "/verification/:id/:otp", 307 // "method": "GET", 308 // "content_type": "application/json", 309 // "response_type": "application/json", 310 // "callback": { 311 // "plugin": "plugin.so", 312 // "function": "Verification" 313 // }, 314 // "url_params": [ 315 // { 316 // "name": "id", 317 // "type": "textnumber", 318 // "required": true 319 // }, 320 // { 321 // "name": "otp", 322 // "type": "textnumber", 323 // "required": true 324 // } 325 // ] 326 // } 327 // ] 328 // } 329 // 330 // ``` 331 // 332 // Example: main.go 333 // 334 // ```go 335 // 336 // package main 337 // 338 // import ( 339 // "fmt" 340 // 341 // "gitlab.hexacode.org/go-libs/hctypes" 342 // "gitlab.hexacode.org/go-libs/microservice/config" 343 // ) 344 // 345 // func Registration(ctx *config.ConfigContext) (int, hctypes.Dict, *config.ReturnHTTP) { 346 // fmt.Println(ctx.Config.ToDict().ToColoredJson()) 347 // fmt.Println(ctx.ConfigApi.ToDict().ToColoredJson()) 348 // fmt.Println(ctx.URLParams.ToColoredJson()) 349 // fmt.Println(ctx.Params.ToColoredJson()) 350 // fmt.Println(ctx.Headers.ToColoredJson()) 351 // 352 // return 200, hctypes.Dict{ 353 // "id": 1, 354 // "otp": 123456, 355 // }, nil 356 // } 357 // 358 // func Verification(ctx *config.ConfigContext) (int, hctypes.Dict, *config.ReturnHTTP) { 359 // fmt.Println(ctx.Config.ToDict().ToColoredJson()) 360 // fmt.Println(ctx.ConfigApi.ToDict().ToColoredJson()) 361 // fmt.Println(ctx.URLParams.ToColoredJson()) 362 // fmt.Println(ctx.Params.ToColoredJson()) 363 // fmt.Println(ctx.Headers.ToColoredJson()) 364 // 365 // return 200, hctypes.Dict{ 366 // "success": true, 367 // "message": "OTP verified", 368 // }, nil 369 // } 370 // 371 // ``` 372 func (config *Config) Run() { 373 err := config.LoadPlugin() 374 375 if err != nil { 376 panic(err) 377 } 378 379 config.router = gin.Default() 380 381 optionses_urls := map[string]bool{} 382 set_options := func(path string, handler func(*gin.Context)) { 383 if _, ok := optionses_urls[path]; ok { 384 return 385 } 386 optionses_urls[path] = true 387 config.router.OPTIONS(path, handler) 388 } 389 390 if config.Templates != nil { 391 config.router.Static("/"+config.Namespace+"/public", "public") 392 for _, template := range config.Templates { 393 config.router.GET(fmt.Sprintf("%s%s", config.Namespace, template.Path), template.HTTPHandler) 394 395 set_options(fmt.Sprintf("%s%s", config.Namespace, template.Path), options_handler) 396 } 397 } 398 399 if config.APIs != nil { 400 for _, api := range config.APIs { 401 api.config = config 402 config.router.Handle(api.Method, fmt.Sprintf("%s%s", config.Namespace, api.Path), api.HTTPHandler) 403 config.router.GET(fmt.Sprintf("%s/config/%s", config.Namespace, api.Name), api.HTTPHandlerConfig) 404 405 set_options(fmt.Sprintf("%s%s", config.Namespace, api.Path), options_handler) 406 set_options(fmt.Sprintf("%s/config/%s", config.Namespace, api.Name), options_handler) 407 } 408 } 409 410 config.router.GET(fmt.Sprintf("%s/health", config.Namespace), func(c *gin.Context) { 411 c.String(200, "OK") 412 }) 413 414 config.router.GET(fmt.Sprintf("%s/configs", config.Namespace), func(c *gin.Context) { 415 c.JSON(200, config.ForPublic()) 416 }) 417 418 set_options(fmt.Sprintf("%s/health", config.Namespace), options_handler) 419 set_options(fmt.Sprintf("%s/configs", config.Namespace), options_handler) 420 421 config.router.NoRoute(func(c *gin.Context) { 422 c.JSON(404, &ReturnHTTPError{ 423 StatusCode: 404, 424 Errors: []*ReturnError{ 425 { 426 Name: "not_found", 427 Errors: "Not Found", 428 }, 429 }, 430 }) 431 }) 432 433 config.router.Run(fmt.Sprintf("0.0.0.0:%d", config.Server.Port)) 434 } 435 436 func (config *Config) ToDict() hctypes.Dict { 437 return hctypes.NewDictFromJson(config.source) 438 } 439 440 // Schedule for monitoring the module 441 // 442 // Parameters: 443 // 444 // host - the host address 445 // module_manager_url - the URL of the module manager 446 func Schedule(host string, module_manager_url string) { 447 go func(host_ string, module_manager_url_ string) { 448 cfg, err := LoadConfig() 449 if err != nil { 450 return 451 } 452 453 port := cfg.Server.Port 454 455 port_i := port 456 if port_i == 0 { 457 return 458 } 459 460 http := requests.NewHttp(hctypes.Dict{ 461 "Content-Type": "application/json", 462 }) 463 464 cfg_s := cfg.ToDict().ToJson().ToString() 465 466 param := hctypes.Dict{ 467 "config": cfg_s, 468 "host": host_, 469 "port": port_i, 470 } 471 472 for { 473 http.Post(fmt.Sprintf("%s/module-manager/monitoring", module_manager_url_), nil, param.ToJson()) 474 fmt.Println("Monitoring") 475 time.Sleep(time.Minute) 476 } 477 }(host, module_manager_url) 478 } 479