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.web.bind.annotation.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@RestController
public class ChatController {
@@ -25,6 +28,7 @@ public class ChatController {
private final MessageService messageService;
private final WebexService webexService;
private final MqttService mqttService;
private final Set<String> expectedMessages;
@Autowired
public ChatController(
@@ -34,6 +38,7 @@ public class ChatController {
this.messageService = messageService;
this.webexService = webexService;
this.mqttService = mqttService;
this.expectedMessages = ConcurrentHashMap.newKeySet();
}
@PostMapping("/message/send")
@@ -47,11 +52,13 @@ public class ChatController {
messagePostRequest.getClientId(),
messagePostRequest.getTimeStamp());
this.webexService.post(model);
String id = this.messageService.save(model);
String messageId = this.webexService.post(model);
model.setId(messageId);
this.messageService.save(model);
expectedMessages.add(messageId);
result.setSuccess(true);
result.setData(id);
result.setData(messageId);
return ResponseEntity.
status(HttpStatus.OK)
.body(result);
@@ -96,27 +103,34 @@ public class ChatController {
@RequestHeader("X-Spark-Signature") String signature,
@RequestBody String rawPayload) {
Logger.displayInfo("========================");
ResponseBody<Void> result = ResponseBody.createEmpty();
if (!webexService.verifySignature(rawPayload, signature)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(result);
}
try {
if (!webexService.verifySignature(rawPayload, signature)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(result);
}
ObjectMapper mapper = new ObjectMapper();
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());
Message msg = webexService.fetchMessage(payload.getData().getId());
this.messageService.save(msg);
this.mqttService.publish("/chat/" + room.getClientId() + "/message", msg);
Logger.displayInfo(msg.getContent());
Logger.displayInfo(msg.getId());
Logger.displayInfo(msg.getClientId());
Logger.displayInfo(
"Webhook received : messageId=" + payload.getData().getId() +", " +
"personId=" + payload.getData().getPersonId()
);
result.setSuccess(true);
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()) {
Room room = getRoomByClient(m.getClientId());
@@ -91,7 +91,9 @@ public class WebexService {
"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) {
Logger.displayError(Arrays.toString(e.getStackTrace()));