2021-03-16 23:38:59 +01:00
|
|
|
import * as blueslip from "./blueslip";
|
2021-02-28 21:16:38 +01:00
|
|
|
import {LazySet} from "./lazy_set";
|
|
|
|
import * as people from "./people";
|
2021-04-15 17:02:54 +02:00
|
|
|
import * as sub_store from "./sub_store";
|
2021-02-28 00:53:59 +01:00
|
|
|
|
2021-01-12 21:38:01 +01:00
|
|
|
// This maps a stream_id to a LazySet of user_ids who are subscribed.
|
2021-01-31 14:43:16 +01:00
|
|
|
const stream_subscribers = new Map();
|
2021-01-12 21:38:01 +01:00
|
|
|
|
2021-03-09 16:02:52 +01:00
|
|
|
export function clear_for_testing() {
|
|
|
|
stream_subscribers.clear();
|
|
|
|
}
|
|
|
|
|
2021-01-29 17:17:32 +01:00
|
|
|
function assert_number(id) {
|
|
|
|
if (typeof id !== "number") {
|
2023-04-24 15:57:45 +02:00
|
|
|
blueslip.error("You must pass ids as numbers to peer_data", {id});
|
2021-01-29 17:17:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function get_user_set(stream_id) {
|
|
|
|
// This is an internal function to get the LazySet of users.
|
|
|
|
// We create one on the fly as necessary, but we warn in that case.
|
2021-01-30 13:38:55 +01:00
|
|
|
assert_number(stream_id);
|
|
|
|
|
2021-04-15 17:02:54 +02:00
|
|
|
if (!sub_store.get(stream_id)) {
|
2021-01-30 13:38:55 +01:00
|
|
|
blueslip.warn("We called get_user_set for an untracked stream: " + stream_id);
|
|
|
|
}
|
|
|
|
|
2021-01-29 17:17:32 +01:00
|
|
|
let subscribers = stream_subscribers.get(stream_id);
|
|
|
|
|
|
|
|
if (subscribers === undefined) {
|
|
|
|
subscribers = new LazySet([]);
|
|
|
|
stream_subscribers.set(stream_id, subscribers);
|
|
|
|
}
|
|
|
|
|
|
|
|
return subscribers;
|
|
|
|
}
|
|
|
|
|
2021-01-13 22:13:59 +01:00
|
|
|
export function is_subscriber_subset(stream_id1, stream_id2) {
|
2021-01-29 17:17:32 +01:00
|
|
|
const sub1_set = get_user_set(stream_id1);
|
|
|
|
const sub2_set = get_user_set(stream_id2);
|
2021-01-12 21:38:01 +01:00
|
|
|
|
2023-03-02 01:58:25 +01:00
|
|
|
return [...sub1_set.keys()].every((key) => sub2_set.has(key));
|
2021-01-12 21:38:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export function potential_subscribers(stream_id) {
|
|
|
|
/*
|
|
|
|
This is a list of unsubscribed users
|
|
|
|
for the current stream, who the current
|
|
|
|
user could potentially subscribe to the
|
|
|
|
stream. This may include some bots.
|
|
|
|
|
|
|
|
We currently use it for typeahead in
|
|
|
|
stream_edit.js.
|
|
|
|
|
|
|
|
This may be a superset of the actual
|
|
|
|
subscribers that you can change in some cases
|
|
|
|
(like if you're a guest?); we should refine this
|
|
|
|
going forward, especially if we use it for something
|
|
|
|
other than typeahead. (The guest use case
|
|
|
|
may be moot now for other reasons.)
|
|
|
|
*/
|
|
|
|
|
2021-01-30 13:51:21 +01:00
|
|
|
const subscribers = get_user_set(stream_id);
|
2021-01-12 21:38:01 +01:00
|
|
|
|
|
|
|
function is_potential_subscriber(person) {
|
|
|
|
// Use verbose style to force better test
|
|
|
|
// coverage, plus we may add more conditions over
|
|
|
|
// time.
|
|
|
|
if (subscribers.has(person.user_id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return people.filter_all_users(is_potential_subscriber);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get_subscriber_count(stream_id) {
|
2021-01-29 17:17:32 +01:00
|
|
|
const subscribers = get_user_set(stream_id);
|
2021-01-12 21:38:01 +01:00
|
|
|
return subscribers.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get_subscribers(stream_id) {
|
2021-01-29 17:17:32 +01:00
|
|
|
// This is our external interface for callers who just
|
|
|
|
// want an array of user_ids who are subscribed to a stream.
|
|
|
|
const subscribers = get_user_set(stream_id);
|
2021-01-12 21:38:01 +01:00
|
|
|
|
2023-03-02 01:58:25 +01:00
|
|
|
return [...subscribers.keys()];
|
2021-01-12 21:38:01 +01:00
|
|
|
}
|
|
|
|
|
2021-01-13 22:03:25 +01:00
|
|
|
export function set_subscribers(stream_id, user_ids) {
|
2021-01-12 21:38:01 +01:00
|
|
|
const subscribers = new LazySet(user_ids || []);
|
2021-01-13 22:03:25 +01:00
|
|
|
stream_subscribers.set(stream_id, subscribers);
|
2021-01-12 21:38:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export function add_subscriber(stream_id, user_id) {
|
2021-01-29 17:17:32 +01:00
|
|
|
// If stream_id/user_id are unknown to us, we will
|
|
|
|
// still track it, but we will warn.
|
|
|
|
const subscribers = get_user_set(stream_id);
|
2023-06-16 15:23:45 +02:00
|
|
|
const person = people.maybe_get_user_by_id(user_id);
|
2021-01-12 21:38:01 +01:00
|
|
|
if (person === undefined) {
|
2021-01-29 17:17:32 +01:00
|
|
|
blueslip.warn("We tried to add invalid subscriber: " + user_id);
|
2021-01-12 21:38:01 +01:00
|
|
|
}
|
|
|
|
subscribers.add(user_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function remove_subscriber(stream_id, user_id) {
|
2021-01-29 17:17:32 +01:00
|
|
|
const subscribers = get_user_set(stream_id);
|
2021-01-12 21:38:01 +01:00
|
|
|
if (!subscribers.has(user_id)) {
|
|
|
|
blueslip.warn("We tried to remove invalid subscriber: " + user_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
subscribers.delete(user_id);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-27 15:54:06 +01:00
|
|
|
export function bulk_add_subscribers({stream_ids, user_ids}) {
|
|
|
|
// We rely on our callers to validate stream_ids and user_ids.
|
|
|
|
for (const stream_id of stream_ids) {
|
2021-01-29 17:17:32 +01:00
|
|
|
const subscribers = get_user_set(stream_id);
|
2021-01-27 15:54:06 +01:00
|
|
|
for (const user_id of user_ids) {
|
|
|
|
subscribers.add(user_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function bulk_remove_subscribers({stream_ids, user_ids}) {
|
|
|
|
// We rely on our callers to validate stream_ids and user_ids.
|
|
|
|
for (const stream_id of stream_ids) {
|
2021-01-29 17:17:32 +01:00
|
|
|
const subscribers = get_user_set(stream_id);
|
2021-01-27 15:54:06 +01:00
|
|
|
for (const user_id of user_ids) {
|
|
|
|
subscribers.delete(user_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-12 21:38:01 +01:00
|
|
|
export function is_user_subscribed(stream_id, user_id) {
|
|
|
|
// Most callers should call stream_data.is_user_subscribed,
|
|
|
|
// which does additional checks.
|
|
|
|
|
2021-01-29 17:17:32 +01:00
|
|
|
const subscribers = get_user_set(stream_id);
|
2021-01-12 21:38:01 +01:00
|
|
|
return subscribers.has(user_id);
|
|
|
|
}
|