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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Ignoring are files
.out
.nfile

# Ignoring directory
.vscode
Expand Down
21 changes: 14 additions & 7 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
[submodule "extern/binacpp"]
path = extern/binacpp
url = https://github.com/binance-exchange/binacpp.git
[submodule "extern/libpqxx"]
path = extern/libpqxx
[submodule "_deps/cpp-httplib"]
path = _deps/cpp-httplib
url = https://github.com/yhirose/cpp-httplib.git
branch = master
[submodule "_deps/binacpp"]
path = _deps/binacpp
url = https://github.com/lpdgrl/binacpp.git
branch = master
[submodule "_deps/libpqxx"]
path = _deps/libpqxx
url = https://github.com/jtv/libpqxx.git
[submodule "extern/flatbuffers"]
path = extern/flatbuffers
branch = master
[submodule "_deps/flatbuffers"]
path = _deps/flatbuffers
url = https://github.com/google/flatbuffers.git
branch = master
63 changes: 37 additions & 26 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
cmake_minimum_required(VERSION 3.10)
project (fhc)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(BINACPP_DIR extern/binacpp)
set(LIBPQXX_DIR extern/libpqxx)
set(FLATBUFFERS_DIR extern/flatbuffers)

set(BINACPP_DIR _deps/binacpp)
set(LIBPQXX_DIR _deps/libpqxx)
set(FLATBUFFERS_DIR _deps/flatbuffers)
set(CPP_HTTPLIB_DIR _deps/cpp-httplib)

set(FHC_HEADERS_DIR include)
set(FHC_CPP_DIR src)

# set(FHC_CPP
# ${FHC_CPP_DIR}/main.cpp
# )

set(FHC_SOURCE_DIR src)
set(EXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/examples)
# Add binacpp
add_subdirectory(${BINACPP_DIR})

Expand All @@ -25,6 +21,11 @@ add_subdirectory(${LIBPQXX_DIR})
# Add flattbuffers
add_subdirectory(${FLATBUFFERS_DIR})

# Add cpp-httplib
add_subdirectory(${CPP_HTTPLIB_DIR})

add_subdirectory(${EXAMPLES_DIR})

# Generate flatbuffers files
set(FLATC ${FLATBUFFERS_DIR}/flatc)
set(SCHEMA ${CMAKE_CURRENT_SOURCE_DIR}/schemas/klines.fbs)
Expand All @@ -33,32 +34,42 @@ set(GENERATED ${CMAKE_CURRENT_SOURCE_DIR}/include/flatbuffers/klines_generated.h
add_custom_command(
OUTPUT ${GENERATED}
COMMAND ${FLATC} --cpp -o ${CMAKE_CURRENT_SOURCE_DIR}/include/flatbuffers/ ${SCHEMA}
DEPENDS ${SCHEMA}
DEPENDS ${SCHEMA} flatc
COMMENT "Generating FlatBuffers code from ${SCHEMA}"
)

add_custom_target(generate_flatbuffers DEPENDS ${GENERATED})

# Paths to include
include_directories(
${CMAKE_SOURCE_DIR}/extern/binacpp/src
FHC_HEADERS_DIR
)

# Target executable file
add_executable(fhc
${FHC_CPP_DIR}/main.cpp
${FHC_CPP_DIR}/server/server.cpp
${FHC_CPP_DIR}/server/request_handler.cpp
${FHC_CPP_DIR}/base/database.cpp
${FHC_CPP_DIR}/base/pqxx_adapter.cpp
${FHC_CPP_DIR}/base/binance_client.cpp
add_library(fhc STATIC
${FHC_SOURCE_DIR}/server/server.cpp
${FHC_SOURCE_DIR}/server/request_handler.cpp
${FHC_SOURCE_DIR}/server/utils.cpp
${FHC_SOURCE_DIR}/server/httplib_adapter.cpp
${FHC_SOURCE_DIR}/base/database.cpp
${FHC_SOURCE_DIR}/base/pqxx_adapter.cpp
${FHC_SOURCE_DIR}/base/binance_client.cpp
${FHC_SOURCE_DIR}/base/sql_loader.cpp
)

add_dependencies(fhc generate_flatbuffers)

target_link_libraries(fhc PRIVATE
target_include_directories(fhc PUBLIC
${BINACPP_DIR}/src
${FHC_HEADERS_DIR}
)

target_link_libraries(fhc PUBLIC
binacpp
pqxx
flatbuffers
httplib
)

target_compile_definitions(fhc PRIVATE
CMAKE_CONFIG_PATH="${CMAKE_SOURCE_DIR}/config/"
)

target_compile_definitions(fhc PRIVATE
CMAKE_SQL_PATH="${CMAKE_SOURCE_DIR}/sql/"
)
100 changes: 100 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Binance historical storage
## Цель проекта
Предпологается, что будет использоваться как API для построения сервисов связанных с выводом информации о криптовалюте (пока только добавлены свечи BTCUSDT).

## Зависимости от third-party
В качестве хранилища данных используется Postgres.

Библиотека Libpqxx используется для взаимодействия с Postgres.

Библиотека flatbuffers используется для zero-copy сериализации данных.

Библиотека http-lib используется для сетевого взаимодействия. В будущем добавлю поддержку boost::beast.

Библиотека binacpp используется для получения данных с биржи Binance. Ее пришлось форкнуть, так как нужно было добавить поддержку api v3 from Binance и CMake сборку.

Все используемые библиотеки затянуты в проект при помощи git submodule.

## Как собрать проект?
Для сборки проекта используется CMake и генератор Ninja. А так же должен быть установлен curl и docker-compose в системе. Проект собирается как STATIC библиотека.

Файл конфигурации для запуска через docker compose находится в корне репозитория. Он подтягивает образ Postgres и adminer (web-морда для Postgres).

Например, чтобы установить curl в Arch Linux, введите команду в терминале:
```shell
pacman -Sy curl docker-composes
```

Запуск рабочего окружения в docker-compose в корне репозитория:
```shell
sudo docker-compose up -d
```

Клонируем репозиторий:
```shell
git clone https://github.com/lpdgrl/FHC.git
```

Подтягиваем зависимости:
```shell
git submodule update --init --recursive
```

Выполняем сборку в корне репозитория:
```shell
mkdir build && cd build
cmake .. -G Ninja
cmake --build .
```

В папке examples находится http-пример для запуска.
Перед первым запуском нужно подготовить конфигурацию в конфиг-файле (.nfile) в директории config. С репозиторием поставляется шаблонный конфиг-файл .nfile-template и для быстрого старта
вы можете его переименовать в .nfile

```shell
mv .nfile-template .nfile
```

Структура конфиг-файла простая:
```shell
DB_HOST=localhost # хост базы данных Postgres
DB_NAME=postgres # имя базы данных
DB_USER=postgres # имя пользователя базы данных
DB_PASSWORD=postgres # пароль базы данных
HTTP_HOST=0.0.0.0 # ip-address http-сервера
HTTP_PORT=8000 # порт http-сервера
```

Теперь все готово, и чтобы запустить http-пример, введите в терминал:
```shell
{подставить свой путь}/build/examples/http_example
```
или, если находитесь в ./build/examples/

```shell
./http-example
```

## Как использовать?
При первоначальном запуске, база данных будет заполняться свечами BTCUSDT с захардкоженной датой 2025-08-01 по текущую дату. Планирую в будущем, добавить возможность чтобы заполнять базу данных с произвольной даты.

В строке браузера введите:
```shell
http://localhost:8000/
```
и вам отобразится веб-страница с выбором дат для получения flatbuffer со свечами по BTCUSDT за выбранный период. Для проверки, что массив байтов пришел, необходимо открыть в браузере консоль из инструментов разработчика и увидите количество переданных байтов и массив сырых байтов.

Чтобы получить обновления по свечам (пока только BTCUSDT) введите в браузере:
```shell
http://localhost:8000/api/update
```
После заполнения базы данных новыми данными на странице отобразится количество добавленных свечей в базу данных либо, что данные в базе данных на текущее время актуальны.

## Какой функционал реализован?
SQL Loader для загрузки sql-файлов и подстановка в них параметров при помощи механизма libpqxx.

Передача произвольного GET-обработчика внутрь httplib. Это подробно показано в примере examples\http-example.

Получение и обновление klines по одной криптовалюте.

[TODO проекта](TODO.MD)
24 changes: 24 additions & 0 deletions TODO.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## TODO:
* [x] 1. Сделать конфиги через .envfile окружение или подобное. Сделать файл .envtemplate

* [x] 2. http запросы (userver). Запросы update и klines.

* [ ] 3. Миграционный скрипт (ранбук на первый запуск)

* [x] 4. Хранимые процедуры или sql файл.

* [x] 5. Оформить репо (readme, examples)

* [x] 6. Форкнуть binacpp

* [ ] 7. Выгрузить свечи BTCUSDT, ETHUSDT, SOLUSDT

* [ ] 8. Выгрузить price по BTC, ETH, SOL

* [ ] 9. Сделать docker-образ с приложением

* [ ] 10. Постоянное обновление данных

* [ ] 11. Прикрутить фронт с flattbuffers

* [ ] 12. Таблица для хранения symbol криптовалюты которую нужно выгружать\обновлять
1 change: 1 addition & 0 deletions _deps/binacpp
Submodule binacpp added at 69a452
1 change: 1 addition & 0 deletions _deps/cpp-httplib
Submodule cpp-httplib added at 27ee11
1 change: 1 addition & 0 deletions _deps/flatbuffers
Submodule flatbuffers added at ac8b12
6 changes: 6 additions & 0 deletions config/.nfile-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DB_HOST=localhost
DB_NAME=postgres
DB_USER=postgres
DB_PASSWORD=postgres
HTTP_HOST=0.0.0.0
HTTP_PORT=8000
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ services:
shm_size: 128mb
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: kis123Oits
POSTGRES_DB: fhc
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- "5432:5432"

Expand Down
9 changes: 9 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Пример CMakeLists.txt в examples/example1/
add_executable(http-example http_example.cpp)


target_link_libraries(http-example PRIVATE fhc)

target_compile_definitions(http-example PRIVATE
CMAKE_PATH_TO_WEB_FILES="${CMAKE_SOURCE_DIR}/examples/web/"
)
56 changes: 56 additions & 0 deletions examples/http_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "../include/server/server.hpp"

#include <iostream>

void RunServer();

int main(int argc, const char** argv) {
RunServer();

return EXIT_SUCCESS;
}

void RunServer() {
using namespace fhc;
server::Server server;

auto api_klines = [&](const std::unordered_map<std::string, std::string>& params, auto write) {
std::string start_date;
std::string end_date;

if (auto it_find_start_time = params.find("StartTime"); it_find_start_time != params.end()) {
start_date = it_find_start_time->second;
}

if (auto it_find_end_time = params.find("EndTime"); it_find_end_time != params.end()) {
end_date = it_find_end_time->second;
}

if (start_date.empty() || end_date.empty()) {
std::cerr << "StartTime or EndTime is empty!" << std::endl;
}

flatbuffers::FlatBufferBuilder builder = server.GetKlinesFromStorage(start_date, end_date);

auto buf = std::make_shared<std::vector<uint8_t>>(
builder.GetBufferPointer(),
builder.GetBufferPointer() + builder.GetSize()
);

write(reinterpret_cast<const char*>(buf->data()), buf->size());
};
server.SetHandler("/api/klines", {server::HTTP_METHOD::GET, api_klines, "application/octet-stream"});

auto api_klines_update = [&](const std::unordered_map<std::string, std::string>& params, auto write) {
std::string result = server.UpdateKlinesInStorage();

write(reinterpret_cast<const char*>(result.data()), result.size());
};

server.SetHandler("/api/update", {server::HTTP_METHOD::GET, api_klines_update, "text/plain"});

server.Init();
server.SetMountPoint("/", CMAKE_PATH_TO_WEB_FILES);
std::cout << "Start server!" << std::endl;
server.Run();
}
35 changes: 35 additions & 0 deletions examples/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Klines</title>
</head>
<body>

<h2>FlatBuffers Raw Test</h2>
<div>
Start Date: <input type="date" id="StartTime" value="date">
End Date: <input type="date" id="EndTime" value="date">
<button onclick="testKlines()">Test</button>
</div>

<script>
async function testKlines() {
const start = document.getElementById("StartTime").value;
const end = document.getElementById("EndTime").value;

try {
const res = await fetch(`/api/klines?StartTime=${encodeURIComponent(start)}&EndTime=${encodeURIComponent(end)}`);
const arrayBuffer = await res.arrayBuffer();
const bytes = new Uint8Array(arrayBuffer);

console.log("Raw bytes received:", bytes);
console.log("Number of bytes:", bytes.length);
} catch (e) {
console.error("Error fetching Klines:", e);
}
}
</script>

</body>
</html>
1 change: 0 additions & 1 deletion extern/binacpp
Submodule binacpp deleted from 49a513
1 change: 0 additions & 1 deletion extern/flatbuffers
Submodule flatbuffers deleted from 4c0eec
Loading