/* Copyright (C) 2013 * swift Project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, * or distributed except according to the terms contained in the LICENSE file. */ //! \file #ifndef BLACKCORE_NETWORK_H #define BLACKCORE_NETWORK_H #include "blackcoreexport.h" #include "blackmisc/simulation/ownaircraftprovider.h" #include "blackmisc/simulation/remoteaircraftprovider.h" #include "blackmisc/simulation/simulationenvironmentprovider.h" #include "blackmisc/simulation/simulatorplugininfo.h" #include "blackmisc/simulation/simulatedaircraft.h" #include "blackmisc/network/rawfsdmessage.h" #include "blackmisc/network/serverlist.h" #include "blackmisc/network/clientprovider.h" #include "blackmisc/network/ecosystemprovider.h" #include "blackmisc/network/clientlist.h" #include "blackmisc/network/textmessagelist.h" #include "blackmisc/aviation/informationmessage.h" #include "blackmisc/aviation/flightplan.h" #include "blackmisc/aviation/callsignset.h" #include "blackmisc/geo/coordinategeodetic.h" #include "blackmisc/pq/frequency.h" #include "blackmisc/pq/length.h" #include "blackmisc/pq/time.h" #include #include #include #include #include #include #include namespace BlackCore { /*! * Interface for a connection to a multi-user flight simulation and ATC network. * * The connection can be in one of three essential states: disconnected, connecting, and * connected. (There is a fourth state, disconnected due to error, which is a substate of * disconnected.) Some slots may only be called when connected, and some may only be called * when disconnected; there is a naming convention to highlight this fact using prefixes: * "preset" slots are only callable when disconnected, "send" slots are only callable when * connected, and "set" slots are callable in any state. * * Slots with the word "query" in their names are handled asynchronously, with one or more * "reply" signals being sent in response to each invokation of a query slot. * * \warning If an INetwork signal is connected to a slot, and that slot emits a signal * which is connected to an INetwork slot, then at least one of those connections * must be a Qt::QueuedConnection. */ class BLACKCORE_EXPORT INetwork : public QObject, public BlackMisc::Network::IEcosystemProvider, // provide info about used ecosystem public BlackMisc::Network::CClientAware, // network can set client information public BlackMisc::Simulation::COwnAircraftAware, // network vatlib consumes own aircraft data and sets ICAO/callsign data public BlackMisc::Simulation::CRemoteAircraftAware, // check if we really need to process network packets (e.g. parts) public BlackMisc::Simulation::CSimulationEnvironmentAware // allows to consume ground elevations { Q_OBJECT Q_INTERFACES(BlackMisc::Network::IEcosystemProvider) protected: //! Constructor INetwork( BlackMisc::Network::IClientProvider *clientProvider, BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider, BlackMisc::Simulation::IRemoteAircraftProvider *remoteAircraftProvider, QObject *parent = nullptr); public: //! Destructor virtual ~INetwork(); //! Underlying library info. virtual const QString &getLibraryInfo(bool detailed) const = 0; //! Login modes enum LoginMode { LoginNormal = 0, //!< Normal login LoginAsObserver, //!< Login as observer LoginStealth //!< Login stealth mode }; //! Status of the connection. enum ConnectionStatus { Disconnected = 0, //!< Not connected Disconnecting, //!< In transition to disconnected DisconnectedError, //!< Disconnected due to socket error DisconnectedFailed, //!< A connection was not established due to socket error DisconnectedLost, //!< Connection lost due to socket error Connecting, //!< Connection initiated but not established Connected //!< Connection established }; Q_ENUM(ConnectionStatus) //! Statistics enable functions @{ bool setStatisticsEnable(bool enabled) { m_statistics = enabled; return enabled; } bool isStatisticsEnabled() const { return m_statistics; } //! @} //! Increase the statistics value for given identifier @{ int increaseStatisticsValue(const QString &identifier, const QString &appendix = {}); int increaseStatisticsValue(const QString &identifier, int value); //! @} //! Clear the statistics void clearStatistics(); //! Text statistics QString getNetworkStatisticsAsText(bool reset, const QString &separator = "\n"); //! Convert a ConnectionStatus to a string. static QString connectionStatusToString(ConnectionStatus status) { const int index = staticMetaObject.indexOfEnumerator("ConnectionStatus"); const QMetaEnum metaEnum = staticMetaObject.enumerator(index); return metaEnum.valueToKey(status); } /*! * Returns true if the given ConnectionStatus represents an error state. */ static bool isErrorStatus(ConnectionStatus status) { return status == DisconnectedError; } /*! * Returns true if the given ConnectionStatus represents a pending state. */ static bool isPendingStatus(ConnectionStatus status) { return status == Disconnecting || status == Connecting; } /*! * Returns true if the given ConnectionStatus represents a disconnected state. */ static bool isDisconnectedStatus(ConnectionStatus status) { return status == Disconnected || status == DisconnectedError || status == DisconnectedFailed || status == DisconnectedLost; } /*! * Returns true if the given ConnectionStatus represents a connected state. */ static bool isConnectedStatus(ConnectionStatus status) { return status == Connected; } //////////////////////////////////////////////////////////////// //! \name Network slots //! @{ //////////////////////////////////////////////////////////////// /*! * Returns true if the current ConnectionStatus is a connected state. */ virtual bool isConnected() const = 0; /*! * Get preset server. */ virtual const BlackMisc::Network::CServer &getPresetServer() const = 0; /*! * Returns true if the current ConnectionStatus is in transition, e.g. connecting. */ virtual bool isPendingConnection() const = 0; /*! * Set the server which will be connected to. * \pre Network must be disconnected when calling this function. */ virtual void presetServer(const BlackMisc::Network::CServer &server) = 0; /*! * Set our own callsign before connecting. * \pre Network must be disconnected when calling this function. */ virtual void presetCallsign(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Set our own aircraft ICAO codes before connecting. * \pre Network must be disconnected when calling this function. */ virtual void presetIcaoCodes(const BlackMisc::Simulation::CSimulatedAircraft &ownAircraft) = 0; /*! * Select a login mode before connecting. * \pre Network must be disconnected when calling this function. */ virtual void presetLoginMode(BlackCore::INetwork::LoginMode mode) = 0; /*! * Set simulator info before connecting. * \pre Network must be disconnected when calling this function. */ virtual void presetSimulatorInfo(const BlackMisc::Simulation::CSimulatorPluginInfo &simInfo) = 0; /*! * Initiate a connection to the network server. * \pre Network must be disconnected when calling this function. * \post Connection status changes from Disconnected to either Connecting or DisconnectedError. */ virtual void initiateConnection() = 0; /*! * Ask the connection to the network server to terminate itself. * \pre It is not legal to call this function when already disconnected. * \post Connection status changes to Disconnected, but maybe not immediately. */ virtual void terminateConnection() = 0; /*! * Send a ping message to a user with a specific callsign. * \pre Network must be connected when calling this function. * \sa pongReceived */ virtual void sendPing(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send a message querying the real name of the user with a specific callsign. * \pre Network must be connected when calling this function. * \sa realNameReplyReceived */ virtual void sendRealNameQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send a message querying our own IP address as reported by the server. * \pre Network must be connected when calling this function. * \sa ipReplyReceived */ virtual void sendIpQuery() = 0; /*! * Send a message querying which server the user with a specific callsign is connected to. * \pre Network must be connected when calling this function. * \sa serverReplyReceived */ virtual void sendServerQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send one or more text messages. * \pre Network must be connected when calling this function. */ virtual void sendTextMessages(const BlackMisc::Network::CTextMessageList &messages) = 0; /*! * Send a wallop message. * \pre Network must be connected when calling this function. */ virtual void sendWallopMessage(const QString &message) = 0; //! @} //////////////////////////////////////////////////////////////// //! \name Custom packets //! @{ //////////////////////////////////////////////////////////////// /*! * Send a FSInn custom packet. * \details FSIPI(R) queries, some example data below: *
* index 0 .. 0/1 ??? * 1 .. MQT, GEC, DLH -> Airline ICAO, most of the time empty * 2 .. AIRCRAFT ICAO "B747" * 3 .. 10.64195 * 4 .. 1.06080: * 5 .. 5825.00000 * 6 .. 4.DD89CCB6.EC9BB7D7 * 7 .. 3-letter combined L2J * 8 .. Model string *
*/ //! @{ virtual void sendCustomFsinnQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; virtual void sendCustomFsinnReponse(const BlackMisc::Aviation::CCallsign &callsign) = 0; //! @} //! Broadcast an incremental aircraft config virtual void broadcastAircraftConfig(const QJsonObject &config) = 0; //! Query callsign for its current full aircraft config virtual void sendAircraftConfigQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; //! @} //////////////////////////////////////////////////////////////// //! \name ATC slots //! @{ //////////////////////////////////////////////////////////////// /*! * Send a message querying whether or not the user with a specific callsign is an ATC station. * \pre Network must be connected when calling this function. * \sa atcReplyReceived */ virtual void sendAtcQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send a message querying the ATIS for the ATC station with a specific callsign. * \pre Network must be connected when calling this function. * \sa atisReplyReceived * \sa atisVoiceRoomReplyReceived * \sa atisLogoffTimeReplyReceived */ virtual void sendAtisQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send a message to file a flight plan. * \pre Network must be connected when calling this function. */ virtual void sendFlightPlan(const BlackMisc::Aviation::CFlightPlan &flightPlan) = 0; /*! * Send a message querying our currently filed flight plan, which may have been amended by a controller. * \pre Network must be connected when calling this function. * \sa flightPlanReplyReceived */ virtual void sendFlightPlanQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; //! @} //////////////////////////////////////////////////////////////// //! \name Aircraft slots //! @{ //////////////////////////////////////////////////////////////// /*! * Send a message querying the capabilities of the client software of the user with a specific callsign. * \pre Network must be connected when calling this function. * \sa capabilitiesReplyReceived */ virtual void sendCapabilitiesQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send a message querying the ICAO codes of the aircraft of the user with a specific callsign. * \pre Network must be connected when calling this function. * \sa icaoCodesReplyReceived */ virtual void sendIcaoCodesQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send a message querying the COM frequency of the user with a specific callsign. * \pre Network must be connected when calling this function. * \sa frequencyReplyReceived */ virtual void sendFrequencyQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Send a user info query, which only shall be sent by supervisiors. Reply is received as * text message * \pre Network must be connected when calling this function. */ virtual void sendUserInfoQuery(const BlackMisc::Aviation::CCallsign &callsign) = 0; /*! * Set the group of callsigns receiving regular interim position updates. */ virtual void setInterimPositionReceivers(const BlackMisc::Aviation::CCallsignSet &receiver) = 0; /*! * Get the group of callsigns receiving regular interim position updates. */ virtual const BlackMisc::Aviation::CCallsignSet &getInterimPositionReceivers() const = 0; /*! * Add callsign receiving regular interim position updates. */ void addInterimPositionReceiver(const BlackMisc::Aviation::CCallsign &receiver) { BlackMisc::Aviation::CCallsignSet set = this->getInterimPositionReceivers(); if (set.contains(receiver)) { return; } // already in set set.push_back(receiver); this->setInterimPositionReceivers(set); } /*! * Remove callsign receiving regular interim position updates. */ void removeInterimPositionReceiver(const BlackMisc::Aviation::CCallsign &receiver) { BlackMisc::Aviation::CCallsignSet set = this->getInterimPositionReceivers(); if (!set.contains(receiver)) { return; } // nothing to remove set.remove(receiver); this->setInterimPositionReceivers(set); } //! @} //////////////////////////////////////////////////////////////// //! \name Weather slots //! @{ //////////////////////////////////////////////////////////////// /*! * Send a message querying the METAR for the airport with a specific ICAO code. * \pre Network must be connected when calling this function. * \sa metarReplyReceived */ virtual void sendMetarQuery(const BlackMisc::Aviation::CAirportIcaoCode &airportIcao) = 0; //! @} //! @} //////////////////////////////////////////////////////////////// //! \name Others //! @{ //////////////////////////////////////////////////////////////// //! Additional offset time @{ virtual qint64 getAdditionalOffsetTime() const = 0; virtual void setAdditionalOffsetTime(qint64 addOffset) = 0; //! @} signals: //! @} //////////////////////////////////////////////////////////////// //! \name ATC signals //! @{ //////////////////////////////////////////////////////////////// /*! * We received a notification of the state of an ATC station on the network. */ void atcPositionUpdate(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &freq, const BlackMisc::Geo::CCoordinateGeodetic &pos, const BlackMisc::PhysicalQuantities::CLength &range); /*! * We received a notification that an ATC station has disconnected from the network. */ void atcDisconnected(const BlackMisc::Aviation::CCallsign &callsign); /*! * We received a reply to one of our queries. * \sa sendAtcQuery */ void atcReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, bool isATC); /*! * We received a reply to one of our ATIS queries. * \sa sendAtisQuery */ void atisReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CInformationMessage &atis); /*! * We received a reply to one of our ATIS queries, containing the controller's voice room URL. * \sa sendAtisQuery */ void atisVoiceRoomReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &url); /*! * We received a reply to one of our ATIS queries, containing the controller's planned logoff time. * \sa sendAtisQuery */ void atisLogoffTimeReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &zuluTime); /*! * We received a reply to one of our flight plan queries, containing our up-to-date flight plan. * \sa sendFlightPlanQuery */ void flightPlanReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CFlightPlan &flightPlan); //! @} //////////////////////////////////////////////////////////////// //! \name Aircraft signals //! @{ //////////////////////////////////////////////////////////////// /*! * We received a notification that a pilot has disconnected from the network. */ void pilotDisconnected(const BlackMisc::Aviation::CCallsign &callsign); /*! * We received a reply to one of our queries. * \sa sendIcaoCodesQuery */ void icaoCodesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &aircraftIcaoDesignator, const QString &airlineIcaoDesignator, const QString &livery); /*! * We received a notification of the state of another aircraft on the network. * Corresponding callsign in \sa CAircraftSituation::getCallsign . */ void aircraftPositionUpdate(const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CTransponder &transponder); /*! * We received a interim notification of the state of another aircraft on the network. * Corresponding callsign in \sa CAircraftSituation::getCallsign . */ void aircraftInterimPositionUpdate(const BlackMisc::Aviation::CAircraftSituation &situation); /*! * We received a reply to one of our queries. * \sa sendFrequencyQuery */ void frequencyReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &freq); //! @} //////////////////////////////////////////////////////////////// //! \name Network signals //! @{ //////////////////////////////////////////////////////////////// /*! * We were kicked from the network. (A connectionStatusChanged signal will also be sent.) */ void kicked(const QString &msg); /*! * The status of our connection has changed. */ void connectionStatusChanged(BlackCore::INetwork::ConnectionStatus oldStatus, BlackCore::INetwork::ConnectionStatus newStatus); /*! * We received a reply to one of our pings. * \sa sendPing */ void pongReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CTime &elapsedTime); /*! * We received a reply to one of our queries. * \sa sendCapabilitiesQuery * @param callsign * @param capabilitiesFlags as in BlackMisc::Network::CClient */ void capabilitiesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, int capabilitiesFlags); /*! * We received a reply to one of our queries. * \param ip Our IP address, as seen by the server. * \sa sendIpQuery */ void ipReplyReceived(const QString &ip); /*! * We received a reply to one of our queries. * \sa sendServerQuery */ void serverReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &server); /*! * We received a reply to one of our queries. * \sa sendRealNameQuery */ void realNameReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &realname); /*! * We received one or more text messages from another user. */ void textMessagesReceived(const BlackMisc::Network::CTextMessageList &messages); /*! * We have sent a text message. */ void textMessageSent(const BlackMisc::Network::CTextMessage &sentMessage); /*! * We received a FSInn custom packet. */ void customFSInnPacketReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &airlineDesignator, const QString &aircraftDesignator, const QString &combinedType, const QString &modelString); /*! * We received an aircraft config packet. */ void aircraftConfigPacketReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &incremental, qint64 currentOffsetTimeMs); /*! * We received a raw message for debugging purposes */ void rawFsdMessageReceived(const BlackMisc::Network::CRawFsdMessage &rawFsdMessage); //! @} //////////////////////////////////////////////////////////////// //! \name Weather signals //! @{ //////////////////////////////////////////////////////////////// /*! * We received a reply to one of our METAR queries. * \sa sendMetarQuery */ void metarReplyReceived(const QString &data); //! @} protected: //! Save the statistics bool saveNetworkStatistics(const QString &server); //! Connected to network void connectedToNewtork(); private: bool m_statistics = false; QMap m_callStatistics; QVector > m_callByTime; }; } // namespace Q_DECLARE_METATYPE(BlackCore::INetwork::ConnectionStatus) Q_DECLARE_METATYPE(BlackCore::INetwork::LoginMode) #endif // guard