gear_node_wrapper/
node.rs

1// This file is part of Gear.
2//
3// Copyright (C) 2024-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Gear protocol node wrapper
20use crate::{utils, Log, NodeInstance};
21use anyhow::Result;
22use std::{
23    env,
24    path::Path,
25    process::{Command, Stdio},
26};
27
28const GEAR_BINARY: &str = "gear";
29const DEFAULT_ARGS: [&str; 4] = ["--dev", "--tmp", "--no-hardware-benchmarks", "--rpc-port"];
30
31/// Gear protocol node wrapper
32pub struct Node {
33    /// Node command
34    command: Command,
35    /// The rpc port of the node if any
36    port: Option<u16>,
37    /// How many logs should the log holder stores
38    logs: Option<usize>,
39}
40
41impl Node {
42    /// Create a new from gear command that found
43    /// in the current system.
44    pub fn new() -> Result<Self> {
45        Self::from_path(which::which(GEAR_BINARY)?)
46    }
47
48    /// Create a new node from path
49    pub fn from_path(path: impl AsRef<Path>) -> Result<Self> {
50        Ok(Self {
51            command: Command::new(path.as_ref()),
52            port: None,
53            logs: None,
54        })
55    }
56
57    /// Append argument to the node
58    ///
59    /// see also [`Node::args`]
60    pub fn arg(&mut self, arg: &str) -> &mut Self {
61        self.command.arg(arg);
62        self
63    }
64
65    /// Append arguments to the node
66    ///
67    /// NOTE: argument `--dev` or `--chain=vara-dev` is managed by [`Node::chain`]
68    /// and could not be removed, if you are about to run a production node, please
69    /// run the node binary directly.
70    pub fn args(&mut self, args: &[&str]) -> &mut Self {
71        self.command.args(args);
72        self
73    }
74
75    /// Sets the rpc port and returns self.
76    pub fn rpc_port(&mut self, port: u16) -> &mut Self {
77        self.port = Some(port);
78        self
79    }
80
81    /// The log holder stores 256 lines of matched logs
82    /// by default, here in this function we receive a limit
83    /// of the logs and resize the logger on spawning.
84    pub fn logs(&mut self, limit: usize) -> &mut Self {
85        self.logs = Some(limit);
86        self
87    }
88
89    /// Spawn the node
90    pub fn spawn(&mut self) -> Result<NodeInstance> {
91        let port = self.port.unwrap_or(utils::pick()).to_string();
92        let mut args = DEFAULT_ARGS.to_vec();
93        args.push(&port);
94
95        let mut process = self
96            .command
97            .env(
98                "RUST_LOG",
99                env::var("RUST_LOG").unwrap_or_else(|_| "".into()),
100            )
101            .args(args)
102            .stderr(Stdio::piped())
103            .stdout(Stdio::piped())
104            .spawn()?;
105
106        let address = format!("{}:{port}", utils::LOCALHOST).parse()?;
107        let mut log = Log::new(self.logs);
108        log.spawn(&mut process)?;
109        Ok(NodeInstance {
110            address,
111            log,
112            process,
113        })
114    }
115}