/* * Copyright 2015 Julien Viet * * 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.termd.core.pty; import io.termd.core.readline.Keymap; import io.termd.core.readline.Readline; import io.termd.core.tty.TtyConnection; import io.termd.core.tty.TtyEvent; import io.termd.core.util.Helper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.util.function.Consumer; /** * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> */ public class TtyBridge { Logger log = LoggerFactory.getLogger(TtyBridge.class); final TtyConnection conn; private Consumer<PtyMaster> processListener; private Consumer<int[]> processStdoutListener; private Consumer<String> processStdinListener; public TtyBridge(TtyConnection conn) { this.conn = conn; } public Consumer<PtyMaster> getProcessListener() { return processListener; } public TtyBridge setProcessListener(Consumer<PtyMaster> processListener) { this.processListener = processListener; return this; } public Consumer<String> getProcessStdinListener() { return processStdinListener; } public TtyBridge setProcessStdinListener(Consumer<String> processStdinListener) { this.processStdinListener = processStdinListener; return this; } public Consumer<int[]> getProcessStdoutListener() { return processStdoutListener; } public TtyBridge setProcessStdoutListener(Consumer<int[]> processStdoutListener) { this.processStdoutListener = processStdoutListener; return this; } public TtyBridge readline() { InputStream inputrc = Keymap.class.getResourceAsStream("inputrc"); Keymap keymap = new Keymap(inputrc); Readline readline = new Readline(keymap); for (io.termd.core.readline.Function function : Helper.loadServices(Thread.currentThread().getContextClassLoader(), io.termd.core.readline.Function.class)) { log.trace("Server is adding function to readline: {}", function); readline.addFunction(function); } conn.setTerminalTypeHandler(term -> { // Not used yet but we should propagage this to the process builder // System.out.println("CLIENT $TERM=" + term); }); conn.stdoutHandler().accept(Helper.toCodePoints("Welcome sir\n")); read(conn, readline); return this; } void read(final TtyConnection conn, final Readline readline) { readline.readline(conn, "% ", line -> { if (processStdinListener != null) { processStdinListener.accept(line); } if (line == null) { conn.close(); return; } PtyMaster task = new PtyMaster(line, buffer -> { conn.execute(() -> { conn.stdoutHandler().accept(buffer); }); if (processStdoutListener != null) { processStdoutListener.accept(buffer); } }, v -> { conn.setEventHandler(null); conn.execute(() -> read(conn, readline)); }); conn.setEventHandler((event,cp) -> { if (event == TtyEvent.INTR) { task.interruptProcess(); } }); if (processListener != null) { processListener.accept(task); } task.start(); }); } }