Json RPC: Object.Set methods have the updated object in the response

This commit is contained in:
BadAix 2016-12-30 14:24:10 +01:00
parent c1eca56e38
commit 9e96b3e13b
5 changed files with 248 additions and 167 deletions

View file

@ -20,7 +20,6 @@ package de.badaix.snapcast;
import android.content.Context; import android.content.Context;
import android.support.v7.widget.PopupMenu; import android.support.v7.widget.PopupMenu;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@ -64,7 +63,7 @@ public class ClientItem extends LinearLayout implements SeekBar.OnSeekBarChangeL
} }
private void update() { private void update() {
Log.d(TAG, "update: " + client.getVisibleName() + ", connected: " + client.isConnected()); //Log.d(TAG, "update: " + client.getVisibleName() + ", connected: " + client.isConnected());
title.setText(client.getVisibleName()); title.setText(client.getVisibleName());
title.setEnabled(client.isConnected()); title.setEnabled(client.isConnected());
volumeSeekBar.setProgress(client.getConfig().getVolume().getPercent()); volumeSeekBar.setProgress(client.getConfig().getVolume().getPercent());

View file

@ -55,6 +55,7 @@ import java.util.ArrayList;
import de.badaix.snapcast.control.RemoteControl; import de.badaix.snapcast.control.RemoteControl;
import de.badaix.snapcast.control.json.Client; import de.badaix.snapcast.control.json.Client;
import de.badaix.snapcast.control.json.Group;
import de.badaix.snapcast.control.json.ServerStatus; import de.badaix.snapcast.control.json.ServerStatus;
import de.badaix.snapcast.control.json.Stream; import de.badaix.snapcast.control.json.Stream;
import de.badaix.snapcast.utils.NsdHelper; import de.badaix.snapcast.utils.NsdHelper;
@ -431,8 +432,9 @@ public class MainActivity extends AppCompatActivity implements GroupItem.GroupIt
remoteControl.setStream(groupId, streamId); remoteControl.setStream(groupId, streamId);
changed = true; changed = true;
} }
if (changed) //TODO
remoteControl.getServerStatus(); // if (changed)
// remoteControl.getServerStatus();
} }
} }
@ -467,7 +469,7 @@ public class MainActivity extends AppCompatActivity implements GroupItem.GroupIt
@Override @Override
public void onClientEvent(RemoteControl remoteControl, Client client, RemoteControl.ClientEvent event) { public void onClientEvent(RemoteControl remoteControl, Client client, RemoteControl.ClientEvent event) {
Log.d(TAG, "onClientEvent: " + event.toString()); Log.d(TAG, "onClientEvent: " + event.toString());
remoteControl.getServerStatus(); // remoteControl.getServerStatus();
/* TODO: group /* TODO: group
if (event == RemoteControl.ClientEvent.deleted) if (event == RemoteControl.ClientEvent.deleted)
serverStatus.removeClient(client); serverStatus.removeClient(client);
@ -475,6 +477,9 @@ public class MainActivity extends AppCompatActivity implements GroupItem.GroupIt
serverStatus.updateClient(client); serverStatus.updateClient(client);
sectionsPagerAdapter.updateServer(serverStatus); sectionsPagerAdapter.updateServer(serverStatus);
*/ */
if (event != RemoteControl.ClientEvent.deleted)
serverStatus.updateClient(client);
groupListFragment.updateServer(serverStatus);
} }
@Override @Override
@ -489,6 +494,12 @@ public class MainActivity extends AppCompatActivity implements GroupItem.GroupIt
// TODO: group sectionsPagerAdapter.updateServer(serverStatus); // TODO: group sectionsPagerAdapter.updateServer(serverStatus);
} }
@Override
public void onGroupUpdate(RemoteControl remoteControl, Group group) {
// TODO
Log.d(TAG, "onGroupUpdate: " + group.toString());
}
private void setActionbarSubtitle(final String subtitle) { private void setActionbarSubtitle(final String subtitle) {
MainActivity.this.runOnUiThread(new Runnable() { MainActivity.this.runOnUiThread(new Runnable() {

View file

@ -44,14 +44,12 @@ public class RemoteControl implements TcpClient.TcpClientListener {
private TcpClient tcpClient; private TcpClient tcpClient;
private long msgId; private long msgId;
private RemoteControlListener listener; private RemoteControlListener listener;
private ServerStatus serverStatus;
private String host; private String host;
private int port; private int port;
private HashMap<Long, String> pendingRequests; private HashMap<Long, String> pendingRequests;
public RemoteControl(RemoteControlListener listener) { public RemoteControl(RemoteControlListener listener) {
this.listener = listener; this.listener = listener;
serverStatus = new ServerStatus();
msgId = 0; msgId = 0;
pendingRequests = new HashMap<>(); pendingRequests = new HashMap<>();
} }
@ -96,7 +94,9 @@ public class RemoteControl implements TcpClient.TcpClientListener {
// Log.d(TAG, "Msg received: " + message); // Log.d(TAG, "Msg received: " + message);
try { try {
JSONObject json = new JSONObject(message); JSONObject json = new JSONObject(message);
if (json.has("id")) { if (json.has("id")) {
/// Response
// Log.d(TAG, "ID: " + json.getString("id")); // Log.d(TAG, "ID: " + json.getString("id"));
long id = json.getLong("id"); long id = json.getLong("id");
String request = ""; String request = "";
@ -107,38 +107,53 @@ public class RemoteControl implements TcpClient.TcpClientListener {
pendingRequests.remove(id); pendingRequests.remove(id);
} }
} }
if (listener == null)
return;
if (json.has("error")) { if (json.has("error")) {
JSONObject error = json.getJSONObject("error"); JSONObject error = json.getJSONObject("error");
Log.e(TAG, "error " + error.getInt("code") + ": " + error.getString("message")); Log.e(TAG, "error " + error.getInt("code") + ": " + error.getString("message"));
} else if (!TextUtils.isEmpty(request)) { }
if (request.equals("Server.GetStatus")) {
serverStatus.fromJson(json.getJSONObject("result")); if (TextUtils.isEmpty(request)) {
if (listener != null) Log.e(TAG, "request for id " + id + " not found");
listener.onServerStatus(this, serverStatus); return;
}
/// Response to a "Object.GetStatus" message
if (request.equals("Client.GetStatus")) {
listener.onClientEvent(this, new Client(json.getJSONObject("result")), ClientEvent.updated);
} else if (request.equals("Group.GetStatus")) {
listener.onGroupUpdate(this, new Group(json.getJSONObject("result")));
} else if (request.equals("Server.GetStatus")) {
listener.onServerStatus(this, new ServerStatus(json.getJSONObject("result")));
} else if (json.getJSONObject("result").has("method") && json.getJSONObject("result").has("params")) {
/// Response to a "Object.Set" message
JSONObject result = json.getJSONObject("result");
String method = result.getString("method");
if ("Client.OnUpdate".equals(method)) {
// listener.onClientEvent(this, new Client(result.getJSONObject("params")), ClientEvent.updated);
} else if ("Group.OnUpdate".equals(method)) {
listener.onGroupUpdate(this, new Group(result.getJSONObject("params")));
} else if ("Server.OnUpdate".equals(method)) {
listener.onServerStatus(this, new ServerStatus(result.getJSONObject("params")));
} }
} }
} else { } else {
/// Notification
if (listener == null)
return;
String method = json.getString("method"); String method = json.getString("method");
// Log.d(TAG, "Notification: " + method);
if (method.contains("Client.On")) { if (method.contains("Client.On")) {
final Client client = new Client(json.getJSONObject("params").getJSONObject("data")); final Client client = new Client(json.getJSONObject("params"));
// serverStatus.addClient(client); listener.onClientEvent(this, client, ClientEvent.fromString(method));
if (listener != null) {
ClientEvent event;
if (method.equals("Client.OnUpdate"))
listener.onClientEvent(this, client, ClientEvent.updated);
else if (method.equals("Client.OnConnect"))
listener.onClientEvent(this, client, ClientEvent.connected);
else if (method.equals("Client.OnDisconnect"))
listener.onClientEvent(this, client, ClientEvent.disconnected);
else if (method.equals("Client.OnDelete")) {
listener.onClientEvent(this, client, ClientEvent.deleted);
}
}
} else if (method.equals("Stream.OnUpdate")) { } else if (method.equals("Stream.OnUpdate")) {
Stream stream = new Stream(json.getJSONObject("params").getJSONObject("data")); listener.onStreamUpdate(this, new Stream(json.getJSONObject("params")));
listener.onStreamUpdate(this, stream); } else if (method.equals("Group.OnUpdate")) {
Log.d(TAG, stream.toString()); listener.onGroupUpdate(this, new Group(json.getJSONObject("params")));
} else if (method.equals("Server.OnUpdate")) {
listener.onServerStatus(this, new ServerStatus(json.getJSONObject("params")));
} }
} }
@ -157,7 +172,6 @@ public class RemoteControl implements TcpClient.TcpClientListener {
@Override @Override
public void onConnected(TcpClient tcpClient) { public void onConnected(TcpClient tcpClient) {
Log.d(TAG, "onConnected"); Log.d(TAG, "onConnected");
serverStatus = new ServerStatus();
if (listener != null) if (listener != null)
listener.onConnected(this); listener.onConnected(this);
} }
@ -165,7 +179,6 @@ public class RemoteControl implements TcpClient.TcpClientListener {
@Override @Override
public void onDisconnected(TcpClient tcpClient, Exception e) { public void onDisconnected(TcpClient tcpClient, Exception e) {
Log.d(TAG, "onDisconnected"); Log.d(TAG, "onDisconnected");
serverStatus = null;
if (listener != null) if (listener != null)
listener.onDisconnected(this, e); listener.onDisconnected(this, e);
} }
@ -262,10 +275,30 @@ public class RemoteControl implements TcpClient.TcpClientListener {
} }
public enum ClientEvent { public enum ClientEvent {
connected, connected("Client.OnConnect"),
disconnected, disconnected("Client.OnDisconnect"),
updated, updated("Client.OnUpdate"),
deleted deleted("Client.OnDelete");
private String text;
ClientEvent(String text) {
this.text = text;
}
public static ClientEvent fromString(String text) {
if (text != null) {
for (ClientEvent b : ClientEvent.values()) {
if (text.equalsIgnoreCase(b.text)) {
return b;
}
}
}
throw new IllegalArgumentException("No ClientEvent with text " + text + " found");
}
public String getText() {
return this.text;
}
} }
public interface RemoteControlListener { public interface RemoteControlListener {
@ -280,5 +313,7 @@ public class RemoteControl implements TcpClient.TcpClientListener {
void onServerStatus(RemoteControl remoteControl, ServerStatus serverStatus); void onServerStatus(RemoteControl remoteControl, ServerStatus serverStatus);
void onStreamUpdate(RemoteControl remoteControl, Stream stream); void onStreamUpdate(RemoteControl remoteControl, Stream stream);
void onGroupUpdate(RemoteControl remoteControl, Group group);
} }
} }

View file

@ -150,9 +150,7 @@ Json JsonNotification::getJson(const std::string& method, Json data)
Json notification = { Json notification = {
{"jsonrpc", "2.0"}, {"jsonrpc", "2.0"},
{"method", method}, {"method", method},
{"params", { {"params", data}
{"data", data}
}}
}; };
return notification; return notification;

View file

@ -112,51 +112,68 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
try try
{ {
request.parse(message); request.parse(message);
logD << "method: " << request.method << ", " << "id: " << request.id << "\n"; logO << "method: " << request.method << ", " << "id: " << request.id << "\n";
json response; json result;
ClientInfoPtr clientInfo = nullptr;
GroupPtr group = nullptr;
msg::ServerSettings serverSettings;
serverSettings.setBufferMs(settings_.bufferMs);
if (request.method.find("Group.Set") == 0) if (request.method.find("Client.") == 0)
{ {
group = Config::instance().getGroup(request.getParam("group").get<string>()); ClientInfoPtr clientInfo = Config::instance().getClientInfo(request.getParam("client").get<string>());
if (group == nullptr)
throw JsonInternalErrorException("Group not found", request.id);
}
if (request.method.find("Client.Set") == 0)
{
clientInfo = Config::instance().getClientInfo(request.getParam("client").get<string>());
if (clientInfo == nullptr) if (clientInfo == nullptr)
throw JsonInternalErrorException("Client not found", request.id); throw JsonInternalErrorException("Client not found", request.id);
}
if (request.method == "Server.GetStatus") if (request.method == "Client.GetStatus")
{ {
/// TODO: rpc result = clientInfo->toJson();
string clientId = request.hasParam("client") ? request.getParam("client").get<string>() : "";
response = Config::instance().getServerStatus(/*clientId,*/ streamManager_->toJson());
// logO << response.dump(4);
}
else if (request.method == "Server.DeleteClient")
{
clientInfo = Config::instance().getClientInfo(request.getParam("client").get<string>());
if (clientInfo == nullptr)
throw JsonInternalErrorException("Client not found", request.id);
response = clientInfo->host.mac;
Config::instance().remove(clientInfo);
Config::instance().save();
json notification = JsonNotification::getJson("Client.OnDelete", clientInfo->toJson());
controlServer_->send(notification.dump(), controlSession);
clientInfo = nullptr;
} }
else if (request.method == "Client.SetVolume") else if (request.method == "Client.SetVolume")
{ {
clientInfo->config.volume.fromJson(request.getParam("volume")); clientInfo->config.volume.fromJson(request.getParam("volume"));
response = clientInfo->config.volume.toJson(); }
else if (request.method == "Client.SetLatency")
{
clientInfo->config.latency = request.getParam<int>("latency", -10000, settings_.bufferMs);
}
else if (request.method == "Client.SetName")
{
clientInfo->config.name = request.getParam("name").get<string>();
}
else
throw JsonMethodNotFoundException(request.id);
if (request.method.find("Client.Set") == 0)
{
/// Response: updated client
result = {{"method", "Client.OnUpdate"}, {"params", clientInfo->toJson()}};
/// Update client
session_ptr session = getStreamSession(request.getParam("client").get<string>());
if (session != nullptr)
{
msg::ServerSettings serverSettings;
serverSettings.setBufferMs(settings_.bufferMs);
serverSettings.setVolume(clientInfo->config.volume.percent);
serverSettings.setMuted(clientInfo->config.volume.muted);
serverSettings.setLatency(clientInfo->config.latency);
session->send(&serverSettings);
}
/// Notify others
json notification = JsonNotification::getJson("Client.OnUpdate", clientInfo->toJson());
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
}
}
else if (request.method.find("Group.") == 0)
{
GroupPtr group = Config::instance().getGroup(request.getParam("group").get<string>());
if (group == nullptr)
throw JsonInternalErrorException("Group not found", request.id);
if (request.method == "Group.GetStatus")
{
result = group->toJson();
} }
else if (request.method == "Group.SetStream") else if (request.method == "Group.SetStream")
{ {
@ -166,8 +183,11 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
throw JsonInternalErrorException("Stream not found", request.id); throw JsonInternalErrorException("Stream not found", request.id);
group->streamId = streamId; group->streamId = streamId;
response = group->streamId;
/// Response: updated group
result = {{"method", "Group.OnUpdate"}, {"params", group->toJson()}};
/// Update clients
for (auto client: group->clients) for (auto client: group->clients)
{ {
session_ptr session = getStreamSession(client->id); session_ptr session = getStreamSession(client->id);
@ -177,6 +197,11 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
session->setPcmStream(stream); session->setPcmStream(stream);
} }
} }
/// Notify others
json notification = JsonNotification::getJson("Group.OnUpdate", group->toJson());
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
} }
else if (request.method == "Group.SetClients") else if (request.method == "Group.SetClients")
{ {
@ -228,37 +253,50 @@ void StreamServer::onMessageReceived(ControlSession* controlSession, const std::
if (group->empty()) if (group->empty())
Config::instance().remove(group); Config::instance().remove(group);
// response = Config::instance().getServerStatus(/*clientId,*/ streamManager_->toJson());
json serverJson = Config::instance().getServerStatus(streamManager_->toJson());
result = {{"method", "Server.OnUpdate"}, {"params", serverJson}};
/// Notify others: since at least two groups are affected, send a complete server update
json notification = JsonNotification::getJson("Server.OnUpdate", serverJson);
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
} }
else if (request.method == "Client.SetLatency") else
{ throw JsonMethodNotFoundException(request.id);
clientInfo->config.latency = request.getParam<int>("latency", -10000, settings_.bufferMs);
response = clientInfo->config.latency;
} }
else if (request.method == "Client.SetName") else if (request.method.find("Server.") == 0)
{ {
clientInfo->config.name = request.getParam("name").get<string>(); if (request.method == "Server.GetStatus")
response = clientInfo->config.name; {
result = Config::instance().getServerStatus(streamManager_->toJson());
}
else if (request.method == "Server.DeleteClient")
{
ClientInfoPtr clientInfo = Config::instance().getClientInfo(request.getParam("client").get<string>());
if (clientInfo == nullptr)
throw JsonInternalErrorException("Client not found", request.id);
Config::instance().remove(clientInfo);
json serverJson = Config::instance().getServerStatus(streamManager_->toJson());
result = {{"method", "Server.OnUpdate"}, {"params", serverJson}};
/// Notify others
json notification = JsonNotification::getJson("Server.OnUpdate", serverJson);
logO << "Notification: " << notification.dump() << "\n";
controlServer_->send(notification.dump(), controlSession);
}
else
throw JsonMethodNotFoundException(request.id);
} }
else else
throw JsonMethodNotFoundException(request.id); throw JsonMethodNotFoundException(request.id);
if (clientInfo != nullptr)
{
serverSettings.setVolume(clientInfo->config.volume.percent);
serverSettings.setMuted(clientInfo->config.volume.muted);
serverSettings.setLatency(clientInfo->config.latency);
session_ptr session = getStreamSession(request.getParam("client").get<string>());
if (session != nullptr)
session->send(&serverSettings);
Config::instance().save(); Config::instance().save();
json notification = JsonNotification::getJson("Client.OnUpdate", clientInfo->toJson()); string responseJson = request.getResponse(result).dump();
controlServer_->send(notification.dump(), controlSession); logO << "Response: " << responseJson << "\n";
} controlSession->send(responseJson);
controlSession->send(request.getResponse(response).dump());
} }
catch (const JsonRequestException& e) catch (const JsonRequestException& e)
{ {