├── .gitignore ├── Cargo.toml ├── tests ├── test.html └── test.rs ├── LICENSE ├── README.md ├── js ├── easy-rpc.js └── msgpack.js ├── src ├── ws.rs ├── shm.rs └── lib.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "easy-rpc" 3 | license = "MIT" 4 | version = "0.1.0" 5 | authors = ["metaworm "] 6 | edition = "2018" 7 | description = "A cross-language RPC framework" 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [features] 12 | default = ['ws', 'shm'] 13 | ws = ['websocket'] 14 | shm = ['shared_memory'] 15 | struct_map = [] 16 | 17 | [dependencies] 18 | rmp = '0.8.8' 19 | rmpv = '0.4.2' 20 | serde = '1.0.103' 21 | rmp-serde = '0.14.2' 22 | serde_bytes = '0.11.3' 23 | downcast-rs = '1.1.1' 24 | websocket = {version = '0.24.0', default-features = false, features = ['sync', 'async'], optional = true} 25 | 26 | [target.'cfg(not(target_os="android"))'.dependencies] 27 | shared_memory = {version = '0.10.0', optional = true} -------------------------------------------------------------------------------- /tests/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | EasyRpc Test 5 | 6 | 7 | 8 | 9 | 10 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 metaworm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `easy-rpc` 是跨通信方式的Rust RPC框架,也有其他语言实现。 2 | 3 | ||Rust|JavaScript| 4 | |--|--|--| 5 | |WebSocket|✓|✓| 6 | |SharedMem|✓|| 7 | 8 | WebSocket/JavaScript用于Rust和网页交互数据,共享内存(SharedMem)用于进程间通信。 9 | 10 | ## 优点 11 | 12 | * 基于MsgPack,不需要协议文件,动态解析类型 13 | * 通信双方可以递归地Request,类似本地的函数递归调用 14 | 15 | ## 缺点 16 | 17 | `easy-rpc`(目前)不是异步实现,每一个会话都会占据一个线程。如果你用在有大量IO的服务端上,可能不太合适。 18 | 19 | ## 文档 20 | 21 | 有待完善。可以参考test里的例子,如果你用过serde系列库,应该会很容易上手。 22 | 23 | ## 注意事项 24 | 25 | `easy-rpc`目前依赖一个git库,所以没有发布到 crates.io,使用时要通过git引用。 26 | 27 | Cargo.toml 28 | 29 | ```toml 30 | [package] 31 | # ... 32 | 33 | [dependencies] 34 | # ... 35 | easy-rpc = {git = 'https://github.com/metaworm/easy-rpc'} 36 | ``` 37 | 38 | ## 示例 39 | 40 | ```rust 41 | use std::sync::Arc; 42 | use easy_rpc::*; 43 | 44 | struct ServerService; 45 | 46 | const MUL: u32 = 1; 47 | easy_service! { 48 | ServerService(self, _ss, arg, response) 49 | 50 | StringMethod { 51 | "add" => (a: u32, b: u32) { 52 | a + b 53 | } 54 | "print" => (s: String) { 55 | println!("{}", s); 56 | } 57 | } 58 | IntegerMethod { 59 | MUL => (a: u32, b: u32) { 60 | a * b 61 | } 62 | } 63 | } 64 | 65 | fn main() -> Result<(), Box> { 66 | std::thread::spawn(|| { 67 | let mut ser = ws::bind("127.0.0.1:3333").unwrap(); 68 | let (adaptor, _uri) = ws::accept(&mut ser).unwrap(); 69 | Session::new(adaptor, Arc::new(ServerService)).loop_handle(); 70 | }); 71 | 72 | std::thread::sleep_ms(100); 73 | let session = Session::new(ws::connect("ws://127.0.0.1:3333")?, Arc::new(EmptyService)); 74 | let val: u32 = session.request("add", (1, 2)).into()?; 75 | session.notify("print", format!("the result is {}", val)); 76 | let val: u32 = session.request(MUL, (2, 3)).into()?; 77 | assert_eq!(val, 6); 78 | 79 | Ok(()) 80 | } 81 | ``` -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::Arc; 3 | use easy_rpc::*; 4 | 5 | struct ClientService; 6 | struct ServerService; 7 | 8 | const RECURSIVE_ADD: u32 = 1; 9 | const ECHO_BIGDATA: u32 = 2; 10 | 11 | easy_service! { 12 | ClientService(self, _ss, arg, ret) 13 | 14 | IntegerMethod { 15 | RECURSIVE_ADD => (val: u32) { 16 | println!("Client Received {:?}", val); 17 | val + 1 18 | } 19 | } 20 | } 21 | 22 | easy_service! { 23 | ServerService(self, ss, arg, ret) 24 | 25 | IntegerMethod { 26 | RECURSIVE_ADD => (val: u32) { 27 | println!("Server Received {:?}", val); 28 | let val = ss.request(RECURSIVE_ADD, &val).into::()?; 29 | println!("Server Requested {:?}", val); 30 | val + 1 31 | } 32 | ECHO_BIGDATA => (data: Vec) { 33 | println!("BigData Received {}", data.len()); 34 | data 35 | } 36 | } 37 | } 38 | 39 | fn session_test(session: &Session) { 40 | let val: u32 = session.request(RECURSIVE_ADD, 0).into().unwrap(); 41 | assert_eq!(val, 2); 42 | 43 | const LEN: usize = 0x10000; 44 | let tail = &[1, 2, 3]; 45 | let mut data: Vec = Vec::with_capacity(LEN); 46 | data.resize(LEN, 0); data.extend_from_slice(tail); 47 | 48 | let data: Vec = session.request(ECHO_BIGDATA, &data).into().unwrap(); 49 | assert_eq!(data.len(), LEN + tail.len()); 50 | assert_eq!(&data[data.len() - tail.len()..], tail); 51 | } 52 | 53 | #[test] 54 | fn test_ws() { 55 | std::thread::spawn(|| { 56 | let mut ser = ws::bind("127.0.0.1:3333").unwrap(); 57 | let (adaptor, _uri) = ws::accept(&mut ser).unwrap(); 58 | let s = Session::new(adaptor, Arc::new(ServerService)); 59 | s.loop_handle(); 60 | }); 61 | 62 | std::thread::sleep_ms(100); 63 | let session = Session::new(ws::connect("ws://127.0.0.1:3333").unwrap(), Arc::new(ClientService)); 64 | session_test(&session); 65 | } 66 | 67 | #[test] 68 | #[ignore] 69 | fn test_js() { 70 | let mut ser = ws::bind("127.0.0.1:3333").unwrap(); 71 | let (adaptor, _uri) = ws::accept(&mut ser).unwrap(); 72 | let session = Session::new(adaptor, Arc::new(ServerService)); 73 | session.loop_handle(); 74 | } 75 | 76 | #[test] 77 | fn test_shm() { 78 | std::thread::spawn(move || { 79 | let adaptor = shm::create("sharememory_test").unwrap(); 80 | adaptor.wait(None); 81 | let s = Session::new(adaptor, Arc::new(ServerService)); 82 | s.loop_handle(); 83 | }); 84 | 85 | std::thread::sleep_ms(100); 86 | let s = Session::new(shm::connect("sharememory_test").unwrap(), Arc::new(ClientService)); 87 | session_test(&s); 88 | } -------------------------------------------------------------------------------- /js/easy-rpc.js: -------------------------------------------------------------------------------- 1 | 2 | let msgpack = MessagePack 3 | 4 | const REQUEST = 0 5 | const RESPONSE = 1 6 | const NOTIFY = 2 7 | 8 | class EasySession { 9 | constructor(url, service) { 10 | let socket = new WebSocket(url) 11 | socket.session = this 12 | this.socket = socket 13 | this.service = service 14 | this._id = 0 15 | this._callback = {} 16 | let self = this 17 | return new Promise((resolve, reject) => { 18 | socket.onmessage = e => self._handle(e.data) 19 | socket.onopen = e => resolve(self) 20 | socket.onerror = e => reject(e) 21 | socket.onclose = e => self.onclose(e) 22 | }); 23 | } 24 | 25 | onclose(event) { 26 | if (typeof this.service.__onclose == 'function') 27 | this.service.__onclose(event) 28 | } 29 | 30 | next_id() { this._id += 1; return this._id } 31 | 32 | request(method, arg) { 33 | let id = this.next_id() 34 | this._send_pack([REQUEST, id, method, arg]) 35 | return new Promise((resolve, reject) => { 36 | this._callback[id] = {resolve, reject} 37 | }) 38 | } 39 | 40 | notify(method, arg) { this._send_pack([NOTIFY, method, arg]) } 41 | 42 | close() { this.socket.close(); } 43 | 44 | async _handle(blob) { 45 | // let data = await blob.arrayBuffer(); 46 | let data = await new Response(blob).arrayBuffer() 47 | let pack = msgpack.decode(data) 48 | switch (pack[0]) { 49 | case REQUEST: { 50 | let req_id = pack[1] 51 | let method = pack[2] 52 | try { 53 | let ret = this.service[method](pack[3], this) 54 | this._send_pack([RESPONSE, req_id, null, ret]) 55 | } catch (err) { 56 | this._send_pack([RESPONSE, req_id, err.toString(), null]); 57 | } 58 | break 59 | } 60 | case NOTIFY: { 61 | let method = pack[1]; 62 | try { 63 | this.service[method](pack[2], this) 64 | } catch (err) { 65 | console.warn('[easy-rpc]', err.toString()) 66 | } 67 | break 68 | } 69 | case RESPONSE: { 70 | let req_id = pack[1] 71 | let err = pack[2] 72 | let callback = this._callback[req_id] 73 | if (err != null) 74 | callback.reject(err) 75 | else 76 | callback.resolve(pack[3]) 77 | delete this._callback[req_id] 78 | break 79 | } 80 | } 81 | } 82 | 83 | _send_pack(pack) { this.socket.send(msgpack.encode(pack)) } 84 | } -------------------------------------------------------------------------------- /src/ws.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::io; 3 | use std::sync::Mutex; 4 | use std::sync::{Arc, RwLock}; 5 | use std::net::{TcpStream, TcpListener, ToSocketAddrs}; 6 | 7 | use websocket::sync::{Server, Client}; 8 | use websocket::server::NoTlsAcceptor; 9 | use websocket::server::WsServer; 10 | use websocket::{ 11 | OwnedMessage, 12 | client::{ClientBuilder, sync::{Reader, Writer}}, 13 | }; 14 | pub use websocket::WebSocketError; 15 | 16 | use crate::{Adaptor, RecvError}; 17 | 18 | pub struct WsAdaptor { 19 | sender: Mutex>, 20 | receiver: Mutex>, 21 | disconnected: RwLock, 22 | } 23 | 24 | impl WsAdaptor { 25 | pub fn new(client: Client) -> io::Result { 26 | let (receiver, sender) = client.split()?; 27 | Ok(WsAdaptor { 28 | sender: Mutex::new(sender), 29 | receiver: Mutex::new(receiver), 30 | disconnected: RwLock::new(false), 31 | }) 32 | } 33 | } 34 | 35 | impl Adaptor for WsAdaptor { 36 | fn send(&self, data: Vec) -> bool { 37 | self.sender.lock().unwrap() 38 | .send_message(&OwnedMessage::Binary(data)).is_ok() 39 | } 40 | 41 | fn recv(&self) -> Result, RecvError> { 42 | match recv_message(&mut self.receiver.lock().unwrap(), &self.sender) { 43 | Err(e) => { 44 | if is_disconnected(&e) { 45 | *self.disconnected.write().unwrap() = true; 46 | Err(RecvError::Disconnect) 47 | } else { panic!("Invalid Error: {:?}", e); } 48 | } 49 | Ok(data) => { Ok(data) } 50 | } 51 | } 52 | 53 | fn connected(&self) -> bool { 54 | !*self.disconnected.read().unwrap() 55 | } 56 | 57 | fn close(&self) { 58 | self.sender.lock().unwrap().shutdown_all(); 59 | } 60 | } 61 | 62 | fn recv_message(r: &mut Reader, s: &Mutex>) -> Result, WebSocketError> { 63 | loop { 64 | match r.recv_message()? { 65 | OwnedMessage::Close(_) => { 66 | s.lock().unwrap() 67 | .send_message(&OwnedMessage::Close(None))?; 68 | } 69 | OwnedMessage::Ping(ping) => { 70 | s.lock().unwrap() 71 | .send_message(&OwnedMessage::Pong(ping))?; 72 | } 73 | OwnedMessage::Binary(msg) => { return Ok(msg); } 74 | _ => {} 75 | } 76 | } 77 | } 78 | 79 | fn is_disconnected(err: &WebSocketError) -> bool { 80 | match *err { 81 | WebSocketError::NoDataAvailable => true, 82 | WebSocketError::IoError(_) => true, 83 | _ => false, 84 | } 85 | } 86 | 87 | pub type ServerT = WsServer; 88 | 89 | pub fn bind(addr: impl ToSocketAddrs) -> io::Result { 90 | Server::bind(addr) 91 | } 92 | 93 | pub fn accept(server: &mut ServerT) -> io::Result<(Arc, String)> { 94 | loop { 95 | if let Ok(s) = server.accept() { 96 | let uri = s.uri(); 97 | if let Ok(s) = s.accept() { 98 | return Ok((Arc::new(WsAdaptor::new(s)?), uri)); 99 | } 100 | } 101 | } 102 | } 103 | 104 | pub fn connect(url: &str) -> Result, WebSocketError> { 105 | Ok(Arc::new(WsAdaptor::new( 106 | ClientBuilder::new(url).unwrap().connect_insecure()? 107 | ).map_err(|e| WebSocketError::IoError(e))?)) 108 | } -------------------------------------------------------------------------------- /src/shm.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::cell::{Cell, UnsafeCell}; 3 | use std::sync::atomic::{AtomicU32, Ordering}; 4 | use std::mem::{size_of, transmute}; 5 | use std::sync::{Arc, Mutex}; 6 | use std::time::{Instant, Duration}; 7 | 8 | use shared_memory::*; 9 | use crate::{Adaptor, RecvError}; 10 | 11 | pub use shared_memory::Timeout; 12 | 13 | struct Channel { 14 | data_ty: AtomicU32, 15 | data_len: AtomicU32, 16 | sended: AtomicU32, 17 | recved: AtomicU32, 18 | buf: [u8; 2048], 19 | } 20 | 21 | const FRAME_NONE: u32 = 0; 22 | const FRAME_PING: u32 = 1; 23 | const FRAME_PONG: u32 = 2; 24 | const FRAME_DATA: u32 = 3; 25 | 26 | enum Frame { 27 | None, 28 | Ping, 29 | Pong, 30 | Timeout, 31 | Data(Vec), 32 | } 33 | 34 | const SYNC_TIME_OUT: Duration = Duration::from_secs(1); 35 | 36 | impl Channel { 37 | fn init(&mut self) { 38 | self.data_ty = AtomicU32::new(FRAME_NONE); 39 | self.data_len = AtomicU32::new(0); 40 | self.sended = AtomicU32::new(0); 41 | self.recved = AtomicU32::new(0); 42 | } 43 | 44 | fn wait_recv(&mut self) -> Option<(u32, u32)> { 45 | let begin = Instant::now(); 46 | loop { 47 | let sended = self.sended.load(Ordering::Relaxed); 48 | let recved = self.recved.load(Ordering::Relaxed); 49 | if recved == sended { return Some((sended, recved)); } 50 | 51 | if begin.elapsed() > SYNC_TIME_OUT { return None; } 52 | } 53 | } 54 | 55 | fn send_type(&mut self, frame: &Frame) -> bool { 56 | let begin = Instant::now(); 57 | while self.data_ty.load(Ordering::Relaxed) != FRAME_NONE { 58 | if begin.elapsed() > SYNC_TIME_OUT { return false; } 59 | } 60 | 61 | match frame { 62 | Frame::Ping => self.data_ty.store(FRAME_PING, Ordering::Relaxed), 63 | Frame::Pong => self.data_ty.store(FRAME_PONG, Ordering::Relaxed), 64 | Frame::Data(ref d) => { 65 | self.data_ty.store(FRAME_DATA, Ordering::Relaxed); 66 | self.data_len.store(d.len() as u32, Ordering::Relaxed); 67 | } 68 | _ => { panic!(); } 69 | } 70 | true 71 | } 72 | 73 | fn send_data(&mut self, data: &[u8]) -> bool { 74 | let (mut sended, mut _recved) = (0u32, 0u32); 75 | loop { 76 | // Copy data slice 77 | { 78 | let sended = sended as usize; 79 | let rest_size = data.len() - sended; 80 | let size = self.buf.len().min(rest_size); 81 | (self.buf[..size]).copy_from_slice(&data[sended .. sended + size]); 82 | // Update sended 83 | let after_size = sended as usize + size; 84 | self.sended.store(after_size as u32, Ordering::Relaxed); 85 | if after_size >= data.len() { break; } 86 | } 87 | // Wait recv 88 | match self.wait_recv() { 89 | Some(r) => { sended = r.0; _recved = r.1; } 90 | None => return false, 91 | } 92 | } 93 | true 94 | } 95 | 96 | fn wait_send(&mut self) -> Option<(u32, u32)> { 97 | let begin = Instant::now(); 98 | loop { 99 | let sended = self.sended.load(Ordering::Relaxed); 100 | let recved = self.recved.load(Ordering::Relaxed); 101 | if sended > recved { return Some((sended, recved)); } 102 | 103 | if begin.elapsed() > SYNC_TIME_OUT { return None; } 104 | } 105 | } 106 | 107 | fn recv(&mut self) -> Frame { 108 | let result = match self.data_ty.load(Ordering::Relaxed) { 109 | FRAME_NONE => Frame::None, 110 | FRAME_PING => Frame::Ping, 111 | FRAME_PONG => Frame::Pong, 112 | FRAME_DATA => { 113 | let data_size = self.data_len.load(Ordering::Relaxed) as usize; 114 | if data_size == 0 { return Frame::None; } 115 | 116 | let mut data: Vec = Vec::with_capacity(data_size); 117 | let mut timeout = false; 118 | loop { 119 | match self.wait_send() { 120 | Some((sended, recved)) => { 121 | // Push data slice 122 | let size = (sended - recved) as usize; 123 | data.extend_from_slice(&self.buf[..size]); 124 | // Update recved 125 | self.recved.store(sended, Ordering::Relaxed); 126 | if sended as usize >= data_size { break; } 127 | } 128 | None => { timeout = true; break; } 129 | } 130 | } 131 | self.sended.store(0, Ordering::Relaxed); 132 | self.recved.store(0, Ordering::Relaxed); 133 | self.data_len.store(0, Ordering::Relaxed); 134 | if timeout { Frame::Timeout } else { Frame::Data(data) } 135 | } 136 | _ => { panic!(); } 137 | }; 138 | self.data_ty.store(FRAME_NONE, Ordering::Relaxed); result 139 | } 140 | } 141 | 142 | struct Communicator { 143 | ch1: Channel, 144 | ch2: Channel, 145 | } 146 | 147 | pub struct ShmAdaptor { 148 | shmem: UnsafeCell, 149 | send_lock: Mutex<()>, 150 | connected: Cell, 151 | client: bool, 152 | } 153 | 154 | impl ShmAdaptor { 155 | const EVT_MASTER: usize = 0; 156 | const EVT_SLAVER: usize = 1; 157 | 158 | #[inline] 159 | fn shmem(&self) -> &mut SharedMem { 160 | unsafe { &mut *self.shmem.get() } 161 | } 162 | 163 | fn send_channel(&self) -> &mut Channel { 164 | let this = self.as_comm(); 165 | if self.client { &mut this.ch2 } else { &mut this.ch1 } 166 | } 167 | 168 | fn recv_channel(&self) -> &mut Channel { 169 | let this = self.as_comm(); 170 | if self.client { &mut this.ch1 } else { &mut this.ch2 } 171 | } 172 | 173 | #[inline] 174 | fn send_eid(&self) -> usize { 175 | if self.client { Self::EVT_MASTER } else { Self::EVT_SLAVER } 176 | } 177 | 178 | #[inline] 179 | fn recv_eid(&self) -> usize { 180 | if self.client { Self::EVT_SLAVER } else { Self::EVT_MASTER } 181 | } 182 | 183 | #[inline] 184 | fn as_comm(&self) -> &'static mut Communicator { 185 | unsafe { transmute(self.shmem().get_ptr()) } 186 | } 187 | 188 | fn send_frame(&self, frame: Frame) -> bool { 189 | let _guard = self.send_lock.lock().unwrap(); 190 | let ch = self.send_channel(); 191 | if !ch.send_type(&frame) { return false; } 192 | 193 | let sid = self.send_eid(); 194 | self.shmem().set(sid, EventState::Signaled); 195 | if let Frame::Data(data) = frame { 196 | return ch.send_data(&data); 197 | } 198 | true 199 | } 200 | 201 | fn new(shmem: SharedMem, client: bool) -> Self { 202 | ShmAdaptor { 203 | shmem: UnsafeCell::new(shmem), 204 | send_lock: Mutex::new(()), 205 | connected: Cell::new(true), 206 | client, 207 | } 208 | } 209 | 210 | pub fn create(path: &str) -> Result { 211 | let size = size_of::(); 212 | let shmem = SharedMemConf::default() 213 | .set_os_path(path).set_size(size) 214 | .add_event(EventType::Auto)? 215 | .add_event(EventType::Auto)? 216 | .create()?; 217 | let this = Self::new(shmem, false); 218 | this.as_comm().ch1.init(); 219 | this.as_comm().ch2.init(); 220 | Ok(this) 221 | } 222 | 223 | pub fn wait(&self, timeout: Option) -> bool { 224 | self.shmem().wait(Self::EVT_MASTER, timeout.unwrap_or(Timeout::Infinite)).is_ok() 225 | } 226 | 227 | pub fn open(path: &str) -> Result { 228 | let mut shmem = SharedMem::open(path)?; 229 | shmem.set(Self::EVT_MASTER, EventState::Signaled); 230 | Ok(Self::new(shmem, true)) 231 | } 232 | } 233 | 234 | unsafe impl Send for ShmAdaptor {} 235 | unsafe impl Sync for ShmAdaptor {} 236 | 237 | impl Adaptor for ShmAdaptor { 238 | fn send(&self, data: Vec) -> bool { 239 | return self.send_frame(Frame::Data(data)); 240 | } 241 | 242 | fn recv(&self) -> Result, RecvError> { 243 | const CELL_TIMEOUT: usize = 100; 244 | let mut ping_time = 0usize; 245 | loop { 246 | let rid = self.recv_eid(); 247 | if let Ok(_) = self.shmem().wait(rid, Timeout::Milli(CELL_TIMEOUT)) { 248 | match self.recv_channel().recv() { 249 | Frame::Data(data) => return Ok(data), 250 | Frame::Ping => { self.send_frame(Frame::Pong); } 251 | Frame::Pong => { if ping_time > 0 { ping_time -= CELL_TIMEOUT; } } 252 | Frame::None | Frame::Timeout => { panic!(""); } 253 | } 254 | } else if ping_time > 200 { 255 | self.connected.set(false); 256 | return Err(RecvError::Disconnect); 257 | } else { 258 | ping_time += CELL_TIMEOUT; 259 | self.send_frame(Frame::Ping); 260 | } 261 | } 262 | } 263 | 264 | fn connected(&self) -> bool { self.connected.get() } 265 | 266 | fn close(&self) { /* TODO: */ } 267 | } 268 | 269 | pub fn create(path: &str) -> Result, SharedMemError> { 270 | Ok(Arc::new(ShmAdaptor::create(path)?)) 271 | } 272 | 273 | pub fn connect(path: &str) -> Result, SharedMemError> { 274 | Ok(Arc::new(ShmAdaptor::open(path)?)) 275 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(unboxed_closures, fn_traits)] 2 | #![allow(unused_must_use)] 3 | 4 | //! `easy-rpc` is a cross-language RPC framework. 5 | //! # Example 6 | //! ``` 7 | //! use std::sync::Arc; 8 | //! use easy_rpc::*; 9 | //! 10 | //! struct ServerService; 11 | //! 12 | //! const MUL: u32 = 1; 13 | //! easy_service! { 14 | //! ServerService(self, _ss, arg, response) 15 | //! 16 | //! StringMethod { 17 | //! "add" => (a: u32, b: u32) { 18 | //! a + b 19 | //! } 20 | //! "print" => (s: String) { 21 | //! println!("{}", s); 22 | //! } 23 | //! } 24 | //! IntegerMethod { 25 | //! MUL => (a: u32, b: u32) { 26 | //! a * b 27 | //! } 28 | //! } 29 | //! } 30 | //! 31 | //! fn main() -> Result<(), Box> { 32 | //! std::thread::spawn(|| { 33 | //! let mut ser = ws::bind("127.0.0.1:3333").unwrap(); 34 | //! let (adaptor, _uri) = ws::accept(&mut ser).unwrap(); 35 | //! Session::new(adaptor, Arc::new(ServerService)).loop_handle(); 36 | //! }); 37 | //! 38 | //! std::thread::sleep_ms(100); 39 | //! let session = Session::new(ws::connect("ws://127.0.0.1:3333")?, Arc::new(EmptyService)); 40 | //! let val: u32 = session.request("add", (1, 2)).into()?; 41 | //! session.notify("print", format!("the result is {}", val)); 42 | //! let val: u32 = session.request(MUL, (2, 3)).into()?; 43 | //! assert_eq!(val, 6); 44 | //! 45 | //! Ok(()) 46 | //! } 47 | //! ``` 48 | 49 | #[macro_use] 50 | extern crate downcast_rs; 51 | extern crate rmp_serde as rmps; 52 | 53 | /// Adaptor of WebSocket 54 | #[cfg(feature = "ws")] 55 | pub mod ws; 56 | /// Adaptor of SharedMemory 57 | #[cfg(all(feature = "shm", not(target_os = "android")))] 58 | pub mod shm; 59 | 60 | #[doc(no_inline)] 61 | pub use serde_bytes::{Bytes, ByteBuf}; 62 | 63 | use std::sync::{ 64 | Arc, RwLock, Mutex, 65 | mpsc::{channel, Sender}, 66 | atomic::{AtomicU32, Ordering}, 67 | }; 68 | use std::fmt::{ 69 | Debug, Display, Formatter, 70 | Result as FmtResult 71 | }; 72 | use std::collections::HashMap; 73 | 74 | use serde::Serialize; 75 | use serde::de::DeserializeOwned; 76 | use rmps::Serializer; 77 | use rmps::decode::Error as DecodeError; 78 | use rmp::{encode, decode}; 79 | use rmpv::{Value, decode::read_value}; 80 | use downcast_rs::DowncastSync; 81 | 82 | const REQUEST: u32 = 0; // Caller->Callee [REQUEST, ID: u32, METHOD: u32, ARGS: Any] 83 | const RESPONSE: u32 = 1; // Callee->Caller [RESPONSE, ID: u32, ERROR: Option, RESULT: Any] 84 | const NOTIFY: u32 = 2; // [NOTIFY, METHOD: u32, ARGS: Any] 85 | 86 | #[derive(Debug)] 87 | pub enum RecvError { 88 | Disconnect, 89 | } 90 | 91 | /// Adaptor of different communicated methods 92 | pub trait Adaptor: DowncastSync { 93 | // Send data 94 | fn send(&self, data: Vec) -> bool; 95 | 96 | // Recv Data, this function maybe blocked 97 | fn recv(&self) -> Result, RecvError>; 98 | 99 | // If the connection still connected 100 | fn connected(&self) -> bool; 101 | 102 | // Close the connection 103 | fn close(&self); 104 | } 105 | impl_downcast!(sync Adaptor); 106 | 107 | #[doc(hidden)] 108 | pub struct RespData(Vec, usize); 109 | 110 | impl RespData { 111 | #[inline] 112 | pub fn into(&self) -> Result { 113 | rmps::from_read_ref(self.as_slice()) 114 | } 115 | 116 | #[inline] 117 | pub fn as_slice(&self) -> &[u8] { &self.0[self.1..] } 118 | } 119 | 120 | pub enum RequestResult { 121 | Data(RespData), 122 | Error(String), 123 | Disconnect, 124 | Decode(RespData), 125 | } 126 | 127 | impl std::error::Error for RequestResult {} 128 | 129 | impl Debug for RequestResult { 130 | fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { 131 | use RequestResult::*; 132 | 133 | match self { 134 | Data(_) => write!(f, ""), 135 | Error(ref s) => write!(f, "Error: {}", s), 136 | Decode(_) => write!(f, "DecodeError"), 137 | Disconnect => write!(f, "Disconnect"), 138 | }; Ok(()) 139 | } 140 | } 141 | 142 | impl Display for RequestResult { 143 | fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { 144 | Debug::fmt(self, f) 145 | } 146 | } 147 | 148 | impl RequestResult { 149 | pub fn into(self) -> Result { 150 | match self { 151 | RequestResult::Data(d) => rmps::from_read_ref(d.as_slice()).map_err(|_| RequestResult::Decode(d)), 152 | else_error => Err(else_error), 153 | } 154 | } 155 | 156 | #[inline] 157 | pub fn intos(self) -> Result { self.into().map_err(|e| format!("{}", e)) } 158 | } 159 | 160 | /// Represent the arguments of a request/notify 161 | pub struct Arg<'a> { 162 | pub method: Method<'a>, 163 | pub bytes: &'a [u8], 164 | pub id: u32, 165 | } 166 | 167 | impl<'a> Arg<'a> { 168 | #[inline] 169 | pub fn into(self) -> Result where T: DeserializeOwned { 170 | rmps::from_read_ref(self.bytes) 171 | } 172 | } 173 | 174 | /// Returner for a request, which can response some data 175 | pub struct Ret<'a, 'b> { 176 | ss: &'a Session, 177 | req_id: &'b mut Option, 178 | } 179 | 180 | impl std::ops::FnOnce<(T, )> for Ret<'_, '_> where T: Serialize { 181 | type Output = (); 182 | 183 | extern "rust-call" fn call_once(self, arg: (T, )) -> Self::Output { 184 | if let Some(req_id) = self.req_id.take() { 185 | self.ss.response(req_id, arg.0); 186 | } 187 | } 188 | } 189 | 190 | impl std::ops::FnOnce<(RequestResult, )> for Ret<'_, '_> { 191 | type Output = (); 192 | 193 | extern "rust-call" fn call_once(self, arg: (RequestResult, )) -> Self::Output { 194 | match arg.0 { 195 | RequestResult::Data(data) => unsafe { self.ret_raw(data.as_slice()) } 196 | RequestResult::Error(err) => { self.error(&err) } _ => {} 197 | } 198 | } 199 | } 200 | 201 | impl<'a, 'b> Ret<'a, 'b> { 202 | pub fn error(self, s: &str) { 203 | if let Some(req_id) = self.req_id.take() { 204 | self.ss.response_error(req_id, s); 205 | } 206 | } 207 | 208 | pub unsafe fn ret_raw(self, msgpack: &[u8]) { 209 | if let Some(req_id) = self.req_id.take() { 210 | let mut resp = self.ss.prepare_response(req_id); 211 | encode::write_nil(&mut resp); 212 | resp.extend_from_slice(msgpack); 213 | self.ss.send_pack(resp); 214 | } 215 | } 216 | 217 | /// Convert to AsyncRet. Be careful the session must be allocated by `Arc` 218 | pub unsafe fn into_async(self) -> Option { 219 | self.req_id.map(|req_id| AsyncRet { ss: self.ss.arc_clone(), req_id }) 220 | } 221 | 222 | /// Distinguish request/notify, return true if the packet is a request 223 | #[inline] 224 | pub fn is_valid(&self) -> bool { return self.req_id.is_some() } 225 | } 226 | 227 | /// Asynchronous returner 228 | pub struct AsyncRet { 229 | ss: Arc, 230 | req_id: u32, 231 | } 232 | 233 | impl AsyncRet { 234 | pub fn error(self, s: &str) { 235 | self.ss.response_error(self.req_id, s); 236 | } 237 | 238 | pub unsafe fn ret_raw(self, msgpack: &[u8]) { 239 | let mut resp = self.ss.prepare_response(self.req_id); 240 | encode::write_nil(&mut resp); 241 | resp.extend_from_slice(msgpack); 242 | self.ss.send_pack(resp); 243 | } 244 | } 245 | 246 | impl std::ops::FnOnce<(T, )> for AsyncRet where T: Serialize { 247 | type Output = (); 248 | 249 | extern "rust-call" fn call_once(self, arg: (T, )) -> Self::Output { 250 | self.ss.response(self.req_id, &arg.0) 251 | } 252 | } 253 | 254 | impl std::ops::FnOnce<(RequestResult, )> for AsyncRet { 255 | type Output = (); 256 | 257 | extern "rust-call" fn call_once(self, arg: (RequestResult, )) -> Self::Output { 258 | match arg.0 { 259 | RequestResult::Data(data) => unsafe { self.ret_raw(data.as_slice()) } 260 | RequestResult::Error(err) => { self.error(&err) } _ => {} 261 | } 262 | } 263 | } 264 | 265 | pub struct HandleError(String); 266 | 267 | impl From for HandleError { 268 | fn from(e: T) -> Self { HandleError(format!("{:#?}", e)) } 269 | } 270 | 271 | /// The method of request/notify, can be an integer or a string 272 | #[derive(Clone, Copy, PartialEq, Eq)] 273 | pub enum Method<'a> { 274 | Int(u32), 275 | Str(&'a str), 276 | } 277 | 278 | impl PartialEq for Method<'_> { 279 | #[inline] 280 | fn eq(&self, other: &u32) -> bool { 281 | match *self { Method::Int(n) => n == *other, _ => false } 282 | } 283 | } 284 | 285 | impl PartialEq for Method<'_> { 286 | #[inline] 287 | fn eq(&self, other: &str) -> bool { 288 | match *self { Method::Str(s) => s == other, _ => false } 289 | } 290 | } 291 | 292 | impl<'a> Method<'a> { 293 | #[inline(always)] 294 | pub fn serialize(&self, w: &mut W) { 295 | match *self { 296 | Method::Int(i) => encode::write_u32(w, i), 297 | Method::Str(s) => encode::write_str(w, s), 298 | }; 299 | } 300 | 301 | #[inline] 302 | pub fn to_str(self) -> Result<&'a str, HandleError> { 303 | match self { 304 | Method::Int(_) => Err(HandleError("Method not match".into())), 305 | Method::Str(s) => Ok(s), 306 | } 307 | } 308 | 309 | #[inline] 310 | pub fn to_int(self) -> Result { 311 | match self { 312 | Method::Int(i) => Ok(i), 313 | Method::Str(_) => Err(HandleError("Method not match".into())), 314 | } 315 | } 316 | } 317 | 318 | /// A sugar for converting integer/string to `Method` 319 | pub trait ToMethod<'a> { 320 | fn to_method(self) -> Method<'a>; 321 | } 322 | 323 | impl ToMethod<'_> for u32 { 324 | #[inline(always)] 325 | fn to_method(self) -> Method<'static> { Method::Int(self) } 326 | } 327 | 328 | impl<'a> ToMethod<'a> for &'a str { 329 | #[inline(always)] 330 | fn to_method(self) -> Method<'a> { Method::Str(self) } 331 | } 332 | 333 | impl<'a> ToMethod<'a> for Method<'a> { 334 | #[inline(always)] 335 | fn to_method(self) -> Method<'a> { self } 336 | } 337 | 338 | /// User defined RPC service, handle the request/notify 339 | pub trait Service: DowncastSync { 340 | fn handle(&self, _ss: &Session, _arg: Arg, _ret: Ret) -> Result<(), HandleError> { 341 | Err(HandleError("No this method".into())) 342 | } 343 | } 344 | impl_downcast!(sync Service); 345 | 346 | /// A [`Service`] implementation for test 347 | pub struct EmptyService; 348 | impl Service for EmptyService {} 349 | 350 | pub type ServiceType = Arc; 351 | 352 | /// Highly abstract communication endpoint 353 | pub struct Session { 354 | sender_table: RwLock>>, 355 | recv_mutex: Mutex<()>, 356 | id_counter: AtomicU32, 357 | pub adaptor: Arc, 358 | pub service: ServiceType, 359 | } 360 | 361 | impl Session { 362 | pub fn new(adaptor: Arc, service: ServiceType) -> Session { 363 | Session { 364 | sender_table: RwLock::new(HashMap::new()), 365 | recv_mutex: Mutex::new(()), 366 | id_counter: AtomicU32::new(1), 367 | adaptor, service, 368 | } 369 | } 370 | 371 | /// Convert `&Session` to `Arc`. Be careful the session must be allocated by `Arc` 372 | pub unsafe fn arc_clone(&self) -> Arc { 373 | let s0 = Arc::from_raw(self as *const Session); 374 | let s1 = s0.clone(); std::mem::forget(s0); s1 375 | } 376 | 377 | #[inline] 378 | fn parse_method<'a>(val: &'a Value) -> Option> { 379 | match val { 380 | Value::Integer(i) => Some(Method::Int(i.as_u64().unwrap() as u32)), 381 | Value::String(s) => Some(Method::Str(s.as_str().unwrap())), 382 | _ => None, 383 | } 384 | } 385 | 386 | /// Receive a packet. 387 | /// This function will always block the current thread if there is no packet available. 388 | pub fn recv_packet(&self) -> Option, RecvError>> { 389 | if let Ok(_) = self.recv_mutex.try_lock() { 390 | Some(self.adaptor.recv()) 391 | } else { None } 392 | } 393 | 394 | /// Handle a packet which received by [`Session::recv_packet`] 395 | pub fn handle_packet(&self, pack: Vec) { 396 | let mut reader = &pack[..]; 397 | let start_ptr = reader.as_ptr() as usize; 398 | let len = decode::read_array_len(&mut reader).unwrap(); 399 | let pack_type: u32 = decode::read_int(&mut reader).unwrap(); 400 | 401 | match pack_type { 402 | REQUEST => { 403 | assert!(len == 4); 404 | let req_id: u32 = decode::read_int(&mut reader).unwrap(); 405 | let method_value = read_value(&mut reader).unwrap(); 406 | let method = Self::parse_method(&method_value).unwrap(); 407 | 408 | let mut req_wrapper = Some(req_id); 409 | let ret = Ret { ss: self, req_id: &mut req_wrapper }; 410 | let arg = Arg { method, id: req_id, bytes: &reader }; 411 | if let Err(e) = self.service.handle(self, arg, ret) { 412 | self.response_error(req_id, e.0); 413 | } else if req_wrapper.is_some() { 414 | // TODO: warning: not response the request 415 | } 416 | } 417 | NOTIFY => { 418 | assert!(len == 3); 419 | let method_value = read_value(&mut reader).unwrap(); 420 | let method = Self::parse_method(&method_value).unwrap(); 421 | let mut req_wrapper = None; 422 | let ret = Ret { ss: self, req_id: &mut req_wrapper }; 423 | let arg = Arg { method, id: 0, bytes: &reader }; 424 | self.service.handle(self, arg, ret); 425 | } 426 | RESPONSE => { 427 | assert!(len == 4); 428 | let req_id: u32 = decode::read_int(&mut reader).unwrap(); 429 | let error = read_value(&mut reader).unwrap(); 430 | if let Some(sender) = self.sender_table.write().unwrap().remove(&req_id) { 431 | sender.send(if error.is_nil() { 432 | let offset = reader.as_ptr() as usize - start_ptr; 433 | RequestResult::Data(RespData(pack, offset)) 434 | } else { 435 | RequestResult::Error(error.as_str().unwrap().into()) 436 | }); 437 | } else { panic!("sender not found"); } 438 | } 439 | _else => { panic!("Invalid PackType"); } 440 | } 441 | } 442 | 443 | /// [`Session::recv_packet`] and then [`Session::handle_packet`] looply util the adaptor disconnect. 444 | pub fn loop_handle(&self) { 445 | loop { 446 | match self.recv_packet() { 447 | Some(Ok(pack)) => self.handle_packet(pack), 448 | Some(Err(RecvError::Disconnect)) => { 449 | self.sender_table.write().unwrap().clear(); 450 | break; 451 | }, 452 | err => { panic!("unexpected error: {:?}", err); } 453 | } 454 | } 455 | } 456 | 457 | fn send_pack(&self, frame: Vec) -> bool { self.adaptor.send(frame) } 458 | 459 | fn next_id(&self) -> u32 { self.id_counter.fetch_add(1, Ordering::SeqCst) } 460 | 461 | fn send_and_wait_response(&self, req_id: u32, pack: Vec) -> RequestResult { 462 | use RecvError::*; 463 | let (sender, recver) = channel::(); 464 | self.sender_table.write().unwrap().insert(req_id, sender); 465 | self.send_pack(pack); 466 | loop { 467 | if let Ok(r) = recver.try_recv() { break r; } 468 | match self.recv_packet() { 469 | None => break recver.recv().unwrap_or(RequestResult::Disconnect), 470 | Some(Ok(pack)) => { self.handle_packet(pack); } 471 | Some(Err(Disconnect)) => break RequestResult::Disconnect, 472 | } 473 | } 474 | } 475 | 476 | fn prepare_request(&self, method: Method) -> (Vec, u32) { 477 | let mut pack: Vec = Vec::with_capacity(0x30); 478 | let req_id = self.next_id(); 479 | encode::write_array_len(&mut pack, 4); 480 | encode::write_u32(&mut pack, REQUEST); 481 | encode::write_u32(&mut pack, req_id); 482 | method.serialize(&mut pack); 483 | (pack, req_id) 484 | } 485 | 486 | fn serialize(arg: &S, w: W) { 487 | if cfg!(feature = "struct_map") { 488 | arg.serialize(&mut Serializer::new(w).with_struct_map()); 489 | } else { 490 | arg.serialize(&mut Serializer::new(w)); 491 | } 492 | } 493 | 494 | /// Do a request. 495 | /// This function will always block the current thread if the other side is not response. 496 | pub fn request<'a>(&self, method: impl ToMethod<'a>, arg: impl Serialize) -> RequestResult { 497 | let (mut pack, req_id) = self.prepare_request(method.to_method()); 498 | Self::serialize(&arg, &mut pack); 499 | self.send_and_wait_response(req_id, pack) 500 | } 501 | 502 | /// Do a notify. 503 | pub fn notify<'a>(&self, method: impl ToMethod<'a>, arg: impl Serialize) -> bool { 504 | let mut pack = self.prepare_notify(method.to_method()); 505 | Self::serialize(&arg, &mut pack); 506 | self.send_pack(pack) 507 | } 508 | 509 | fn response(&self, req_id: u32, arg: impl Serialize) { 510 | let mut pack = self.prepare_response(req_id); 511 | encode::write_nil(&mut pack); 512 | Self::serialize(&arg, &mut pack); 513 | self.send_pack(pack); 514 | } 515 | 516 | fn response_error(&self, req_id: u32, err: impl AsRef) { 517 | let mut pack = self.prepare_response(req_id); 518 | encode::write_str(&mut pack, err.as_ref()); 519 | encode::write_nil(&mut pack); 520 | self.send_pack(pack); 521 | } 522 | 523 | /// Do a request with msgpack bytes. 524 | pub unsafe fn request_transfer<'a>(&self, method: impl ToMethod<'a>, msgpack: &[u8]) -> RequestResult { 525 | let (mut pack, req_id) = self.prepare_request(method.to_method()); 526 | pack.extend_from_slice(msgpack); 527 | self.send_and_wait_response(req_id, pack) 528 | } 529 | 530 | /// Do a notify with msgpack bytes. 531 | pub unsafe fn notify_transfer<'a>(&self, method: impl ToMethod<'a>, msgpack: &[u8]) -> bool { 532 | let mut pack = self.prepare_notify(method.to_method()); 533 | pack.extend_from_slice(msgpack); 534 | self.send_pack(pack) 535 | } 536 | 537 | pub unsafe fn response_transfer<'a>(&self, req_id: u32, msgpack: &[u8]) -> bool { 538 | let mut pack = self.prepare_response(req_id); 539 | encode::write_nil(&mut pack); 540 | pack.extend_from_slice(msgpack); 541 | self.send_pack(pack) 542 | } 543 | 544 | pub unsafe fn response_error_transfer<'a>(&self, req_id: u32, err: &str) -> bool { 545 | let mut pack = self.prepare_response(req_id); 546 | encode::write_str(&mut pack, err); 547 | encode::write_nil(&mut pack); 548 | self.send_pack(pack) 549 | } 550 | 551 | fn prepare_notify(&self, method: Method) -> Vec { 552 | let mut pack: Vec = Vec::new(); 553 | encode::write_array_len(&mut pack, 3); 554 | encode::write_u32(&mut pack, NOTIFY); 555 | method.serialize(&mut pack); 556 | pack 557 | } 558 | 559 | fn prepare_response(&self, req_id: u32) -> Vec { 560 | let mut pack: Vec = Vec::new(); 561 | encode::write_array_len(&mut pack, 4); 562 | encode::write_u32(&mut pack, RESPONSE); 563 | encode::write_u32(&mut pack, req_id); 564 | pack 565 | } 566 | } 567 | 568 | unsafe impl Send for Session {} 569 | unsafe impl Sync for Session {} 570 | 571 | #[macro_export] 572 | macro_rules! easy_handle { 573 | (@expand_args $arg:ident, $($i:ident: $t:ty),+) => { 574 | let ($($i),+): ($($t),+) = $arg.into()?; 575 | }; 576 | (@expand_args $arg:ident,) => {}; 577 | 578 | (@body_option $ret:ident manual $body:block) => { $body }; 579 | (@body_option $ret:ident $body:block) => { $ret($body) }; 580 | 581 | ( 582 | @switch $switch:expr, $arg:ident, $ret:ident, 583 | $($m:tt => ($($argdef:tt)*) $($body_option:ident)? $block:block) * 584 | ) => { 585 | match $switch { 586 | $($m => { 587 | easy_handle!(@expand_args $arg, $($argdef)*); 588 | easy_handle!(@body_option $ret $($body_option)? $block) 589 | })* 590 | _ => { return Err("Unhandled Method".into()); } 591 | } 592 | }; 593 | 594 | ( 595 | $arg:ident, $ret:ident, 596 | IntegerMethod { $($tts_int:tt)* } 597 | $(Str($str_var:ident) => $handle_str:block)? 598 | ) => { 599 | use $crate::Method::*; 600 | #[allow(unreachable_patterns)] 601 | match $arg.method { 602 | Int(i) => easy_handle!(@switch i, $arg, $ret, $($tts_int)*), 603 | $(Str($str_var) => $handle_str,)? 604 | _ => { return Err("Unhandled Method".into()); } 605 | } 606 | }; 607 | 608 | ( 609 | $arg:ident, $ret:ident, 610 | StringMethod { $($tts_str:tt)* } 611 | $(Int($int_var:ident) => $handle_int:block)? 612 | ) => { 613 | use $crate::Method::*; 614 | #[allow(unreachable_patterns)] 615 | match $arg.method { 616 | Str(s) => easy_handle!(@switch s, $arg, $ret, $($tts_str)*), 617 | $(Int($int_var) => $handle_int,)? 618 | _ => { return Err("Unhandled Method".into()); } 619 | } 620 | }; 621 | 622 | ( 623 | $arg:ident, $ret:ident, 624 | StringMethod { $($tts_str:tt)* } 625 | IntegerMethod { $($tts_int:tt)* } 626 | ) => { 627 | use $crate::Method::*; 628 | #[allow(unreachable_patterns)] 629 | match $arg.method { 630 | Str(s) => easy_handle!(@switch s, $arg, $ret, $($tts_str)*), 631 | Int(i) => easy_handle!(@switch i, $arg, $ret, $($tts_int)*), 632 | } 633 | }; 634 | } 635 | 636 | #[macro_export] 637 | macro_rules! easy_service { 638 | ($sv:tt($self_:tt, $ss:ident, $arg:ident, $ret:ident) $($tts:tt)*) => { 639 | impl $crate::Service for $sv { 640 | fn handle(&$self_, $ss: &Session, $arg: Arg, $ret: Ret) -> Result<(), HandleError> { 641 | easy_handle!($arg, $ret, $($tts)*); 642 | Ok(()) 643 | } 644 | } 645 | }; 646 | } -------------------------------------------------------------------------------- /js/msgpack.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.MessagePack=t():e.MessagePack=t()}(this,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";r.r(t);var n=function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,i,o=r.call(e),s=[];try{for(;(void 0===t||t-- >0)&&!(n=o.next()).done;)s.push(n.value)}catch(e){i={error:e}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(i)throw i.error}}return s},i=function(){for(var e=[],t=0;t=55296&&i<=56319&&n65535&&(l-=65536,s.push(l>>>10&1023|55296),l=56320|1023&l),s.push(l)}else s.push(h);s.length-4>=u&&(a+=String.fromCharCode.apply(String,i(s)),s.length=0)}return s.length>0&&(a+=String.fromCharCode.apply(String,i(s))),a}var f=o?new TextDecoder:null;var l=function(e,t){this.type=e,this.data=t};function p(e,t,r){var n=Math.floor(r/4294967296),i=r;e.setUint32(t,n),e.setUint32(t+4,i)}function d(e,t){return 4294967296*e.getInt32(t)+e.getUint32(t+4)}var y=4294967295,w=17179869183;function v(e){var t=e.sec,r=e.nsec;if(t>=0&&r>=0&&t<=w){if(0===r&&t<=y){var n=new Uint8Array(4);return(s=new DataView(n.buffer)).setUint32(0,t),n}var i=t/4294967296,o=4294967295&t;n=new Uint8Array(8);return(s=new DataView(n.buffer)).setUint32(0,r<<2|3&i),s.setUint32(4,o),n}var s;n=new Uint8Array(12);return(s=new DataView(n.buffer)).setUint32(0,r),p(s,4,t),n}function g(e){var t=e.getTime(),r=Math.floor(t/1e3),n=1e6*(t-1e3*r),i=Math.floor(n/1e9);return{sec:r+i,nsec:n-1e9*i}}function b(e){return e instanceof Date?v(g(e)):null}function m(e){var t=new DataView(e.buffer,e.byteOffset,e.byteLength);switch(e.byteLength){case 4:return{sec:t.getUint32(0),nsec:0};case 8:var r=t.getUint32(0);return{sec:4294967296*(3&r)+t.getUint32(4),nsec:r>>>2};case 12:return{sec:d(t,4),nsec:t.getUint32(0)};default:throw new Error("Unrecognized data size for timestamp: "+e.length)}}function U(e){var t=m(e);return new Date(1e3*t.sec+t.nsec/1e6)}var x={type:-1,encode:b,decode:U},S=function(){function e(){this.builtInEncoders=[],this.builtInDecoders=[],this.encoders=[],this.decoders=[],this.register(x)}return e.prototype.register=function(e){var t=e.type,r=e.encode,n=e.decode;if(t>=0)this.encoders[t]=r,this.decoders[t]=n;else{var i=1+t;this.builtInEncoders[i]=r,this.builtInDecoders[i]=n}},e.prototype.tryToEncode=function(e){for(var t=0;t=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},M=100,z=2048,C=function(){function e(e,t,r,n,i){void 0===e&&(e=S.defaultCodec),void 0===t&&(t=M),void 0===r&&(r=z),void 0===n&&(n=!1),void 0===i&&(i=!1),this.extensionCodec=e,this.maxDepth=t,this.initialBufferSize=r,this.sortKeys=n,this.forceFloat32=i,this.pos=0,this.view=new DataView(new ArrayBuffer(this.initialBufferSize)),this.bytes=new Uint8Array(this.view.buffer)}return e.prototype.encode=function(e,t){if(t>this.maxDepth)throw new Error("Too deep objects in depth "+t);null==e?this.encodeNil():"boolean"==typeof e?this.encodeBoolean(e):"number"==typeof e?this.encodeNumber(e):"string"==typeof e?this.encodeString(e):this.encodeObject(e,t)},e.prototype.getUint8Array=function(){return this.bytes.subarray(0,this.pos)},e.prototype.ensureBufferSizeToWrite=function(e){var t=this.pos+e;this.view.byteLength=0?e<128?this.writeU8(e):e<256?(this.writeU8(204),this.writeU8(e)):e<65536?(this.writeU8(205),this.writeU16(e)):e<4294967296?(this.writeU8(206),this.writeU32(e)):(this.writeU8(207),this.writeU64(e)):e>=-32?this.writeU8(224|e+32):e>=-128?(this.writeU8(208),this.writeI8(e)):e>=-32768?(this.writeU8(209),this.writeI16(e)):e>=-2147483648?(this.writeU8(210),this.writeI32(e)):(this.writeU8(211),this.writeI64(e)):this.forceFloat32?(this.writeU8(202),this.writeF32(e)):(this.writeU8(203),this.writeF64(e))},e.prototype.writeStringHeader=function(e){if(e<32)this.writeU8(160+e);else if(e<256)this.writeU8(217),this.writeU8(e);else if(e<65536)this.writeU8(218),this.writeU16(e);else{if(!(e<4294967296))throw new Error("Too long string: "+e+" bytes in UTF-8");this.writeU8(219),this.writeU32(e)}},e.prototype.encodeString=function(e){var t=e.length;if(o&&t>200){var r=s(e);this.ensureBufferSizeToWrite(5+r),this.writeStringHeader(r),h(e,this.bytes,this.pos),this.pos+=r}else{if(A&&t>1024){var n=5+4*t;this.ensureBufferSizeToWrite(n);var i=L(e,this.bytes,this.pos);return void(this.pos+=i)}r=s(e);this.ensureBufferSizeToWrite(5+r),this.writeStringHeader(r),function(e,t,r){for(var n=e.length,i=r,o=0;o>6&31|192;else{if(s>=55296&&s<=56319&&o>12&15|224,t[i++]=s>>6&63|128):(t[i++]=s>>18&7|240,t[i++]=s>>12&63|128,t[i++]=s>>6&63|128)}t[i++]=63&s|128}else t[i++]=s}}(e,this.bytes,this.pos),this.pos+=r}},e.prototype.encodeObject=function(e,t){var r=this.extensionCodec.tryToEncode(e);if(null!=r)this.encodeExtension(r);else if(Array.isArray(e))this.encodeArray(e,t);else if(ArrayBuffer.isView(e))this.encodeBinary(e);else{if("object"!=typeof e)throw new Error("Unrecognized object: "+Object.prototype.toString.apply(e));this.encodeMap(e,t)}},e.prototype.encodeBinary=function(e){var t=e.byteLength;if(t<256)this.writeU8(196),this.writeU8(t);else if(t<65536)this.writeU8(197),this.writeU16(t);else{if(!(t<4294967296))throw new Error("Too large binary: "+t);this.writeU8(198),this.writeU32(t)}var r=E(e);this.writeU8a(r)},e.prototype.encodeArray=function(e,t){var r,n,i=e.length;if(i<16)this.writeU8(144+i);else if(i<65536)this.writeU8(220),this.writeU16(i);else{if(!(i<4294967296))throw new Error("Too large array: "+i);this.writeU8(221),this.writeU32(i)}try{for(var o=k(e),s=o.next();!s.done;s=o.next()){var a=s.value;this.encode(a,t+1)}}catch(e){r={error:e}}finally{try{s&&!s.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}},e.prototype.encodeMap=function(e,t){var r=Object.keys(e);this.sortKeys&&r.sort();var n=r.length;if(n<16)this.writeU8(128+n);else if(n<65536)this.writeU8(222),this.writeU16(n);else{if(!(n<4294967296))throw new Error("Too large map object: "+n);this.writeU8(223),this.writeU32(n)}for(var i=0;i0&&e<=this.maxKeyLength},e.prototype.get=function(e,t,r){var n=this.caches[r-1],i=n.length;e:for(var o=0;o=this.maxLengthPerKey?r[Math.random()*r.length|0]=n:r.push(n)},e.prototype.decode=function(e,t,r){var n=this.get(e,t,r);if(n)return n;var i=c(e,t,r),o=Uint8Array.prototype.slice.call(e,t,t+r);return this.store(o,i),i},e}(),K=function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function s(e){try{h(n.next(e))}catch(e){o(e)}}function a(e){try{h(n.throw(e))}catch(e){o(e)}}function h(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}h((n=n.apply(e,t||[])).next())}))},_=function(e,t){var r,n,i,o,s={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(o){return function(a){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;s;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return s.label++,{value:o[1],done:!1};case 5:s.label++,n=o[1],o=[0];continue;case 7:o=s.ops.pop(),s.trys.pop();continue;default:if(!(i=(i=s.trys).length>0&&i[i.length-1])&&(6===o[0]||2===o[0])){s=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]1||a(e,t)}))})}function a(e,t){try{(r=i[e](t)).value instanceof N?Promise.resolve(r.value.v).then(h,u):c(o[0][2],r)}catch(e){c(o[0][3],e)}var r}function h(e){a("next",e)}function u(e){a("throw",e)}function c(e,t){e(t),o.shift(),o.length&&a(o[0][0],o[0][1])}},H=-1,G=new DataView(new ArrayBuffer(0)),X=new Uint8Array(G.buffer),q=function(){try{G.getInt8(0)}catch(e){return e.constructor}throw new Error("never reached")}(),J=new q("Insufficient data"),Q=4294967295,Y=new O,Z=function(){function e(e,t,r,n,i,o,s){void 0===e&&(e=S.defaultCodec),void 0===t&&(t=Q),void 0===r&&(r=Q),void 0===n&&(n=Q),void 0===i&&(i=Q),void 0===o&&(o=Q),void 0===s&&(s=Y),this.extensionCodec=e,this.maxStrLength=t,this.maxBinLength=r,this.maxArrayLength=n,this.maxMapLength=i,this.maxExtLength=o,this.cachedKeyDecoder=s,this.totalPos=0,this.pos=0,this.view=G,this.bytes=X,this.headByte=H,this.stack=[]}return e.prototype.setBuffer=function(e){this.bytes=E(e),this.view=function(e){if(e instanceof ArrayBuffer)return new DataView(e);var t=E(e);return new DataView(t.buffer,t.byteOffset,t.byteLength)}(this.bytes),this.pos=0},e.prototype.appendBuffer=function(e){if(this.headByte!==H||this.hasRemaining()){var t=this.bytes.subarray(this.pos),r=E(e),n=new Uint8Array(t.length+r.length);n.set(t),n.set(r,t.length),this.setBuffer(n)}else this.setBuffer(e)},e.prototype.hasRemaining=function(e){return void 0===e&&(e=1),this.view.byteLength-this.pos>=e},e.prototype.createNoExtraBytesError=function(e){var t=this.view,r=this.pos;return new RangeError("Extra "+(t.byteLength-r)+" byte(s) found at buffer["+e+"]")},e.prototype.decodeSingleSync=function(){var e=this.decodeSync();if(this.hasRemaining())throw this.createNoExtraBytesError(this.pos);return e},e.prototype.decodeSingleAsync=function(e){var t,r,n,i;return K(this,void 0,void 0,(function(){var o,s,a,h,u,c,f,l;return _(this,(function(p){switch(p.label){case 0:o=!1,p.label=1;case 1:p.trys.push([1,6,7,12]),t=V(e),p.label=2;case 2:return[4,t.next()];case 3:if((r=p.sent()).done)return[3,5];if(a=r.value,o)throw this.createNoExtraBytesError(this.totalPos);this.appendBuffer(a);try{s=this.decodeSync(),o=!0}catch(e){if(!(e instanceof q))throw e}this.totalPos+=this.pos,p.label=4;case 4:return[3,2];case 5:return[3,12];case 6:return h=p.sent(),n={error:h},[3,12];case 7:return p.trys.push([7,,10,11]),r&&!r.done&&(i=t.return)?[4,i.call(t)]:[3,9];case 8:p.sent(),p.label=9;case 9:return[3,11];case 10:if(n)throw n.error;return[7];case 11:return[7];case 12:if(o){if(this.hasRemaining())throw this.createNoExtraBytesError(this.totalPos);return[2,s]}throw c=(u=this).headByte,f=u.pos,l=u.totalPos,new RangeError("Insufficient data in parcing "+j(c)+" at "+l+" ("+f+" in the current buffer)")}}))}))},e.prototype.decodeArrayStream=function(e){return this.decodeMultiAsync(e,!0)},e.prototype.decodeStream=function(e){return this.decodeMultiAsync(e,!1)},e.prototype.decodeMultiAsync=function(e,t){return R(this,arguments,(function(){var r,n,i,o,s,a,h,u,c;return _(this,(function(f){switch(f.label){case 0:r=t,n=-1,f.label=1;case 1:f.trys.push([1,13,14,19]),i=V(e),f.label=2;case 2:return[4,N(i.next())];case 3:if((o=f.sent()).done)return[3,12];if(s=o.value,t&&0===n)throw this.createNoExtraBytesError(this.totalPos);this.appendBuffer(s),r&&(n=this.readArraySize(),r=!1,this.complete()),f.label=4;case 4:f.trys.push([4,9,,10]),f.label=5;case 5:return[4,N(this.decodeSync())];case 6:return[4,f.sent()];case 7:return f.sent(),0==--n?[3,8]:[3,5];case 8:return[3,10];case 9:if(!((a=f.sent())instanceof q))throw a;return[3,10];case 10:this.totalPos+=this.pos,f.label=11;case 11:return[3,2];case 12:return[3,19];case 13:return h=f.sent(),u={error:h},[3,19];case 14:return f.trys.push([14,,17,18]),o&&!o.done&&(c=i.return)?[4,N(c.call(i))]:[3,16];case 15:f.sent(),f.label=16;case 16:return[3,18];case 17:if(u)throw u.error;return[7];case 18:return[7];case 19:return[2]}}))}))},e.prototype.decodeSync=function(){e:for(;;){var e=this.readHeadByte(),t=void 0;if(e>=224)t=e-256;else if(e<192)if(e<128)t=e;else if(e<144){if(0!==(n=e-128)){this.pushMapState(n),this.complete();continue e}t={}}else if(e<160){if(0!==(n=e-144)){this.pushArrayState(n),this.complete();continue e}t=[]}else{var r=e-160;t=this.decodeUtf8String(r,0)}else if(192===e)t=null;else if(194===e)t=!1;else if(195===e)t=!0;else if(202===e)t=this.readF32();else if(203===e)t=this.readF64();else if(204===e)t=this.readU8();else if(205===e)t=this.readU16();else if(206===e)t=this.readU32();else if(207===e)t=this.readU64();else if(208===e)t=this.readI8();else if(209===e)t=this.readI16();else if(210===e)t=this.readI32();else if(211===e)t=this.readI64();else if(217===e){r=this.lookU8();t=this.decodeUtf8String(r,1)}else if(218===e){r=this.lookU16();t=this.decodeUtf8String(r,2)}else if(219===e){r=this.lookU32();t=this.decodeUtf8String(r,4)}else if(220===e){if(0!==(n=this.readU16())){this.pushArrayState(n),this.complete();continue e}t=[]}else if(221===e){if(0!==(n=this.readU32())){this.pushArrayState(n),this.complete();continue e}t=[]}else if(222===e){if(0!==(n=this.readU16())){this.pushMapState(n),this.complete();continue e}t={}}else if(223===e){if(0!==(n=this.readU32())){this.pushMapState(n),this.complete();continue e}t={}}else if(196===e){var n=this.lookU8();t=this.decodeBinary(n,1)}else if(197===e){n=this.lookU16();t=this.decodeBinary(n,2)}else if(198===e){n=this.lookU32();t=this.decodeBinary(n,4)}else if(212===e)t=this.decodeExtension(1,0);else if(213===e)t=this.decodeExtension(2,0);else if(214===e)t=this.decodeExtension(4,0);else if(215===e)t=this.decodeExtension(8,0);else if(216===e)t=this.decodeExtension(16,0);else if(199===e){n=this.lookU8();t=this.decodeExtension(n,1)}else if(200===e){n=this.lookU16();t=this.decodeExtension(n,2)}else{if(201!==e)throw new Error("Unrecognized type byte: "+j(e));n=this.lookU32();t=this.decodeExtension(n,4)}this.complete();for(var i=this.stack;i.length>0;){var o=i[i.length-1];if(0===o.type){if(o.array[o.position]=t,o.position++,o.position!==o.size)continue e;i.pop(),t=o.array}else{if(1===o.type){if(s=void 0,"string"!==(s=typeof t)&&"number"!==s)throw new Error("The type of key must be string or number but "+typeof t);o.key=t,o.type=2;continue e}if(2===o.type){if(o.map[o.key]=t,o.readCount++,o.readCount!==o.size){o.key=null,o.type=1;continue e}i.pop(),t=o.map}}}return t}var s},e.prototype.readHeadByte=function(){return this.headByte===H&&(this.headByte=this.readU8()),this.headByte},e.prototype.complete=function(){this.headByte=H},e.prototype.readArraySize=function(){var e=this.readHeadByte();switch(e){case 220:return this.readU16();case 221:return this.readU32();default:if(e<160)return e-144;throw new Error("Unrecognized array type byte: "+j(e))}},e.prototype.pushMapState=function(e){if(e>this.maxMapLength)throw new Error("Max length exceeded: map length ("+e+") > maxMapLengthLength ("+this.maxMapLength+")");this.stack.push({type:1,size:e,key:null,readCount:0,map:{}})},e.prototype.pushArrayState=function(e){if(e>this.maxArrayLength)throw new Error("Max length exceeded: array length ("+e+") > maxArrayLength ("+this.maxArrayLength+")");this.stack.push({type:0,size:e,array:new Array(e),position:0})},e.prototype.decodeUtf8String=function(e,t){if(e>this.maxStrLength)throw new Error("Max length exceeded: UTF-8 byte length ("+e+") > maxStrLength ("+this.maxStrLength+")");if(this.bytes.byteLength200?function(e,t,r){var n=e.subarray(t,t+r);return f.decode(n)}(this.bytes,n,e):A&&e>1024?I(this.bytes,n,e):c(this.bytes,n,e),this.pos+=t+e,r},e.prototype.stateIsMapKey=function(){return this.stack.length>0&&1===this.stack[this.stack.length-1].type},e.prototype.decodeBinary=function(e,t){if(e>this.maxBinLength)throw new Error("Max length exceeded: bin length ("+e+") > maxBinLength ("+this.maxBinLength+")");if(!this.hasRemaining(e+t))throw J;var r=this.pos+t,n=this.bytes.subarray(r,r+e);return this.pos+=t+e,n},e.prototype.decodeExtension=function(e,t){if(e>this.maxExtLength)throw new Error("Max length exceeded: ext length ("+e+") > maxExtLength ("+this.maxExtLength+")");var r=this.view.getInt8(this.pos+t),n=this.decodeBinary(e,t+1);return this.extensionCodec.decode(n,r)},e.prototype.lookU8=function(){return this.view.getUint8(this.pos)},e.prototype.lookU16=function(){return this.view.getUint16(this.pos)},e.prototype.lookU32=function(){return this.view.getUint32(this.pos)},e.prototype.readU8=function(){var e=this.view.getUint8(this.pos);return this.pos++,e},e.prototype.readI8=function(){var e=this.view.getInt8(this.pos);return this.pos++,e},e.prototype.readU16=function(){var e=this.view.getUint16(this.pos);return this.pos+=2,e},e.prototype.readI16=function(){var e=this.view.getInt16(this.pos);return this.pos+=2,e},e.prototype.readU32=function(){var e=this.view.getUint32(this.pos);return this.pos+=4,e},e.prototype.readI32=function(){var e=this.view.getInt32(this.pos);return this.pos+=4,e},e.prototype.readU64=function(){var e,t,r=(e=this.view,t=this.pos,4294967296*e.getUint32(t)+e.getUint32(t+4));return this.pos+=8,r},e.prototype.readI64=function(){var e=d(this.view,this.pos);return this.pos+=8,e},e.prototype.readF32=function(){var e=this.view.getFloat32(this.pos);return this.pos+=4,e},e.prototype.readF64=function(){var e=this.view.getFloat64(this.pos);return this.pos+=8,e},e}(),$={};function ee(e,t){void 0===t&&(t=$);var r=new Z(t.extensionCodec,t.maxStrLength,t.maxBinLength,t.maxArrayLength,t.maxMapLength,t.maxExtLength);return r.setBuffer(e),r.decodeSingleSync()}var te=function(e,t){var r,n,i,o,s={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(o){return function(a){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;s;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return s.label++,{value:o[1],done:!1};case 5:s.label++,n=o[1],o=[0];continue;case 7:o=s.ops.pop(),s.trys.pop();continue;default:if(!(i=(i=s.trys).length>0&&i[i.length-1])&&(6===o[0]||2===o[0])){s=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]1||a(e,t)}))})}function a(e,t){try{(r=i[e](t)).value instanceof re?Promise.resolve(r.value.v).then(h,u):c(o[0][2],r)}catch(e){c(o[0][3],e)}var r}function h(e){a("next",e)}function u(e){a("throw",e)}function c(e,t){e(t),o.shift(),o.length&&a(o[0][0],o[0][1])}};function ie(e){return null!=e[Symbol.asyncIterator]?e:function(e){return ne(this,arguments,(function(){var t,r,n,i;return te(this,(function(o){switch(o.label){case 0:t=e.getReader(),o.label=1;case 1:o.trys.push([1,,9,10]),o.label=2;case 2:return[4,re(t.read())];case 3:return r=o.sent(),n=r.done,i=r.value,n?[4,re(void 0)]:[3,5];case 4:return[2,o.sent()];case 5:return[4,re(i)];case 6:return[4,o.sent()];case 7:return o.sent(),[3,2];case 8:return[3,10];case 9:return t.releaseLock(),[7];case 10:return[2]}}))}))}(e)}var oe=function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function s(e){try{h(n.next(e))}catch(e){o(e)}}function a(e){try{h(n.throw(e))}catch(e){o(e)}}function h(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}h((n=n.apply(e,t||[])).next())}))},se=function(e,t){var r,n,i,o,s={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(o){return function(a){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;s;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return s.label++,{value:o[1],done:!1};case 5:s.label++,n=o[1],o=[0];continue;case 7:o=s.ops.pop(),s.trys.pop();continue;default:if(!(i=(i=s.trys).length>0&&i[i.length-1])&&(6===o[0]||2===o[0])){s=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]