|
1 |
| -#![allow(unused_variables)] |
2 | 1 | extern crate futures;
|
3 | 2 | extern crate tokio;
|
4 | 3 | extern crate xrl;
|
5 | 4 |
|
6 | 5 | use futures::{future, Future, Stream};
|
7 |
| -use xrl::{spawn, Client, Frontend, FrontendBuilder, MeasureWidth, ServerResult, XiNotification}; |
| 6 | +use xrl::*; |
8 | 7 |
|
9 |
| -// Type that represent our client |
| 8 | +// Type that represent a `xi-core` peer. It implements `Frontend`, |
| 9 | +// which means it can handle notifications and requests from |
| 10 | +// `xi-core`. |
| 11 | +#[allow(dead_code)] |
10 | 12 | struct MyFrontend {
|
11 |
| - #[allow(dead_code)] |
| 13 | + // This is not actually used in this example, but if we wanted to |
| 14 | + // our frontend could use a `Client` so that it could send |
| 15 | + // requests and notifications to `xi-core`, instead of just |
| 16 | + // handling incoming messages. |
12 | 17 | client: Client,
|
13 | 18 | }
|
14 | 19 |
|
15 |
| -// Implement how our client handles notifications and requests from the core. |
| 20 | +// Implement how our client handles notifications & requests from the core. |
16 | 21 | impl Frontend for MyFrontend {
|
17 |
| - fn handle_notification(&mut self, notification: XiNotification) -> ServerResult<()> { |
| 22 | + type NotificationResult = Result<(), ()>; |
| 23 | + fn handle_notification(&mut self, notification: XiNotification) -> Self::NotificationResult { |
18 | 24 | use XiNotification::*;
|
19 |
| - |
20 | 25 | match notification {
|
21 | 26 | Update(update) => println!("received `update` from Xi core:\n{:?}", update),
|
22 | 27 | ScrollTo(scroll) => println!("received `scroll_to` from Xi core:\n{:?}", scroll),
|
@@ -50,44 +55,63 @@ impl Frontend for MyFrontend {
|
50 | 55 | println!("received `language_changed` from Xi core:\n{:?}", lang)
|
51 | 56 | }
|
52 | 57 | }
|
53 |
| - Box::new(future::ok(())) |
| 58 | + Ok(()) |
54 | 59 | }
|
55 | 60 |
|
56 |
| - fn handle_measure_width(&mut self, request: MeasureWidth) -> ServerResult<Vec<Vec<f32>>> { |
57 |
| - Box::new(future::ok(Vec::new())) |
| 61 | + type MeasureWidthResult = Result<Vec<Vec<f32>>, ()>; |
| 62 | + // we don't actually use the `request` argument in this example, |
| 63 | + // hence the attribute. |
| 64 | + #[allow(unused_variables)] |
| 65 | + fn handle_measure_width(&mut self, request: MeasureWidth) -> Self::MeasureWidthResult { |
| 66 | + Ok(Vec::new()) |
58 | 67 | }
|
59 | 68 | }
|
60 | 69 |
|
61 | 70 | struct MyFrontendBuilder;
|
62 | 71 |
|
63 |
| -impl FrontendBuilder<MyFrontend> for MyFrontendBuilder { |
64 |
| - fn build(self, client: Client) -> MyFrontend { |
65 |
| - MyFrontend { client: client } |
| 72 | +impl FrontendBuilder for MyFrontendBuilder { |
| 73 | + type Frontend = MyFrontend; |
| 74 | + fn build(self, client: Client) -> Self::Frontend { |
| 75 | + MyFrontend { client } |
66 | 76 | }
|
67 | 77 | }
|
68 | 78 |
|
69 | 79 | fn main() {
|
70 |
| - // spawn Xi core |
71 |
| - let (client, core_stderr) = spawn("xi-core", MyFrontendBuilder {}); |
| 80 | + tokio::run(future::lazy(move || { |
| 81 | + // spawn Xi core |
| 82 | + let (client, core_stderr) = spawn("xi-core", MyFrontendBuilder {}); |
| 83 | + |
| 84 | + // start logging Xi core's stderr |
| 85 | + tokio::spawn( |
| 86 | + core_stderr |
| 87 | + .for_each(|msg| { |
| 88 | + println!("xi-core stderr: {}", msg); |
| 89 | + Ok(()) |
| 90 | + }) |
| 91 | + .map_err(|_| ()), |
| 92 | + ); |
72 | 93 |
|
73 |
| - // All clients must send client_started notification first |
74 |
| - tokio::run(client.client_started(None, None).map_err(|_| ())); |
75 |
| - // start logging Xi core's stderr |
76 |
| - let log_core_errors = core_stderr |
77 |
| - .for_each(|msg| { |
78 |
| - println!("xi-core stderr: {}", msg); |
79 |
| - Ok(()) |
80 |
| - }) |
81 |
| - .map_err(|_| ()); |
82 |
| - ::std::thread::spawn(move || { |
83 |
| - tokio::run(log_core_errors); |
84 |
| - }); |
85 |
| - // Send a request to open a new view, and print the result |
86 |
| - let open_new_view = client |
87 |
| - .new_view(None) |
88 |
| - .map(|view_name| println!("opened new view: {}", view_name)) |
89 |
| - .map_err(|_| ()); |
90 |
| - tokio::run(open_new_view); |
91 |
| - // sleep until xi-requests are received |
92 |
| - ::std::thread::sleep(::std::time::Duration::new(5, 0)); |
| 94 | + let client_clone = client.clone(); |
| 95 | + client |
| 96 | + // Xi core expects the first notification to be |
| 97 | + // "client_started" |
| 98 | + .client_started(None, None) |
| 99 | + .map_err(|e| eprintln!("failed to send \"client_started\": {:?}", e)) |
| 100 | + .and_then(move |_| { |
| 101 | + let client = client_clone.clone(); |
| 102 | + client |
| 103 | + .new_view(None) |
| 104 | + .map(|view_name| println!("opened new view: {}", view_name)) |
| 105 | + .map_err(|e| eprintln!("failed to open a new view: {:?}", e)) |
| 106 | + .and_then(move |_| { |
| 107 | + // Forces to shut down the Xi-RPC |
| 108 | + // endoint. Otherwise, this example would keep |
| 109 | + // running until the xi-core process |
| 110 | + // terminates. |
| 111 | + println!("shutting down"); |
| 112 | + client_clone.shutdown(); |
| 113 | + Ok(()) |
| 114 | + }) |
| 115 | + }) |
| 116 | + })); |
93 | 117 | }
|
0 commit comments