mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
web/main: fix restoring state on reload
This commit is contained in:
parent
bf7769ee95
commit
2c7ad651e4
6 changed files with 63 additions and 6 deletions
|
@ -81,6 +81,10 @@ func (c *CommandHandler) Init() {
|
|||
Data: marshaledPayload,
|
||||
})
|
||||
}
|
||||
c.App.EmitEvent("hicli_event", &hicli.JSONCommand{
|
||||
Command: "init_complete",
|
||||
RequestID: 0,
|
||||
})
|
||||
log.Info().Int("room_count", roomCount).Msg("Sent initial rooms to client")
|
||||
}()
|
||||
}
|
||||
|
|
|
@ -259,5 +259,13 @@ func (gmx *Gomuks) sendInitialData(ctx context.Context, conn *websocket.Conn) {
|
|||
return
|
||||
}
|
||||
}
|
||||
err := writeCmd(ctx, conn, &hicli.JSONCommand{
|
||||
Command: "init_complete",
|
||||
RequestID: 0,
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to send initial rooms done event to client")
|
||||
return
|
||||
}
|
||||
log.Info().Int("room_count", roomCount).Msg("Sent initial rooms to client")
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import type {
|
|||
export default class Client {
|
||||
readonly state = new CachedEventDispatcher<ClientState>()
|
||||
readonly syncStatus = new NonNullCachedEventDispatcher<SyncStatus>({ type: "waiting", error_count: 0 })
|
||||
readonly initComplete = new NonNullCachedEventDispatcher<boolean>(false)
|
||||
readonly store = new StateStore()
|
||||
#stateRequests: RoomStateGUID[] = []
|
||||
#stateRequestQueued = false
|
||||
|
@ -105,6 +106,8 @@ export default class Client {
|
|||
this.state.emit(ev.data)
|
||||
} else if (ev.command === "sync_status") {
|
||||
this.syncStatus.emit(ev.data)
|
||||
} else if (ev.command === "init_complete") {
|
||||
this.initComplete.emit(true)
|
||||
} else if (ev.command === "sync_complete") {
|
||||
this.store.applySync(ev.data)
|
||||
} else if (ev.command === "events_decrypted") {
|
||||
|
@ -317,9 +320,16 @@ export default class Client {
|
|||
}
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.rpc.logout()
|
||||
clearState() {
|
||||
this.initComplete.emit(false)
|
||||
this.syncStatus.emit({ type: "waiting", error_count: 0 })
|
||||
this.state.clearCache()
|
||||
localStorage.clear()
|
||||
this.store.clear()
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.rpc.logout()
|
||||
this.clearState()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,6 +118,10 @@ export interface SyncStatusEvent extends RPCCommand<SyncStatus> {
|
|||
command: "sync_status"
|
||||
}
|
||||
|
||||
export interface InitCompleteEvent extends RPCCommand<void> {
|
||||
command: "init_complete"
|
||||
}
|
||||
|
||||
export type RPCEvent =
|
||||
ClientStateEvent |
|
||||
SyncStatusEvent |
|
||||
|
@ -125,4 +129,5 @@ export type RPCEvent =
|
|||
SendCompleteEvent |
|
||||
EventsDecryptedEvent |
|
||||
SyncCompleteEvent |
|
||||
ImageAuthTokenEvent
|
||||
ImageAuthTokenEvent |
|
||||
InitCompleteEvent
|
||||
|
|
|
@ -159,6 +159,7 @@ const handleURLHash = (client: Client, context: ContextFields) => {
|
|||
console.error("Invalid matrix URI", decodedURI)
|
||||
return
|
||||
}
|
||||
console.log("Handling URI", uri)
|
||||
const newURL = new URL(location.href)
|
||||
newURL.hash = ""
|
||||
if (uri.identifier.startsWith("@")) {
|
||||
|
@ -206,9 +207,20 @@ const MainScreen = () => {
|
|||
context.setRightPanel(evt.state?.right_panel ?? null, false)
|
||||
}
|
||||
window.addEventListener("popstate", listener)
|
||||
const initHandle = () => {
|
||||
listener({ state: history.state } as PopStateEvent)
|
||||
handleURLHash(client, context)
|
||||
return () => window.removeEventListener("popstate", listener)
|
||||
}
|
||||
let cancel = () => {}
|
||||
if (client.initComplete.current) {
|
||||
initHandle()
|
||||
} else {
|
||||
cancel = client.initComplete.once(initHandle)
|
||||
}
|
||||
return () => {
|
||||
window.removeEventListener("popstate", listener)
|
||||
cancel()
|
||||
}
|
||||
}, [context, client])
|
||||
useEffect(() => context.keybindings.listen(), [context])
|
||||
useInsertionEffect(() => {
|
||||
|
|
|
@ -33,6 +33,16 @@ export class EventDispatcher<T> {
|
|||
return this.#listen(listener)
|
||||
}
|
||||
|
||||
once(listener: (data: T) => void): () => void {
|
||||
let unsub: (() => void) | undefined = undefined
|
||||
const wrapped = (data: T) => {
|
||||
unsub?.()
|
||||
listener(data)
|
||||
}
|
||||
unsub = this.#listen(wrapped)
|
||||
return unsub
|
||||
}
|
||||
|
||||
#listen(listener: (data: T) => void): () => void {
|
||||
this.#listeners.push(listener)
|
||||
return () => {
|
||||
|
@ -72,6 +82,10 @@ export class CachedEventDispatcher<T> extends EventDispatcher<T> {
|
|||
}
|
||||
return unlisten
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
this.current = null
|
||||
}
|
||||
}
|
||||
|
||||
export class NonNullCachedEventDispatcher<T> extends CachedEventDispatcher<T> {
|
||||
|
@ -81,4 +95,8 @@ export class NonNullCachedEventDispatcher<T> extends CachedEventDispatcher<T> {
|
|||
super(cache)
|
||||
this.current = cache
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
throw new Error("Cannot clear cache of NonNullCachedEventDispatcher")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue