83 lines
2.1 KiB
TypeScript
83 lines
2.1 KiB
TypeScript
|
import type { Entity, EntityLiving, Id } from "~/shared/types/common";
|
||
|
import { DateTime, Zone } from "~/shared/utils/luxon";
|
||
|
|
||
|
export abstract class ClientEntity {
|
||
|
/**
|
||
|
Millisecond offset used to indicate this is a new entitity.
|
||
|
*/
|
||
|
static newEntityMillis = -1;
|
||
|
/**
|
||
|
Timestamp of the entity received from server. If this is
|
||
|
a new entity this will have a millisecond offset equal to
|
||
|
{@link ClientEntity.newEntityMillis}.
|
||
|
*/
|
||
|
serverUpdatedAt: DateTime;
|
||
|
/**
|
||
|
True if the server has deleted this entity, but the client
|
||
|
is holding on to it in order to resolve an edit conflcit
|
||
|
*/
|
||
|
serverDeleted: boolean;
|
||
|
|
||
|
constructor(
|
||
|
/**
|
||
|
Server supplied id of this entity. Each kind of entity has its own namespace of ids.
|
||
|
*/
|
||
|
public readonly id: Id,
|
||
|
/**
|
||
|
Server's timestamp of this entity at the time it was modified. If the entity
|
||
|
is unmodified this will track {@link serverUpdatedAt}. If this is a new entity
|
||
|
it'll have a millesecond offset equal to {@link ClientEntity.newEntityMillis}.
|
||
|
*/
|
||
|
public updatedAt: DateTime,
|
||
|
/**
|
||
|
Flag indicating the client intends to delete this entity.
|
||
|
*/
|
||
|
public deleted: boolean,
|
||
|
) {
|
||
|
this.serverUpdatedAt = updatedAt;
|
||
|
this.serverDeleted = deleted;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
True if this entity does not yet exist on the server.
|
||
|
*/
|
||
|
isNew() {
|
||
|
return this.serverUpdatedAt.toMillis() === ClientEntity.newEntityMillis;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
True if both the server and the client have modified this entity
|
||
|
independently of each other.
|
||
|
*/
|
||
|
isConflict() {
|
||
|
return this.serverUpdatedAt.toMillis() !== this.updatedAt.toMillis();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
True if this entity has been modified on the client.
|
||
|
*/
|
||
|
isModified() {
|
||
|
return (
|
||
|
this.isNew()
|
||
|
|| this.deleted
|
||
|
|| this.serverDeleted
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Discard any client side modifications to this entity. Not allowed if
|
||
|
{@link serverDeleted} is true or this is a new entity.
|
||
|
*/
|
||
|
abstract discard(): void
|
||
|
|
||
|
/**
|
||
|
Apply an update delivered from the API to this entity.
|
||
|
*/
|
||
|
abstract apiUpdate(api: EntityLiving, opts: { zone: Zone, locale: string }): void
|
||
|
|
||
|
/**
|
||
|
Serialise this entity to the API format. Not allowed if {@link deleted} is true.
|
||
|
*/
|
||
|
abstract toApi(): Entity
|
||
|
}
|