#pragma once #include "sad_DetectedServer.hpp" #include "spit_message.hpp" #include "spit_object.hpp" #include "spit_player.hpp" #include "spit_processor.hpp" #include "spit_repo.hpp" #include "spit_socket.hpp" #include "spit_type.hpp" #include #include #include using namespace std; namespace spit { class SClient : ISadClient { public: using Callbacks = SProcessor::Callbacks; using ProjUpdate = SProcessor::ProjUpdate; using ServerEvent = SProcessor::ServerEvent; using ObjectEvent = SProcessor::ObjectEvent; using Connection = SProcessor::Connection; using PlayerType = SPlayer::PTypes; using ValueFlags = SPlayer::VFlags; SClient(string name, string projName, ISocket &socket, Callbacks calls); virtual ~SClient(); private: Callbacks mCallbacks; fos::TaskT *mThreadReceive{}; fos::TaskT *mThreadProcess{}; bool mStopReceiveMessages{}; Connection mConnectionStatus{Connection::None}; bool mDisconnectedByServer{}; // flag true = when server disconnects SProcessor mProcessor; string mClientProjectName; uint8_t mMessageNumberSend{1}; int mMessageNumberReceived{-1}; // set to -1 because the first received message will set the number (1..255) vector> mOvertakingMessages; // Server's info filled by parseConnectAnswer string mServerID{}; string mServerName{}; string mServerComputerName{}; int mServerStepTime{-1}; public: /** The ID of the client.
Every client instance should set an unique id*/ string getID() { return mProcessor.getID(); } /** The name of the client, should be set by the user app*/ string getName() { return mProcessor.getName(); } /** The name of the client's host computer*/ string getComputerName() { return mProcessor.getComputerName(); } void setClientProjectName(string clientProjectName) { mClientProjectName = clientProjectName; } string getClientProjectName() { return mClientProjectName; } // connected Server Infos /** The ID of the connected SPITServer*/ string getServerID() { return mServerID; } /** The host computername of the connected SPITServer*/ string getServerComputerName() { return mServerComputerName; } /** The name of the connected SPITServer*/ string getServerName() { return mServerName; } /** Expected Refreah Rate of the connectd SPITServer.
* When the server plays objects, it will do so at discrete time steps.
* Play events will take place in these time steps.. */ int getServerStepTime() { return mServerStepTime; } /** Should be called when the client wants to close his project*/ void clientProjectClose(); /** * Should be called whenever the client has a project loaded */ void clientProjectLoaded(); void setActionType(string spitypeID, bool actionAssigned) { mProcessor.setActionType(spitypeID, actionAssigned); } void setActionObject(string objectID, bool actionAssigned) { mProcessor.setActionObject(objectID, actionAssigned); } //--------------- SPITMessage --------------- private: bool startReceiveSPITMessages(); void stopReceiveSPITMessages(); static void receiveSpitMessage(SClient &rM); static void processSpitMessage(SClient &rM); // Reconnect to the server when connection is lost see eventConnectionStatus and eventServerDetected bool _doReconnect{}; // true = on eventServerDetected connect to the server identified by mServerID public: int sendMessage(Message::OPPart &spitMessageOPPart); //--------------- ServerAutoDetection SAD --------------- public: /** Starts the autodetection of SPITServers in the local network. If a connection is tried, the autodetection should be stopped before.*/ void startServerAutoDetect(); /** Stops the autodetection of SPITServers in the local network*/ void stopServerAutoDetect(); /** Called every time a new SPITServer is detetced in the local network */ void eventServerDetected(SadDetectedServer &server); /** Called every time a prior detected SPITServer is is no longer found.*/ void eventServerLost(SadDetectedServer &server); void eventServerChanged(SadDetectedServer &server); //--------------- Connection --------------- public: /** * Tries a connection to the SPITServer * @param p_ServerIP ip address of the SPITServer * @param p_ServerPort port of the SPITServer * @param p_ClientIP IP of the client * @param p_ClientPort if "0" any free port will be used * @param p_LoginName maybe some SPITServer need a login - liveSHOWsoftware will not. * @param p_LoginPassword maybe some SPITServer need a login - liveSHOWsoftware will not * @return true = the connection try is ok, SPITServer will answer with COnnectAnswer and an eventConnectionStatus will occur.
* false = something is going wrong. (client could not bind) */ bool connect(string serverIP, string serverPort, string clientIP, string clientPort, string loginName = "", string loginPassword = ""); /** * Terminates the connection to the SPITServer. */ void disconnect(); private: void disconnectInternal(Connection cause); void resetMessageNumberReceived(); void parseMessage(unique_ptr message); void checkParseMessage(unique_ptr message); void addOvertakingMessage(unique_ptr message); void parseConnectAnswer(Message::ConnectAnswer &message); void parseDisconnect(Message::Disconnect &message); void parseWatchdog(Message::Watchdog &message); void parseWatchdogAnswer(Message::WatchdogAnswer &message); public: /** Used internally*/ void sendWatchdog(); /** Used internally. When the connection to the SPITServer is lost an eventConnectionStatus will occur*/ void eventWatchdogLost(); //--------------- SPIT Project --------------- /** Returns the SPITServer's project ID - may be the same as the project's name*/ string getServerProjectID() { return mProcessor.getServerProjectID(); } /** Returns the SPITServer's project name*/ string getServerProjectName() { return mProcessor.getServerProjectName(); } /** Returns frame rate per second. This is the time resolution in which the server transmits time data. The unit of time data is always frames.*/ int getServerFramesPerSecond() { return mProcessor.getServerFramesPerSecond(); } public: static void sendProject(SClient *p_PtrSClient); // --------------- SPIT Types --------------- public: /** * Creates a fixed SPITType for application actions that are always present and project independent.
* Fixed SPIT types cannot be changed or deleted by the server.
* These SPITTypes will be automatically added to the SPITType-List and sended to the server. * @param p_ID an unique of the SPITType, these are always the same per client approach. Different client approaches should use different ids. * @param p_GroupName a name which groups the actions/SPITTypes * @param p_Name the name of the Action/SPITType * @param p_DefaultDelay maybe there is an default delay until the action starts, this is only used for graphical representations, 0 is allowd * @param p_DefaultDuration maybe the action has a default duration, this is only used for graphical representations, 0 is allowd * @return the pointer to the new SPITType. */ SType *createTypeFixed(string iD, string groupName, string name, uint64_t defaultDelay, uint64_t defaultDuration); public: bool changeType(SType *spitType) { return mProcessor.changeType(spitType); } int removeType(string spitypeID) { return mProcessor.removeType(spitypeID); } public: public: bool changeObject(SObject *sObject) { return mProcessor.changeObject(sObject); } void sendRemoteObject(string objectID, int valuePpm = 0, char valueFlag = 0x00) { mProcessor.sendRemoteObject(objectID, valuePpm, valueFlag); } private: static void processSocketTask(SClient &instance); fos::TaskT *sThread{}; bool mAbortSearch{}; bool sAnswered{}; static fos::Semaphore sStartSad; ISocket &mSocket; void answerWatchdog() { sAnswered = true; } }; } // namespace spit