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
use crate::Error;
use crate::Webtile;
use serde_json::json;

impl Webtile {
    /// Login to the game, using a username and password. It returns a vector
    /// of all playable game IDs.
    ///
    /// # Arguments
    ///
    /// * `username` - A string slice of the user's username.
    /// * `password` - A string slice of the user's password.
    ///
    /// # Example
    ///
    /// ```no_run
    /// // Login under the user "Username", with a password of "Password"
    /// webtile.login_with_credentials("Username", "Password")?;
    /// ```
    pub fn login_with_credentials(
        &mut self,
        username: &str,
        password: &str,
    ) -> Result<Vec<String>, Error> {
        self.write_json(json!({
            "msg": "login",
            "username": username,
            "password": password,
        }))?;

        self.read_until("login_success", None, None)?;

        self.write_json(json!({
            "msg": "go_lobby"
        }))?;
        self.read_until("go_lobby", None, None)?;

        Ok(self.get_playable_games())
    }

    /// Login to the game, using a cookie. It returns a vector of all playable
    /// game IDs.
    ///
    /// # Arguments
    ///
    /// * `cookie` - A string slice of the user's cookie (received previously).
    ///
    /// # Example
    ///
    /// ```no_run
    /// // Login under the user "Username", with a cookie
    /// webtile.login_with_cookie("Username%123456789123456789123456789")?;
    /// ```
    pub fn login_with_cookie(&mut self, cookie: &str) -> Result<Vec<String>, Error> {
        self.write_json(json!({"msg": "token_login", "cookie": cookie}))?;

        self.read_until("login_success", None, None)?;

        self.write_json(json!({
            "msg": "go_lobby"
        }))?;
        self.read_until("go_lobby", None, None)?;

        Ok(self.get_playable_games())
    }

    /// Request a cookie from the DCSS Webtile.
    ///
    /// # Example
    ///
    /// ```no_run
    /// webtile.request_cookie()?;
    /// ```
    pub fn request_cookie(&mut self) -> Result<String, Error> {
        self.write_json(json!({"msg": "set_login_cookie"}))?;

        self.read_until("login_cookie", None, None)?;

        for message in self.read_only_messages() {
            let message_obj = message.as_object().unwrap();
            if message_obj["msg"] == "login_cookie" {
                return Ok(message_obj["cookie"].as_str().unwrap().to_owned());
            }
        }

        unreachable!()
    }

    /// Get the RC file content for a specific game ID.
    ///
    /// # Arguments
    ///
    /// * `game_id` - A string slice of the game's ID.
    ///
    /// # Example
    ///
    /// ```no_run
    /// webtile.get_rc_file("dcss-web-trunk")?;
    /// ```
    pub fn get_rc_file(&mut self, game_id: &str) -> Result<String, Error> {
        self.write_json(json!({"msg": "get_rc", "game_id": game_id}))?;

        self.read_until("rcfile_contents", None, None)?;

        for message in self.read_only_messages() {
            let message_obj = message.as_object().unwrap();
            if message_obj["msg"] == "rcfile_contents" {
                return Ok(message_obj["contents"].as_str().unwrap().to_owned());
            }
        }

        unreachable!()
    }

    /// Set the RC file content of a specific game ID.
    ///
    /// # Arguments
    ///
    /// * `game_id` - A string slice of the game's ID.
    /// * `content` - A string slice of the content to write to the RC file.
    ///
    /// # Example
    ///
    /// ```no_run
    /// webtile.set_rc_file("dcss-web-trunk", "show_more = false\nrest_delay = -1")?;
    /// ```
    pub fn set_rc_file(&mut self, game_id: &str, content: &str) -> Result<(), Error> {
        self.write_json(json!({"msg": "set_rc", "game_id": game_id, "contents": content}))?;

        Ok(())
    }

    /// Process the data received when successfully logging in, to extract the playable games
    fn get_playable_games(&self) -> Vec<String> {
        for message in self.read_only_messages() {
            let message_obj = message.as_object().unwrap();
            if message_obj["msg"] == "set_game_links" {
                return process_playable_game(message_obj["content"].as_str().unwrap());
            }
        }

        unreachable!()
    }
}

/// Process the data received when successfully logging in, to extract the playable games
fn process_playable_game(game_list_html: &str) -> Vec<String> {
    let mut game_list_vec = game_list_html
        .split('#')
        .map(|x| x.split('\"').next().unwrap_or("").to_owned())
        .map(|x| x[5..x.len()].to_owned())
        .collect::<Vec<String>>();

    game_list_vec.remove(0);

    game_list_vec
}