diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a043cb9..9603f45c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ modelix-model-api-gen = { id = "org.modelix.model-api-gen", version.ref = "model npm-publish = { id = "dev.petuska.npm.publish", version = "3.4.1" } [versions] -modelixCore = "3.14.2-9-gdeccc44-SNAPSHOT" +modelixCore = "3.14.2-11-g3bffd93-SNAPSHOT" [libraries] modelix-model-api = { group = "org.modelix", name = "model-api", version.ref = "modelixCore" } diff --git a/projectional-editor-ssr-mps/src/main/kotlin/org/modelix/editor/ssr/mps/ModelixSSRServerForMPS.kt b/projectional-editor-ssr-mps/src/main/kotlin/org/modelix/editor/ssr/mps/ModelixSSRServerForMPS.kt index d01a800e..9d7e0907 100644 --- a/projectional-editor-ssr-mps/src/main/kotlin/org/modelix/editor/ssr/mps/ModelixSSRServerForMPS.kt +++ b/projectional-editor-ssr-mps/src/main/kotlin/org/modelix/editor/ssr/mps/ModelixSSRServerForMPS.kt @@ -41,7 +41,7 @@ import org.modelix.model.api.BuiltinLanguages import org.modelix.model.api.INode import org.modelix.model.api.NodeReference import org.modelix.model.api.runSynchronized -import org.modelix.model.mpsadapters.MPSLanguageRepository +import org.modelix.model.mpsadapters.MPSChangeTranslator import org.modelix.model.mpsadapters.MPSRepositoryAsNode import java.net.URLEncoder import java.nio.charset.StandardCharsets @@ -66,6 +66,7 @@ class ModelixSSRServerForMPS : Disposable { private var ssrServer: ModelixSSRServer? = null private var ktorServer: ApplicationEngine? = null private var aspectsFromMPS: LanguageAspectsFromMPSModules? = null + private var mpsChangeTranslator: MPSChangeTranslator? = null private val projects: MutableSet = Collections.synchronizedSet(HashSet()) fun registerProject(project: Project) { @@ -95,10 +96,12 @@ class ModelixSSRServerForMPS : Disposable { println("starting modelix SSR server") + val repository = getMPSProjects().first().repository + mpsChangeTranslator = MPSChangeTranslator() + mpsChangeTranslator!!.start(repository) val ssrServer = ModelixSSRServer((getRootNode() ?: return).getArea()) - val aspectsFromMPS = LanguageAspectsFromMPSModules(getMPSProjects().first().repository) - this.aspectsFromMPS = aspectsFromMPS - ssrServer.editorEngine.addRegistry(aspectsFromMPS) + aspectsFromMPS = LanguageAspectsFromMPSModules(repository) + ssrServer.editorEngine.addRegistry(aspectsFromMPS!!) ktorServer = embeddedServer(Netty, port = 43593) { initKtorServer(ssrServer) } diff --git a/projectional-editor-ssr-server/src/main/kotlin/org/modelix/editor/ssr/server/ModelixSSRServer.kt b/projectional-editor-ssr-server/src/main/kotlin/org/modelix/editor/ssr/server/ModelixSSRServer.kt index 6360435b..aa47af5d 100644 --- a/projectional-editor-ssr-server/src/main/kotlin/org/modelix/editor/ssr/server/ModelixSSRServer.kt +++ b/projectional-editor-ssr-server/src/main/kotlin/org/modelix/editor/ssr/server/ModelixSSRServer.kt @@ -20,12 +20,17 @@ import org.modelix.editor.ssr.common.INodeUpdateData import org.modelix.editor.ssr.common.MessageFromClient import org.modelix.editor.ssr.common.MessageFromServer import org.modelix.editor.ssr.common.TextNodeUpdateData +import org.modelix.incremental.DependencyTracking +import org.modelix.incremental.IDependencyListener +import org.modelix.incremental.IStateVariableGroup +import org.modelix.incremental.IStateVariableReference import org.modelix.incremental.IncrementalEngine +import org.modelix.kotlin.utils.runSynchronized import org.modelix.model.api.INodeResolutionScope import org.modelix.model.api.NodeReference import org.modelix.model.api.resolveIn -import org.modelix.model.api.runSynchronized import org.modelix.model.area.IArea +import java.util.Collections private val LOG = KotlinLogging.logger { } @@ -33,26 +38,50 @@ class ModelixSSRServer(private val nodeResolutionScope: INodeResolutionScope) { private val incrementalEngine = IncrementalEngine() val editorEngine: EditorEngine = EditorEngine(incrementalEngine) + private val allSessions: MutableSet = Collections.synchronizedSet(LinkedHashSet()) private val lock = Any() + private val dependencyListener: IDependencyListener = object : IDependencyListener { + override fun parentGroupChanged(childGroup: IStateVariableGroup) {} + override fun accessed(key: IStateVariableReference<*>) {} + override fun modified(key: IStateVariableReference<*>) { updateAll() } + } fun install(route: Route) { route.installRoutes() } + fun dispose() { + DependencyTracking.removeListener(dependencyListener) + } + private fun Route.installRoutes() { - route("client") { + DependencyTracking.registerListener(dependencyListener) - } webSocket("ws") { val session = WebsocketSession(this) try { + allSessions.add(session) session.receiveMessages() } finally { + allSessions.remove(session) session.dispose() } } } + fun updateAll() { + val sessions = runSynchronized(allSessions) { allSessions.toList() } + runSynchronized(lock) { + sessions.forEach { + try { + it.updateAllEditors() + } catch (ex: Exception) { + LOG.error(ex) { "Failed to send editor update" } + } + } + } + } + private inner class WebsocketSession(val ws: DefaultWebSocketServerSession) { private val editors = HashMap() @@ -100,6 +129,10 @@ class ModelixSSRServer(private val nodeResolutionScope: INodeResolutionScope) { editors.clear() } + fun updateAllEditors() { + editors.values.forEach { it.sendUpdate() } + } + private inner class EditorSession(val editorId: String) { private var editorComponent: EditorComponent? = null private val commonElementPrefix = editorId + "-" diff --git a/settings.gradle.kts b/settings.gradle.kts index 2891254d..8a816e17 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,7 +14,7 @@ pluginManagement { } versionCatalogs { create("coreLibs") { - from("org.modelix:core-version-catalog:3.14.2-9-gdeccc44-SNAPSHOT") + from("org.modelix:core-version-catalog:3.14.2-11-g3bffd93-SNAPSHOT") } } }