diff --git a/docs/JSON-RPC.md b/docs/JSON-RPC.md index 2edbafbf19..c5f6aa37d0 100644 --- a/docs/JSON-RPC.md +++ b/docs/JSON-RPC.md @@ -321,6 +321,8 @@ Results: | result.city | string | The server city. | | result.countryId | number | The server country ID (see QLocale::Country). | | result.welcomeMessage | string | The server welcome message. | +| result.directoryType | string | The directory type as a string (see EDirectoryType and SerializeDirectoryType). | +| result.directoryAddress | string | The string used to look up the directory address (only assume valid if directoryType is "custom" and registrationStatus is "registered"). | | result.directory | string | The directory with which this server requested registration, or blank if none. | | result.registrationStatus | string | The server registration status as string (see ESvrRegStatus and SerializeRegistrationStatus). | @@ -342,6 +344,24 @@ Results: | result | string | Always "acknowledged". To check if the recording was restarted or if there is any error, call `jamulusserver/getRecorderStatus` again. | +### jamulusserver/setDirectory + +Set the directory type and, for custom, the directory address. + +Parameters: + +| Name | Type | Description | +| --- | --- | --- | +| params.directoryType | string | The directory type as a string (see EDirectoryType and DeserializeDirectoryType). | +| [params.directoryAddress] | string | (optional) The directory address, required if `directoryType` is "custom". | + +Results: + +| Name | Type | Description | +| --- | --- | --- | +| result | string | Always "ok". | + + ### jamulusserver/setRecordingDirectory Sets the server recording directory. diff --git a/src/serverrpc.cpp b/src/serverrpc.cpp index 56f2253c5a..231d974927 100644 --- a/src/serverrpc.cpp +++ b/src/serverrpc.cpp @@ -122,19 +122,23 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare /// @result {string} result.city - The server city. /// @result {number} result.countryId - The server country ID (see QLocale::Country). /// @result {string} result.welcomeMessage - The server welcome message. + /// @result {string} result.directoryType - The directory type as a string (see EDirectoryType and SerializeDirectoryType). + /// @result {string} result.directoryAddress - The string used to look up the directory address (only assume valid if directoryType is "custom" + /// and registrationStatus is "registered"). /// @result {string} result.directory - The directory with which this server requested registration, or blank if none. /// @result {string} result.registrationStatus - The server registration status as string (see ESvrRegStatus and SerializeRegistrationStatus). pRpcServer->HandleMethod ( "jamulusserver/getServerProfile", [=] ( const QJsonObject& params, QJsonObject& response ) { - QString dsName = ""; - - if ( AT_NONE != pServer->GetDirectoryType() ) - dsName = NetworkUtil::GetDirectoryAddress ( pServer->GetDirectoryType(), pServer->GetDirectoryAddress() ); + EDirectoryType directoryType = pServer->GetDirectoryType(); + QString directoryAddress = pServer->GetDirectoryAddress(); + QString dsName = ( AT_NONE == directoryType ) ? "" : NetworkUtil::GetDirectoryAddress ( directoryType, directoryAddress ); QJsonObject result{ { "name", pServer->GetServerName() }, { "city", pServer->GetServerCity() }, { "countryId", pServer->GetServerCountry() }, { "welcomeMessage", pServer->GetWelcomeMessage() }, + { "directoryType", SerializeDirectoryType ( directoryType ) }, + { "directoryAddress", directoryAddress }, { "directory", dsName }, { "registrationStatus", SerializeRegistrationStatus ( pServer->GetSvrRegStatus() ) }, }; @@ -142,6 +146,48 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare Q_UNUSED ( params ); } ); + /// @rpc_method jamulusserver/setDirectory + /// @brief Set the directory type and, for custom, the directory address. + /// @param {string} params.directoryType - The directory type as a string (see EDirectoryType and DeserializeDirectoryType). + /// @param {string} [params.directoryAddress] - (optional) The directory address, required if `directoryType` is "custom". + /// @result {string} result - Always "ok". + pRpcServer->HandleMethod ( "jamulusserver/setDirectory", [=] ( const QJsonObject& params, QJsonObject& response ) { + auto jsonDirectoryType = params["directoryType"]; + auto directoryAddress = params["directoryAddress"]; + EDirectoryType directoryType = AT_NONE; + + if ( !jsonDirectoryType.isString() ) + { + response["error"] = CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams, "Invalid params: directory type is not a string" ); + return; + } + else + { + directoryType = DeserializeDirectoryType ( jsonDirectoryType.toString().toStdString() ); + } + + if ( !directoryAddress.isUndefined() ) + { + if ( !directoryAddress.isString() ) + { + response["error"] = + CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams, "Invalid params: directory address is not a string" ); + return; + } + } + else if ( AT_CUSTOM == directoryType ) + { + response["error"] = CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams, + "Invalid params: directory address is required when directory type is \"custom\"" ); + return; + } + + pServer->SetDirectoryAddress ( directoryAddress.toString() ); // ignored unless AT_CUSTOM == directoryType + pServer->SetDirectoryType ( directoryType ); + + response["result"] = "ok"; + } ); + /// @rpc_method jamulusserver/setServerName /// @brief Sets the server name. /// @param {string} params.serverName - The new server name. @@ -226,37 +272,73 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare } ); } -QJsonValue CServerRpc::SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus ) +#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) +const std::unordered_map> +#else +const std::unordered_map +#endif + CServerRpc::sumDirectoryTypeToString = { + { EDirectoryType::AT_NONE, "none" }, + { EDirectoryType::AT_DEFAULT, "any_genre_1" }, + { EDirectoryType::AT_ANY_GENRE2, "any_genre_2" }, + { EDirectoryType::AT_ANY_GENRE3, "any_genre_3" }, + { EDirectoryType::AT_GENRE_ROCK, "genre_rock" }, + { EDirectoryType::AT_GENRE_JAZZ, "genre_jazz" }, + { EDirectoryType::AT_GENRE_CLASSICAL_FOLK, "genre_classical_folk" }, + { EDirectoryType::AT_GENRE_CHORAL, "genre_choral_barbershop" }, + { EDirectoryType::AT_CUSTOM, "custom" }, +}; + +inline QJsonValue CServerRpc::SerializeDirectoryType ( EDirectoryType eAddrType ) { - switch ( eSvrRegStatus ) - { - case SRS_NOT_REGISTERED: - return "not_registered"; - - case SRS_BAD_ADDRESS: - return "bad_address"; + auto found = sumDirectoryTypeToString.find ( eAddrType ); + if ( found == sumDirectoryTypeToString.end() ) + return QJsonValue ( QString ( "unknown(%1)" ).arg ( eAddrType ) ); - case SRS_REQUESTED: - return "requested"; - - case SRS_TIME_OUT: - return "time_out"; - - case SRS_UNKNOWN_RESP: - return "unknown_resp"; - - case SRS_REGISTERED: - return "registered"; + return QJsonValue ( QString::fromStdString ( found->second ) ); +} - case SRS_SERVER_LIST_FULL: - return "directory_server_full"; // TODO - rename to "server_list_full" +const std::unordered_map CServerRpc::sumStringToDirectoryType = { + { "none", EDirectoryType::AT_NONE }, + { "any_genre_1", EDirectoryType::AT_DEFAULT }, + { "any_genre_2", EDirectoryType::AT_ANY_GENRE2 }, + { "any_genre_3", EDirectoryType::AT_ANY_GENRE3 }, + { "genre_rock", EDirectoryType::AT_GENRE_ROCK }, + { "genre_jazz", EDirectoryType::AT_GENRE_JAZZ }, + { "genre_classical_folk", EDirectoryType::AT_GENRE_CLASSICAL_FOLK }, + { "genre_choral_barbershop", EDirectoryType::AT_GENRE_CHORAL }, + { "custom", EDirectoryType::AT_CUSTOM }, +}; + +inline EDirectoryType CServerRpc::DeserializeDirectoryType ( std::string sAddrType ) +{ + auto found = sumStringToDirectoryType.find ( sAddrType ); + if ( found == sumStringToDirectoryType.end() ) + return AT_DEFAULT; - case SRS_VERSION_TOO_OLD: - return "server_version_too_old"; + return found->second; +} - case SRS_NOT_FULFILL_REQUIREMENTS: - return "requirements_not_fulfilled"; - } +#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) +const std::unordered_map> +#else +const std::unordered_map +#endif + CServerRpc::sumSvrRegStatusToString = { { SRS_NOT_REGISTERED, "not_registered" }, + { SRS_BAD_ADDRESS, "bad_address" }, + { SRS_REQUESTED, "requested" }, + { SRS_TIME_OUT, "time_out" }, + { SRS_UNKNOWN_RESP, "unknown_resp" }, + { SRS_REGISTERED, "registered" }, + { SRS_SERVER_LIST_FULL, "directory_server_full" }, // TODO: rename to "server_list_full" + { SRS_VERSION_TOO_OLD, "server_version_too_old" }, + { SRS_NOT_FULFILL_REQUIREMENTS, "requirements_not_fulfilled" } }; + +inline QJsonValue CServerRpc::SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus ) +{ + auto found = sumSvrRegStatusToString.find ( eSvrRegStatus ); + if ( found == sumSvrRegStatusToString.end() ) + return QJsonValue ( QString ( "unknown(%1)" ).arg ( eSvrRegStatus ) ); - return QString ( "unknown(%1)" ).arg ( eSvrRegStatus ); + return QJsonValue ( QString::fromStdString ( found->second ) ); } diff --git a/src/serverrpc.h b/src/serverrpc.h index f4f28efcff..176aae1075 100644 --- a/src/serverrpc.h +++ b/src/serverrpc.h @@ -25,9 +25,15 @@ #pragma once +#include #include "server.h" #include "rpcserver.h" +// hash functor for enum classes (only needed on legacy macOS Qt5) +#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) +# include "util.h" +#endif + /* Classes ********************************************************************/ class CServerRpc : public QObject { @@ -35,5 +41,18 @@ class CServerRpc : public QObject public: CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* parent = nullptr ); - static QJsonValue SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus ); + +private: + const static std::unordered_map sumStringToDirectoryType; +#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + const static std::unordered_map> sumDirectoryTypeToString; + const static std::unordered_map> sumSvrRegStatusToString; +#else + const static std::unordered_map sumDirectoryTypeToString; + const static std::unordered_map sumSvrRegStatusToString; +#endif + + QJsonValue SerializeDirectoryType ( EDirectoryType eAddrType ); + EDirectoryType DeserializeDirectoryType ( std::string sAddrType ); + QJsonValue SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus ); }; diff --git a/src/util.h b/src/util.h index c09885f408..dc6e4f2834 100644 --- a/src/util.h +++ b/src/util.h @@ -1360,3 +1360,16 @@ class CErrorRate bool bBlockOnDoubleErrors; bool bPreviousState; }; + +// Generic hash functor for enum classes +// Can be removed once macOS Legacy uses C++11 or newer +#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) +template +struct EnumClassHash +{ + std::size_t operator() ( T t ) const + { + return std::hash::type>() ( static_cast::type> ( t ) ); + } +}; +#endif