/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#pragma once

#include "engine_error.h"
#include "protocol_binary.h"
#include "rbac.h"
#include "types.h"

#include <mcbp/protocol/opcode.h>
#include <nlohmann/json_fwd.hpp>
#include <gsl/gsl>
#include <string>

/**
 * Commands to operate on a specific cookie.
 */
struct ServerCookieIface {
    virtual ~ServerCookieIface() = default;

    /**
     * Store engine-specific session data on the given cookie.
     *
     * The engine interface allows for a single item to be
     * attached to the connection that it can use to track
     * connection-specific data throughout duration of the
     * connection.
     *
     * @param cookie The cookie provided by the frontend
     * @param engine_data pointer to opaque data
     */
    virtual void store_engine_specific(gsl::not_null<const void*> cookie,
                                       void* engine_data) = 0;

    /**
     * Retrieve engine-specific session data for the given cookie.
     *
     * @param cookie The cookie provided by the frontend
     *
     * @return the data provied by store_engine_specific or NULL
     *         if none was provided
     */
    virtual void* get_engine_specific(gsl::not_null<const void*> cookie) = 0;

    /**
     * Check if datatype is supported by the connection.
     *
     * @param cookie The cookie provided by the frontend
     * @param datatype The datatype to test
     *
     * @return true if connection supports the datatype or else false.
     */
    virtual bool is_datatype_supported(gsl::not_null<const void*> cookie,
                                       protocol_binary_datatype_t datatype) = 0;

    /**
     * Check if mutation extras is supported by the connection.
     *
     * @param cookie The cookie provided by the frontend
     *
     * @return true if supported or else false.
     */
    virtual bool is_mutation_extras_supported(
            gsl::not_null<const void*> cookie) = 0;

    /**
     * Check if collections are supported by the connection.
     *
     * @param cookie The cookie provided by the frontend
     *
     * @return true if supported or else false.
     */
    virtual bool is_collections_supported(
            gsl::not_null<const void*> cookie) = 0;

    /**
     * Retrieve the opcode of the connection, if
     * ewouldblock flag is set. Please note that the ewouldblock
     * flag for a connection is cleared before calling into
     * the engine interface, so this method only works in the
     * notify hooks.
     *
     * @param cookie The cookie provided by the frontend
     *
     * @return the opcode from the binary_header saved in the
     * connection.
     */
    virtual cb::mcbp::ClientOpcode get_opcode_if_ewouldblock_set(
            gsl::not_null<const void*> cookie) = 0;

    /**
     * Validate given ns_server's session cas token against
     * saved token in memached, and if so incrment the session
     * counter.
     *
     * @param cas The cas token from the request
     *
     * @return true if session cas matches the one saved in
     * memcached
     */
    virtual bool validate_session_cas(uint64_t cas) = 0;

    /**
     * Decrement session_cas's counter everytime a control
     * command completes execution.
     */
    virtual void decrement_session_ctr() = 0;

    /**
     * Let a connection know that IO has completed.
     * @param cookie cookie representing the connection
     * @param status the status for the io operation
     */
    virtual void notify_io_complete(gsl::not_null<const void*> cookie,
                                    ENGINE_ERROR_CODE status) = 0;

    /**
     * Notify the core that we're holding on to this cookie for
     * future use. (The core guarantees it will not invalidate the
     * memory until the cookie is invalidated by calling release())
     */
    virtual ENGINE_ERROR_CODE reserve(gsl::not_null<const void*> cookie) = 0;

    /**
     * Notify the core that we're releasing the reference to the
     * The engine is not allowed to use the cookie (the core may invalidate
     * the memory)
     */
    virtual ENGINE_ERROR_CODE release(gsl::not_null<const void*> cookie) = 0;

    /**
     * Set the priority for this connection
     */
    virtual void set_priority(gsl::not_null<const void*> cookie,
                              CONN_PRIORITY priority) = 0;

    /**
     * Get the priority for this connection
     */
    virtual CONN_PRIORITY get_priority(gsl::not_null<const void*> cookie) = 0;

    /**
     * Get the bucket the connection is bound to
     *
     * @cookie The connection object
     * @return the bucket identifier for a cookie
     */
    virtual bucket_id_t get_bucket_id(gsl::not_null<const void*> cookie) = 0;

    /**
     * Get connection id
     *
     * @param cookie the cookie sent to the engine for an operation
     * @return a unique identifier for a connection
     */
    virtual uint64_t get_connection_id(gsl::not_null<const void*> cookie) = 0;

    /**
     * Check if the cookie have the specified privilege in it's
     * active set.
     *
     * @todo We should probably add the key we want to access as part
     *       of the API. We're going to need that when we're adding
     *       support for collections. For now let's assume that it
     *       won't be a big problem to fix that later on.
     * @param cookie the cookie sent to the engine for an operation
     * @param privilege the privilege to check for
     * @return true if the cookie have the privilege in its active set,
     *         false otherwise
     */
    virtual cb::rbac::PrivilegeAccess check_privilege(
            gsl::not_null<const void*> cookie,
            cb::rbac::Privilege privilege) = 0;

    /**
     * Method to map an engine error code to the appropriate mcbp response
     * code (the client may not support all error codes so we may have
     * to remap some).
     *
     * @param cookie the client cookie (to look up the client connection)
     * @param code the engine error code to get the mcbp response code.
     * @return the mcbp response status to use
     * @throws std::engine_error if the error code results in being
     *                           ENGINE_DISCONNECT after remapping
     *         std::logic_error if the error code doesn't make sense
     *         std::invalid_argument if the code doesn't exist
     */
    virtual cb::mcbp::Status engine_error2mcbp(
            gsl::not_null<const void*> cookie, ENGINE_ERROR_CODE code) = 0;

    /**
     * Get the log information to be used for a log entry.
     *
     * The typical log entry from the core is:
     *
     *  `id> message` - Data read from ta client
     *  `id: message` - Status messages for this client
     *  `id< message` - Data sent back to the client
     *
     * If the caller wants to dump more information about the connection
     * (like socket name, peer name, user name) the pair returns this
     * info as the second field. The info may be invalidated by the core
     * at any time (but not while the engine is operating in a single call
     * from the core) so it should _not_ be cached.
     */
    virtual std::pair<uint32_t, std::string> get_log_info(
            gsl::not_null<const void*> cookie) = 0;

    virtual std::string get_authenticated_user(
            gsl::not_null<const void*> cookie) = 0;

    virtual in_port_t get_connected_port(gsl::not_null<const void*> cookie) = 0;

    /**
     * Set the error context string to be sent in response. This should not
     * contain security sensitive information. If sensitive information needs to
     * be preserved, log it with a UUID and send the UUID.
     *
     * Note this has no affect for the following response codes.
     *   cb::mcbp::Status::Success
     *   cb::mcbp::Status::SubdocSuccessDeleted
     *   cb::mcbp::Status::SubdocMultiPathFailure
     *   cb::mcbp::Status::Rollback
     *   cb::mcbp::Status::NotMyVbucket
     *
     * @param cookie the client cookie (to look up client connection)
     * @param message the message string to be set as the error context
     */
    virtual void set_error_context(gsl::not_null<void*> cookie,
                                   cb::const_char_buffer message) = 0;

    /**
     * Set a JSON object to be included in an error response (along side
     * anything set by set_error_context).
     *
     * The json object cannot include "error" as a top-level key
     *
     * Note this has no affect for the following response codes.
     *   cb::mcbp::Status::Success
     *   cb::mcbp::Status::SubdocSuccessDeleted
     *   cb::mcbp::Status::SubdocMultiPathFailure
     *   cb::mcbp::Status::Rollback
     *   cb::mcbp::Status::NotMyVbucket
     *
     * @param cookie the client cookie (to look up client connection)
     * @param json extra json object to include in a error response.
     */
    virtual void set_error_json_extras(gsl::not_null<void*> cookie,
                                       const nlohmann::json& json) = 0;
};


/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Portions Copyright (c) Microsoft Corporation

#pragma once

#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <gsl/pointers>

#include "core/common/common.h"
#include "core/common/callback.h"
#include "core/platform/env_time.h"

#ifndef _WIN32
#include <sys/types.h>
#include <unistd.h>
#endif

namespace onnxruntime {

#ifdef _WIN32
using PIDType = unsigned long;
#else
using PIDType = pid_t;
#endif

/// \brief An interface used by the onnxruntime implementation to
/// access operating system functionality like the filesystem etc.
///
/// Callers may wish to provide a custom Env object to get fine grain
/// control.
///
/// All Env implementations are safe for concurrent access from
/// multiple threads without any external synchronization.
class Env {
 public:
  virtual ~Env() = default;

  /// \brief Returns a default environment suitable for the current operating
  /// system.
  ///
  /// Sophisticated users may wish to provide their own Env
  /// implementation instead of relying on this default environment.
  ///
  /// The result of Default() belongs to this library and must never be deleted.
  static const Env& Default();

  virtual int GetNumCpuCores() const = 0;

  /// \brief Returns the number of micro-seconds since the Unix epoch.
  virtual uint64_t NowMicros() const { return env_time_->NowMicros(); }

  /// \brief Returns the number of seconds since the Unix epoch.
  virtual uint64_t NowSeconds() const { return env_time_->NowSeconds(); }

  /// Sleeps/delays the thread for the prescribed number of micro-seconds.
  /// On Windows, it's the min time to sleep, not the actual one.
  virtual void SleepForMicroseconds(int64_t micros) const = 0;

#ifndef _WIN32
  /**
   *
   * \param file_path file_path must point to a regular file, which can't be a pipe/socket/...
   * \param[out] p  allocated buffer with the file data
   * \param[in] offset file offset. If offset>0, then len must also be >0.
   * \param[in, out] len length to read(or has read). If len==0, read the whole file.
   * @return
   */
  virtual common::Status ReadFileAsString(const char* file_path, off_t offset, void*& p, size_t& len,
      OrtCallback& deleter) const = 0;
#else
  virtual common::Status ReadFileAsString(const wchar_t* file_path, int64_t offset, void*& p, size_t& len,
                                          OrtCallback& deleter) const = 0;
#endif

#ifdef _WIN32
  //Mainly for use with protobuf library
  virtual common::Status FileOpenRd(const std::wstring& path, /*out*/ int& fd) const = 0;
  //Mainly for use with protobuf library
  virtual common::Status FileOpenWr(const std::wstring& path, /*out*/ int& fd) const = 0;
#endif
  //Mainly for use with protobuf library
  virtual common::Status FileOpenRd(const std::string& path, /*out*/ int& fd) const = 0;
  //Mainly for use with protobuf library
  virtual common::Status FileOpenWr(const std::string& path, /*out*/ int& fd) const = 0;
  //Mainly for use with protobuf library
  virtual common::Status FileClose(int fd) const = 0;
  //This functions is always successful. It can't fail.
  virtual PIDType GetSelfPid() const = 0;

  // \brief Load a dynamic library.
  //
  // Pass "library_filename" to a platform-specific mechanism for dynamically
  // loading a library.  The rules for determining the exact location of the
  // library are platform-specific and are not documented here.
  //
  // On success, returns a handle to the library in "*handle" and returns
  // OK from the function.
  // Otherwise returns nullptr in "*handle" and an error status from the
  // function.
  virtual common::Status LoadDynamicLibrary(const std::string& library_filename, void** handle) const = 0;

  virtual common::Status UnloadDynamicLibrary(void* handle) const = 0;

  // \brief Get a pointer to a symbol from a dynamic library.
  //
  // "handle" should be a pointer returned from a previous call to LoadDynamicLibrary.
  // On success, store a pointer to the located symbol in "*symbol" and return
  // OK from the function. Otherwise, returns nullptr in "*symbol" and an error
  // status from the function.
  virtual common::Status GetSymbolFromLibrary(void* handle, const std::string& symbol_name, void** symbol) const = 0;

  // \brief build the name of dynamic library.
  //
  // "name" should be name of the library.
  // "version" should be the version of the library or NULL
  // returns the name that LoadDynamicLibrary() can use
  virtual std::string FormatLibraryFileName(const std::string& name, const std::string& version) const = 0;

 protected:
  Env();

 private:
  ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(Env);
  EnvTime* env_time_ = EnvTime::Default();
};

}  // namespace onnxruntime


#ifndef LOGGER_INCLUDE
#define LOGGER_INCLUDE

#include <gsl/string_span>

#include "log.h"
BOOST_LOG_GLOBAL_LOGGER(
    exec_helper_log_logger,
    execHelper::log::LoggerType); // NOLINT(modernize-use-using)

static const gsl::czstring<> LOG_CHANNEL = "log";
#define LOG(x)                                                                 \
    BOOST_LOG_STREAM_CHANNEL_SEV(exec_helper_log_logger::get(), LOG_CHANNEL,   \
                                 x)                                            \
        << boost::log::add_value(fileLog, __FILE__)                            \
        << boost::log::add_value(lineLog, __LINE__)

#endif /* LOGGER_INCLUDE */


//
// CI Hello World
//
// Copyright (C) 2017 Assured Information Security, Inc.
// Author: Rian Quinn        <quinnr@ainfosec.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#ifndef CONSUMER_H
#define CONSUMER_H

#include <gsl/gsl>
#include <producer.h>

/// Consumer
///
/// A simple example of a consumer that is capable of accepting the real
/// producer, or a mocked version for unit testing.
///
class consumer
{
public:

    /// Default Constructor
    ///
    /// @param p the producer that this consumer will use.
    ///
    explicit consumer(gsl::not_null<producer *> p)
    { p->print_msg(); }

    /// Default Destructor
    ///
    ~consumer() = default;

public:

    // We define the copy and move constructors / operators because Clang Tidy
    // (legitimately) complains about the definition of a destructor without
    // defining the copy and move semantics for this class. In general a class
    // should always be marked non-copyable unless such functionality is
    // specifically desired.

    consumer(consumer &&) noexcept = default;               ///< Default move construction
    consumer &operator=(consumer &&) noexcept = default;    ///< Default move operator

    consumer(const consumer &) = delete;                    ///< Deleted copy construction
    consumer &operator=(const consumer &) = delete;         ///< Deleted copy operator
};

#endif


#pragma once

#include "poll_event.h"
#include "poll_response.h"
#include "poll_target.h"

#include <cstddef>
#include <optional>
#include <string>
#include <vector>

#include <gsl/span>

namespace wrappers::zmq {

class context;

class socket final {

public:
    enum class type {
        pair,
        pub,
        sub,
        req,
        rep,
        dealer,
        router,
        pull,
        push,
        xpub,
        xsub,
        stream,
    };

    explicit socket(context &ctx, type socket_type) noexcept;
    socket(const socket &other) = delete;
    socket &operator=(const socket &other) = delete;
    socket(socket &&other) noexcept;
    socket &operator=(socket &&other) noexcept;
    ~socket() noexcept;

    [[nodiscard]] bool bind(const std::string &endpoint) noexcept;

    [[nodiscard]] bool connect(const std::string &endpoint) noexcept;

    [[nodiscard]] bool blocking_send() noexcept;
    [[nodiscard]] bool blocking_send(gsl::span<std::byte> message) noexcept;

    [[nodiscard]] std::optional<std::vector<std::byte>>
    blocking_receive() noexcept;

    [[nodiscard]] bool
    async_receive(void *data,
                  void (*callback)(void *, gsl::span<std::byte>)) noexcept;

    friend std::optional<std::vector<poll_response>>
    blocking_poll(gsl::span<poll_target> targets) noexcept;

private:
    void *m_socket = nullptr;
};

} // namespace wrappers::zmq


/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018-Present Couchbase, Inc.
 *
 *   Use of this software is governed by the Business Source License included
 *   in the file licenses/BSL-Couchbase.txt.  As of the Change Date specified
 *   in that file, in accordance with the Business Source License, use of this
 *   software will be governed by the Apache License, Version 2.0, included in
 *   the file licenses/APL2.txt.
 */

#pragma once

#include <mcbp/protocol/response.h>
#include <mcbp/protocol/status.h>
#include <nlohmann/json_fwd.hpp>
#include <platform/thread.h>
#include <chrono>
#include <gsl/gsl>
#include <mutex>
#include <queue>
#include <unordered_map>
#include <vector>

class Connection;
class AuthnAuthzServiceTask;

/**
 * The ExternalAuthManagerThread class takes care of the scheduling between
 * the authentication requests and the responses received.
 *
 * One of the problems is that we try to communicate between multiple
 * frontend threads, which could cause deadlocks. To avoid locking
 * problems we're using a dedicated thread to communicate with the
 * other threads.
 */
class ExternalAuthManagerThread : public Couchbase::Thread {
public:
    ExternalAuthManagerThread() : Couchbase::Thread("mcd:ext_auth") {
    }
    ExternalAuthManagerThread(const ExternalAuthManagerThread&) = delete;

    /**
     * The named (external) user logged on to the system
     */
    void login(const std::string& user);

    /**
     * The named (external) user logged off the system
     */
    void logoff(const std::string& user);

    /**
     * Get the list of active users defined in the system
     */
    nlohmann::json getActiveUsers() const;

    /**
     * Add the provided connection to the list of available authentication
     * providers
     */
    void add(Connection& connection);

    /**
     * Remove the connection from the list of available providers (the
     * connection may not be registered)
     */
    void remove(Connection& connection);

    /**
     * Enqueue a SASL request to the list of requests to send to the
     * RBAC provider. NOTE: This method must _NOT_ be called from the
     * worker threads as that may result in a deadlock (should be
     * called from the tasks execute() method when running on the
     * executor threads)
     *
     * @param request the task to notify when the result comes back
     */
    void enqueueRequest(AuthnAuthzServiceTask& request);

    /**
     * Received an authentication response on the provided connection
     *
     * @param connection the connection the message was received on
     * @param response
     */
    void responseReceived(const cb::mcbp::Response& response);

    /**
     * Request the authentication daemon to stop
     */
    void shutdown();

    void setPushActiveUsersInterval(std::chrono::microseconds interval) {
        activeUsersPushInterval.store(interval);
        condition_variable.notify_one();
    }

    void setRbacCacheEpoch(std::chrono::steady_clock::time_point tp);

    /// Check to see if we've got an up to date RBAC entry for the user
    bool haveRbacEntryForUser(const std::string& user) const;

protected:
    /// The main loop of the thread
    void run() override;

    /**
     * Process all of the requests added by the various SaslTasks by putting
     * them into the queue of messages to send to the Authentication Provider.
     */
    void processRequestQueue();
    /**
     * Process all of the response messages enqueued and notify the SaslTask
     */
    void processResponseQueue();

    /**
     * Iterate over all of the connections marked as closed. Generate
     * error responses for all outstanding requests; decrement the reference
     * count and tell the thread to complete its shutdown logic.
     */
    void purgePendingDeadConnections();

    /// Push the list of active users to the authentication provider
    void pushActiveUsers();

    /// Let the daemon thread run as long as this member is set to true
    bool running = true;

    /// The next value to use in the opaque field
    uint32_t next = 0;

    /// The map between the opaque field being used and the SaslAuthTask
    /// requested the operation
    /// Second should be a std pair of a connection and a task, so that
    /// when we remove a connection we can iterate over the entire
    /// map and create aborts for the one we don't have anymore (or
    /// we could redistribute them O:)
    std::unordered_map<uint32_t, std::pair<Connection*, AuthnAuthzServiceTask*>>
            requestMap;

    /// The mutex variable used to protect access to _all_ the internal
    /// members
    std::mutex mutex;
    /// The daemon thread will block and wait on this variable when there
    /// isn't any work to do
    std::condition_variable condition_variable;

    /// A list of available connections to use as authentication providers
    std::vector<Connection*> connections;

    /**
     * All of the various tasks enqueue their SASL request in this queue
     * to allow the authentication provider thread to inject them into
     * the worker thread (to avoid a possible deadlock)
     */
    std::queue<AuthnAuthzServiceTask*> incomingRequests;

    /**
     * We need to pass the response information from one of the frontend
     * thread back to the sasl task, and we'd like to use the same
     * logic when we're terminating the connections.
     */
    struct AuthResponse {
        AuthResponse(uint32_t opaque, std::string payload)
            : opaque(opaque),
              status(cb::mcbp::Status::Etmpfail),
              payload(std::move(payload)) {
        }
        AuthResponse(uint32_t opaque,
                     cb::mcbp::Status status,
                     cb::const_byte_buffer value)
            : opaque(opaque),
              status(status),
              payload(reinterpret_cast<const char*>(value.data()),
                      value.size()) {
        }
        uint32_t opaque;
        cb::mcbp::Status status;
        std::string payload;
    };

    /**
     * All of the various responses is stored within this queue to
     * be handled by the daemon thread
     */
    std::queue<std::unique_ptr<AuthResponse>> incommingResponse;

    std::vector<Connection*> pendingRemoveConnection;

    class ActiveUsers {
    public:
        void login(const std::string& user);

        void logoff(const std::string& user);

        nlohmann::json to_json() const;

    private:
        mutable std::mutex mutex;
        std::unordered_map<std::string, uint32_t> users;
    } activeUsers;

    /**
     * The interval we'll push the current active users to the external
     * authentication service.
     *
     * The list can't be considered as "absolute" as memcached is a
     * highly multithreaded application and we may have disconnects
     * happening in multiple threads at the same time and we might
     * have login messages waiting to acquire the lock for the map.
     * The intention with the list is that we'll poll the users from
     * LDAP to check if the group membership has changed since the last
     * time we checked. Given that LDAP is an external system and it
     * can't push change notifications to our system our guarantee
     * is that the change is reflected in memcached at within 2 times
     * of the interval we push these users.
     *
     * We don't need microseconds resolution "in production", but
     * we don't want to have our unit tests wait multiple seconds
     * for this message to be sent
     */
    std::atomic<std::chrono::microseconds> activeUsersPushInterval{
            std::chrono::minutes(5)};

    /**
     * The time point we last sent the list of active users to the auth
     * provider
     */
    std::chrono::steady_clock::time_point activeUsersLastSent;

    /**
     * It should be possible for the authentication provider to
     * invalidate the entire cache, but we can't simply drop the
     * current cache as that would cause all of the connected clients
     * to be disconnected. Instead the authentication provider may
     * tell us to start requesting a new RBAC entry if the cached
     * one is older than a given time point. Combined with the logic
     * that we'll push all of the connected users the authentication
     * provider can make sure that all of the connections use the
     * correct RBAC definition. Ideally we would have stored this
     * as a std::chrono::steady_clock::TimePoint, but that don't
     * play well with std::atomic, so we're storing the raw
     * number of seconds instead.
     */
    std::atomic<uint64_t> rbacCacheEpoch{{}};
};

extern std::unique_ptr<ExternalAuthManagerThread> externalAuthManager;


#pragma once

#include "AsyncSystem.h"
#include "IAssetRequest.h"
#include "Library.h"

#include <gsl/span>

#include <cstddef>
#include <memory>
#include <string>
#include <vector>

namespace CesiumAsync {
class AsyncSystem;

/**
 * @brief Provides asynchronous access to assets, usually files downloaded via
 * HTTP.
 */
class CESIUMASYNC_API IAssetAccessor {
public:
  /**
   * @brief An HTTP header represented as a key/value pair.
   */
  typedef std::pair<std::string, std::string> THeader;

  virtual ~IAssetAccessor() = default;

  /**
   * @brief Starts a new request for the asset with the given URL.
   * The request proceeds asynchronously without blocking the calling thread.
   *
   * @param asyncSystem The async system used to do work in threads.
   * @param url The URL of the asset.
   * @param headers The headers to include in the request.
   * @return The in-progress asset request.
   */
  virtual CesiumAsync::Future<std::shared_ptr<IAssetRequest>> requestAsset(
      const AsyncSystem& asyncSystem,
      const std::string& url,
      const std::vector<THeader>& headers = {}) = 0;

  /**
   * @brief Starts a new POST request to the given URL.
   *
   * The request proceeds asynchronously without blocking the calling thread.
   *
   * @param asyncSystem The async system used to do work in threads.
   * @param url The URL of the asset.
   * @param headers The headers to include in the request.
   * @param contentPayload The payload data of the POST.
   * @return The in-progress asset request.
   */
  virtual CesiumAsync::Future<std::shared_ptr<IAssetRequest>> post(
      const AsyncSystem& asyncSystem,
      const std::string& url,
      const std::vector<THeader>& headers = std::vector<THeader>(),
      const gsl::span<const std::byte>& contentPayload = {}) = 0;

  /**
   * @brief Ticks the asset accessor system while the main thread is blocked.
   *
   * If the asset accessor is not dependent on the main thread to
   * dispatch requests, this method does not need to do anything.
   */
  virtual void tick() noexcept = 0;
};

} // namespace CesiumAsync


#ifndef STDAFX__H
#define STDAFX__H

#include <SDKDDKVer.h>

#if !defined(_STL_EXTRA_DISABLED_WARNINGS)
#define _STL_EXTRA_DISABLED_WARNINGS 4061 4324 4365 4514 4571 4582 4583 4623 4625 4626 4710 4774 4820 4987 5026 5027 5039
#endif

#if !defined(_SCL_SECURE_NO_WARNINGS)
#define _SCL_SECURE_NO_WARNINGS 1
#endif

#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS 1
#endif

#if !defined(_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING)
#define _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING 1
#endif

#define STRICT
#define NOMINMAX

#pragma warning(disable: 4668) // warning C4668: '%s' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
#pragma warning(disable: 4710) // warning C4710: '%s': function not inlined
#pragma warning(disable: 4711) // warning C4711: function '%s' selected for automatic inline expansion
#pragma warning(disable: 4820) // warning C4820: '%s': '%d' bytes padding added after data member '%s'

#pragma warning(push)
#pragma warning(disable: 5039) // warning C5039: '%s': pointer or reference to potentially throwing function passed to extern C function under -EHc. Undefined behavior may occur if this function throws an exception.
#include <Windows.h>
#pragma warning(pop)

#pragma warning(push)
#pragma warning(disable: 4005) // warning C4005: '%s': macro redefinition
#include <Winternl.h>
#include <ntstatus.h>
#pragma warning(pop)

// disable for everything
#pragma warning(disable: 4061) // warning C4061: enumerator '%s' in switch of enum '%s' is not explicitly handled by a case label
#pragma warning(disable: 4324) // warning C4234: structure was padded due to alignment specifier
#pragma warning(disable: 4514) // warning C4514: '%s': unreferenced inline function has been removed
#pragma warning(disable: 4623) // warning C4623: '%s': default constructor was implicitly defined as deleted
#pragma warning(disable: 4625) // warning C4625: '%s': copy constructor was implicitly defined as deleted
#pragma warning(disable: 4626) // warning C4626: '%s': assignment operator was implicitly defined as deleted
#pragma warning(disable: 4710) // warning C4710: '%s': function not inlined
#pragma warning(disable: 4820) // warning C4820: '%s': '%d' bytes padding added after data member '%s'
#pragma warning(disable: 5026) // warning C5026: '%s': move constructor was implicitly defined as deleted
#pragma warning(disable: 5027) // warning C5027: '%s': move assignment operator was implicitly defined as deleted

#pragma warning(disable: 26412) // warning C26412: Do not dereference an invalid pointer (lifetimes rule 1). 'return of %s' was invalidated at line %d by 'no initialization'.
#pragma warning(disable: 26426) // warning C26426: Global initializer calls a non-constexpr function '%s' (i.22: http://go.microsoft.com/fwlink/?linkid=853919).
#pragma warning(disable: 26481) // warning C26481: Don't use pointer arithmetic. Use span instead. (bounds.1: http://go.microsoft.com/fwlink/p/?LinkID=620413)
#pragma warning(disable: 26482) // warning C26482: Only index into arrays using constant expressions (bounds.2: http://go.microsoft.com/fwlink/p/?LinkID=620414).
#pragma warning(disable: 26485) // warning C26485: Expression '%s::`vbtable'': No array to pointer decay. (bounds.3: http://go.microsoft.com/fwlink/p/?LinkID=620415)
#pragma warning(disable: 26490) // warning C26490: Don't use reinterpret_cast. (type.1: http://go.microsoft.com/fwlink/p/?LinkID=620417)
#pragma warning(disable: 26499) // warning C26499: Could not find any lifetime tracking information for '%s'

// disable for standard headers
#pragma warning(push)
#pragma warning(disable: 5039) // warning C5039: '%s': pointer or reference to potentially throwing function passed to extern C function under -EHc. Undefined behavior may occur if this function throws an exception.

#pragma warning(disable: 26400) // warning C26400: Do not assign the result of an allocation or a function call with an owner<T> return value to a raw pointer, use owner<T> instead. (i.11 http://go.microsoft.com/fwlink/?linkid=845474)
#pragma warning(disable: 26401) // warning C26401: Do not delete a raw pointer that is not an owner<T>. (i.11: http://go.microsoft.com/fwlink/?linkid=845474)
#pragma warning(disable: 26408) // warning C26408: Avoid malloc() and free(), prefer the nothrow version of new with delete. (r.10 http://go.microsoft.com/fwlink/?linkid=845483)
#pragma warning(disable: 26409) // warning C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead. (r.11 http://go.microsoft.com/fwlink/?linkid=845485)
#pragma warning(disable: 26411) // warning C26411: The parameter '%s' is a reference to unique pointer and it is never reassigned or reset, use T* or T& instead. (r.33 http://go.microsoft.com/fwlink/?linkid=845479)
#pragma warning(disable: 26412) // warning C26412: Do not dereference an invalid pointer (lifetimes rule 1). 'return of %s' was invalidated at line %d by 'end of function scope (local lifetimes end)'.
#pragma warning(disable: 26413) // warning C26413: Do not dereference nullptr (lifetimes rule 2). 'nullptr' was pointed to nullptr at line %d.
#pragma warning(disable: 26423) // warning C26423: The allocation was not directly assigned to an owner.
#pragma warning(disable: 26424) // warning C26424: Failing to delete or assign ownership of allocation at line %d.
#pragma warning(disable: 26425) // warning C26425: Assigning '%s' to a static variable.
#pragma warning(disable: 26461) // warning C26461: The reference argument '%s' for function %s can be marked as const. (con.3: https://go.microsoft.com/fwlink/p/?LinkID=786684)
#pragma warning(disable: 26471) // warning C26471: Don't use reinterpret_cast. A cast from void* can use static_cast. (type.1: http://go.microsoft.com/fwlink/p/?LinkID=620417).
#pragma warning(disable: 26481) // warning C26481: Don't use pointer arithmetic. Use span instead. (bounds.1: http://go.microsoft.com/fwlink/p/?LinkID=620413)
#pragma warning(disable: 26482) // warning C26482: Only index into arrays using constant expressions. (bounds.2: http://go.microsoft.com/fwlink/p/?LinkID=620414)
#pragma warning(disable: 26490) // warning C26490: Don't use reinterpret_cast. (type.1: http://go.microsoft.com/fwlink/p/?LinkID=620417)
#pragma warning(disable: 26493) // warning C26493: Don't use C-style casts that would perform a static_cast downcast, const_cast, or reinterpret_cast. (type.4: http://go.microsoft.com/fwlink/p/?LinkID=620420)
#pragma warning(disable: 26494) // warning C26494: Variable '%s' is uninitialized. Always initialize an object. (type.5: http://go.microsoft.com/fwlink/p/?LinkID=620421)
#pragma warning(disable: 26495) // warning C26495: Variable '%s' is uninitialized. Always initialize a member variable. (type.6: http://go.microsoft.com/fwlink/p/?LinkID=620422)
#pragma warning(disable: 26496) // warning C26496: Variable '%s' is assigned only once, mark it as const. (con.4: https://go.microsoft.com/fwlink/p/?LinkID=784969)
#pragma warning(disable: 26497) // warning C26497: This function %s could be marked constexpr if compile-time evaluation is desired. (f.4: https://go.microsoft.com/fwlink/p/?LinkID=784970)

#include <cstddef>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <type_traits>
#include <utility>
#include <memory>
#include <tuple>
#include <thread>
#include <cstdlib>

// disable additionally for third-party libraries
#pragma warning(push)
#pragma warning(disable: 4365) // warning C4365: '%s': conversion from '%s' to '%s', signed/unsigned mismatch
#pragma warning(disable: 4371) // warning C4371: '%s': layout of class may have changed from a previous version of the compiler due to better packing of member '%s'
#pragma warning(disable: 4619) // warning C4619: #pragma warning: there is no warning number '%d'
#pragma warning(disable: 5031) // warning C5031: #pragma warning(pop): likely mismatch, popping warning state pushed in different file
#pragma warning(disable: 26429) // warning C26429: Symbol '%s' is never tested for nullness, it can be marked as not_null (f.23: http://go.microsoft.com/fwlink/?linkid=853921).
#pragma warning(disable: 26432) // warning C26432: If you define or delete any default operation in the type '%s', define or delete them all (c.21: http://go.microsoft.com/fwlink/?linkid=853922).
#pragma warning(disable: 26434) // warning C26434: Function '%s' hides a non-virtual function '%s' (c.128: http://go.microsoft.com/fwlink/?linkid=853923).
#pragma warning(disable: 26439) // warning C26439: This kind of function may not throw. Declare it 'noexcept' (f.6: http://go.microsoft.com/fwlink/?linkid=853927).
#pragma warning(disable: 26440) // warning C26440: Function '%s' can be declared 'noexcept' (f.6: http://go.microsoft.com/fwlink/?linkid=853927).
#pragma warning(disable: 26472) // warning C26472: Don't use a static_cast for arithmetic conversions. Use brace initialization, gsl::narrow_cast or gsl::narow (type.1: http://go.microsoft.com/fwlink/p/?LinkID=620417).

#ifndef BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE
#define BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE
#endif

#include <gsl/gsl>

#include <fmt/format.h>

#pragma warning(pop)

#pragma warning(pop)

#endif


// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include <limits>
#include <cassert>
#include <chrono>
#include <vector>
#include <map>
#include <set>
#include <numeric>

#include <wrl/client.h>
#include <wrl/implements.h>

#include <wil/wrl.h>
#include <wil/result.h>

#include <gsl/gsl>


#pragma once

#include <Runtime/Runtime.h>
#include <napi/napi.h>
#include <memory>
#include <gsl/gsl>

namespace babylon
{
    class ScriptHost final
    {
    public:
        explicit ScriptHost(RuntimeImpl&);
        ScriptHost(const ScriptHost&) = delete;
        ~ScriptHost();

        void RunScript(gsl::czstring<> script, gsl::czstring<> url);

        Napi::Env& Env();

    private:
        class Impl;
        std::unique_ptr<Impl> m_impl;
    };
}