import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.System.Logger;
import java.net.StandardProtocolFamily;
import java.net.UnixDomainSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
+import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
-import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.nio.file.StandardWatchEventKinds;
-import java.nio.file.WatchEvent;
-import java.nio.file.WatchKey;
-import java.nio.file.WatchService;
import java.util.UUID;
public class JShellClient {
+ private final static Logger logger = System.getLogger(JShellClient.class.getName());
+
public final static String STDIO = "stdio";
public final static String STDERR = "stderr";
public final static String CMDIO = "cmdio";
public static void main(String[] args) throws IOException, InterruptedException {
try {
Path targetStateDirectory = Paths.get(args[0]);
+ String symbolicName = args[1];
Path localBase = targetStateDirectory.resolve("jsh");
if (Files.isSymbolicLink(localBase)) {
localBase = localBase.toRealPath();
toRawTerminal();
}
- SocketPipeSource std = new SocketPipeSource();
- std.setInputStream(System.in);
- std.setOutputStream(System.out);
+ SocketPipeSource stdio = new SocketPipeSource();
+ stdio.setInputStream(System.in);
+ stdio.setOutputStream(System.out);
+
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ // logger.log(Logger.Level.INFO, "Shutting down...");
+ System.out.println("\nShutting down...");
+ stdio.shutdown();
+ }, "Shut down JShell client"));
+ Path bundleSnDir = localBase.resolve(symbolicName);
+ if (!Files.exists(bundleSnDir))
+ Files.createDirectory(bundleSnDir);
UUID uuid = UUID.randomUUID();
- Path sessionDir = localBase.resolve(uuid.toString());
+ Path sessionDir = bundleSnDir.resolve(uuid.toString());
Files.createDirectory(sessionDir);
- Path stdPath = sessionDir.resolve(JShellClient.STDIO);
-
- // wait for sockets to be available
- WatchService watchService = FileSystems.getDefault().newWatchService();
- sessionDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
- WatchKey key;
- watch: while ((key = watchService.take()) != null) {
- for (WatchEvent<?> event : key.pollEvents()) {
- Path path = sessionDir.resolve((Path) event.context());
- if (Files.isSameFile(stdPath, path)) {
- break watch;
- }
- }
+ Path stdioPath = sessionDir.resolve(JShellClient.STDIO);
+
+ while (!(Files.exists(stdioPath))) {
+ // TODO timeout
+ Thread.sleep(50);
+
+// // wait for sockets to be available
+// WatchService watchService = FileSystems.getDefault().newWatchService();
+// sessionDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
+// WatchKey key;
+// watch: while ((key = watchService.take()) != null) {
+// for (WatchEvent<?> event : key.pollEvents()) {
+// Path path = sessionDir.resolve((Path) event.context());
+// if (Files.isSameFile(stdioPath, path)) {
+// break watch;
+// }
+// }
+// }
+// watchService.close();
}
- watchService.close();
- UnixDomainSocketAddress stdSocketAddress = UnixDomainSocketAddress.of(stdPath);
+ UnixDomainSocketAddress stdioSocketAddress = UnixDomainSocketAddress.of(stdioPath.toRealPath());
- SocketChannel channel = SocketChannel.open(StandardProtocolFamily.UNIX);
- channel.connect(stdSocketAddress);
+ try (SocketChannel stdioChannel = SocketChannel.open(StandardProtocolFamily.UNIX)) {
+ stdioChannel.connect(stdioSocketAddress);
+ stdio.forward(stdioChannel);
+ }
- std.forward(channel);
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
- try {
- stty(ttyConfig.trim());
- } catch (Exception e) {
- System.err.println("Exception restoring tty config");
- }
+ if (ttyConfig != null)
+ try {
+ stty(ttyConfig.trim());
+ } catch (Exception e) {
+ System.err.println("Exception restoring tty config");
+ }
}
}
private WritableByteChannel outChannel;
private Thread readOutThread;
+ private Thread forwardThread;
public void forward(SocketChannel channel) throws IOException {
+ forwardThread = Thread.currentThread();
readOutThread = new Thread(() -> {
try {
buffer.rewind();
}
System.exit(0);
+ } catch (ClosedByInterruptException e) {
+ // silent
} catch (IOException e) {
e.printStackTrace();
}
while (channel.isConnected()) {
if (inChannel.read(buffer) < 0)
break;
+// int b = (int) buffer.get(0);
+// if (b == 0x1B) {
+// System.out.println("Ctrl+C");
+// }
+
buffer.flip();
channel.write(buffer);
buffer.rewind();
}
}
+ public void shutdown() {
+ try {
+ inChannel.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ outChannel.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ forwardThread.interrupt();
+ readOutThread.interrupt();
+ }
+
public void setInputStream(InputStream in) {
inChannel = Channels.newChannel(in);
}