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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (c) 2021 Open Community Project Association https://ocpa.ch
// This software is published under the AGPLv3 license.

//! # User Accounts Module Functions

use state::Storage;
use std::sync::RwLock;
use prost::Message;
use super::rpc::Rpc;

/// include generated protobuf RPC rust definition file
mod proto { include!("../../../libqaul/src/rpc/protobuf_generated/rust/qaul.rpc.user_accounts.rs"); }

/// mutable user account state
static USERACCOUNTS: Storage<RwLock<UserAccounts>> = Storage::new();


/// default user initialization
pub enum MyUserAccountInitialiation {
    /// there was no request sent yet
    Uninitialized,
    /// no user account created yet
    NoDefaultAccount,
    /// user account is initialized
    Initialized,
}

/// user accounts module function handling
pub struct UserAccounts {
    initialiation: MyUserAccountInitialiation,
    my_user_account: Option<proto::MyUserAccount>,
}

impl UserAccounts {
    /// Initialize User Accounts
    pub fn init() {
        // create user accounts state
        let user_accounts = UserAccounts { 
            initialiation: MyUserAccountInitialiation::Uninitialized,
            my_user_account: None,
        };
        USERACCOUNTS.set(RwLock::new(user_accounts));

        // request default user
        Self::request_default_account();
    }

    /// return user id
    pub fn get_user_id() -> Option<Vec<u8>> {
        // get state
        let user_accounts = USERACCOUNTS.get().read().unwrap();

        if let Some(my_user_account) = &user_accounts.my_user_account {
            return Some(my_user_account.id.clone())
        }

        None
    }

    /// CLI command interpretation
    /// 
    /// The CLI commands of user accounts module are processed here
    pub fn cli(command: &str) {
        match command {
            // request default user account
            cmd if cmd.starts_with("default") => {
                Self::request_default_account();
            },
            // create new user account
            cmd if cmd.starts_with("create ") => {
                Self::create_user_account(cmd.strip_prefix("create ").unwrap().to_string());
            },
            // unknown command
            _ => log::error!("unknown account command"),
        }
    }

    /// Create new user account
    fn create_user_account(user_name: String) {
        // create info request message
        let proto_message = proto::UserAccounts {
            message: Some(proto::user_accounts::Message::CreateUserAccount(
                proto::CreateUserAccount {
                    name: user_name,
                }
            )),
        };

        // encode message
        let mut buf = Vec::with_capacity(proto_message.encoded_len());
        proto_message.encode(&mut buf).expect("Vec<u8> provides capacity as needed");

        // send message
        Rpc::send_message(buf, super::rpc::proto::Modules::Useraccounts.into(), "".to_string());
    }

    /// Request default user account
    fn request_default_account() {
        // create info request message
        let proto_message = proto::UserAccounts {
            message: Some(proto::user_accounts::Message::GetDefaultUserAccount(true)),
        };

        // encode message
        let mut buf = Vec::with_capacity(proto_message.encoded_len());
        proto_message.encode(&mut buf).expect("Vec<u8> provides capacity as needed");

        // send message
        Rpc::send_message(buf, super::rpc::proto::Modules::Useraccounts.into(), "".to_string());
    }

    /// Process received RPC message
    /// 
    /// Decodes received protobuf encoded binary RPC message
    /// of the user accounts module.
    pub fn rpc(data: Vec<u8>) {
        match proto::UserAccounts::decode(&data[..]) {
            Ok(user_accounts) => {
                match user_accounts.message {
                    Some(proto::user_accounts::Message::DefaultUserAccount(proto_defaultuseraccount)) => {
                        // get state
                        let mut user_accounts = USERACCOUNTS.get().write().unwrap();

                        // check if default user is set
                        if proto_defaultuseraccount.user_account_exists {
                            if let Some(my_user_account) = proto_defaultuseraccount.my_user_account {
                                // print user account
                                println!("Your user account is:");
                                println!("{}, ID[{}]",my_user_account.name, my_user_account.id_base58);
                                println!("    public key: {}", my_user_account.key_base58);

                                // save it to state
                                user_accounts.my_user_account = Some(my_user_account);
                                user_accounts.initialiation = MyUserAccountInitialiation::Initialized;    
                            }
                            else {
                                log::error!("unexpected message configuration");
                            }
                        }
                        else {
                            // print message to create a new user account
                            println!("No user account created yet");
                            println!("Please create a user account:");
                            println!("");
                            println!("    account create {{Your User Name}}");
                            println!("");

                            // save it to state
                            user_accounts.initialiation = MyUserAccountInitialiation::NoDefaultAccount;
                        }
                    },
                    Some(proto::user_accounts::Message::MyUserAccount(proto_myuseraccount)) => {
                        // get state
                        let mut user_accounts = USERACCOUNTS.get().write().unwrap();

                        // print received user
                        println!("New user account created:");
                        println!("{}, ID[{}]",proto_myuseraccount.name, proto_myuseraccount.id_base58);
                        println!("    public key: {}", proto_myuseraccount.key_base58);

                        // save it to state
                        user_accounts.my_user_account = Some(proto_myuseraccount);
                        user_accounts.initialiation = MyUserAccountInitialiation::Initialized;
                    },
                    _ => {
                        log::error!("unprocessable RPC user accounts message");
                    },
                }    
            },
            Err(error) => {
                log::error!("{:?}", error);
            },
        }
    }
}