mirror of
https://github.com/tribufu/sdk-cpp
synced 2025-06-16 18:54:18 +00:00
Add libhv and test http client
This commit is contained in:
371
vendor/libhv/include/hv/Channel.h
vendored
Normal file
371
vendor/libhv/include/hv/Channel.h
vendored
Normal file
@ -0,0 +1,371 @@
|
||||
#ifndef HV_CHANNEL_HPP_
|
||||
#define HV_CHANNEL_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "hloop.h"
|
||||
#include "hsocket.h"
|
||||
|
||||
#include "Buffer.h"
|
||||
|
||||
namespace hv {
|
||||
|
||||
class Channel {
|
||||
public:
|
||||
Channel(hio_t* io = NULL) {
|
||||
io_ = io;
|
||||
fd_ = -1;
|
||||
id_ = 0;
|
||||
ctx_ = NULL;
|
||||
status = CLOSED;
|
||||
if (io) {
|
||||
fd_ = hio_fd(io);
|
||||
id_ = hio_id(io);
|
||||
ctx_ = hio_context(io);
|
||||
hio_set_context(io, this);
|
||||
if (hio_is_opened(io)) {
|
||||
status = OPENED;
|
||||
}
|
||||
if (hio_getcb_read(io) == NULL) {
|
||||
hio_setcb_read(io_, on_read);
|
||||
}
|
||||
if (hio_getcb_write(io) == NULL) {
|
||||
hio_setcb_write(io_, on_write);
|
||||
}
|
||||
if (hio_getcb_close(io) == NULL) {
|
||||
hio_setcb_close(io_, on_close);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Channel() {
|
||||
if (isOpened()) {
|
||||
close();
|
||||
// NOTE: Detach after destructor to avoid triggering onclose
|
||||
if (io_ && id_ == hio_id(io_)) {
|
||||
hio_set_context(io_, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hio_t* io() { return io_; }
|
||||
int fd() { return fd_; }
|
||||
uint32_t id() { return id_; }
|
||||
int error() { return hio_error(io_); }
|
||||
|
||||
// context
|
||||
void* context() {
|
||||
return ctx_;
|
||||
}
|
||||
void setContext(void* ctx) {
|
||||
ctx_ = ctx;
|
||||
}
|
||||
template<class T>
|
||||
T* newContext() {
|
||||
ctx_ = new T;
|
||||
return (T*)ctx_;
|
||||
}
|
||||
template<class T>
|
||||
T* getContext() {
|
||||
return (T*)ctx_;
|
||||
}
|
||||
template<class T>
|
||||
void deleteContext() {
|
||||
if (ctx_) {
|
||||
delete (T*)ctx_;
|
||||
ctx_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// contextPtr
|
||||
std::shared_ptr<void> contextPtr() {
|
||||
return contextPtr_;
|
||||
}
|
||||
void setContextPtr(const std::shared_ptr<void>& ctx) {
|
||||
contextPtr_ = ctx;
|
||||
}
|
||||
void setContextPtr(std::shared_ptr<void>&& ctx) {
|
||||
contextPtr_ = std::move(ctx);
|
||||
}
|
||||
template<class T>
|
||||
std::shared_ptr<T> newContextPtr() {
|
||||
contextPtr_ = std::make_shared<T>();
|
||||
return std::static_pointer_cast<T>(contextPtr_);
|
||||
}
|
||||
template<class T>
|
||||
std::shared_ptr<T> getContextPtr() {
|
||||
return std::static_pointer_cast<T>(contextPtr_);
|
||||
}
|
||||
void deleteContextPtr() {
|
||||
contextPtr_.reset();
|
||||
}
|
||||
|
||||
bool isOpened() {
|
||||
if (io_ == NULL || status >= DISCONNECTED) return false;
|
||||
return id_ == hio_id(io_) && hio_is_opened(io_);
|
||||
}
|
||||
bool isClosed() {
|
||||
return !isOpened();
|
||||
}
|
||||
|
||||
int startRead() {
|
||||
if (!isOpened()) return -1;
|
||||
return hio_read_start(io_);
|
||||
}
|
||||
|
||||
int stopRead() {
|
||||
if (!isOpened()) return -1;
|
||||
return hio_read_stop(io_);
|
||||
}
|
||||
|
||||
int readOnce() {
|
||||
if (!isOpened()) return -1;
|
||||
return hio_read_once(io_);
|
||||
}
|
||||
|
||||
int readString() {
|
||||
if (!isOpened()) return -1;
|
||||
return hio_readstring(io_);
|
||||
}
|
||||
|
||||
int readLine() {
|
||||
if (!isOpened()) return -1;
|
||||
return hio_readline(io_);
|
||||
}
|
||||
|
||||
int readBytes(int len) {
|
||||
if (!isOpened() || len <= 0) return -1;
|
||||
return hio_readbytes(io_, len);
|
||||
}
|
||||
|
||||
// write thread-safe
|
||||
int write(const void* data, int size) {
|
||||
if (!isOpened()) return -1;
|
||||
return hio_write(io_, data, size);
|
||||
}
|
||||
|
||||
int write(Buffer* buf) {
|
||||
return write(buf->data(), buf->size());
|
||||
}
|
||||
|
||||
int write(const std::string& str) {
|
||||
return write(str.data(), str.size());
|
||||
}
|
||||
|
||||
// iobuf setting
|
||||
void setMaxReadBufsize(uint32_t size) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_max_read_bufsize(io_, size);
|
||||
}
|
||||
void setMaxWriteBufsize(uint32_t size) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_max_write_bufsize(io_, size);
|
||||
}
|
||||
size_t writeBufsize() {
|
||||
if (io_ == NULL) return 0;
|
||||
return hio_write_bufsize(io_);
|
||||
}
|
||||
bool isWriteComplete() {
|
||||
return writeBufsize() == 0;
|
||||
}
|
||||
|
||||
// close thread-safe
|
||||
int close(bool async = false) {
|
||||
if (isClosed()) return -1;
|
||||
status = CLOSED;
|
||||
return async ? hio_close_async(io_) : hio_close(io_);
|
||||
}
|
||||
|
||||
public:
|
||||
hio_t* io_;
|
||||
int fd_;
|
||||
uint32_t id_;
|
||||
void* ctx_;
|
||||
enum Status {
|
||||
OPENED,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
DISCONNECTED,
|
||||
CLOSED,
|
||||
} status;
|
||||
std::function<void(Buffer*)> onread;
|
||||
// NOTE: Use Channel::isWriteComplete in onwrite callback to determine whether all data has been written.
|
||||
std::function<void(Buffer*)> onwrite;
|
||||
std::function<void()> onclose;
|
||||
std::shared_ptr<void> contextPtr_;
|
||||
|
||||
private:
|
||||
static void on_read(hio_t* io, void* data, int readbytes) {
|
||||
Channel* channel = (Channel*)hio_context(io);
|
||||
if (channel && channel->onread) {
|
||||
Buffer buf(data, readbytes);
|
||||
channel->onread(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_write(hio_t* io, const void* data, int writebytes) {
|
||||
Channel* channel = (Channel*)hio_context(io);
|
||||
if (channel && channel->onwrite) {
|
||||
Buffer buf((void*)data, writebytes);
|
||||
channel->onwrite(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_close(hio_t* io) {
|
||||
Channel* channel = (Channel*)hio_context(io);
|
||||
if (channel) {
|
||||
channel->status = CLOSED;
|
||||
if (channel->onclose) {
|
||||
channel->onclose();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SocketChannel : public Channel {
|
||||
public:
|
||||
std::function<void()> onconnect; // only for TcpClient
|
||||
std::function<void()> heartbeat;
|
||||
|
||||
SocketChannel(hio_t* io) : Channel(io) {
|
||||
}
|
||||
virtual ~SocketChannel() {}
|
||||
|
||||
// SSL/TLS
|
||||
int enableSSL() {
|
||||
if (io_ == NULL) return -1;
|
||||
return hio_enable_ssl(io_);
|
||||
}
|
||||
bool isSSL() {
|
||||
if (io_ == NULL) return false;
|
||||
return hio_is_ssl(io_);
|
||||
}
|
||||
int setSSL(hssl_t ssl) {
|
||||
if (io_ == NULL) return -1;
|
||||
return hio_set_ssl(io_, ssl);
|
||||
}
|
||||
int setSslCtx(hssl_ctx_t ssl_ctx) {
|
||||
if (io_ == NULL) return -1;
|
||||
return hio_set_ssl_ctx(io_, ssl_ctx);
|
||||
}
|
||||
int newSslCtx(hssl_ctx_opt_t* opt) {
|
||||
if (io_ == NULL) return -1;
|
||||
return hio_new_ssl_ctx(io_, opt);
|
||||
}
|
||||
// for hssl_set_sni_hostname
|
||||
int setHostname(const std::string& hostname) {
|
||||
if (io_ == NULL) return -1;
|
||||
return hio_set_hostname(io_, hostname.c_str());
|
||||
}
|
||||
|
||||
// timeout
|
||||
void setConnectTimeout(int timeout_ms) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_connect_timeout(io_, timeout_ms);
|
||||
}
|
||||
void setCloseTimeout(int timeout_ms) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_close_timeout(io_, timeout_ms);
|
||||
}
|
||||
void setReadTimeout(int timeout_ms) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_read_timeout(io_, timeout_ms);
|
||||
}
|
||||
void setWriteTimeout(int timeout_ms) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_write_timeout(io_, timeout_ms);
|
||||
}
|
||||
void setKeepaliveTimeout(int timeout_ms) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_keepalive_timeout(io_, timeout_ms);
|
||||
}
|
||||
|
||||
// heartbeat
|
||||
// NOTE: Beware of circular reference problems caused by passing SocketChannelPtr by value.
|
||||
void setHeartbeat(int interval_ms, std::function<void()> fn) {
|
||||
if (io_ == NULL) return;
|
||||
heartbeat = std::move(fn);
|
||||
hio_set_heartbeat(io_, interval_ms, send_heartbeat);
|
||||
}
|
||||
|
||||
/*
|
||||
* unpack
|
||||
*
|
||||
* NOTE: unpack_setting_t of multiple IOs of the same function also are same,
|
||||
* so only the pointer of unpack_setting_t is stored in hio_t,
|
||||
* the life time of unpack_setting_t shoud be guaranteed by caller.
|
||||
*/
|
||||
void setUnpack(unpack_setting_t* setting) {
|
||||
if (io_ == NULL) return;
|
||||
hio_set_unpack(io_, setting);
|
||||
}
|
||||
|
||||
int startConnect(int port, const char* host = "127.0.0.1") {
|
||||
sockaddr_u peeraddr;
|
||||
memset(&peeraddr, 0, sizeof(peeraddr));
|
||||
int ret = sockaddr_set_ipport(&peeraddr, host, port);
|
||||
if (ret != 0) {
|
||||
// hloge("unknown host %s", host);
|
||||
return ret;
|
||||
}
|
||||
return startConnect(&peeraddr.sa);
|
||||
}
|
||||
|
||||
int startConnect(struct sockaddr* peeraddr) {
|
||||
if (io_ == NULL) return -1;
|
||||
hio_set_peeraddr(io_, peeraddr, SOCKADDR_LEN(peeraddr));
|
||||
return startConnect();
|
||||
}
|
||||
|
||||
int startConnect() {
|
||||
if (io_ == NULL) return -1;
|
||||
status = CONNECTING;
|
||||
hio_setcb_connect(io_, on_connect);
|
||||
return hio_connect(io_);
|
||||
}
|
||||
|
||||
bool isConnected() {
|
||||
return status == CONNECTED && isOpened();
|
||||
}
|
||||
|
||||
std::string localaddr() {
|
||||
if (io_ == NULL) return "";
|
||||
struct sockaddr* addr = hio_localaddr(io_);
|
||||
char buf[SOCKADDR_STRLEN] = {0};
|
||||
return SOCKADDR_STR(addr, buf);
|
||||
}
|
||||
|
||||
std::string peeraddr() {
|
||||
if (io_ == NULL) return "";
|
||||
struct sockaddr* addr = hio_peeraddr(io_);
|
||||
char buf[SOCKADDR_STRLEN] = {0};
|
||||
return SOCKADDR_STR(addr, buf);
|
||||
}
|
||||
|
||||
private:
|
||||
static void on_connect(hio_t* io) {
|
||||
SocketChannel* channel = (SocketChannel*)hio_context(io);
|
||||
if (channel) {
|
||||
channel->status = CONNECTED;
|
||||
if (channel->onconnect) {
|
||||
channel->onconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void send_heartbeat(hio_t* io) {
|
||||
SocketChannel* channel = (SocketChannel*)hio_context(io);
|
||||
if (channel && channel->heartbeat) {
|
||||
channel->heartbeat();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Channel> ChannelPtr;
|
||||
typedef std::shared_ptr<SocketChannel> SocketChannelPtr;
|
||||
|
||||
}
|
||||
|
||||
#endif // HV_CHANNEL_HPP_
|
Reference in New Issue
Block a user