diff --git a/NetPanel.Bl/SshBl.cs b/NetPanel.Bl/SshBl.cs index b42cc7b..8e22fdb 100644 --- a/NetPanel.Bl/SshBl.cs +++ b/NetPanel.Bl/SshBl.cs @@ -16,47 +16,109 @@ namespace NetPanel.Bl private string _pwd = ""; private string _host = ""; - private SshClient client = null; + /// + /// 客户端 + /// + private SshClient _client = null; + /// + /// sell + /// + private ShellStream _shellStream = null; + /// + /// 读取流 + /// + private StreamReader _reader = null; + /// + /// 写入流 + /// + private StreamWriter _writer = null; - public SshBl(string host, string username, string pwd) + /// + /// 是否连接完成 + /// + private bool _isConnected = false; + + + + + + /// + /// ssh连接 + /// + /// ip + /// 登录用户 + /// 登录密码 + /// 单元格 + /// 行 + /// 宽 + /// 高 + public SshBl(string host, string username, string pwd, uint columns, uint rows, uint width, uint height) { _username = username; _pwd = pwd; _host = host; - client = new SshClient(host, username, pwd); - client.Connect(); + _client = new SshClient(host, username, pwd); + _client.Connect(); + if (_client.IsConnected) + { + _shellStream = _client.CreateShellStream("xterm", columns, rows, width, height, 1024); + _reader = new StreamReader(_shellStream); + _writer = new StreamWriter(_shellStream); + } } + /// + /// 单条读取,可循环读取 + /// + /// - public StreamReader RunCommand(string command) + public string ReadLine() { - - var sshCommand = client.CreateCommand(command); - var asyncExecute = sshCommand.BeginExecute(); - - return new StreamReader(sshCommand.OutputStream); - //string outStr; - //while ((outStr = reader.ReadLine()) != null) - //{ - - //} + return _reader.ReadLine(); } - public string ServerVersion() + /// + /// 写入命令 + /// + /// + + public void WriteLine(string line) { - return client.ConnectionInfo.ServerVersion; - + _writer.WriteLine(line); } + + /// + /// 全部读取,可循环读取 + /// + /// + public string ReadToEnd() + { + return _reader.ReadToEnd(); + } + + + /// + /// Ssh 客户端 + /// + public SshClient Client { get { return _client; } } + + /// /// 关闭 /// public void Dispose() { - client.Disconnect(); - client.Dispose(); + + if (_writer != null) _writer.Close(); + if (_reader != null) _reader.Close(); + //if (_shellStream != null) _shellStream.Close(); + if (_shellStream != null) _shellStream.Dispose(); + + if (_client != null) { _client.Disconnect(); _client.Dispose(); } + } } } diff --git a/NetPanel/Controllers/SSH/SSHController.cs b/NetPanel/Controllers/SSH/SSHController.cs index 7590b22..d651cf4 100644 --- a/NetPanel/Controllers/SSH/SSHController.cs +++ b/NetPanel/Controllers/SSH/SSHController.cs @@ -1,7 +1,9 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using NetPanel.Bl; - +using NetPanel.Help; +using Renci.SshNet; +using System.Diagnostics; using System.Text; namespace NetPanel.Controllers.SSH @@ -9,14 +11,43 @@ namespace NetPanel.Controllers.SSH public class SSHController : Controller { - - public IActionResult SSH() + + public async Task SSH() { - //SshBl sshBl = new SshBl("172.31.110.239", "root", "123456789"); + //SshBl sshBl = new SshBl("172.29.119.239", "root", "123456789", 80, 24, 800, 600); + + + + //var output = sshBl.ReadLine(); + + //sshBl.WriteLine("top"); + //int cc = 0; + //while (true) + //{ + // var outpu3 = sshBl.Read(); + + // if (cc == 0) + // { + // await Task.Delay(5000); + // sshBl.WriteLine("\x03"); + + // cc = 1; + // } + // else if (cc == 2) + // { + // break; + // } + + //} + + + + //sshBl.Dispose(); + ////string tt = sshBl.ServerVersion(); //StringBuilder sbStr = new StringBuilder(); //string tt = ""; @@ -47,6 +78,6 @@ namespace NetPanel.Controllers.SSH - + } } diff --git a/NetPanel/SignalR/ChatHub.cs b/NetPanel/SignalR/ChatHub.cs index a1779ca..d701871 100644 --- a/NetPanel/SignalR/ChatHub.cs +++ b/NetPanel/SignalR/ChatHub.cs @@ -1,7 +1,13 @@ using Microsoft.AspNetCore.SignalR; using NetPanel.Bl; using NetPanel.Entity; +using NetPanel.Help; +using Renci.SshNet.Common; using Renci.SshNet.Messages; +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Net.Sockets; using System.Security.Cryptography; using System.Text; @@ -10,6 +16,15 @@ namespace NetPanel.SignalR public class ChatHub : Hub { + /// + /// ssh 管理 + /// + private static Dictionary dicSsh = new Dictionary(); + + /// + /// 建立连接时 + /// + /// public override async Task OnConnectedAsync() { @@ -25,30 +40,114 @@ namespace NetPanel.SignalR await client.SendAsync("ConnectionId", rm); } + /// + /// 断开异步时 + /// + /// + /// - public async Task CreateConnectionAsync(string connectionId, string command) + public override async Task OnDisconnectedAsync(Exception? ex) + { + var cid = Context.ConnectionId; + if (dicSsh.ContainsKey(cid)) + { + dicSsh[cid].Dispose(); + dicSsh.Remove(cid); + } + await base.OnDisconnectedAsync(ex); + } + + /// + /// 创建终端链接 + /// + /// + /// + /// + public async Task CreateConnectionAsync(uint width, uint height, uint columns, uint rows) + { + + var cid = Context.ConnectionId; + ReturnMsg rm = new ReturnMsg(); + rm.Code = 1; + if (!dicSsh.ContainsKey(cid)) + { + SshBl ssh = new SshBl("172.29.119.239", "root", "123456789", columns, rows, width, height); + dicSsh.Add(cid, ssh); + ReceiveMessage(cid); + } + return rm; + } + + /// + /// 写入命令 + /// + /// + /// + public async Task WriteLineAsync(string curr_line) { ReturnMsg rm = new ReturnMsg(); rm.Code = 1; - - //SshBl sshBl = new SshBl("172.31.110.239", "root", "123456789"); - ////string tt = sshBl.ServerVersion(); - //StringBuilder sbStr = new StringBuilder(); - //string tt = ""; - //var reader = sshBl.RunCommand("top"); - //string outStr = null; - //while ((outStr = reader.ReadLine()) != null) - //{ - // sbStr.Append(outStr + "/r/n"); - //} - rm.Obj = "====>" + command; - //根据id获取指定客户端 - var client = Clients.Client(connectionId); - - // await client.SendAsync("CreateConnectionAsync", rm); - - + var cid = Context.ConnectionId; + if (dicSsh.ContainsKey(cid)) + { + dicSsh[cid].WriteLine(curr_line); + ReceiveMessage(cid); + } return rm; } + + + + + /// + /// 发送响应 + /// + /// + /// + public async Task ReceiveMessage(string cid) + { + ReturnMsg rm = new ReturnMsg(); + rm.Code = 1; + int count = 0; + SshBl ssh = dicSsh[cid]; + //根据id获取指定客户端 + var client = Clients.Client(cid); + while (true) + { + try + { + + string line = ssh.ReadLine(); + if (line.IsNotNull()) + { + if (line.Contains(":~#")) + { + rm.Code = 2; ; + rm.Obj = line; + await client.SendAsync("ReceiveMessage", rm); + break; + } + else + { + rm.Obj = line + "\n"; + await client.SendAsync("ReceiveMessage", rm); + } + } + else + { + await Task.Delay(100); + } + } + catch (Exception ex) + { + } + } + + + + + } + + } } diff --git a/NetPanel/Views/SSH/SSH.cshtml b/NetPanel/Views/SSH/SSH.cshtml index ec07a45..b238536 100644 --- a/NetPanel/Views/SSH/SSH.cshtml +++ b/NetPanel/Views/SSH/SSH.cshtml @@ -49,8 +49,8 @@ convertEol: true, //启用时,光标将设置为下一行的开头 disableStdin: false, //是否应禁用输入。 theme: { - foreground: 'yellow', //字体 - background: '#060101', //背景色 + // foreground: 'yellow', //字体 + // background: '#060101', //背景色 cursor: 'help',//设置光标 } }); @@ -58,9 +58,15 @@ // 获取窗口的宽度和高度。 const width = window.innerWidth; const height = window.innerHeight; + const columns = parseInt(width / 10); + const rows = parseInt(height / 22); + + //cursorx 这个长度不能删除,用于ev.keyCode === 8 + var cursorx = 0; + // 调整终端的尺寸。 - term.resize(parseInt(width / 10), parseInt(height / 22)); + term.resize(columns, parseInt(height / 22)); //回车输入的内容 var curr_line = ''; @@ -71,30 +77,38 @@ var connectionId = ''; term.open(document.getElementById('terminal')); + + term.prompt = () => { term.write('\n\u001b[32m$ >\u001b[37m'); }; - //通讯 var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); //signalR接收消息 - connection.on("ReceiveMessage", function (user, message) { - term.write(message); + connection.on("ReceiveMessage", function (msg) { + term.write(msg.obj); + }); - //获取通讯id + // 已建立连接 connection.on("ConnectionId", function (msg) { - - term.write('Welcome to my Scheme web intepreter!\r\n123'); - term.prompt(); + // term.write('Welcome to my Scheme web intepreter!\r\n123'); + // term.prompt(); connectionId = msg.obj; + //创建 ssh 客户端 + connection.invoke('CreateConnectionAsync', width, height, columns, rows).then((result) => { + + }); }); + + + // 监听后端终端关闭 connection.on('WriteErrorAsync', () => { @@ -104,26 +118,26 @@ - - term.on('key', function (key, ev) { + const printable = !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey //const printable = !e.domEvent.altKey && !e.domEvent.altGraphKey && !e.domEvent.ctrlKey && !e.domEvent.metaKey; - + if (cursorx == 0) { + cursorx = term.buffer.cursorX; + } if (ev.keyCode === 13) { // Enter key if (curr_line.replace(/^\s+|\s+$/g, '').length != 0) { // Check if string is all whitespace entries.push(curr_line); currPos = entries.length - 1; // term.prompt(); - connection.invoke('CreateConnectionAsync', connectionId, curr_line).then((result) => { - if (result.code == 1) { - //term.prompt(); - //term.write(result.obj); - term.write('\n' + result.obj); - term.prompt(); + connection.invoke('WriteLineAsync', curr_line).then((result) => { + if (result.code == 1) { + + // term.write('\n' + result.obj); + // term.prompt(); } }); @@ -133,7 +147,7 @@ } curr_line = ''; } else if (ev.keyCode === 8) { // Backspace - if (term.buffer.cursorX > 3) { + if (term.buffer.cursorX > cursorx) { curr_line = curr_line.slice(0, -1); term.write('\b \b'); }