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);
|
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} roomId
|
||||||
* @param {string} name
|
* @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
|
/** The event has been sent to the server, but we have not yet received the
|
||||||
* echo. */
|
* echo. */
|
||||||
SENT: "sent",
|
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];
|
[EventStatus.QUEUED, EventStatus.NOT_SENT, EventStatus.SENT];
|
||||||
|
|
||||||
ALLOWED_TRANSITIONS[EventStatus.QUEUED] =
|
ALLOWED_TRANSITIONS[EventStatus.QUEUED] =
|
||||||
[EventStatus.SENDING];
|
[EventStatus.SENDING, EventStatus.CANCELLED];
|
||||||
|
|
||||||
ALLOWED_TRANSITIONS[EventStatus.SENT] =
|
ALLOWED_TRANSITIONS[EventStatus.SENT] =
|
||||||
[];
|
[];
|
||||||
|
|
||||||
ALLOWED_TRANSITIONS[EventStatus.NOT_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
|
* 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;
|
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);
|
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
|
* 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.
|
* '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
|
* '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.
|
* <p>This event is raised to reflect each of the transitions above.
|
||||||
*
|
*
|
||||||
|
@@ -2,22 +2,30 @@
|
|||||||
var sdk = require("../..");
|
var sdk = require("../..");
|
||||||
var HttpBackend = require("../mock-request");
|
var HttpBackend = require("../mock-request");
|
||||||
var utils = require("../test-utils");
|
var utils = require("../test-utils");
|
||||||
|
var EventStatus = sdk.EventStatus;
|
||||||
|
|
||||||
describe("MatrixClient retrying", function() {
|
describe("MatrixClient retrying", function() {
|
||||||
var baseUrl = "http://localhost.or.something";
|
var baseUrl = "http://localhost.or.something";
|
||||||
var client, httpBackend;
|
var client, httpBackend;
|
||||||
|
var scheduler;
|
||||||
var userId = "@alice:localhost";
|
var userId = "@alice:localhost";
|
||||||
var accessToken = "aseukfgwef";
|
var accessToken = "aseukfgwef";
|
||||||
|
var roomId = "!room:here";
|
||||||
|
var room;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this);
|
utils.beforeEach(this);
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
|
scheduler = new sdk.MatrixScheduler();
|
||||||
client = sdk.createClient({
|
client = sdk.createClient({
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
accessToken: accessToken
|
accessToken: accessToken,
|
||||||
|
scheduler: scheduler,
|
||||||
});
|
});
|
||||||
|
room = new sdk.Room(roomId);
|
||||||
|
client.store.storeRoom(room);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
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() {
|
describe("resending", function() {
|
||||||
xit("should be able to resend a NOT_SENT event", 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