Program Listing for File Server.h

Program Listing for File Server.h#

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

/*
*Copyright(c)2024-2026KaranaDynamicsPtyLtd.Allrightsreserved.
*
*NOTICETOUSER:
*
*Thissourcecodeand/ordocumentation(the"LicensedMaterials")is
*theconfidentialandproprietaryinformationofKaranaDynamicsInc.
*UseoftheseLicensedMaterialsisgovernedbythetermsandconditions
*ofaseparatesoftwarelicenseagreementbetweenKaranaDynamicsandthe
*Licensee("LicenseAgreement").Unlessexpresslypermittedunderthat
*agreement,anyreproduction,modification,distribution,ordisclosure
*oftheLicensedMaterials,inwholeorinpart,toanythirdparty
*withoutthepriorwrittenconsentofKaranaDynamicsisstrictlyprohibited.
*
*THELICENSEDMATERIALSAREPROVIDED"ASIS"WITHOUTWARRANTYOFANYKIND.
*KARANADYNAMICSDISCLAIMSALLWARRANTIES,EXPRESSORIMPLIED,INCLUDING
*BUTNOTLIMITEDTOWARRANTIESOFMERCHANTABILITY,NON-INFRINGEMENT,AND
*FITNESSFORAPARTICULARPURPOSE.
*
*INNOEVENTSHALLKARANADYNAMICSBELIABLEFORANYDAMAGESWHATSOEVER,
*INCLUDINGBUTNOTLIMITEDTOLOSSOFPROFITS,DATA,ORUSE,EVENIF
*ADVISEDOFTHEPOSSIBILITYOFSUCHDAMAGES,WHETHERINCONTRACT,TORT,
*OROTHERWISEARISINGOUTOFORINCONNECTIONWITHTHELICENSEDMATERIALS.
*
*U.S.GovernmentEndUsers:TheLicensedMaterialsarea"commercialitem"
*asdefinedat48C.F.R.2.101,andareprovidedtotheU.S.Government
*onlyasacommercialenditemunderthetermsofthislicense.
*
*AnyuseoftheLicensedMaterialsinindividualorcommercialsoftwaremust
*include,intheuserdocumentationandinternalsourcecodecomments,
*thisNotice,Disclaimer,andU.S.GovernmentUseProvision.
*/


#pragmaonce
#include<condition_variable>
#include<cstdlib>
#include<filesystem>
#include<functional>
#include<future>
#include<memory>
#include<mutex>
#include<thread>
#include<type_traits>

#include<boost/asio.hpp>
#include<boost/beast/core.hpp>
#include<boost/beast/websocket.hpp>

namespaceKarana::WebUI{
structLocalClientOptions{
boolsilent=true;
boolsandbox=false;
};

classConnection{
public:
usingconn_t=boost::beast::websocket::stream<boost::beast::tcp_stream>;

usinghandler_t=std::function<void(Connection&)>;

usingmsg_handler_t=std::function<void(Connection&,constuint8_t*data,size_tsize)>;

Connection(std::unique_ptr<conn_t>conn,msg_handler_ton_message,handler_ton_close);

~Connection();

voidsend(constuint8_t*data,size_tlen);

voidonMessage(msg_handler_ton_message);

voidonClose(handler_ton_close);

private:
void_doRead();

std::unique_ptr<conn_t>_conn;
msg_handler_t_on_message;
handler_t_on_close;
boost::beast::flat_buffer_buffer;
};

classServer{
public:
Server(unsignedshortport=29523);

~Server();

template<classT,classR=typenamestd::invoke_result<T>::type>
std::future<R>callAsync(constT&callable){
std::promise<R>promise;
std::future<R>future=promise.get_future();
boost::asio::post(_io_context,[promise=std::move(promise),callable]()mutable{
ifconstexpr(std::is_void_v<R>){
callable();
promise.set_value();
}else{
promise.set_value(callable());
}
});
returnfuture;
}

template<classT,classR=typenamestd::invoke_result<T>::type>
RcallSync(constT&callable){
std::promise<R>promise;
std::future<R>future=promise.get_future();
boost::asio::post(_io_context,[promise=std::move(promise),callable]()mutable{
ifconstexpr(std::is_void_v<R>){
callable();
promise.set_value();
}else{
promise.set_value(callable());
}
});
ifconstexpr(std::is_void_v<R>){
future.get();
return;
}else{
returnfuture.get();
}
}

voidsync();

std::stringguessUrl()const;

unsignedshortport()const;

boolonThread();

voidbroadcast(constuint8_t*data,size_tlen);

voidsendOne(constuint8_t*data,size_tlen);

voidonConnect(Connection::handler_ton_connect);

voidonMessage(Connection::msg_handler_ton_message);

voidonClose(Connection::handler_ton_close);

voidwaitForClients(intclients=1,floattimeout=0);

//Launchaninstanceoftheelectronfrontendasa
//subprocessandautomaticallyconnect.Thefrontend's
//lifetimewillbemanagedbytheserver.

voidlaunchLocalClient(constLocalClientOptions&options=LocalClientOptions{});

staticboolcanFindLocalClientExecutable();

voidcloseLocalClients();

voidprintConnectionInfo();

private:
//Helpertogetthecontextsofatextfileasastring
std::string_loadText(conststd::string&path);

//Helpertohandlearequestbyservingastaticfile
void_serveFile(boost::beast::tcp_stream&stream,
constboost::beast::http::request<boost::beast::http::string_body>&req,
conststd::string&path,
conststd::string&content_type);

//Helpertosimplysenda200okresponse
void_sendOk(boost::beast::tcp_stream&stream,
constboost::beast::http::request<boost::beast::http::string_body>&req);

//Helpertohandlearequestbysendingabadrequestresponse
void_badRequest(boost::beast::tcp_stream&stream,
constboost::beast::http::request<boost::beast::http::string_body>&req);

//Helpertohandlearequestbyupgradingtoapersistentwebsocketconnection
void
_upgradeWebsocket(boost::beast::tcp_stream&stream,
constboost::beast::http::request<boost::beast::http::string_body>&req);

//Helpertohandlehttprequests
void_handleRequest(boost::asio::ip::tcp::socketsocket);

//Helpertoasynchronouslyaccepthttprequests
void_doAccept();

private:
boost::asio::io_context_io_context;
Connection::handler_t_on_connect;
Connection::msg_handler_t_on_message;
Connection::handler_t_on_close;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>_work_guard;
boost::asio::ip::tcp::acceptor_acceptor;
constunsignedshort_port;
std::thread_thread;
std::vector<std::unique_ptr<Connection>>_connections;
std::filesystem::path_base_path;
std::unique_ptr<classClientManager>_client_manager;

std::mutex_client_count_mutex;
std::condition_variable_client_count_cv;
int_client_count=0;
};
}//namespaceKarana::WebUI