text: // Copyright (c) 2010 Satoshi Nakamoto
  // Copyright (c) 2009-2019 The TNGC Core developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifndef TNGC_RPC_SERVER_H
  #define TNGC_RPC_SERVER_H
  
  #include <amount.h>
  #include <rpc/request.h>
  #include <rpc/util.h>
  
  #include <functional>
  #include <map>
  #include <stdint.h>
  #include <string>
  
  #include <univalue.h>
  
  static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1;
  
  class CRPCCommand;
  
  namespace RPCServer
  {
      void OnStarted(std::function<void ()> slot);
      void OnStopped(std::function<void ()> slot);
  }
  
  /** Query whether RPC is running */
  bool IsRPCRunning();
  
  /** Throw JSONRPCError if RPC is not running */
  void RpcInterruptionPoint();
  
  /**
   * Set the RPC warmup status.  When this is done, all RPC calls will error out
   * immediately with RPC_IN_WARMUP.
   */
  void SetRPCWarmupStatus(const std::string& newStatus);
  /* Mark warmup as done.  RPC calls will be processed from now on.  */
  void SetRPCWarmupFinished();
  
  /* returns the current warmup state.  */
  bool RPCIsInWarmup(std::string *outStatus);
  
  /** Opaque base class for timers returned by NewTimerFunc.
   * This provides no methods at the moment, but makes sure that delete
   * cleans up the whole state.
   */
  class RPCTimerBase
  {
  public:
      virtual ~RPCTimerBase() {}
  };
  
  /**
   * RPC timer "driver".
   */
  class RPCTimerInterface
  {
  public:
      virtual ~RPCTimerInterface() {}
      /** Implementation name */
      virtual const char *Name() = 0;
      /** Factory function for timers.
       * RPC will call the function to create a timer that will call func in *millis* milliseconds.
       * @note As the RPC mechanism is backend-neutral, it can use different implementations of timers.
       * This is needed to cope with the case in which there is no HTTP server, but
       * only GUI RPC console, and to break the dependency of pcserver on httprpc.
       */
      virtual RPCTimerBase* NewTimer(std::function<void()>& func, int64_t millis) = 0;
  };
  
  /** Set the factory function for timers */
  void RPCSetTimerInterface(RPCTimerInterface *iface);
  /** Set the factory function for timer, but only, if unset */
  void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface);
  /** Unset factory function for timers */
  void RPCUnsetTimerInterface(RPCTimerInterface *iface);
  
  /**
   * Run func nSeconds from now.
   * Overrides previous timer <name> (if any).
   */
  void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nSeconds);
  
  typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
  typedef RPCHelpMan (*RpcMethodFnType)();
  
  class CRPCCommand
  {
  public:
      //! RPC method handler reading request and assigning result. Should return
      //! true if request is fully handled, false if it should be passed on to
      //! subsequent handlers.
      using Actor = std::function<bool(const JSONRPCRequest& request, UniValue& result, bool last_handler)>;
  
      //! Constructor taking Actor callback supporting multiple handlers.
      CRPCCommand(std::string category, std::string name, Actor actor, std::vector<std::string> args, intptr_t unique_id)
          : category(std::move(category)), name(std::move(name)), actor(std::move(actor)), argNames(std::move(args)),
            unique_id(unique_id)
      {
      }
  
      //! Simplified constructor taking plain RpcMethodFnType function pointer.
      CRPCCommand(std::string category, std::string name_in, RpcMethodFnType fn, std::vector<std::string> args_in)
          : CRPCCommand(
                category,
                fn().m_name,
                [fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn().HandleRequest(request); return true; },
                fn().GetArgNames(),
                intptr_t(fn))
      {
          CHECK_NONFATAL(fn().m_name == name_in);
          CHECK_NONFATAL(fn().GetArgNames() == args_in);
      }
  
      //! Simplified constructor taking plain rpcfn_type function pointer.
      CRPCCommand(const char* category, const char* name, rpcfn_type fn, std::initializer_list<const char*> args)
          : CRPCCommand(category, name,
                        [fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn(request); return true; },
                        {args.begin(), args.end()}, intptr_t(fn))
      {
      }
  
      std::string category;
      std::string name;
      Actor actor;
      std::vector<std::string> argNames;
      intptr_t unique_id;
  };
  
  /**
   * RPC command dispatcher.
   */
  class CRPCTable
  {
  private:
      std::map<std::string, std::vector<const CRPCCommand*>> mapCommands;
  public:
      CRPCTable();
      std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
  
      /**
       * Execute a method.
       * @param request The JSONRPCRequest to execute
       * @returns Result of the call.
       * @throws an exception (UniValue) when an error happens.
       */
      UniValue execute(const JSONRPCRequest &request) const;
  
      /**
      * Returns a list of registered commands
      * @returns List of registered commands.
      */
      std::vector<std::string> listCommands() const;
  
  
      /**
       * Appends a CRPCCommand to the dispatch table.
       *
       * Precondition: RPC server is not running
       *
       * Commands with different method names but the same unique_id will
       * be considered aliases, and only the first registered method name will
       * show up in the help text command listing. Aliased commands do not have
       * to have the same behavior. Server and client code can distinguish
       * between calls based on method name, and aliased commands can also
       * register different names, types, and numbers of parameters.
       */
      void appendCommand(const std::string& name, const CRPCCommand* pcmd);
      bool removeCommand(const std::string& name, const CRPCCommand* pcmd);
  };
  
  bool IsDeprecatedRPCEnabled(const std::string& method);
  
  extern CRPCTable tableRPC;
  
  void StartRPC();
  void InterruptRPC();
  void StopRPC();
  std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq);
  
  // Retrieves any serialization flags requested in command line argument
  int RPCSerializationFlags();
  
  #endif // TNGC_RPC_SERVER_H
  