Skip to content

Commit 659a8ba

Browse files
authored
Merge pull request #3533 from pljones/feature/3532-rpc-setdirectory
3532: Add jamulusserver/setDirectory request
2 parents ba07f4e + a0f38c9 commit 659a8ba

File tree

4 files changed

+166
-32
lines changed

4 files changed

+166
-32
lines changed

docs/JSON-RPC.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ Results:
321321
| result.city | string | The server city. |
322322
| result.countryId | number | The server country ID (see QLocale::Country). |
323323
| result.welcomeMessage | string | The server welcome message. |
324+
| result.directoryType | string | The directory type as a string (see EDirectoryType and SerializeDirectoryType). |
325+
| result.directoryAddress | string | The string used to look up the directory address (only assume valid if directoryType is "custom" and registrationStatus is "registered"). |
324326
| result.directory | string | The directory with which this server requested registration, or blank if none. |
325327
| result.registrationStatus | string | The server registration status as string (see ESvrRegStatus and SerializeRegistrationStatus). |
326328

@@ -342,6 +344,24 @@ Results:
342344
| result | string | Always "acknowledged". To check if the recording was restarted or if there is any error, call `jamulusserver/getRecorderStatus` again. |
343345

344346

347+
### jamulusserver/setDirectory
348+
349+
Set the directory type and, for custom, the directory address.
350+
351+
Parameters:
352+
353+
| Name | Type | Description |
354+
| --- | --- | --- |
355+
| params.directoryType | string | The directory type as a string (see EDirectoryType and DeserializeDirectoryType). |
356+
| [params.directoryAddress] | string | (optional) The directory address, required if `directoryType` is "custom". |
357+
358+
Results:
359+
360+
| Name | Type | Description |
361+
| --- | --- | --- |
362+
| result | string | Always "ok". |
363+
364+
345365
### jamulusserver/setRecordingDirectory
346366

347367
Sets the server recording directory.

src/serverrpc.cpp

Lines changed: 113 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -122,26 +122,72 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare
122122
/// @result {string} result.city - The server city.
123123
/// @result {number} result.countryId - The server country ID (see QLocale::Country).
124124
/// @result {string} result.welcomeMessage - The server welcome message.
125+
/// @result {string} result.directoryType - The directory type as a string (see EDirectoryType and SerializeDirectoryType).
126+
/// @result {string} result.directoryAddress - The string used to look up the directory address (only assume valid if directoryType is "custom"
127+
/// and registrationStatus is "registered").
125128
/// @result {string} result.directory - The directory with which this server requested registration, or blank if none.
126129
/// @result {string} result.registrationStatus - The server registration status as string (see ESvrRegStatus and SerializeRegistrationStatus).
127130
pRpcServer->HandleMethod ( "jamulusserver/getServerProfile", [=] ( const QJsonObject& params, QJsonObject& response ) {
128-
QString dsName = "";
129-
130-
if ( AT_NONE != pServer->GetDirectoryType() )
131-
dsName = NetworkUtil::GetDirectoryAddress ( pServer->GetDirectoryType(), pServer->GetDirectoryAddress() );
131+
EDirectoryType directoryType = pServer->GetDirectoryType();
132+
QString directoryAddress = pServer->GetDirectoryAddress();
133+
QString dsName = ( AT_NONE == directoryType ) ? "" : NetworkUtil::GetDirectoryAddress ( directoryType, directoryAddress );
132134

133135
QJsonObject result{
134136
{ "name", pServer->GetServerName() },
135137
{ "city", pServer->GetServerCity() },
136138
{ "countryId", pServer->GetServerCountry() },
137139
{ "welcomeMessage", pServer->GetWelcomeMessage() },
140+
{ "directoryType", SerializeDirectoryType ( directoryType ) },
141+
{ "directoryAddress", directoryAddress },
138142
{ "directory", dsName },
139143
{ "registrationStatus", SerializeRegistrationStatus ( pServer->GetSvrRegStatus() ) },
140144
};
141145
response["result"] = result;
142146
Q_UNUSED ( params );
143147
} );
144148

149+
/// @rpc_method jamulusserver/setDirectory
150+
/// @brief Set the directory type and, for custom, the directory address.
151+
/// @param {string} params.directoryType - The directory type as a string (see EDirectoryType and DeserializeDirectoryType).
152+
/// @param {string} [params.directoryAddress] - (optional) The directory address, required if `directoryType` is "custom".
153+
/// @result {string} result - Always "ok".
154+
pRpcServer->HandleMethod ( "jamulusserver/setDirectory", [=] ( const QJsonObject& params, QJsonObject& response ) {
155+
auto jsonDirectoryType = params["directoryType"];
156+
auto directoryAddress = params["directoryAddress"];
157+
EDirectoryType directoryType = AT_NONE;
158+
159+
if ( !jsonDirectoryType.isString() )
160+
{
161+
response["error"] = CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams, "Invalid params: directory type is not a string" );
162+
return;
163+
}
164+
else
165+
{
166+
directoryType = DeserializeDirectoryType ( jsonDirectoryType.toString().toStdString() );
167+
}
168+
169+
if ( !directoryAddress.isUndefined() )
170+
{
171+
if ( !directoryAddress.isString() )
172+
{
173+
response["error"] =
174+
CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams, "Invalid params: directory address is not a string" );
175+
return;
176+
}
177+
}
178+
else if ( AT_CUSTOM == directoryType )
179+
{
180+
response["error"] = CRpcServer::CreateJsonRpcError ( CRpcServer::iErrInvalidParams,
181+
"Invalid params: directory address is required when directory type is \"custom\"" );
182+
return;
183+
}
184+
185+
pServer->SetDirectoryAddress ( directoryAddress.toString() ); // ignored unless AT_CUSTOM == directoryType
186+
pServer->SetDirectoryType ( directoryType );
187+
188+
response["result"] = "ok";
189+
} );
190+
145191
/// @rpc_method jamulusserver/setServerName
146192
/// @brief Sets the server name.
147193
/// @param {string} params.serverName - The new server name.
@@ -226,37 +272,73 @@ CServerRpc::CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* pare
226272
} );
227273
}
228274

229-
QJsonValue CServerRpc::SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus )
275+
#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
276+
const std::unordered_map<EDirectoryType, std::string, EnumClassHash<EDirectoryType>>
277+
#else
278+
const std::unordered_map<EDirectoryType, std::string>
279+
#endif
280+
CServerRpc::sumDirectoryTypeToString = {
281+
{ EDirectoryType::AT_NONE, "none" },
282+
{ EDirectoryType::AT_DEFAULT, "any_genre_1" },
283+
{ EDirectoryType::AT_ANY_GENRE2, "any_genre_2" },
284+
{ EDirectoryType::AT_ANY_GENRE3, "any_genre_3" },
285+
{ EDirectoryType::AT_GENRE_ROCK, "genre_rock" },
286+
{ EDirectoryType::AT_GENRE_JAZZ, "genre_jazz" },
287+
{ EDirectoryType::AT_GENRE_CLASSICAL_FOLK, "genre_classical_folk" },
288+
{ EDirectoryType::AT_GENRE_CHORAL, "genre_choral_barbershop" },
289+
{ EDirectoryType::AT_CUSTOM, "custom" },
290+
};
291+
292+
inline QJsonValue CServerRpc::SerializeDirectoryType ( EDirectoryType eAddrType )
230293
{
231-
switch ( eSvrRegStatus )
232-
{
233-
case SRS_NOT_REGISTERED:
234-
return "not_registered";
235-
236-
case SRS_BAD_ADDRESS:
237-
return "bad_address";
294+
auto found = sumDirectoryTypeToString.find ( eAddrType );
295+
if ( found == sumDirectoryTypeToString.end() )
296+
return QJsonValue ( QString ( "unknown(%1)" ).arg ( eAddrType ) );
238297

239-
case SRS_REQUESTED:
240-
return "requested";
241-
242-
case SRS_TIME_OUT:
243-
return "time_out";
244-
245-
case SRS_UNKNOWN_RESP:
246-
return "unknown_resp";
247-
248-
case SRS_REGISTERED:
249-
return "registered";
298+
return QJsonValue ( QString::fromStdString ( found->second ) );
299+
}
250300

251-
case SRS_SERVER_LIST_FULL:
252-
return "directory_server_full"; // TODO - rename to "server_list_full"
301+
const std::unordered_map<std::string, EDirectoryType> CServerRpc::sumStringToDirectoryType = {
302+
{ "none", EDirectoryType::AT_NONE },
303+
{ "any_genre_1", EDirectoryType::AT_DEFAULT },
304+
{ "any_genre_2", EDirectoryType::AT_ANY_GENRE2 },
305+
{ "any_genre_3", EDirectoryType::AT_ANY_GENRE3 },
306+
{ "genre_rock", EDirectoryType::AT_GENRE_ROCK },
307+
{ "genre_jazz", EDirectoryType::AT_GENRE_JAZZ },
308+
{ "genre_classical_folk", EDirectoryType::AT_GENRE_CLASSICAL_FOLK },
309+
{ "genre_choral_barbershop", EDirectoryType::AT_GENRE_CHORAL },
310+
{ "custom", EDirectoryType::AT_CUSTOM },
311+
};
312+
313+
inline EDirectoryType CServerRpc::DeserializeDirectoryType ( std::string sAddrType )
314+
{
315+
auto found = sumStringToDirectoryType.find ( sAddrType );
316+
if ( found == sumStringToDirectoryType.end() )
317+
return AT_DEFAULT;
253318

254-
case SRS_VERSION_TOO_OLD:
255-
return "server_version_too_old";
319+
return found->second;
320+
}
256321

257-
case SRS_NOT_FULFILL_REQUIREMENTS:
258-
return "requirements_not_fulfilled";
259-
}
322+
#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
323+
const std::unordered_map<ESvrRegStatus, std::string, EnumClassHash<ESvrRegStatus>>
324+
#else
325+
const std::unordered_map<ESvrRegStatus, std::string>
326+
#endif
327+
CServerRpc::sumSvrRegStatusToString = { { SRS_NOT_REGISTERED, "not_registered" },
328+
{ SRS_BAD_ADDRESS, "bad_address" },
329+
{ SRS_REQUESTED, "requested" },
330+
{ SRS_TIME_OUT, "time_out" },
331+
{ SRS_UNKNOWN_RESP, "unknown_resp" },
332+
{ SRS_REGISTERED, "registered" },
333+
{ SRS_SERVER_LIST_FULL, "directory_server_full" }, // TODO: rename to "server_list_full"
334+
{ SRS_VERSION_TOO_OLD, "server_version_too_old" },
335+
{ SRS_NOT_FULFILL_REQUIREMENTS, "requirements_not_fulfilled" } };
336+
337+
inline QJsonValue CServerRpc::SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus )
338+
{
339+
auto found = sumSvrRegStatusToString.find ( eSvrRegStatus );
340+
if ( found == sumSvrRegStatusToString.end() )
341+
return QJsonValue ( QString ( "unknown(%1)" ).arg ( eSvrRegStatus ) );
260342

261-
return QString ( "unknown(%1)" ).arg ( eSvrRegStatus );
343+
return QJsonValue ( QString::fromStdString ( found->second ) );
262344
}

src/serverrpc.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,34 @@
2525

2626
#pragma once
2727

28+
#include <unordered_map>
2829
#include "server.h"
2930
#include "rpcserver.h"
3031

32+
// hash functor for enum classes (only needed on legacy macOS Qt5)
33+
#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
34+
# include "util.h"
35+
#endif
36+
3137
/* Classes ********************************************************************/
3238
class CServerRpc : public QObject
3339
{
3440
Q_OBJECT
3541

3642
public:
3743
CServerRpc ( CServer* pServer, CRpcServer* pRpcServer, QObject* parent = nullptr );
38-
static QJsonValue SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus );
44+
45+
private:
46+
const static std::unordered_map<std::string, EDirectoryType> sumStringToDirectoryType;
47+
#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
48+
const static std::unordered_map<EDirectoryType, std::string, EnumClassHash<EDirectoryType>> sumDirectoryTypeToString;
49+
const static std::unordered_map<ESvrRegStatus, std::string, EnumClassHash<ESvrRegStatus>> sumSvrRegStatusToString;
50+
#else
51+
const static std::unordered_map<EDirectoryType, std::string> sumDirectoryTypeToString;
52+
const static std::unordered_map<ESvrRegStatus, std::string> sumSvrRegStatusToString;
53+
#endif
54+
55+
QJsonValue SerializeDirectoryType ( EDirectoryType eAddrType );
56+
EDirectoryType DeserializeDirectoryType ( std::string sAddrType );
57+
QJsonValue SerializeRegistrationStatus ( ESvrRegStatus eSvrRegStatus );
3958
};

src/util.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,3 +1360,16 @@ class CErrorRate
13601360
bool bBlockOnDoubleErrors;
13611361
bool bPreviousState;
13621362
};
1363+
1364+
// Generic hash functor for enum classes
1365+
// Can be removed once macOS Legacy uses C++11 or newer
1366+
#if defined( Q_OS_MACOS ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
1367+
template<typename T>
1368+
struct EnumClassHash
1369+
{
1370+
std::size_t operator() ( T t ) const
1371+
{
1372+
return std::hash<typename std::underlying_type<T>::type>() ( static_cast<typename std::underlying_type<T>::type> ( t ) );
1373+
}
1374+
};
1375+
#endif

0 commit comments

Comments
 (0)