Advertisement
serhiy1994

CefSharp multiinstance launching

Nov 2nd, 2021
589
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.76 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5.  
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Threading;
  9. using System.Runtime.CompilerServices;
  10. using IPC;
  11. using EngineBrowser.IPC.Protocol;
  12. using Newtonsoft.Json;
  13. using ExSearch.EngineCefSharp.Service.Abstract.Managers;
  14. using ExSearch.Engine.Core.Abstract.General;
  15. using ExSearch.EngineCefSharp.Service.Utils;
  16. using ExSearch.Engine.Core.Abstract.Log;
  17. using ExSearch.Engine.Core.Utils;
  18. using ExSearch.EngineCefSharp.Service.Entities.Managers;
  19.  
  20. namespace ExSearch.EngineCefSharp.Service.Concrete.Managers
  21. {
  22.     /// <summary>
  23.     /// Realization IBrowserManager, IBrowser.
  24.     ///Allows to manage ExSearch.Engine.BrowserCefSharp.exe processes - run, stop.
  25.     /// </summary>
  26.     internal sealed class BrowserManager : IDisposable, IBrowserManager, IBrowser
  27.     {
  28.         #region FIELDS
  29.         private readonly ILog log;
  30.         private readonly string browserPath;
  31.         private readonly int browserInstancesCount;
  32.         private readonly ThreadSafeList<BrowserLogic> browsers;
  33.         private SemaphoreSlim browserThreadsLimit;
  34.         private ManualResetEventSlim allBrowsersLaunched;
  35.         #endregion
  36.  
  37.         #region CONSTRUCTORS
  38.         public BrowserManager(ILog log)
  39.         {
  40.             this.log = log;
  41.             this.browserPath = Configurator.BrowserPath;
  42.             this.browserInstancesCount = Configurator.BrowserInstancesCount;
  43.             this.browsers = new ThreadSafeList<BrowserLogic>(this.browserInstancesCount);
  44.             this.browserThreadsLimit = new SemaphoreSlim(this.browserInstancesCount, this.browserInstancesCount);
  45.             this.allBrowsersLaunched = new ManualResetEventSlim(false);
  46.             InitBrowsers();
  47.         }
  48.         #endregion
  49.  
  50.         #region PROPERTIES
  51.         #endregion
  52.  
  53.         #region METHODS
  54.         #region IBrowserManager
  55.         /// <summary>
  56.         /// Run all browsers.
  57.         /// </summary>
  58.         public void RunBrowsers()
  59.         {
  60.             // kill old/mistaking browsers
  61.             KillBrowsers();
  62.  
  63.             BrowserLogic[] browserLogicArray = this.browsers.ToArray();
  64.             foreach (BrowserLogic browserLogic in browserLogicArray)
  65.                 browserLogic.Run();
  66.             // checking async all browsers
  67.             Task.Factory.StartNew(() =>
  68.             {
  69.                 while (true)
  70.                 {
  71.                     Thread.Sleep(100);
  72.                     if (browserInstancesCount.Equals(browserLogicArray.Count(browserLogicElem => browserLogicElem.State != BrowserState.Unavailable)))
  73.                     {
  74.                         try
  75.                         {
  76.                             if (this.allBrowsersLaunched != null)
  77.                                 this.allBrowsersLaunched.Set();
  78.                         }
  79.                         catch { }
  80.                         break;
  81.                     }
  82.                 }
  83.             });
  84.         }
  85.  
  86.         /// <summary>
  87.         /// Stop all browsers.
  88.         /// </summary>
  89.         public void ExitBrowsers()
  90.         {
  91.             if (this.allBrowsersLaunched != null)
  92.                 this.allBrowsersLaunched.Reset();
  93.             BrowserLogic[] browserLogicArray = this.browsers.ToArray();
  94.             foreach (BrowserLogic browserLogic in browserLogicArray)
  95.                 browserLogic.Exit();
  96.             // delete old/mistaking browsers
  97.             KillBrowsers();
  98.         }
  99.         #endregion
  100.  
  101.         #region IBrowser
  102.         /// <summary>
  103.         /// Load content (html page only).
  104.         /// </summary>
  105.         public Content Download(string url, bool fullContent)
  106.         {
  107.             if (string.IsNullOrWhiteSpace(url))
  108.                 throw new ArgumentException("URL not specified or empty");
  109.             allBrowsersLaunched.Wait(); // for initialize all browsers
  110.             browserThreadsLimit.Wait();
  111.             try
  112.             {
  113.                 BrowserLogic browserLogic = AcquireBrowser();
  114.                 try
  115.                 {
  116.                     return browserLogic.Download(url, fullContent);
  117.                 }
  118.                 finally
  119.                 {
  120.                     ReleaseBrowser(browserLogic);
  121.                 }
  122.             }
  123.             finally
  124.             {
  125.                 browserThreadsLimit.Release();
  126.             }
  127.         }
  128.         #endregion
  129.  
  130.         #region IDisposable
  131.         public void Dispose()
  132.         {
  133.             DeinitBrowsers();
  134.             if (browserThreadsLimit != null)
  135.             {
  136.                 browserThreadsLimit.Dispose();
  137.                 browserThreadsLimit = null;
  138.             }
  139.             if (allBrowsersLaunched != null)
  140.             {
  141.                 allBrowsersLaunched.Dispose();
  142.                 allBrowsersLaunched = null;
  143.             }
  144.         }
  145.         #endregion
  146.  
  147.         #region Private
  148.         /// <summary>
  149.         /// Request a free browser and make it used.
  150.         /// </summary>
  151.         [MethodImpl(MethodImplOptions.Synchronized)]
  152.         private BrowserLogic AcquireBrowser()
  153.         {
  154.             BrowserLogic browserLogic;
  155.             while (true)
  156.             {
  157.                 browserLogic = browsers.ToArray().FirstOrDefault(browserLogicElem =>
  158.                 {
  159.                     if (browserLogicElem.State == BrowserState.Launched)
  160.                     {
  161.                         browserLogicElem.State = BrowserState.InProcess;
  162.                         return true;
  163.                     }
  164.                     return false;
  165.                 });
  166.                 if (browserLogic != null)
  167.                     break;
  168.                 else
  169.                     Thread.Sleep(100);
  170.             }
  171.             return browserLogic;
  172.         }
  173.  
  174.         /// <summary>
  175.         /// Free a browser being in use.
  176.         /// </summary>
  177.         private void ReleaseBrowser(BrowserLogic browserLogic)
  178.         {
  179.             if (browserLogic.State == BrowserState.InProcess)
  180.                 browserLogic.State = BrowserState.Launched;
  181.         }
  182.  
  183.         private void InitBrowsers()
  184.         {
  185.             for (int i = 0; i < browserInstancesCount; i++)
  186.                 browsers.Add(new BrowserLogic(this.browserPath, i + 1, Guid.NewGuid()));
  187.         }
  188.  
  189.         private void DeinitBrowsers()
  190.         {
  191.             for (int i = 0; i < browserInstancesCount; i++)
  192.                 if (browsers[i] != null)
  193.                 {
  194.                     browsers[i].Dispose();
  195.                     browsers[i] = null;
  196.                 }
  197.             browsers.Clear();
  198.         }
  199.  
  200.         /// <summary>
  201.         /// Delete all browsers.
  202.         /// </summary>
  203.         private void KillBrowsers()
  204.         {
  205.             Process[] browsers = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(this.browserPath));
  206.             foreach (Process browser in browsers)
  207.                 try
  208.                 {
  209.                     browser.Kill();
  210.                 }
  211.                 catch { }
  212.         }
  213.         #endregion
  214.         #endregion
  215.  
  216.         #region NESTED TYPES (ENUMS, STRUCTURES, CLASSES)
  217.         /// <summary>
  218.         /// Class describing one browser instance functionality.
  219.         /// </summary>
  220.         private sealed class BrowserLogic : IDisposable
  221.         {
  222.             #region FIELDS
  223.             private readonly string browserPath;
  224.             private Process process;
  225.             private IPCSender<string, string> ipcSender;
  226.             private readonly Synchronized<BrowserState> state;
  227.             private readonly int number;
  228.             private readonly Guid guid;
  229.             private ManualResetEventSlim whileInProcessState;
  230.             #endregion
  231.  
  232.             #region CONSTRUCTORS
  233.             public BrowserLogic(string browserPath, int number, Guid guid)
  234.             {
  235.                 this.browserPath = browserPath;
  236.                 this.state = new Synchronized<BrowserState>(BrowserState.Unavailable);
  237.                 this.number = number;
  238.                 this.guid = guid;
  239.                 this.whileInProcessState = new ManualResetEventSlim(true);
  240.             }
  241.             #endregion
  242.  
  243.             #region PROPERTIES
  244.             /// <summary>
  245.             /// A browser state.
  246.             /// </summary>
  247.             public BrowserState State
  248.             {
  249.                 get
  250.                 {
  251.                     return this.state.Value;
  252.                 }
  253.                 set
  254.                 {
  255.                     if (whileInProcessState != null && value == BrowserState.InProcess)
  256.                         whileInProcessState.Reset();
  257.                     this.state.Value = value;
  258.                     if (whileInProcessState != null && value == BrowserState.Launched)
  259.                         whileInProcessState.Set();
  260.                 }
  261.             }
  262.             #endregion
  263.  
  264.             #region METHODS
  265.             #region IDisposable
  266.             public void Dispose()
  267.             {
  268.                 if (this.process != null)
  269.                 {
  270.                     this.process.Dispose();
  271.                     this.process = null;
  272.                 }
  273.                 if (this.whileInProcessState != null)
  274.                 {
  275.                     this.whileInProcessState.Dispose();
  276.                     this.whileInProcessState = null;
  277.                 }
  278.             }
  279.             #endregion
  280.  
  281.             public void Run()
  282.             {
  283.                 RunProcess();
  284.                 StartIPCSender();
  285.  
  286.                 Task.Factory.StartNew(() =>
  287.                 {
  288.                     bool availabilityProcess = false;
  289.                     do
  290.                     {
  291.                         Thread.Sleep(100);
  292.                         string returnString = ipcSender.Send(JsonConvert.SerializeObject(new Message { Command = Command.Ping }));
  293.                         if (returnString != null)
  294.                         {
  295.                             Return returnObj = JsonConvert.DeserializeObject<Return>(returnString);
  296.                             if (returnObj.Command == Command.Ping)
  297.                                 availabilityProcess = true;
  298.                         }
  299.                     }
  300.                     while (!availabilityProcess);
  301.                     this.State = BrowserState.Launched;
  302.                 });
  303.             }
  304.  
  305.             public void Exit()
  306.             {
  307.                 bool canExit = false;
  308.                 if (this.State == BrowserState.Launched)
  309.                 {
  310.                     this.State = BrowserState.Unavailable;
  311.                     canExit = true;
  312.                 }
  313.                 else if (this.State == BrowserState.InProcess)
  314.                 {
  315.                     if (whileInProcessState != null)
  316.                         whileInProcessState.Wait();
  317.                     this.State = BrowserState.Unavailable;
  318.                     canExit = true;
  319.                 }
  320.                 if (canExit)
  321.                 {
  322.                     string returnString = ipcSender.Send(JsonConvert.SerializeObject(new Message { Command = Command.Exit }));
  323.                     if (returnString != null)
  324.                     {
  325.                         Return returnObj = JsonConvert.DeserializeObject<Return>(returnString);
  326.                         if (returnObj.Command == Command.Exit)
  327.                         {
  328.                             StopIPCSender();
  329.                             ExitProcess();
  330.                         }
  331.                     }
  332.                 }
  333.             }
  334.  
  335.             public Content Download(string url, bool fullContent)
  336.             {
  337.                 string returnString = ipcSender.Send(JsonConvert.SerializeObject(new Message { Command = fullContent ? Command.DownloadFull : Command.Download, ContentType = ContentType.Data, Content = JsonConvert.SerializeObject(fullContent ? (object)(new DownloadFullMessageContent { Url = url }) : (object)(new DownloadMessageContent { Url = url })) }));
  338.                 if (returnString == null) // connection error
  339.                     throw new Exception("Can't retrieve content. Connection error");
  340.                 Return returnObj = JsonConvert.DeserializeObject<Return>(returnString);
  341.                 if (returnObj.ContentType == ContentType.Data)
  342.                 {
  343.                     switch (returnObj.Command)
  344.                     {
  345.                         case Command.DownloadFull:
  346.                             DownloadFullReturnContent downloadFullReturnContent = JsonConvert.DeserializeObject<DownloadFullReturnContent>(returnObj.Content);
  347.                             return null; // TODO!!!
  348.                         case Command.Download:
  349.                             DownloadReturnContent downloadReturnContent = JsonConvert.DeserializeObject<DownloadReturnContent>(returnObj.Content);
  350.                             return new Content { IsArchive = false, ContentUrl = url, FileName = downloadReturnContent.FileName, ContentType = downloadReturnContent.MimeType, ContentData = downloadReturnContent.Data };
  351.                         default:
  352.                             throw new Exception(string.Format("Can't retrieve content. Protocol (Command.{0}) error.", Enum.GetName(returnObj.Command.GetType(), returnObj.Command)));
  353.                     }
  354.                 }
  355.                 else
  356.                     throw new Exception(string.Format("Can't retrieve content. {0}", returnObj.ContentType == ContentType.Error ? returnObj.Content : "Protocol error (ContentType.Empty)."));
  357.             }
  358.  
  359.             private void RunProcess()
  360.             {
  361.                 ProcessStartInfo processStartInfo = new ProcessStartInfo();
  362.                 processStartInfo.FileName = this.browserPath;
  363.                 processStartInfo.Arguments = string.Format(" /number {0} /guid {1}", this.number, this.guid.ToString("N"));
  364.                 processStartInfo.LoadUserProfile = true;
  365.                 processStartInfo.UseShellExecute = false;
  366.                 processStartInfo.WorkingDirectory = Path.GetDirectoryName(processStartInfo.FileName);
  367.                 this.process = Process.Start(processStartInfo);
  368.             }
  369.  
  370.             private void ExitProcess()
  371.             {
  372.                 if (this.process != null)
  373.                 {
  374.                     this.process.WaitForExit();
  375.                     this.process.Dispose();
  376.                     this.process = null;
  377.                 }
  378.             }
  379.  
  380.             private void StartIPCSender()
  381.             {
  382.                 StopIPCSender();
  383.                 this.ipcSender = new IPCSender<string, string>();
  384.                 this.ipcSender.Open(new Channel(guid.ToString("N")));
  385.             }
  386.  
  387.             private void StopIPCSender()
  388.             {
  389.                 if (ipcSender != null)
  390.                     ipcSender = null;
  391.             }
  392.             #endregion
  393.  
  394.             #region NESTED TYPES (ENUMS, STRUCTURES, CLASSES)
  395.             #endregion
  396.         }
  397.         #endregion
  398.     }
  399. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement