This commit is contained in:
fasiondog 2024-08-03 11:32:44 +08:00
parent bf55a8e151
commit 054b18c058
12 changed files with 999 additions and 55 deletions

View File

@ -14,12 +14,13 @@
#include "hikyuu/version.h"
#include "hikyuu/DataType.h"
#include "hikyuu/utilities/os.h"
#include "node/NodeClient.h"
#include "hikyuu/utilities/http_client/HttpClient.h"
#include "sysinfo.h"
using json = nlohmann::json;
#define FEEDBACK_SERVER_ADDR "tcp://1.tcp.cpolar.cn:20981"
// #define FEEDBACK_SERVER_ADDR "tcp://1.tcp.cpolar.cn:20981"
#define FEEDBACK_SERVER_ADDR "http://127.0.0.1:80"
namespace hku {
@ -116,27 +117,15 @@ void sendFeedback() {
saveUUID(uid);
}
NodeClient client(FEEDBACK_SERVER_ADDR);
client.dial();
json req, res;
req["cmd"] = 2;
client.post(req, res);
std::string host = res["host"].get<std::string>();
uint64_t port = res["port"].get<uint64_t>();
g_latest_version = res.contains("last_version") ? res["last_version"].get<int>() : 0;
client.close();
client.setServerAddr(fmt::format("tcp://{}:{}", host, port));
client.dial();
req["cmd"] = 1;
HttpClient client(FEEDBACK_SERVER_ADDR);
json req;
req["uid"] = boost::uuids::to_string(uid);
req["part"] = "hikyuu";
req["version"] = HKU_VERSION;
req["build"] = fmt::format("{}", HKU_VERSION_BUILD);
req["platform"] = getPlatform();
req["arch"] = getCpuArch();
client.post(req, res);
client.post("/hku/visit", req);
} catch (...) {
// do nothing
@ -149,24 +138,14 @@ void sendFeedback() {
void sendPythonVersionFeedBack(int major, int minor, int micro) {
std::thread t([=]() {
try {
NodeClient client(FEEDBACK_SERVER_ADDR);
client.dial();
json req, res;
req["cmd"] = 2;
client.post(req, res);
std::string host = res["host"].get<std::string>();
uint64_t port = res["port"].get<uint64_t>();
g_latest_version = res.contains("last_version") ? res["last_version"].get<int>() : 0;
client.close();
client.setServerAddr(fmt::format("tcp://{}:{}", host, port));
client.dial();
req["cmd"] = 3;
HttpClient client(FEEDBACK_SERVER_ADDR);
json req;
req["major"] = major;
req["minor"] = minor;
req["micro"] = micro;
client.post(req, res);
auto res = client.post("/hku/pyver", req);
json r = res.json();
g_latest_version = r["data"]["last_version"].get<int>();
} catch (...) {
// do nothing
}

View File

@ -0,0 +1,230 @@
/*
* LRUCache11 - a templated C++11 based LRU cache class that allows
* specification of
* key, value and optionally the map container type (defaults to
* std::unordered_map)
* By using the std::unordered_map and a linked list of keys it allows O(1) insert, delete
* and
* refresh operations.
*
* This is a header-only library and all you need is the LRUCache11.hpp file
*
* Github: https://github.com/mohaps/lrucache11
*
* This is a follow-up to the LRUCache project -
* https://github.com/mohaps/lrucache
*
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include <algorithm>
#include <cstdint>
#include <list>
#include <mutex>
#include <stdexcept>
#include <thread>
#include <unordered_map>
namespace lru11 {
/*
* a noop lockable concept that can be used in place of std::mutex
*/
class NullLock {
public:
void lock() {}
void unlock() {}
bool try_lock() {
return true;
}
};
/**
* error raised when a key not in cache is passed to get()
*/
class KeyNotFound : public std::invalid_argument {
public:
KeyNotFound() : std::invalid_argument("key_not_found") {}
};
template <typename K, typename V>
struct KeyValuePair {
public:
K key;
V value;
KeyValuePair(K k, V v) : key(std::move(k)), value(std::move(v)) {}
};
/**
* The LRU Cache class templated by
* Key - key type
* Value - value type
* MapType - an associative container like std::unordered_map
* LockType - a lock type derived from the Lock class (default:
*NullLock = no synchronization)
*
* The default NullLock based template is not thread-safe, however passing
*Lock=std::mutex will make it
* thread-safe
*/
template <class Key, class Value, class Lock = NullLock,
class Map =
std::unordered_map<Key, typename std::list<KeyValuePair<Key, Value>>::iterator>>
class Cache {
public:
typedef KeyValuePair<Key, Value> node_type;
typedef std::list<KeyValuePair<Key, Value>> list_type;
typedef Map map_type;
typedef Lock lock_type;
using Guard = std::lock_guard<lock_type>;
/**
* the maxSize is the soft limit of keys and (maxSize + elasticity) is the
* hard limit
* the cache is allowed to grow till (maxSize + elasticity) and is pruned back
* to maxSize keys
* set maxSize = 0 for an unbounded cache (but in that case, you're better off
* using a std::unordered_map
* directly anyway! :)
*/
explicit Cache(size_t maxSize = 64, size_t elasticity = 10)
: maxSize_(maxSize), elasticity_(elasticity) {}
virtual ~Cache() = default;
size_t size() const {
Guard g(lock_);
return cache_.size();
}
bool empty() const {
Guard g(lock_);
return cache_.empty();
}
void clear() {
Guard g(lock_);
cache_.clear();
keys_.clear();
}
void insert(const Key& k, const Value& v) {
Guard g(lock_);
const auto iter = cache_.find(k);
if (iter != cache_.end()) {
iter->second->value = v;
keys_.splice(keys_.begin(), keys_, iter->second);
return;
}
keys_.emplace_front(k, v);
cache_[k] = keys_.begin();
prune();
}
void insert(const Key& k, Value&& v) {
Guard g(lock_);
const auto iter = cache_.find(k);
if (iter != cache_.end()) {
iter->second->value = std::move(v);
keys_.splice(keys_.begin(), keys_, iter->second);
return;
}
keys_.emplace_front(k, std::move(v));
cache_[k] = keys_.begin();
prune();
}
bool tryGet(const Key& kIn, Value& vOut) {
Guard g(lock_);
const auto iter = cache_.find(kIn);
if (iter == cache_.end()) {
return false;
}
keys_.splice(keys_.begin(), keys_, iter->second);
vOut = iter->second->value;
return true;
}
/**
* The const reference returned here is only
* guaranteed to be valid till the next insert/delete
* 便
*/
Value& get(const Key& k) {
Guard g(lock_);
const auto iter = cache_.find(k);
if (iter == cache_.end()) {
throw KeyNotFound();
}
keys_.splice(keys_.begin(), keys_, iter->second);
return iter->second->value;
}
/**
* returns a copy of the stored object (if found)
*/
Value getCopy(const Key& k) {
return get(k);
}
bool remove(const Key& k) {
Guard g(lock_);
auto iter = cache_.find(k);
if (iter == cache_.end()) {
return false;
}
keys_.erase(iter->second);
cache_.erase(iter);
return true;
}
bool contains(const Key& k) const {
Guard g(lock_);
return cache_.find(k) != cache_.end();
}
size_t getMaxSize() const {
return maxSize_;
}
size_t getElasticity() const {
return elasticity_;
}
size_t getMaxAllowedSize() const {
return maxSize_ + elasticity_;
}
template <typename F>
void cwalk(F& f) const {
Guard g(lock_);
std::for_each(keys_.begin(), keys_.end(), f);
}
protected:
size_t prune() {
size_t maxAllowed = maxSize_ + elasticity_;
if (maxSize_ == 0 || cache_.size() < maxAllowed) {
return 0;
}
size_t count = 0;
while (cache_.size() > maxSize_) {
cache_.erase(keys_.back().key);
keys_.pop_back();
++count;
}
return count;
}
private:
// Disallow copying.
Cache(const Cache&) = delete;
Cache& operator=(const Cache&) = delete;
mutable Lock lock_;
Map cache_;
list_type keys_;
size_t maxSize_;
size_t elasticity_;
};
} // namespace lru11

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2023 hikyuu.org
*
* Created on: 2023-01-15
* Author: fasiondog
*/
#pragma once
#include <string>
#include "osdef.h"
#include "cppdef.h"
#if !HKU_OS_IOS && CPP_STANDARD >= CPP_STANDARD_17
#include <any>
#else
#include <boost/any.hpp>
#endif
#if defined(HKU_SUPPORT_DATETIME)
#include "hikyuu/utilities/datetime/Datetime.h"
#endif
namespace hku {
#if !HKU_OS_IOS && CPP_STANDARD >= CPP_STANDARD_17
using any_t = std::any;
using std::any_cast;
#else
using any_t = boost::any;
using boost::any_cast;
#endif
//------------------------------------------------------------------------------
//
// 常见基本类型包装的 any_t 和 std::string 的互相转换函数
// any_to_string 要用户自定义类型需包含从 std::string 进行构造的构造函数
// string_to_any 需要用户自定义实现 std::to_string 特化方法
//
//------------------------------------------------------------------------------
template <typename ValueT>
inline std::string any_to_string(const any_t& data) {
return any_cast<ValueT>(data).str();
}
template <typename ValueT>
inline any_t string_to_any(const std::string& data) {
return any_t(ValueT(data));
}
template <>
inline std::string any_to_string<int>(const any_t& data) {
return std::to_string(any_cast<int>(data));
}
template <>
inline std::string any_to_string<long>(const any_t& data) {
return std::to_string(any_cast<long>(data));
}
template <>
inline std::string any_to_string<long long>(const any_t& data) {
return std::to_string(any_cast<long long>(data));
}
template <>
inline std::string any_to_string<unsigned int>(const any_t& data) {
return std::to_string(any_cast<unsigned int>(data));
}
template <>
inline std::string any_to_string<unsigned long>(const any_t& data) {
return std::to_string(any_cast<unsigned long>(data));
}
template <>
inline std::string any_to_string<unsigned long long>(const any_t& data) {
return std::to_string(any_cast<unsigned long long>(data));
}
template <>
inline std::string any_to_string<float>(const any_t& data) {
return std::to_string(any_cast<float>(data));
}
template <>
inline std::string any_to_string<double>(const any_t& data) {
return std::to_string(any_cast<double>(data));
}
template <>
inline std::string any_to_string<long double>(const any_t& data) {
return std::to_string(any_cast<long double>(data));
}
template <>
inline any_t string_to_any<int>(const std::string& data) {
return any_t(std::stoi(data));
}
template <>
inline any_t string_to_any<long>(const std::string& data) {
return any_t(std::stol(data));
}
template <>
inline any_t string_to_any<long long>(const std::string& data) {
return any_t(std::stoll(data));
}
template <>
inline any_t string_to_any<unsigned int>(const std::string& data) {
return any_t((unsigned int)(std::stoul(data)));
}
template <>
inline any_t string_to_any<unsigned long>(const std::string& data) {
return any_t(std::stoul(data));
}
template <>
inline any_t string_to_any<unsigned long long>(const std::string& data) {
return any_t(std::stoull(data));
}
template <>
inline any_t string_to_any<float>(const std::string& data) {
return any_t(std::stof(data));
}
template <>
inline any_t string_to_any<double>(const std::string& data) {
return any_t(std::stod(data));
}
template <>
inline any_t string_to_any<long double>(const std::string& data) {
return any_t(std::stold(data));
}
} // namespace hku

View File

@ -166,6 +166,10 @@ public:
return post(path, HttpParams(), headers, body);
}
HttpResponse post(const std::string& path, const json& body) {
return post(path, HttpHeaders(), body);
}
private:
void _connect();
HttpResponse _readResChunk(const std::string& method, const std::string& uri,

View File

@ -1,4 +1,4 @@
/*
/*
* IniFile.cpp
*
* Created on: 2010-5-19

View File

@ -1,4 +1,4 @@
/*
/*
* IniFile.h
*
* Created on: 2010-5-19

View File

@ -0,0 +1,291 @@
/*
* Copyright (c) hikyuu
* Created on: 2021/12/06
* Author: fasiondog
*
* : boost的md5计算在windows和linux平台上结果不一致 dlib
*/
#include "arithmetic.h"
#include "md5.h"
#include "Log.h"
namespace hku {
inline uint32_t F(uint32_t x, uint32_t y, uint32_t z) {
return ((x & y) | ((~x) & z));
}
// ------------------------------------------------------------------------------------
inline uint32_t G(uint32_t x, uint32_t y, uint32_t z) {
return ((x & z) | (y & (~z)));
}
// ------------------------------------------------------------------------------------
inline uint32_t H(uint32_t x, uint32_t y, uint32_t z) {
return (x ^ y ^ z);
}
// ------------------------------------------------------------------------------------
inline uint32_t I(uint32_t x, uint32_t y, uint32_t z) {
return (y ^ (x | (~z)));
}
// ------------------------------------------------------------------------------------
inline uint32_t rotate_left(uint32_t x, uint32_t n) {
return ((x << n) | (x >> (32 - n)));
}
// ------------------------------------------------------------------------------------
inline void FF(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s,
uint32_t ac) {
a += F(b, c, d) + x + ac;
a = rotate_left(a, s);
a += b;
}
// ------------------------------------------------------------------------------------
inline void GG(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s,
uint32_t ac) {
a += G(b, c, d) + x + ac;
a = rotate_left(a, s);
a += b;
}
// ------------------------------------------------------------------------------------
inline void HH(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s,
uint32_t ac) {
a += H(b, c, d) + x + ac;
a = rotate_left(a, s);
a += b;
}
// ------------------------------------------------------------------------------------
inline void II(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s,
uint32_t ac) {
a += I(b, c, d) + x + ac;
a = rotate_left(a, s);
a += b;
}
void scramble_block(uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d, uint32_t* x) {
const uint32_t S11 = 7;
const uint32_t S12 = 12;
const uint32_t S13 = 17;
const uint32_t S14 = 22;
const uint32_t S21 = 5;
const uint32_t S22 = 9;
const uint32_t S23 = 14;
const uint32_t S24 = 20;
const uint32_t S31 = 4;
const uint32_t S32 = 11;
const uint32_t S33 = 16;
const uint32_t S34 = 23;
const uint32_t S41 = 6;
const uint32_t S42 = 10;
const uint32_t S43 = 15;
const uint32_t S44 = 21;
// round 1
FF(a, b, c, d, x[0], S11, 0xd76aa478); // 1
FF(d, a, b, c, x[1], S12, 0xe8c7b756); // 2
FF(c, d, a, b, x[2], S13, 0x242070db); // 3
FF(b, c, d, a, x[3], S14, 0xc1bdceee); // 4
FF(a, b, c, d, x[4], S11, 0xf57c0faf); // 5
FF(d, a, b, c, x[5], S12, 0x4787c62a); // 6
FF(c, d, a, b, x[6], S13, 0xa8304613); // 7
FF(b, c, d, a, x[7], S14, 0xfd469501); // 8
FF(a, b, c, d, x[8], S11, 0x698098d8); // 9
FF(d, a, b, c, x[9], S12, 0x8b44f7af); // 10
FF(c, d, a, b, x[10], S13, 0xffff5bb1); // 11
FF(b, c, d, a, x[11], S14, 0x895cd7be); // 12
FF(a, b, c, d, x[12], S11, 0x6b901122); // 13
FF(d, a, b, c, x[13], S12, 0xfd987193); // 14
FF(c, d, a, b, x[14], S13, 0xa679438e); // 15
FF(b, c, d, a, x[15], S14, 0x49b40821); // 16
// Round 2
GG(a, b, c, d, x[1], S21, 0xf61e2562); // 17
GG(d, a, b, c, x[6], S22, 0xc040b340); // 18
GG(c, d, a, b, x[11], S23, 0x265e5a51); // 19
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); // 20
GG(a, b, c, d, x[5], S21, 0xd62f105d); // 21
GG(d, a, b, c, x[10], S22, 0x2441453); // 22
GG(c, d, a, b, x[15], S23, 0xd8a1e681); // 23
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); // 24
GG(a, b, c, d, x[9], S21, 0x21e1cde6); // 25
GG(d, a, b, c, x[14], S22, 0xc33707d6); // 26
GG(c, d, a, b, x[3], S23, 0xf4d50d87); // 27
GG(b, c, d, a, x[8], S24, 0x455a14ed); // 28
GG(a, b, c, d, x[13], S21, 0xa9e3e905); // 29
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); // 30
GG(c, d, a, b, x[7], S23, 0x676f02d9); // 31
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32
// Round 3
HH(a, b, c, d, x[5], S31, 0xfffa3942); // 33
HH(d, a, b, c, x[8], S32, 0x8771f681); // 34
HH(c, d, a, b, x[11], S33, 0x6d9d6122); // 35
HH(b, c, d, a, x[14], S34, 0xfde5380c); // 36
HH(a, b, c, d, x[1], S31, 0xa4beea44); // 37
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); // 38
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); // 39
HH(b, c, d, a, x[10], S34, 0xbebfbc70); // 40
HH(a, b, c, d, x[13], S31, 0x289b7ec6); // 41
HH(d, a, b, c, x[0], S32, 0xeaa127fa); // 42
HH(c, d, a, b, x[3], S33, 0xd4ef3085); // 43
HH(b, c, d, a, x[6], S34, 0x4881d05); // 44
HH(a, b, c, d, x[9], S31, 0xd9d4d039); // 45
HH(d, a, b, c, x[12], S32, 0xe6db99e5); // 46
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); // 47
HH(b, c, d, a, x[2], S34, 0xc4ac5665); // 48
// Round 4
II(a, b, c, d, x[0], S41, 0xf4292244); // 49
II(d, a, b, c, x[7], S42, 0x432aff97); // 50
II(c, d, a, b, x[14], S43, 0xab9423a7); // 51
II(b, c, d, a, x[5], S44, 0xfc93a039); // 52
II(a, b, c, d, x[12], S41, 0x655b59c3); // 53
II(d, a, b, c, x[3], S42, 0x8f0ccc92); // 54
II(c, d, a, b, x[10], S43, 0xffeff47d); // 55
II(b, c, d, a, x[1], S44, 0x85845dd1); // 56
II(a, b, c, d, x[8], S41, 0x6fa87e4f); // 57
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58
II(c, d, a, b, x[6], S43, 0xa3014314); // 59
II(b, c, d, a, x[13], S44, 0x4e0811a1); // 60
II(a, b, c, d, x[4], S41, 0xf7537e82); // 61
II(d, a, b, c, x[11], S42, 0xbd3af235); // 62
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); // 63
II(b, c, d, a, x[9], S44, 0xeb86d391); // 64
}
std::string HKU_UTILS_API md5(const unsigned char* input, size_t len) {
HKU_CHECK(input, "char *buf is null!");
// make a temp version of input with enough space for padding and len appended
unsigned long extra_len = 64 - len % 64;
if (extra_len <= 8)
extra_len += 64;
unsigned char* temp = new unsigned char[extra_len + len];
// number of 16 word blocks
const unsigned long N = (extra_len + static_cast<unsigned long>(len)) / 64;
const unsigned char* input2 = input;
unsigned char* temp2 = temp;
unsigned char* end = temp + len;
// copy input into temp
while (temp2 != end) {
*temp2 = *input2;
++temp2;
++input2;
}
// pad temp
end += extra_len - 8;
*temp2 = static_cast<unsigned char>(0x80);
++temp2;
while (temp2 != end) {
*temp2 = 0;
++temp2;
}
// make len the number of bits in the original message
// but first multiply len by 8 and since len is only 32 bits the number might
// overflow so we will carry out the multiplication manually and end up with
// the result in the base 65536 number with three digits
// result = low + high*65536 + upper*65536*65536
unsigned long low = len & 0xFFFF;
unsigned long high = static_cast<unsigned long>(len) >> 16;
unsigned long upper;
unsigned long tmp;
tmp = low * 8;
low = tmp & 0xFFFF;
tmp = high * 8 + (tmp >> 16);
high = tmp & 0xFFFF;
upper = tmp >> 16;
// append the length
*temp2 = static_cast<unsigned char>(low & 0xFF);
++temp2;
*temp2 = static_cast<unsigned char>((low >> 8) & 0xFF);
++temp2;
*temp2 = static_cast<unsigned char>((high) & 0xFF);
++temp2;
*temp2 = static_cast<unsigned char>((high >> 8) & 0xFF);
++temp2;
*temp2 = static_cast<unsigned char>((upper) & 0xFF);
;
++temp2;
*temp2 = static_cast<unsigned char>((upper >> 8) & 0xFF);
;
++temp2;
*temp2 = 0;
++temp2;
*temp2 = 0;
uint32_t a = 0x67452301;
uint32_t b = 0xefcdab89;
uint32_t c = 0x98badcfe;
uint32_t d = 0x10325476;
// an array of 16 words
uint32_t x[16];
for (unsigned long i = 0; i < N; ++i) {
// copy a block of 16 words from m into x
for (unsigned long j = 0; j < 16; ++j) {
x[j] = ((static_cast<uint32_t>(temp[4 * (j + 16 * i) + 3]) << 24) |
(static_cast<uint32_t>(temp[4 * (j + 16 * i) + 2]) << 16) |
(static_cast<uint32_t>(temp[4 * (j + 16 * i) + 1]) << 8) |
(static_cast<uint32_t>(temp[4 * (j + 16 * i)])));
}
uint32_t aa = a;
uint32_t bb = b;
uint32_t cc = c;
uint32_t dd = d;
scramble_block(a, b, c, d, x);
a = a + aa;
b = b + bb;
c = c + cc;
d = d + dd;
}
unsigned char output[16];
// put a, b, c, and d into output
output[0] = static_cast<unsigned char>((a) & 0xFF);
output[1] = static_cast<unsigned char>((a >> 8) & 0xFF);
output[2] = static_cast<unsigned char>((a >> 16) & 0xFF);
output[3] = static_cast<unsigned char>((a >> 24) & 0xFF);
output[4] = static_cast<unsigned char>((b) & 0xFF);
output[5] = static_cast<unsigned char>((b >> 8) & 0xFF);
output[6] = static_cast<unsigned char>((b >> 16) & 0xFF);
output[7] = static_cast<unsigned char>((b >> 24) & 0xFF);
output[8] = static_cast<unsigned char>((c) & 0xFF);
output[9] = static_cast<unsigned char>((c >> 8) & 0xFF);
output[10] = static_cast<unsigned char>((c >> 16) & 0xFF);
output[11] = static_cast<unsigned char>((c >> 24) & 0xFF);
output[12] = static_cast<unsigned char>((d) & 0xFF);
output[13] = static_cast<unsigned char>((d >> 8) & 0xFF);
output[14] = static_cast<unsigned char>((d >> 16) & 0xFF);
output[15] = static_cast<unsigned char>((d >> 24) & 0xFF);
delete[] temp;
return byteToHexStr((const char*)output, 16);
}
} // namespace hku

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019~2021, hikyuu
*
* Created on: 2021/12/06
* Author: fasiondog
*/
#pragma once
#ifndef HKU_UTILS_MD5_H
#define HKU_UTILS_MD5_H
#include <string>
#ifndef HKU_UTILS_API
#define HKU_UTILS_API
#endif
namespace hku {
/**
* @brief md5
*
* @param input
* @param len
* @return std::string
*/
std::string HKU_UTILS_API md5(const unsigned char* input, size_t len);
/**
* @brief md5
*
* @param src
* @return std::string
*/
inline std::string md5(const std::string& src) {
return md5((const unsigned char*)src.data(), src.size());
}
} // namespace hku
#endif // #define HKU_UTILS_MD5_H

View File

@ -7,6 +7,11 @@
#pragma once
#include "hikyuu/utilities/config.h"
#if !HKU_ENABLE_NODE
#error "Don't enable node client, please config with --node=y"
#endif
#include <atomic>
#include <nng/nng.h>
#include <nng/protocol/reqrep0/req.h>
@ -59,13 +64,11 @@ public:
return true;
} catch (const std::exception& e) {
HKU_ERROR_IF(m_show_log, "Failed dail server: {}! {}", m_server_addr, e.what());
} catch (...) {
HKU_ERROR_IF(m_show_log, "Failed dail server: {}! Unknown error!", m_server_addr);
}
// } catch (const std::exception& e) {
// HKU_ERROR("Failed dail server: {}! {}", m_server_addr, e.what());
// } catch (...) {
// HKU_ERROR("Failed dail server: {}! Unknown error!", m_server_addr);
// }
m_connected = false;
nng_close(m_socket);
@ -101,6 +104,10 @@ public:
return _send(req) && _recv(res);
}
void showLog(bool show) {
m_show_log = show;
}
private:
bool _send(const json& req) const noexcept {
bool success = false;
@ -118,13 +125,11 @@ private:
NODE_NNG_CHECK(rv, "Failed nng_sendmsg!");
success = true;
} catch (const std::exception& e) {
HKU_ERROR_IF(m_show_log, "Failed send result! {}", e.what());
} catch (...) {
HKU_ERROR_IF(m_show_log, "Failed send result! Unknown error!");
}
// } catch (const std::exception& e) {
// HKU_ERROR("Failed send result! {}", e.what());
// } catch (...) {
// HKU_ERROR("Failed send result! Unknown error!");
// }
if (!success) {
nng_msg_free(msg);
@ -137,21 +142,22 @@ private:
bool success = false;
nng_msg* msg{nullptr};
int rv = nng_recvmsg(m_socket, &msg, 0);
// HKU_ERROR_IF_RETURN(rv != 0, success, "Failed nng_recvmsg! {}", nng_strerror(rv));
HKU_IF_RETURN(rv != 0, success);
if (rv != 0) {
HKU_ERROR_IF(m_show_log, "Failed nng_recvmsg! {}", nng_strerror(rv));
return success;
}
m_last_ack_time = Datetime::now();
try {
res = decodeMsg(msg);
success = true;
} catch (const std::exception& e) {
HKU_ERROR_IF(m_show_log, "Failed recv response! {}", e.what());
} catch (...) {
HKU_ERROR_IF(m_show_log, "Failed recv response! Unknown error!");
}
// } catch (const std::exception& e) {
// HKU_ERROR("Failed recv response! {}", e.what());
// } catch (...) {
// HKU_ERROR("Failed recv response! Unknown error!");
// }
nng_msg_free(msg);
return success;
@ -161,8 +167,9 @@ private:
std::mutex m_mutex;
std::string m_server_addr; // 服务端地址
nng_socket m_socket;
std::atomic_bool m_connected{false};
Datetime m_last_ack_time{Datetime::now()}; // 最后一次接收服务端响应的时间
std::atomic_bool m_connected{false};
std::atomic_bool m_show_log{true};
};
} // namespace hku

View File

@ -7,7 +7,7 @@
#pragma once
#include "hikyuu/utilities/exception.h"
#include <hikyuu/utilities/exception.h>
namespace hku {

View File

@ -12,6 +12,7 @@
#include <vector>
#include <nng/nng.h>
#include <nlohmann/json.hpp>
#include <hikyuu/utilities/Log.h>
#include "NodeError.h"
using json = nlohmann::json;
@ -26,8 +27,8 @@ namespace hku {
* req ->
* {"cmd": int, ...}
*
* req ->
* {"cmd": int, "ret": code, "msg": str}
* <- res
* {"ret": code, "msg": str} // msg 存在错误时返回错误信息 (可选)
*
*
*/

View File

@ -0,0 +1,249 @@
/*
* Copyright (c) 2022 hikyuu.org
*
* Created on: 2022-04-15
* Author: fasiondog
*/
#pragma once
#include "hikyuu/utilities/config.h"
#if !HKU_ENABLE_NODE
#error "Don't enable node server, please config with --node=y"
#endif
#include <string>
#include <unordered_map>
#include <nng/nng.h>
#include <nng/protocol/reqrep0/rep.h>
#include <hikyuu/utilities/osdef.h>
#if HKU_OS_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <WS2tcpip.h>
#include <Ws2ipdef.h>
#else
#include <arpa/inet.h>
#endif
#include "hikyuu/utilities/Log.h"
#include "NodeMessage.h"
namespace hku {
class NodeServer {
CLASS_LOGGER_IMP(NodeServer)
private:
static constexpr size_t PARALLEL = 128;
public:
NodeServer() = default;
explicit NodeServer(const std::string& addr) : m_addr(addr) {}
virtual ~NodeServer() {
stop();
}
void setAddr(const std::string& addr) {
m_addr = addr;
}
void regHandle(const std::string& cmd, const std::function<json(json&& req)>& handle) {
m_handles[cmd] = handle;
}
void regHandle(const std::string& cmd, std::function<json(json&& req)>&& handle) {
m_handles[cmd] = std::move(handle);
}
void start() {
CLS_CHECK(!m_addr.empty(), "You must set NodeServer's addr first!");
// 启动 node server
int rv = nng_rep0_open(&m_socket);
CLS_CHECK(0 == rv, "Failed open server socket! {}", nng_strerror(rv));
rv = nng_listen(m_socket, m_addr.c_str(), &m_listener, 0);
CLS_CHECK(0 == rv, "Failed listen node server socket ({})! {}", m_addr, nng_strerror(rv));
CLS_TRACE("channel lisenter server: {}", m_addr);
m_works.resize(PARALLEL);
for (size_t i = 0, total = m_works.size(); i < total; i++) {
Work* w = &m_works[i];
rv = nng_aio_alloc(&w->aio, _serverCallback, w);
CLS_CHECK(0 == rv, "Failed create work {}! {}", i, nng_strerror(rv));
rv = nng_ctx_open(&w->ctx, m_socket);
CLS_CHECK(0 == rv, "Failed open ctx {}! {}", i, nng_strerror(rv));
w->state = Work::INIT;
w->server = this;
}
for (size_t i = 0, total = m_works.size(); i < total; i++) {
_serverCallback(&m_works[i]);
}
}
void loop() {
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void stop() {
HKU_IF_RETURN(m_works.empty(), void());
for (size_t i = 0, total = m_works.size(); i < total; i++) {
Work* w = &m_works[i];
w->server = nullptr;
w->state = Work::FINISH;
if (w->aio) {
nng_aio_stop(w->aio);
nng_aio_free(w->aio);
nng_ctx_close(w->ctx);
w->aio = nullptr;
}
}
// 关闭 socket 服务节点
nng_listener_close(m_listener);
nng_close(m_socket);
m_works.clear();
CLS_INFO("stopped node server.");
}
private:
struct Work {
enum { INIT, RECV, SEND, FINISH } state = INIT;
nng_aio* aio{nullptr};
nng_ctx ctx;
NodeServer* server{nullptr};
};
static void _serverCallback(void* arg) {
Work* work = static_cast<Work*>(arg);
int rv = 0;
switch (work->state) {
case Work::INIT:
work->state = Work::RECV;
nng_ctx_recv(work->ctx, work->aio);
break;
case Work::RECV:
_processRequest(work);
break;
case Work::SEND:
if ((rv = nng_aio_result(work->aio)) != 0) {
CLS_FATAL("Failed nng_ctx_send! {}", nng_strerror(rv));
work->state = Work::FINISH;
return;
}
work->state = Work::RECV;
nng_ctx_recv(work->ctx, work->aio);
break;
case Work::FINISH:
break;
default:
CLS_FATAL("nng bad state!");
break;
}
}
static void _processRequest(Work* work) {
NodeServer* server = work->server;
CLS_IF_RETURN(!server || !work->aio, void());
nng_msg* msg = nullptr;
json res;
try {
int rv = nng_aio_result(work->aio);
HKU_CHECK(rv == 0, "Failed nng_aio_result!");
msg = nng_aio_get_msg(work->aio);
json req = decodeMsg(msg);
NODE_CHECK(req.contains("cmd"), NodeErrorCode::MISSING_CMD, "Missing command!");
// 兼容老版本数字cmd
std::string cmd = req["cmd"].is_number() ? fmt::format("{}", req["cmd"].get<int>())
: req["cmd"].get<std::string>();
auto iter = server->m_handles.find(cmd);
NODE_CHECK(iter != server->m_handles.end(), NodeErrorCode::INVALID_CMD,
"The server does not know how to process the message: {}", cmd);
// tcp 连接尝试获取客户端地址和端口加入 req 中
req["remote_host"] = "";
req["remote_port"] = 0;
nng_pipe p = nng_msg_get_pipe(msg);
if (nng_pipe_id(p) > 0) {
uint16_t port = 0;
nng_sockaddr ra;
rv = nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra);
if (rv == 0) {
if (ra.s_family == NNG_AF_INET) {
char ipAddr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&ra.s_in.sa_addr, ipAddr, INET_ADDRSTRLEN);
port = ntohs(ra.s_in.sa_port);
req["remote_host"] = ipAddr;
req["remote_port"] = port;
} else if (ra.s_family == NNG_AF_INET6) {
char ipAddr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&ra.s_in.sa_addr, ipAddr, INET6_ADDRSTRLEN);
port = ntohs(ra.s_in6.sa_port);
req["remote_host"] = ipAddr;
req["remote_port"] = port;
}
}
}
res = iter->second(std::move(req));
res["ret"] = NodeErrorCode::SUCCESS;
encodeMsg(msg, res);
nng_aio_set_msg(work->aio, msg);
work->state = Work::SEND;
nng_ctx_send(work->ctx, work->aio);
} catch (const NodeNngError& e) {
CLS_FATAL(e.what());
work->state = Work::FINISH;
} catch (const NodeError& e) {
CLS_ERROR(e.what());
res["ret"] = e.errcode();
res["msg"] = e.what();
encodeMsg(msg, res);
nng_aio_set_msg(work->aio, msg);
work->state = Work::SEND;
nng_ctx_send(work->ctx, work->aio);
} catch (const std::exception& e) {
CLS_ERROR(e.what());
res["ret"] = NodeErrorCode::UNKNOWN_ERROR;
res["msg"] = e.what();
encodeMsg(msg, res);
nng_aio_set_msg(work->aio, msg);
work->state = Work::SEND;
nng_ctx_send(work->ctx, work->aio);
} catch (...) {
std::string errmsg = "Unknown error!";
CLS_ERROR(errmsg);
res["ret"] = NodeErrorCode::UNKNOWN_ERROR;
res["msg"] = errmsg;
nng_aio_set_msg(work->aio, msg);
work->state = Work::SEND;
nng_ctx_send(work->ctx, work->aio);
}
}
private:
std::string m_addr;
nng_socket m_socket;
nng_listener m_listener;
std::vector<Work> m_works;
std::unordered_map<std::string, std::function<json(json&& req)>> m_handles;
};
} // namespace hku