Push multiple updates in each update event

Refactor HostUpdatesEvent, InstanceDetailsUpdatesEvent, ModUpdatesEvent,
ModPackUpdatesEvent and UserUpdatesEvent to have multiple updates of the
entities they support in each event. This is intended to make the events
capable of syncing the entire list that they represent.
This commit is contained in:
Hornwitser committed 2023-12-08 22:01:46 +01:00
1 parent f12a9926eb
commit 20330bc2c3
18 files changed
+215 -190

No files matched your search

+11 -11
View File
@@ -229,29 +229,29 @@ export default class BaseControllerPlugin {
async onPrepareHostDisconnect(connection: HostConnection) { }
/**
* Called when a mod pack is updated
* Called when one or more mod packs are updated
*
* Invoked when a mod pack has been added, updated or deleted in the
* cluster.
* Invoked when one or more mod pack have been added, updated or deleted
* in the cluster.
*
* If the mod pack has been deleted its `.isDeleted` property will be
* If a mod pack has been deleted its `.isDeleted` property will be
* true.
*
* @param modPack - Mod pack that updated.
* @param modPacks - Mod packs that updated.
*/
async onModPackUpdated(modPack: ModPack) { }
async onModPacksUpdated(modPacks: ModPack[]) { }
/**
* Called when a mod stored on the controller is updated
* Called when one or more mod stored on the controller are updated
*
* Invoked when a mod has been added, updated or deleted from the pool
* of shared mods stored on the cluster.
* Invoked when one or more mods have been added, updated or deleted
* from the pool of shared mods stored on the cluster.
*
* If a mod has been deleted its `.isDeleted` property will be true.
*
* @param mod - Mod that updated.
* @param mods - Mods that updated.
*/
async onModUpdated(mod: ModInfo) { }
async onModsUpdated(mods: ModInfo[]) { }
/**
* Called when a player joins or leaves an instance
+11 -11
View File
@@ -195,7 +195,7 @@ export default class ControlConnection extends BaseConnection {
hostConnection.connector.terminate();
}
this._controller.hostUpdated(host as HostInfo);
this._controller.hostsUpdated([host]);
}
async handleHostListRequest(): Promise<lib.HostDetails[]> {
@@ -434,7 +434,7 @@ export default class ControlConnection extends BaseConnection {
throw new lib.RequestError(`Mod pack with ID ${modPack.id} already exist`);
}
this._controller.modPacks.set(modPack.id, modPack);
this._controller.modPackUpdated(modPack);
this._controller.modPacksUpdated([modPack]);
}
async handleModPackUpdateRequest(request: lib.ModPackUpdateRequest) {
@@ -443,7 +443,7 @@ export default class ControlConnection extends BaseConnection {
throw new lib.RequestError(`Mod pack with ID ${modPack.id} does not exist`);
}
this._controller.modPacks.set(modPack.id, modPack);
this._controller.modPackUpdated(modPack);
this._controller.modPacksUpdated([modPack]);
}
async handleModPackDeleteRequest(request: lib.ModPackDeleteRequest) {
@@ -454,7 +454,7 @@ export default class ControlConnection extends BaseConnection {
}
modPack.isDeleted = true;
this._controller.modPacks.delete(id);
this._controller.modPackUpdated(modPack);
this._controller.modPacksUpdated([modPack]);
}
async handleModGetRequest(request: lib.ModGetRequest) {
@@ -680,7 +680,7 @@ export default class ControlConnection extends BaseConnection {
async handleUserCreateRequest(request: lib.UserCreateRequest) {
let user = this._controller.userManager.createUser(request.name);
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
}
async handleUserRevokeTokenRequest(request: lib.UserRevokeTokenRequest) {
@@ -698,7 +698,7 @@ export default class ControlConnection extends BaseConnection {
controlConnection.connector.terminate();
}
}
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
}
async handleUserUpdateRolesRequest(request: lib.UserUpdateRolesRequest) {
@@ -715,7 +715,7 @@ export default class ControlConnection extends BaseConnection {
user.roleIds = new Set(request.roles);
this._controller.userPermissionsUpdated(user);
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
}
async handleUserSetAdminRequest(request: lib.UserSetAdminRequest) {
@@ -731,7 +731,7 @@ export default class ControlConnection extends BaseConnection {
}
user.isAdmin = admin;
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
this._controller.sendTo("allInstances", new lib.InstanceAdminlistUpdateEvent(name, admin));
}
@@ -749,7 +749,7 @@ export default class ControlConnection extends BaseConnection {
user.isBanned = banned;
user.banReason = reason;
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
this._controller.sendTo("allInstances", new lib.InstanceBanlistUpdateEvent(name, banned, reason));
}
@@ -766,7 +766,7 @@ export default class ControlConnection extends BaseConnection {
}
user.isWhitelisted = whitelisted;
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
this._controller.sendTo("allInstances", new lib.InstanceWhitelistUpdateEvent(name, whitelisted));
}
@@ -779,7 +779,7 @@ export default class ControlConnection extends BaseConnection {
user.isDeleted = true;
this._controller.userManager.users.delete(name);
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
if (user.isAdmin) {
this._controller.sendTo("allInstances", new lib.InstanceAdminlistUpdateEvent(name, false));
+48 -38
View File
@@ -143,16 +143,16 @@ export default class Controller {
this.subscriptions = new lib.SubscriptionController(this);
this.modStore.on("change", mod => {
this.modUpdated(mod);
this.modsUpdated([mod]);
});
// Handle subscriptions for all internal properties
this.subscriptions.handle(lib.HostUpdateEvent);
this.subscriptions.handle(lib.InstanceDetailsUpdateEvent);
this.subscriptions.handle(lib.HostUpdatesEvent);
this.subscriptions.handle(lib.InstanceDetailsUpdatesEvent);
this.subscriptions.handle(lib.InstanceSaveListUpdateEvent);
this.subscriptions.handle(lib.ModPackUpdateEvent);
this.subscriptions.handle(lib.ModUpdateEvent);
this.subscriptions.handle(lib.UserUpdateEvent);
this.subscriptions.handle(lib.ModPackUpdatesEvent);
this.subscriptions.handle(lib.ModUpdatesEvent);
this.subscriptions.handle(lib.UserUpdatesEvent);
}
async start(args: ControllerArgs) {
@@ -607,8 +607,8 @@ export default class Controller {
);
}
hostUpdated(host: HostInfo) {
let update = new lib.HostDetails(
hostsUpdated(hosts: HostInfo[]) {
let updates = hosts.map(host => new lib.HostDetails(
host.agent,
host.version,
host.name,
@@ -616,9 +616,9 @@ export default class Controller {
this.wsServer.hostConnections.has(host.id),
host.public_address,
host.token_valid_after,
);
));
this.subscriptions.broadcast(new lib.HostUpdateEvent(update));
this.subscriptions.broadcast(new lib.HostUpdatesEvent(updates));
}
/**
@@ -690,7 +690,7 @@ export default class Controller {
this.instancesDirty = true;
await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance);
this.addInstanceHooks(instance);
this.instanceDetailsUpdated(instance);
this.instanceDetailsUpdated([instance]);
return instance;
}
@@ -742,7 +742,7 @@ export default class Controller {
);
} else {
instance.status = "unassigned";
this.instanceDetailsUpdated(instance);
this.instanceDetailsUpdated([instance]);
}
}
@@ -765,7 +765,7 @@ export default class Controller {
let prev = instance.status;
instance.status = "deleted";
this.instanceDetailsUpdated(instance);
this.instanceDetailsUpdated([instance]);
await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance, prev);
}
@@ -793,7 +793,7 @@ export default class Controller {
addInstanceHooks(instance: InstanceInfo) {
instance.config.on("fieldChanged", (group: lib.ConfigGroup, field: string, prev: any) => {
if (group.name === "instance" && field === "name") {
this.instanceDetailsUpdated(instance);
this.instanceDetailsUpdated([instance]);
}
this.instancesDirty = true;
@@ -801,50 +801,60 @@ export default class Controller {
});
}
instanceDetailsUpdated(instance: InstanceInfo) {
let assigned_host: number|null|undefined = instance.config.get("instance.assigned_host");
if (assigned_host === null) {
assigned_host = undefined;
}
instanceDetailsUpdated(instances: InstanceInfo[]) {
const now = Date.now();
const updates: lib.InstanceDetails[] = [];
for (const instance of instances) {
let assigned_host: number|null|undefined = instance.config.get("instance.assigned_host");
if (assigned_host === null) {
assigned_host = undefined;
}
let game_port: number|null|undefined = instance.game_port;
if (game_port === null) {
game_port = undefined;
}
let game_port: number|null|undefined = instance.game_port;
if (game_port === null) {
game_port = undefined;
}
this.subscriptions.broadcast(new lib.InstanceDetailsUpdateEvent(
new lib.InstanceDetails(
updates.push(new lib.InstanceDetails(
instance.config.get("instance.name"),
instance.id,
assigned_host,
game_port,
instance.status,
Date.now(),
)
));
now,
));
}
this.subscriptions.broadcast(new lib.InstanceDetailsUpdatesEvent(updates));
}
saveListUpdate(instanceId: number, saves: lib.SaveDetails[]) {
this.subscriptions.broadcast(new lib.InstanceSaveListUpdateEvent(instanceId, saves));
}
modPackUpdated(modPack: lib.ModPack) {
modPack.updatedAt = Date.now();
modPacksUpdated(modPacks: lib.ModPack[]) {
const now = Date.now();
for (const modPack of modPacks) {
modPack.updatedAt = now;
}
this.modPacksDirty = true;
this.subscriptions.broadcast(new lib.ModPackUpdateEvent(modPack));
lib.invokeHook(this.plugins, "onModPackUpdated", modPack);
this.subscriptions.broadcast(new lib.ModPackUpdatesEvent(modPacks));
lib.invokeHook(this.plugins, "onModPacksUpdated", modPacks);
}
modUpdated(mod: lib.ModInfo) {
modsUpdated(mods: lib.ModInfo[]) {
// ModStore sets updatedAt for mods
this.subscriptions.broadcast(new lib.ModUpdateEvent(mod));
lib.invokeHook(this.plugins, "onModUpdated", mod);
this.subscriptions.broadcast(new lib.ModUpdatesEvent(mods));
lib.invokeHook(this.plugins, "onModsUpdated", mods);
}
userUpdated(user: ControllerUser) {
user.updatedAt = Date.now();
usersUpdated(users: ControllerUser[]) {
const now = Date.now();
for (const user of users) {
user.updatedAt = now;
}
this.userManager.dirty = true;
this.subscriptions.broadcast(new lib.UserUpdateEvent(user));
this.subscriptions.broadcast(new lib.UserUpdatesEvent(users));
}
/**
+12 -5
View File
@@ -69,16 +69,18 @@ export default class HostConnection extends BaseConnection {
this.connector.on("close", () => {
// Update status to unknown for instances on this host.
const instances: InstanceInfo[] = [];
for (let instance of this._controller.instances.values()) {
if (instance.config.get("instance.assigned_host") !== this._id) {
continue;
}
instances.push(instance);
let prev = instance.status;
instance.status = "unknown";
this._controller.instanceDetailsUpdated(instance);
lib.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, prev);
}
this._controller.instanceDetailsUpdated(instances);
});
this.handle(lib.InstanceStatusChangedEvent, this.handleInstanceStatusChangedEvent.bind(this));
@@ -180,7 +182,7 @@ export default class HostConnection extends BaseConnection {
instance.status = request.status as lib.InstanceStatus;
instance.game_port = request.gamePort || null;
logger.verbose(`Instance ${instance.config.get("instance.name")} State: ${instance.status}`);
this._controller.instanceDetailsUpdated(instance);
this._controller.instanceDetailsUpdated([instance]);
await lib.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, prev);
}
@@ -195,6 +197,7 @@ export default class HostConnection extends BaseConnection {
}
// Assign instances the host has but controller does not
const instanceUpdates: InstanceInfo[] = [];
for (let instanceData of request.instances) {
let instanceConfig = new lib.InstanceConfig("controller");
await instanceConfig.load(instanceData.config as lib.SerializedConfig, "host");
@@ -214,7 +217,7 @@ export default class HostConnection extends BaseConnection {
let prev = controllerInstance.status;
controllerInstance.status = instanceData.status as InstanceStatus;
logger.verbose(`Instance ${instanceConfig.get("instance.name")} State: ${instanceData.status}`);
this._controller.instanceDetailsUpdated(controllerInstance);
instanceUpdates.push(controllerInstance);
await lib.invokeHook(
this._controller.plugins, "onInstanceStatusChanged", controllerInstance, prev
);
@@ -234,10 +237,14 @@ export default class HostConnection extends BaseConnection {
instanceConfig.get("instance.id"), instanceConfig.serialize("host")
)
);
this._controller.instanceDetailsUpdated(newInstance);
instanceUpdates.push(newInstance);
await lib.invokeHook(this._controller.plugins, "onInstanceStatusChanged", newInstance);
}
if (instanceUpdates.length) {
this._controller.instanceDetailsUpdated(instanceUpdates);
}
// Push lists to make sure they are in sync.
let adminlist: Set<string> = new Set();
let banlist: Map<string, string> = new Map();
@@ -286,7 +293,7 @@ export default class HostConnection extends BaseConnection {
user.instanceStats.set(instanceId, event.stats);
user.recalculatePlayerStats();
this._controller.userUpdated(user);
this._controller.usersUpdated([user]);
let instance = this._controller.instances.get(instanceId)!;
await lib.invokeHook(this._controller.plugins, "onPlayerEvent", instance, {
+2 -2
View File
@@ -274,13 +274,13 @@ ${err.stack}`
connector.on("close", () => {
if (this.hostConnections.get(data.id) === connection) {
this.hostConnections.delete(data.id);
this.controller.hostUpdated(this.controller.hosts.get(data.id) as HostInfo);
this.controller.hostsUpdated([this.controller.hosts.get(data.id)!]);
} else {
logger.warn("Unlisted HostConnection closed");
}
});
this.hostConnections.set(data.id, connection);
this.controller.hostUpdated(this.controller.hosts.get(data.id) as HostInfo);
this.controller.hostsUpdated([this.controller.hosts.get(data.id)!]);
let src = new lib.Address(lib.Address.host, data.id);
connector.ready(socket, src, sessionToken, undefined);
}
+1 -1
View File
@@ -256,7 +256,7 @@ async function uploadExport(req: Request, res: Response) {
modPack.exportManifest = new lib.ExportManifest(assets);
modPack.fillDefaultSettings(settingPrototypes, logger);
res.app.locals.controller.modPackUpdated(modPack);
res.app.locals.controller.modPacksUpdated([modPack]);
res.sendStatus(200);
}
+5 -5
View File
@@ -52,23 +52,23 @@ export class HostListRequest {
static Response = jsonArray(HostDetails);
}
export class HostUpdateEvent {
declare ["constructor"]: typeof HostUpdateEvent;
export class HostUpdatesEvent {
declare ["constructor"]: typeof HostUpdatesEvent;
static type = "event" as const;
static src = "controller" as const;
static dst = "control" as const;
static permission = "core.host.subscribe" as const;
constructor(
public update: HostDetails,
public updates: HostDetails[],
) { }
static jsonSchema = Type.Object({
"update": HostDetails.jsonSchema,
"updates": Type.Array(HostDetails.jsonSchema),
});
static fromJSON(json: Static<typeof this.jsonSchema>) {
return new this(HostDetails.fromJSON(json.update));
return new this(json.updates.map(update => HostDetails.fromJSON(update)));
}
}
+7 -9
View File
@@ -81,25 +81,23 @@ export class InstanceDetailsListRequest {
static Response = jsonArray(InstanceDetails);
};
export class InstanceDetailsUpdateEvent {
declare ["constructor"]: typeof InstanceDetailsUpdateEvent;
export class InstanceDetailsUpdatesEvent {
declare ["constructor"]: typeof InstanceDetailsUpdatesEvent;
static type = "event" as const;
static src = "controller" as const;
static dst = "control" as const;
static permission = "core.instance.subscribe" as const;
constructor(
public details: InstanceDetails,
public updates: InstanceDetails[],
) { }
static jsonSchema = InstanceDetails.jsonSchema;
toJSON() {
return this.details;
}
static jsonSchema = Type.Object({
"updates": Type.Array(InstanceDetails.jsonSchema),
});
static fromJSON(json: Static<typeof this.jsonSchema>) {
return new this(InstanceDetails.fromJSON(json));
return new this(json.updates.map(update => InstanceDetails.fromJSON(update)));
}
};
+10 -10
View File
@@ -245,42 +245,42 @@ export class ModDeleteRequest {
}
}
export class ModPackUpdateEvent {
declare ["constructor"]: typeof ModPackUpdateEvent;
export class ModPackUpdatesEvent {
declare ["constructor"]: typeof ModPackUpdatesEvent;
static type = "event" as const;
static src = "controller" as const;
static dst = "control" as const;
static permission = "core.mod_pack.subscribe" as const;
constructor(
public modPack: ModPack,
public updates: ModPack[],
) { }
static jsonSchema = Type.Object({
"modPack": ModPack.jsonSchema,
"updates": Type.Array(ModPack.jsonSchema),
});
static fromJSON(json: Static<typeof this.jsonSchema>) {
return new this(ModPack.fromJSON(json.modPack));
return new this(json.updates.map(update => ModPack.fromJSON(update)));
}
}
export class ModUpdateEvent {
declare ["constructor"]: typeof ModUpdateEvent;
export class ModUpdatesEvent {
declare ["constructor"]: typeof ModUpdatesEvent;
static type = "event" as const;
static src = "controller" as const;
static dst = "control" as const;
static permission = "core.mod.subscribe" as const;
constructor(
public mod: ModInfo,
public updates: ModInfo[],
) { }
static jsonSchema = Type.Object({
"mod": ModInfo.jsonSchema,
"updates": Type.Array(ModInfo.jsonSchema),
});
static fromJSON(json: Static<typeof this.jsonSchema>) {
return new this(ModInfo.fromJSON(json.mod));
return new this(json.updates.map(update => ModInfo.fromJSON(update)));
}
}
+5 -5
View File
@@ -301,22 +301,22 @@ export class UserDeleteRequest {
}
}
export class UserUpdateEvent {
declare ["constructor"]: typeof UserUpdateEvent;
export class UserUpdatesEvent {
declare ["constructor"]: typeof UserUpdatesEvent;
static type = "event" as const;
static src = "controller" as const;
static dst = "control" as const;
static permission = "core.user.subscribe" as const;
constructor(
public user: User,
public updates: User[],
) { }
static jsonSchema = Type.Object({
"user": User.jsonSchema,
"updates": Type.Array(User.jsonSchema),
});
static fromJSON(json: Static<typeof this.jsonSchema>) {
return new this(User.fromJSON(json.user));
return new this(json.updates.map(update => User.fromJSON(update)));
}
}
+5 -5
View File
@@ -31,7 +31,7 @@ export const dataClasses: (RequestClass<unknown, unknown> | EventClass<unknown>)
subscriptions.SubscriptionRequest,
host.HostListRequest,
host.HostUpdateEvent,
host.HostUpdatesEvent,
host.HostMetricsRequest,
host.ControllerConnectionEvent,
host.PrepareControllerDisconnectRequest,
@@ -40,7 +40,7 @@ export const dataClasses: (RequestClass<unknown, unknown> | EventClass<unknown>)
instance.InstanceDetailsGetRequest,
instance.InstanceDetailsListRequest,
instance.InstanceDetailsUpdateEvent,
instance.InstanceDetailsUpdatesEvent,
instance.InstanceCreateRequest,
instance.InstanceConfigGetRequest,
instance.InstanceConfigSetFieldRequest,
@@ -88,8 +88,8 @@ export const dataClasses: (RequestClass<unknown, unknown> | EventClass<unknown>)
mod.ModSearchRequest,
mod.ModDownloadRequest,
mod.ModDeleteRequest,
mod.ModPackUpdateEvent,
mod.ModUpdateEvent,
mod.ModPackUpdatesEvent,
mod.ModUpdatesEvent,
user.PermissionListRequest,
user.RoleListRequest,
@@ -106,5 +106,5 @@ export const dataClasses: (RequestClass<unknown, unknown> | EventClass<unknown>)
user.UserSetWhitelistedRequest,
user.UserSetBannedRequest,
user.UserDeleteRequest,
user.UserUpdateEvent,
user.UserUpdatesEvent,
];
+12 -10
View File
@@ -35,11 +35,11 @@ export function useHost(id: number): [ HostState, () => void ] {
}
updateHost();
function updateHandler(newHost: lib.HostDetails) {
if (newHost.id !== id) {
return;
function updateHandler(newHosts: lib.HostDetails[]) {
const newHost = newHosts.find(h => h.id === id);
if (newHost) {
setHost({ ...newHost, loading: false, missing: false, present: true });
}
setHost({ ...newHost, loading: false, missing: false, present: true });
}
control.hostUpdate.subscribe(updateHandler);
@@ -66,14 +66,16 @@ export function useHostList() {
useEffect(() => {
updateHostList();
function updateHandler(newHost: lib.HostDetails) {
function updateHandler(newHosts: lib.HostDetails[]) {
setHostList(oldList => {
let newList = oldList.concat();
let index = newList.findIndex(s => s.id === newHost.id);
if (index !== -1) {
newList[index] = newHost;
} else {
newList.push(newHost);
for (const newHost of newHosts) {
let index = newList.findIndex(s => s.id === newHost.id);
if (index !== -1) {
newList[index] = newHost;
} else {
newList.push(newHost);
}
}
return newList;
});
+15 -13
View File
@@ -31,11 +31,11 @@ export function useInstance(id: number): [InstanceState, ()=>void] {
}
updateInstance();
function updateHandler(newInstance: lib.InstanceDetails) {
if (newInstance.id !== id) {
return;
function updateHandler(newInstances: lib.InstanceDetails[]) {
const newInstance = newInstances.find(i => i.id === id);
if (newInstance) {
setInstance({ ...newInstance, present: true });
}
setInstance({ ...newInstance, present: true });
}
control.instanceUpdate.subscribe(updateHandler);
@@ -62,18 +62,20 @@ export function useInstanceList() {
useEffect(() => {
updateInstanceList();
function updateHandler(newInstance: lib.InstanceDetails) {
function updateHandler(newInstances: lib.InstanceDetails[]) {
setInstanceList(oldList => {
let newList = oldList.concat();
let index = newList.findIndex(s => s.id === newInstance.id);
if (newInstance.status !== "deleted") {
if (index !== -1) {
newList[index] = newInstance;
} else {
newList.push(newInstance);
for (const newInstance of newInstances) {
let index = newList.findIndex(s => s.id === newInstance.id);
if (newInstance.status !== "deleted") {
if (index !== -1) {
newList[index] = newInstance;
} else {
newList.push(newInstance);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
return newList;
});
+15 -13
View File
@@ -33,11 +33,11 @@ export function useModPack(id: number) {
}
updateModPack();
function updateHandler(newModPack: lib.ModPack) {
if (newModPack.id !== id) {
return;
function updateHandler(modPacks: lib.ModPack[]) {
const newModPack = modPacks.find(m => m.id === id);
if (newModPack) {
setModPack(newModPack);
}
setModPack(newModPack);
}
control.modPackUpdate.subscribe(updateHandler);
return () => {
@@ -63,18 +63,20 @@ export function useModPackList() {
useEffect(() => {
updateModPackList();
function updateHandler(newModPack: lib.ModPack) {
function updateHandler(newModPacks: lib.ModPack[]) {
setModPackList(oldList => {
let newList = oldList.concat();
let index = newList.findIndex(u => u.id === newModPack.id);
if (!newModPack.isDeleted) {
if (index !== -1) {
newList[index] = newModPack;
} else {
newList.push(newModPack);
for (const newModPack of newModPacks) {
let index = newList.findIndex(u => u.id === newModPack.id);
if (!newModPack.isDeleted) {
if (index !== -1) {
newList[index] = newModPack;
} else {
newList.push(newModPack);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
return newList;
});
+11 -9
View File
@@ -21,18 +21,20 @@ export function useModList() {
useEffect(() => {
updateModList();
function updateHandler(newMod: lib.ModInfo) {
function updateHandler(newMods: lib.ModInfo[]) {
setModList(oldList => {
let newList = oldList.concat();
let index = newList.findIndex(mod => mod.name === newMod.name && mod.version === newMod.version);
if (!newMod.isDeleted) {
if (index !== -1) {
newList[index] = newMod;
} else {
newList.push(newMod);
for (const newMod of newMods) {
let index = newList.findIndex(mod => mod.name === newMod.name && mod.version === newMod.version);
if (!newMod.isDeleted) {
if (index !== -1) {
newList[index] = newMod;
} else {
newList.push(newMod);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
return newList;
});
+15 -13
View File
@@ -78,11 +78,11 @@ export function useUser(name: string): [RawUserState, () => void] {
}
updateUser();
function updateHandler(newUser: lib.User) {
if (newUser.name !== name) {
return;
function updateHandler(newUsers: lib.User[]) {
const newUser = newUsers.find(u => u.name === name);
if (newUser) {
setUser({ ...newUser, present: true });
}
setUser({ ...newUser, present: true });
}
control.userUpdate.subscribe(updateHandler);
@@ -109,18 +109,20 @@ export function useUserList() {
useEffect(() => {
updateUserList();
function updateHandler(newUser: lib.User) {
function updateHandler(newUsers: lib.User[]) {
setUserList(oldList => {
let newList = oldList.concat();
let index = newList.findIndex(u => u.name === newUser.name);
if (!newUser.isDeleted) {
if (index !== -1) {
newList[index] = newUser;
} else {
newList.push(newUser);
for (const newUser of newUsers) {
let index = newList.findIndex(u => u.name === newUser.name);
if (!newUser.isDeleted) {
if (index !== -1) {
newList[index] = newUser;
} else {
newList.push(newUser);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
} else if (index !== -1) {
newList.splice(index, 1);
}
return newList;
});
+10 -10
View File
@@ -60,28 +60,28 @@ export class Control extends lib.Link {
logHandlers: Map<lib.LogFilter, logHandler[]> = new Map();
/** Updates handled by the subscription service */
hostUpdate = new lib.EventSubscriber<lib.HostUpdateEvent, lib.HostDetails>(
lib.HostUpdateEvent, event => event.update,
hostUpdate = new lib.EventSubscriber<lib.HostUpdatesEvent, lib.HostDetails[]>(
lib.HostUpdatesEvent, event => event.updates,
);
instanceUpdate = new lib.EventSubscriber<lib.InstanceDetailsUpdateEvent, lib.InstanceDetails>(
lib.InstanceDetailsUpdateEvent, event => event.details,
instanceUpdate = new lib.EventSubscriber<lib.InstanceDetailsUpdatesEvent, lib.InstanceDetails[]>(
lib.InstanceDetailsUpdatesEvent, event => event.updates,
);
saveListUpdate = new lib.EventSubscriber<lib.InstanceSaveListUpdateEvent>(
lib.InstanceSaveListUpdateEvent,
);
modPackUpdate = new lib.EventSubscriber<lib.ModPackUpdateEvent, lib.ModPack>(
lib.ModPackUpdateEvent, event => event.modPack,
modPackUpdate = new lib.EventSubscriber<lib.ModPackUpdatesEvent, lib.ModPack[]>(
lib.ModPackUpdatesEvent, event => event.updates,
);
modUpdate = new lib.EventSubscriber<lib.ModUpdateEvent, lib.ModInfo>(
lib.ModUpdateEvent, event => event.mod,
modUpdate = new lib.EventSubscriber<lib.ModUpdatesEvent, lib.ModInfo[]>(
lib.ModUpdatesEvent, event => event.updates,
);
userUpdate = new lib.EventSubscriber<lib.UserUpdateEvent, lib.User>(
lib.UserUpdateEvent, event => event.user,
userUpdate = new lib.EventSubscriber<lib.UserUpdatesEvent, lib.User[]>(
lib.UserUpdatesEvent, event => event.updates,
);
declare connector: ControlConnector;
+20 -20
View File
@@ -36,56 +36,56 @@ class TestControl extends lib.Link {
return;
}
this.send(
new lib.SubscriptionRequest(lib.HostUpdateEvent.name, true)
new lib.SubscriptionRequest(lib.HostUpdatesEvent.name, true)
).catch(err => logger.error(`Error setting host subscriptions:\n${err.stack}`));
this.send(
new lib.SubscriptionRequest(lib.InstanceDetailsUpdateEvent.name, true)
new lib.SubscriptionRequest(lib.InstanceDetailsUpdatesEvent.name, true)
).catch(err => logger.error(`Error setting instance subscriptions:\n${err.stack}`));
this.send(
new lib.SubscriptionRequest(lib.InstanceSaveListUpdateEvent.name, true)
).catch(err => logger.error(`Error setting save list subscriptions:\n${err.stack}`));
this.send(
new lib.SubscriptionRequest(lib.ModUpdateEvent.name, true)
new lib.SubscriptionRequest(lib.ModUpdatesEvent.name, true)
).catch(err => logger.error(`Error setting mod subscriptions:\n${err.stack}`));
this.send(
new lib.SubscriptionRequest(lib.ModPackUpdateEvent.name, true)
new lib.SubscriptionRequest(lib.ModPackUpdatesEvent.name, true)
).catch(err => logger.error(`Error setting mod pack subscriptions:\n${err.stack}`));
this.send(
new lib.SubscriptionRequest(lib.UserUpdateEvent.name, true)
new lib.SubscriptionRequest(lib.UserUpdatesEvent.name, true)
).catch(err => logger.error(`Error setting user subscriptions:\n${err.stack}`));
});
this.handle(lib.AccountUpdateEvent);
this.handle(lib.HostUpdateEvent, this.handleHostUpdateEvent.bind(this));
this.handle(lib.InstanceDetailsUpdateEvent, this.handleInstanceDetailsUpdateEvent.bind(this));
this.handle(lib.HostUpdatesEvent, this.handleHostUpdatesEvent.bind(this));
this.handle(lib.InstanceDetailsUpdatesEvent, this.handleInstanceDetailsUpdatesEvent.bind(this));
this.handle(lib.InstanceSaveListUpdateEvent, this.handleInstanceSaveListUpdateEvent.bind(this));
this.handle(lib.ModUpdateEvent, this.handleModUpdateEvent.bind(this));
this.handle(lib.ModPackUpdateEvent, this.handleModPackUpdateEvent.bind(this));
this.handle(lib.UserUpdateEvent, this.handleUserUpdateEvent.bind(this));
this.handle(lib.ModUpdatesEvent, this.handleModUpdatesEvent.bind(this));
this.handle(lib.ModPackUpdatesEvent, this.handleModPackUpdatesEvent.bind(this));
this.handle(lib.UserUpdatesEvent, this.handleUserUpdatesEvent.bind(this));
}
async handleHostUpdateEvent(event) {
this.hostUpdates.push(event.update);
async handleHostUpdatesEvent(event) {
this.hostUpdates.push(...event.updates);
}
async handleInstanceDetailsUpdateEvent(event) {
this.instanceUpdates.push(event.details);
async handleInstanceDetailsUpdatesEvent(event) {
this.instanceUpdates.push(...event.updates);
}
async handleInstanceSaveListUpdateEvent(event) {
this.saveListUpdates.push(event);
}
async handleModUpdateEvent(event) {
this.modUpdates.push(event.mod);
async handleModUpdatesEvent(event) {
this.modUpdates.push(...event.updates);
}
async handleModPackUpdateEvent(event) {
this.modPackUpdates.push(event.modPack);
async handleModPackUpdatesEvent(event) {
this.modPackUpdates.push(...event.updates);
}
async handleUserUpdateEvent(event) {
this.userUpdates.push(event.user);
async handleUserUpdatesEvent(event) {
this.userUpdates.push(...event.updates);
}
}