message updates no longer crashing

This commit is contained in:
Michael Peters 2021-11-07 14:13:59 -06:00
parent 84c05330ba
commit 6e38c4202a
7 changed files with 64 additions and 44 deletions

View File

@ -20,9 +20,11 @@ electronMain.initialize();
(async () => {
await electron.app.whenReady();
LOG.silly('electron app is ready');
await LOG.ensureSourceMaps();
LOG.silly('base log source maps loaded');
const window = new electron.BrowserWindow({
width: 1580,//1080,
height: 720,

View File

@ -70,10 +70,8 @@ export default class Actions {
async fetchAndUpdateMessagesRecent(q: Q, server: ClientController, channel: Channel | { id: string }) {
await Util.withPotentialErrorWarnOnCancel(q, {
taskFunc: async () => {
LOG.debug('active server is s#' + this.ui.activeServer?.id);
LOG.debug('active channel is ch#' + this.ui.activeChannel?.id);
if (this.ui.activeServer === null || this.ui.activeServer.id !== server.id) return;
if (this.ui.activeChannel === null || this.ui.activeChannel.id !== server.id) return;
if (this.ui.activeChannel === null || this.ui.activeChannel.id !== channel.id) return;
let messages = await server.grabRecentMessages(channel.id, Globals.MESSAGES_PER_REQUEST);
await this.ui.setMessages(server, channel, messages, { atTop: messages.length < Globals.MESSAGES_PER_REQUEST, atBottom: true });
},
@ -89,7 +87,7 @@ export default class Actions {
await Util.withPotentialErrorWarnOnCancel(q, {
taskFunc: async () => {
if (this.ui.activeServer === null || this.ui.activeServer.id !== server.id) return;
if (this.ui.activeChannel === null || this.ui.activeChannel.id !== server.id) return;
if (this.ui.activeChannel === null || this.ui.activeChannel.id !== channel.id) return;
let topPair = this.ui.getTopMessagePair();
if (topPair == null) return;
let messages = await server.fetchMessagesBefore(channel.id, topPair.message.id, Globals.MESSAGES_PER_REQUEST);
@ -112,7 +110,7 @@ export default class Actions {
await Util.withPotentialErrorWarnOnCancel(q, {
taskFunc: async () => {
if (this.ui.activeServer === null || this.ui.activeServer.id !== server.id) return;
if (this.ui.activeChannel === null || this.ui.activeChannel.id !== server.id) return;
if (this.ui.activeChannel === null || this.ui.activeChannel.id !== channel.id) return;
let bottomPair = this.ui.getBottomMessagePair();
if (bottomPair == null) return;
let messages = await server.fetchMessagesAfter(channel.id, bottomPair.message.id, Globals.MESSAGES_PER_REQUEST);

View File

@ -14,6 +14,7 @@ import { Message, Member, Channel, Changes, ConnectionInfo, CacheServerData, Ser
import DBCache from './db-cache';
import ResourceRAMCache from './resource-ram-cache';
import RecentMessageRAMCache from './message-ram-cache';
import { channel } from 'diagnostics_channel';
// Events:
// 'connected' function() called when connected to the server
@ -23,11 +24,11 @@ import RecentMessageRAMCache from './message-ram-cache';
// 'update-server' function(serverData) called when the server metadata updates
// 'deleted-members' function(members) called when members were deleted on the server-side
// 'updated-members' function(data: Array [ { oldDataPoint, newDataPoint } ]) called when a member was updated on the server-side
// 'updated-members' function(data: Array [ { oldMember, newMember } ]) called when a member was updated on the server-side
// 'added-members' function(members) called when members were added on the server-side
// 'deleted-channels' function(channels) called when channels were deleted on the server-side
// 'updated-channels' function(data: Array [ { oldDataPoint, newDataPoint } ]) called when a channel was updated on the server-side
// 'updated-channels' function(data: Array [ { oldChannel, newChannel } ]) called when a channel was updated on the server-side
// 'added-channels' function(channels) called when channels are added on the server-side
// 'new-message' function(message) called when a message is received in a channel
@ -54,7 +55,7 @@ import RecentMessageRAMCache from './message-ram-cache';
// async setStatus(status) Set the current logged in user's status
// async setDisplayName(displayName) Sets the current logged in user's display name
// async setAvatar(avatarBu{ updated: { oldDataPoint: T, newDataPoint: T }[], added: T[], removed: T[] }
// async setAvatar(avatarBuff)
// async updateChannel(channelId, name, flavorText) Updates a channel's name and flavor text
// async queryTokens() Queries for the login tokens as [ { token, member_id, created, expires }, ... ]
@ -162,7 +163,7 @@ export default class ClientController extends EventEmitter {
await this.ensureMembers();
let oldMember = this.members.get(member.id);
if (oldMember) {
this.emit('updated-members', [ { oldDataPoint: oldMember, newDataPoint: member } ]);
this.emit('updated-members', [ { oldMember: oldMember, newMember: member } ]);
} else {
this.emit('added-members', [ member ]);
}
@ -171,7 +172,7 @@ export default class ClientController extends EventEmitter {
await this.ensureChannels();
let oldChannel = this.channels.get(channel.id);
if (oldChannel) {
this.emit('updated-channels', [ { oldDataPoint: oldChannel, newDataPoint: channel } ]);
this.emit('updated-channels', [ { oldChannel: oldChannel, newChannel: channel } ]);
} else {
this.emit('added-channels', [ channel ]);
}
@ -193,9 +194,9 @@ export default class ClientController extends EventEmitter {
}
await DBCache.updateServerMembers(this.id, Array.from(this.members.values()));
});
this.on('updated-members', async (data: { oldDataPoint: Member, newDataPoint: Member }[]) => {
for (const { oldDataPoint, newDataPoint } of data) {
this.members.set(newDataPoint.id, newDataPoint);
this.on('updated-members', async (data: { oldMember: Member, newMember: Member }[]) => {
for (const { oldMember, newMember } of data) {
this.members.set(newMember.id, newMember);
}
await DBCache.updateServerMembers(this.id, Array.from(this.members.values()));
});
@ -212,9 +213,9 @@ export default class ClientController extends EventEmitter {
}
await DBCache.updateServerChannels(this.id, Array.from(this.channels.values()));
});
this.on('updated-channels', async (data: { oldDataPoint: Channel, newDataPoint: Channel }[]) => {
for (const { oldDataPoint, newDataPoint } of data) {
this.channels.set(newDataPoint.id, newDataPoint);
this.on('updated-channels', async (data: { oldChannel: Channel, newChannel: Channel }[]) => {
for (const { oldChannel, newChannel } of data) {
this.channels.set(newChannel.id, newChannel);
}
await DBCache.updateServerChannels(this.id, Array.from(this.channels.values()));
});
@ -236,13 +237,12 @@ export default class ClientController extends EventEmitter {
// Alternatively, just store the date in the message and use order-by
this._recentMessages.dropChannel(this.id, channel.id);
});
this.on('updated-messages', async (data: { oldDataPoint: Message, newDataPoint: Message }[]) => {
LOG.debug('updated-messages: ', data);
for (let { oldDataPoint, newDataPoint } of data) {
this._recentMessages.updateMessage(this.id, oldDataPoint, newDataPoint);
this.on('updated-messages', async (channel: Channel, data: { oldMessage: Message, newMessage: Message }[]) => {
for (let { oldMessage, newMessage } of data) {
this._recentMessages.updateMessage(this.id, oldMessage, newMessage);
}
});
this.on('deleted-messages', async (messages: Message[]) => {
this.on('deleted-messages', async (_channel: Channel, messages: Message[]) => {
for (let message of messages) {
this._recentMessages.deleteMessage(this.id, message);
}
@ -515,7 +515,7 @@ export default class ClientController extends EventEmitter {
async grabRecentMessages(channelId: string, number: number): Promise<Message[]> {
let cached = this._recentMessages.getRecentMessages(this.id, channelId, number);
if (cached != null) return cached;
if (cached !== null) return cached;
return await this.fetchMessagesRecent(channelId, number);
}
@ -621,7 +621,7 @@ export default class ClientController extends EventEmitter {
this.emit('added-members', changes.added);
}
if (changes.updated.length > 0) {
this.emit('updated-members', changes.updated);
this.emit('updated-members', changes.updated.map(change => ({ oldMember: change.oldDataPoint, newMember: change.newDataPoint })));
}
return true;
@ -662,7 +662,7 @@ export default class ClientController extends EventEmitter {
this.emit('added-channels', changes.added);
}
if (changes.updated.length > 0) {
this.emit('updated-channels', changes.updated);
this.emit('updated-channels', changes.updated.map(change => ({ oldChannel: change.oldDataPoint, newChannel: change.newDataPoint })));
}
return true;

View File

@ -38,6 +38,9 @@ window.addEventListener('DOMContentLoaded', () => {
document.body.classList.remove('preload');
(async () => {
await LOG.ensureSourceMaps();
LOG.silly('web client log source maps loaded');
await DBCache.connect();
await DBCache.init();
@ -149,12 +152,12 @@ window.addEventListener('DOMContentLoaded', () => {
await ui.deleteMembers(server, members);
});
controller.on('updated-members', async (server: ClientController, data: { oldDataPoint: Member, newDataPoint: Member }[]) => {
controller.on('updated-members', async (server: ClientController, data: { oldMember: Member, newMember: Member }[]) => {
LOG.debug(data.length + ' updated members s#' + server.id);
await ui.updateMembers(server, data);
if (
ui.activeConnection !== null &&
data.find((c: any) => c.newDataPoint.id === (ui.activeConnection as ConnectionInfo).id)
data.find(change => change.newMember.id === (ui.activeConnection as ConnectionInfo).id)
) {
await actions.fetchAndUpdateConnection(server);
}
@ -170,7 +173,7 @@ window.addEventListener('DOMContentLoaded', () => {
await ui.deleteChannels(server, channels);
});
controller.on('updated-channels', async (server: ClientController, data: { oldDataPoint: Channel, newDataPoint: Channel }[]) => {
controller.on('updated-channels', async (server: ClientController, data: { oldChannel: Channel, newChannel: Channel }[]) => {
LOG.debug(data.length + ' updated channels');
await ui.updateChannels(actions, server, data);
});
@ -187,7 +190,7 @@ window.addEventListener('DOMContentLoaded', () => {
await ui.deleteMessages(server, channel, messages);
});
controller.on('updated-messages', async (server: ClientController, channel: Channel, data: { oldDataPoint: Message, newDataPoint: Message }[]) => {
controller.on('updated-messages', async (server: ClientController, channel: Channel, data: { oldMessage: Message, newMessage: Message }[]) => {
LOG.debug(data.length + ' updated messages');
// messages were updated on the server-side
await ui.updateMessages(server, channel, data);
@ -218,12 +221,12 @@ window.addEventListener('DOMContentLoaded', () => {
// messages that were updated (currently extraneous)
// Note: this should never happen since these should be handled by updated-messages
// Note: this may be used to replace dummy pre-sent messages
let toUpdate: { newDataPoint: Message, oldDataPoint: Message }[] = [];
let toUpdate: { newMessage: Message, oldMessage: Message }[] = [];
for (let addedMessage of addedBefore.values()) {
if (ui.messagePairs.has(addedMessage.id)) {
toUpdate.push({
newDataPoint: addedMessage,
oldDataPoint: (ui.messagePairs.get(addedMessage.id) as { message: Message, element: HTMLElement }).message
newMessage: addedMessage,
oldMessage: (ui.messagePairs.get(addedMessage.id) as { message: Message, element: HTMLElement }).message
});
}
}

View File

@ -263,10 +263,9 @@ export default class UI {
});
}
public async updateChannels(actions: Actions, server: ClientController, data: { oldDataPoint: Channel, newDataPoint: Channel }[]): Promise<void> {
public async updateChannels(actions: Actions, server: ClientController, data: { oldChannel: Channel, newChannel: Channel }[]): Promise<void> {
await this.lockChannels(server, () => {
for (const { oldDataPoint, newDataPoint } of data) {
let newChannel = newDataPoint;
for (const { oldChannel, newChannel } of data) {
let oldElement = this.q.$('#channel-list .channel[meta-id="' + newChannel.id + '"]');
let newElement = createChannel(this.document, this.q, this, actions, server, newChannel);
oldElement.parentElement?.replaceChild(newElement, oldElement);
@ -359,10 +358,9 @@ export default class UI {
});
}
public async updateMembers(server: ClientController, data: { oldDataPoint: Member, newDataPoint: Member }[]): Promise<void> {
public async updateMembers(server: ClientController, data: { oldMember: Member, newMember: Member }[]): Promise<void> {
await this.lockMembers(server, () => {
for (const { oldDataPoint, newDataPoint } of data) {
let newMember = newDataPoint;
for (const { oldMember, newMember } of data) {
let oldElement = this.q.$_('#server-members .member[meta-id="' + newMember.id + '"]');
if (oldElement) {
let newElement = createMember(this.q, server, newMember);
@ -373,8 +371,7 @@ export default class UI {
});
if (this.activeChannel === null) return;
await this.lockMessages(server, this.activeChannel, () => {
for (const { oldDataPoint, newDataPoint } of data) {
let newMember = newDataPoint;
for (const { oldMember, newMember } of data) {
let newStyle = newMember.roleColor ? 'color: ' + newMember.roleColor : null;
let newName = newMember.displayName;
// the extra query selectors may be overkill
@ -635,11 +632,9 @@ export default class UI {
});
}
public async updateMessages(server: ClientController, channel: Channel, data: { oldDataPoint: Message, newDataPoint: Message }[]): Promise<void> {
public async updateMessages(server: ClientController, channel: Channel, data: { oldMessage: Message, newMessage: Message }[]): Promise<void> {
await this.lockMessages(server, channel, () => {
for (const { oldDataPoint, newDataPoint } of data) {
let oldMessage = oldDataPoint;
let newMessage = newDataPoint;
for (const { oldMessage, newMessage } of data) {
if (this.messagePairs.has(oldMessage.id)) {
let oldElement = (this.messagePairs.get(oldMessage.id) as { message: Message, element: HTMLElement }).element;
let prevElement = Q.previousElement(oldElement);

View File

@ -146,6 +146,8 @@ export default class Logger {
private name: string;
private console: Console;
private sourceMaps = new Map<string, SourceMapConsumer>();
private hasSourceMaps = false;
private sourceMapsWaiters: (() => void)[] = [];
private constructor(name: string, processConsole?: Console) {
this.name = name;
@ -158,10 +160,25 @@ export default class Logger {
(async () => {
let sourceMaps = await getStaticSourceMaps();
log.sourceMaps = sourceMaps;
log.onGetSourceMaps();
})();
return log;
}
private onGetSourceMaps() {
this.hasSourceMaps = true;
for (let sourceMapWaiter of this.sourceMapsWaiters) {
sourceMapWaiter();
}
}
public async ensureSourceMaps(): Promise<void> {
if (this.hasSourceMaps) return;
return new Promise((resolve) => {
this.sourceMapsWaiters.push(resolve);
});
}
/** Logs a message and potentially corresponding data */
private log(level: LoggerLevel, message: string | null, data?: Error | any): void {
let frames: StackTrace.Frame[] = StackTrace.parse(new Error());

View File

@ -1,3 +1,6 @@
Moved to https://cowfield.atlassian.net
------ Minimum Viable Product ------
Clean up TypeScript type names
@ -6,6 +9,8 @@ Clean up HTML / CSS
Get rid of all static classes that store state
There's a bug with 'undefined' when
Unit tests would be pretty nice for the cache stuff
Get rid of the duplicate fetch metadata query at startup (fetch-server)