net.rs (4770B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use serde::Serialize; 6 use std::{time, thread}; 7 use std::net::TcpStream; 8 use tungstenite::{WebSocket, stream::MaybeTlsStream}; 9 use webrender_api::debugger::DebuggerMessage; 10 11 // Network interfaces for interacting with a WR remote debugger instance 12 13 // Simple HTTP connection used to issue most commands and queries 14 pub struct HttpConnection { 15 host: String, 16 } 17 18 impl HttpConnection { 19 pub fn new(host: &str) -> Self { 20 let host = format!("http://{}", host); 21 22 HttpConnection { 23 host, 24 } 25 } 26 27 pub fn get( 28 &mut self, 29 endpoint: &str, 30 ) -> Result<Option<String>, String> { 31 self.get_with_query( 32 endpoint, 33 &[], 34 ) 35 } 36 37 pub fn get_with_query( 38 &mut self, 39 endpoint: &str, 40 params: &[(&str, &str)], 41 ) -> Result<Option<String>, String> { 42 let url = format!("{}/{}", self.host, endpoint); 43 44 match reqwest::blocking::Client::builder() 45 .build() 46 .expect("bug") 47 .get(url) 48 .query(params) 49 .send() { 50 Ok(response) => { 51 let text = response.text().expect("no content"); 52 if text.is_empty() { 53 Ok(None) 54 } else { 55 Ok(Some(text)) 56 } 57 } 58 Err(error) => { 59 Err(error.to_string()) 60 } 61 } 62 } 63 64 pub fn post_with_content<T: Serialize>( 65 &mut self, 66 endpoint: &str, 67 content: &T, 68 ) -> Result<Option<String>, String> { 69 let url = format!("{}/{}", self.host, endpoint); 70 let body = serde_json::to_string(content).expect("bug"); 71 72 match reqwest::blocking::Client::builder() 73 .build() 74 .expect("bug") 75 .post(url) 76 .body(body) 77 .send() { 78 Ok(response) => { 79 let text = response.text().expect("no content"); 80 if text.is_empty() { 81 Ok(None) 82 } else { 83 Ok(Some(text)) 84 } 85 } 86 Err(error) => { 87 Err(error.to_string()) 88 } 89 } 90 } 91 92 pub fn post( 93 &mut self, 94 endpoint: &str, 95 ) -> Result<Option<String>, String> { 96 self.post_with_content( 97 endpoint, 98 &"", 99 ) 100 } 101 } 102 103 // Network events that can be received from the stream socket 104 pub enum NetworkEvent { 105 Connected, 106 Disconnected, 107 Message(DebuggerMessage), 108 } 109 110 pub struct NetworkEventStream; 111 112 // Thread that connects to a WR instance and reads realtime updates as provided, such as 113 // profiler updates, debug flag changes etc. The messages are pushed pushed via a callback. 114 impl NetworkEventStream { 115 pub fn spawn<F>( 116 host: &str, 117 callback: F, 118 ) where 119 F: Fn(NetworkEvent) + Send + 'static, 120 { 121 let host = host.to_string(); 122 let mut connection: Option<WebSocket<MaybeTlsStream<TcpStream>>> = None; 123 124 loop { 125 match connection { 126 Some(ref mut socket) => { 127 match socket.read() { 128 Ok(msg) => { 129 let msg = match msg { 130 tungstenite::Message::Text(text) => text, 131 _ => todo!(), 132 }; 133 let msg: DebuggerMessage = serde_json::from_str(msg.as_str()).expect("bug"); 134 callback(NetworkEvent::Message(msg)); 135 } 136 Err(..) => { 137 // Connection dropped 138 connection = None; 139 callback(NetworkEvent::Disconnected); 140 } 141 } 142 } 143 None => { 144 // Try connect 145 let uri = format!("ws://{}/debugger-socket", host); 146 match tungstenite::connect(uri) { 147 Ok((socket, _)) => { 148 // Connected 149 connection = Some(socket); 150 callback(NetworkEvent::Connected); 151 } 152 Err(..) => { 153 // Wait until try again 154 thread::sleep(time::Duration::new(1, 0)); 155 } 156 } 157 } 158 } 159 } 160 } 161 }