예제 #1
0
        /// <summary>
        /// Reads data from the child process
        /// </summary>
        void ChildProcessRead(DispatchData data, int error)
        {
            using (var map = data.CreateMap(out var buffer, out var size)) {
                // Faster, but harder to debug:
                // terminalView.Feed (buffer, (int) size);
                if (size == 0)
                {
                    if (!string.IsNullOrEmpty(ExitText))
                    {
                        terminalView.Terminal.Feed(ExitText);
                    }

                    ShellExited?.Invoke();
                    return;
                }
                byte [] copy = new byte [(int)size];
                Marshal.Copy(buffer, copy, 0, (int)size);

#if DEBUG
                System.IO.File.WriteAllBytes("/tmp/log-" + (x++), copy);
#endif
                terminalView.Feed(copy);
            }

            DispatchIO.Read(shellFileDescriptor, (nuint)readBuffer.Length, DispatchQueue.CurrentQueue, ChildProcessRead);
        }
예제 #2
0
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            terminalView = new TerminalView(View.Frame);
            var t    = terminalView.Terminal;
            var size = new UnixWindowSize();

            GetSize(t, ref size);

            pid = Pty.ForkAndExec("/bin/bash", new string [] { "/bin/bash" }, Terminal.GetEnvironmentVariables(), out fd, size);
            DispatchIO.Read(fd, (nuint)readBuffer.Length, DispatchQueue.CurrentQueue, ChildProcessRead);


            terminalView.UserInput += (byte [] data) => {
                DispatchIO.Write(fd, DispatchData.FromByteBuffer(data), DispatchQueue.CurrentQueue, ChildProcessWrite);
            };
            terminalView.Feed("Welcome to XtermSharp - NSView frontend!\n");
            terminalView.TitleChanged += (TerminalView sender, string title) => {
                View.Window.Title = title;
            };
            terminalView.SizeChanged += (newCols, newRows) => {
                UnixWindowSize nz = new UnixWindowSize();
                GetSize(t, ref nz);
                var res = Pty.SetWinSize(fd, ref nz);
                Console.WriteLine(res);
            };
            View.AddSubview(terminalView);
        }
예제 #3
0
        /// <summary>
        /// Notfies the subshell that the user entered some data
        /// </summary>
        public override void NotifyUserInput(byte [] data)
        {
            if (!IsRunning)
            {
                return;
            }

            DispatchIO.Write(shellFileDescriptor, DispatchData.FromByteBuffer(data), DispatchQueue.CurrentQueue, ChildProcessWrite);
        }
예제 #4
0
        /// <summary>
        /// Launches the shell
        /// </summary>
        public virtual void Start(string shellPath = "/bin/bash", string [] args = null, string [] env = null)
        {
            OnStart();

            var shellArgs = args == null ? new string [1] : new string [args.Length + 1];

            shellArgs [0] = shellPath;
            args?.CopyTo(shellArgs, 1);

            ProcessId = Pty.ForkAndExec(shellPath, shellArgs, env ?? Terminal.GetEnvironmentVariables(), out shellFileDescriptor, initialSize);
            DispatchIO.Read(shellFileDescriptor, (nuint)readBuffer.Length, DispatchQueue.CurrentQueue, ChildProcessRead);
        }
예제 #5
0
 static void ReceiveLoop(NWConnection connection)
 {
     connection.ReceiveData(1, uint.MaxValue, (DispatchData dispatchData, NWContentContext context, bool isComplete, NWError error) => {
         Action scheduleNext = () => {
             // If the context is marked as complete, and is the final context,
             // we're read-closed.
             if (isComplete)
             {
                 if (context != null && context.IsFinal)
                 {
                     if (verbose)
                     {
                         warn("Exiting because isComplete && context.IsFinal");
                     }
                     Environment.Exit(0);
                 }
                 if (dispatchData == null)
                 {
                     if (verbose)
                     {
                         warn($"Exiting because isComplete && data == zero;  error={error}");
                     }
                     Environment.Exit(0);
                 }
             }
             if (error == null)
             {
                 ReceiveLoop(connection);
             }
         };
         if (dispatchData != null)
         {
             const int STDOUT_FILENO = 1;
             DispatchIO.Write(STDOUT_FILENO, dispatchData, DispatchQueue.MainQueue, (data, stdoutError) => {
                 if (stdoutError != 0)
                 {
                     warn("stdout write error");
                 }
                 scheduleNext();
             });
         }
         else
         {
             scheduleNext();
         }
     });
 }
예제 #6
0
        /// <summary>
        /// Launches the shell
        /// </summary>
        public void StartShell(string shellPath = "/bin/bash", string [] args = null)
        {
            // TODO: throw error if already started
            terminalView.Feed(WelcomeText + "\n");

            var size = new UnixWindowSize();

            GetUnixWindowSize(terminalView.Frame, terminalView.Terminal.Rows, terminalView.Terminal.Cols, ref size);

            var shellArgs = args == null ? new string [1] : new string [args.Length + 1];

            shellArgs [0] = shellPath;
            args?.CopyTo(shellArgs, 1);

            shellPid = Pty.ForkAndExec(shellPath, shellArgs, Terminal.GetEnvironmentVariables(), out shellFileDescriptor, size);
            DispatchIO.Read(shellFileDescriptor, (nuint)readBuffer.Length, DispatchQueue.CurrentQueue, ChildProcessRead);
        }
예제 #7
0
        void ChildProcessRead(DispatchData data, int error)
        {
            using (var map = data.CreateMap(out var buffer, out var size)) {
                // Faster, but harder to debug:
                // terminalView.Feed (buffer, (int) size);
                //Console.WriteLine ("Read {0} bytes", size);
                if (size == 0)
                {
                    View.Window.Close();
                    return;
                }
                byte [] copy = new byte [(int)size];
                Marshal.Copy(buffer, copy, 0, (int)size);

                System.IO.File.WriteAllBytes("/tmp/log-" + (x++), copy);
                terminalView.Feed(copy);
            }
            DispatchIO.Read(fd, (nuint)readBuffer.Length, DispatchQueue.CurrentQueue, ChildProcessRead);
        }
예제 #8
0
    static void SendLoop(NWConnection connection)
    {
        const int STDIN_FILENO = 0;

        DispatchIO.Read(STDIN_FILENO, 8192, DispatchQueue.MainQueue, (DispatchData readData, int stdinError) => {
            if (stdinError != 0)
            {
                warn($"Standard input error: {stdinError}");
            }
            else if (readData == null || readData.Size == 0)
            {
                // Null data represent EOF
                // Send a "write close" on the connection, by sending
                // null data with the final message context marked as
                // complete.  Note that it is valid to send with null
                // data but a non-null context.
                connection.Send((byte [] )null, context: NWContentContext.FinalMessage, isComplete: true, callback: (NWError error) => {
                    if (error != null)
                    {
                        warn($"send error: {error.ErrorCode}");
                    }
                });
                // Stop reading from stdin, do not schedule another SendLoop
            }
            else
            {
                connection.Send(readData, context: NWContentContext.DefaultMessage, isComplete: true, callback: (NWError error) => {
                    if (error != null)
                    {
                        warn($"send error: {error.ErrorCode}");
                    }
                    else
                    {
                        // continue reading from stdin
                        SendLoop(connection);
                    }
                });
            }
        });
    }
예제 #9
0
        /// <summary>
        /// Reads data from the child process
        /// </summary>
        void ChildProcessRead(DispatchData data, int error)
        {
            using (var map = data.CreateMap(out var buffer, out var size)) {
                // Faster, but harder to debug:
                // terminalView.Feed (buffer, (int) size);
                if (size == 0)
                {
                    OnStop();
                    return;
                }

                byte [] copy = new byte [(int)size];
                Marshal.Copy(buffer, copy, 0, (int)size);

#if DEBUG_LOG_FILE
                System.IO.File.WriteAllBytes("/tmp/log-" + (debugFileIndex++), copy);
#endif
                SendOnData(copy);
            }

            DispatchIO.Read(shellFileDescriptor, (nuint)readBuffer.Length, DispatchQueue.CurrentQueue, ChildProcessRead);
        }
예제 #10
0
        /// <summary>
        /// Notifies the subshell that the terminal emited some data, eg a response to device status
        /// </summary>
        public override void NotifyDataEmitted(string txt)
        {
            var data = System.Text.Encoding.UTF8.GetBytes(txt);

            DispatchIO.Write(shellFileDescriptor, DispatchData.FromByteBuffer(data), DispatchQueue.CurrentQueue, ChildProcessWrite);
        }
예제 #11
0
 void HandleUserInput(byte [] data)
 {
     DispatchIO.Write(shellFileDescriptor, DispatchData.FromByteBuffer(data), DispatchQueue.CurrentQueue, ChildProcessWrite);
 }