/* * CR3 Call * Package: gitlab.hexacode.org/go-libs/cr3call * Maintainer: Azzis Arswendo * * Copyright (C) 2024 Hexacode Teknologi Indonesia * All Rights Reserved */ package cr3call import ( "errors" "fmt" "strings" "gitlab.hexacode.org/go-libs/hctypes" "gitlab.hexacode.org/go-libs/microservice/config" "gitlab.hexacode.org/go-libs/microservice/validate" "gitlab.hexacode.org/go-libs/requests" ) type CR3Call struct { module_namager_url string } type EndpointConfig struct { Type string `json:"type,omitempty"` Url string `json:"url,omitempty"` Api *config.ConfigAPI `json:"api,omitempty"` Template *config.ConfigTemplate `json:"template,omitempty"` } type CR3CallData struct { URLQuery hctypes.Dict URLParams hctypes.Dict Params hctypes.Dict Headers hctypes.Dict } // New creates a new instance of CR3Call with the given module_namager_url. // // Parameters: // - module_namager_url: The URL of the module manager. // // Returns: // - *CR3Call: A pointer to the newly created CR3Call instance. func New(module_namager_url string) *CR3Call { return &CR3Call{ module_namager_url: module_namager_url, } } // GetConfig retrieves the configuration for a given module and submodule. // // Parameters: // - module_name: The name of the module. // - submodule_name: The name of the submodule. // // Returns: // - *EndpointConfig: A pointer to the EndpointConfig struct representing the configuration, or nil if an error occurs. // - error: An error if the configuration cannot be retrieved. func (c *CR3Call) GetConfig(module_name, submodule_name string) (*EndpointConfig, error) { http := requests.NewHttp(hctypes.Dict{ "Content-Type": "application/json", }) resp, err := http.Get(fmt.Sprintf("%s%s%s/%s", c.module_namager_url, "/module-manager/get-config/", module_name, submodule_name), nil, nil) if err != nil { return nil, err } if resp.Status == 200 { config := hctypes.NewDictFromJson(resp.Body) f_status, ok := config.GetFloat64("status") if ok { status := int(f_status) if status == 200 { result, ok := config.GetDict("result") if ok { ret := &EndpointConfig{} err = result.Unmarshal(&ret) if err == nil { return ret, nil } else { return nil, err } } } } } return nil, errors.New("failed to get config") } // GetPage retrieves the page URL based on the module and submodule names. // // Parameters: // - module_name: The name of the module. // - submodule_name: The name of the submodule. // Returns: // - string: The URL of the page. // - error: An error if the page URL cannot be retrieved. func (c *CR3Call) GetPage(module_name, submodule_name string) (string, error) { config, err := c.GetConfig(module_name, submodule_name) if err != nil { return "", err } if config.Type == "page" { return fmt.Sprintf("%s/%s%s", c.module_namager_url, module_name, config.Template.Path), nil } return "", errors.New("not a page") } // GetAPI retrieves the API configuration for a given module and submodule. // // Parameters: // - module_name: The name of the module. // - submodule_name: The name of the submodule. // // Returns: // - string: The URL of the API. // - *config.ConfigAPI: The API configuration. // - error: An error if the API configuration cannot be retrieved. func (c *CR3Call) GetAPI(module_name, submodule_name string) (string, *config.ConfigAPI, error) { config, err := c.GetConfig(module_name, submodule_name) if err != nil { return "", nil, err } if config.Type == "api" { return config.Url, config.Api, nil } return "", nil, errors.New("not an api") } // Call performs a HTTP request based on the provided module name, submodule name, and data. // // Parameters: // - module_name: The name of the module. // - submodule_name: The name of the submodule. // - data: The data for the HTTP request. // - use_module_manager_url: If true then use mocule manager url, if false then use microservice url // Returns: // - hctypes.Dict: The result of the HTTP request. // - error: An error if the request fails. func (c *CR3Call) Call(module_name, submodule_name string, data CR3CallData, use_module_manager_url bool) (hctypes.Dict, error) { api_url, api, err := c.GetAPI(module_name, submodule_name) if err != nil { return hctypes.Dict{}, err } url := c.module_namager_url url = fmt.Sprintf("%s/%s%s", url, module_name, api.Path) if !use_module_manager_url { url = api_url } headers := hctypes.Dict{ "Content-Type": "application/json", } if data.Headers != nil { for k, v := range data.Headers { headers[k] = v } } config_url_params := map[string]*validate.Options{} if api.URLParams != nil { for _, param := range api.URLParams { config_url_params[param.Name] = param } } if len(config_url_params) > 0 { if data.URLParams != nil { for k, v := range data.URLParams { switch vv := v.(type) { case hctypes.String: url = strings.Replace(url, fmt.Sprintf(":%s", k), string(vv), -1) case hctypes.Float64: if config_url_param, ok := config_url_params[k]; ok { if config_url_param.Type == "number" || config_url_param.Type == "integer" || config_url_param.Type == "int" { url = strings.Replace(url, fmt.Sprintf(":%s", k), fmt.Sprintf("%d", int64(vv)), -1) } else if config_url_param.Type == "float" || config_url_param.Type == "double" { url = strings.Replace(url, fmt.Sprintf(":%s", k), fmt.Sprintf("%f", vv), -1) } } } } } } http := requests.NewHttp(headers) var buffer hctypes.Buffer = nil if data.Params != nil { buffer = data.Params.ToJson() } switch api.Method { case "GET": resp, err := http.Get(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } case "POST": resp, err := http.Post(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } case "PUT": resp, err := http.Put(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } case "DELETE": resp, err := http.Delete(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } case "PATCH": resp, err := http.Patch(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } case "HEAD": resp, err := http.Head(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } case "OPTIONS": resp, err := http.Options(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } case "TRACE": resp, err := http.Trace(url, data.URLQuery, buffer) if err != nil { return hctypes.Dict{}, err } if resp.Status == 200 { return hctypes.NewDictFromJson(resp.Body), nil } default: return hctypes.Dict{}, errors.New("method not supported") } return hctypes.Dict{}, errors.New("unexpected error") } // GetNamespaces retrieves the namespaces from the module manager. // // Returns: // - []string: The list of namespaces. // - error: An error if the namespaces cannot be retrieved. func (c *CR3Call) GetNamespaces() ([]string, error) { resp, err := c.Call("module-manager", "get-namespaces", CR3CallData{}, true) if err != nil { return nil, err } f_status, ok := resp.GetFloat64("status") if ok { status := int(f_status) if status == 200 { result, ok := resp.GetDict("result") if ok { namespaces, ok := result.GetList("namespaces") if ok { ret := []string{} namespaces.Unmarshal(&ret) return ret, nil } } } } return nil, errors.New("unexpected error") } // GetApis retrieves the APIs and pages for a given module. // // Parameters: // - module_name: The name of the module. // Returns: // - []string: The list of APIs. // - []string: The list of pages. // - error: An error if the APIs and pages cannot be retrieved. func (c *CR3Call) GetApis(module_name string) ([]string, []string, error) { resp, err := c.Call("module-manager", "get-apis", CR3CallData{ URLParams: hctypes.Dict{ "namespace": hctypes.String(module_name), }, }, true) if err != nil { return nil, nil, err } f_status, ok := resp.GetFloat64("status") if ok { status := int(f_status) if status == 200 { result, ok := resp.GetDict("result") if ok { apis, ok := result.GetList("apis") pages, ok2 := result.GetList("pages") if ok && ok2 { ret_apis := []string{} apis.Unmarshal(&ret_apis) ret_pages := []string{} pages.Unmarshal(&ret_pages) return ret_apis, ret_pages, nil } } } } return nil, nil, errors.New("unexpected error") }