terminal-chat

Форк
0
288 строк · 6.9 Кб
1
use std::{
2
  str::FromStr, 
3
  fmt, 
4
  error::Error
5
};
6

7
/*
8
  Сигнал может содержать следующие хедеры
9
  USER:         USERNAME
10
  SERVER:       AUTH_STATUS
11
  USER+SERVER:  WITH_MESSAGE
12
  USER+SERVER:  SIGNAL_TYPE
13
  SERVER:       SERVER_MESSAGE
14
*/
15

16
#[derive(Debug)]
17
pub struct ParseSignalDataError;
18
impl Error for ParseSignalDataError {}
19
impl fmt::Display for ParseSignalDataError {
20
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21
    write!(f, "invalid signal data")
22
  }
23
}
24

25
#[derive(Debug)]
26
pub struct AuthConnectionError;
27
impl Error for AuthConnectionError {}
28
impl fmt::Display for AuthConnectionError {
29
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30
    write!(f, "auth connection error")
31
  }
32
}
33

34
#[derive(Debug)]
35
pub struct IncomingMessageError;
36
impl Error for IncomingMessageError {}
37
impl fmt::Display for IncomingMessageError {
38
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39
    write!(f, "incoming message error")
40
  }
41
}
42

43

44
#[derive(Debug, Clone, Copy)]
45
pub enum SignalType {
46
  Connection,
47
  NewMessage,
48
}
49

50
impl FromStr for SignalType {
51
  type Err = ParseSignalDataError;
52

53
  fn from_str(s: &str) -> Result<Self, Self::Err> {
54
    match s {
55
      "CONNECTION" => Ok(SignalType::Connection),
56
      "NEW_MESSAGE" => Ok(SignalType::NewMessage),
57
      _ => Err(ParseSignalDataError)
58
    }
59
  }
60
}
61

62
impl ToString for SignalType {
63
  fn to_string(&self) -> String {
64
    match self {
65
      SignalType::Connection => "CONNECTION".to_owned(),
66
      SignalType::NewMessage => "NEW_MESSAGE".to_owned(),
67
    }
68
  }
69
}
70

71

72
#[derive(Debug, Clone, Copy)]
73
pub enum AuthStatus {
74
  ACCEPTED,
75
  DENIED
76
}
77

78
impl FromStr for AuthStatus {
79
  type Err = ParseSignalDataError;
80

81
  fn from_str(s: &str) -> Result<Self, Self::Err> {
82
    match s {
83
      "ACCEPTED" => Ok(AuthStatus::ACCEPTED),
84
      "DENIED" => Ok(AuthStatus::DENIED),
85
      _ => Err(ParseSignalDataError)
86
    }
87
  }
88
}
89

90
impl ToString for AuthStatus {
91
  fn to_string(&self) -> String {
92
    match self {
93
      AuthStatus::ACCEPTED => "ACCEPTED".to_owned(),
94
      AuthStatus::DENIED => "DENIED".to_owned()
95
    }
96
  }
97
}
98

99

100
pub enum SignalHeader {
101
  Username(String),
102
  AuthStatus(AuthStatus),
103
  SignalType(SignalType),
104
  WithMessage,
105
  ServerMessage
106
}
107

108
impl FromStr for SignalHeader {
109
  type Err = ParseSignalDataError;
110

111
  fn from_str(s: &str) -> Result<Self, Self::Err> {
112
    let (header, value) = s.split_once(':').unwrap_or((s, s));
113

114
    match header {
115
      "USERNAME" => Ok(SignalHeader::Username(value.trim().to_owned())),
116
      "AUTH_STATUS" => {
117
        match AuthStatus::from_str(value.trim()) {
118
          Ok(v) => return Ok(SignalHeader::AuthStatus(v)),
119
          Err(_) => Err(ParseSignalDataError)
120
        }
121
      },
122
      "SIGNAL_TYPE" => {
123
        match SignalType::from_str(value.trim()) {
124
          Ok(v) => return Ok(SignalHeader::SignalType(v)),
125
          Err(_) => Err(ParseSignalDataError)
126
        }
127
      }
128
      "WITH_MESSAGE" => Ok(SignalHeader::WithMessage),
129
      "SERVER_MESSAGE" => Ok(SignalHeader::ServerMessage),
130
      _ => Err(ParseSignalDataError)
131
    }
132
  }
133
}
134

135
impl ToString for SignalHeader {
136
  fn to_string(&self) -> String {
137
    match self {
138
      SignalHeader::Username(v) => format!("USERNAME: {v}\r\n"),
139
      SignalHeader::AuthStatus(v) => format!("AUTH_STATUS: {}\r\n", v.to_string()),
140
      SignalHeader::SignalType(v) => format!("SIGNAL_TYPE: {}\r\n", v.to_string()),
141
      SignalHeader::WithMessage => "WITH_MESSAGE\r\n".to_owned(),
142
      SignalHeader::ServerMessage => "SERVER_MESSAGE\r\n".to_owned()
143
    }
144
  }
145
}
146

147
#[derive(Debug, Clone)]
148
pub struct SignalData {
149
  pub username: Option<String>,
150
  pub password: Option<String>,
151
  pub key: Option<String>,
152
  pub auth_status: Option<AuthStatus>,
153
  pub signal_type: Option<SignalType>,
154
  pub with_message: bool,
155
  pub message: Option<String>,
156
  pub server_message: bool
157
}
158

159
impl SignalData {
160
  pub fn new(headers: Vec<SignalHeader>, message: Option<&str>) -> SignalData {
161
    let mut data = SignalData {
162
      username: None,
163
      password: None,
164
      key: None,
165
      auth_status: None,
166
      signal_type: None,
167
      with_message: false,
168
      message: None,
169
      server_message: false
170
    };
171

172
    for header in headers {
173
      match header {
174
        SignalHeader::Username(v) => {
175
          data.username = Some(v);
176
        },
177
        SignalHeader::AuthStatus(v) => {
178
          data.auth_status = Some(v);
179
        },
180
        SignalHeader::SignalType(v) => {
181
          data.signal_type = Some(v);
182
        },
183
        SignalHeader::WithMessage => {
184
          data.with_message = true;
185
          data.message = Some(message.unwrap_or("").to_owned());
186
        },
187
        SignalHeader::ServerMessage => {
188
          data.server_message = true;
189
        }
190
      }
191
    }
192

193
    data
194
  }
195
}
196

197
impl FromStr for SignalData {
198
  type Err = ParseSignalDataError;
199

200
  fn from_str(s: &str) -> Result<Self, Self::Err> {
201
    let mut data = SignalData { 
202
      username: None, 
203
      password: None, 
204
      key: None, 
205
      auth_status: None, 
206
      signal_type: None,
207
      with_message: false,
208
      message: None,
209
      server_message: false,
210
    };
211
    let splitted = s.split("\r\n");
212
    for string in splitted {
213
      let header = match SignalHeader::from_str(string) {
214
        Ok(v) => v,
215
        Err(_) => continue
216
      };
217

218
      match header {
219
        SignalHeader::Username(v) => {
220
          data.username = Some(v);
221
        },
222
        SignalHeader::AuthStatus(v) => {
223
          data.auth_status = Some(v);
224
        },
225
        SignalHeader::SignalType(v) => {
226
          data.signal_type = Some(v);
227
        }
228
        SignalHeader::WithMessage => {
229
          data.with_message = true;
230
        },
231
        SignalHeader::ServerMessage => {
232
          data.server_message = true;
233
        }
234
      }
235
    }
236

237
    if data.with_message {
238
      let splitted = s.split_once("\r\n\r\n");
239
      if let Some(v) = splitted {
240
        if v.1.ends_with("\r\n\r\n") {
241
          let string = v.1.to_owned();
242
          data.message = Some(string[..string.len() - 4].to_owned());
243
        }
244
        else {
245
          data.message = Some(v.1.to_owned());
246
        }
247
      }
248
      else {
249
        return Err(ParseSignalDataError);
250
      }
251
    }
252

253
    if let None = data.signal_type {
254
      return Err(ParseSignalDataError)
255
    }
256

257
    Ok(data)
258
  }
259
}
260

261
impl ToString for SignalData {
262
  fn to_string(&self) -> String {
263
    let mut res_str = String::new();
264

265
    if let Some(v) = &self.username {
266
      res_str.push_str(&SignalHeader::Username(v.to_owned()).to_string());
267
    }
268
    if let Some(v) = &self.auth_status {
269
      res_str.push_str(&SignalHeader::AuthStatus(v.clone()).to_string());
270
    }
271
    if let Some(v) = &self.signal_type {
272
      res_str.push_str(&SignalHeader::SignalType(v.clone()).to_string());
273
    }
274
    if self.server_message {
275
      res_str.push_str(&SignalHeader::ServerMessage.to_string());
276
    }
277
    if self.with_message {
278
      if let Some(v) = &self.message {
279
        res_str.push_str(&SignalHeader::WithMessage.to_string());
280
        res_str.push_str("\r\n");
281
        res_str.push_str(&v);
282
      }
283
    }
284
    res_str.push_str("\r\n\r\n");
285

286
    res_str
287
  }
288
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.