Socket now sends sensor updates

This commit is contained in:
Claudio Maggioni 2020-03-15 13:41:57 +01:00
parent fd6103b6da
commit 5a441a6992
12 changed files with 126 additions and 14 deletions

View file

@ -1,3 +1,5 @@
<!-- vim: set ts=2 sw=2 et tw=80: -->
<html>
<head>
<meta charset="utf-8">
@ -25,6 +27,8 @@ connection.onmessage = function(evt) {
"<img src='https://maggioni.xyz/astley.gif'>";
} else if (data.authenticated === false) {
malusa.innerHTML = "<h1>Authentication error</h1>";
} else {
malusa.innerHTML += "<p><pre>" + JSON.stringify(JSON.parse(evt.data), null, 2) + "</pre></p>";
}
};

View file

@ -20,7 +20,7 @@ public class GsonConfig {
return converter;
}
private Gson gson() {
public static Gson gson() {
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter());
builder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy());

View file

@ -5,6 +5,9 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SensorSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.math.BigDecimal;
import java.security.Principal;
import java.util.*;
import java.util.List;
import javax.validation.Valid;
@ -19,6 +22,8 @@ public class SensorController {
@Autowired private SensorRepository sensorRepository;
@Autowired private SensorSocketEndpoint sensorSocketEndpoint;
@GetMapping
public List<Sensor> findAll() {
return toList(sensorRepository.findAll());
@ -35,10 +40,32 @@ public class SensorController {
newSensor.setSensor(s.getSensor());
newSensor.setName(s.getName());
newSensor.setRoomId(s.getRoomId());
newSensor.setValue(s.getValue());
return sensorRepository.save(newSensor);
}
@PutMapping("/{id}/value")
public Sensor updateValue(
@PathVariable("id") Long sensorId,
@RequestParam("value") BigDecimal value,
final Principal principal)
throws NotFoundException {
final Sensor sensor =
sensorRepository
.findByIdAndUsername(sensorId, principal.getName())
.orElseThrow(NotFoundException::new);
sensor.setValue(value);
final Sensor toReturn = sensorRepository.save(sensor);
System.out.println("sensor: " + sensor);
sensorSocketEndpoint.broadcast(sensor, sensorRepository.findUser(sensorId));
return toReturn;
}
@DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) {
sensorRepository.deleteById(id);

View file

@ -2,6 +2,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor;
import com.google.gson.annotations.SerializedName;
import java.math.BigDecimal;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.validation.constraints.NotNull;
@ -28,6 +29,8 @@ public class SensorSaveRequest {
@Enumerated(value = EnumType.STRING)
private Sensor.SensorType sensor;
@NotNull private BigDecimal value;
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
@ -60,4 +63,12 @@ public class SensorSaveRequest {
public void setSensor(Sensor.SensorType sensor) {
this.sensor = sensor;
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
}

View file

@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import com.google.gson.annotations.SerializedName;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.*;
@ -26,6 +27,11 @@ public abstract class Device {
@ApiModelProperty(hidden = true)
private long id;
@ManyToOne
@JoinColumn(name = "room_id", updatable = false, insertable = false)
@GsonExclude
private Room room;
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.

View file

@ -1,6 +1,8 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
@ -10,4 +12,23 @@ import org.springframework.data.repository.query.Param;
*/
public interface DeviceRepository<T extends Device> extends CrudRepository<T, Long> {
List<T> findByRoomId(@Param("roomId") long roomId);
/**
* Finds devices by their id and a username
*
* @param id the device id
* @param username a User's username
* @return an optional device, empty if none found
*/
@Query("SELECT d FROM Device d JOIN d.room r JOIN r.user u WHERE d.id = ?1 AND u.username = ?2")
Optional<T> findByIdAndUsername(Long id, String username);
/**
* Find the user associated with a device through a room
*
* @param deviceId the device id
* @return a user object
*/
@Query("SELECT u FROM Device d JOIN d.room r JOIN r.user u WHERE d.id = ?1")
User findUser(Long deviceId);
}

View file

@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import com.google.gson.annotations.SerializedName;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.*;
@ -128,6 +129,11 @@ public class Room {
@Column(name = "image", columnDefinition = "TEXT")
private String image;
@ManyToOne
@JoinColumn(name = "user_id", updatable = false, insertable = false)
@GsonExclude
private User user;
/**
* User that owns the house this room is in as a foreign key id. To use when updating and
* inserting from a REST call.

View file

@ -1,6 +1,8 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import com.google.gson.annotations.SerializedName;
import java.math.BigDecimal;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
@ -11,6 +13,12 @@ import javax.validation.constraints.NotNull;
@Entity
public class Sensor extends InputDevice {
private static final Map<SensorType, Integer> TYPICAL_VALUES =
Map.of(
SensorType.TEMPERATURE, 17,
SensorType.HUMIDITY, 40,
SensorType.LIGHT, 1000);
/** Type of sensor, i.e. of the thing the sensor measures. */
public enum SensorType {
/** A sensor that measures temperature in degrees celsius */
@ -27,8 +35,8 @@ public class Sensor extends InputDevice {
}
/** The value of this sensor according to its sensor type */
@Column(nullable = false)
private int value;
@Column(nullable = false, length = 10, precision = 1)
private BigDecimal value;
/** The type of this sensor */
@Column(nullable = false)
@ -42,19 +50,22 @@ public class Sensor extends InputDevice {
public void setSensor(SensorType sensor) {
this.sensor = sensor;
// TODO: setup hook for sockets live update
}
public int getValue() {
public BigDecimal getValue() {
return this.value;
}
public void setValue(int newValue) {
public void setValue(BigDecimal newValue) {
this.value = newValue;
}
public Sensor() {
super("sensor");
}
@Override
public String toString() {
return "Sensor{" + "value=" + value + ", sensor=" + sensor + '}';
}
}

View file

@ -1,6 +1,7 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import io.swagger.annotations.ApiModelProperty;
import java.util.Objects;
import javax.persistence.*;
/** A user of the Smarthut application */
@ -105,4 +106,22 @@ public class User {
+ isEnabled
+ '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id.equals(user.id)
&& name.equals(user.name)
&& username.equals(user.username)
&& password.equals(user.password)
&& email.equals(user.email)
&& isEnabled.equals(user.isEnabled);
}
@Override
public int hashCode() {
return Objects.hash(id, name, username, password, email, isEnabled);
}
}

View file

@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonConfig;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtils;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
@ -18,7 +19,7 @@ import org.springframework.stereotype.Component;
@Component
public class AuthenticationMessageListener {
private Gson gson = new Gson();
private Gson gson = GsonConfig.gson();
private JWTTokenUtils jwtTokenUtils;

View file

@ -2,6 +2,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.didThrow;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonConfig;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
@ -16,7 +17,7 @@ import org.springframework.stereotype.Component;
@Component
public class SensorSocketEndpoint extends Endpoint {
private Gson gson = new Gson();
private Gson gson = GsonConfig.gson();
private AuthenticationMessageListener authenticationMessageListener;
@ -58,9 +59,10 @@ public class SensorSocketEndpoint extends Endpoint {
*/
public long broadcast(Object message, User u) {
final Collection<Session> sessions = authorizedClients.get(u);
System.out.println(authorizedClients + " " + sessions + " " + u);
return sessions.stream()
.parallel()
.filter(didThrow(s -> s.getAsyncRemote().sendObject(gson.toJson(message))))
.filter(didThrow(s -> s.getBasicRemote().sendText(gson.toJson(message))))
.count();
}

View file

@ -1,8 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.utils;
import java.util.List;
import java.util.concurrent.Future;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@ -11,14 +9,20 @@ import java.util.stream.StreamSupport;
public final class Utils {
private Utils() {}
@FunctionalInterface
public interface ConsumerWithException<T> {
void apply(T input) throws Throwable;
}
public static <T> List<T> toList(Iterable<T> iterable) {
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
}
public static <T> Predicate<T> didThrow(Function<T, Future<?>> consumer) {
public static <T> Predicate<T> didThrow(ConsumerWithException<T> consumer) {
return (t) -> {
try {
consumer.apply(t).get();
consumer.apply(t);
System.out.println("successful");
return true;
} catch (Throwable e) {
System.err.println(e.getMessage());