Skip to content

Commit faca042

Browse files
committed
wip
1 parent 7c6836f commit faca042

File tree

13 files changed

+458
-0
lines changed

13 files changed

+458
-0
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package org.keyproject.key.api;
2+
3+
4+
import com.google.gson.GsonBuilder;
5+
import org.eclipse.lsp4j.jsonrpc.Launcher;
6+
import org.eclipse.lsp4j.websocket.jakarta.WebSocketLauncherBuilder;
7+
import org.keyproject.key.api.remoteapi.KeyApiImpl;
8+
import org.keyproject.key.api.remoteclient.ClientApi;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
import picocli.CommandLine;
12+
import picocli.CommandLine.Option;
13+
14+
import javax.annotation.Nullable;
15+
import java.io.*;
16+
import java.net.InetAddress;
17+
import java.net.ServerSocket;
18+
import java.net.Socket;
19+
import java.util.Collection;
20+
import java.util.Collections;
21+
import java.util.List;
22+
import java.util.concurrent.ExecutionException;
23+
24+
/**
25+
* @author Alexander Weigl
26+
* @version 1 (07.10.23)
27+
*/
28+
@CommandLine.Command
29+
public class StartServer implements Runnable {
30+
private static final Logger LOGGER = LoggerFactory.getLogger(StartServer.class);
31+
32+
//region CLI arguments
33+
@Option(names = "--std", description = "use stdout and stdin for communication")
34+
boolean stdStreams;
35+
@Option(names = "--trace", description = "use stdout and stdin for communication")
36+
boolean enableTracing;
37+
38+
@Option(names = "--server", paramLabel = "PORT", description = "enables the TCP server mode")
39+
@Nullable
40+
Integer serverPort;
41+
42+
@Option(names = "--connectTo", paramLabel = "PORT", description = "enables the TCP client mode")
43+
@Nullable
44+
Integer clientPort;
45+
46+
47+
@Option(names = "--infile", paramLabel = "FILE or PIPE", description = "read from named pipe or file")
48+
@Nullable
49+
File inFile;
50+
51+
@Option(names = "--outfile", paramLabel = "FILE or PIPE", description = "write to named pipe or file")
52+
File outFile;
53+
54+
@Option(names = {"-h", "--help"}, usageHelp = true, description = "display a help message")
55+
boolean helpRequested = false;
56+
57+
@Option(names = "--websocket")
58+
boolean websocket;
59+
//endregion
60+
61+
public static void main(String[] args) {
62+
new CommandLine(new StartServer()).execute(args);
63+
}
64+
65+
private InputStream in;
66+
private OutputStream out;
67+
68+
private void establishStreams() throws IOException {
69+
in = System.in;
70+
out = System.out;
71+
72+
if (stdStreams) {
73+
return;
74+
}
75+
76+
if (clientPort != null) {
77+
var socket = new Socket(InetAddress.getLocalHost(), clientPort);
78+
socket.setKeepAlive(true);
79+
socket.setTcpNoDelay(true);
80+
in = socket.getInputStream();
81+
out = socket.getOutputStream();
82+
return;
83+
}
84+
85+
if (serverPort != null) {
86+
var server = new ServerSocket(serverPort);
87+
LOGGER.info("Waiting on port {}", serverPort);
88+
var socket = server.accept();
89+
LOGGER.info("Connection to client established: {}", socket.getRemoteSocketAddress());
90+
socket.setKeepAlive(true);
91+
socket.setTcpNoDelay(true);
92+
in = socket.getInputStream();
93+
out = socket.getOutputStream();
94+
return;
95+
}
96+
97+
98+
if (inFile != null) {
99+
in = new FileInputStream(inFile);
100+
}
101+
102+
if (outFile != null) {
103+
out = new FileOutputStream(outFile);
104+
}
105+
106+
if (out == null || in == null) {
107+
throw new IllegalStateException("Could not initialize the streams");
108+
}
109+
}
110+
111+
112+
@Override
113+
public void run() {
114+
if (helpRequested) {
115+
return;
116+
}
117+
118+
/*
119+
var server = new Server();
120+
var connector = new ServerConnector();
121+
server.addConnector(connector);
122+
// Setup the basic application "context" for this application at "/"
123+
// This is also known as the handler tree (in jetty speak)
124+
var context = new ServletContextHandler(ServletContextHandler.SESSIONS);
125+
context.setContextPath("/");
126+
server.setHandler(context);
127+
128+
// Initialize javax.websocket layer
129+
JavaxWebSocketServletContainerInitializer.configure(context, (servletContext, wsContainer) ->
130+
{
131+
// Configure defaults for container
132+
wsContainer.setDefaultMaxTextMessageBufferSize(65535);
133+
134+
// Add WebSocket endpoint to javax.websocket layer
135+
wsContainer.addEndpoint(WebSocketEndpoint.class);
136+
});*/
137+
138+
139+
try {
140+
if (websocket) {
141+
var launcherBuilder = new WebSocketLauncherBuilder<ClientApi>()
142+
.setOutput(out)
143+
.setInput(in)
144+
.traceMessages(new PrintWriter(System.err))
145+
.validateMessages(true);
146+
launcherBuilder.configureGson(StartServer::configureJson);
147+
launcherBuilder.setLocalService(new KeyApiImpl());
148+
launcherBuilder.setRemoteInterface(ClientApi.class);
149+
launcherBuilder.create().startListening().get();
150+
} else {
151+
establishStreams();
152+
try (var lin = in; var lout = out) {
153+
var listener = launch(lout, lin);
154+
LOGGER.info("JSON-RPC is listening for requests");
155+
listener.startListening().get();
156+
}
157+
}
158+
} catch (IOException | InterruptedException | ExecutionException e) {
159+
throw new RuntimeException(e);
160+
}
161+
}
162+
163+
public static void configureJson(GsonBuilder gsonBuilder) {
164+
gsonBuilder.registerTypeAdapter(File.class, new FileTypeAdapter());
165+
}
166+
167+
public static Launcher<ClientApi> launch(OutputStream out, InputStream in) {
168+
// var localServices = getLocalServices();
169+
// var remoteInterfaces = getRemoteInterfaces();
170+
var launcherBuilder = new Launcher.Builder<ClientApi>()
171+
.setOutput(out)
172+
.setInput(in)
173+
.traceMessages(new PrintWriter(System.err))
174+
.validateMessages(true);
175+
176+
launcherBuilder.configureGson(StartServer::configureJson);
177+
178+
//if (localServices != null && !localServices.isEmpty())
179+
launcherBuilder.setLocalService(new KeyApiImpl());
180+
//if (remoteInterfaces != null && !remoteInterfaces.isEmpty())
181+
launcherBuilder.setRemoteInterface(ClientApi.class);
182+
183+
return launcherBuilder.create();
184+
}
185+
186+
187+
private static Collection<Class<? extends ClientApi>> getRemoteInterfaces() {
188+
return Collections.singleton(ClientApi.class);
189+
/* return ServiceLoader.load(ClientService.class)
190+
.stream()
191+
.map(ServiceLoader.Provider::type)
192+
.collect(Collectors.toSet());
193+
*/
194+
}
195+
196+
private static List<Object> getLocalServices() {
197+
return Collections.singletonList(new KeyApiImpl());
198+
/*return ServiceLoader.load(KeyService.class)
199+
.stream().map(ServiceLoader.Provider::get)
200+
.map(it -> (Object) it)
201+
.toList();*/
202+
}
203+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.keyproject.key.api.remoteapi;
2+
3+
/**
4+
* @author Alexander Weigl
5+
* @version 1 (06.10.23)
6+
*/
7+
public record EnvId(String id) {
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.keyproject.key.api.remoteapi;
2+
3+
import java.io.File;
4+
import java.util.List;
5+
6+
public record LoadParams(File keyFile, File javaFile, List<File> classPath, File bootClassPath, List<File> includes) {
7+
8+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.keyproject.key.api.remoteclient;
2+
3+
record LogMessageParams(
4+
/**
5+
* The message type. See {@link MessageType}
6+
*/
7+
MessageType type,
8+
9+
/**
10+
* The actual message
11+
*/
12+
String message
13+
) {
14+
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.keyproject.key.api.remoteclient;
2+
3+
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
4+
5+
public record LogTraceParams(
6+
/**
7+
* The message to be logged.
8+
*/
9+
@NonNull
10+
String messag,
11+
12+
/**
13+
* Additional information that can be computed if the `trace` configuration
14+
* is set to `'verbose'`
15+
*/
16+
String verbose
17+
) {
18+
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.keyproject.key.api.remoteclient;
2+
3+
public record MessageActionItem(
4+
/**
5+
* A short title like 'Retry', 'Open Log' etc.
6+
*/
7+
String title
8+
) {
9+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.keyproject.key.api.remoteclient;
2+
3+
public enum MessageType {
4+
Unused,
5+
/**
6+
* An error message.
7+
*/
8+
Error,
9+
/**
10+
* A warning message.
11+
*/
12+
Warning,
13+
/**
14+
* An information message.
15+
*/
16+
Info,
17+
/**
18+
* A log message.
19+
*/
20+
Log,
21+
/**
22+
* A debug message.
23+
*
24+
* @proposed
25+
* @since 3.18.0
26+
*/
27+
Debug
28+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.keyproject.key.api.remoteclient;
2+
3+
import de.uka.ilkd.key.pp.Range;
4+
5+
public record ShowDocumentParams(
6+
/**
7+
* The uri to show.
8+
*/
9+
String uri,
10+
11+
/**
12+
* Indicates to show the resource in an external program.
13+
* To show, for example, `https://code.visualstudio.com/`
14+
* in the default WEB browser set `external` to `true`.
15+
*/
16+
Boolean external,
17+
18+
/**
19+
* An optional property to indicate whether the editor
20+
* showing the document should take focus or not.
21+
* Clients might ignore this property if an external
22+
* program is started.
23+
*/
24+
Boolean takeFocus,
25+
26+
/**
27+
* An optional selection range if the document is a text
28+
* document. Clients might ignore the property if an
29+
* external program is started or the file is not a text
30+
* file.
31+
*/
32+
Range selection
33+
) {
34+
35+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.keyproject.key.api.remoteclient;
2+
3+
public record ShowDocumentResult(
4+
/**
5+
* A boolean indicating if the show was successful.
6+
*/
7+
boolean success
8+
) {
9+
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.keyproject.key.api.remoteclient;
2+
3+
public record ShowMessageParams(
4+
/**
5+
* The message type. See {@link MessageType}.
6+
*/
7+
MessageType type,
8+
9+
/**
10+
* The actual message.
11+
*/
12+
String message) {
13+
14+
}

0 commit comments

Comments
 (0)