Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/JSON-RPC.md
Original file line number Diff line number Diff line change
Expand Up @@ -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). |

Expand All @@ -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.
Expand Down
144 changes: 113 additions & 31 deletions src/serverrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,26 +122,72 @@ 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() ) },
};
response["result"] = result;
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.
Expand Down Expand Up @@ -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<EDirectoryType, std::string, EnumClassHash<EDirectoryType>>
#else
const std::unordered_map<EDirectoryType, std::string>
#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<std::string, EDirectoryType> 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<ESvrRegStatus, std::string, EnumClassHash<ESvrRegStatus>>
#else
const std::unordered_map<ESvrRegStatus, std::string>
#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 ) );
}
21 changes: 20 additions & 1 deletion src/serverrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,34 @@

#pragma once

#include <unordered_map>
#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
{
Q_OBJECT

public:
CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* parent = nullptr );
static QJsonValue SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus );

private:
const static std::unordered_map<std::string, EDirectoryType> sumStringToDirectoryType;
#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
const static std::unordered_map<EDirectoryType, std::string, EnumClassHash<EDirectoryType>> sumDirectoryTypeToString;
const static std::unordered_map<ESvrRegStatus, std::string, EnumClassHash<ESvrRegStatus>> sumSvrRegStatusToString;
#else
const static std::unordered_map<EDirectoryType, std::string> sumDirectoryTypeToString;
const static std::unordered_map<ESvrRegStatus, std::string> sumSvrRegStatusToString;
#endif

QJsonValue SerializeDirectoryType ( EDirectoryType eAddrType );
EDirectoryType DeserializeDirectoryType ( std::string sAddrType );
QJsonValue SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus );
};
13 changes: 13 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename T>
struct EnumClassHash
{
std::size_t operator() ( T t ) const
{
return std::hash<typename std::underlying_type<T>::type>() ( static_cast<typename std::underlying_type<T>::type> ( t ) );
}
};
#endif