Ejemplo n.º 1
0
        //執行指令
        static public void Execute(string cmd, string arg)
        {
            //如果是空白指令就直接無視掉就行
            if (cmd.Trim() == "")
            {
                return;
            }

            //Internal commands
            switch (cmd)
            {
            // DEBUG() 開關除錯模式
            case "DEBUG":
                Debugging = !Debugging;
                MESSAGE(Localization.GetMessage("DEBUG", "Entered debug mode. AZUSA will display all errors and listen to all commands."));
                Variables.Write("$SYS_DEBUG", Debugging.ToString());
                break;

            // BROADCAST({expr}) 向所有引擎廣播消息
            case "BROADCAST":
                ProcessManager.Broadcast(arg);
                break;

            // EXIT() 退出程序
            case "EXIT":
                //創建一個負責退出的線程
                new Thread(new ThreadStart(EXIT)).Start();
                break;

            // RESTART() 重啟程序
            case "RESTART":
                //創建一個負責重啟的線程
                new Thread(new ThreadStart(RESTART)).Start();
                break;

            // WAIT({int}) 暫停線程
            case "WAIT":
                System.Threading.Thread.Sleep(Convert.ToInt32(arg));
                break;

            // ACTVIEW() 打開活動檢視器
            case "ACTVIEW":
                itmActivity_Click(null, EventArgs.Empty);
                break;

            // PRCMON() 打開進程檢視器
            case "PRCMON":
                itmMonitor_Click(null, EventArgs.Empty);
                break;

            // EXEC(filepath,IsApp) 創建進程
            case "EXEC":
                string patharg = arg.Replace("{AZUSA}", Environment.CurrentDirectory);

                // Get the second arg (true/false) indicating whether process should be executed through AZUSA
                bool thruAZUSA = true;
                if (patharg.Contains(','))
                {
                    Boolean.TryParse(patharg.Split(',').Last(), out thruAZUSA);
                }

                patharg = patharg.Trim();
                string path = patharg;
                string Arg  = "";
                if (patharg.Contains('$'))
                {
                    path = patharg.Split('$')[0];
                    Arg  = patharg.Replace(path + "$", "");
                }
                if (path.EndsWith(".exe") && thruAZUSA)
                {
                    ProcessManager.AddProcess(Path.GetFileNameWithoutExtension(path), path, Arg);
                }
                else
                {
                    try
                    {
                        System.Diagnostics.Process target = new System.Diagnostics.Process();
                        target.StartInfo.FileName         = path;
                        target.StartInfo.Arguments        = arg;
                        target.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(path);
                        target.Start();
                    }
                    catch
                    {
                        Internals.ERROR(Localization.GetMessage("ENGSTARTFAIL", "Unable to run {arg}. Please make sure it is in the correct folder.", path));
                    }
                }

                break;

            // KILL(prcName) 終止進程
            case "KILL":
                ProcessManager.Kill(arg);
                break;

            // SCRIPT({SID(.part)},arg1=val1,arg2=val2,...) 執行腳本檔
            case "SCRIPT":
                //創建執行物件
                MUTAN.IRunnable obj;

                //解析參數
                string[] parsed = Utils.SplitWithProtection(arg).ToArray();

                //分割參數, 以便取得部分名, 例如 TEST.part1
                string[] scr = parsed[0].Split('.');

                List <string> var = new List <string>();
                List <string> val = new List <string>();

                //處理傳入值
                for (int i = 1; i < parsed.Count(); i++)
                {
                    var.Add(Utils.LSplit(parsed[i], "="));
                    val.Add(Utils.RSplit(parsed[i], "="));
                }

                //用來暫存腳本內容的陣列
                string[] program;

                //首先嘗試讀入腳本內容
                var scriptpath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\Scripts\" + scr[0];
                if (File.Exists(scriptpath + ".mut"))
                {
                    program = File.ReadAllLines(scriptpath + ".mut");
                }
                else if (File.Exists(scriptpath + ".msf"))
                {
                    program = File.ReadAllLines(scriptpath + ".msf");
                }
                else
                {
                    Internals.ERROR(Localization.GetMessage("SCRMISSING", "Unable to find the script named {arg}. Please make sure it is in the correct folder.", scr[0]));
                    return;
                }


                //如果有分塊的話, 就先進行提取
                if (scr.Length > 1)
                {
                    for (int i = 1; i < scr.Length; i++)
                    {
                        program = MUTAN.GetPart(program, scr[i]);
                    }
                }

                //取代傳入值
                for (int ln = 0; ln < program.Count(); ln++)
                {
                    for (int i = 0; i < var.Count(); i++)
                    {
                        program[ln] = program[ln].Replace("{" + var[i] + "}", val[i]);
                    }
                }


                //然後進行解析
                MUTAN.Parser.TryParse(program, out obj);

                //清理暫存
                program = null;

                //解析結果不為空的話就執行
                //否則就報錯
                if (obj != null)
                {
                    MUTAN.ReturnCode tmp = obj.Run();

                    if (tmp.Command != "END")
                    {
                        Execute(tmp.Command, tmp.Argument);
                    }


                    //扔掉物件
                    obj = null;
                }
                else
                {
                    ERROR(Localization.GetMessage("SCRERROR", "An error occured while running script named {arg}. Please make sure there is no syntax error.", scr[0]));
                }
                break;

            //等待回應
            case "WAITFORRESP":
                //把 $WAITFORRESP 設成 TRUE
                Variables.Write("$WAITFORRESP", "TRUE");
                ////通知引擎 (主要是針對 AI) 現在正等待回應
                ProcessManager.Broadcast("EVENT(WaitingForResp)");

                respCache = arg;
                break;

            // MAKERESP(resp) 作出反應
            case "MAKERESP":
                //把 $WAITFORRESP 設成 FALSE
                Variables.Write("$WAITFORRESP", "FALSE");
                Variables.Write("$RESP", arg);

                if (respCache == "")
                {
                    break;
                }

                ////通知引擎已作出反應
                //ProcessManager.Broadcast("RESPONDED");

                //解析暫存
                MUTAN.Parser.TryParse(respCache.Split('\n'), out obj);

                //清空暫存
                respCache = "";

                //解析結果不為空的話就執行
                //否則就報錯
                if (obj != null)
                {
                    MUTAN.ReturnCode tmp = obj.Run();

                    if (tmp.Command != "END")
                    {
                        Execute(tmp.Command, tmp.Argument);
                    }

                    //扔掉物件
                    obj = null;
                }
                else
                {
                    ERROR(Localization.GetMessage("SCRERROR", "An error occured while running a response script. Please make sure there is no syntax error. [MUTAN, " + respCache + "]"));
                }
                break;

            // ERR({expr}) 發送錯誤信息
            case "ERR":
                //ERR 是屬於表現層的系統指令, 容許被接管
                bool routed = false;

                List <IOPortedPrc> ListCopy = new List <IOPortedPrc>(ProcessManager.GetCurrentProcesses());

                //檢查每一個現在運行中的進程
                foreach (IOPortedPrc prc in ListCopy)
                {
                    try
                    {
                        //如果進程有接管這個指令, 就把指令內容傳過去
                        if (prc.RIDs.ContainsKey(cmd))
                        {
                            //設 routed 為 true
                            routed = true;

                            //根據 RIDs 的值,決定只傳參數還是指令跟參數整個傳過去
                            //RIDs 的值如果是 true 的話就表示只傳參數
                            if (prc.RIDs[cmd])
                            {
                                prc.WriteLine(arg);
                            }
                            else
                            {
                                prc.WriteLine(cmd + "(" + arg + ")");
                            }
                        }
                    }
                    catch { }
                }

                //扔掉 ListCopy
                ListCopy = null;

                //否則就由圖標發出提示
                if (!routed)
                {
                    ERROR(arg);
                }
                break;

            // MSG({expr}) 發送信息
            case "MSG":
                //MSG 是屬於表現層的系統指令, 容許被接管
                routed = false;

                ListCopy = new List <IOPortedPrc>(ProcessManager.GetCurrentProcesses());

                //檢查每一個現在運行中的進程
                foreach (IOPortedPrc prc in ListCopy)
                {
                    try
                    {
                        //如果進程有接管這個指令, 就把指令內容傳過去
                        if (prc.RIDs.ContainsKey(cmd))
                        {
                            //設 routed 為 true
                            routed = true;

                            //根據 RIDs 的值,決定只傳參數還是指令跟參數整個傳過去
                            //RIDs 的值如果是 true 的話就表示只傳參數
                            if (prc.RIDs[cmd])
                            {
                                prc.WriteLine(arg);
                            }
                            else
                            {
                                prc.WriteLine(cmd + "(" + arg + ")");
                            }
                        }
                    }
                    catch { }
                }

                //扔掉 ListCopy
                ListCopy = null;

                //否則就由圖標發出提示
                if (!routed)
                {
                    MESSAGE(arg);
                }
                break;

            // MENU(name, script) 添加右鍵選單項目
            case "MENU":
                parsed = arg.Split(',');
                Internals.ADDMENUITEM(parsed[0].Trim(), arg.Replace(parsed[0] + ",", "").Trim());
                break;

            default:
                //如果不是系統指令, 先檢查是否有引擎登記接管了這個指令
                // routed 記錄指令是否已被接管
                routed = false;

                ListCopy = new List <IOPortedPrc>(ProcessManager.GetCurrentProcesses());

                //檢查每一個現在運行中的進程
                foreach (IOPortedPrc prc in ListCopy)
                {
                    try
                    {
                        //如果進程有接管這個指令, 就把指令內容傳過去
                        if (prc.RIDs.ContainsKey(cmd))
                        {
                            //設 routed 為 true
                            routed = true;

                            //根據 RIDs 的值,決定只傳參數還是指令跟參數整個傳過去
                            //RIDs 的值如果是 true 的話就表示只傳參數
                            if (prc.RIDs[cmd])
                            {
                                prc.WriteLine(arg);
                            }
                            else
                            {
                                prc.WriteLine(cmd + "(" + arg + ")");
                            }
                        }
                    }
                    catch { }
                }

                //扔掉 ListCopy
                ListCopy = null;

                //所有進程都檢查完畢
                //如果 routed 為 true, 那麼已經有進程接管了, AZUSA 就可以不用繼續執行
                //No need to continue executing the command because it has been routed already
                if (!routed)
                {
                    //否則的話就當成函式呼叫, 如果有註明副檔名的就根據副檔名執行
                    if (cmd.Contains('.'))
                    {
                        switch (cmd.Split('.')[1])
                        {
                        case "bat":
                            ProcessManager.AddProcess(cmd, "cmd.exe", "/C \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + "\" " + arg);
                            return;

                        case "cmd":
                            ProcessManager.AddProcess(cmd, "cmd.exe", "/C \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + "\" " + arg);
                            return;

                        case "vbs":
                            ProcessManager.AddProcess(cmd, "cscript.exe", " \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + "\" " + arg);
                            return;
                        }
                    }

                    //如果沒副檔名就先找 exe
                    if (!ProcessManager.AddProcess(cmd, Environment.CurrentDirectory + @"\Routines\" + cmd + ".exe", arg))
                    {
                        //再找 bat (利用 bat 可以呼叫基本上任何直譯器調用任何腳本語言了)
                        if (File.Exists(Environment.CurrentDirectory + @"\Routines\" + cmd + ".bat"))
                        {
                            ActivityLog.Add("Calling \"" + "cmd.exe " + "/C \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + ".bat\" " + arg + "\"");
                            ProcessManager.AddProcess(cmd, "cmd.exe", "/C \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + ".bat\" " + arg);
                        }
                        //再找 cmd
                        else if (File.Exists(Environment.CurrentDirectory + @"\Routines\" + cmd + ".cmd"))
                        {
                            ActivityLog.Add("Calling \"" + "cmd.exe " + "/C \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + ".cmd\" " + arg + "\"");
                            ProcessManager.AddProcess(cmd, "cmd.exe", "/C \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + ".cmd\" " + arg);
                            //再找 vbs
                        }
                        else if (File.Exists(Environment.CurrentDirectory + @"\Routines\" + cmd + ".vbs"))
                        {
                            ProcessManager.AddProcess(cmd, "cscript.exe", " \"" + Environment.CurrentDirectory + @"\Routines\" + cmd + ".vbs\" " + arg);
                            //都找不到就報錯
                        }
                        else
                        {
                            ERROR(Localization.GetMessage("ENGSTARTFAIL", "Unable to run {arg}. Please make sure it is in the correct folder.", cmd));
                        }
                    }
                }
                break;
            }
        }
Ejemplo n.º 2
0
        //處理引擎的輸出
        void Engine_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            string Data = Utils.UriDecode(e.Data);

            //如果是空白輸出, 不要理會
            //Ignore NULL and empty inputs that will crash the program
            if (Data == null || Data.Trim() == "")
            {
                return;
            }

            //activity log
            ActivityLog.Add("From " + Name + ": " + Data);

            //如果是詢問, 則調用 MUTAN 表達式解析器, 並返回結東
            //詢問的語法是 "(表達式)?"
            //First check if the engine is asking a question about value of an expression
            if (Data.EndsWith("?"))
            {
                //首先保護進程以免受到 BROADCAST 干擾
                NoBroadcast = true;

                string result;

                //去掉最後的問號, 就是表達式了
                //如果格式有誤的話, 會返回 INVALIDEXPR (無效的表達式) 或 IMBALBRACKET (括號不平衡)
                MUTAN.ExprParser.TryParse(Data.TrimEnd('?'), out result);
                Engine.StandardInput.WriteLine(result);

                //解除 BROADCAST 干擾保護
                NoBroadcast = false;

                //activity log
                ActivityLog.Add("To " + Name + ": " + result);

                return;
            }

            string RID = "";
            string arg = "";

            //首先假設是溝通用的指令, 主要是用來讓進程宣佈自己的角色和功能, 並取得可用接口等等的溝通協調用的指令
            //對字串分割並去掉多餘空白
            if (MUTAN.IsExec(Data))
            {
                RID = Data.Split('(')[0];
                arg = Data.Substring(RID.Length + 1, Data.Length - RID.Length - 2);
                RID = RID.Trim();
            }


            switch (RID)
            {
            //這是用來進入除錯模式的, 除錯模式下不會要求完備性
            case "DEBUG":
                Internals.Debugging = true;
                Variables.Write("$SYS_DEBUG", "TRUE");
                Internals.MESSAGE(Localization.GetMessage("DEBUG", "Entered debug mode. AZUSA will display all errors and listen to all commands."));
                return;

            //進行回傳
            case "Return":
                output    = arg;
                RESPONDED = true;
                return;

            //這是用來讓進程取得 AZUSA 的 pid, 進程可以利用 pid 檢查 AZUSA 是否存活, 當 AZUSA 意外退出時, 進程可以檢查到並一併退出
            case "GetAzusaPid":

                //首先保護進程以免受到 BROADCAST 干擾
                NoBroadcast = true;

                Engine.StandardInput.WriteLine(Process.GetCurrentProcess().Id);
                //activity log
                ActivityLog.Add("To " + Name + ": " + Process.GetCurrentProcess().Id);

                //解除 BROADCAST 干擾保護
                NoBroadcast = false;

                return;

            //這是讓進程宣佈自己的身份的, 這指令應該是進程完成各種初始化之後才用的
            case "RegisterAs":
                //先記錄現在是否完備
                bool tmp = ProcessManager.CheckCompleteness();

                //然後進行相應的登錄
                switch (arg)
                {
                case "AI":
                    currentType = PortType.AI;
                    ProcessManager.AIPid.Add(pid);
                    break;

                case "Input":
                    currentType = PortType.Input;
                    ProcessManager.InputPid.Add(pid);
                    break;

                case "Output":
                    currentType = PortType.Output;
                    ProcessManager.OutputPid.Add(pid);
                    break;

                case "Application":
                    currentType = PortType.Application;
                    break;

                default:
                    break;
                }

                //再次檢查完備性, 如果之前不完備, 現在完備了就進行提示
                if (!tmp && ProcessManager.CheckCompleteness())
                {
                    Internals.READY();
                }

                return;

            //這是讓進程宣佈自己的可連接的接口, AZUSA 記錄後可以轉告其他進程, 進程之間可以直接對接而不必經 AZUSA
            case "RegisterPort":
                ProcessManager.Ports.Add(arg.Trim('"'), currentType);
                this.Ports.Add(arg.Trim('"'));
                ProcessManager.Broadcast("PortHasChanged");
                return;

            //這是讓進程取得當前可用所有端口
            case "GetAllPorts":

                //首先保護進程以免受到 BROADCAST 干擾
                NoBroadcast = true;

                string result = "";
                foreach (KeyValuePair <string, PortType> port in ProcessManager.Ports)
                {
                    result += port.Key + ",";
                }

                Engine.StandardInput.WriteLine(result.Trim(','));

                //解除 BROADCAST 干擾保護
                NoBroadcast = false;

                //activity log
                ActivityLog.Add("To " + Name + ": " + result.Trim(','));

                return;

            //這是讓進程取得當前可用的AI 端口(AI引擎的接口)
            case "GetAIPorts":

                //首先保護進程以免受到 BROADCAST 干擾
                NoBroadcast = true;

                result = "";
                foreach (KeyValuePair <string, PortType> port in ProcessManager.Ports)
                {
                    if (port.Value == PortType.AI)
                    {
                        result += port.Key + ",";
                    }
                }

                Engine.StandardInput.WriteLine(result.Trim(','));

                //解除 BROADCAST 干擾保護
                NoBroadcast = false;

                //activity log
                ActivityLog.Add("To " + Name + ": " + result.Trim(','));

                return;

            //這是讓進程取得當前可用的輸入端口(輸入引擎的接口)
            case "GetInputPorts":

                //首先保護進程以免受到 BROADCAST 干擾
                NoBroadcast = true;

                result = "";
                foreach (KeyValuePair <string, PortType> port in ProcessManager.Ports)
                {
                    if (port.Value == PortType.Input)
                    {
                        result += port.Key + ",";
                    }
                }

                Engine.StandardInput.WriteLine(result.Trim(','));

                //解除 BROADCAST 干擾保護
                NoBroadcast = false;

                //activity log
                ActivityLog.Add("To " + Name + ": " + result.Trim(','));

                return;

            //這是讓進程取得當前可用的輸出端口(輸出引擎的接口)
            case "GetOutputPorts":

                //首先保護進程以免受到 BROADCAST 干擾
                NoBroadcast = true;

                result = "";
                foreach (KeyValuePair <string, PortType> port in ProcessManager.Ports)
                {
                    if (port.Value == PortType.Output)
                    {
                        result += port.Key + ",";
                    }
                }

                Engine.StandardInput.WriteLine(result.Trim(','));

                //解除 BROADCAST 干擾保護
                NoBroadcast = false;

                //activity log
                ActivityLog.Add("To " + Name + ": " + result.Trim(','));

                return;

            //這是讓進程可以宣佈自己責負甚麼函式, AZUSA 在接收到這種函件就會轉發給進程
            //函式接管不是唯一的, 可以同時有多個進程接管同一個函式, AZUSA 會每個宣告了接管的進程都轉發一遍
            case "LinkRID":
                string[] parsed = arg.Split(',');

                this.RIDs.Add(parsed[0], Convert.ToBoolean(parsed[1]));

                return;

            default:
                break;
            }

            //檢查整體架構是否完備, 完備或除錯模式下才執行指令
            if (Internals.SysReady || Internals.Debugging)
            {
                //否則假設是 MUTAN 指令,嘗試解析, 如果失敗的話, 就無視掉本次輸出

                //先創建一個可運行物件, 用來儲存解析結果
                MUTAN.IRunnable obj;


                //然後用單行解析器
                if (MUTAN.LineParser.TryParse(Data, out obj))
                {
                    //如果成功解析, 則運行物件, 獲取回傳碼
                    MUTAN.ReturnCode tmp = obj.Run();

                    //然後按回傳碼執行指令
                    if (tmp.Command != "")
                    {
                        Internals.Execute(tmp.Command, tmp.Argument);
                    }
                }
            }
            else
            {
                Internals.ERROR(Localization.GetMessage("ENGINEMISSING", "Some engines are missing. AZUSA will not execute any MUTAN commands unless AI and I/O are all registered."));
            }
        }