DEV: Emit a 'change' event when PresenceChannel info changes (#17088)
e.g. ``` presenceChannel = this.presence.getChannel('/blah'); presenceChannel.subscribe(); presenceChannel.on('change', (channel) => console.log(channel.users)); ``` This commit also does some refactoring to remove the use of an unnecessary EmberObject and dynamic `defineProperty` call
This commit is contained in:
parent
f723b4c322
commit
275849771f
|
@ -1,6 +1,5 @@
|
|||
import Service from "@ember/service";
|
||||
import EmberObject, { computed, defineProperty } from "@ember/object";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
import EmberObject, { computed } from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import {
|
||||
cancel,
|
||||
|
@ -20,6 +19,7 @@ import userPresent, {
|
|||
removeOnPresenceChange,
|
||||
} from "discourse/lib/user-presence";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import Evented from "@ember/object/evented";
|
||||
|
||||
const PRESENCE_INTERVAL_S = 30;
|
||||
const PRESENCE_DEBOUNCE_MS = isTesting() ? 0 : 500;
|
||||
|
@ -45,17 +45,12 @@ export class PresenceChannelNotFound extends Error {}
|
|||
|
||||
// Instances of this class are handed out to consumers. They act as
|
||||
// convenient proxies to the PresenceService and PresenceServiceState
|
||||
class PresenceChannel extends EmberObject {
|
||||
// The 'change' event is fired whenever the users list or the count change
|
||||
class PresenceChannel extends EmberObject.extend(Evented) {
|
||||
init({ name, presenceService }) {
|
||||
super.init(...arguments);
|
||||
this.name = name;
|
||||
this.presenceService = presenceService;
|
||||
defineProperty(
|
||||
this,
|
||||
"_presenceState",
|
||||
readOnly(`presenceService._presenceChannelStates.${name}`)
|
||||
);
|
||||
|
||||
this.set("present", false);
|
||||
this.set("subscribed", false);
|
||||
}
|
||||
|
@ -91,8 +86,12 @@ class PresenceChannel extends EmberObject {
|
|||
if (this.subscribed) {
|
||||
return;
|
||||
}
|
||||
await this.presenceService._subscribe(this, initialData);
|
||||
const state = await this.presenceService._subscribe(this, initialData);
|
||||
this.set("subscribed", true);
|
||||
this.set("_presenceState", state);
|
||||
|
||||
this._publishChange();
|
||||
state.on("change", this._publishChange);
|
||||
}
|
||||
|
||||
async unsubscribe() {
|
||||
|
@ -101,6 +100,14 @@ class PresenceChannel extends EmberObject {
|
|||
}
|
||||
await this.presenceService._unsubscribe(this);
|
||||
this.set("subscribed", false);
|
||||
this._presenceState.off("change", this._publishChange);
|
||||
this.set("_presenceState", null);
|
||||
this._publishChange();
|
||||
}
|
||||
|
||||
@bind
|
||||
_publishChange() {
|
||||
this.trigger("change", this);
|
||||
}
|
||||
|
||||
@computed("_presenceState.users", "subscribed")
|
||||
|
@ -128,7 +135,7 @@ class PresenceChannel extends EmberObject {
|
|||
}
|
||||
}
|
||||
|
||||
class PresenceChannelState extends EmberObject {
|
||||
class PresenceChannelState extends EmberObject.extend(Evented) {
|
||||
init({ name, presenceService }) {
|
||||
super.init(...arguments);
|
||||
this.name = name;
|
||||
|
@ -179,6 +186,7 @@ class PresenceChannelState extends EmberObject {
|
|||
);
|
||||
|
||||
this.set("_subscribedCallback", callback);
|
||||
this.trigger("change");
|
||||
}
|
||||
|
||||
// Stop subscribing to updates from the server about this channel
|
||||
|
@ -191,6 +199,7 @@ class PresenceChannelState extends EmberObject {
|
|||
this.set("_subscribedCallback", null);
|
||||
this.set("users", null);
|
||||
this.set("count", null);
|
||||
this.trigger("change");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,6 +230,7 @@ class PresenceChannelState extends EmberObject {
|
|||
|
||||
if (this.countOnly && data.count_delta !== undefined) {
|
||||
this.set("count", this.count + data.count_delta);
|
||||
this.trigger("change");
|
||||
} else if (
|
||||
!this.countOnly &&
|
||||
(data.entering_users || data.leaving_user_ids)
|
||||
|
@ -235,6 +245,7 @@ class PresenceChannelState extends EmberObject {
|
|||
this.users.removeObjects(toRemove);
|
||||
}
|
||||
this.set("count", this.users.length);
|
||||
this.trigger("change");
|
||||
} else {
|
||||
// Unexpected message
|
||||
await this._resubscribe();
|
||||
|
@ -247,7 +258,7 @@ export default class PresenceService extends Service {
|
|||
init() {
|
||||
super.init(...arguments);
|
||||
this._queuedEvents = [];
|
||||
this._presenceChannelStates = EmberObject.create();
|
||||
this._presenceChannelStates = new Map();
|
||||
this._presentProxies = new Map();
|
||||
this._subscribedProxies = new Map();
|
||||
this._initialDataRequests = new Map();
|
||||
|
@ -429,7 +440,7 @@ export default class PresenceService extends Service {
|
|||
|
||||
this._addSubscribed(channelProxy);
|
||||
const channelName = channelProxy.name;
|
||||
let state = this._presenceChannelStates[channelName];
|
||||
let state = this._presenceChannelStates.get(channelName);
|
||||
if (!state) {
|
||||
state = PresenceChannelState.create({
|
||||
name: channelName,
|
||||
|
@ -438,14 +449,15 @@ export default class PresenceService extends Service {
|
|||
this._presenceChannelStates.set(channelName, state);
|
||||
await state.subscribe(initialData);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
_unsubscribe(channelProxy) {
|
||||
const subscribedCount = this._removeSubscribed(channelProxy);
|
||||
if (subscribedCount === 0) {
|
||||
const channelName = channelProxy.name;
|
||||
this._presenceChannelStates[channelName].unsubscribe();
|
||||
this._presenceChannelStates.set(channelName, undefined);
|
||||
this._presenceChannelStates.get(channelName).unsubscribe();
|
||||
this._presenceChannelStates.delete(channelName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,12 +59,17 @@ acceptance("Presence - Subscribing", function (needs) {
|
|||
test("subscribing and receiving updates", async function (assert) {
|
||||
let presenceService = this.container.lookup("service:presence");
|
||||
let channel = presenceService.getChannel("/test/ch1");
|
||||
let changes = 0;
|
||||
const countChanges = () => changes++;
|
||||
channel.on("change", countChanges);
|
||||
|
||||
assert.strictEqual(channel.name, "/test/ch1");
|
||||
|
||||
await channel.subscribe({
|
||||
users: usersFixture(),
|
||||
last_message_id: 1,
|
||||
});
|
||||
assert.strictEqual(changes, 1);
|
||||
|
||||
assert.strictEqual(channel.users.length, 3, "it starts with three users");
|
||||
|
||||
|
@ -78,6 +83,7 @@ acceptance("Presence - Subscribing", function (needs) {
|
|||
);
|
||||
|
||||
assert.strictEqual(channel.users.length, 2, "one user is removed");
|
||||
assert.strictEqual(changes, 2);
|
||||
|
||||
publishToMessageBus(
|
||||
"/presence/test/ch1",
|
||||
|
@ -89,6 +95,8 @@ acceptance("Presence - Subscribing", function (needs) {
|
|||
);
|
||||
|
||||
assert.strictEqual(channel.users.length, 3, "one user is added");
|
||||
assert.strictEqual(changes, 3);
|
||||
channel.off("change", countChanges);
|
||||
});
|
||||
|
||||
test("fetches data when no initial state", async function (assert) {
|
||||
|
@ -216,14 +224,14 @@ acceptance("Presence - Subscribing", function (needs) {
|
|||
assert.strictEqual(channel.subscribed, false, "channel can unsubscribe");
|
||||
assert.strictEqual(
|
||||
channelDup._presenceState,
|
||||
channel._presenceState,
|
||||
"state is maintained"
|
||||
presenceService._presenceChannelStates.get(channel.name),
|
||||
"state is maintained in the subscribed channel"
|
||||
);
|
||||
|
||||
await channelDup.unsubscribe();
|
||||
assert.strictEqual(channel.subscribed, false, "channelDup can unsubscribe");
|
||||
assert.strictEqual(
|
||||
channelDup._presenceState,
|
||||
presenceService._presenceChannelStates.get(channel.name),
|
||||
undefined,
|
||||
"state is cleared"
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue