diff --git a/WebSocketClient/index.html b/WebSocketClient/index.html index ef772d9..4b5f151 100644 --- a/WebSocketClient/index.html +++ b/WebSocketClient/index.html @@ -5,40 +5,19 @@
The Universal Variability Language (UVL) is a community effort towards a widely adopted textual specification for feature models. This playground provides the opportunity to get used to the language with diff --git a/WebSocketClient/src/main.ts b/WebSocketClient/src/main.ts index a3053af..edf64d4 100644 --- a/WebSocketClient/src/main.ts +++ b/WebSocketClient/src/main.ts @@ -23,6 +23,7 @@ import { instance } from "@viz-js/viz"; import { Message } from 'vscode-jsonrpc'; import { v4 as uuidv4 } from 'uuid'; import lodash from 'lodash'; +import { ExecuteCommandRequest } from 'vscode-languageserver-protocol' import { buildWorkerDefinition } from 'monaco-editor-workers'; buildWorkerDefinition('./node_modules/monaco-editor-workers/dist/workers', new URL('', window.location.href).href, false); @@ -78,8 +79,26 @@ const createWebSocket = (url: string): WebSocket => { return webSocket; }; +function displayConfigureView(configUri: string) { + const url = new URL(configUri); + let protocol = 'http'; + if (window.location.protocol === "https:") { + protocol = 'https'; + } + const newUrl: string = `${protocol}://${config.languageServerHostName}:${url.port}${url.pathname}`; + + let myIframe: HTMLIFrameElement | null = document.getElementById('config-view') as HTMLIFrameElement; + if(!myIframe){ + myIframe = document.createElement('iframe') as HTMLIFrameElement; + myIframe.id = "config-view"; + const iframeContainer: any = document.getElementById('flex-container'); + iframeContainer.appendChild(myIframe); + } + myIframe.src = newUrl; +} + const createLanguageClient = (transports: MessageTransports): MonacoLanguageClient => { - return new MonacoLanguageClient({ + const client = new MonacoLanguageClient({ name: 'UVL Language Client', clientOptions: { // use a language id as a document selector @@ -99,38 +118,41 @@ const createLanguageClient = (transports: MessageTransports): MonacoLanguageClie fileEvents: [vscode.workspace.createFileSystemWatcher('**')] }, connectionOptions: { + // This construct can be used to filter the messages we are receiving from the language server messageStrategy: { handleMessage(message: Message, next: (message: Message) => void) { if(Message.isRequest(message)){ - const m: any = message; - if(m.method === 'workspace/executeCommand' && m.params.command === 'uvls.open_web'){ - const configUri: string = m.params.arguments[0].uri; - const url = new URL(configUri); - let protocoll = 'http'; - if (window.location.protocol === "https:") { - protocoll = 'https'; - } - const newUrl: string = `${protocoll}://${config.languageServerHostName}:${url.port}${url.pathname}`; - const iframeContainer: any = document.getElementById('iframeContainer'); - const myIframe: any = document.getElementById('myIframe'); - iframeContainer.style.display = 'block'; - myIframe.src = newUrl; - } + // Filters requests send by uvls -> Anti-Pattern in our opinion } - if(Message.isResponse(message)){ - let result = message.result; - if(typeof result === "string" || result instanceof String){ - if(result.startsWith("digraph")){ - createDiagramFromDot(result as string); - } - } + else if(Message.isResponse(message)){ + // Filters responses send by uvls } - if(Message.isNotification(message)){ + else if(Message.isNotification(message)){ + // Filters Notification messages following json-rpc spec } - + // "next" is the default behaviour next(message); } } + }, + // The Middleware allows us to intercept all messages that would be sent to the language server + middleware: { + executeCommand(command, args, next) { + const information = {command: command, arguments: args}; + if(command === "uvls/open_config") { + client?.sendRequest(ExecuteCommandRequest.type, information).then((res) => { + displayConfigureView(res.uri); + }); + } + else if(command === "uvls/generate_diagram") { + client?.sendRequest(ExecuteCommandRequest.type, information).then((res) => { + createDiagramFromDot(res as string); + }); + } + else { + next(command, args); + } + }, } }, // create a language client connection from the JSON RPC connection on demand @@ -140,6 +162,7 @@ const createLanguageClient = (transports: MessageTransports): MonacoLanguageClie } } }); + return client; }; function createDiagramFromDot(res: string): void { @@ -217,8 +240,8 @@ export const startPythonClient = async () => { modelRef.object.onDidChangeContent(() => { debouncedSave(); }); - - + + modelRef.object.setLanguageId(languageId); // create monaco editor diff --git a/WebSocketClient/style.css b/WebSocketClient/style.css index a66b8b2..768b2cf 100644 --- a/WebSocketClient/style.css +++ b/WebSocketClient/style.css @@ -11,9 +11,9 @@ body { } .container { + display: flex; width: 50%; - margin: 0 auto; - padding: 20px; + height: 100% } .header { @@ -24,16 +24,25 @@ body { text-align: center; } +iframe { + border: none; +} + .graph { - width: 50%; - padding: 100px 20px 20px; + padding: 10px; overflow: scroll; + text-align: center; } .flex-container { display: flex; - width: 100%; height: 75%; + justify-content: space-around; +} + +iframe { + flex-grow: 1; + max-width: 50%; } h1 { @@ -47,11 +56,12 @@ h1 { padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); - width:100%; - height:700px; + min-width: 50%; + max-width: 100%; + height:80ch; border:1px solid grey; - margin-left: auto; - margin-right: auto; + margin-left: 10px; + margin-right: 10px; } p { diff --git a/WebSocketLanguageServer/lib/uvls b/WebSocketLanguageServer/lib/uvls index 9208bf6..bf9a583 100755 Binary files a/WebSocketLanguageServer/lib/uvls and b/WebSocketLanguageServer/lib/uvls differ diff --git a/docker-compose-http.yaml b/docker-compose-http.yaml index fdbc637..9c241cc 100644 --- a/docker-compose-http.yaml +++ b/docker-compose-http.yaml @@ -64,4 +64,4 @@ services: networks: proxy: - name: proxy \ No newline at end of file + name: proxy diff --git a/docker-compose.yaml b/docker-compose.yaml index ab6df0b..14eff74 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -7,6 +7,7 @@ services: - 80:80 - 443:443 - 30000:30000 + - 3000:3000 networks: - proxy volumes: @@ -15,7 +16,8 @@ services: #- /var/log:/var/log command: - --api.dashboard=true - - --log.level=INFO + - --api.insecure=true + - --log.level=DEBUG #- --log.filepath=/var/log/traefik.log - --accesslog=true #- --accesslog.filepath=/var/log/traefik-access.log @@ -23,6 +25,7 @@ services: - --providers.docker.exposedByDefault=false - --entrypoints.web.address=:80 - --entrypoints.ws.address=:30000 + - --entrypoints.configure.address=:3000 - --entrypoints.ws.http.tls.certresolver=myresolver - --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https @@ -35,7 +38,7 @@ services: - --certificatesResolvers.myresolver.acme.caServer=https://acme-v02.api.letsencrypt.org/directory labels: - traefik.enable=true - - traefik.http.routers.mydashboard.rule=Host(`${HOSTNAME}`) && Path(`/dashboard`) + - traefik.http.routers.mydashboard.rule=Host(`${HOSTNAME}`) && (PathPrefix(`/dashboard/`) || PathPrefix(`/api`)) - traefik.http.routers.mydashboard.service=api@internal - traefik.http.routers.mydashboard.middlewares=myauth - traefik.http.middlewares.myauth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/ @@ -66,11 +69,18 @@ services: - proxy labels: - "traefik.enable=true" + - "traefik.http.routers.languageserver.entrypoints=ws" - "traefik.http.routers.languageserver.rule=Host(`${HOSTNAME}`) && Path(`/`)" - "traefik.http.services.languageserver.loadbalancer.server.port=30000" - - "traefik.http.routers.languageserver.entrypoints=ws" - "traefik.http.routers.languageserver.tls.certresolver=myresolver" - + - "traefik.http.routers.languageserver.service=languageserver" + + - "traefik.http.routers.configureview.entrypoints=configure" + - "traefik.http.routers.configureview.rule=Host(`${HOSTNAME}`)" + - "traefik.http.routers.configureview.service=configureview" + - "traefik.http.services.configureview.loadbalancer.server.port=3000" + - "traefik.http.routers.configureview.tls.certresolver=myresolver" + networks: proxy: name: proxy