Skip to content

Commit

Permalink
hkuserver continuue
Browse files Browse the repository at this point in the history
  • Loading branch information
fasiondog committed Apr 13, 2021
1 parent 84857ea commit 203885c
Show file tree
Hide file tree
Showing 15 changed files with 239 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ bool SQLiteConnect::tableExist(const string& tablename) {
}

void SQLiteConnect::transaction() {
exec("BEGIN TRANSACTION");
exec("BEGIN IMMEDIATE");
}

void SQLiteConnect::commit() {
Expand Down
109 changes: 109 additions & 0 deletions hikyuu_cpp/hikyuu_server/common/snowflake.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright(C) 2021 hikyuu.org
*
* The code comes from: https://github.com/sniper00/snowflake-cpp
* Thanks sniper00
*
* Create on: 2021-04-13
* Author: fasiondog
*/

#pragma once

#include <cstdint>
#include <chrono>
#include <stdexcept>
#include <mutex>

namespace hku {

class snowflake_nonlock {
public:
void lock() {}
void unlock() {}
};

template <int64_t Twepoch, typename Lock = snowflake_nonlock>
class snowflake {
using lock_type = Lock;
static constexpr int64_t TWEPOCH = Twepoch;
static constexpr int64_t WORKER_ID_BITS = 5L;
static constexpr int64_t DATACENTER_ID_BITS = 5L;
static constexpr int64_t MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1;
static constexpr int64_t MAX_DATACENTER_ID = (1 << DATACENTER_ID_BITS) - 1;
static constexpr int64_t SEQUENCE_BITS = 12L;
static constexpr int64_t WORKER_ID_SHIFT = SEQUENCE_BITS;
static constexpr int64_t DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
static constexpr int64_t TIMESTAMP_LEFT_SHIFT =
SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
static constexpr int64_t SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1;

using time_point = std::chrono::time_point<std::chrono::steady_clock>;

time_point start_time_point_ = std::chrono::steady_clock::now();
int64_t start_millsecond_ = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();

int64_t last_timestamp_ = -1;
int64_t workerid_ = 0;
int64_t datacenterid_ = 0;
int64_t sequence_ = 0;
lock_type lock_;

public:
snowflake() = default;

snowflake(const snowflake&) = delete;

snowflake& operator=(const snowflake&) = delete;

void init(int64_t workerid, int64_t datacenterid) {
if (workerid > MAX_WORKER_ID || workerid < 0) {
throw std::runtime_error("worker Id can't be greater than 31 or less than 0");
}

if (datacenterid > MAX_DATACENTER_ID || datacenterid < 0) {
throw std::runtime_error("datacenter Id can't be greater than 31 or less than 0");
}

workerid_ = workerid;
datacenterid_ = datacenterid;
}

int64_t nextid() {
std::lock_guard<lock_type> lock(lock_);
// std::chrono::steady_clock cannot decrease as physical time moves forward
auto timestamp = millsecond();
if (last_timestamp_ == timestamp) {
sequence_ = (sequence_ + 1) & SEQUENCE_MASK;
if (sequence_ == 0) {
timestamp = wait_next_millis(last_timestamp_);
}
} else {
sequence_ = 0;
}

last_timestamp_ = timestamp;

return ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) |
(datacenterid_ << DATACENTER_ID_SHIFT) | (workerid_ << WORKER_ID_SHIFT) | sequence_;
}

private:
int64_t millsecond() const noexcept {
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start_time_point_);
return start_millsecond_ + diff.count();
}

int64_t wait_next_millis(int64_t last) const noexcept {
auto timestamp = millsecond();
while (timestamp <= last) {
timestamp = millsecond();
}
return timestamp;
}
};

} // namespace hku
2 changes: 1 addition & 1 deletion hikyuu_cpp/hikyuu_server/http/HttpError.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ enum HttpErrorCode {
WRONG_PARAMETER_TYPE // 参数类型错误(各个业务接口返回各个接口的参数)
};

#define HTTP_VALID_CHECK(expr, errcode, ...) \
#define HTTP_CHECK(expr, errcode, ...) \
{ \
if (!(expr)) { \
throw HttpError(errcode, fmt::format(__VA_ARGS__)); \
Expand Down
4 changes: 2 additions & 2 deletions hikyuu_cpp/hikyuu_server/http/HttpFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ inline void MissContentFilter(HttpHandle *handle) {
void *data = nullptr;
size_t len = 0;
handle->getReqData(&data, &len);
HTTP_VALID_CHECK(data, HttpErrorCode::MISS_CONTENT, "Miss content!");
HTTP_CHECK(data, HttpErrorCode::MISS_CONTENT, "Miss content!");
}

inline void ApiTokenAuthorizeFilter(HttpHandle *handle) {
const char *token = handle->getReqHeader("token");
HTTP_VALID_CHECK(token, HttpErrorCode::MISS_TOKEN, "Miss token!");
HTTP_CHECK(token, HttpErrorCode::MISS_TOKEN, "Miss token!");
}

} // namespace hku
2 changes: 1 addition & 1 deletion hikyuu_cpp/hikyuu_server/http/HttpHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ json HttpHandle::getReqJson() {
void* data;
size_t len;
nng_http_req_get_data(m_nng_req, &data, &len);
HTTP_VALID_CHECK(data, INVALID_JSON_REQUEST, "Req data is empty!");
HTTP_CHECK(data, INVALID_JSON_REQUEST, "Req data is empty!");
json result;
try {
result = json::parse((const char*)data);
Expand Down
4 changes: 2 additions & 2 deletions hikyuu_cpp/hikyuu_server/service/Account/LoginHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class LoginHandle : public HttpHandle {

virtual void run() override {
json req = getReqJson();
HTTP_VALID_CHECK(req.contains("user"), HttpErrorCode::MISS_PARAMETER,
"Invalid login request! missing user");
HTTP_CHECK(req.contains("user"), HttpErrorCode::MISS_PARAMETER,
"Invalid login request! missing user");
setResHeader("Content-Type", "application/json; charset=UTF-8");
setResData(
R"({"hku_token":"7c98806c0711cf996d602890e0ab9119d9a86afe04296ba69a16f0d9d76be755"})");
Expand Down
2 changes: 1 addition & 1 deletion hikyuu_cpp/hikyuu_server/service/RestErrorCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

namespace hku {

enum TradeErrorCode { TD_ACCOUNT_REPETITION = 20000 };
enum TradeErrorCode { TD_ACCOUNT_REPETITION = 20000, TD_ACCOUNT_INVALD_TYPE };

}
4 changes: 2 additions & 2 deletions hikyuu_cpp/hikyuu_server/service/RestHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace hku {

inline void AuthorizeFilter(HttpHandle *handle) {
const char *token = handle->getReqHeader("hku_token");
HTTP_VALID_CHECK(token, HttpErrorCode::MISS_TOKEN, "Miss token!");
HTTP_VALID_CHECK(
HTTP_CHECK(token, HttpErrorCode::MISS_TOKEN, "Miss token!");
HTTP_CHECK(
strcmp(token, "7c98806c0711cf996d602890e0ab9119d9a86afe04296ba69a16f0d9d76be755") == 0,
HttpErrorCode::UNAUTHORIZED, "Failed authorize!");
}
Expand Down
11 changes: 5 additions & 6 deletions hikyuu_cpp/hikyuu_server/service/assist/LogLevelHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,18 @@ class LogLevelHandle : public RestHandle {

virtual void run() override {
json req = getReqJson();
HTTP_VALID_CHECK(req.contains("level"), HttpErrorCode::MISS_PARAMETER,
"Missing key: level");
HTTP_VALID_CHECK(req["level"].is_number_integer(), HttpErrorCode::WRONG_PARAMETER_TYPE,
"level type must be integer");
HTTP_CHECK(req.contains("level"), HttpErrorCode::MISS_PARAMETER, "Missing key: level");
HTTP_CHECK(req["level"].is_number_integer(), HttpErrorCode::WRONG_PARAMETER_TYPE,
"level type must be integer");
int level = req["level"].get<int>();
if (!req.contains("logger")) {
set_logger_level(level);
setResData(R"({"result": true})");
return;
}

HTTP_VALID_CHECK(req["logger"].is_string(), HttpErrorCode::WRONG_PARAMETER_TYPE,
"logger type must be string");
HTTP_CHECK(req["logger"].is_string(), HttpErrorCode::WRONG_PARAMETER_TYPE,
"logger type must be string");
std::string logger = req["logger"].get<std::string>();
if (have_logger(logger)) {
set_logger_level(logger, level);
Expand Down
21 changes: 10 additions & 11 deletions hikyuu_cpp/hikyuu_server/service/trade/TradeAccountHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,24 @@ namespace hku {

void AddTradeAccountHandle::run() {
json req = getReqJson();
HTTP_VALID_CHECK(req.contains("name"), HttpErrorCode::MISS_PARAMETER,
R"(Missing param "name")");
HTTP_VALID_CHECK(req.contains("type"), HttpErrorCode::MISS_PARAMETER,
R"(Missing param "type")");
HTTP_CHECK(req.contains("name"), HttpErrorCode::MISS_PARAMETER, R"(Missing param "name")");
HTTP_CHECK(req.contains("type"), HttpErrorCode::MISS_PARAMETER, R"(Missing param "type")");
TradeAccountModel account;
std::string name = req["name"].get<std::string>();
std::string td_type = req["type"].get<std::string>();
HTTP_CHECK(TradeService::isValidEumValue(TradeAccountModel::getTableName(), "type", td_type),
TradeErrorCode::TD_ACCOUNT_INVALD_TYPE, "Invalid trade account type: {}", td_type);
account.setName(name);
account.setType(req["type"].get<std::string>());
account.setAccount(UUID());
account.setType(td_type);
account.setTdId(TradeService::newTdId());
auto con = TradeService::getDBConnect();
{
TransAction trans(con);
HTTP_VALID_CHECK(!TradeAccountModel::isExistName(con, name),
TradeErrorCode::TD_ACCOUNT_REPETITION, "Name repetition");
HTTP_CHECK(!TradeAccountModel::isExistName(con, name),
TradeErrorCode::TD_ACCOUNT_REPETITION, "Name repetition");
con->save(account, false);
}
json res;
to_json(res, account);
setResData(res);
setResData(account.json());
}

void GetTradeAccountHandle::run() {}
Expand Down
44 changes: 29 additions & 15 deletions hikyuu_cpp/hikyuu_server/service/trade/TradeService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@ namespace hku {
std::unique_ptr<ConnectPool<SQLiteConnect>> TradeService::ms_sqlite_pool;
std::unique_ptr<ConnectPool<MySQLConnect>> TradeService::ms_mysql_pool;

TradeService::snowflake_t TradeService::ms_td_id_generator;
TradeService::snowflake_t TradeService::ms_sta_id_generator;

TradeService::TradeService(const char* url, const std::string& config_file) : HttpService(url) {
ms_td_id_generator.init(1, 1);
ms_sta_id_generator.init(1, 1);

if (ms_sqlite_pool || ms_mysql_pool) {
return;
}

IniParser ini;
ini.read(config_file);

Parameter param;
auto options = ini.getOptionList("database");
for (auto& option : *options) {
param.set<string>(option, ini.get("database", option));
}

initTradeServiceDB(param);
}

void TradeService::initTradeServiceSqlite(const Parameter& param) {
Parameter sqlite_param;
sqlite_param.set<string>("db", param.get<string>("db"));
Expand Down Expand Up @@ -55,21 +78,12 @@ DBConnectPtr TradeService::getDBConnect() {
: DBConnectPtr();
}

TradeService::TradeService(const char* url, const std::string& config_file) : HttpService(url) {
if (ms_sqlite_pool || ms_mysql_pool) {
return;
}

IniParser ini;
ini.read(config_file);

Parameter param;
auto options = ini.getOptionList("database");
for (auto& option : *options) {
param.set<string>(option, ini.get("database", option));
}

initTradeServiceDB(param);
bool TradeService::isValidEumValue(const std::string& table, const std::string& field,
const std::string& val) {
int count = getDBConnect()->queryInt(fmt::format(
R"(select count(1) from td_enum where table_name="{}" and field_name="{}" and value="{}")",
table, field, val));
return count > 0;
}

} // namespace hku
16 changes: 16 additions & 0 deletions hikyuu_cpp/hikyuu_server/service/trade/TradeService.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <hikyuu/utilities/db_connect/sqlite/SQLiteConnect.h>
#include <hikyuu/utilities/db_connect/mysql/MySQLConnect.h>
#include "http/HttpService.h"
#include "common/snowflake.h"
#include "WalletHandle.h"
#include "TradeAccountHandle.h"

Expand All @@ -38,6 +39,17 @@ class TradeService : public HttpService {
public:
static DBConnectPtr getDBConnect();

static int64_t newTdId() {
return ms_td_id_generator.nextid();
}

static int64_t newStaId() {
return ms_sta_id_generator.nextid();
}

static bool isValidEumValue(const std::string &table, const std::string &field,
const std::string &val);

private:
static void initTradeServiceSqlite(const Parameter &param);
static void initTradeServiceMysql(const Parameter &param);
Expand All @@ -46,6 +58,10 @@ class TradeService : public HttpService {
private:
static std::unique_ptr<ConnectPool<SQLiteConnect>> ms_sqlite_pool;
static std::unique_ptr<ConnectPool<MySQLConnect>> ms_mysql_pool;

using snowflake_t = snowflake<1618243200000L, std::mutex>;
static snowflake_t ms_td_id_generator;
static snowflake_t ms_sta_id_generator;
};

} // namespace hku
Loading

0 comments on commit 203885c

Please sign in to comment.