...

Source file src/gitlab.hexacode.org/go-libs/cr3call/cr3call.go

Documentation: gitlab.hexacode.org/go-libs/cr3call

     1  /*
     2   * CR3 Call
     3   * Package: gitlab.hexacode.org/go-libs/cr3call
     4   * Maintainer: Azzis Arswendo <azzis@hexacode.org>
     5   *
     6   * Copyright (C) 2024 Hexacode Teknologi Indonesia
     7   * All Rights Reserved
     8   */
     9  
    10  package cr3call
    11  
    12  import (
    13  	"errors"
    14  	"fmt"
    15  	"strings"
    16  
    17  	"gitlab.hexacode.org/go-libs/hctypes"
    18  	"gitlab.hexacode.org/go-libs/microservice/config"
    19  	"gitlab.hexacode.org/go-libs/microservice/validate"
    20  	"gitlab.hexacode.org/go-libs/requests"
    21  )
    22  
    23  type CR3Call struct {
    24  	module_namager_url string
    25  }
    26  
    27  type EndpointConfig struct {
    28  	Type     string                 `json:"type,omitempty"`
    29  	Url      string                 `json:"url,omitempty"`
    30  	Api      *config.ConfigAPI      `json:"api,omitempty"`
    31  	Template *config.ConfigTemplate `json:"template,omitempty"`
    32  }
    33  
    34  type CR3CallData struct {
    35  	URLQuery  hctypes.Dict
    36  	URLParams hctypes.Dict
    37  	Params    hctypes.Dict
    38  	Headers   hctypes.Dict
    39  }
    40  
    41  // New creates a new instance of CR3Call with the given module_namager_url.
    42  //
    43  // Parameters:
    44  // - module_namager_url: The URL of the module manager.
    45  //
    46  // Returns:
    47  // - *CR3Call: A pointer to the newly created CR3Call instance.
    48  func New(module_namager_url string) *CR3Call {
    49  	return &CR3Call{
    50  		module_namager_url: module_namager_url,
    51  	}
    52  }
    53  
    54  // GetConfig retrieves the configuration for a given module and submodule.
    55  //
    56  // Parameters:
    57  // - module_name: The name of the module.
    58  // - submodule_name: The name of the submodule.
    59  //
    60  // Returns:
    61  // - *EndpointConfig: A pointer to the EndpointConfig struct representing the configuration, or nil if an error occurs.
    62  // - error: An error if the configuration cannot be retrieved.
    63  func (c *CR3Call) GetConfig(module_name, submodule_name string) (*EndpointConfig, error) {
    64  	http := requests.NewHttp(hctypes.Dict{
    65  		"Content-Type": "application/json",
    66  	})
    67  
    68  	resp, err := http.Get(fmt.Sprintf("%s%s%s/%s", c.module_namager_url, "/module-manager/get-config/", module_name, submodule_name), nil, nil)
    69  
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	if resp.Status == 200 {
    75  		config := hctypes.NewDictFromJson(resp.Body)
    76  
    77  		f_status, ok := config.GetFloat64("status")
    78  
    79  		if ok {
    80  			status := int(f_status)
    81  			if status == 200 {
    82  				result, ok := config.GetDict("result")
    83  				if ok {
    84  					ret := &EndpointConfig{}
    85  					err = result.Unmarshal(&ret)
    86  					if err == nil {
    87  						return ret, nil
    88  					} else {
    89  						return nil, err
    90  					}
    91  				}
    92  			}
    93  		}
    94  	}
    95  
    96  	return nil, errors.New("failed to get config")
    97  }
    98  
    99  // GetPage retrieves the page URL based on the module and submodule names.
   100  //
   101  // Parameters:
   102  // - module_name: The name of the module.
   103  // - submodule_name: The name of the submodule.
   104  // Returns:
   105  // - string: The URL of the page.
   106  // - error: An error if the page URL cannot be retrieved.
   107  func (c *CR3Call) GetPage(module_name, submodule_name string) (string, error) {
   108  	config, err := c.GetConfig(module_name, submodule_name)
   109  	if err != nil {
   110  		return "", err
   111  	}
   112  
   113  	if config.Type == "page" {
   114  		return fmt.Sprintf("%s/%s%s", c.module_namager_url, module_name, config.Template.Path), nil
   115  	}
   116  
   117  	return "", errors.New("not a page")
   118  }
   119  
   120  // GetAPI retrieves the API configuration for a given module and submodule.
   121  //
   122  // Parameters:
   123  // - module_name: The name of the module.
   124  // - submodule_name: The name of the submodule.
   125  //
   126  // Returns:
   127  // - string: The URL of the API.
   128  // - *config.ConfigAPI: The API configuration.
   129  // - error: An error if the API configuration cannot be retrieved.
   130  func (c *CR3Call) GetAPI(module_name, submodule_name string) (string, *config.ConfigAPI, error) {
   131  	config, err := c.GetConfig(module_name, submodule_name)
   132  	if err != nil {
   133  		return "", nil, err
   134  	}
   135  
   136  	if config.Type == "api" {
   137  		return config.Url, config.Api, nil
   138  	}
   139  
   140  	return "", nil, errors.New("not an api")
   141  }
   142  
   143  // Call performs a HTTP request based on the provided module name, submodule name, and data.
   144  //
   145  // Parameters:
   146  // - module_name: The name of the module.
   147  // - submodule_name: The name of the submodule.
   148  // - data: The data for the HTTP request.
   149  // - use_module_manager_url: If true then use mocule manager url, if false then use microservice url
   150  // Returns:
   151  // - hctypes.Dict: The result of the HTTP request.
   152  // - error: An error if the request fails.
   153  func (c *CR3Call) Call(module_name, submodule_name string, data CR3CallData, use_module_manager_url bool) (hctypes.Dict, error) {
   154  	api_url, api, err := c.GetAPI(module_name, submodule_name)
   155  
   156  	if err != nil {
   157  		return hctypes.Dict{}, err
   158  	}
   159  
   160  	url := c.module_namager_url
   161  	url = fmt.Sprintf("%s/%s%s", url, module_name, api.Path)
   162  
   163  	if !use_module_manager_url {
   164  		url = api_url
   165  	}
   166  
   167  	headers := hctypes.Dict{
   168  		"Content-Type": "application/json",
   169  	}
   170  
   171  	if data.Headers != nil {
   172  		for k, v := range data.Headers {
   173  			headers[k] = v
   174  		}
   175  	}
   176  
   177  	config_url_params := map[string]*validate.Options{}
   178  
   179  	if api.URLParams != nil {
   180  		for _, param := range api.URLParams {
   181  			config_url_params[param.Name] = param
   182  		}
   183  	}
   184  
   185  	if len(config_url_params) > 0 {
   186  		if data.URLParams != nil {
   187  			for k, v := range data.URLParams {
   188  				switch vv := v.(type) {
   189  				case hctypes.String:
   190  					url = strings.Replace(url, fmt.Sprintf(":%s", k), string(vv), -1)
   191  				case hctypes.Float64:
   192  					if config_url_param, ok := config_url_params[k]; ok {
   193  						if config_url_param.Type == "number" || config_url_param.Type == "integer" || config_url_param.Type == "int" {
   194  							url = strings.Replace(url, fmt.Sprintf(":%s", k), fmt.Sprintf("%d", int64(vv)), -1)
   195  						} else if config_url_param.Type == "float" || config_url_param.Type == "double" {
   196  							url = strings.Replace(url, fmt.Sprintf(":%s", k), fmt.Sprintf("%f", vv), -1)
   197  						}
   198  					}
   199  				}
   200  			}
   201  		}
   202  	}
   203  
   204  	http := requests.NewHttp(headers)
   205  
   206  	var buffer hctypes.Buffer = nil
   207  	if data.Params != nil {
   208  		buffer = data.Params.ToJson()
   209  	}
   210  
   211  	switch api.Method {
   212  	case "GET":
   213  		resp, err := http.Get(url, data.URLQuery, buffer)
   214  		if err != nil {
   215  			return hctypes.Dict{}, err
   216  		}
   217  		if resp.Status == 200 {
   218  			return hctypes.NewDictFromJson(resp.Body), nil
   219  		}
   220  	case "POST":
   221  		resp, err := http.Post(url, data.URLQuery, buffer)
   222  		if err != nil {
   223  			return hctypes.Dict{}, err
   224  		}
   225  		if resp.Status == 200 {
   226  			return hctypes.NewDictFromJson(resp.Body), nil
   227  		}
   228  	case "PUT":
   229  		resp, err := http.Put(url, data.URLQuery, buffer)
   230  		if err != nil {
   231  			return hctypes.Dict{}, err
   232  		}
   233  		if resp.Status == 200 {
   234  			return hctypes.NewDictFromJson(resp.Body), nil
   235  		}
   236  	case "DELETE":
   237  		resp, err := http.Delete(url, data.URLQuery, buffer)
   238  		if err != nil {
   239  			return hctypes.Dict{}, err
   240  		}
   241  		if resp.Status == 200 {
   242  			return hctypes.NewDictFromJson(resp.Body), nil
   243  		}
   244  	case "PATCH":
   245  		resp, err := http.Patch(url, data.URLQuery, buffer)
   246  		if err != nil {
   247  			return hctypes.Dict{}, err
   248  		}
   249  		if resp.Status == 200 {
   250  			return hctypes.NewDictFromJson(resp.Body), nil
   251  		}
   252  	case "HEAD":
   253  		resp, err := http.Head(url, data.URLQuery, buffer)
   254  		if err != nil {
   255  			return hctypes.Dict{}, err
   256  		}
   257  		if resp.Status == 200 {
   258  			return hctypes.NewDictFromJson(resp.Body), nil
   259  		}
   260  	case "OPTIONS":
   261  		resp, err := http.Options(url, data.URLQuery, buffer)
   262  		if err != nil {
   263  			return hctypes.Dict{}, err
   264  		}
   265  		if resp.Status == 200 {
   266  			return hctypes.NewDictFromJson(resp.Body), nil
   267  		}
   268  	case "TRACE":
   269  		resp, err := http.Trace(url, data.URLQuery, buffer)
   270  		if err != nil {
   271  			return hctypes.Dict{}, err
   272  		}
   273  		if resp.Status == 200 {
   274  			return hctypes.NewDictFromJson(resp.Body), nil
   275  		}
   276  	default:
   277  		return hctypes.Dict{}, errors.New("method not supported")
   278  	}
   279  
   280  	return hctypes.Dict{}, errors.New("unexpected error")
   281  }
   282  
   283  // GetNamespaces retrieves the namespaces from the module manager.
   284  //
   285  // Returns:
   286  // - []string: The list of namespaces.
   287  // - error: An error if the namespaces cannot be retrieved.
   288  func (c *CR3Call) GetNamespaces() ([]string, error) {
   289  	resp, err := c.Call("module-manager", "get-namespaces", CR3CallData{}, true)
   290  
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  
   295  	f_status, ok := resp.GetFloat64("status")
   296  	if ok {
   297  		status := int(f_status)
   298  		if status == 200 {
   299  			result, ok := resp.GetDict("result")
   300  			if ok {
   301  				namespaces, ok := result.GetList("namespaces")
   302  				if ok {
   303  					ret := []string{}
   304  					namespaces.Unmarshal(&ret)
   305  
   306  					return ret, nil
   307  				}
   308  			}
   309  		}
   310  	}
   311  
   312  	return nil, errors.New("unexpected error")
   313  }
   314  
   315  // GetApis retrieves the APIs and pages for a given module.
   316  //
   317  // Parameters:
   318  // - module_name: The name of the module.
   319  // Returns:
   320  // - []string: The list of APIs.
   321  // - []string: The list of pages.
   322  // - error: An error if the APIs and pages cannot be retrieved.
   323  func (c *CR3Call) GetApis(module_name string) ([]string, []string, error) {
   324  	resp, err := c.Call("module-manager", "get-apis", CR3CallData{
   325  		URLParams: hctypes.Dict{
   326  			"namespace": hctypes.String(module_name),
   327  		},
   328  	}, true)
   329  
   330  	if err != nil {
   331  		return nil, nil, err
   332  	}
   333  
   334  	f_status, ok := resp.GetFloat64("status")
   335  	if ok {
   336  		status := int(f_status)
   337  		if status == 200 {
   338  			result, ok := resp.GetDict("result")
   339  			if ok {
   340  				apis, ok := result.GetList("apis")
   341  				pages, ok2 := result.GetList("pages")
   342  				if ok && ok2 {
   343  					ret_apis := []string{}
   344  					apis.Unmarshal(&ret_apis)
   345  
   346  					ret_pages := []string{}
   347  					pages.Unmarshal(&ret_pages)
   348  
   349  					return ret_apis, ret_pages, nil
   350  				}
   351  			}
   352  		}
   353  	}
   354  
   355  	return nil, nil, errors.New("unexpected error")
   356  }
   357  

View as plain text