Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions email_client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
project(email-client)

cmake_minimum_required(VERSION 3.9)

MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
IF(MSVC)
GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
SET(PrecompiledBinary "${CMAKE_CURRENT_BINARY_DIR}/${PrecompiledBasename}.pch")
SET(Sources ${${SourcesVar}})

SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_OUTPUTS "${PrecompiledBinary}")
SET_SOURCE_FILES_PROPERTIES(${Sources}
PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_DEPENDS "${PrecompiledBinary}")
# Add precompiled header to SourcesVar
LIST(APPEND ${SourcesVar} ${PrecompiledSource})
ENDIF(MSVC)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)

ADD_MSVC_PRECOMPILED_HEADER(${PROJECT_NAME} "pch.h" "pch.cpp")

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}\
-Werror\
-Wall\
-Wextra\
-Winit-self\
-Wold-style-cast\
-Woverloaded-virtual\
-Winit-self\
-pedantic-errors\
-Wuninitialized\
-Wuseless-cast\
-Woverloaded-virtual\
-Wnon-virtual-dtor\
-Wconversion\
-Wswitch-default\
-Wtrigraphs\
-Wlogical-op\
-Wfloat-equal\
-Wstrict-overflow=4\
-fsanitize=leak\
-fsanitize=undefined\
-fomit-frame-pointer\
")

add_executable(
${PROJECT_NAME}
src/main.cpp

src/client.cpp
src/email.cpp

src/network/response.cpp
src/network/request.cpp
src/network/client_socket.cpp

src/util/commands.cpp
src/util/user_view.cpp

src/serialisation/serialization.cpp

)

target_link_libraries(${PROJECT_NAME})

target_include_directories(
${PROJECT_NAME}
PUBLIC ${PROJECT_SOURCE_DIR}/include
)
83 changes: 83 additions & 0 deletions email_client/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Протокол для обмена сообщениями в системе "Email server"

## Общие замечания

- тип запроса и статус ответа -- 1 байт (`uint8`)
- все числа в 4 байта -- `uint32` в _little endian_
- все строки в кодировке UTF_8

### Заголовок всех запросов от клиента серверу

- 4 байта -- размер сообщения (без учёта этих 4-х байт)
- 4 байта -- размер адреса
- строка -- адрес отправителя
- 1 байт -- тип запроса

### Заголовок всех запросов от сервера клиентам

- 4 байта -- размер сообщения

### Статус ответа

В каждом ответе сервер присылает 1 байт (`uint8`) -- статус ответа на запрос
Статус 0 -- запрос успешен
Статус не ноль -- что-то пошло не так (см. ниже тело отчёта)

- _только при статусе отличном от 0_
- 4 байта -- размер сообщения об ошибке
- сообщение об ошибке

### 1. A посылает сообщение для B

Запрос:
- заголовок (тип сообщения 0)
- 4 байта -- размер адреса отправителя
- адрес получателя
- 4 байта -- размер адреса получателя
- адрес получателя
- 4 байта -- размер темы письма
- тема письма
- 4 байта -- размер тела письма
- тело письма

Ответ:
- заголовок
- 1 байт -- статус запроса
- _сообщение при статусе != 0_

### 2. A проверяет свои входящие сообщения

Запрос:
- заголовок (тип сообщения 1)

Ответ:
- заголовок
- 1 байт -- статус запроса
- _тело ниже только при статусе 0_
- 4 байта -- количество сообщений (**n**)
- _дальше **n** записей_
- 4 байта -- id письма
- 4 байта -- размер адреса отправителя
- адрес получателя
- 4 байта -- размер темы письма
- тема письма
- _сообщение при статусе != 0_

### 3. A хочет получить сообщение с сервера

Запрос:
- Заголовок (тип сообщения 2)
- 4 байта -- id письма

Ответ:
- 1 байт -- статус запроса
- _тело ниже только при статусе 0_
- 4 байта -- размер адреса отправителя
- адрес получателя
- 4 байта -- размер адреса получателя
- адрес получателя
- 4 байта -- размер темы письма
- тема письма
- 4 байта -- размер тела письма
- тело письма
- _сообщение при статусе != 0_
50 changes: 50 additions & 0 deletions email_client/include/client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include "pch.h"
#include "email.h"
#include "network/response.h"
#include "network/request.h"
#include "network/client_socket.h"
#include "util/commands.h"
#include "util/user_view.h"

namespace email {

using port_t = uint16_t;
using net_address_t = std::string;

class Client {
public:
static const port_t DEFAULT_SERVER_PORT;
static const std::string DEFAULT_SERVER_ADDRESS;

Client(const std::string &host_email, const std::string &server_address, uint16_t port);

static Client from_input();

void run();

void shut_down();

private:

const std::string host_email_;
const std::string server_address_;
const port_t server_port_;
bool is_alive_;
network::ClientSocket socket_;

void process_command(util::ClientCommands::CommandID cmd);

void send_email(const Email &email);

void check_email();

void get_email(uint32_t id);

void print_help();

void process_error_response(const std::shared_ptr<response::Response>& response);
};

} // namespace email
54 changes: 54 additions & 0 deletions email_client/include/email.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once

#include "pch.h"

namespace email {

class Email {
public:

Email() = default;

Email(const Email &other) = default;

Email(const std::string &recipient, const std::string &author,
const std::string &theme, const std::string &body);

Email(Email&& email) noexcept = default;

const std::string &get_author() const;

const std::string &get_recipient() const;

const std::string &get_theme() const;

const std::string &get_body() const;

uint32_t size() const;

private:
std::string author_;
std::string recipient_;
std::string theme_;
std::string body_;
};

class EmailInfo {
public:
EmailInfo() = default;

EmailInfo(uint32_t id, const std::string &author, const std::string &theme);

uint32_t get_id() const;

const std::string &get_author() const;

const std::string &get_theme() const;

private:
uint32_t id_;
std::string author_;
std::string theme_;
};

} // namespace email
47 changes: 47 additions & 0 deletions email_client/include/network/client_socket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include "pch.h"
#include "serialization/serialization.h"
#include "response.h"
#include "request.h"

namespace network {

struct socket_exception : std::exception {
explicit socket_exception(std::string msg = "");

const char *what() const noexcept override;

private:
std::string msg_;
};

class ClientSocket {
public:

ClientSocket(const std::string &server_address, uint16_t port);

~ClientSocket();

void open_connection();

void close_connection();

std::shared_ptr<response::Response> send_request(std::unique_ptr<request::Request> &request);

private:
int descriptor_;
std::string server_address_;
uint16_t port_;

void write_message(const serialization::SerializedMessage &message);

std::unique_ptr<uint8_t[]> receive_message();

uint32_t read_message_size();

void read_to_buffer(uint8_t *buffer, size_t size);

};

} // namespace network
15 changes: 15 additions & 0 deletions email_client/include/network/message.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "pch.h"

namespace network {

class Message {
public:
virtual uint32_t size() const = 0;

virtual ~Message() = default;

};

} // namespace network
67 changes: 67 additions & 0 deletions email_client/include/network/request.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#pragma once

#include "pch.h"
#include "email.h"
#include "network/message.h"

namespace request {

enum RequestType {
SEND_EMAIL = 1,
CHECK_EMAIL = 2,
GET_EMAIL = 3
};

class Request : public network::Message {
protected:
Request(RequestType type, const std::string &author);

public:
uint32_t size() const override;

virtual RequestType get_type() const;

const std::string &get_author() const;

private:
RequestType type_;
const std::string author_;
};

class SendRequest : public Request {
public:
explicit SendRequest(email::Email email);

const email::Email &get_email() const;

RequestType get_type() const override;

uint32_t size() const override;

private:
email::Email email_;
};

class CheckRequest : public Request {
public:
explicit CheckRequest(const std::string &author);

uint32_t size() const override;

};

class GetRequest : public Request {
public:
GetRequest(const std::string &author, uint32_t id);

uint32_t get_id() const;

protected:
uint32_t size() const override;

private:
uint32_t id_;
uint32_t size_;
};

} // namespace request
Loading