Introduce per-server user map

This allows us to store information about users in a signle place,
instead of putting it in user buffers. This is required to display
metadata about users in the channel members list.
This commit is contained in:
Simon Ser 2021-09-21 13:33:15 +02:00
parent e7f8620933
commit c66ce61029
3 changed files with 49 additions and 40 deletions

View file

@ -1234,11 +1234,17 @@ export default class App extends Component {
let bufferHeader = null; let bufferHeader = null;
if (activeBuffer) { if (activeBuffer) {
let activeUser = null;
if (activeBuffer.type == BufferType.NICK) {
activeUser = activeServer.users.get(activeBuffer.name);
}
bufferHeader = html` bufferHeader = html`
<section id="buffer-header"> <section id="buffer-header">
<${BufferHeader} <${BufferHeader}
buffer=${activeBuffer} buffer=${activeBuffer}
server=${activeServer} server=${activeServer}
user=${activeUser}
isBouncer=${isBouncer} isBouncer=${isBouncer}
bouncerNetwork=${activeBouncerNetwork} bouncerNetwork=${activeBouncerNetwork}
onChannelClick=${this.handleChannelClick} onChannelClick=${this.handleChannelClick}

View file

@ -125,23 +125,25 @@ export default function BufferHeader(props) {
`; `;
break; break;
case BufferType.NICK: case BufferType.NICK:
if (props.buffer.who) { if (props.user) {
let who = props.buffer.who;
let realname = stripANSI(who.realname || "");
let status = UserStatus.HERE; let status = UserStatus.HERE;
if (who.away) { if (props.user.offline) {
status = UserStatus.OFFLINE;
} else if (props.user.away) {
status = UserStatus.GONE; status = UserStatus.GONE;
} }
if (props.buffer.offline) {
status = UserStatus.OFFLINE; let realname = props.buffer.name;
if (props.user.realname) {
realname = stripANSI(props.user.realname || "");
} }
description = html`<${NickStatus} status=${status}/> ${realname} (${who.username}@${who.hostname})`; let mask = null;
} else if (props.buffer.offline) { if (props.user.username && props.user.hostname) {
// User is offline, but we don't have WHO information mask = `(${props.user.username}@${props.user.hostname})`;
description = html`<${NickStatus} status=${UserStatus.OFFLINE}/> ${props.buffer.name}`; }
description = html`<${NickStatus} status=${status}/> ${realname} ${mask}`;
} }
actions = html` actions = html`

View file

@ -248,6 +248,7 @@ export const State = {
id, id,
status: ServerStatus.DISCONNECTED, status: ServerStatus.DISCONNECTED,
isupport: new Map(), isupport: new Map(),
users: new irc.CaseMapMap(null, irc.CaseMapping.RFC1459),
}); });
return [id, { servers }]; return [id, { servers }];
}, },
@ -278,8 +279,6 @@ export const State = {
serverInfo: null, // if server serverInfo: null, // if server
topic: null, // if channel topic: null, // if channel
members: new irc.CaseMapMap(null, client.cm), // if channel members: new irc.CaseMapMap(null, client.cm), // if channel
who: null, // if nick
offline: false, // if nick
messages: [], messages: [],
unread: Unread.NONE, unread: Unread.NONE,
prevReadReceipt: null, prevReadReceipt: null,
@ -295,6 +294,17 @@ export const State = {
function updateBuffer(name, updater) { function updateBuffer(name, updater) {
return State.updateBuffer(state, { server: serverID, name }, updater); return State.updateBuffer(state, { server: serverID, name }, updater);
} }
function updateUser(name, updater) {
return updateServer((server) => {
let users = new irc.CaseMapMap(server.users);
let updated = updateState(users.get(name), updater);
if (!updated) {
return;
}
users.set(name, updated);
return { users };
});
}
// Don't update our internal state if it's a chat history message // Don't update our internal state if it's a chat history message
if (irc.findBatchByType(msg, "chathistory")) { if (irc.findBatchByType(msg, "chathistory")) {
@ -321,7 +331,12 @@ export const State = {
}); });
return { return {
buffers, buffers,
...updateServer({ isupport: new Map(client.isupport) }), ...updateServer((server) => {
return {
isupport: new Map(client.isupport),
users: new irc.CaseMapMap(server.users, client.cm),
};
}),
}; };
case irc.RPL_NOTOPIC: case irc.RPL_NOTOPIC:
channel = msg.params[1]; channel = msg.params[1];
@ -356,16 +371,17 @@ export const State = {
nick: msg.params[5], nick: msg.params[5],
away: msg.params[6] == 'G', // H for here, G for gone away: msg.params[6] == 'G', // H for here, G for gone
realname: last.slice(last.indexOf(" ") + 1), realname: last.slice(last.indexOf(" ") + 1),
offline: false,
}; };
return updateBuffer(who.nick, { who, offline: false }); return updateUser(who.nick, who);
case irc.RPL_ENDOFWHO: case irc.RPL_ENDOFWHO:
target = msg.params[1]; target = msg.params[1];
if (!client.isChannel(target) && target.indexOf("*") < 0) { if (!client.isChannel(target) && target.indexOf("*") < 0) {
// Not a channel nor a mask, likely a nick // Not a channel nor a mask, likely a nick
return updateBuffer(target, (buf) => { return updateUser(target, (user) => {
// TODO: mark user offline if we have old WHO info but this // TODO: mark user offline if we have old WHO info but this
// WHO reply is empty // WHO reply is empty
if (buf.who) { if (user) {
return; return;
} }
return { offline: true }; return { offline: true };
@ -404,26 +420,15 @@ export const State = {
return { members }; return { members };
}); });
case "SETNAME": case "SETNAME":
return updateBuffer(msg.prefix.name, (buf) => { return updateUser(msg.prefix.name, { realname: msg.params[0] });
let who = { ...buf.who, realname: msg.params[0] };
return { who };
});
case "CHGHOST": case "CHGHOST":
return updateBuffer(msg.prefix.name, (buf) => { return updateUser(msg.prefix.name, {
let who = { username: msg.params[0],
...buf.who, hostname: msg.params[1],
username: msg.params[0],
hostname: msg.params[1],
};
return { who };
}); });
case "AWAY": case "AWAY":
let awayMessage = msg.params[0]; let awayMessage = msg.params[0];
return updateUser(msg.prefix.name, { away: !!awayMessage });
return updateBuffer(msg.prefix.name, (buf) => {
let who = { ...buf.who, away: !!awayMessage };
return { who };
});
case "TOPIC": case "TOPIC":
channel = msg.params[0]; channel = msg.params[0];
topic = msg.params[1]; topic = msg.params[1];
@ -459,9 +464,7 @@ export const State = {
for (let target of targets) { for (let target of targets) {
let prefix = irc.parsePrefix(target); let prefix = irc.parsePrefix(target);
let update = updateBuffer(prefix.name, (buf) => { let update = updateUser(prefix.name, { offline: false });
return { offline: false };
});
state = { ...state, ...update }; state = { ...state, ...update };
} }
@ -471,9 +474,7 @@ export const State = {
for (let target of targets) { for (let target of targets) {
let prefix = irc.parsePrefix(target); let prefix = irc.parsePrefix(target);
let update = updateBuffer(prefix.name, (buf) => { let update = updateUser(prefix.name, { offline: true });
return { offline: true };
});
state = { ...state, ...update }; state = { ...state, ...update };
} }