other minor fixes^2

This commit is contained in:
Claudio Maggioni (maggicl) 2020-05-03 19:50:00 +02:00
parent 4a963115bb
commit 69d1b38ff2
7 changed files with 44 additions and 28 deletions

View file

@ -71,14 +71,18 @@ public abstract class Device {
@SocketGsonExclude @SocketGsonExclude
private Set<State<?>> states = new HashSet<>(); private Set<State<?>> states = new HashSet<>();
@Transient @GsonExclude private boolean fromHost = false; @Transient @GsonExclude private Long fromHostId = null;
@Transient @GsonExclude private boolean fromGuest = false; @Transient @GsonExclude private boolean fromGuest = false;
@Transient @GsonExclude private boolean deleted = false; @Transient @GsonExclude private boolean deleted = false;
public boolean isFromHost() { public Long getFromHostId() {
return fromHost; return fromHostId;
}
public void setFromHostId(Long fromHostId) {
this.fromHostId = fromHostId;
} }
public boolean isDeleted() { public boolean isDeleted() {
@ -97,10 +101,6 @@ public abstract class Device {
this.fromGuest = fromGuest; this.fromGuest = fromGuest;
} }
public void setFromHost(boolean fromHost) {
this.fromHost = fromHost;
}
public long getId() { public long getId() {
return id; return id;
} }

View file

@ -78,7 +78,7 @@ public class UpdateTasks {
c.forEach( c.forEach(
s -> s ->
sensorSocketEndpoint.queueDeviceUpdate( sensorSocketEndpoint.queueDeviceUpdate(
s, sensorRepository.findUser(s.getId()))); s, sensorRepository.findUser(s.getId()), false, null, false));
} }
/** Sends device updates through sensor socket in batch every one second */ /** Sends device updates through sensor socket in batch every one second */

View file

@ -125,21 +125,17 @@ public class DeviceService {
// We're telling the host that a guest has modified a device. Therefore, fromGuest becomes // We're telling the host that a guest has modified a device. Therefore, fromGuest becomes
// true. // true.
device.setFromHost(false);
device.setFromGuest(true);
// broadcast device update to host // broadcast device update to host
endpoint.queueDeviceUpdate(device, host); endpoint.queueDeviceUpdate(device, host, true, null, false);
// We're telling all guests that a higher entity has issued a device update. Therefore, // We're telling all guests that a higher entity has issued a device update. Therefore,
// fromHost becomes true. // fromHost becomes true.
device.setFromHost(true);
device.setFromGuest(false);
for (final User guest : guests) { for (final User guest : guests) {
if (guest.equals(currentUser)) { if (guest.equals(currentUser)) {
continue; continue;
} }
// enqueue all device updates for all other guests // enqueue all device updates for all other guests
endpoint.queueDeviceUpdate(device, guest); endpoint.queueDeviceUpdate(device, guest, false, host.getId(), false);
} }
return device; return device;
@ -157,15 +153,13 @@ public class DeviceService {
final User user = userRepository.findByUsername(username); final User user = userRepository.findByUsername(username);
final Set<User> guests = user.getGuests(); final Set<User> guests = user.getGuests();
// make sure we're broadcasting from host // make sure we're broadcasting from host
device.setFromHost(true);
device.setFromGuest(false);
for (final User guest : guests) { for (final User guest : guests) {
// broadcast to endpoint the object device, with receiving user set to guest // broadcast to endpoint the object device, with receiving user set to guest
endpoint.queueDeviceUpdate(device, guest); endpoint.queueDeviceUpdate(device, guest, false, user.getId(), false);
} }
if (causedByTrigger) { if (causedByTrigger) {
endpoint.queueDeviceUpdate(device, user); endpoint.queueDeviceUpdate(device, user, false, user.getId(), false);
} }
} }

View file

@ -14,7 +14,7 @@ public class MotionSensorService {
@Autowired private MotionSensorRepository motionSensorRepository; @Autowired private MotionSensorRepository motionSensorRepository;
/** /**
* Updates detection status of given motion sensor and propagates update throgh socket * Updates detection status of given motion sensor and propagates update through socket
* *
* @param sensor the motion sensor to update * @param sensor the motion sensor to update
* @param detected the new detection status * @param detected the new detection status
@ -26,7 +26,7 @@ public class MotionSensorService {
final MotionSensor toReturn = deviceService.saveAsOwner(sensor, username); final MotionSensor toReturn = deviceService.saveAsOwner(sensor, username);
sensorSocketEndpoint.queueDeviceUpdate( sensorSocketEndpoint.queueDeviceUpdate(
sensor, motionSensorRepository.findUser(sensor.getId())); sensor, motionSensorRepository.findUser(sensor.getId()), false, null, false);
return toReturn; return toReturn;
} }

View file

@ -43,7 +43,8 @@ public class SensorService {
sensor = sensor =
deviceService.saveAsOwner( deviceService.saveAsOwner(
sensor, sensorRepository.findUser(sensor.getId()).getUsername()); sensor, sensorRepository.findUser(sensor.getId()).getUsername());
endpoint.queueDeviceUpdate(sensor, sensorRepository.findUser(sensor.getId())); endpoint.queueDeviceUpdate(
sensor, sensorRepository.findUser(sensor.getId()), false, null, false);
return sensor; return sensor;
} }
} }

View file

@ -54,7 +54,7 @@ public class ThermostatService {
this.computeState(t); this.computeState(t);
deviceService.saveAsOwner(t, thermostatRepository.findUser(t.getId()).getUsername()); deviceService.saveAsOwner(t, thermostatRepository.findUser(t.getId()).getUsername());
endpoint.queueDeviceUpdate(t, thermostatRepository.findUser(t.getId())); endpoint.queueDeviceUpdate(t, thermostatRepository.findUser(t.getId()), false, null, false);
} }
public void updateStates() { public void updateStates() {

View file

@ -5,6 +5,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtils;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps; import com.google.common.collect.Multimaps;
@ -21,6 +22,8 @@ public class SensorSocketEndpoint extends Endpoint {
private Gson gson = GsonConfig.socketGson(); private Gson gson = GsonConfig.socketGson();
@Autowired private DeviceService deviceService;
private UserRepository userRepository; private UserRepository userRepository;
private JWTTokenUtils jwtTokenUtils; private JWTTokenUtils jwtTokenUtils;
@ -28,7 +31,10 @@ public class SensorSocketEndpoint extends Endpoint {
private Multimap<User, Session> authorizedClients = private Multimap<User, Session> authorizedClients =
Multimaps.synchronizedMultimap(HashMultimap.create()); Multimaps.synchronizedMultimap(HashMultimap.create());
private final Map<User, Map<Long, Device>> messages = new HashMap<>(); // messages are now stored as strings as a "hack" to capture and clone the state of the device,
// since
// fromHost and fromGuest are just mutable properties and hibernate caches the object.
private final Map<User, Map<Long, String>> messages = new HashMap<>();
@Autowired @Autowired
public SensorSocketEndpoint(UserRepository userRepository, JWTTokenUtils jwtTokenUtils) { public SensorSocketEndpoint(UserRepository userRepository, JWTTokenUtils jwtTokenUtils) {
@ -41,18 +47,33 @@ public class SensorSocketEndpoint extends Endpoint {
* *
* @param device the device update to be sent * @param device the device update to be sent
* @param u the user the device belongs * @param u the user the device belongs
* @param fromGuest value for device.fromGuest. This will be put in the device passed.
* @param fromHostId value for device.fromHostId. This will be put in the device passed.
* @param deleted value for device.deleted. This will be put in the device passed.
*/ */
public void queueDeviceUpdate(Device device, User u) { public void queueDeviceUpdate(
Device device, User u, boolean fromGuest, Long fromHostId, boolean deleted) {
synchronized (messages) { synchronized (messages) {
device.setFromGuest(fromGuest);
device.setFromHostId(fromHostId);
device.setDeleted(deleted);
// sort of an hack: force the population of thermostat measureTemperature and other
// possible
// computed fields in the future. This should already be done by the callers of this
// method but for
// whatever reason they don't do it.
deviceService.populateComputedFields(List.of(device));
messages.putIfAbsent(u, new HashMap<>()); messages.putIfAbsent(u, new HashMap<>());
messages.get(u).put(device.getId(), device); messages.get(u).put(device.getId(), gson.toJson(device));
} }
} }
/** Sends all device updates queued to be sent in a unique WebSocket message */ /** Sends all device updates queued to be sent in a unique WebSocket message */
public void flushDeviceUpdates() { public void flushDeviceUpdates() {
synchronized (messages) { synchronized (messages) {
for (Map.Entry<User, Map<Long, Device>> batchForUser : messages.entrySet()) { for (Map.Entry<User, Map<Long, String>> batchForUser : messages.entrySet()) {
broadcast(batchForUser.getKey(), batchForUser.getValue().values()); broadcast(batchForUser.getKey(), batchForUser.getValue().values());
batchForUser.getValue().clear(); batchForUser.getValue().clear();
} }
@ -66,13 +87,13 @@ public class SensorSocketEndpoint extends Endpoint {
* @param messages the message batch to send * @param messages the message batch to send
* @param u the user to which to send the message * @param u the user to which to send the message
*/ */
private void broadcast(User u, Collection<?> messages) { private void broadcast(User u, Collection<String> messages) {
if (messages.isEmpty()) return; if (messages.isEmpty()) return;
final HashSet<Session> sessions = new HashSet<>(authorizedClients.get(u)); final HashSet<Session> sessions = new HashSet<>(authorizedClients.get(u));
for (Session s : sessions) { for (Session s : sessions) {
try { try {
if (s.isOpen()) { if (s.isOpen()) {
s.getBasicRemote().sendText(gson.toJson(messages)); s.getBasicRemote().sendText("[" + String.join(",", messages) + "]");
} else { } else {
authorizedClients.remove(u, s); authorizedClients.remove(u, s);
} }