Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import io.cloudbeaver.server.websockets.CBEventsLongPollingServlet;
import io.cloudbeaver.server.websockets.CBEventsWebSocket;
import io.cloudbeaver.server.websockets.CBWebSocketServerConfigurator;
import io.cloudbeaver.server.websockets.lsp.LSPWebSocketConstants;
import io.cloudbeaver.server.websockets.lsp.LSPWebSocketEndpoint;
import io.cloudbeaver.service.DBWServiceBindingServlet;
import io.cloudbeaver.service.DBWServiceBindingWebSocket;
import jakarta.websocket.server.ServerEndpointConfig;
Expand Down Expand Up @@ -174,13 +176,24 @@ public void runServer() {

JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, (context, container) -> {
// Add echo endpoint to server container
ServerEndpointConfig eventWsEnpoint = ServerEndpointConfig.Builder
CBWebSocketServerConfigurator configurator =
new CBWebSocketServerConfigurator(application.getSessionManager());

ServerEndpointConfig eventWsEndpoint = ServerEndpointConfig.Builder
.create(
CBEventsWebSocket.class,
serverConfiguration.getServicesURI() + "ws"
).configurator(new CBWebSocketServerConfigurator(application.getSessionManager()))
).configurator(configurator)
.build();
container.addEndpoint(eventWsEndpoint);

ServerEndpointConfig lspWsEndpoint = ServerEndpointConfig.Builder
.create(
LSPWebSocketEndpoint.class,
serverConfiguration.getServicesURI() + LSPWebSocketConstants.ENDPOINT_SUFFIX
).configurator(configurator)
.build();
container.addEndpoint(eventWsEnpoint);
container.addEndpoint(lspWsEndpoint);
});

JettyUtils.initSessionManager(
Expand Down
8 changes: 6 additions & 2 deletions server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
org.apache.commons.jexl,
org.jkiss.utils;visibility:=reexport,
org.jkiss.dbeaver.model.sql;visibility:=reexport,
org.jkiss.dbeaver.model.lsp,
org.jkiss.dbeaver.data.gis,
org.jkiss.bundle.jetty.server;visibility:=reexport,
com.google.gson;visibility:=reexport,
Expand All @@ -19,7 +20,8 @@ Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
org.jkiss.dbeaver.net.ssh,
io.cloudbeaver.model;visibility:=reexport,
io.cloudbeaver.model.cli,
io.cloudbeaver.service.security;visibility:=reexport
io.cloudbeaver.service.security;visibility:=reexport,
org.eclipse.lsp4j.websocket.jakarta
Export-Package: io.cloudbeaver,
io.cloudbeaver.model,
io.cloudbeaver.model.app,
Expand All @@ -33,9 +35,11 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.server.jobs,
io.cloudbeaver.server.servlets,
io.cloudbeaver.server.websockets,
io.cloudbeaver.server.websockets.lsp,
io.cloudbeaver.service,
io.cloudbeaver.service.navigator,
io.cloudbeaver.service.sql
Import-Package: org.slf4j
Import-Package: org.slf4j,
jakarta.websocket
Bundle-Localization: OSGI-INF/l10n/bundle
Automatic-Module-Name: io.cloudbeaver.server
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@

public class CBJettyWebSocketManager {
private static final Log log = Log.getLog(CBJettyWebSocketManager.class);
private static final Map<String, List<CBEventsWebSocket>> socketBySessionId = new ConcurrentHashMap<>();
private static final Map<String, List<CBAbstractWebSocket>> socketBySessionId = new ConcurrentHashMap<>();

private CBJettyWebSocketManager() {
}

public static void registerWebSocket(@NotNull String webSessionId, @NotNull CBEventsWebSocket webSocket) {
public static void registerWebSocket(@NotNull String webSessionId, @NotNull CBAbstractWebSocket webSocket) {
socketBySessionId.computeIfAbsent(webSessionId, key -> new CopyOnWriteArrayList<>()).add(webSocket);
}

Expand All @@ -57,7 +57,7 @@ public static void sendPing() {
entry -> {
var sessionId = entry.getKey();
var webSockets = entry.getValue();
for (CBEventsWebSocket webSocket : webSockets) {
for (CBAbstractWebSocket webSocket : webSockets) {
try {
webSocket.getSession().getBasicRemote().sendPing(
ByteBuffer.wrap("cb-ping".getBytes(StandardCharsets.UTF_8))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2026 DBeaver Corp
*
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of DBeaver Corp and its suppliers, if any.
* The intellectual and technical concepts contained
* herein are proprietary to DBeaver Corp and its suppliers
* and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from DBeaver Corp.
*/
package io.cloudbeaver.server.websockets.lsp;

import io.cloudbeaver.model.session.BaseWebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.impl.AbstractSessionPersistent;
import org.jkiss.dbeaver.model.lsp.DBLServerSessionProvider;

public class LSPWebServerSesssionProvider implements DBLServerSessionProvider {

@NotNull
private final BaseWebSession session;

public LSPWebServerSesssionProvider(@NotNull BaseWebSession session) {
this.session = session;
}

@Nullable
@Override
public AbstractSessionPersistent getSession() {
return session;
}

@NotNull
@Override
public DBPWorkspace getWorkspace() {
return session.getWorkspace();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2026 DBeaver Corp
*
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of DBeaver Corp and its suppliers, if any.
* The intellectual and technical concepts contained
* herein are proprietary to DBeaver Corp and its suppliers
* and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from DBeaver Corp.
*/
package io.cloudbeaver.server.websockets.lsp;

import java.time.Duration;

public class LSPWebSocketConstants {

public static final String ENDPOINT_SUFFIX = "ws/lsp";
public static final Duration IDLE_TIMEOUT = Duration.ofMinutes(5);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2026 DBeaver Corp
*
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of DBeaver Corp and its suppliers, if any.
* The intellectual and technical concepts contained
* herein are proprietary to DBeaver Corp and its suppliers
* and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from DBeaver Corp.
*/
package io.cloudbeaver.server.websockets.lsp;

import io.cloudbeaver.model.session.BaseWebSession;
import io.cloudbeaver.server.websockets.CBAbstractWebSocket;
import io.cloudbeaver.server.websockets.CBJettyWebSocketManager;
import io.cloudbeaver.server.websockets.CBWebSocketServerConfigurator;
import jakarta.websocket.CloseReason;
import jakarta.websocket.EndpointConfig;
import jakarta.websocket.Session;
import org.eclipse.lsp4j.jsonrpc.Launcher;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.websocket.jakarta.WebSocketLauncherBuilder;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.lsp.DBLServer;

public class LSPWebSocketEndpoint extends CBAbstractWebSocket {
private static final Log log = Log.getLog(LSPWebSocketEndpoint.class);

public LSPWebSocketEndpoint() {}

@Override
public void onOpen(Session wsSession, EndpointConfig endpointConfig) {
BaseWebSession webSession = (BaseWebSession) wsSession.getUserProperties()
.get(CBWebSocketServerConfigurator.PROP_WEB_SESSION);
CBJettyWebSocketManager.registerWebSocket(webSession.getSessionId(), this);

wsSession.setMaxIdleTimeout(LSPWebSocketConstants.IDLE_TIMEOUT.toMillis());
wsSession.setMaxTextMessageBufferSize(Integer.MAX_VALUE);
wsSession.setMaxBinaryMessageBufferSize(Integer.MAX_VALUE);

LSPWebServerSesssionProvider sessionProvider = new LSPWebServerSesssionProvider(webSession);
DBLServer server = new DBLServer(sessionProvider);
var builder = new WebSocketLauncherBuilder<LanguageClient>();
builder.setSession(wsSession);
builder.setLocalService(server);
builder.setRemoteInterface(LanguageClient.class);
Launcher<LanguageClient> launcher = builder.create();
server.connect(launcher.getRemoteProxy());
}

@Override
public void onClose(Session session, CloseReason closeReason) {
log.debug("Closing websocket session: " + session.getId());
}

@Override
public void onError(Session session, Throwable thr) {
log.error("LSP WebSocket error", thr);
}
}
Loading