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

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);
}
}
}
}