aboutsummaryrefslogtreecommitdiff
path: root/src/client/mod.rs
blob: 4ab06013e5aeda55ee87dc3630cf16cf89228fa6 (plain)
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
//use std::io::BufWriter;
use std::result::Result;
use std::vec::Vec;

use tokio::net::TcpStream;
use tokio::prelude::*;

use tokio_util::codec::{Framed};
use futures_util::stream::StreamExt;
use futures::SinkExt;

use crate::protocol::frame::QuasselCodec;

use failure::Error;

extern crate log;
// use log::{info, warn, debug};

pub struct Client {
    stream: Framed<TcpStream, QuasselCodec>,
    pub tls: bool,
    pub compression: bool,
}

impl Client {
    pub async fn run(&mut self) {
        // TODO while endlessly loops over same stream element
        while let Some(msg) = self.stream.next().await {
            println!("bing");
            let msg = msg.unwrap();
            handle_login_message(self, &msg).await.unwrap();
        };
     }

    pub async fn connect(address: &'static str, port: u64, tls: bool, compression: bool) -> Result<Client, Error> {
        use crate::protocol::primitive::deserialize::Deserialize;
        use crate::protocol::message::ConnAck;
        use crate::protocol::primitive::{StringList};
        use crate::protocol::message::ClientInit;
        use crate::protocol::message::handshake::HandshakeSerialize;

        let mut s = TcpStream::connect(format!("{}:{}", address, port)).await?;

        // Set Features
        let mut init: Vec<u8> = vec![];
        let mut handshake: u32 = 0x42b33f00;
        if tls {
            handshake |= 0x01;
        }
        if compression {
            handshake |= 0x02;
        }
        let mut proto: u32 = 0x00000002;
        let fin: u32 = 0x80000000;
        proto |= fin;
        init.extend(handshake.to_be_bytes().iter());
        init.extend(proto.to_be_bytes().iter());
        s.write(&init).await?;


        let mut buf = [0; 4];
        s.read(&mut buf).await?;
        let (_, val) = ConnAck::parse(&buf).unwrap();
        println!("Received: {:?}", val);

        let codec = QuasselCodec::builder()
            .compression(compression)
            .new_codec();
        let stream = Framed::new(s, codec);

        let mut client = Client {
            stream: stream,
            tls: tls,
            compression: compression,
        };

        let mut features = StringList::new();
        features.push("SynchronizedMarkerLine".to_string());
        features.push("Authenticators".to_string());
        features.push("ExtendedFeatures".to_string());
        let client_init = ClientInit {
            client_version:String::from("Rust 0.0.0"),
            client_date: String::from("1579009211"),
            feature_list: features,
            client_features: 0x00008000,
        };

        client.stream.send(client_init.serialize()?).await?;

        return Ok(client);
    }
}

pub async fn handle_login_message(client: &mut Client, buf: &[u8]) -> Result<(), Error> {
    use crate::protocol::message::ClientLogin;
    use crate::protocol::message::handshake::{HandshakeSerialize, HandshakeDeserialize, VariantMap};
    use crate::protocol::error::ProtocolError;
    use crate::util::get_msg_type;

    let (_, res) = VariantMap::parse(buf)?;
    println!("res {:?}", res);
    let msgtype = get_msg_type(&res["MsgType"])?;
    match msgtype {
        "ClientInitAck" => {
            let login = ClientLogin {user: "audron".to_string(), password: "audron".to_string()};
            client.stream.send(login.serialize()?).await?;
        },
        "ClientInitReject" => { println!("init failed: {:?}", res) },
        "ClientLoginAck" => { println!("login done: {:?}", res) },
        "ClientLoginReject" => { println!("login failed: {:?}", res)},
        _ => bail!(ProtocolError::WrongMsgType)
    }
    return Ok(());
}