This commit is contained in:
Jon Eugster
2023-07-05 14:54:06 +02:00
parent a32baeb8e7
commit c5f54834ed
31 changed files with 225 additions and 174 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { Connection } from '../connection'
import { Connection } from './connection'
interface GameInfo {
title: null|string,
+68
View File
@@ -0,0 +1,68 @@
/**
* @fileOverview todo
*/
import * as React from 'react';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'
import { LeanClient } from 'lean4web/client/src/editor/leanclient';
export class Connection {
private game: string = undefined // We only keep a connection to a single game at a time
private leanClient: LeanClient = null
getLeanClient(game): LeanClient {
if (this.game !== game) {
if (this.leanClient) {
this.leanClient.stop() // Stop previous Lean client
}
this.game = game
// Start a new Lean client for the new `gameId`.
const socketUrl = ((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + '/websocket/' + game
const uri = monaco.Uri.parse('file:///')
this.leanClient = new LeanClient(socketUrl, undefined, uri, () => {})
}
return this.leanClient
}
/** If not already started, starts the Lean client. resolves the returned promise as soon as a
* Lean client is running.
*/
startLeanClient = (game) => {
return new Promise<LeanClient>((resolve) => {
const leanClient = this.getLeanClient(game)
if (leanClient.isRunning()) {
resolve(leanClient)
} else {
if (!leanClient.isStarted()) {
leanClient.start()
}
leanClient.restarted(() => {
// This keep alive message is not recognized by the server,
// but it makes sure that the websocket connection does not
// time out after 60 seconds.
setInterval(() => {leanClient.sendNotification('$/keepAlive', {}) }, 5000)
resolve(leanClient)
})
}
})
}
}
export const connection = new Connection()
export const ConnectionContext = React.createContext(null);
export const useLeanClient = (gameId) => {
const leanClient = connection.getLeanClient(gameId)
const [leanClientStarted, setLeanClientStarted] = React.useState(leanClient.isStarted())
React.useEffect(() => {
const t1 = leanClient.restarted(() => { console.log("START"); setLeanClientStarted(true) })
const t2 = leanClient.stopped(() => { console.log("STOP"); setLeanClientStarted(false) })
return () => {t1.dispose(); t2.dispose()}
}, [leanClient, setLeanClientStarted])
return {leanClientStarted, leanClient}
}
+6
View File
@@ -0,0 +1,6 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
+1 -1
View File
@@ -1,6 +1,6 @@
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
import { loadState } from "./localStorage";
import { loadState } from "./local_storage";
export interface GameProgressState {
[world: string] : {[level: number]: LevelProgressState}
+5 -4
View File
@@ -1,10 +1,11 @@
import { configureStore } from '@reduxjs/toolkit';
import { connection } from '../connection'
import thunkMiddleware from 'redux-thunk'
import { debounce } from "debounce";
import { connection } from './connection'
import { apiSlice } from './api'
import { progressSlice } from './progress'
import { saveState } from "./localStorage";
import { debounce } from "debounce";
import { saveState } from "./local_storage";
export const store = configureStore({
reducer: {