Skip to content

Commit

Permalink
add examples. bug fix.
Browse files Browse the repository at this point in the history
  • Loading branch information
levalup committed Jul 8, 2024
1 parent caccddb commit 42eeda8
Show file tree
Hide file tree
Showing 23 changed files with 962 additions and 185 deletions.
84 changes: 47 additions & 37 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,28 @@
### New features

- Add `callback` method on handles.
- Use `callback` method to directly obtain callback for such as `async`, `check` or `timer`.
- Use `listen_callback` method to obtain the callback for stream's `listen`.
- You can set up handling functions independently before performing any work.
- This can be very useful when operations may involve multiple starts and stops.
- Use `callback` method to directly obtain callback for such as `async`, `check` or `timer`.
- Use `listen_callback` method to obtain the callback for stream's `listen`.
- You can set up handling functions independently before performing any work.
- This can be very useful when operations may involve multiple starts and stops.
- Add examples.
- `pipe`, `tcp` change state to `detached` after `connected`.
- This is an experimental feature and may be adjusted before the official release.

## Bug fix

- Fix the variable usage error in the `lib_t::open(string)` method.
- Fix `pipe_connect` forgot set data field.

## Break changes

- Change return value of `signal_t::start_oneshot`.
- `callback<int>` -> `promise<int>`
- `callback<int>` -> `promise<int>`
- Remove `acceptable_stream` abstract class layer.
- Practical experience proves that this abstraction layer does not significantly solve the problem of usability,
but also introduces some unnecessary complexity.
- Remove `stream_t::accept`.
- Overload the function in specific subtypes to avoid ambiguous semantics inherent in it.

--------------------------------

Expand All @@ -33,19 +41,19 @@
### New features

- Add CI workflows.
- Test latest ubuntu/windows gcc, clang and cl.
- Test classic GCC 4.8.5 with libuv 1.44.2.
- Test GCC 5, 6, 7, 8, 9, 10, 11, 12, latest.
- Test GCC with -std=11, 14, 17.
- Test MacOS with Xcode(Clang).
- Test MinGW.
- Test MSVC with /std:11, 14, 17.
- Test single header.
- Test latest ubuntu/windows gcc, clang and cl.
- Test classic GCC 4.8.5 with libuv 1.44.2.
- Test GCC 5, 6, 7, 8, 9, 10, 11, 12, latest.
- Test GCC with -std=11, 14, 17.
- Test MacOS with Xcode(Clang).
- Test MinGW.
- Test MSVC with /std:11, 14, 17.
- Test single header.

### Bug fix

- Fix the issue that the generated single header file may vary in different environments,
- which leads to compilation errors.
- which leads to compilation errors.

--------------------------------

Expand All @@ -57,29 +65,30 @@

- Tested and passed on gcc `4.8.5` with `libuv` `v1.44.2`.
- Enhanced the capabilities of `promise/callback`.
- It can properly handle movable but non-copyable objects.
- It supports passing references.
- It can properly handle movable but non-copyable objects.
- It supports passing references.
- Add `merge.py` to merge the code of uvcxx into a single header file.
- You can find `uvcxx-single.h` in the release package.
- You can find `uvcxx-single.h` in the release package.

### Bug fix

- Fix std::async UB with no policy in early C++ standard.
- Add `std::launch::async`.
- Add `std::launch::async`.

### Break changes

- The release of associated resources, such as `uv_fs_req_cleanup`, will be called before the `finally` of the `promise`.
- This adjustment is necessary for compilation on gcc `4.8.x`.
- Except for the deprecated usage, this modification has no impact in most scenarios.
- Bote: do not save related resources in the `then` function and use in `finally`.
- The release of associated resources, such as `uv_fs_req_cleanup`, will be called before the `finally` of
the `promise`.
- This adjustment is necessary for compilation on gcc `4.8.x`.
- Except for the deprecated usage, this modification has no impact in most scenarios.
- Bote: do not save related resources in the `then` function and use in `finally`.

- Add `status` check on `handle` callback and change callback type.
- `fs_event` start return `callback<const char *, uv_fs_event>`.
- `fs_poll` start return `callback<const uv_stat_t *, const uv_stat_t *>`.
- `poll` start return `callback<int>`.
- `stream` listen return `callback<>`.
- Handle status issue with `except<uvcxx::errcode>(...)`.
- `fs_event` start return `callback<const char *, uv_fs_event>`.
- `fs_poll` start return `callback<const uv_stat_t *, const uv_stat_t *>`.
- `poll` start return `callback<int>`.
- `stream` listen return `callback<>`.
- Handle status issue with `except<uvcxx::errcode>(...)`.

--------------------------------

Expand All @@ -90,12 +99,12 @@
### New features

- Cover about all APIs of `libuv`.
- Add `uv::os` wrapper for `uv_os_xxx`.
- Add most of miscellaneous utilities.
- Add `uv::os` wrapper for `uv_os_xxx`.
- Add most of miscellaneous utilities.
- Downwards to C++11, while keep compatibility to C++14 and C++17.
- The minimum GCC version tested is 5.4.
- CMAKE_CXX_STANDARD in (11 14 17), have passed the tests on MSVC (19.34), GCC (11), and Clang (15).
- More compatibility tests are pending.
- The minimum GCC version tested is 5.4.
- CMAKE_CXX_STANDARD in (11 14 17), have passed the tests on MSVC (19.34), GCC (11), and Clang (15).
- More compatibility tests are pending.

### Bug fix

Expand All @@ -122,7 +131,7 @@

### Break changes

- Removed some overloaded versions of `fs::read` and `fs::write`. Simplified by using `buffer_like` type.
- Removed some overloaded versions of `fs::read` and `fs::write`. Simplified by using `buffer_like` type.

--------------------------------

Expand All @@ -133,9 +142,9 @@
### New features

- Cover about `[97%]` APIs of `libuv`.
- Add `thread`, `cond`, `mutex`, `rwlock`, `sem`, `once` and `barrier`.
- Add `process`.
- Finish `fs`.
- Add `thread`, `cond`, `mutex`, `rwlock`, `sem`, `once` and `barrier`.
- Add `process`.
- Finish `fs`.
- Add scripts to calculate coverage and compatibility of `libuv`.
- Designed and implemented a more secure resource lifecycle management.
- Verified compilation in latest ubuntu `gcc` and `clang`, windows `msvc` and `mingw`.
Expand All @@ -162,7 +171,8 @@
### New features

- The inheritance relationship of objects is basically stable, but there are still some interfaces that need to be encapsulated, and the details of encapsulation may also change.
- The inheritance relationship of objects is basically stable, but there are still some interfaces that need to be
encapsulated, and the details of encapsulation may also change.

### Bug fix

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ The `handle` can continue to work without any external references, so that expli

See [lifecycle.md](docs/lifecycle.md) for more details.

**Be careful** not to capture the handle itself by value in the lambda of the callback function, unless you are very clear about the lifecycle of the handle.
Remember, it is always a good practice to explicitly call `close` at any time,
unless you are very clear about the lifecycle of the handle.

## 2. Compatibility

Expand Down
6 changes: 6 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ if (WALL)
endif ()
endif ()

if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
foreach (target ${TARGETS})
set_target_properties(${target} PROPERTIES OUTPUT_NAME "debug-${target}")
endforeach ()
endif ()

if (WERROR)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
foreach (target ${TARGETS})
Expand Down
89 changes: 89 additions & 0 deletions examples/pipe.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// Created by Levalup.
// L.eval: Let programmer get rid of only work jobs.
//

#include <iostream>

#include "uvcxx/pipe.h"
#include "uvcxx/buf.h"
#include "uvcxx/timer.h"
#include "uvcxx/utilities.h"

int main() {
// setting
std::string pipe_name = "a.pipe";
auto server_time_ms = 1000;

(void) std::remove(pipe_name.c_str());

uv::loop_t server_loop;
uv::loop_t client_loop;

// server
{
uv::pipe_t server(server_loop, false);
server.bind(pipe_name);

server.listen(128).call([=]() mutable {
auto conn = server.accept(false);

uv::buf_t server_buf;
conn.alloc().call([=](size_t size, uv_buf_t *buf) mutable {
server_buf.resize(size);
*buf = server_buf;
});
conn.read_start().call([=](ssize_t nread, const uv_buf_t *buf) mutable {
std::cout << "server read: " << std::string(buf->base, nread) << std::endl;
}).except<uvcxx::E_EAGAIN>([]() {
}).except<uvcxx::E_EOF>([=]() mutable {
conn.close(nullptr);
}).except([=]() mutable {
conn.close(nullptr);
});
}).except([=](const std::exception &e) {
std::cout << "[ERROR] listen named pipe " << pipe_name << " failed. " << e.what() << std::endl;
throw uvcxx::close_handle();
}).finally([=]() {
(void) std::remove(pipe_name.c_str());
});

std::cout << "[INFO] stop server after " << server_time_ms << "ms" << std::endl;
uv::timer_t(server_loop).start(server_time_ms, 1).call([=]() mutable {
server.close(nullptr);
throw uvcxx::close_handle(); // close timer
});
}

// client
for (int i = 0; i < 5; ++i) {
auto msg = uvcxx::catstr("hello~", i);

uv::pipe_t client(client_loop, false);
client.connect(pipe_name).then([=]() mutable {
client.write(msg).then([=]() {
std::cout << "client write: " << msg << std::endl;
}).finally([=]() mutable {
client.close(nullptr);
});
}).except([=]() mutable {
std::cout << "[ERROR] can not connect to " << pipe_name << std::endl;
client.close(nullptr);
});
}

auto server_run = std::async(std::launch::async, [&]() {
server_loop.run();
std::cout << "[INFO] server exit" << std::endl;
});

auto client_run = std::async(std::launch::async, [&]() {
client_loop.run();
std::cout << "[INFO] client exit" << std::endl;
});

server_run.wait();
client_run.wait();

return 0;
}
115 changes: 115 additions & 0 deletions examples/tcp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// Created by Levalup.
// L.eval: Let programmer get rid of only work jobs.
//

#include <iostream>

#include "uvcxx/cxx/sockaddr.h"
#include "uvcxx/tcp.h"
#include "uvcxx/buf.h"
#include "uvcxx/timer.h"
#include "uvcxx/utilities.h"

uvcxx::any_address_t getsockname(const uv::tcp_t &tcp) {
uvcxx::any_address_t name;
auto len = name.len();
(void) tcp.getsockname(name, &len);
return name;
}

uvcxx::any_address_t getpeername(const uv::tcp_t &tcp) {
uvcxx::any_address_t name;
auto len = name.len();
(void) tcp.getpeername(name, &len);
return name;
}

int main() {
// setting
std::string localhost = "127.0.0.1";
int port = 0;
auto server_time_ms = 1000;

uv::loop_t server_loop;
uv::loop_t client_loop;

// server
{
// make address support IPv4 and IPv6
auto addr = uvcxx::make_address("0.0.0.0", port);
// if work IPv4 only, simplify code as following
// uvcxx::IPv4 addr("0.0.0.0", port); // or uvcxx::IPv4(uvcxx::address_t::ANY, port);

uv::tcp_t server(server_loop);
server.bind(addr, 0);

auto server_sock = getsockname(server);
port = server_sock.port();

std::cout << "[INFO] server start listen: " << server_sock << std::endl;

server.listen(128).call([=]() mutable {
auto conn = server.accept(false);

std::cout << "[INFO] received [" << getsockname(conn) << " <- " << getpeername(conn) << "]" << std::endl;

uv::buf_t server_buf;
conn.alloc().call([=](size_t size, uv_buf_t *buf) mutable {
server_buf.resize(size);
*buf = server_buf;
});
conn.read_start().call([=](ssize_t nread, const uv_buf_t *buf) mutable {
std::cout << "server read: " << std::string(buf->base, nread) << std::endl;
}).except<uvcxx::E_EAGAIN>([]() {
}).except<uvcxx::E_EOF>([=]() mutable {
conn.close(nullptr);
}).except([=]() mutable {
conn.close(nullptr);
});
}).except([=](const std::exception &e) {
std::cout << "[ERROR] listen " << addr << " failed. " << e.what() << std::endl;
throw uvcxx::close_handle();
});

std::cout << "[INFO] stop server after " << server_time_ms << "ms" << std::endl;
uv::timer_t(server_loop).start(server_time_ms, 1).call([=]() mutable {
server.close(nullptr);
throw uvcxx::close_handle(); // close timer
});
}

// client
for (int i = 0; i < 5; ++i) {
auto addr = uvcxx::make_address(localhost, port);

auto msg = uvcxx::catstr("hello~", i);

uv::tcp_t client(client_loop, false);
client.connect(addr).then([=]() mutable {
client.write(msg).then([=]() {
std::cout << "client write: " << msg << std::endl;
}).finally([=]() mutable {
client.close(nullptr);
});
}).except([=]() mutable {
std::cout << "[ERROR] can not connect to " << addr << std::endl;
client.close(nullptr);
});
}

auto server_run = std::async(std::launch::async, [&]() {
server_loop.run();
std::cout << "[INFO] server exit" << std::endl;
});

auto client_run = std::async(std::launch::async, [&]() {
client_loop.run();
std::cout << "[INFO] client exit" << std::endl;
});

server_run.wait();
client_run.wait();

return 0;
}
Loading

0 comments on commit 42eeda8

Please sign in to comment.