1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::any::Any;
use std::borrow::BorrowMut;
use std::sync::Arc;
use std::time::Duration;
use solana_clap_utils::keypair::{DefaultSigner};
use solana_cli_config::{Config, ConfigInput};
use solana_cli_output::display::println_name_value;
use solana_cli_output::OutputFormat;
use solana_client::rpc_client::RpcClient;
use solana_program::pubkey::Pubkey;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel};
use crate::command::{CliConfig, ProcessResult};

pub struct CommonCli {
    cli_config: CliConfig,
    program_id: Pubkey,
}


pub trait Matche {
    fn as_any(&self) -> &dyn Any;
    fn get_config_file(&self) -> &str;
    fn get_owner(&self) -> &str;
}


impl CommonCli {
    pub fn new(program_id: Pubkey) -> CommonCli {
        CommonCli {
            cli_config: CliConfig {
                signers: vec![],
                json_rpc_url: "".to_string(),
                rpc_timeout: Default::default(),
                commitment: Default::default(),
                confirm_transaction_initial_timeout: Default::default(),
                output_format: OutputFormat::Display
            },
            program_id
        }
    }

    pub fn parse_args(
        mut self,
        app: Box<dyn Matche>
    ) -> Self {
        let config_file = app.get_config_file();
        let config = if config_file.is_empty() {
            Config::default()
        } else {
            Config::load(config_file).unwrap_or_default()
        };
        let json_rpc_url = config.json_rpc_url;

        let rpc_timeout = Duration::from_secs(20);

        let commitment = CommitmentConfig {
            commitment: CommitmentLevel::Finalized,
        };

        let confirm_transaction_initial_timeout = Duration::from_secs(10);
        let default_signer_arg_name = "keypair".to_string();
        let (_, default_signer_path) = ConfigInput::compute_keypair_path_setting(
            app.get_owner(),
            &config.keypair_path,
        );
        let default_signer = DefaultSigner::new(default_signer_arg_name, &default_signer_path);
        let mut wallet_manager: Option<Arc<RemoteWalletManager>> = None;
        let k = default_signer.signer_from_path(&Default::default(), &mut wallet_manager);
        self.cli_config.signers = vec![k.unwrap()];
        self.cli_config.json_rpc_url = json_rpc_url;
        self.cli_config.rpc_timeout = rpc_timeout;
        self.cli_config.commitment = commitment;
        self.cli_config.confirm_transaction_initial_timeout = confirm_transaction_initial_timeout;
        self.cli_config.output_format = OutputFormat::Display;
        self
    }

    pub fn process_command(
        mut self,
        process_command: fn(
            config: &mut CliConfig,
            rpc_client: RpcClient,
            app: Box<dyn Matche>,
        ) -> ProcessResult,
        app: Box<dyn Matche>
    ) {
        let rpc_client = RpcClient::new_with_timeouts_and_commitment(
            self.cli_config.json_rpc_url.to_string(),
            self.cli_config.rpc_timeout,
            self.cli_config.commitment,
            self.cli_config.confirm_transaction_initial_timeout,
        );
        let result = process_command(self.cli_config.borrow_mut(), rpc_client, app);
        match result {
            Err(err) => println!("err: {}", err),
            Ok(sig) => println_name_value("", &sig),
        };
    }

    pub fn get_pubkey_for_program_with_seeds(self, seeds: &[&[u8]]) -> (Pubkey, u8) {
        Pubkey::find_program_address(
            seeds,
            &self.program_id,
        )
    }
}