Handle duplicate webhooks

This commit is contained in:
2026-01-02 22:41:50 +01:00
parent c7bd24a286
commit 81a8afa332
2 changed files with 31 additions and 15 deletions

View File

@@ -17,7 +17,10 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@RestController @RestController
public class ChatController { public class ChatController {
@@ -25,6 +28,7 @@ public class ChatController {
private final MessageService messageService; private final MessageService messageService;
private final WebexService webexService; private final WebexService webexService;
private final MqttService mqttService; private final MqttService mqttService;
private final Set<String> expectedMessages;
@Autowired @Autowired
public ChatController( public ChatController(
@@ -34,6 +38,7 @@ public class ChatController {
this.messageService = messageService; this.messageService = messageService;
this.webexService = webexService; this.webexService = webexService;
this.mqttService = mqttService; this.mqttService = mqttService;
this.expectedMessages = ConcurrentHashMap.newKeySet();
} }
@PostMapping("/message/send") @PostMapping("/message/send")
@@ -47,11 +52,13 @@ public class ChatController {
messagePostRequest.getClientId(), messagePostRequest.getClientId(),
messagePostRequest.getTimeStamp()); messagePostRequest.getTimeStamp());
this.webexService.post(model); String messageId = this.webexService.post(model);
String id = this.messageService.save(model); model.setId(messageId);
this.messageService.save(model);
expectedMessages.add(messageId);
result.setSuccess(true); result.setSuccess(true);
result.setData(id); result.setData(messageId);
return ResponseEntity. return ResponseEntity.
status(HttpStatus.OK) status(HttpStatus.OK)
.body(result); .body(result);
@@ -96,27 +103,34 @@ public class ChatController {
@RequestHeader("X-Spark-Signature") String signature, @RequestHeader("X-Spark-Signature") String signature,
@RequestBody String rawPayload) { @RequestBody String rawPayload) {
Logger.displayInfo("========================");
ResponseBody<Void> result = ResponseBody.createEmpty(); ResponseBody<Void> result = ResponseBody.createEmpty();
if (!webexService.verifySignature(rawPayload, signature)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(result);
}
try { try {
if (!webexService.verifySignature(rawPayload, signature)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(result);
}
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
WebexWebhook payload = mapper.readValue(rawPayload, WebexWebhook.class); WebexWebhook payload = mapper.readValue(rawPayload, WebexWebhook.class);
boolean accepted = expectedMessages.remove(payload.getData().getId());
if (accepted) {
Logger.displayInfo("Accepted");
} else {
Logger.displayInfo("Rejected");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result);
}
Room room = webexService.getRoomById(payload.getData().getRoomId()); Room room = webexService.getRoomById(payload.getData().getRoomId());
Message msg = webexService.fetchMessage(payload.getData().getId()); Message msg = webexService.fetchMessage(payload.getData().getId());
this.messageService.save(msg); this.messageService.save(msg);
this.mqttService.publish("/chat/" + room.getClientId() + "/message", msg); this.mqttService.publish("/chat/" + room.getClientId() + "/message", msg);
Logger.displayInfo(msg.getContent()); Logger.displayInfo(
Logger.displayInfo(msg.getId()); "Webhook received : messageId=" + payload.getData().getId() +", " +
Logger.displayInfo(msg.getClientId()); "personId=" + payload.getData().getPersonId()
);
result.setSuccess(true); result.setSuccess(true);
return ResponseEntity.ok(result); return ResponseEntity.ok(result);

View File

@@ -77,7 +77,7 @@ public class WebexService {
} }
} }
public void post(Message m) throws ServiceException { public String post(Message m) throws ServiceException {
try (HttpClient client = HttpClient.newHttpClient()) { try (HttpClient client = HttpClient.newHttpClient()) {
Room room = getRoomByClient(m.getClientId()); Room room = getRoomByClient(m.getClientId());
@@ -91,7 +91,9 @@ public class WebexService {
"text", m.getContent() "text", m.getContent()
); );
sendPostRequest(client, "https://webexapis.com/v1/messages", botToken, body); String response = sendPostRequest(client, "https://webexapis.com/v1/messages", botToken, body);
JsonNode jsonNode = mapper.readTree(response);
return jsonNode.get("id").asText();
} catch (Exception e) { } catch (Exception e) {
Logger.displayError(Arrays.toString(e.getStackTrace())); Logger.displayError(Arrays.toString(e.getStackTrace()));