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,
|
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")
|
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
|
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")
|
log.Info().Int("room_count", roomCount).Msg("Sent initial rooms to client")
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import type {
|
||||||
export default class Client {
|
export default class Client {
|
||||||
readonly state = new CachedEventDispatcher<ClientState>()
|
readonly state = new CachedEventDispatcher<ClientState>()
|
||||||
readonly syncStatus = new NonNullCachedEventDispatcher<SyncStatus>({ type: "waiting", error_count: 0 })
|
readonly syncStatus = new NonNullCachedEventDispatcher<SyncStatus>({ type: "waiting", error_count: 0 })
|
||||||
|
readonly initComplete = new NonNullCachedEventDispatcher<boolean>(false)
|
||||||
readonly store = new StateStore()
|
readonly store = new StateStore()
|
||||||
#stateRequests: RoomStateGUID[] = []
|
#stateRequests: RoomStateGUID[] = []
|
||||||
#stateRequestQueued = false
|
#stateRequestQueued = false
|
||||||
|
@ -105,6 +106,8 @@ export default class Client {
|
||||||
this.state.emit(ev.data)
|
this.state.emit(ev.data)
|
||||||
} else if (ev.command === "sync_status") {
|
} else if (ev.command === "sync_status") {
|
||||||
this.syncStatus.emit(ev.data)
|
this.syncStatus.emit(ev.data)
|
||||||
|
} else if (ev.command === "init_complete") {
|
||||||
|
this.initComplete.emit(true)
|
||||||
} else if (ev.command === "sync_complete") {
|
} else if (ev.command === "sync_complete") {
|
||||||
this.store.applySync(ev.data)
|
this.store.applySync(ev.data)
|
||||||
} else if (ev.command === "events_decrypted") {
|
} else if (ev.command === "events_decrypted") {
|
||||||
|
@ -317,9 +320,16 @@ export default class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async logout() {
|
clearState() {
|
||||||
await this.rpc.logout()
|
this.initComplete.emit(false)
|
||||||
|
this.syncStatus.emit({ type: "waiting", error_count: 0 })
|
||||||
|
this.state.clearCache()
|
||||||
localStorage.clear()
|
localStorage.clear()
|
||||||
this.store.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"
|
command: "sync_status"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InitCompleteEvent extends RPCCommand<void> {
|
||||||
|
command: "init_complete"
|
||||||
|
}
|
||||||
|
|
||||||
export type RPCEvent =
|
export type RPCEvent =
|
||||||
ClientStateEvent |
|
ClientStateEvent |
|
||||||
SyncStatusEvent |
|
SyncStatusEvent |
|
||||||
|
@ -125,4 +129,5 @@ export type RPCEvent =
|
||||||
SendCompleteEvent |
|
SendCompleteEvent |
|
||||||
EventsDecryptedEvent |
|
EventsDecryptedEvent |
|
||||||
SyncCompleteEvent |
|
SyncCompleteEvent |
|
||||||
ImageAuthTokenEvent
|
ImageAuthTokenEvent |
|
||||||
|
InitCompleteEvent
|
||||||
|
|
|
@ -159,6 +159,7 @@ const handleURLHash = (client: Client, context: ContextFields) => {
|
||||||
console.error("Invalid matrix URI", decodedURI)
|
console.error("Invalid matrix URI", decodedURI)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
console.log("Handling URI", uri)
|
||||||
const newURL = new URL(location.href)
|
const newURL = new URL(location.href)
|
||||||
newURL.hash = ""
|
newURL.hash = ""
|
||||||
if (uri.identifier.startsWith("@")) {
|
if (uri.identifier.startsWith("@")) {
|
||||||
|
@ -206,9 +207,20 @@ const MainScreen = () => {
|
||||||
context.setRightPanel(evt.state?.right_panel ?? null, false)
|
context.setRightPanel(evt.state?.right_panel ?? null, false)
|
||||||
}
|
}
|
||||||
window.addEventListener("popstate", listener)
|
window.addEventListener("popstate", listener)
|
||||||
listener({ state: history.state } as PopStateEvent)
|
const initHandle = () => {
|
||||||
handleURLHash(client, context)
|
listener({ state: history.state } as PopStateEvent)
|
||||||
return () => window.removeEventListener("popstate", listener)
|
handleURLHash(client, context)
|
||||||
|
}
|
||||||
|
let cancel = () => {}
|
||||||
|
if (client.initComplete.current) {
|
||||||
|
initHandle()
|
||||||
|
} else {
|
||||||
|
cancel = client.initComplete.once(initHandle)
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("popstate", listener)
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
}, [context, client])
|
}, [context, client])
|
||||||
useEffect(() => context.keybindings.listen(), [context])
|
useEffect(() => context.keybindings.listen(), [context])
|
||||||
useInsertionEffect(() => {
|
useInsertionEffect(() => {
|
||||||
|
|
|
@ -33,6 +33,16 @@ export class EventDispatcher<T> {
|
||||||
return this.#listen(listener)
|
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 {
|
#listen(listener: (data: T) => void): () => void {
|
||||||
this.#listeners.push(listener)
|
this.#listeners.push(listener)
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -72,6 +82,10 @@ export class CachedEventDispatcher<T> extends EventDispatcher<T> {
|
||||||
}
|
}
|
||||||
return unlisten
|
return unlisten
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearCache() {
|
||||||
|
this.current = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NonNullCachedEventDispatcher<T> extends CachedEventDispatcher<T> {
|
export class NonNullCachedEventDispatcher<T> extends CachedEventDispatcher<T> {
|
||||||
|
@ -81,4 +95,8 @@ export class NonNullCachedEventDispatcher<T> extends CachedEventDispatcher<T> {
|
||||||
super(cache)
|
super(cache)
|
||||||
this.current = cache
|
this.current = cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearCache() {
|
||||||
|
throw new Error("Cannot clear cache of NonNullCachedEventDispatcher")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue