Per-channel sync

Discord no longer seems to support per-guild sync, but per-channel sync
was added. Switch to that syncing user lists on channel join.

Fixes: #201

Signed-off-by: Artem Savkov <artem.savkov@gmail.com>
This commit is contained in:
Artem Savkov 2020-02-06 13:32:26 +01:00
parent 6500934bba
commit 1b9870a0ea
4 changed files with 65 additions and 1 deletions

View File

@ -800,6 +800,28 @@ void discord_handle_message(struct im_connection *ic, json_value *minfo,
}
}
static void parse_list_update_item(struct im_connection *ic,
const char *guild_id, const char *op,
json_value *item)
{
discord_data *dd = ic->proto_data;
json_value *member = json_o_get(item, "member");
json_value *uinfo = json_o_get(member, "user");
json_value *pinfo = json_o_get(member, "presence");
if (g_strcmp0(op, "DELETE") == 0) {
discord_handle_user(ic, uinfo, guild_id, ACTION_DELETE);
} else {
user_info *user = get_user(dd, json_o_str(uinfo, "id"), guild_id,
SEARCH_ID);
if (user == NULL) {
discord_handle_user(ic, uinfo, guild_id, ACTION_CREATE);
}
discord_handle_presence(ic, pinfo, guild_id);
}
}
gboolean discord_parse_message(struct im_connection *ic, gchar *buf, guint64 size)
{
discord_data *dd = ic->proto_data;
@ -944,6 +966,33 @@ gboolean discord_parse_message(struct im_connection *ic, gchar *buf, guint64 siz
discord_handle_presence(ic, pinfo, id);
}
}
} else if (g_strcmp0(event, "GUILD_MEMBER_LIST_UPDATE") == 0) {
json_value *data = json_o_get(js, "d");
json_value *ops = json_o_get(data, "ops");
const char *guild_id = json_o_str(data, "guild_id");
if (ops != NULL && ops->type == json_array) {
for (int oidx = 0; oidx < ops->u.array.length; oidx++) {
const char *op = json_o_str(ops->u.array.values[oidx], "op");
if (g_strcmp0(op, "SYNC") == 0) {
json_value *items = json_o_get(ops->u.array.values[oidx], "items");
if (items != NULL && items->type == json_array) {
for (int iidx = 0; iidx < items->u.array.length; iidx++) {
json_value *item = items->u.array.values[iidx];
if (item != NULL && json_o_get(item, "member") != NULL) {
parse_list_update_item(ic, guild_id, op, item);
}
}
}
} else {
json_value *item = json_o_get(ops->u.array.values[oidx], "item");
if (item != NULL && json_o_get(item, "member") != NULL) {
parse_list_update_item(ic, guild_id, op, item);
}
}
}
}
} else if (g_strcmp0(event, "VOICE_STATE_UPDATE") == 0) {
json_value *vsinfo = json_o_get(js, "d");
discord_handle_voice_state(ic, vsinfo, json_o_str(vsinfo, "guild_id"));

View File

@ -98,6 +98,16 @@ void discord_ws_sync_server(discord_data *dd, const char *id)
g_string_free(buf, TRUE);
}
void discord_ws_sync_channel(discord_data *dd, const char *guild_id,
const char *channel_id, unsigned int members)
{
GString *buf = g_string_new("");
g_string_printf(buf, "{\"op\":%d,\"d\":{\"guild_id\":\"%s\",\"typing\":true,\"activities\":true,\"channels\":{\"%s\":[[0,%u]]}}}",
OPCODE_REQUEST_SYNC_CHANNEL, guild_id, channel_id, members);
discord_ws_send_payload(dd, buf->str, buf->len);
g_string_free(buf, TRUE);
}
static gboolean discord_ws_heartbeat_timeout(gpointer data, gint fd,
b_input_condition cond)
{

View File

@ -29,7 +29,9 @@ typedef enum {
OPCODE_INVALID_SESSION,
OPCODE_HELLO,
OPCODE_HEARTBEAT_ACK,
OPCODE_REQUEST_SYNC
OPCODE_REQUEST_SYNC,
OPCODE_UNKNOWN,
OPCODE_REQUEST_SYNC_CHANNEL
} discord_opcode;
gboolean discord_ws_keepalive_loop(gpointer data, gint fd,
@ -40,3 +42,5 @@ void discord_ws_cleanup(discord_data *dd);
void discord_ws_set_status(struct im_connection *ic, gchar *status,
gchar *message);
void discord_ws_sync_server(discord_data *dd, const char *id);
void discord_ws_sync_channel(discord_data *dd, const char *guild_id,
const char *channel_id, unsigned int members);

View File

@ -195,6 +195,7 @@ struct groupchat *discord_chat_do_join(struct im_connection *ic,
if (cinfo != NULL && cinfo->type == CHANNEL_TEXT) {
sinfo = cinfo->to.channel.sinfo;
gc = imcb_chat_new(ic, cinfo->to.channel.name);
discord_ws_sync_channel(dd, sinfo->id, cinfo->id, 0);
if (is_auto_join) {
imcb_chat_name_hint(gc, room);