tripeur пре 4 година
родитељ
комит
0ab9ba818e

+ 1 - 1
src/main/java/fr/jaquin/bdlg/planner/solver/PlanningConstraintProvider.java

@@ -102,7 +102,7 @@ public class PlanningConstraintProvider implements ConstraintProvider {
 
   private Constraint competencyTeachingEffort(ConstraintFactory constraintFactory) {
     // We favor volonteer that already have required competencies.
-    // TODO: Idealy you should group by per volonteer and computed missing teachable
+    // TODO: Ideally you should group by per volonteer and computed missing teachable
     // competencies
     return getAssignedSlotStream(constraintFactory).penalize(
         "Avoid teaching competences to volunteer", HardMediumSoftScore.ONE_SOFT,

+ 43 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/DisconnectListener.java

@@ -0,0 +1,43 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.messaging.SessionDisconnectEvent;
+import fr.jaquin.bdlg.planner.websockets.messages.PlanningUpdateMessage;
+
+
+@Component
+public class DisconnectListener extends SubscriptionMap
+    implements ApplicationListener<SessionDisconnectEvent> {
+  @Autowired
+  private SimpMessagingTemplate simpMessagingTemplate;
+
+  @Override
+  public void onApplicationEvent(SessionDisconnectEvent event) {
+
+    String username = event.getUser().getName();
+    var map = getMap();
+    List<String> clearingList = new ArrayList<String>();
+    map.forEach((uuid, list) -> {
+      if (list.contains(username)) {
+        list.remove(username);
+        if (list.size() == 0) {
+          clearingList.add(uuid);
+        } else {
+          // Emit new list and lock owner
+          PlanningUpdateMessage msg = new PlanningUpdateMessage();
+          msg.setMethod("toast");
+          msg.setUser(username);
+          msg.setUuid(uuid);
+          msg.setPayload("Deconnection de " + username);
+          simpMessagingTemplate.convertAndSend("/planning/" + uuid, msg);
+        }
+      }
+    });
+    clearingList.forEach(uuid -> map.remove(uuid));
+  }
+}

+ 43 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/SubscriptionListener.java

@@ -0,0 +1,43 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.messaging.SessionSubscribeEvent;
+import fr.jaquin.bdlg.planner.websockets.messages.StompResponseMessage;
+import fr.jaquin.bdlg.planner.websockets.messages.StompResponseMessage.StompQuery;
+
+@Component
+public class SubscriptionListener extends SubscriptionMap
+    implements ApplicationListener<SessionSubscribeEvent> {
+  @Autowired
+  private SimpMessagingTemplate simpMessagingTemplate;
+
+  @Override
+  public void onApplicationEvent(SessionSubscribeEvent event) {
+    String simpDestination = event.getMessage().getHeaders().get("simpDestination").toString();
+
+    if (simpDestination.startsWith("/planning/")) {
+      String uuid = simpDestination.substring(10);
+      String username = event.getUser().getName();
+      var map = getMap();
+      if (!map.containsKey(uuid)) {
+        map.put(uuid, Collections.synchronizedList(new LinkedList<String>()));
+      } else {
+        // Ask first user the current version of its planning
+        StompResponseMessage msg = new StompResponseMessage();
+        msg.setDestination(username);
+        msg.setType(StompQuery.planningRequest);
+        msg.setUuid(uuid);
+        msg.setPayload("");
+        String leader = map.get(uuid).get(0);
+        simpMessagingTemplate.convertAndSendToUser(leader, "/queue/query", msg);
+      }
+      map.get(uuid).add(username);
+    }
+
+  }
+}

+ 14 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/SubscriptionMap.java

@@ -0,0 +1,14 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class SubscriptionMap {
+
+  protected static ConcurrentHashMap<String, List<String>> SubscriptionMap =
+      new ConcurrentHashMap<String, List<String>>();
+
+  public ConcurrentHashMap<String, List<String>> getMap() {
+    return SubscriptionMap;
+  }
+}

+ 44 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/UnsubscriptionListener.java

@@ -0,0 +1,44 @@
+package fr.jaquin.bdlg.planner.websockets;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.messaging.SessionUnsubscribeEvent;
+import fr.jaquin.bdlg.planner.websockets.messages.PlanningUpdateMessage;
+
+
+@Component
+public class UnsubscriptionListener extends SubscriptionMap
+    implements ApplicationListener<SessionUnsubscribeEvent> {
+  @Autowired
+  private SimpMessagingTemplate simpMessagingTemplate;
+
+  @Override
+  public void onApplicationEvent(SessionUnsubscribeEvent event) {
+    String simpDestination = event.getMessage().getHeaders().get("simpSubscriptionId").toString();
+
+    if (simpDestination.startsWith("/planning/")) {
+      String uuid = simpDestination.substring(10);
+      String username = event.getUser().getName();
+      ConcurrentHashMap<String, List<String>> map = getMap();
+      if (map.containsKey(uuid)) {
+        List<String> list = map.get(uuid);
+        list.remove(username);
+        if (list.size() == 0) {
+          map.remove(uuid);
+        } else {
+          // Emit new list and lock owner
+          PlanningUpdateMessage msg = new PlanningUpdateMessage();
+          msg.setMethod("toast");
+          msg.setUser(username);
+          msg.setUuid(uuid);
+          msg.setPayload("Deconnection de " + username);
+          simpMessagingTemplate.convertAndSend(simpDestination, msg);
+        }
+      }
+    }
+  }
+}

+ 1 - 1
src/main/java/fr/jaquin/bdlg/planner/websockets/WebSocketConfig.java

@@ -13,7 +13,7 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
   @Override
   public void configureMessageBroker(final MessageBrokerRegistry config) {
     config.setApplicationDestinationPrefixes("/app");
-    config.enableSimpleBroker("/toast", "/planning/");
+    config.enableSimpleBroker("/toast", "/planning/", "/queue/");
   }
 
   @Override

+ 8 - 1
src/main/java/fr/jaquin/bdlg/planner/websockets/WebsocketController.java

@@ -6,6 +6,8 @@ import org.springframework.messaging.handler.annotation.Payload;
 import org.springframework.messaging.handler.annotation.SendTo;
 import org.springframework.messaging.simp.SimpMessagingTemplate;
 import org.springframework.stereotype.Controller;
+import fr.jaquin.bdlg.planner.websockets.messages.PlanningUpdateMessage;
+import fr.jaquin.bdlg.planner.websockets.messages.StompResponseMessage;
 
 @Controller
 public class WebsocketController {
@@ -22,7 +24,12 @@ public class WebsocketController {
 
   @MessageMapping("/notify")
   public void shareUpdate(@Payload PlanningUpdateMessage message) throws Exception {
-    String destination = "/planning/" + message.getUuid();
+    String destination = "/app/planning/" + message.getUuid();
     simpMessagingTemplate.convertAndSend(destination, message);
   }
+
+  @MessageMapping("/response")
+  public void passQueryResponse(@Payload StompResponseMessage message) throws Exception {
+    simpMessagingTemplate.convertAndSendToUser(message.getDestination(), "/queue/query", message);
+  }
 }

+ 9 - 5
src/main/java/fr/jaquin/bdlg/planner/websockets/PlanningUpdateMessage.java → src/main/java/fr/jaquin/bdlg/planner/websockets/messages/PlanningUpdateMessage.java

@@ -1,10 +1,8 @@
-package fr.jaquin.bdlg.planner.websockets;
+package fr.jaquin.bdlg.planner.websockets.messages;
 
 public class PlanningUpdateMessage {
   public enum PlanningUpdateMethod {
-    toast, addCreneau, removeCreneau, editCreneau, addBenevole2Creneau, removeBenevole2Creneau, clearBenevole2Creneau,
-    addCreneauGroup, addCreneauGroupAt, removeCreneauGroup, editCreneauGroup, reorderCreneauGroup, addBenevole,
-    removeBenevole, editBenevole, addConstraint, removeConstraint, editConstraint, newVersion
+    toast, addCreneau, removeCreneau, editCreneau, addBenevole2Creneau, removeBenevole2Creneau, clearBenevole2Creneau, addCreneauGroup, addCreneauGroupAt, removeCreneauGroup, editCreneauGroup, reorderCreneauGroup, addBenevole, removeBenevole, editBenevole, addConstraint, removeConstraint, editConstraint, newVersion
   }
 
   private String uuid;
@@ -12,7 +10,13 @@ public class PlanningUpdateMessage {
   private String method;
   private String payload;
 
-  public PlanningUpdateMessage() {
+  public PlanningUpdateMessage() {}
+
+  public PlanningUpdateMessage(String uuid, String user, String method, String payload) {
+    this.uuid = uuid;
+    this.user = user;
+    this.method = method;
+    this.payload = payload;
   }
 
   public String getUuid() {

+ 47 - 0
src/main/java/fr/jaquin/bdlg/planner/websockets/messages/StompResponseMessage.java

@@ -0,0 +1,47 @@
+package fr.jaquin.bdlg.planner.websockets.messages;
+
+public class StompResponseMessage {
+  public enum StompQuery {
+    planningRequest, planningData
+  }
+
+  private StompQuery type;
+  private String uuid;
+  private String destination;
+  private String payload;
+
+  public StompResponseMessage() {}
+
+  public StompQuery getType() {
+    return this.type;
+  }
+
+  public void setType(StompQuery type) {
+    this.type = type;
+  }
+
+  public String getUuid() {
+    return this.uuid;
+  }
+
+  public void setUuid(String uuid) {
+    this.uuid = uuid;
+  }
+
+  public String getDestination() {
+    return this.destination;
+  }
+
+  public void setDestination(String destination) {
+    this.destination = destination;
+  }
+
+  public String getPayload() {
+    return this.payload;
+  }
+
+  public void setPayload(String payload) {
+    this.payload = payload;
+  }
+
+}