private Func <Uri, CancellationToken, Task <WebSocket> > CreateClient(string login, string password) { var token = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{login}:{password}")); return(async(uri, t) => { var client = SystemClientWebSocket.CreateClientWebSocket(); switch (client) { case System.Net.WebSockets.Managed.ClientWebSocket managed: managed.Options.SetRequestHeader("Authorization", $"Basic {token}"); await managed.ConnectAsync(uri, t); break; case ClientWebSocket coreSocket: coreSocket.Options.SetRequestHeader("Authorization", $"Basic {token}"); await coreSocket.ConnectAsync(uri, t); break; } return client; }); }
public Task InitializeWebSocket() { // do not attempt to initialize if cancellation is requested if (Completion != null) { throw new OperationCanceledException(); } lock (_initializeLock) { // if an initialization task is already running, return that if (_initializeWebSocketTask != null && !_initializeWebSocketTask.IsFaulted && !_initializeWebSocketTask.IsCompleted) { return(_initializeWebSocketTask); } // if the websocket is open, return a completed task if (_clientWebSocket != null && _clientWebSocket.State == WebSocketState.Open) { return(Task.CompletedTask); } // else (re-)create websocket and connect _clientWebSocket?.Dispose(); #if NETFRAMEWORK // fix websocket not supported on win 7 using // https://github.com/PingmanTools/System.Net.WebSockets.Client.Managed _clientWebSocket = SystemClientWebSocket.CreateClientWebSocket(); switch (_clientWebSocket) { case ClientWebSocket nativeWebSocket: nativeWebSocket.Options.AddSubProtocol("graphql-ws"); nativeWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; nativeWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials; Options.ConfigureWebsocketOptions(nativeWebSocket.Options); break; case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket: managedWebSocket.Options.AddSubProtocol("graphql-ws"); managedWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; managedWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials; break; default: throw new NotSupportedException($"unknown websocket type {_clientWebSocket.GetType().Name}"); } #else _clientWebSocket = new ClientWebSocket(); _clientWebSocket.Options.AddSubProtocol("graphql-ws"); _clientWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; _clientWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials; Options.ConfigureWebsocketOptions(_clientWebSocket.Options); #endif return(_initializeWebSocketTask = ConnectAsync(_internalCancellationToken)); } }
internal WebSocketTransport Build(Action <IEnumerable <JObject> > eventPublisher) { return(new WebSocketTransport( WebSocketFactory ?? (() => SystemClientWebSocket.CreateClientWebSocket()), Uri ?? throw new Exception("Please set Uri."), ResponseTimeout ?? TimeSpan.FromSeconds(65), eventPublisher)); }
/// <summary> /// WebSocket factory to support Windows 7 and Windows Server 2008. /// https://github.com/hardkoded/puppeteer-sharp/issues/1368#issuecomment-580946444 /// The minimum Windows versions supporting the WebSocket library are Windows 8 and Windows Server 2012. /// <see href="https://github.com/hardkoded/puppeteer-sharp#prerequisites"/>. /// </summary> /// <param name="uri">The URI.</param> /// <param name="socketOptions">The socket options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The WebSocket factory.</returns> private static async Task <WebSocket> WebSocketFactory(Uri uri, IConnectionOptions socketOptions, CancellationToken cancellationToken) { var client = SystemClientWebSocket.CreateClientWebSocket(); if (client is System.Net.WebSockets.Managed.ClientWebSocket managed) { managed.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await managed.ConnectAsync(uri, cancellationToken); } else { var coreSocket = client as ClientWebSocket; coreSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await coreSocket.ConnectAsync(uri, cancellationToken); } return(client); }
public async Task Open_and_close_WebSocket() { using (var webSocket = SystemClientWebSocket.CreateClientWebSocket()) { Debug.WriteLine("Connecting"); await webSocket.ConnectAsync(new Uri("ws://localhost:5088/bayeux/"), CancellationToken.None); await Delay(10); //Debug.WriteLine("Sending"); //await webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes("hola")), WebSocketMessageType.Text, endOfMessage: true, cancellationToken: CancellationToken.None); //await Delay(10); Debug.WriteLine("Closing"); await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); await Delay(5); Debug.WriteLine("Connecting again"); await webSocket.ConnectAsync(new Uri("ws://localhost:5088/bayeux/"), CancellationToken.None); await Delay(5); Debug.WriteLine("End"); } }
/// <summary> /// Конвертирование на основе содержимого файла html /// </summary> /// <param name="htmlContent">содержимое файла html</param> /// <param name="executablePath">абсолютный путь к исполняемому файлу chrome.exe</param> /// <returns>содержимое результата в формате pdf в байтовом представлении</returns> public static async Task <byte[]> ConvertFromContentAsync(string htmlContent, string executablePath = DEFAULT_CHROME_PATH) { using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { ExecutablePath = executablePath, Headless = true, WebSocketFactory = async(uri, socketOptions, cancellationToken) => { var client = SystemClientWebSocket.CreateClientWebSocket(); if (client is System.Net.WebSockets.Managed.ClientWebSocket managed) { managed.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await managed.ConnectAsync(uri, cancellationToken); } else { var coreSocket = client as ClientWebSocket; coreSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await coreSocket.ConnectAsync(uri, cancellationToken); } return(client); }, }).ConfigureAwait(false))
private async void InitWebSocket() { if (wssPort != "443") { socketPath = "wss://" + hostName + ":" + wssPort + "/Services/Remote_Control_Socket.cshtml"; } await TestSSL(); try { Socket = SystemClientWebSocket.CreateClientWebSocket(); } catch (Exception ex) { WriteToLog(ex); System.Windows.MessageBox.Show("Unable to create web socket.", "Web Sockets Not Supported", MessageBoxButton.OK, MessageBoxImage.Error); return; } try { await Socket.ConnectAsync(new Uri(socketPath), CancellationToken.None); } catch { try { if (wsPort != "80") { socketPath = "ws://" + hostName + ":" + wsPort + "/Services/Remote_Control_Socket.cshtml"; } Socket = SystemClientWebSocket.CreateClientWebSocket(); await Socket.ConnectAsync(new Uri(socketPath), CancellationToken.None); } catch (Exception ex) { WriteToLog(ex); System.Windows.MessageBox.Show("Unable to connect to server.", "Connection Failed", MessageBoxButton.OK, MessageBoxImage.Error); return; } } if (socketPath.StartsWith("ws://")) { var result = System.Windows.MessageBox.Show("A secure connection couldn't be established. SSL is not configured properly on the server. Do you want to proceed with an unencrypted connection?", "Connection Not Secure", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.No) { App.Current.Shutdown(); return; } } WriteToLog($"Connection opened on {socketPath}."); // Send notification to server that this connection is for a client app. var request = new { Type = "ConnectionType", ConnectionType = "ClientApp", ComputerName = Environment.MachineName, }; await SocketSend(request); HandleSocket(); }
protected async Task Connect() { Socket = SystemClientWebSocket.ConnectAsync(new Uri("ws://remote.natfrp.com:2333"), Source.Token).Result; await Socket.SendAsync(new ArraySegment <byte>(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary <string, object> { { "version", REMOTE_VERSION }, { "type", "launcher" }, { "token", Natfrp.Token }, { "identifier", Identifier } }))), WebSocketMessageType.Text, true, Source.Token); Main.LogManager.Log(LogManager.CATEGORY_SERVICE_INFO, "Service", "RemoteManager: 远程管理已连接"); var remote = new RemotePipeConnection(); byte[] buffer = new byte[8192]; while (!Source.IsCancellationRequested) { // Ensure message is complete int length = 0; WebSocketReceiveResult result = null; while (true) { result = await Socket.ReceiveAsync(new ArraySegment <byte>(buffer, length, buffer.Length - length), Source.Token); length += result.Count; if (result.EndOfMessage) { break; } else if (length >= buffer.Length) { Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 接收到过长消息, 已断开服务器连接, 将在稍后重连"); await Socket.CloseAsync(WebSocketCloseStatus.MessageTooBig, "消息过长", Source.Token); return; } } // Handle close message if (result.MessageType == WebSocketMessageType.Close) { switch (result.CloseStatus.Value) { case WebSocketCloseStatus.NormalClosure: Main.LogManager.Log(LogManager.CATEGORY_SERVICE_INFO, "Service", "RemoteManager: 服务端正常断开 [" + result.CloseStatusDescription + "] 将在稍后重连"); break; case WebSocketCloseStatus.PolicyViolation: Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 服务器拒绝请求, 已停止远程管理功能: " + result.CloseStatusDescription); Stop(); return; case WebSocketCloseStatus.InternalServerError: Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 服务器内部错误, " + result.CloseStatusDescription); break; default: Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 未知错误 [" + result.CloseStatus + "], " + result.CloseStatusDescription); break; } await Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, Source.Token); return; } // Hmm, ensure something unexpected won't crash the socket if (length < OVERHEAD) { Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 收到过短的消息"); return; } // Process payload using (var ms = new MemoryStream()) { ms.Write(buffer, 0, OVERHEAD); switch (buffer[0]) { case 0x01: // Heartbeat if (length != OVERHEAD) { Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 心跳包长度异常"); continue; } break; case 0x02: // Remote Command if (length < 24 + OVERHEAD) { Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 收到过短的指令"); continue; } byte[] nonce = new byte[24], data = new byte[length - nonce.Length - OVERHEAD]; Buffer.BlockCopy(buffer, OVERHEAD, nonce, 0, nonce.Length); Buffer.BlockCopy(buffer, nonce.Length + OVERHEAD, data, 0, data.Length); try { data = SecretBox.Open(data, nonce, EncryptKey); } catch { Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 指令解密失败, 原因可能为密钥错误, 如果您无故看到此错误请检查账户是否被盗"); break; } remote.Buffer = data; Main.Pipe_DataReceived(remote, data.Length); nonce = SecretBox.GenerateNonce(); ms.Write(nonce, 0, nonce.Length); data = SecretBox.Create(remote.Buffer, nonce, EncryptKey); ms.Write(data, 0, data.Length); break; default: Main.LogManager.Log(LogManager.CATEGORY_SERVICE_WARNING, "Service", "RemoteManager: 收到未知消息"); continue; } await Socket.SendAsync(new ArraySegment <byte>(ms.ToArray()), WebSocketMessageType.Binary, true, Source.Token); } } }
/// <summary> /// <para>设置一个 Chromium 浏览器 启动选项 的对象,并返回这个对象;此方法兼容 Windows7 / Windows Server 2008</para> /// <para>异常可能:程序运行目录下 Chromium 浏览器不可用。</para> /// </summary> /// <param name="checkIsDownload">检查 是否下载 Chromium 浏览器;默认 false</param> /// <param name="isDisplay">Chromium 运行时 是否显示界面;默认 true</param> /// <param name="args">要传递给 Chromium 浏览器实例的其他参数。( 此方法会自动传入 "--no-sandbox" 参数 ) /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para> /// </param> /// <param name="ignoredDefaultArgs">如果给出数组,则过滤掉给定的 Puppeteer.DefaultArgs 默认参数。 /// ( 此方法会自动设置 "--enable-automation" 过滤掉这个参数 ) /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para> /// </param> /// <returns></returns> private static async Task <LaunchOptions> SetChromiumLaunchOptions( bool checkIsDownload = false, bool isDisplay = true, string[] args = null, string[] ignoredDefaultArgs = null) { return(await Task.Run(async() => { BrowserFetcher browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions()); RevisionInfo revisionInfo = browserFetcher.RevisionInfo(BrowserFetcher.DefaultRevision); #region 检查下载 Chromium if (!(revisionInfo.Downloaded && revisionInfo.Local)) { if (checkIsDownload) { #region 载地址 解析;参考于源代码:https://github.com/hardkoded/puppeteer-sharp/blob/37ea56934281209830254df3ec3ffe37c57cfac2/lib/PuppeteerSharp/BrowserFetcher.cs // https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/706915/chrome-win.zip 下载地址( 样例 ) // const string DefaultDownloadHost = "https://storage.googleapis.com"; // const int DefaultRevision = 706915; // [Platform.Linux] = "{0}/chromium-browser-snapshots/Linux_x64/{1}/{2}.zip", // [Platform.MacOS] = "{0}/chromium-browser-snapshots/Mac/{1}/{2}.zip", // [Platform.Win32] = "{0}/chromium-browser-snapshots/Win/{1}/{2}.zip", // [Platform.Win64] = "{0}/chromium-browser-snapshots/Win_x64/{1}/{2}.zip" // case Platform.Linux: // return "chrome-linux"; // case Platform.MacOS: // return "chrome-mac"; // case Platform.Win32: // case Platform.Win64: // return revision > 591479 ? "chrome-win" : "chrome-win32"; #endregion // 检查 revisionInfo.Revision 这个版本的 Chromium 浏览器 是否 可下载 bool isCan = await browserFetcher.CanDownloadAsync(revisionInfo.Revision); if (isCan) { // 下载 revisionInfo.Revision 这个版本的无头浏览器;可能需要等待一些时间 await browserFetcher.DownloadAsync(revisionInfo.Revision); } else { throw new Exception($"程序检测出 Chromium 浏览器(默认版本 {revisionInfo.Revision})无法更新!"); } } else { throw new Exception("程序运行目录下 Chromium 浏览器不可用。请开发人员检查 程序运行目录下 是否正确安装 Chromium 浏览器。"); } } #endregion #region 兼容 Windows7 / Windows Server 2008 LaunchOptions launchOptions = default(LaunchOptions); // 这个判断是为了兼容 Windows7 和 Windows Server 2008 if (OSHelper.IsWin7Under()) { launchOptions = new LaunchOptions { WebSocketFactory = async(uri, socketOptions, cancellationToken) => { WebSocket client = SystemClientWebSocket.CreateClientWebSocket(); if (client is System.Net.WebSockets.Managed.ClientWebSocket managed) { managed.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await managed.ConnectAsync(uri, cancellationToken); } else { ClientWebSocket coreSocket = client as ClientWebSocket; coreSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await coreSocket.ConnectAsync(uri, cancellationToken); } return client; } }; } else { launchOptions = new LaunchOptions(); } #endregion #region 设置 Args 参数 string[] argss = default(string[]); if (args != null && args.Length > 0) { List <string> argsList = args.ToList <string>(); argsList.Add("--no-sandbox"); argss = argsList.ToArray(); } else { argss = new string[] { "--no-sandbox" }; } launchOptions.Args = argss; //这些参数将会传递给 Chromium #endregion #region 设置 IgnoredDefaultArgs 参数 string[] defaultArgs = default(string[]); if (ignoredDefaultArgs != null && ignoredDefaultArgs.Length > 0) { List <string> ignoredDefaultArgsList = ignoredDefaultArgs.ToList <string>(); ignoredDefaultArgsList.Add("--enable-automation"); defaultArgs = ignoredDefaultArgsList.ToArray(); } else { defaultArgs = new string[] { "--enable-automation" }; } launchOptions.IgnoredDefaultArgs = defaultArgs; //这些参数将被 Chromium 忽略 #endregion launchOptions.Headless = !isDisplay; // Headless : true 是无头模式,无界面;false,有界面 return launchOptions; })); }
private WebSocket ObtainConnection() { lock (this) { if (_wsCancellationSource.IsCancellationRequested) { return(null); } if (_webSocket == null) { _webSocket = SystemClientWebSocket.CreateClientWebSocket(); } switch (_webSocket.State) { case WebSocketState.None: break; case WebSocketState.Connecting: case WebSocketState.Open: // All good return(_webSocket); case WebSocketState.CloseSent: case WebSocketState.CloseReceived: case WebSocketState.Closed: _webSocket.Abort(); _webSocket.Dispose(); _webSocket = SystemClientWebSocket.CreateClientWebSocket(); break; case WebSocketState.Aborted: _webSocket.Dispose(); _webSocket = SystemClientWebSocket.CreateClientWebSocket(); break; default: throw new ArgumentOutOfRangeException(); } Debug.Assert(_webSocket.State == WebSocketState.None); // Connect Logger.Debug("(重新)连接 EdgeTTS 服务器中..."); if (_webSocket is ClientWebSocket ws) { var options = ws.Options; options.SetRequestHeader("Accept-Encoding", "gzip, deflate, br"); options.SetRequestHeader("Cache-Control", "no-cache"); options.SetRequestHeader("Pragma", "no-cache"); } else { var options = ((System.Net.WebSockets.Managed.ClientWebSocket)_webSocket).Options; options.SetRequestHeader("Accept-Encoding", "gzip, deflate, br"); options.SetRequestHeader("Cache-Control", "no-cache"); options.SetRequestHeader("Pragma", "no-cache"); } _webSocket.ConnectAsync(new Uri(URL), _wsCancellationSource.Token).Wait(); return(_webSocket); } }
private byte[] Synthesis(XfyunTTSSettings settings, string text) { var apiSecret = settings.ApiSecret; var apiKey = settings.ApiKey; var appId = settings.AppId; if (string.IsNullOrEmpty(apiKey) || string.IsNullOrEmpty(apiSecret) || string.IsNullOrEmpty(appId)) { Logger.Error(strings.msgErrorEmptyApiSecretKey); _settingsControl.NotifyEmptyApiKey(); return(null); } var base64Text = Convert.ToBase64String(Encoding.UTF8.GetBytes(text)); if (base64Text.Length > 8000) { Logger.Error("Convert string too long. No more than 2000 chinese characters."); return(null); } using (var ws = SystemClientWebSocket.CreateClientWebSocket()) { // Connect var date = DateTime.UtcNow.ToString("R"); var sign = $"host: tts-api.xfyun.cn\ndate: {date}\nGET /v2/tts HTTP/1.1"; string sha; using (var hash = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret))) { sha = Convert.ToBase64String(hash.ComputeHash(Encoding.UTF8.GetBytes(sign))); hash.Clear(); } var authorization = $"api_key=\"{apiKey}\"," + $" algorithm=\"hmac-sha256\"," + $" headers=\"host date request-line\"," + $" signature=\"{sha}\""; var url = $"wss://tts-api.xfyun.cn/v2/tts?host=tts-api.xfyun.cn" + $"&date={WebUtility.UrlEncode(date).Replace("+", "%20")}" + $"&authorization={Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization))}"; try { ws.ConnectAsync(new Uri(url), _wsCancellationSource.Token).Wait(); } catch (AggregateException e) { var inner = e.InnerExceptions.First().GetBaseException(); if (inner is WebException webException) { var resp = (HttpWebResponse)webException.Response; string body = null; using (var stream = resp.GetResponseStream()) { if (stream != null) { var reader = new StreamReader(stream, string.IsNullOrEmpty(resp.CharacterSet) ? Encoding.UTF8 : Encoding.GetEncoding(resp.CharacterSet)); body = reader.ReadToEnd(); } } Logger.Error($"Unable to connect to server: {body}"); switch (resp.StatusCode) { case HttpStatusCode.Unauthorized: case HttpStatusCode.Forbidden: Logger.Error(strings.msgErrorXfyunAuthFail); return(null); } } throw; } // Send request var request = new TTSRequest { Common = new TTSRequest.CommonParam { AppId = settings.AppId, }, Business = new TTSRequest.BusinessParam { Voice = settings.Voice, Pitch = settings.Pitch * 10, Speed = settings.Speed * 10, Volume = settings.Volume * 10, }, Data = new TTSRequest.DataParam { Status = 2, Text = base64Text, } }; ws.SendText(JsonConvert.SerializeObject(request), _wsCancellationSource); // Start receiving var buffer = new MemoryStream(); var session = new WebSocketHelper.Session(ws); while (true) { var message = WebSocketHelper.ReceiveNextMessage(session, _wsCancellationSource); Logger.Debug($"Received WS message\n{message}"); if (message.Type == WebSocketMessageType.Text) { var resp = JsonConvert.DeserializeObject <TTSResponse>(message.MessageStr); if (resp.Code == 0) { // Success! if (resp.Data != null) { var data = Convert.FromBase64String(resp.Data.Audio); buffer.Write(data, 0, data.Length); if (resp.Data.Status == 2) { // Complete! return(buffer.ToArray()); } } } else { Logger.Error($"Unexpected response code received: {resp.Code}: {resp.Message}"); switch (resp.Code) { case 10005: case 10313: Logger.Error(strings.msgErrorXfyunWrongAppId); break; case 11200: case 11201: Logger.Error(strings.msgErrorXfyunInsufficientApiQuota); break; } return(null); } } else if (message.Type == WebSocketMessageType.Binary) { throw new IOException("Unexpected binary message received"); } else if (message.Type == WebSocketMessageType.Close) { throw new IOException("Unexpected closing of connection"); } else { throw new ArgumentOutOfRangeException(); } } } }
/// <summary> /// <para>设置一个 Chromium 浏览器 启动选项 的对象,并返回这个对象;此方法兼容 Windows7 / Windows Server 2008</para> /// <para>异常可能:程序运行目录下 Chromium 浏览器不可用。</para> /// </summary> /// <param name="checkIsDownload">检查 是否下载 Chromium 浏览器;默认 false</param> /// <param name="isDisplay">Chromium 运行时 是否显示界面;默认 true</param> /// <param name="args">要传递给 Chromium 浏览器实例的其他参数。( 此方法会自动传入 "--no-sandbox" 参数 ) /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para> /// </param> /// <param name="ignoredDefaultArgs">如果给出数组,则过滤掉给定的 Puppeteer.DefaultArgs 默认参数。 /// ( 此方法会自动设置 "--enable-automation" 过滤掉这个参数 ) /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para> /// </param> /// <returns></returns> private static async Task <LaunchOptions> SetChromiumLaunchOptions( bool checkIsDownload = false, bool isDisplay = true, string[] args = null, string[] ignoredDefaultArgs = null) { return(await Task.Run(async() => { BrowserFetcher browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions()); RevisionInfo revisionInfo = browserFetcher.RevisionInfo(BrowserFetcher.DefaultChromiumRevision); #region 检查下载 Chromium if (!(revisionInfo.Downloaded && revisionInfo.Local)) { if (checkIsDownload) { // 检查 revisionInfo.Revision 这个版本的 Chromium 浏览器 是否 可下载 bool isCan = await browserFetcher.CanDownloadAsync(revisionInfo.Revision); if (isCan) { // 下载 revisionInfo.Revision 这个版本的无头浏览器;可能需要等待一些时间 await browserFetcher.DownloadAsync(revisionInfo.Revision); } else { throw new Exception($"程序检测出 Chromium 浏览器(默认版本 {revisionInfo.Revision})无法更新!"); } } else { throw new Exception("程序运行目录下 Chromium 浏览器不可用。请开发人员检查 程序运行目录下 是否正确安装 Chromium 浏览器。"); } } #endregion #region 兼容 Windows7 / Windows Server 2008 LaunchOptions launchOptions = default(LaunchOptions); // 这个判断是为了兼容 Windows7 和 Windows Server 2008 if (OSHelper.IsWin7Under()) { launchOptions = new LaunchOptions { WebSocketFactory = async(uri, socketOptions, cancellationToken) => { WebSocket client = SystemClientWebSocket.CreateClientWebSocket(); if (client is System.Net.WebSockets.Managed.ClientWebSocket managed) { managed.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await managed.ConnectAsync(uri, cancellationToken); } else { ClientWebSocket coreSocket = client as ClientWebSocket; coreSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await coreSocket.ConnectAsync(uri, cancellationToken); } return client; } }; } else { launchOptions = new LaunchOptions(); } #endregion #region 设置 Args 参数 string[] argss = default(string[]); if (args != null && args.Length > 0) { List <string> argsList = args.ToList <string>(); argsList.Add("--no-sandbox"); argss = argsList.ToArray(); } else { argss = new string[] { "--no-sandbox" }; } launchOptions.Args = argss; // 这些参数将会传递给 Chromium #endregion #region 设置 IgnoredDefaultArgs 参数 string[] defaultArgs = default(string[]); if (ignoredDefaultArgs != null && ignoredDefaultArgs.Length > 0) { List <string> ignoredDefaultArgsList = ignoredDefaultArgs.ToList <string>(); ignoredDefaultArgsList.Add("--enable-automation"); defaultArgs = ignoredDefaultArgsList.ToArray(); } else { defaultArgs = new string[] { "--enable-automation" }; } launchOptions.IgnoredDefaultArgs = defaultArgs; // 这些参数将被 Chromium 忽略 #endregion launchOptions.Headless = !isDisplay; // Headless : true 是无头模式,无界面;false,有界面 return launchOptions; })); }
/// <summary> /// 测试无头浏览器 /// </summary> /// <param name="isDisplay">是否显示界面</param> /// <returns></returns> private async Task TestHeadlessChromiumAsync(bool isDisplay = true) { this.Invoke(new Action(() => { this.rTxt_log.AppendText("正在启动无头浏览器... \n"); })); #region 兼容 Win7 及以下系统 (包含 Win7) LaunchOptions launchOptions; if (OSHelper.IsWin7Under()) { launchOptions = new LaunchOptions { WebSocketFactory = async(uri, socketOptions, cancellationToken) => { var client = SystemClientWebSocket.CreateClientWebSocket(); if (client is System.Net.WebSockets.Managed.ClientWebSocket managed) { managed.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await managed.ConnectAsync(uri, cancellationToken); } else { var coreSocket = client as ClientWebSocket; coreSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0); await coreSocket.ConnectAsync(uri, cancellationToken); } return(client); } }; } else { launchOptions = new LaunchOptions(); } launchOptions.Headless = !isDisplay; // Headless true 是无头模式;false 是开发者模式,有界面 #endregion string htmlContent = string.Empty; // 启动 Chromium 浏览器 using (Browser browser = await Puppeteer.LaunchAsync(launchOptions)) { this.Invoke(new Action(() => { this.rTxt_log.AppendText("无头浏览器已启动。 \n"); })); // 新建一个标签页 using (Page page = await browser.NewPageAsync()) { // 导航到 url 页 await page.GoToAsync(_testUrl); string fileName = DateTime.Now.ToString("yyyy-MM-dd_HH.mm.ss"); // 保存截图 await page.ScreenshotAsync($"{SavePageDirectory}{fileName}.png"); // 获取并返回页面的 Html 内容 htmlContent = await page.GetContentAsync(); // 保存 Html 内容 WriteCreate($"{SavePageDirectory}{fileName}.html", htmlContent); this.Invoke(new Action(() => { this.rTxt_log.AppendText($"测试页面已保存成功。目录 ==> {SavePageDirectory} \n"); })); // 界面停留,给开发人员看 await Task.Delay(14 * 1000); } } }