Program Listing for File Router.h

Program Listing for File Router.h#

Return to documentation for file (include/Karana/WebUI/Router.h)

/*
 * Copyright (c) 2024-2026 Karana Dynamics Pty Ltd. All rights reserved.
 *
 * NOTICE TO USER:
 *
 * This source code and/or documentation (the "Licensed Materials") is
 * the confidential and proprietary information of Karana Dynamics Inc.
 * Use of these Licensed Materials is governed by the terms and conditions
 * of a separate software license agreement between Karana Dynamics and the
 * Licensee ("License Agreement"). Unless expressly permitted under that
 * agreement, any reproduction, modification, distribution, or disclosure
 * of the Licensed Materials, in whole or in part, to any third party
 * without the prior written consent of Karana Dynamics is strictly prohibited.
 *
 * THE LICENSED MATERIALS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
 * KARANA DYNAMICS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL KARANA DYNAMICS BE LIABLE FOR ANY DAMAGES WHATSOEVER,
 * INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR USE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WHETHER IN CONTRACT, TORT,
 * OR OTHERWISE ARISING OUT OF OR IN CONNECTION WITH THE LICENSED MATERIALS.
 *
 * U.S. Government End Users: The Licensed Materials are a "commercial item"
 * as defined at 48 C.F.R. 2.101, and are provided to the U.S. Government
 * only as a commercial end item under the terms of this license.
 *
 * Any use of the Licensed Materials in individual or commercial software must
 * include, in the user documentation and internal source code comments,
 * this Notice, Disclaimer, and U.S. Government Use Provision.
 */

#pragma once
#include "Karana/KCore/SharedPointer.h"
#include "Karana/WebUI/HttpWsServer.h"

namespace Karana::WebUI {
    /**
     * @class ContentSource
     * @brief Helper for content coming from a file or in-memory string
     *
     * This class has implicit conversions from the standard string and
     * filepath types for convenience.
     */
    class ContentSource {
      public:
        /**
         * @brief Constructor for an empty ContentSource
         */
        ContentSource() = default;

        /**
         * @brief Copy Constructor for ContentSource
         * @param other - the ContentSource to copy
         */
        ContentSource(const ContentSource &other);

        /**
         * @brief Move Constructor for ContentSource
         * @param other - the ContentSource to move
         */
        ContentSource(ContentSource &&other) noexcept;

        /**
         * @brief ContentSource std::filesystem::path conversion constructor
         * @param source - path to the file containing the content
         */
        ContentSource(std::filesystem::path source);

        /**
         * @brief ContentSource std::string_view conversion constructor
         * @param source - string containing a filepath or content
         */
        ContentSource(std::string_view source);

        /**
         * @brief ContentSource char* conversion constructor
         * @param source - string containing a filepath or content
         */
        ContentSource(const char *source);

        /**
         * @brief ContentSource std::string conversion constructor
         * @param source - string containing a filepath or content
         */
        ContentSource(const std::string &source);

        /**
         * @brief ContentSource rvalue std::string conversion constructor
         * @param source - string containing a filepath or content
         */
        ContentSource(std::string &&source);

        /**
         * @brief Get the given string or file content
         * @return The content
         */
        std::string_view getContent() const;

        /**
         * @brief Whether there is any content
         * @return Whether there is any content
         */
        operator bool() const;

      private:
        std::string _content_buffer = {};
        std::string_view _content_view = {};
    };

    /**
     * @class Router
     * @brief Manager for multiplexing messages on a websocket
     *
     * See \sref{webui_sec} for more discussion on WebUI.
     */
    class Router {
      public:
        /**
         * @brief Router constructor.
         * @param server - the websocket server.
         */
        Router(const Karana::Core::ks_ptr<HttpWsServer> &server);

        Router(const Router &) = delete;
        Router &operator=(const Router &) = delete;

        /**
         * @brief Router destructor.
         */
        virtual ~Router();

        /**
         * @brief Create and track a new channel.
         * @param esm - JavaScript esm module with setup callback.
         * @param css - CSS to ensure is added to the page.
         * @param init_msg - Static message to send to new channel frontends.
         * @returns A shared porter to the channel.
         */
        Karana::Core::ks_ptr<class Channel> channel(const ContentSource &esm,
                                                    const ContentSource &css = {},
                                                    std::string_view init_msg = {});

      private:
        std::unique_ptr<struct RouterState> _state;
    };

    /**
     * @class Channel
     * @brief A multiplexed line of communication on a websocket.
     *
     * See \sref{webui_sec} for more discussion on WebUI.
     */
    class Channel {
      public:
        Channel(const Channel &) = delete;
        Channel &operator=(const Channel &) = delete;

        /**
         * @brief Router destructor.
         */
        virtual ~Channel();

        /**
         * @brief A universally unique identifier for the channel.
         * @returns The uuid
         */
        std::string_view uuid() const;

        /**
         * @brief Send a message on this channel to all clients
         * @param msg - The message to send
         */
        void broadcastMessage(std::string_view msg);

        /**
         * @brief Send a message on this channel to a specific client
         * @param msg - The message to send
         * @param client_id - The id for the client to send to
         */
        void sendMessage(std::string_view msg, int client_id);

        /**
         * @brief Set a function called on websocket client connection
         * @param callback - The callback function
         */
        void setOnConnect(std::function<void(int)> callback);

        /**
         * @brief Set a function called on receiving a websocket message
         * @param callback - The callback function
         */
        void setOnMessage(std::function<void(std::string_view, int)> callback);

        /**
         * @brief Set a function called on websocket client disconnect
         * @param callback - The callback function
         */
        void setOnDisconnect(std::function<void(int)> callback);

        /**
         * @brief Submit a function to be called in the event loop
         * @param callback - The callback function
         */
        void defer(std::function<void()> callback);

        /**
         * @brief Block for deferred calls
         *
         * This places a deferred callback on the event loop and waits
         * for the callback to be called, ensuring any prior callbacks
         * have also been called. This does _not_ wait for the event
         * loop to reach quiescence.
         */
        void sync();

      private:
        friend class Router;
        /**
         * @brief Channel constructor.
         * @param uuid - the channel's uuid
         * @param server - the websocket server.
         * @param establish_msg - message to establish on new frontends.
         *
         * A channel must be constructed by calling Router::channel
         */
        explicit Channel(std::string_view uuid,
                         const Karana::Core::ks_ptr<HttpWsServer> &server,
                         std::string_view establish_msg);

        std::unique_ptr<struct ChannelState> _state;
    };

} // namespace Karana::WebUI