github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/utils/httpserverutils.go (about)

     1  /*
     2  Copyright 2023.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package utils
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/base64"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"io"
    26  	"net"
    27  	"os"
    28  	"strings"
    29  
    30  	"github.com/cespare/xxhash"
    31  	log "github.com/sirupsen/logrus"
    32  	"github.com/valyala/fasthttp"
    33  )
    34  
    35  const (
    36  	ContentJson = "application/json; charset=utf-8"
    37  )
    38  
    39  type HttpServerResponse struct {
    40  	Message    string `json:"message"`
    41  	StatusCode int    `json:"status"`
    42  }
    43  
    44  type HttpServerSettingsResponse struct {
    45  	Persistent map[string]string `json:"persistent"`
    46  	Transient  map[string]string `json:"transient"`
    47  }
    48  
    49  type Hits struct {
    50  	Index   string                 `json:"_index"`
    51  	Type    string                 `json:"_type"`
    52  	Id      string                 `json:"_id"`
    53  	Version int                    `json:"_version"`
    54  	Score   int                    `json:"_score"`
    55  	Source  map[string]interface{} `json:"_source"`
    56  }
    57  
    58  type HitsCount struct {
    59  	Value    uint64 `json:"value"`
    60  	Relation string `json:"relation"`
    61  }
    62  type HttpServerESResponse struct {
    63  	Hits      []Hits      `json:"hits"`
    64  	Max_score int         `json:"max_score"`
    65  	Total     interface{} `json:"total"`
    66  }
    67  
    68  type StatResponse struct {
    69  	Value interface{} `json:"value"`
    70  }
    71  
    72  type BucketWrapper struct {
    73  	Bucket []map[string]interface{} `json:"buckets"`
    74  }
    75  
    76  type HttpServerESResponseOuter struct {
    77  	Hits       HttpServerESResponse     `json:"hits"`
    78  	Aggs       map[string]BucketWrapper `json:"aggregations"`
    79  	Took       int64                    `json:"took"`
    80  	Timed_out  bool                     `json:"timed_out"`
    81  	StatusCode int                      `json:"status"`
    82  	Shards     map[string]interface{}   `json:"_shards"`
    83  }
    84  
    85  type MultiSearchESResponse struct {
    86  	Results []HttpServerESResponseOuter `json:"responses"`
    87  }
    88  
    89  type HttpServerESResponseScroll struct {
    90  	Hits       HttpServerESResponse     `json:"hits"`
    91  	Aggs       map[string]BucketWrapper `json:"aggregations"`
    92  	Took       int64                    `json:"took"`
    93  	Timed_out  bool                     `json:"timed_out"`
    94  	StatusCode int                      `json:"status"`
    95  	Scroll_id  string                   `json:"_scroll_id"`
    96  }
    97  
    98  type SingleESResponse struct {
    99  	Index          string                 `json:"_index"`
   100  	Type           string                 `json:"_type"`
   101  	Id             string                 `json:"_id"`
   102  	Version        int                    `json:"_version"`
   103  	SequenceNumber int                    `json:"_seq_no"`
   104  	Source         map[string]interface{} `json:"_source"`
   105  	Found          bool                   `json:"found"`
   106  	PrimaryTerm    int                    `json:"_primary_term"`
   107  }
   108  
   109  type DocIndexedResponse struct {
   110  	Index          string                        `json:"_index"`
   111  	Type           string                        `json:"_type"`
   112  	Id             string                        `json:"_id"`
   113  	Version        int                           `json:"_version"`
   114  	SequenceNumber int                           `json:"_seq_no"`
   115  	Result         string                        `json:"result"`
   116  	PrimaryTerm    int                           `json:"_primary_term"`
   117  	Shards         map[string]interface{}        `json:"_shards"`
   118  	Get            DocIndexedResponseSubFieldGet `json:"get"`
   119  }
   120  
   121  type DocIndexedResponseSubFieldGet struct {
   122  	SequenceNumber int                    `json:"_seq_no"`
   123  	PrimaryTerm    int                    `json:"_primary_term"`
   124  	Found          bool                   `json:"found"`
   125  	Source         map[string]interface{} `json:"_source"`
   126  }
   127  
   128  type IndexNameInfoResponse struct {
   129  	Aliases  map[string]bool        `json:"aliases"`
   130  	Mappings map[string]interface{} `json:"mappings"`
   131  	Settings SettingsInfo           `json:"settings"`
   132  }
   133  type NodesStatsResponseInfo struct {
   134  	Total      int `json:"total"`
   135  	Successful int `json:"successful"`
   136  	Failed     int `json:"failed"`
   137  }
   138  
   139  type NodesStatsMemResponse struct {
   140  	HeapCommitted           string `json:"heap_committed"`
   141  	HeapCommittedInBytes    uint64 `json:"heap_committed_in_bytes"`
   142  	HeapMax                 string `json:"heap_max"`
   143  	HeapMaxInBytes          uint64 `json:"heap_max_in_bytes"`
   144  	HeapUsed                string `json:"heap_used"`
   145  	HeapUsedInBytes         uint64 `json:"heap_used_in_bytes"`
   146  	HeapUsedPercent         int    `json:"heap_used_percent"`
   147  	NonHeapCommitted        string `json:"non_heap_committed"`
   148  	NonHeapCommittedInBytes int    `json:"non_heap_committed_in_bytes"`
   149  	NonHeapUsed             string `json:"non_heap_used"`
   150  	NonHeapUsedInBytes      int    `json:"non_heap_used_bytes"`
   151  }
   152  type NodesResponseInfo struct {
   153  	Timestamp        int64                  `json:"timestamp"`
   154  	Name             string                 `json:"name"`
   155  	TransportAddress string                 `json:"transport_address"`
   156  	HostName         string                 `json:"host"`
   157  	IP               string                 `json:"ip"`
   158  	OSResponse       map[string]interface{} `json:"os"`
   159  	JVMResponse      map[string]interface{} `json:"jvm"`
   160  	FSResponse       map[string]interface{} `json:"fs"`
   161  	ProcessResponse  map[string]interface{} `json:"process"`
   162  }
   163  
   164  type AllResponseInfo struct {
   165  	Primaries map[string]interface{} `json:"primaries"`
   166  	Total     map[string]interface{} `json:"total"`
   167  }
   168  type LoadAverageResponseInfo struct {
   169  	LoadResponse float64 `json:"1m"`
   170  }
   171  type SettingsInfo struct {
   172  	Index SettingsIndexInfo `json:"index"`
   173  }
   174  
   175  type SettingsIndexInfo struct {
   176  	NumberOfShards   int    `json:"number_of_shards"`
   177  	NumberOfReplicas int    `json:"number_of_replicas"`
   178  	ProvidedName     string `json:"provided_name"`
   179  }
   180  type BulkErrorResponse struct {
   181  	ErrorResponse BulkErrorResponseInfo `json:"error"`
   182  }
   183  type BulkErrorResponseInfo struct {
   184  	Reason string `json:"reason"`
   185  	Type   string `json:"type"`
   186  }
   187  type MgetESResponse struct {
   188  	Docs []SingleESResponse `json:"docs"`
   189  }
   190  type AllNodesInfoResponse struct {
   191  	Nodes map[string]*NodeInfo `json:"nodes"`
   192  }
   193  
   194  type MemResponseInfo struct {
   195  	Total        string `json:"total"`
   196  	TotalInBytes uint64 `json:"total_in_bytes"`
   197  	Free         string `json:"free"`
   198  	FreeInBytes  uint64 `json:"free_in_bytes"`
   199  	Used         string `json:"used"`
   200  	UsedInBytes  uint64 `json:"used_in_bytes"`
   201  	FreePercent  uint64 `json:"free_percent"`
   202  	UsedPercent  uint64 `json:"used_percent"`
   203  }
   204  type VirtualMemResponse struct {
   205  	TotalVirtual        string `json:"total_virtual"`
   206  	TotalVirtualInBytes uint64 `json:"total_virtual_in_bytes"`
   207  }
   208  type SwapResponseInfo struct {
   209  	Total        string `json:"total"`
   210  	TotalInBytes int64  `json:"total_in_bytes"`
   211  	Free         string `json:"free"`
   212  	FreeInBytes  int64  `json:"free_in_bytes"`
   213  	Used         string `json:"used"`
   214  	UsedInBytes  int64  `json:"used_in_bytes"`
   215  }
   216  
   217  type NodesTransportResponseInfo struct {
   218  	Name             string `json:"name"`
   219  	TransportAddress string `json:"transport_address"`
   220  	HostName         string `json:"host"`
   221  	IP               string `json:"ip"`
   222  	Version          string `json:"version"`
   223  	BuildFlavor      string `json:"build_flavor"`
   224  	BuildType        string `json:"build_type"`
   225  	BuildHash        string `json:"build_hash"`
   226  }
   227  
   228  type ClusterHealthResponseInfo struct {
   229  	ClusterName          string  `json:"cluster_name"`
   230  	Status               string  `json:"status"`
   231  	TimedOut             bool    `json:"timed_out"`
   232  	NumberOfNodes        int     `json:"number_of_nodes"`
   233  	NumberOfDataNodes    int     `json:"number_of_data_nodes"`
   234  	ActivePrimaryShards  int     `json:"active_primary_shards"`
   235  	ActiveShards         int     `json:"active_shards"`
   236  	RelocatingShards     int     `json:"relocating_shards"`
   237  	InitiliazeShards     int     `json:"initializing_shards"`
   238  	UnassignedShards     int     `json:"unassigned_shards"`
   239  	DelayedShards        int     `json:"delayed_unassigned_shards"`
   240  	NumberOfPendingTasks int     `json:"number_of_pending_tasks"`
   241  	NumberInFlightFetch  int     `json:"number_of_in_flight_fetch"`
   242  	TaskMaxWaiting       int     `json:"task_max_waiting_in_queue_millis"`
   243  	ActiveShardsPercent  float64 `json:"active_shards_percent_as_number"`
   244  }
   245  
   246  type DocsResponse struct {
   247  	Count   int `json:"count"`
   248  	Deleted int `json:"deleted"`
   249  }
   250  type StoreResponse struct {
   251  	SizeInBytes     uint64 `json:"size_in_bytes"`
   252  	ReservedInBytes int    `json:"reservec_in_bytes"`
   253  }
   254  type ClusterStateResponseInfo struct {
   255  	ClusterName  string                 `json:"cluster_name"`
   256  	ClusterUUID  string                 `json:"cluster_uuid"`
   257  	MasterNode   string                 `json:"master_node"`
   258  	Blocks       map[string]interface{} `json:"blocks"`
   259  	RoutingTable map[string]interface{} `json:"routing_table"`
   260  }
   261  
   262  type ClusterStateBlocksInfo struct {
   263  	ClusterName string                 `json:"cluster_name"`
   264  	ClusterUUID string                 `json:"cluster_uuid"`
   265  	Blocks      map[string]interface{} `json:"blocks"`
   266  }
   267  
   268  type NodesAllResponseInfo struct {
   269  	Name             string              `json:"name"`
   270  	TransportAddress string              `json:"transport_address"`
   271  	HostName         string              `json:"host"`
   272  	IP               string              `json:"ip"`
   273  	Version          string              `json:"version"`
   274  	BuildFlavor      string              `json:"build_flavor"`
   275  	BuildType        string              `json:"build_type"`
   276  	BuildHash        string              `json:"build_hash"`
   277  	OSResponse       NodesOSResponseInfo `json:"os"`
   278  }
   279  type NodesOSResponseInfo struct {
   280  	RefreshInterval     string `json:"refresh_interval"`
   281  	RefreshIntervalInMS int    `json:"refresh_interval_in_millis"`
   282  	Name                string `json:"name"`
   283  	PrettyName          string `json:"pretty_name"`
   284  	Arch                string `json:"arch"`
   285  	Version             string `json:"version"`
   286  	AvailableProcessors int    `json:"available_processors"`
   287  	AllocatedProcessors int    `json:"allocated_processors"`
   288  }
   289  
   290  type ShardsItemsResponse struct {
   291  	State          string                 `json:"state"`
   292  	Primary        bool                   `json:"primary"`
   293  	Node           string                 `json:"node"`
   294  	RelocatingNode *string                `json:"relocating_node"`
   295  	Shard          int                    `json:"shard"`
   296  	Index          string                 `json:"index"`
   297  	AllocationId   map[string]interface{} `json:"allocation_id"`
   298  }
   299  type AllIndicesInfoResponse []IndexInfo
   300  
   301  type MultiNodesInfoResponse []*MemberInfo
   302  
   303  type GreetResponse struct {
   304  	Name        string       `json:"name"`
   305  	ClusterName string       `json:"cluster_name"`
   306  	ClusterUUID string       `json:"cluster_uuid"`
   307  	Version     GreetVersion `json:"version"`
   308  }
   309  
   310  type GreetVersion struct {
   311  	Number                           string `json:"number"`
   312  	BuildFlavour                     string `json:"build_flavor"`
   313  	BuildType                        string `json:"build_type"`
   314  	BuildDate                        string `json:"build_date"`
   315  	BuildHash                        string `json:"build_hash"`
   316  	BuildSnapshot                    bool   `json:"build_snapshot"`
   317  	LuceneVersion                    string `json:"lucene_version"`
   318  	MinimumWireCompatibilityVersion  string `json:"minimum_wire_compatibility_version"`
   319  	MinimumIndexCompatibilityVersion string `json:"minimum_index_compatibility_version"`
   320  }
   321  type TotalFsResponse struct {
   322  	Total            string `json:"total"`
   323  	TotalInBytes     uint64 `json:"total_in_bytes"`
   324  	Free             string `json:"free"`
   325  	FreeInBytes      uint64 `json:"free_in_bytes"`
   326  	Available        string `json:"available"`
   327  	AvailableInBytes uint64 `json:"available_in_bytes"`
   328  }
   329  type ProcessCpuResponse struct {
   330  	Percent       int    `json:"percent"`
   331  	Total         string `json:"total"`
   332  	TotalInMillis uint64 `json:"total_in_millis"`
   333  }
   334  type GetMasterResponse struct {
   335  	Id   string `json:"id"`
   336  	Host string `json:"host"`
   337  	IP   string `json:"ip"`
   338  	Node string `json:"node"`
   339  }
   340  type NodesStatsIdInfo struct {
   341  	Timestamp        int64  `json:"timestamp"`
   342  	Name             string `json:"name"`
   343  	TransportAddress string `json:"transport_address"`
   344  	Host             string `json:"host"`
   345  	IP               string `json:"ip"`
   346  }
   347  
   348  type NodesStatsIngestInfo struct {
   349  	Name             string                 `json:"name"`
   350  	TransportAddress string                 `json:"transport_address"`
   351  	Host             string                 `json:"host"`
   352  	IP               string                 `json:"ip"`
   353  	Version          string                 `json:"version"`
   354  	BuildFlavour     string                 `json:"build_flavor"`
   355  	BuildType        string                 `json:"build_type"`
   356  	BuildHash        string                 `json:"build_hash"`
   357  	Roles            []string               `json:"roles"`
   358  	Ingest           map[string]interface{} `json:"ingest"`
   359  }
   360  
   361  type DeleteIndexErrorResponseInfo struct {
   362  	Type         string `json:"type"`
   363  	Reason       string `json:"reason"`
   364  	ResourceType string `json:"resource.type"`
   365  	ResourceId   string `json:"resource.id"`
   366  	IndexUUID    string `json:"index.uuid"`
   367  	Index        string `json:"index"`
   368  }
   369  
   370  type ResultPerIndex map[string]map[string]interface{} // maps index name to index stats
   371  
   372  type ClusterStatsResponseInfo struct {
   373  	IngestionStats map[string]interface{}            `json:"ingestionStats"`
   374  	QueryStats     map[string]interface{}            `json:"queryStats"`
   375  	MetricsStats   map[string]interface{}            `json:"metricsStats"`
   376  	IndexStats     []ResultPerIndex                  `json:"indexStats"`
   377  	ChartStats     map[string]map[string]interface{} `json:"chartStats"`
   378  }
   379  
   380  type MetricsStatsResponseInfo struct {
   381  	AggStats map[string]map[string]interface{} `json:"aggStats"`
   382  }
   383  
   384  type AllSavedQueries map[string]map[string]interface{}
   385  
   386  type AutoCompleteDataInfo struct {
   387  	ColumnNames      []string `json:"colNames"`
   388  	MeasureFunctions []string `json:"measureFunctions"`
   389  }
   390  
   391  func NewSingleESResponse() *SingleESResponse {
   392  	return &SingleESResponse{
   393  		Index:          "",
   394  		Type:           "",
   395  		Id:             "",
   396  		Version:        1,
   397  		SequenceNumber: 0,
   398  		Source:         make(map[string]interface{}),
   399  		Found:          false,
   400  		PrimaryTerm:    1,
   401  	}
   402  }
   403  
   404  func WriteResponse(ctx *fasthttp.RequestCtx, httpResp HttpServerResponse) {
   405  	ctx.SetContentType(ContentJson)
   406  	jval, _ := json.Marshal(httpResp)
   407  	_, err := ctx.Write(jval)
   408  	if err != nil {
   409  		return
   410  	}
   411  }
   412  
   413  func WriteJsonResponse(ctx *fasthttp.RequestCtx, httpResp interface{}) {
   414  	ctx.SetContentType(ContentJson)
   415  	jval, _ := json.Marshal(httpResp)
   416  	_, err := ctx.Write(jval)
   417  	if err != nil {
   418  		return
   419  	}
   420  }
   421  
   422  func SetBadMsg(ctx *fasthttp.RequestCtx, msg string) {
   423  	if len(msg) == 0 {
   424  		msg = "Bad Request"
   425  	}
   426  	var httpResp HttpServerResponse
   427  	ctx.SetStatusCode(fasthttp.StatusBadRequest)
   428  	httpResp.Message = msg
   429  	httpResp.StatusCode = fasthttp.StatusBadRequest
   430  	WriteResponse(ctx, httpResp)
   431  }
   432  
   433  func ExtractParamAsString(_interface interface{}) string {
   434  	switch intfc := _interface.(type) {
   435  	case string:
   436  		return intfc
   437  	default:
   438  		return ""
   439  	}
   440  }
   441  
   442  func NewSettingsIndexInfo(providedName string) *SettingsIndexInfo {
   443  	return &SettingsIndexInfo{
   444  		NumberOfShards:   1,
   445  		NumberOfReplicas: 1,
   446  		ProvidedName:     providedName,
   447  	}
   448  }
   449  
   450  func NewBulkErrorResponseInfo(reason string, typ string) *BulkErrorResponseInfo {
   451  	return &BulkErrorResponseInfo{
   452  		Reason: reason,
   453  		Type:   typ,
   454  	}
   455  }
   456  
   457  func NewNodesStatsResponseInfo(total int, successful int, failed int) *NodesStatsResponseInfo {
   458  	return &NodesStatsResponseInfo{
   459  		Total:      total,
   460  		Successful: successful,
   461  		Failed:     failed,
   462  	}
   463  }
   464  
   465  func NewNodesResponseInfo(timestamp int64, host string, addressPort string, ipAddress string, osResponse map[string]interface{}, jvmResponse map[string]interface{}, fsResponse map[string]interface{}, processResponse map[string]interface{}) *NodesResponseInfo {
   466  	return &NodesResponseInfo{
   467  		Timestamp:        timestamp,
   468  		Name:             host,
   469  		HostName:         ipAddress,
   470  		TransportAddress: addressPort,
   471  		IP:               ipAddress,
   472  		OSResponse:       osResponse,
   473  		JVMResponse:      jvmResponse,
   474  		FSResponse:       fsResponse,
   475  		ProcessResponse:  processResponse,
   476  	}
   477  }
   478  
   479  func NewLoadAverageResponseInfo(loadAverage float64) *LoadAverageResponseInfo {
   480  	return &LoadAverageResponseInfo{
   481  		LoadResponse: loadAverage,
   482  	}
   483  }
   484  
   485  func NewAllResponseInfo() *AllResponseInfo {
   486  	return &AllResponseInfo{
   487  		Primaries: make(map[string]interface{}),
   488  		Total:     make(map[string]interface{}),
   489  	}
   490  }
   491  
   492  func NewMemResponseInfo(total string, totalInBytes uint64, free string, freeInBytes uint64, used string, usedInBytes uint64, freePercent float64, usedPercent float64) *MemResponseInfo {
   493  	return &MemResponseInfo{
   494  		Total:        total,
   495  		TotalInBytes: totalInBytes,
   496  		Free:         free,
   497  		FreeInBytes:  freeInBytes,
   498  		Used:         used,
   499  		UsedInBytes:  usedInBytes,
   500  		FreePercent:  uint64(freePercent),
   501  		UsedPercent:  uint64(usedPercent),
   502  	}
   503  }
   504  
   505  func NewSwapResponseInfo() *SwapResponseInfo {
   506  	return &SwapResponseInfo{
   507  		Total:        "3gb",
   508  		TotalInBytes: 3221225472,
   509  		Free:         "816.2mb",
   510  		FreeInBytes:  855900160,
   511  		Used:         "2.2gb",
   512  		UsedInBytes:  2365325312,
   513  	}
   514  }
   515  
   516  func NewNodesTransportResponseInfo(host string, addressPort string, version string) *NodesTransportResponseInfo {
   517  	return &NodesTransportResponseInfo{
   518  		Name:             host,
   519  		TransportAddress: addressPort,
   520  		HostName:         addressPort,
   521  		IP:               addressPort,
   522  		Version:          version,
   523  		BuildFlavor:      "oss",
   524  		BuildType:        "tar",
   525  		BuildHash:        "c4138e51121ef06a6404866cddc601906fe5c868",
   526  	}
   527  }
   528  
   529  func NewClusterStateResponseInfo(uuidVal string, indicesResponse map[string]interface{}) *ClusterStateResponseInfo {
   530  	return &ClusterStateResponseInfo{
   531  		ClusterName:  "siglens",
   532  		ClusterUUID:  uuidVal,
   533  		MasterNode:   "QXiD6Xa-RVqdZSLL8I_ZpQ",
   534  		Blocks:       make(map[string]interface{}),
   535  		RoutingTable: indicesResponse,
   536  	}
   537  }
   538  
   539  func NewClusterStateBlocksInfo(uuidVal string) *ClusterStateBlocksInfo {
   540  	return &ClusterStateBlocksInfo{
   541  		ClusterName: "siglens",
   542  		ClusterUUID: uuidVal,
   543  		Blocks:      make(map[string]interface{}),
   544  	}
   545  }
   546  
   547  func NewNodesAllResponseInfo(host string, addressPort string, version string, osResponse NodesOSResponseInfo) *NodesAllResponseInfo {
   548  	return &NodesAllResponseInfo{
   549  		Name:             host,
   550  		TransportAddress: addressPort,
   551  		HostName:         addressPort,
   552  		IP:               addressPort,
   553  		Version:          version,
   554  		BuildFlavor:      "oss",
   555  		BuildType:        "tar",
   556  		BuildHash:        "c4138e51121ef06a6404866cddc601906fe5c868",
   557  		OSResponse:       osResponse,
   558  	}
   559  }
   560  
   561  func NewNodesOSResponseInfo() *NodesOSResponseInfo {
   562  	return &NodesOSResponseInfo{
   563  		RefreshInterval:     "1s",
   564  		RefreshIntervalInMS: 1000,
   565  		Name:                "Mac OS X",
   566  		PrettyName:          "Mac OS X",
   567  		Arch:                "aarch64",
   568  		Version:             "11.3",
   569  		AvailableProcessors: 8,
   570  		AllocatedProcessors: 8,
   571  	}
   572  }
   573  
   574  func NewClusterHealthResponseInfo() *ClusterHealthResponseInfo {
   575  	return &ClusterHealthResponseInfo{
   576  		ClusterName:          "siglens",
   577  		Status:               "green",
   578  		TimedOut:             false,
   579  		NumberOfNodes:        1,
   580  		NumberOfDataNodes:    1,
   581  		ActivePrimaryShards:  0,
   582  		ActiveShards:         0,
   583  		RelocatingShards:     0,
   584  		InitiliazeShards:     0,
   585  		UnassignedShards:     0,
   586  		DelayedShards:        0,
   587  		NumberOfPendingTasks: 0,
   588  		NumberInFlightFetch:  0,
   589  		TaskMaxWaiting:       0,
   590  		ActiveShardsPercent:  100.0,
   591  	}
   592  }
   593  
   594  func NewNodesStatsMemResponse(heapcommitted string, heapCommittedBytes uint64, heapMax string, heapMaxBytes uint64, heapUsed string, heapUsedBytes uint64) *NodesStatsMemResponse {
   595  	return &NodesStatsMemResponse{
   596  		HeapCommitted:           heapcommitted,
   597  		HeapCommittedInBytes:    heapCommittedBytes,
   598  		HeapMax:                 heapMax,
   599  		HeapMaxInBytes:          heapMaxBytes,
   600  		HeapUsed:                heapUsed,
   601  		HeapUsedInBytes:         heapUsedBytes,
   602  		HeapUsedPercent:         2,
   603  		NonHeapCommitted:        "80.6mb",
   604  		NonHeapCommittedInBytes: 84606976,
   605  		NonHeapUsed:             "77.9mb",
   606  		NonHeapUsedInBytes:      81756968,
   607  	}
   608  }
   609  func NewDocsResponse(evenCount int) *DocsResponse {
   610  	return &DocsResponse{
   611  		Count:   evenCount,
   612  		Deleted: 0,
   613  	}
   614  }
   615  func NewStoreResponse(bytesReceivedCount uint64) *StoreResponse {
   616  	return &StoreResponse{
   617  		SizeInBytes:     bytesReceivedCount,
   618  		ReservedInBytes: 0,
   619  	}
   620  }
   621  func NewShardsItemsResponse(indexName string, allocationResponse map[string]interface{}) *ShardsItemsResponse {
   622  	return &ShardsItemsResponse{
   623  		State:          "STARTED",
   624  		Primary:        true,
   625  		Node:           "Ic2KfXpfQhaWhgeXAAcMYw",
   626  		RelocatingNode: nil,
   627  		Shard:          0,
   628  		Index:          indexName,
   629  		AllocationId:   allocationResponse,
   630  	}
   631  }
   632  func NewGreetVersion(esVersion string) GreetVersion {
   633  	return GreetVersion{
   634  		Number:                           esVersion,
   635  		BuildFlavour:                     "oss",
   636  		BuildType:                        "tar",
   637  		BuildDate:                        "2021-10-07T21:56:19.031608185Z",
   638  		BuildHash:                        "83c34f456ae29d60e94d886e455e6a3409bba9ed",
   639  		BuildSnapshot:                    false,
   640  		LuceneVersion:                    "8.9.0",
   641  		MinimumWireCompatibilityVersion:  "6.8.0",
   642  		MinimumIndexCompatibilityVersion: "6.0.0-beta1",
   643  	}
   644  }
   645  
   646  func NewGreetResponse(host string, uuidVal string, esVersion string) GreetResponse {
   647  	return GreetResponse{
   648  		Name:        host,
   649  		ClusterName: "siglens",
   650  		ClusterUUID: uuidVal,
   651  		Version:     NewGreetVersion(esVersion),
   652  	}
   653  }
   654  func NewTotalFsResponse(total string, totalInBytes uint64, free string, freeInBytes uint64, available string, availableInBytes uint64) *TotalFsResponse {
   655  	return &TotalFsResponse{
   656  		Total:            total,
   657  		TotalInBytes:     totalInBytes,
   658  		Free:             free,
   659  		FreeInBytes:      freeInBytes,
   660  		Available:        available,
   661  		AvailableInBytes: totalInBytes - availableInBytes,
   662  	}
   663  }
   664  func NewVirtualMemResponse(totalVirtual string, totalVirtualBytes uint64) *VirtualMemResponse {
   665  	return &VirtualMemResponse{
   666  		TotalVirtual:        totalVirtual,
   667  		TotalVirtualInBytes: totalVirtualBytes,
   668  	}
   669  }
   670  func NewProcessCpuResponse(percent int) *ProcessCpuResponse {
   671  	return &ProcessCpuResponse{
   672  		Percent:       percent,
   673  		Total:         "10.2s",
   674  		TotalInMillis: 10256,
   675  	}
   676  }
   677  func NewGetMasterResponse(id string, host string, node string) *GetMasterResponse {
   678  	return &GetMasterResponse{
   679  		Id:   id,
   680  		Host: host,
   681  		IP:   host,
   682  		Node: node,
   683  	}
   684  }
   685  func NewNodesStatsIdInfo(timestamp int64, hostname string, addressPort string, ipAddress string) *NodesStatsIdInfo {
   686  	return &NodesStatsIdInfo{
   687  		Timestamp:        timestamp,
   688  		Name:             hostname,
   689  		TransportAddress: addressPort,
   690  		Host:             ipAddress,
   691  		IP:               ipAddress,
   692  	}
   693  }
   694  
   695  func NewNodesStatsIngestInfo(hostname string, addressPort string,
   696  	ipAddress string, version string, ingestFeats map[string]interface{}) *NodesStatsIngestInfo {
   697  	return &NodesStatsIngestInfo{
   698  		Name:             hostname,
   699  		TransportAddress: addressPort,
   700  		Host:             ipAddress,
   701  		IP:               ipAddress,
   702  		Version:          version,
   703  		BuildFlavour:     "oss",
   704  		BuildType:        "tar",
   705  		BuildHash:        "83c34f456ae29d60e94d886e455e6a3409bba9ed",
   706  		Roles:            []string{"data", "ingest", "master", "remote_cluster_client"},
   707  		Ingest:           ingestFeats,
   708  	}
   709  }
   710  
   711  func NewDeleteIndexErrorResponseInfo(indexName string) *DeleteIndexErrorResponseInfo {
   712  	return &DeleteIndexErrorResponseInfo{
   713  		Type:         "index_not_found_exception",
   714  		Reason:       "no such index" + "[" + indexName + "]",
   715  		ResourceType: "index_or_alias",
   716  		ResourceId:   indexName,
   717  		IndexUUID:    "_na_",
   718  		Index:        indexName,
   719  	}
   720  }
   721  
   722  func NewAutoCompleteDataInfo(columnNames []string, measureFunctions []string) *AutoCompleteDataInfo {
   723  	return &AutoCompleteDataInfo{
   724  		ColumnNames:      columnNames,
   725  		MeasureFunctions: measureFunctions,
   726  	}
   727  }
   728  
   729  func (eo *HttpServerESResponse) GetHits() uint64 {
   730  	switch t := eo.Total.(type) {
   731  	case uint64:
   732  		return t
   733  	case HitsCount:
   734  		return t.Value
   735  	case map[string]interface{}:
   736  		retVal, ok := t["value"]
   737  		if !ok {
   738  			log.Infof("Tried to get hits for a map with no 'value' key! Map: %v", retVal)
   739  			return 0
   740  		}
   741  		switch hit := retVal.(type) {
   742  		case float64:
   743  			return uint64(hit)
   744  		case uint64:
   745  			return hit
   746  		case int64:
   747  			return uint64(hit)
   748  		default:
   749  			log.Infof("Map value is not a supported type!: %v %T", hit, hit)
   750  			return 0
   751  		}
   752  	default:
   753  		log.Infof("Tried to get hits for unsupported type %T", t)
   754  		return 0
   755  	}
   756  }
   757  
   758  func ExtractBearerToken(ctx *fasthttp.RequestCtx) (string, error) {
   759  	authHeader := ctx.Request.Header.Peek("Authorization")
   760  	authToken := strings.Split(string(authHeader), "Bearer ")
   761  	if len(authToken) != 2 {
   762  		return "", errors.New("malformed bearer token")
   763  	}
   764  	jwtToken := authToken[1]
   765  	return jwtToken, nil
   766  }
   767  
   768  // Reads the basic authorization from the request to extract the username and
   769  // password. Then hashes the username and password and compares with the
   770  // expected hash values.
   771  // Returns true if the hashes match. Returns false if the hashes do not match
   772  // or if basic authentication credentials are not provided in the request.
   773  // The provided usernameHash and passwordHash fields should be hashed with
   774  // the xxhash.Sum64 algorithm.
   775  // Basic authentication is defined at https://www.rfc-editor.org/rfc/rfc2617#section-2
   776  func VerifyBasicAuth(ctx *fasthttp.RequestCtx, usernameHash uint64, passwordHash uint64) bool {
   777  	auth := string(ctx.Request.Header.Peek("Authorization"))
   778  	if len(auth) == 0 {
   779  		return false
   780  	}
   781  
   782  	// The auth string should be something like:
   783  	// Basic dXNlcm5hbWU6cGFzc3dvcmQK
   784  	const prefix = "Basic "
   785  	if !strings.HasPrefix(auth, prefix) {
   786  		return false
   787  	}
   788  
   789  	base64Encoding := auth[len(prefix):]
   790  	decoded, err := base64.StdEncoding.DecodeString(base64Encoding)
   791  	if err != nil {
   792  		log.Errorf("VerifyBasicAuth: failed to decode %s: %v", base64Encoding, err)
   793  	}
   794  
   795  	// The decoded string should be something like:
   796  	// username:password
   797  	username, password, foundColon := strings.Cut(string(decoded), ":")
   798  	if !foundColon {
   799  		return false
   800  	}
   801  
   802  	usernameMatches := (xxhash.Sum64String(username) == usernameHash)
   803  	passwordMatches := (xxhash.Sum64String(password) == passwordHash)
   804  
   805  	return usernameMatches && passwordMatches
   806  }
   807  
   808  // Use the MAC address as a computer-specific identifier. If it is not available, use the hostname instead.
   809  func GetSpecificIdentifier() (string, error) {
   810  	interfaces, err := net.Interfaces()
   811  	if err != nil {
   812  		return "", fmt.Errorf("GetSpecificIdentifier: %v", err)
   813  	}
   814  
   815  	for _, iface := range interfaces {
   816  		if len(iface.HardwareAddr.String()) != 0 {
   817  			return iface.HardwareAddr.String(), nil
   818  		}
   819  	}
   820  
   821  	hostname, err := os.Hostname()
   822  	if err != nil {
   823  		return "", nil
   824  	}
   825  
   826  	return hostname, nil
   827  }
   828  
   829  func GetDecodedBody(ctx *fasthttp.RequestCtx) ([]byte, error) {
   830  	contentEncoding := string(ctx.Request.Header.Peek("Content-Encoding"))
   831  	switch contentEncoding {
   832  	case "":
   833  		return ctx.Request.Body(), nil
   834  	case "gzip":
   835  		return gunzip(ctx.Request.Body())
   836  	default:
   837  		return nil, fmt.Errorf("GetDecodedBody: unsupported content encoding: %s", contentEncoding)
   838  	}
   839  }
   840  
   841  func gunzip(data []byte) ([]byte, error) {
   842  	return fasthttp.AppendGunzipBytes(nil, data)
   843  }
   844  
   845  // This takes a group of JSON objects (not inside a JSON array) and splits them
   846  // into individual JSON objects.
   847  func ExtractSeriesOfJsonObjects(body []byte) ([]map[string]interface{}, error) {
   848  	var objects []map[string]interface{}
   849  	decoder := json.NewDecoder(bytes.NewReader(body))
   850  
   851  	for {
   852  		var obj map[string]interface{}
   853  		if err := decoder.Decode(&obj); err != nil {
   854  			// If we reach the end of the input, break the loop.
   855  			if err == io.EOF {
   856  				break
   857  			}
   858  
   859  			return nil, fmt.Errorf("ExtractSeriesOfJsonObjects: error decoding JSON: %v", err)
   860  		}
   861  
   862  		objects = append(objects, obj)
   863  	}
   864  
   865  	return objects, nil
   866  }