|
1 | | -use neon::prelude::*; |
2 | | -use once_cell::sync::OnceCell; |
| 1 | +use neon::{prelude::*, types::extract::Error}; |
3 | 2 | use serde::Deserialize; |
4 | | -use tokio::runtime::Runtime; |
5 | 3 |
|
6 | 4 | #[derive(Deserialize)] |
7 | 5 | struct NodeRelease { |
8 | 6 | version: String, |
9 | 7 | date: String, |
10 | 8 | } |
11 | 9 |
|
12 | | -// Return a global tokio runtime or create one if it doesn't exist. |
13 | | -// Throws a JavaScript exception if the `Runtime` fails to create. |
14 | | -fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> { |
15 | | - static RUNTIME: OnceCell<Runtime> = OnceCell::new(); |
16 | | - |
17 | | - RUNTIME.get_or_try_init(|| Runtime::new().or_else(|err| cx.throw_error(err.to_string()))) |
18 | | -} |
19 | | - |
20 | 10 | // Get the version of the currently running node process from [`process.version`](https://nodejs.org/api/process.html#processversion) |
21 | | -fn node_version<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<String> { |
| 11 | +fn node_version(cx: &mut Cx) -> NeonResult<String> { |
22 | 12 | let version = cx |
23 | 13 | .global::<JsObject>("process")? |
24 | 14 | .get::<JsString, _, _>(cx, "version")? |
@@ -46,55 +36,17 @@ async fn fetch_node_release(version: &str) -> Result<Option<NodeRelease>, reqwes |
46 | 36 | Ok(version) |
47 | 37 | } |
48 | 38 |
|
49 | | -// Get the release date of the currently running Node process. |
50 | | -// Returns a `Promise<string>` and executes asynchronously on the `tokio` |
51 | | -// thread pool. |
52 | | -fn node_release_date(mut cx: FunctionContext) -> JsResult<JsPromise> { |
53 | | - let rt = runtime(&mut cx)?; |
54 | | - let version = node_version(&mut cx)?; |
55 | | - let channel = cx.channel(); |
56 | | - |
57 | | - // Create a JavaScript promise and a `deferred` handle for resolving it. |
58 | | - // It is important to be careful not to perform failable actions after |
59 | | - // creating the promise to avoid an unhandled rejection. |
60 | | - let (deferred, promise) = cx.promise(); |
61 | | - |
62 | | - // Spawn an `async` task on the tokio runtime. Only Rust types that are |
63 | | - // `Send` may be moved into this block. `Context` may not be passed and all |
64 | | - // JavaScript values must first be converted to Rust types. |
65 | | - // |
66 | | - // This task will _not_ block the JavaScript main thread. |
67 | | - rt.spawn(async move { |
68 | | - // Inside this block, it is possible to `await` Rust `Future` |
69 | | - let release = fetch_node_release(&version).await; |
70 | | - |
71 | | - // Settle the promise from the result of a closure. JavaScript exceptions |
72 | | - // will be converted to a Promise rejection. |
73 | | - // |
74 | | - // This closure will execute on the JavaScript main thread. It should be |
75 | | - // limited to converting Rust types to JavaScript values. Expensive operations |
76 | | - // should be performed outside of it. |
77 | | - deferred.settle_with(&channel, move |mut cx| { |
78 | | - // Convert a `reqwest::Error` to a JavaScript exception |
79 | | - let release = release.or_else(|err| cx.throw_error(err.to_string()))?; |
80 | | - |
81 | | - match release { |
82 | | - // Resolve the promise with the release date |
83 | | - Some(release) => Ok(cx.string(release.date)), |
84 | | - |
85 | | - // Reject the `Promise` if the version could not be found |
86 | | - None => cx.throw_error(format!("Could not find version: {}", version)), |
87 | | - } |
88 | | - }); |
89 | | - }); |
90 | | - |
91 | | - // Return the promise back to JavaScript |
92 | | - Ok(promise) |
93 | | -} |
| 39 | +#[neon::export(async)] |
| 40 | +fn node_release_date( |
| 41 | + cx: &mut Cx, |
| 42 | +) -> NeonResult<impl Future<Output = Result<String, Error>> + use<>> { |
| 43 | + let version = node_version(cx)?; |
94 | 44 |
|
95 | | -#[neon::main] |
96 | | -fn main(mut cx: ModuleContext) -> NeonResult<()> { |
97 | | - cx.export_function("nodeReleaseDate", node_release_date)?; |
| 45 | + Ok(async move { |
| 46 | + let release = fetch_node_release(&version) |
| 47 | + .await? |
| 48 | + .ok_or_else(|| format!("Could not find version: {version}"))?; |
98 | 49 |
|
99 | | - Ok(()) |
| 50 | + Ok(release.date) |
| 51 | + }) |
100 | 52 | } |
0 commit comments