text: /***********************************************************************************************************************************
  Http Client Cache
  ***********************************************************************************************************************************/
  #include "build.auto.h"
  
  #include "common/debug.h"
  #include "common/io/http/cache.h"
  #include "common/log.h"
  #include "common/object.h"
  #include "common/type/list.h"
  
  /***********************************************************************************************************************************
  Object type
  ***********************************************************************************************************************************/
  struct HttpClientCache
  {
      MemContext *memContext;                                         // Mem context
  
      const String *host;                                             // Client settings
      unsigned int port;
      TimeMSec timeout;
      bool verifyPeer;
      const String *caFile;
      const String *caPath;
  
      List *clientList;                                               // List of http clients
  };
  
  OBJECT_DEFINE_FREE(HTTP_CLIENT_CACHE);
  
  /***********************************************************************************************************************************
  New object
  ***********************************************************************************************************************************/
  HttpClientCache *
  httpClientCacheNew(
      const String *host, unsigned int port, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath)
  {
      FUNCTION_LOG_BEGIN(logLevelDebug)
          FUNCTION_LOG_PARAM(STRING, host);
          FUNCTION_LOG_PARAM(UINT, port);
          FUNCTION_LOG_PARAM(TIME_MSEC, timeout);
          FUNCTION_LOG_PARAM(BOOL, verifyPeer);
          FUNCTION_LOG_PARAM(STRING, caFile);
          FUNCTION_LOG_PARAM(STRING, caPath);
      FUNCTION_LOG_END();
  
      ASSERT(host != NULL);
  
      HttpClientCache *this = NULL;
  
      MEM_CONTEXT_NEW_BEGIN("HttpClientCache")
      {
          // Allocate state and set context
          this = memNew(sizeof(HttpClientCache));
  
          *this = (HttpClientCache)
          {
              .memContext = MEM_CONTEXT_NEW(),
              .host = strDup(host),
              .port = port,
              .timeout = timeout,
              .verifyPeer = verifyPeer,
              .caFile = strDup(caFile),
              .caPath = strDup(caPath),
              .clientList = lstNew(sizeof(HttpClient *)),
          };
      }
      MEM_CONTEXT_NEW_END();
  
      FUNCTION_LOG_RETURN(HTTP_CLIENT_CACHE, this);
  }
  
  /***********************************************************************************************************************************
  Get an http client from the cache
  ***********************************************************************************************************************************/
  HttpClient *
  httpClientCacheGet(HttpClientCache *this)
  {
      FUNCTION_LOG_BEGIN(logLevelTrace)
          FUNCTION_LOG_PARAM(HTTP_CLIENT_CACHE, this);
      FUNCTION_LOG_END();
  
      ASSERT(this != NULL);
  
      HttpClient *result = NULL;
  
      // Search for a client that is not busy
      for (unsigned int clientIdx = 0; clientIdx < lstSize(this->clientList); clientIdx++)
      {
          HttpClient *httpClient = *(HttpClient **)lstGet(this->clientList, clientIdx);
  
          if (!httpClientBusy(httpClient))
              result = httpClient;
      }
  
      // If none found then create a new one
      if (result == NULL)
      {
          MEM_CONTEXT_BEGIN(this->memContext)
          {
              result = httpClientNew(this->host, this->port, this->timeout, this->verifyPeer, this->caFile, this->caPath);
              lstAdd(this->clientList, &result);
          }
          MEM_CONTEXT_END();
      }
  
      FUNCTION_LOG_RETURN(HTTP_CLIENT, result);
  }
  