Skip to content

Commit

Permalink
dbeaver/pro#1441 Universal Database Tunnel POC (#2941)
Browse files Browse the repository at this point in the history
* dbeaver/pro#1441 Universal Database Tunnel POC

* dbeaver/pro#1441 Resolve data source on the server side

* dbeaver/pro#1441 Use service binding for registering web sockets

* dbeaver/pro#1441 Fix compile

* dbeaver/pro#1441 Construct WebSocket endpoint from service endpoint

---------

Co-authored-by: kseniaguzeeva <[email protected]>
Co-authored-by: serge-rider <[email protected]>
  • Loading branch information
3 people authored Oct 1, 2024
1 parent 3fbc227 commit 434a988
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver;

import io.cloudbeaver.model.session.WebHeadlessSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.rm.RMProject;

public class WebHeadlessSessionProjectImpl extends WebProjectImpl {
public WebHeadlessSessionProjectImpl(
@NotNull WebHeadlessSession session,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
) {
super(
session.getWorkspace(),
session.getUserContext().getRmController(),
session.getSessionContext(),
project,
session.getUserContext().getPreferenceStore()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,22 @@
*/
package io.cloudbeaver.server.jetty;

import io.cloudbeaver.server.GQLApplicationAdapter;
import io.cloudbeaver.model.config.CBServerConfig;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.model.config.CBServerConfig;
import io.cloudbeaver.server.GQLApplicationAdapter;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
import io.cloudbeaver.server.servlets.CBImageServlet;
import io.cloudbeaver.server.servlets.CBStaticServlet;
import io.cloudbeaver.server.servlets.CBStatusServlet;
import io.cloudbeaver.server.servlets.ProxyResourceHandler;
import io.cloudbeaver.server.websockets.CBJettyWebSocketManager;
import io.cloudbeaver.service.DBWServiceBindingServlet;
import org.eclipse.jetty.ee10.servlet.*;
import io.cloudbeaver.service.DBWServiceBindingWebSocket;
import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.servlet.ServletMapping;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.session.DefaultSessionCache;
import org.eclipse.jetty.session.DefaultSessionIdManager;
Expand Down Expand Up @@ -130,11 +134,24 @@ public void runServer() {
}
}

CBJettyWebSocketContext webSocketContext = new CBJettyWebSocketContext(server, servletContextHandler);
for (DBWServiceBindingWebSocket wsb : WebServiceRegistry.getInstance()
.getWebServices(DBWServiceBindingWebSocket.class)
) {
if (wsb.isApplicable(this.application)) {
try {
wsb.addWebSockets(this.application, webSocketContext);
} catch (DBException e) {
log.error(e.getMessage(), e);
}
}
}

WebSocketUpgradeHandler webSocketHandler = WebSocketUpgradeHandler.from(server, servletContextHandler, (wsContainer) -> {
wsContainer.setIdleTimeout(Duration.ofMinutes(5));
// Add websockets
wsContainer.addMapping(
serverConfiguration.getServicesURI() + "ws/*",
serverConfiguration.getServicesURI() + "ws",
new CBJettyWebSocketManager(this.application.getSessionManager())
);
}
Expand All @@ -159,6 +176,11 @@ public void runServer() {
log.debug("\t" + sm.getServletName() + ": " + Arrays.toString(sm.getPathSpecs())); //$NON-NLS-1$
}

log.debug("Active websocket mappings:");
for (String mapping : webSocketContext.getMappings()) {
log.debug("\t" + mapping);
}

}

boolean forwardProxy = application.getAppConfiguration().isEnabledForwardProxy();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server.jetty;

import io.cloudbeaver.service.DBWWebSocketContext;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.websocket.api.Configurable;
import org.eclipse.jetty.websocket.server.WebSocketCreator;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler;
import org.jkiss.code.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class CBJettyWebSocketContext implements DBWWebSocketContext {
private final List<String> mappings = new ArrayList<>();

private final Server server;
private final ContextHandler handler;

public CBJettyWebSocketContext(@NotNull Server server, @NotNull ContextHandler handler) {
this.server = server;
this.handler = handler;
}

@Override
public void addWebSocket(@NotNull String mapping, @NotNull Function<Configurable, WebSocketCreator> configurator) {
handler.insertHandler(WebSocketUpgradeHandler.from(
server,
handler,
container -> container.addMapping(mapping, configurator.apply(container))
));
mappings.add(mapping);
}

@NotNull
public List<String> getMappings() {
return mappings;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service;

import io.cloudbeaver.model.app.WebApplication;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;

public interface DBWServiceBindingWebSocket<APPLICATION extends WebApplication> extends DBWServiceBinding {
default boolean isApplicable(@NotNull WebApplication application) {
return true;
}

void addWebSockets(@NotNull APPLICATION application, @NotNull DBWWebSocketContext context) throws DBException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service;

import org.eclipse.jetty.websocket.api.Configurable;
import org.eclipse.jetty.websocket.server.WebSocketCreator;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;

import java.util.function.Function;

public interface DBWWebSocketContext {
void addWebSocket(@NotNull String mapping, @NotNull Function<Configurable, WebSocketCreator> configurator) throws DBException;
}

0 comments on commit 434a988

Please sign in to comment.