You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
657 lines
17 KiB
657 lines
17 KiB
using System;
|
|
using System.Linq;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Collections.Generic;
|
|
|
|
using Sog;
|
|
using Sog.Log;
|
|
using Sog.IO;
|
|
|
|
using Google.Protobuf.WellKnownTypes;
|
|
using Google.Protobuf;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
namespace SMConsole
|
|
{
|
|
/*
|
|
|
|
*/
|
|
public class ConsoleInfo
|
|
{
|
|
public int m_historyPos = -1;
|
|
public List<string> m_history = new List<string>();
|
|
public int m_maxHistoryLen = 100;
|
|
public string m_input = "";
|
|
public string INPUT_PRE_HEAD;
|
|
public string m_historyfile;
|
|
|
|
public ConsoleInfo(string inputHead,string historyFile)
|
|
{
|
|
INPUT_PRE_HEAD = inputHead;
|
|
m_historyfile = historyFile;
|
|
}
|
|
}
|
|
public class SMConsoleInput : Singleton<SMConsoleInput>
|
|
{
|
|
private bool firstHead = false;
|
|
private bool exited = false;
|
|
private bool IsConsoleModle = true;
|
|
|
|
private Dictionary<bool, ConsoleInfo> m_consoleInfo = new Dictionary<bool, ConsoleInfo>();
|
|
|
|
|
|
private static string m_consoleInputHead = "smconsole >";
|
|
private static string m_consoleHistoryfile = "./inputHistory";
|
|
|
|
private static string m_shellInputHead = "shell $:";
|
|
private static string m_shellHistoryfile = "./inputShellHistory";
|
|
|
|
private ConsoleInfo m_ModleInfo => m_consoleInfo[IsConsoleModle];
|
|
|
|
|
|
private bool m_isWindows = OSUtils.IsWindows();
|
|
|
|
|
|
public SMConsoleInput()
|
|
{
|
|
ConsoleInfo info = new ConsoleInfo(m_consoleInputHead, m_consoleHistoryfile);
|
|
m_consoleInfo.Add(true, info);
|
|
info = new ConsoleInfo(m_shellInputHead, m_shellHistoryfile);
|
|
m_consoleInfo.Add(false, info);
|
|
|
|
InitHistoryFromFile();
|
|
}
|
|
|
|
|
|
public void Update()
|
|
{
|
|
try
|
|
{
|
|
if (firstHead == false)
|
|
{
|
|
firstHead = true;
|
|
WriteInputHeadInfo();
|
|
|
|
//System.Threading.Thread runTask = new System.Threading.Thread(this.TryUseThread);
|
|
//runTask.Start();
|
|
}
|
|
CheckReadyKey();
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
TraceLog.Exception(ex);
|
|
}
|
|
}
|
|
|
|
//读取历史记录文件
|
|
private void InitHistoryFromFile()
|
|
{
|
|
try
|
|
{
|
|
foreach (var info in m_consoleInfo.Values)
|
|
{
|
|
string[] allline = File.ReadAllLines(info.m_historyfile);
|
|
if (allline.Length > 0)
|
|
{
|
|
info.m_history.AddRange(allline);
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
//保存历史记录
|
|
private void SaveHistoryToFile()
|
|
{
|
|
try
|
|
{
|
|
foreach (var info in m_consoleInfo.Values)
|
|
{
|
|
File.WriteAllLines(info.m_historyfile, info.m_history.ToArray());
|
|
}
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void WriteToHistTory(string cmd)
|
|
{
|
|
if(string.IsNullOrEmpty(cmd))
|
|
{
|
|
return;
|
|
}
|
|
if (m_ModleInfo.m_history.Count > 0 && m_ModleInfo.m_history.Last() == cmd)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_ModleInfo.m_history.Add(cmd);
|
|
|
|
|
|
if (m_ModleInfo.m_history.Count > m_ModleInfo.m_maxHistoryLen)
|
|
{
|
|
m_ModleInfo.m_history.RemoveAt(0);
|
|
}
|
|
|
|
SaveHistoryToFile();
|
|
}
|
|
|
|
private void RewriteHistoryCmd(string cmd)
|
|
{
|
|
if (!string.IsNullOrEmpty(m_ModleInfo.m_input))
|
|
{
|
|
int x = Console.CursorLeft - m_ModleInfo.m_input.Length;
|
|
int y = Console.CursorTop;
|
|
|
|
Console.SetCursorPosition(x, y);
|
|
for (int i = 0; i < m_ModleInfo.m_input.Length; i++)
|
|
{
|
|
Console.Write(' ');
|
|
}
|
|
Console.SetCursorPosition(x, y);
|
|
}
|
|
m_ModleInfo.m_input = cmd;
|
|
Console.Write(m_ModleInfo.m_input);
|
|
}
|
|
|
|
private void GoBackHistTory()
|
|
{
|
|
if(m_ModleInfo.m_history.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
if(m_ModleInfo.m_historyPos == -1)
|
|
{
|
|
m_ModleInfo.m_historyPos = 0;
|
|
}
|
|
else
|
|
{
|
|
m_ModleInfo.m_historyPos++;
|
|
}
|
|
|
|
if(m_ModleInfo.m_historyPos >= m_ModleInfo.m_history.Count)
|
|
{
|
|
m_ModleInfo.m_historyPos = m_ModleInfo.m_history.Count - 1;
|
|
}
|
|
|
|
string historyCmd = m_ModleInfo.m_history[m_ModleInfo.m_historyPos];
|
|
RewriteHistoryCmd(historyCmd);
|
|
}
|
|
|
|
private void GoFrontHistTory()
|
|
{
|
|
if (m_ModleInfo.m_history.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
if (m_ModleInfo.m_historyPos == -1)
|
|
{
|
|
m_ModleInfo.m_historyPos = m_ModleInfo.m_history.Count-1;
|
|
}
|
|
else
|
|
{
|
|
m_ModleInfo.m_historyPos--;
|
|
}
|
|
|
|
if(m_ModleInfo.m_historyPos < 0)
|
|
{
|
|
m_ModleInfo.m_historyPos = 0;
|
|
}
|
|
|
|
string historyCmd = m_ModleInfo.m_history[m_ModleInfo.m_historyPos];
|
|
RewriteHistoryCmd(historyCmd);
|
|
}
|
|
|
|
private void ClearSpecialCharNum(int charNum)
|
|
{
|
|
int x = Console.CursorLeft;
|
|
int y = Console.CursorTop;
|
|
|
|
Console.SetCursorPosition(x - charNum, y);
|
|
for (int i=0; i<charNum; i++)
|
|
{
|
|
Console.Write(' ');
|
|
}
|
|
|
|
Console.SetCursorPosition(x - charNum, y);
|
|
}
|
|
|
|
private void DoOnBackspace()
|
|
{
|
|
int x = Console.CursorLeft;
|
|
if (m_ModleInfo.m_input.Length > 0 && x > m_ModleInfo.INPUT_PRE_HEAD.Length)
|
|
{
|
|
|
|
int y = Console.CursorTop;
|
|
if( x == m_ModleInfo.INPUT_PRE_HEAD.Length + m_ModleInfo.m_input.Length)
|
|
{
|
|
Console.SetCursorPosition(x - 1, y);
|
|
Console.Write(' ');
|
|
Console.SetCursorPosition(x - 1, y);
|
|
m_ModleInfo.m_input = m_ModleInfo.m_input.Substring(0, m_ModleInfo.m_input.Length - 1);
|
|
}else
|
|
{
|
|
m_ModleInfo.m_input = m_ModleInfo.m_input.Remove(x - m_ModleInfo.INPUT_PRE_HEAD.Length - 1,1);
|
|
WriteRemainChar(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckReadyKey()
|
|
{
|
|
if (! Console.KeyAvailable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int oldX = Console.CursorLeft;
|
|
ConsoleKeyInfo info;
|
|
info = Console.ReadKey(true);
|
|
int newX = Console.CursorLeft;
|
|
//TraceLog.Trace("SMConsoleInput.CheckReadyKey input key {0} char {1} oldX {2} newX {3}", info.Key, info.KeyChar, oldX, newX);
|
|
|
|
if (newX > oldX)
|
|
{
|
|
ClearSpecialCharNum(newX - oldX);
|
|
}
|
|
newX = Console.CursorLeft;
|
|
//乱套了
|
|
if (newX > m_ModleInfo.m_input.Length + m_ModleInfo.INPUT_PRE_HEAD.Length)
|
|
{
|
|
TraceLog.Trace("SMConsoleInput.CheckReadyKey invlaid input key {0} char {1} newX {2} m_input.Length {3} INPUT_PRE_HEAD len {4}"
|
|
, info.Key, info.KeyChar, newX, m_ModleInfo.m_input.Length, m_ModleInfo.INPUT_PRE_HEAD.Length);
|
|
|
|
int y = Console.CursorTop;
|
|
|
|
Console.SetCursorPosition(0, y);
|
|
for(int i=0; i< newX + 10; i++)
|
|
{
|
|
Console.Write(' ');
|
|
}
|
|
Console.SetCursorPosition(0, y);
|
|
WriteInputHeadInfo();
|
|
Console.Write(m_ModleInfo.m_input);
|
|
}
|
|
|
|
if (info.Key == ConsoleKey.Enter)
|
|
{
|
|
m_ModleInfo.m_historyPos = -1;
|
|
ProcessSMCommand(m_ModleInfo.m_input);
|
|
if (exited == false)
|
|
{
|
|
WriteToHistTory(m_ModleInfo.m_input);
|
|
m_ModleInfo.m_input = "";
|
|
Console.WriteLine();
|
|
WriteInputHeadInfo();
|
|
}
|
|
}
|
|
else if(info.Key == ConsoleKey.Tab)
|
|
{
|
|
m_ModleInfo.m_input = m_ModleInfo.m_input + " #tab";
|
|
ProcessSMCommand(m_ModleInfo.m_input);
|
|
}
|
|
//处理退格
|
|
else if (info.Key == ConsoleKey.Backspace)
|
|
{
|
|
DoOnBackspace();
|
|
}
|
|
else if (info.Key == ConsoleKey.Delete)
|
|
{
|
|
DoOnBackspace();
|
|
}
|
|
//Windows
|
|
else if((info.Key == ConsoleKey.UpArrow || info.KeyChar == '[') && m_isWindows)
|
|
{
|
|
GoFrontHistTory();
|
|
}
|
|
else if ((info.Key == ConsoleKey.DownArrow || info.KeyChar == ']'))
|
|
{
|
|
GoBackHistTory();
|
|
}else if(info.Key == ConsoleKey.LeftArrow && m_isWindows)
|
|
{
|
|
DoOnMoveCursorPosition(-1);
|
|
}
|
|
else if (info.Key == ConsoleKey.RightArrow && m_isWindows)
|
|
{
|
|
DoOnMoveCursorPosition(1);
|
|
}
|
|
//Linux
|
|
else if (!m_isWindows && info.KeyChar == 79 && Console.KeyAvailable)
|
|
{
|
|
ConsoleKeyInfo exinfo = Console.ReadKey(true);
|
|
if (exinfo.KeyChar == 65)
|
|
{
|
|
GoFrontHistTory();
|
|
}
|
|
else if (exinfo.KeyChar == 66)
|
|
{
|
|
GoBackHistTory();
|
|
}
|
|
else if (exinfo.KeyChar == 68)
|
|
{
|
|
DoOnMoveCursorPosition(-1);
|
|
}
|
|
else if (exinfo.KeyChar == 67)
|
|
{
|
|
DoOnMoveCursorPosition(1);
|
|
}
|
|
}
|
|
else if (IsValidInputChar(info.KeyChar))
|
|
{
|
|
//TraceLog.Trace("CheckReadyKey valid input key {0} char {1} oldX {2} newX {3}", info.Key, info.KeyChar, oldX , newX);
|
|
//回显
|
|
int NowX = Console.CursorLeft;
|
|
if (NowX == m_ModleInfo.INPUT_PRE_HEAD.Length + m_ModleInfo.m_input.Length)
|
|
{
|
|
Console.Write(info.KeyChar);
|
|
m_ModleInfo.m_input += info.KeyChar;
|
|
}
|
|
else
|
|
{
|
|
m_ModleInfo.m_input =
|
|
m_ModleInfo.m_input.Insert(NowX - m_ModleInfo.INPUT_PRE_HEAD.Length, info.KeyChar.ToString());
|
|
WriteRemainChar(1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private void WriteRemainChar(int addPosition)
|
|
{
|
|
int NowX = Console.CursorLeft;
|
|
if(addPosition < 0 )
|
|
{
|
|
Console.SetCursorPosition(NowX + addPosition, Console.CursorTop);
|
|
NowX = Console.CursorLeft;
|
|
}
|
|
for(int i = NowX - m_ModleInfo.INPUT_PRE_HEAD.Length; i < m_ModleInfo.m_input.Length;i++)
|
|
{
|
|
Console.Write(m_ModleInfo.m_input[i]);
|
|
}
|
|
if(addPosition < 0 )
|
|
{
|
|
Console.Write(' ');
|
|
}
|
|
if (addPosition > 0)
|
|
{
|
|
Console.SetCursorPosition(NowX + addPosition, Console.CursorTop);
|
|
}else
|
|
{
|
|
Console.SetCursorPosition(NowX, Console.CursorTop);
|
|
}
|
|
|
|
}
|
|
|
|
private void DoOnMoveCursorPosition(int symbol)
|
|
{
|
|
int NowX = Console.CursorLeft;
|
|
int NowY = Console.CursorTop;
|
|
if(symbol < 0 && NowX > m_ModleInfo.INPUT_PRE_HEAD.Length)
|
|
{
|
|
Console.SetCursorPosition(Console.CursorLeft + symbol, Console.CursorTop);
|
|
}else if(symbol > 0 && NowX < m_ModleInfo.m_input.Length + m_ModleInfo.INPUT_PRE_HEAD.Length)
|
|
{
|
|
Console.SetCursorPosition(Console.CursorLeft + symbol, Console.CursorTop);
|
|
}
|
|
}
|
|
|
|
private void WriteInputHeadInfo()
|
|
{
|
|
if(IsConsoleModle)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.White;
|
|
}else
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkGreen;
|
|
}
|
|
Console.Write(m_ModleInfo.INPUT_PRE_HEAD);
|
|
}
|
|
|
|
|
|
|
|
private bool IsValidInputChar(char key)
|
|
{
|
|
if(key >= 'a' && key <= 'z')
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (key >= 'A' && key <= 'Z')
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (key >= '0' && key <= '9')
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//服务器id *.*.*
|
|
//gm指令-t -b
|
|
//base64编码
|
|
//win目录
|
|
//文件名,中文文件名这里不支持
|
|
//shell
|
|
if (key == '*' || key == '.' || key == ' '
|
|
|| key == '-'
|
|
|| key == '+' || key == '/' || key == '='
|
|
|| key == ':' || key == '\\'
|
|
|| key == '_'
|
|
|| key == '>' || key == '<' || key == '|' || key == '$' || key == '@'
|
|
|| key == '!' || key == '&' || key == '(' || key == ')' || key == ';'
|
|
|| key == ',' || key == '~'
|
|
)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
private void ProcessSMCommand(string command)
|
|
{
|
|
if (string.IsNullOrEmpty(command))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((command.ToLower() == "exit" || command.ToLower() == "quit" || command.ToLower() == "q") && IsConsoleModle)
|
|
{
|
|
SMConsoleUtils.GetApp().StopServer();
|
|
SMConsoleUtils.GetApp().SetStopSuccess();
|
|
|
|
exited = true;
|
|
|
|
Thread.Sleep(10);
|
|
Console.WriteLine();
|
|
return;
|
|
}
|
|
|
|
if(command.ToLower() == "history")
|
|
{
|
|
for (int i = 0; i < m_ModleInfo.m_history.Count; i ++)
|
|
{
|
|
string w = string.Format("{0,-50}", m_ModleInfo.m_history[i]);
|
|
if(i % 3 == 0)
|
|
{
|
|
Console.WriteLine();
|
|
}
|
|
Console.Write(w);
|
|
}
|
|
//ProcessSMShellCommand(command.ToLower());
|
|
return;
|
|
}
|
|
|
|
if(command.ToLower() == "clear")
|
|
{
|
|
Console.Clear(); //清屏专用
|
|
return;
|
|
}
|
|
|
|
SMConsoleCommandReq req = new SMConsoleCommandReq();
|
|
req.Command = command;
|
|
SMConsoleNet.Instance.SendMsgToCenter(req, SMMsgID.ConsoleCommandReq);
|
|
}
|
|
|
|
private void ProcessSMShellCommand(string cmd)
|
|
{
|
|
Process process;
|
|
if (OSUtils.IsWindows())
|
|
{
|
|
process = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardInput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
FileName = "cmd.exe",
|
|
Arguments = $"/C \"{cmd}\""
|
|
}
|
|
};
|
|
}
|
|
else
|
|
{
|
|
process = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardInput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
FileName = "/bin/bash",
|
|
Arguments = $"-c \"{cmd}\""
|
|
}
|
|
};
|
|
}
|
|
process.EnableRaisingEvents = true;
|
|
process.Start();
|
|
|
|
//process.StandardInput.WriteLine("exit");
|
|
string errorStr = process.StandardError.ReadToEnd();
|
|
if (string.IsNullOrEmpty(errorStr) == false)
|
|
{
|
|
Console.Write("Run Commond:{" + process.StartInfo.Arguments + "} return error =>");
|
|
Console.Write(errorStr);
|
|
}
|
|
string contentStr = process.StandardOutput.ReadToEnd();
|
|
if (string.IsNullOrEmpty(contentStr) == false)
|
|
{
|
|
Console.Write(contentStr);
|
|
}
|
|
Console.WriteLine();
|
|
|
|
process.WaitForExit();
|
|
process.Close();
|
|
}
|
|
|
|
private void AckExTabCommand(SMConsoleCommandRes res)
|
|
{
|
|
if (string.IsNullOrEmpty(res.Message) == false)
|
|
{
|
|
string[] messageSplit = res.Message.Split(' ');
|
|
if (messageSplit.Length > 2)
|
|
{
|
|
m_ModleInfo.m_input = m_ModleInfo.m_input.Split(" #")[0];
|
|
|
|
Console.WriteLine();
|
|
Console.WriteLine("{0}", res.Message);
|
|
WriteInputHeadInfo();
|
|
if (string.IsNullOrEmpty(m_ModleInfo.m_input) == false)
|
|
{
|
|
Console.Write(m_ModleInfo.m_input);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.SetCursorPosition(0, Console.CursorTop);
|
|
WriteInputHeadInfo();
|
|
m_ModleInfo.m_input = messageSplit[0];
|
|
Console.Write(m_ModleInfo.m_input);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ModleInfo.m_input = m_ModleInfo.m_input.Split(" #")[0];
|
|
Console.SetCursorPosition(0, Console.CursorTop);
|
|
WriteInputHeadInfo();
|
|
Console.Write(m_ModleInfo.m_input);
|
|
}
|
|
}
|
|
|
|
public void AckCommand(SMConsoleCommandRes res)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
if (m_ModleInfo.m_input.Contains(" #tab"))
|
|
{
|
|
AckExTabCommand(res);
|
|
return;
|
|
}
|
|
|
|
if(res.Command.Contains("enter_agent_shell"))
|
|
{
|
|
string[] message = res.Message.Split("#");
|
|
if (message.Length == 2)
|
|
{
|
|
if(message[1] == "success")
|
|
{
|
|
Console.SetCursorPosition(0, Console.CursorTop);
|
|
IsConsoleModle = false;
|
|
Console.WriteLine("{0} Success! ", res.Command);
|
|
WriteInputHeadInfo();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(res.Message == "#exit")
|
|
{
|
|
Console.SetCursorPosition(0, Console.CursorTop);
|
|
IsConsoleModle = true;
|
|
Console.WriteLine("exit agent shell Success! ");
|
|
WriteInputHeadInfo();
|
|
return;
|
|
}
|
|
|
|
//接收消息显示
|
|
int length = Console.CursorLeft + 1;
|
|
Console.SetCursorPosition(0, Console.CursorTop);
|
|
Console.Write(new char[length]);
|
|
Console.SetCursorPosition(0, Console.CursorTop);
|
|
if (res.Nonewline == 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.WriteLine(" ACK:{0}",res.Command);
|
|
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
Console.WriteLine("{0}", res.Message);
|
|
}
|
|
else if(res.Nonewline == 1)
|
|
{
|
|
Console.WriteLine("{0}", res.Message);
|
|
}
|
|
|
|
WriteInputHeadInfo();
|
|
//之前输入一半的补回去
|
|
if (m_ModleInfo.m_input.Length > 0)
|
|
{
|
|
Console.Write(m_ModleInfo.m_input);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|