You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-06 12:02:40 +03:00
Support for cancelling pending events
Implement client.cancelPendingEvent which will cancel queued or not_sent events
This commit is contained in:
@@ -725,6 +725,28 @@ MatrixClient.prototype.resendEvent = function(event, room) {
|
||||
return _sendEvent(this, room, event);
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel a queued or unsent event.
|
||||
*
|
||||
* @param {MatrixEvent} event Event to cancel
|
||||
* @throws Error if the event is not in QUEUED or NOT_SENT state
|
||||
*/
|
||||
MatrixClient.prototype.cancelPendingEvent = function(event) {
|
||||
if ([EventStatus.QUEUED, EventStatus.NOT_SENT].indexOf(event.status) < 0) {
|
||||
throw new Error("cannot cancel an event with status " + event.status);
|
||||
}
|
||||
|
||||
// first tell the scheduler to forget about it, if it's queued
|
||||
if (this.scheduler) {
|
||||
this.scheduler.removeEventFromQueue(event);
|
||||
}
|
||||
|
||||
// then tell the room about the change of state, which will remove it
|
||||
// from the room's list of pending events.
|
||||
var room = this.getRoom(event.getRoomId());
|
||||
_updatePendingEventStatus(room, event, EventStatus.CANCELLED);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} roomId
|
||||
* @param {string} name
|
||||
|
@@ -36,6 +36,9 @@ module.exports.EventStatus = {
|
||||
/** The event has been sent to the server, but we have not yet received the
|
||||
* echo. */
|
||||
SENT: "sent",
|
||||
|
||||
/** The event was cancelled before it was successfully sent. */
|
||||
CANCELLED: "cancelled",
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -729,13 +729,16 @@ ALLOWED_TRANSITIONS[EventStatus.SENDING] =
|
||||
[EventStatus.QUEUED, EventStatus.NOT_SENT, EventStatus.SENT];
|
||||
|
||||
ALLOWED_TRANSITIONS[EventStatus.QUEUED] =
|
||||
[EventStatus.SENDING];
|
||||
[EventStatus.SENDING, EventStatus.CANCELLED];
|
||||
|
||||
ALLOWED_TRANSITIONS[EventStatus.SENT] =
|
||||
[];
|
||||
|
||||
ALLOWED_TRANSITIONS[EventStatus.NOT_SENT] =
|
||||
[EventStatus.SENDING, EventStatus.QUEUED];
|
||||
[EventStatus.SENDING, EventStatus.QUEUED, EventStatus.CANCELLED];
|
||||
|
||||
ALLOWED_TRANSITIONS[EventStatus.CANCELLED] =
|
||||
[];
|
||||
|
||||
/**
|
||||
* Update the status / event id on a pending event, to reflect its transmission
|
||||
@@ -797,6 +800,17 @@ Room.prototype.updatePendingEvent = function(event, newStatus, newEventId) {
|
||||
this._eventIdToTimeline[newEventId] = existingTimeline;
|
||||
}
|
||||
}
|
||||
else if (newStatus == EventStatus.CANCELLED) {
|
||||
// remove it from the pending event list, or the timeline.
|
||||
if (this._pendingEventList) {
|
||||
utils.removeElement(
|
||||
this._pendingEventList,
|
||||
function(ev) { return ev.getId() == oldEventId; },
|
||||
false
|
||||
);
|
||||
}
|
||||
this.removeEvent(oldEventId);
|
||||
}
|
||||
|
||||
this.emit("Room.localEchoUpdated", event, this, event.getId(), oldStatus);
|
||||
};
|
||||
@@ -1479,9 +1493,10 @@ module.exports = Room;
|
||||
* arrived, the event is updated with a new event id and the status is set to
|
||||
* 'SENT'. The server-generated fields are of course not updated yet.
|
||||
*
|
||||
* <p>Finally, the /send might fail. In this case, the event's status is set to
|
||||
* <p>If the /send fails, In this case, the event's status is set to
|
||||
* 'NOT_SENT'. If it is later resent, the process starts again, setting the
|
||||
* status to 'SENDING'.
|
||||
* status to 'SENDING'. Alternatively, the message may be cancelled, which
|
||||
* removes the event from the room, and sets the status to 'CANCELLED'.
|
||||
*
|
||||
* <p>This event is raised to reflect each of the transitions above.
|
||||
*
|
||||
|
@@ -2,22 +2,30 @@
|
||||
var sdk = require("../..");
|
||||
var HttpBackend = require("../mock-request");
|
||||
var utils = require("../test-utils");
|
||||
var EventStatus = sdk.EventStatus;
|
||||
|
||||
describe("MatrixClient retrying", function() {
|
||||
var baseUrl = "http://localhost.or.something";
|
||||
var client, httpBackend;
|
||||
var scheduler;
|
||||
var userId = "@alice:localhost";
|
||||
var accessToken = "aseukfgwef";
|
||||
var roomId = "!room:here";
|
||||
var room;
|
||||
|
||||
beforeEach(function() {
|
||||
utils.beforeEach(this);
|
||||
httpBackend = new HttpBackend();
|
||||
sdk.request(httpBackend.requestFn);
|
||||
scheduler = new sdk.MatrixScheduler();
|
||||
client = sdk.createClient({
|
||||
baseUrl: baseUrl,
|
||||
userId: userId,
|
||||
accessToken: accessToken
|
||||
accessToken: accessToken,
|
||||
scheduler: scheduler,
|
||||
});
|
||||
room = new sdk.Room(roomId);
|
||||
client.store.storeRoom(room);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@@ -40,6 +48,49 @@ describe("MatrixClient retrying", function() {
|
||||
|
||||
});
|
||||
|
||||
it("should mark events as EventStatus.CANCELLED when cancelled", function(done) {
|
||||
|
||||
// send a couple of events; the second will be queued
|
||||
var ev1, ev2;
|
||||
client.sendMessage(roomId, "m1").then(function(ev) {
|
||||
expect(ev).toEqual(ev1);
|
||||
});
|
||||
client.sendMessage(roomId, "m2").then(function(ev) {
|
||||
expect(ev).toEqual(ev2);
|
||||
});
|
||||
|
||||
// both events should be in the timeline at this point
|
||||
var tl = room.getLiveTimeline().getEvents();
|
||||
expect(tl.length).toEqual(2);
|
||||
ev1 = tl[0];
|
||||
ev2 = tl[1];
|
||||
|
||||
expect(ev1.status).toEqual(EventStatus.SENDING);
|
||||
expect(ev2.status).toEqual(EventStatus.QUEUED);
|
||||
|
||||
// now we can cancel the second and check everything looks sane
|
||||
client.cancelPendingEvent(ev2);
|
||||
expect(ev2.status).toEqual(EventStatus.CANCELLED);
|
||||
expect(tl.length).toEqual(1);
|
||||
|
||||
// shouldn't be able to cancel the first message yet
|
||||
expect(function() { client.cancelPendingEvent(ev1); })
|
||||
.toThrow();
|
||||
|
||||
// fail the first send
|
||||
httpBackend.when("PUT", "/send/m.room.message/")
|
||||
.respond(400);
|
||||
httpBackend.flush().then(function() {
|
||||
expect(ev1.status).toEqual(EventStatus.NOT_SENT);
|
||||
expect(tl.length).toEqual(1);
|
||||
|
||||
// cancel the first message
|
||||
client.cancelPendingEvent(ev1);
|
||||
expect(ev1.status).toEqual(EventStatus.CANCELLED);
|
||||
expect(tl.length).toEqual(0);
|
||||
}).catch(utils.failTest).done(done);
|
||||
});
|
||||
|
||||
describe("resending", function() {
|
||||
xit("should be able to resend a NOT_SENT event", function() {
|
||||
|
||||
|
@@ -1225,4 +1225,76 @@ describe("Room", function() {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updatePendingEvent", function() {
|
||||
it("should remove cancelled events from the pending list", function() {
|
||||
var room = new Room(roomId, {
|
||||
pendingEventOrdering: "detached"
|
||||
});
|
||||
var eventA = utils.mkMessage({
|
||||
room: roomId, user: userA, event: true
|
||||
});
|
||||
eventA.status = EventStatus.SENDING;
|
||||
var eventId = eventA.getId();
|
||||
|
||||
room.addPendingEvent(eventA, "TXN1");
|
||||
expect(room.getPendingEvents()).toEqual(
|
||||
[eventA]
|
||||
);
|
||||
|
||||
// the event has to have been failed or queued before it can be
|
||||
// cancelled
|
||||
room.updatePendingEvent(eventA, EventStatus.NOT_SENT);
|
||||
|
||||
var callCount = 0;
|
||||
room.on("Room.localEchoUpdated",
|
||||
function(event, emitRoom, oldEventId, oldStatus) {
|
||||
expect(event).toEqual(eventA);
|
||||
expect(event.status).toEqual(EventStatus.CANCELLED);
|
||||
expect(emitRoom).toEqual(room);
|
||||
expect(oldEventId).toEqual(eventId);
|
||||
expect(oldStatus).toEqual(EventStatus.NOT_SENT);
|
||||
callCount++;
|
||||
});
|
||||
|
||||
room.updatePendingEvent(eventA, EventStatus.CANCELLED);
|
||||
expect(room.getPendingEvents()).toEqual([]);
|
||||
expect(callCount).toEqual(1);
|
||||
});
|
||||
|
||||
|
||||
it("should remove cancelled events from the timeline", function() {
|
||||
var room = new Room(roomId);
|
||||
var eventA = utils.mkMessage({
|
||||
room: roomId, user: userA, event: true
|
||||
});
|
||||
eventA.status = EventStatus.SENDING;
|
||||
var eventId = eventA.getId();
|
||||
|
||||
room.addPendingEvent(eventA, "TXN1");
|
||||
expect(room.getLiveTimeline().getEvents()).toEqual(
|
||||
[eventA]
|
||||
);
|
||||
|
||||
// the event has to have been failed or queued before it can be
|
||||
// cancelled
|
||||
room.updatePendingEvent(eventA, EventStatus.NOT_SENT);
|
||||
|
||||
var callCount = 0;
|
||||
room.on("Room.localEchoUpdated",
|
||||
function(event, emitRoom, oldEventId, oldStatus) {
|
||||
expect(event).toEqual(eventA);
|
||||
expect(event.status).toEqual(EventStatus.CANCELLED);
|
||||
expect(emitRoom).toEqual(room);
|
||||
expect(oldEventId).toEqual(eventId);
|
||||
expect(oldStatus).toEqual(EventStatus.NOT_SENT);
|
||||
callCount++;
|
||||
});
|
||||
|
||||
room.updatePendingEvent(eventA, EventStatus.CANCELLED);
|
||||
expect(room.getLiveTimeline().getEvents()).toEqual([]);
|
||||
expect(callCount).toEqual(1);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user