Compare commits
278 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb15b5aa1b | ||
|
|
93476594ee | ||
|
|
04cb432e72 | ||
|
|
242838e3f3 | ||
|
|
0a993494e2 | ||
|
|
a3f2a6e3ac | ||
|
|
58b8b3d610 | ||
|
|
998a86975b | ||
|
|
6bb7a6f291 | ||
|
|
32f06f4fe8 | ||
|
|
f26fe9dea8 | ||
|
|
d5ea72a18a | ||
|
|
8b2aa01b3d | ||
|
|
35c840ab61 | ||
|
|
08350199e3 | ||
|
|
e774913db9 | ||
|
|
949e46642a | ||
|
|
3a8c06fe5b | ||
|
|
e4bb43bce7 | ||
|
|
3c57dd9a98 | ||
|
|
3754bfe088 | ||
|
|
cef9d850d8 | ||
|
|
04a7c36e7b | ||
|
|
9adfaf25ca | ||
|
|
8c10ef9de7 | ||
|
|
78e410dc1a | ||
|
|
258ddaed5f | ||
|
|
70572c4424 | ||
|
|
5be31bad4c | ||
|
|
d4f217f9f1 | ||
|
|
6e0fe7b8c6 | ||
|
|
2b4a0f158b | ||
|
|
34d2b00441 | ||
|
|
eb06aed649 | ||
|
|
7cb57e0c46 | ||
|
|
b771134121 | ||
|
|
dd63b4e225 | ||
|
|
b53cd6fd8b | ||
|
|
a4657c479d | ||
|
|
39c142fa56 | ||
|
|
a578b44788 | ||
|
|
21372c17e8 | ||
|
|
f70a0dbc2b | ||
|
|
fb2f8d9eff | ||
|
|
4d54eb946f | ||
|
|
98dd44b5eb | ||
|
|
7261037df8 | ||
|
|
0784a26081 | ||
|
|
a89a4155ea | ||
|
|
25feca605d | ||
|
|
4a1f1c6daa | ||
|
|
1678cdbddd | ||
|
|
a38f5452d8 | ||
|
|
44541bd1bd | ||
|
|
a4436b746e | ||
|
|
204e31d481 | ||
|
|
d32ddd2970 | ||
|
|
c64c538b6c | ||
|
|
63af166c32 | ||
|
|
4c9520165e | ||
|
|
ba10b27646 | ||
|
|
a497837cc9 | ||
|
|
f3414a0603 | ||
|
|
ed5b527559 | ||
|
|
b32fd63c83 | ||
|
|
683883b08a | ||
|
|
8830320c60 | ||
|
|
77b91ff98e | ||
|
|
dea293ffaa | ||
|
|
b004e1a808 | ||
|
|
3eaf8efc37 | ||
|
|
113772521d | ||
|
|
0c866baaf7 | ||
|
|
87e5440e00 | ||
|
|
9c88a9b352 | ||
|
|
36b586f7d3 | ||
|
|
d88bfcae87 | ||
|
|
7fda7c5072 | ||
|
|
14cb806b1c | ||
|
|
042da09665 | ||
|
|
18081ecb66 | ||
|
|
2da8140e2d | ||
|
|
def75703a4 | ||
|
|
426988b000 | ||
|
|
f86c810aea | ||
|
|
06f084d4ba | ||
|
|
8743dfc155 | ||
|
|
bd90d77bc7 | ||
|
|
5e4694abba | ||
|
|
f0ac08cb42 | ||
|
|
67acfdb53b | ||
|
|
cf0f8c6fd4 | ||
|
|
ac42b79b30 | ||
|
|
d84a031f32 | ||
|
|
e059473135 | ||
|
|
950aa6486e | ||
|
|
a3c179d089 | ||
|
|
220c4fe13b | ||
|
|
ec1f973bd4 | ||
|
|
6d771874a8 | ||
|
|
70697f4ae9 | ||
|
|
3636701fc2 | ||
|
|
b2ed37f5f5 | ||
|
|
1e4f964c47 | ||
|
|
68803053f4 | ||
|
|
36b9d189a1 | ||
|
|
897e83f66a | ||
|
|
efcd2a3858 | ||
|
|
324ca2ac32 | ||
|
|
64fb9fc8e5 | ||
|
|
684d912ca9 | ||
|
|
3db9e8f75a | ||
|
|
6243d3624a | ||
|
|
5664b04075 | ||
|
|
25b8fad800 | ||
|
|
1d3d6dd2dc | ||
|
|
2918b4e9ce | ||
|
|
9f8047d6d4 | ||
|
|
7326baf110 | ||
|
|
472245a8bd | ||
|
|
c8c2ccadd6 | ||
|
|
62511d77bc | ||
|
|
2f6be7b7ab | ||
|
|
cca65db1f4 | ||
|
|
fa83b0fb5e | ||
|
|
86fb93d0ef | ||
|
|
432c55de9b | ||
|
|
b388750a8d | ||
|
|
5876a2b11d | ||
|
|
a0f7be6825 | ||
|
|
1e6013d230 | ||
|
|
97c02c4f57 | ||
|
|
3d60ab1a6d | ||
|
|
a32596ed02 | ||
|
|
67a5eab44f | ||
|
|
775a7262f8 | ||
|
|
3ed391ab13 | ||
|
|
9f6bcee5be | ||
|
|
d2efc89796 | ||
|
|
437ab75068 | ||
|
|
aea6671b14 | ||
|
|
010d8de944 | ||
|
|
b0015be668 | ||
|
|
bf61f55dd3 | ||
|
|
83973cbc04 | ||
|
|
58b299ee60 | ||
|
|
d799a7fc85 | ||
|
|
2ea56b1dd1 | ||
|
|
6ed211328e | ||
|
|
e0e0be194e | ||
|
|
0156258c9b | ||
|
|
184488be25 | ||
|
|
60bd3aea38 | ||
|
|
41257c60f2 | ||
|
|
26973f335c | ||
|
|
6dd4a420f8 | ||
|
|
77af4a3fc4 | ||
|
|
6e5890921a | ||
|
|
13cbd81881 | ||
|
|
0c1a21e75c | ||
|
|
0e86ec5847 | ||
|
|
91ab230d81 | ||
|
|
112828c677 | ||
|
|
6b1651be7e | ||
|
|
a4a27cacff | ||
|
|
d2cc600e97 | ||
|
|
9ed3eaebd1 | ||
|
|
a77051e73a | ||
|
|
934851e3f5 | ||
|
|
c3e189c612 | ||
|
|
0b329720bf | ||
|
|
a10844d4bf | ||
|
|
52785475b9 | ||
|
|
1a794772b2 | ||
|
|
dc67c97ab2 | ||
|
|
f9056e732c | ||
|
|
60614d32b8 | ||
|
|
00d5c11e65 | ||
|
|
37aa1c8260 | ||
|
|
3a29890651 | ||
|
|
fb270887b4 | ||
|
|
e5870c79e1 | ||
|
|
fd52f76e4d | ||
|
|
3a02460be1 | ||
|
|
d35f557161 | ||
|
|
99e6ba7124 | ||
|
|
ff97bbbc9d | ||
|
|
3d9e45e733 | ||
|
|
991f5cdbb8 | ||
|
|
938b8af9b0 | ||
|
|
c0b9dc919b | ||
|
|
4a6289ecf7 | ||
|
|
ff0d29309a | ||
|
|
b2647468e2 | ||
|
|
8872af2d86 | ||
|
|
d611ca264f | ||
|
|
0ee7ef41fe | ||
|
|
03b98bc234 | ||
|
|
fc197b5117 | ||
|
|
8233a6e6b2 | ||
|
|
fda5b57f4f | ||
|
|
1f2b6ed23d | ||
|
|
4d92e354be | ||
|
|
fc50c60987 | ||
|
|
d9ab73a281 | ||
|
|
336e5dfb1d | ||
|
|
bfc4a2c95b | ||
|
|
53da326aea | ||
|
|
6fd64f93a0 | ||
|
|
216f5f4da1 | ||
|
|
fe73fa048a | ||
|
|
1f7d4acc40 | ||
|
|
008361d83c | ||
|
|
0fe8d7959b | ||
|
|
8d1a431f68 | ||
|
|
4afb5ebb20 | ||
|
|
0e36f685e8 | ||
|
|
ebc8199d42 | ||
|
|
3a32097dc8 | ||
|
|
855d851f47 | ||
|
|
55d7782af5 | ||
|
|
76f247847f | ||
|
|
da3b5f00f5 | ||
|
|
bc88511a29 | ||
|
|
1b6d9625e8 | ||
|
|
ba618cf070 | ||
|
|
3e6b09eb8d | ||
|
|
ed766f709a | ||
|
|
8f868995fc | ||
|
|
2cef4d6f20 | ||
|
|
7a8e526adf | ||
|
|
337bd035a8 | ||
|
|
3fae068b9b | ||
|
|
0890c29b7e | ||
|
|
852b9e2489 | ||
|
|
6dfe8f839a | ||
|
|
2cb056ec7b | ||
|
|
b117c6118b | ||
|
|
90affa4d51 | ||
|
|
866beeda31 | ||
|
|
8a8610a928 | ||
|
|
87e23c74b5 | ||
|
|
6f6294ebc2 | ||
|
|
3264417f15 | ||
|
|
ea4b6c84d0 | ||
|
|
749581309e | ||
|
|
6ce60d4088 | ||
|
|
6852f49401 | ||
|
|
af80bf5ef1 | ||
|
|
e59a989521 | ||
|
|
ff19fe0bc1 | ||
|
|
0186f0444c | ||
|
|
8a93cb6e31 | ||
|
|
529ebf3b49 | ||
|
|
aa43978b3e | ||
|
|
34042167eb | ||
|
|
1dc61d523d | ||
|
|
b127f58e41 | ||
|
|
00c19381fc | ||
|
|
6f5c43ae8e | ||
|
|
8349a74801 | ||
|
|
995603f6fe | ||
|
|
6b64e20161 | ||
|
|
c053e861e8 | ||
|
|
e9685cfbe7 | ||
|
|
78df87fddd | ||
|
|
b269d9cfa6 | ||
|
|
7c043fae5e | ||
|
|
8fbb39fd52 | ||
|
|
27dc68dd84 | ||
|
|
af3d06f3b4 | ||
|
|
183ebc0333 | ||
|
|
41913613c0 | ||
|
|
2167cddb01 | ||
|
|
ae8f5c81d4 | ||
|
|
c11d30ddba | ||
|
|
c0edac3cf3 | ||
|
|
a9bad602df |
41
.clang-format
Normal file
41
.clang-format
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
BasedOnStyle: llvm
|
||||||
|
---
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
ColumnLimit: 0
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '<[[:alnum:]_]+>'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '<(gtest|gmock)/'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '<[[:alnum:]_./]+>'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '<entt/'
|
||||||
|
Priority: 4
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 5
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentWidth: 4
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
Language: Cpp
|
||||||
|
PointerAlignment: Right
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceAroundPointerQualifiers: After
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCtorInitializerColon: false
|
||||||
|
SpaceBeforeInheritanceColon: false
|
||||||
|
SpaceBeforeParens: Never
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: false
|
||||||
|
Standard: Latest
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
12
.clang-tidy
Normal file
12
.clang-tidy
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Checks: >
|
||||||
|
bugprone-*,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
concurrency-*,
|
||||||
|
modernize-*,
|
||||||
|
-modernize-avoid-c-arrays,
|
||||||
|
-modernize-use-trailing-return-type,
|
||||||
|
performance-*,
|
||||||
|
portability-*,
|
||||||
|
CheckOptions:
|
||||||
|
- key: bugprone-suspicious-include.HeaderFileExtensions
|
||||||
|
value: ";h;hpp;ipp"
|
||||||
@ -13,7 +13,9 @@ def get_version():
|
|||||||
match = re.search(r'project\(uvw VERSION (.*)\)', content)
|
match = re.search(r'project\(uvw VERSION (.*)\)', content)
|
||||||
if match:
|
if match:
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
return os.getenv("TRAVIS_BRANCH", "master")
|
tag_version = os.getenv("GITHUB_REF")
|
||||||
|
package_version = tag_version.replace("refs/tags/v", "")
|
||||||
|
return package_version
|
||||||
|
|
||||||
def get_username():
|
def get_username():
|
||||||
return os.getenv("CONAN_USERNAME", "skypjack")
|
return os.getenv("CONAN_USERNAME", "skypjack")
|
||||||
@ -28,7 +30,7 @@ def get_reference():
|
|||||||
def get_upload():
|
def get_upload():
|
||||||
username = get_username()
|
username = get_username()
|
||||||
url = "https://api.bintray.com/conan/{}/conan".format(username)
|
url = "https://api.bintray.com/conan/{}/conan".format(username)
|
||||||
default_upload = url if os.getenv("TRAVIS_TAG") else False
|
default_upload = url if os.getenv("GITHUB_REF") else False
|
||||||
return os.getenv("CONAN_UPLOAD", default_upload)
|
return os.getenv("CONAN_UPLOAD", default_upload)
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +43,6 @@ if __name__ == "__main__":
|
|||||||
builder = ConanMultiPackager(reference=get_reference(),
|
builder = ConanMultiPackager(reference=get_reference(),
|
||||||
username=get_username(),
|
username=get_username(),
|
||||||
upload=get_upload(),
|
upload=get_upload(),
|
||||||
remotes="https://api.bintray.com/conan/bincrafters/public-conan",
|
|
||||||
test_folder=test_folder,
|
test_folder=test_folder,
|
||||||
stable_branch_pattern=r'v?\d+\.\d+\.\d+.*',
|
stable_branch_pattern=r'v?\d+\.\d+\.\d+.*',
|
||||||
upload_only_when_stable=upload_when_stable())
|
upload_only_when_stable=upload_when_stable())
|
||||||
|
|||||||
@ -4,8 +4,6 @@
|
|||||||
import os
|
import os
|
||||||
from conans import ConanFile, CMake
|
from conans import ConanFile, CMake
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestPackageConan(ConanFile):
|
class TestPackageConan(ConanFile):
|
||||||
settings = "os", "compiler", "build_type", "arch"
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
generators = "cmake"
|
generators = "cmake"
|
||||||
|
|||||||
@ -3,14 +3,14 @@
|
|||||||
#include <uvw.hpp>
|
#include <uvw.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
void listen(uvw::Loop &loop) {
|
void listen(uvw::loop &loop) {
|
||||||
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>();
|
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
|
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
||||||
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
|
std::shared_ptr<uvw::tcp_handle> client = srv.loop().resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
client->on<uvw::CloseEvent>([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::TCPHandle &) { ptr->close(); });
|
client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
|
||||||
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); });
|
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
||||||
|
|
||||||
srv.accept(*client);
|
srv.accept(*client);
|
||||||
client->read();
|
client->read();
|
||||||
@ -20,12 +20,12 @@ void listen(uvw::Loop &loop) {
|
|||||||
tcp->listen();
|
tcp->listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void conn(uvw::Loop &loop) {
|
void conn(uvw::loop &loop) {
|
||||||
auto tcp = loop.resource<uvw::TCPHandle>();
|
auto tcp = loop.resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* handle errors */ });
|
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
|
||||||
|
|
||||||
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &tcp) {
|
tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
|
||||||
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
|
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
|
||||||
tcp.write(std::move(dataWrite), 2);
|
tcp.write(std::move(dataWrite), 2);
|
||||||
tcp.close();
|
tcp.close();
|
||||||
@ -36,7 +36,7 @@ void conn(uvw::Loop &loop) {
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << "Getting UVW loop ...\n";
|
std::cout << "Getting UVW loop ...\n";
|
||||||
auto loop = uvw::Loop::getDefault();
|
auto loop = uvw::loop::get_default();
|
||||||
std::cout << "Staring UVW listener ...\n";
|
std::cout << "Staring UVW listener ...\n";
|
||||||
listen(*loop);
|
listen(*loop);
|
||||||
std::cout << "Connecting ...\n";
|
std::cout << "Connecting ...\n";
|
||||||
|
|||||||
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: skypjack
|
||||||
|
patreon:
|
||||||
|
open_collective:
|
||||||
|
ko_fi:
|
||||||
|
tidelift:
|
||||||
|
community_bridge:
|
||||||
|
liberapay:
|
||||||
|
issuehunt:
|
||||||
|
otechie:
|
||||||
|
custom: https://www.paypal.me/skypjack
|
||||||
21
.github/workflows/build-macos.yml
vendored
Normal file
21
.github/workflows/build-macos.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: build-macos
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
macos:
|
||||||
|
timeout-minutes: 60
|
||||||
|
runs-on: macOS-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cmake ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF ..
|
||||||
|
make -j2
|
||||||
25
.github/workflows/build-meson.yml
vendored
Normal file
25
.github/workflows/build-meson.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: build-meson
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
meson:
|
||||||
|
timeout-minutes: 60
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Meson
|
||||||
|
env:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
run: |
|
||||||
|
sudo apt-get update --fix-missing
|
||||||
|
sudo apt-get install -y meson
|
||||||
|
- name: Meson Build (shared)
|
||||||
|
run: |
|
||||||
|
meson setup build
|
||||||
|
meson compile -C build
|
||||||
|
- name: Meson Build (static)
|
||||||
|
run: |
|
||||||
|
rm -rf build/
|
||||||
|
meson setup build --default-library=static
|
||||||
|
meson compile -C build
|
||||||
39
.github/workflows/build-ubuntu-20.04.yml
vendored
Normal file
39
.github/workflows/build-ubuntu-20.04.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
name: build-ubuntu-20.04
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
linux:
|
||||||
|
timeout-minutes: 60
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler:
|
||||||
|
- { pkg: g++, exe: 'g++', version: 7 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 8 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 9 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 8 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 9 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 10 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 11 }
|
||||||
|
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||||
|
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install ${{ matrix.compiler.exe }}
|
||||||
|
run: |
|
||||||
|
sudo apt-get update --fix-missing
|
||||||
|
sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }}
|
||||||
|
- name: Compile tests
|
||||||
|
env:
|
||||||
|
CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }}
|
||||||
|
run: |
|
||||||
|
cmake ${{ matrix.mode }} --preset ci-ubuntu
|
||||||
|
cmake --build build/ --parallel 2
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 5 -C Debug -j2
|
||||||
38
.github/workflows/build-ubuntu-latest.yml
vendored
Normal file
38
.github/workflows/build-ubuntu-latest.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: build-ubuntu-latest
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
linux:
|
||||||
|
timeout-minutes: 60
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler:
|
||||||
|
- { pkg: g++, exe: 'g++', version: 10 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 11 }
|
||||||
|
- { pkg: g++, exe: 'g++', version: 12 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 12 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 13 }
|
||||||
|
- { pkg: clang, exe: 'clang++', version: 14 }
|
||||||
|
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install ${{ matrix.compiler.exe }}
|
||||||
|
run: |
|
||||||
|
sudo apt-get update --fix-missing
|
||||||
|
sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }}
|
||||||
|
- name: Compile tests
|
||||||
|
env:
|
||||||
|
CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }}
|
||||||
|
run: |
|
||||||
|
cmake ${{ matrix.mode }} --preset ci-ubuntu
|
||||||
|
cmake --build build/ --parallel 2
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 5 -C Debug -j2
|
||||||
22
.github/workflows/build-win.yml
vendored
Normal file
22
.github/workflows/build-win.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
name: build-win
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
windows:
|
||||||
|
timeout-minutes: 60
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
generator: [Visual Studio 17 2022]
|
||||||
|
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cmake -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF -DCMAKE_CXX_FLAGS=/W1 -G"${{ matrix.generator }}" ..
|
||||||
|
cmake --build . -j 2
|
||||||
33
.github/workflows/coverage.yml
vendored
Normal file
33
.github/workflows/coverage.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
name: coverage
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
codecov:
|
||||||
|
timeout-minutes: 30
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CXXFLAGS: "-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline"
|
||||||
|
CXX: g++
|
||||||
|
run: |
|
||||||
|
cmake -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF ..
|
||||||
|
make -j4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 5 -C Debug -j4
|
||||||
|
- name: Upload coverage to Codecov
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
run: |
|
||||||
|
wget https://codecov.io/bash -O codecov
|
||||||
|
chmod +x codecov
|
||||||
|
./codecov -t $CODECOV_TOKEN -B $GITHUB_REF -s .
|
||||||
32
.github/workflows/deploy.yml
vendored
Normal file
32
.github/workflows/deploy.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
conan:
|
||||||
|
timeout-minutes: 5
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: docker://conanio/gcc8
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@master
|
||||||
|
with:
|
||||||
|
version: 3.7
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
pip install --upgrade wheel
|
||||||
|
pip install conan_package_tools
|
||||||
|
- name: Deploy
|
||||||
|
env:
|
||||||
|
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
|
||||||
|
CONAN_PASSWORD: ${{ secrets.CONAN_PASSWORD }}
|
||||||
|
CONAN_UPLOAD: ${{ secrets.CONAN_UPLOAD }}
|
||||||
|
CONAN_GCC_VERSIONS: 8
|
||||||
|
run: |
|
||||||
|
python .conan/build.py
|
||||||
30
.github/workflows/sanitizer.yml
vendored
Normal file
30
.github/workflows/sanitizer.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
name: sanitizer
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
clang:
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler: [clang++]
|
||||||
|
sanitizer: [ASAN, UBSAN]
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CXX: ${{ matrix.compiler }}
|
||||||
|
run: |
|
||||||
|
cmake ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -DUVW_USE_${{ matrix.sanitizer }}=ON -Dlibuv_buildtests=OFF ..
|
||||||
|
make -j2
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest --timeout 5 -C Debug -j2
|
||||||
78
.github/workflows/tools.yml
vendored
Normal file
78
.github/workflows/tools.yml
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
name: tools
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- tools
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
iwyu:
|
||||||
|
timeout-minutes: 60
|
||||||
|
|
||||||
|
env:
|
||||||
|
IWYU: "0.22"
|
||||||
|
LLVM: "18"
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install llvm/clang
|
||||||
|
# see: https://apt.llvm.org/
|
||||||
|
run: |
|
||||||
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
|
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM main"
|
||||||
|
sudo apt update
|
||||||
|
sudo apt remove -y "llvm*"
|
||||||
|
sudo apt remove -y "libclang-dev*"
|
||||||
|
sudo apt remove -y "clang*"
|
||||||
|
sudo apt install -y llvm-$LLVM-dev
|
||||||
|
sudo apt install -y libclang-$LLVM-dev
|
||||||
|
sudo apt install -y clang-$LLVM
|
||||||
|
- name: Compile iwyu
|
||||||
|
# see: https://github.com/include-what-you-use/include-what-you-use
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/include-what-you-use/include-what-you-use.git --branch $IWYU --depth 1
|
||||||
|
mkdir include-what-you-use/build
|
||||||
|
cd include-what-you-use/build
|
||||||
|
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=./ \
|
||||||
|
..
|
||||||
|
make -j4
|
||||||
|
bin/include-what-you-use --version
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
export PATH=$PATH:${GITHUB_WORKSPACE}/build/include-what-you-use/build/bin
|
||||||
|
cmake -DUVW_BUILD_TESTING=ON \
|
||||||
|
-Dlibuv_buildtests=OFF \
|
||||||
|
-DCMAKE_C_COMPILER=clang-$LLVM \
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||||
|
-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/uvw.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" \
|
||||||
|
..
|
||||||
|
make -j4
|
||||||
|
|
||||||
|
clang-tidy:
|
||||||
|
timeout-minutes: 60
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Compile tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CXX: clang++
|
||||||
|
run: |
|
||||||
|
cmake -DUVW_BUILD_TESTING=ON -DUVW_USE_CLANG_TIDY=ON -Dlibuv_buildtests=OFF ..
|
||||||
|
make -j4
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: build
|
||||||
|
env:
|
||||||
|
CTEST_OUTPUT_ON_FAILURE: 1
|
||||||
|
run: ctest -C Debug -j4
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,2 +1,9 @@
|
|||||||
*.user
|
*.user
|
||||||
|
CMakeSettings.json
|
||||||
.conan/test_package/build
|
.conan/test_package/build
|
||||||
|
cmake-build-debug/
|
||||||
|
.idea/
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
.cache/
|
||||||
|
out/
|
||||||
|
|||||||
71
.travis.yml
71
.travis.yml
@ -1,71 +0,0 @@
|
|||||||
language: cpp
|
|
||||||
dist: trusty
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: linux
|
|
||||||
compiler: gcc
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
|
||||||
packages: ['g++-6']
|
|
||||||
env: COMPILER=g++-6
|
|
||||||
- os: linux
|
|
||||||
compiler: clang
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0']
|
|
||||||
packages: ['clang-4.0', 'libstdc++-4.9-dev']
|
|
||||||
env: COMPILER=clang++-4.0
|
|
||||||
- os: osx
|
|
||||||
osx_image: xcode8.3
|
|
||||||
compiler: clang
|
|
||||||
env: COMPILER=clang++
|
|
||||||
- os: linux
|
|
||||||
compiler: gcc
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
|
||||||
packages: ['g++-6']
|
|
||||||
env:
|
|
||||||
- C_COMPILER=gcc-6
|
|
||||||
- COMPILER=g++-6
|
|
||||||
- CXXFLAGS="-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline"
|
|
||||||
before_script:
|
|
||||||
- pip install --user cpp-coveralls
|
|
||||||
after_success:
|
|
||||||
- coveralls --gcov gcov-6 --gcov-options '\-lp' --root ${TRAVIS_BUILD_DIR} --build-root ${TRAVIS_BUILD_DIR}/build --extension cpp --extension hpp --exclude deps --include src
|
|
||||||
- os: linux
|
|
||||||
dist: xenial
|
|
||||||
sudo: true
|
|
||||||
language: python
|
|
||||||
python: "3.7"
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
env:
|
|
||||||
- CONAN_GCC_VERSIONS=8
|
|
||||||
- CONAN_DOCKER_IMAGE=conanio/gcc8
|
|
||||||
install:
|
|
||||||
- pip install conan_package_tools
|
|
||||||
script:
|
|
||||||
- python .conan/build.py
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
on_success: never
|
|
||||||
on_failure: always
|
|
||||||
|
|
||||||
install:
|
|
||||||
- echo ${PATH}
|
|
||||||
- cmake --version
|
|
||||||
- export CC=${C_COMPILER}
|
|
||||||
- export CXX=${COMPILER}
|
|
||||||
- echo ${CXX}
|
|
||||||
- ${CXX} --version
|
|
||||||
- ${CXX} -v
|
|
||||||
|
|
||||||
script:
|
|
||||||
- mkdir -p build && cd build
|
|
||||||
- cmake .. -DBUILD_TESTING=ON && make -j4
|
|
||||||
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j4 -R uvw
|
|
||||||
40
AUTHORS
40
AUTHORS
@ -1,27 +1,29 @@
|
|||||||
# Author
|
# Author
|
||||||
|
|
||||||
Michele Caini aka skypjack
|
skypjack
|
||||||
|
|
||||||
# Collaborators
|
# Collaborators
|
||||||
|
|
||||||
Paolo Monteverde aka morbo84
|
morbo84
|
||||||
|
stefanofiorentino
|
||||||
|
|
||||||
# Contributors
|
# Contributors
|
||||||
|
|
||||||
Federico Bertolucci aka lessness
|
lessness
|
||||||
Luca Martini aka lordlukas
|
lordlukas
|
||||||
Elia Mazzuoli aka Zikoel
|
lpmi-13
|
||||||
Francesco De Felice aka fradefe
|
Zikoel
|
||||||
Tushar Maheshwari aka tusharpm
|
fradefe
|
||||||
Jan Vcelak aka fcelda
|
tusharpm
|
||||||
Raoul Hecky aka raoul
|
fcelda
|
||||||
Daniel Filonik aka filonik
|
raoul
|
||||||
Wojciech Bartnik aka yisonPylkita
|
filonik
|
||||||
Miigon aka Miigon
|
yisonPylkita
|
||||||
Slyshyk Oleksiy aka slyshykO
|
Miigon
|
||||||
bmagistro aka bmagistro
|
slyshykO
|
||||||
Richard Caseres aka richardbmx
|
bmagistro
|
||||||
|
richardbmx
|
||||||
# Special thanks for patrons
|
wnsgml972
|
||||||
|
ffontaine
|
||||||
Arn aka ArnCarveris
|
elindsey
|
||||||
|
erez-o
|
||||||
|
|||||||
292
CMakeLists.txt
292
CMakeLists.txt
@ -2,7 +2,7 @@
|
|||||||
# uvw
|
# uvw
|
||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Building in-tree is not allowed (we take care of your craziness).
|
# Building in-tree is not allowed (we take care of your craziness).
|
||||||
@ -15,138 +15,250 @@ endif()
|
|||||||
#
|
#
|
||||||
# Project configuration
|
# Project configuration
|
||||||
#
|
#
|
||||||
|
set(UVW_VERSION_MAJOR 3)
|
||||||
|
set(UVW_VERSION_MINOR 5)
|
||||||
|
set(UVW_VERSION_PATCH 0)
|
||||||
|
|
||||||
project(uvw VERSION 1.11.3)
|
project(
|
||||||
|
uvw
|
||||||
|
VERSION ${UVW_VERSION_MAJOR}.${UVW_VERSION_MINOR}.${UVW_VERSION_PATCH}
|
||||||
|
DESCRIPTION "Header-only, event based, tiny and easy to use libuv wrapper in modern C++ - now available also as static library!"
|
||||||
|
HOMEPAGE_URL "https://github.com/skypjack/uvw"
|
||||||
|
LANGUAGES C CXX
|
||||||
|
)
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE Debug)
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(PROJECT_AUTHOR "Michele Caini")
|
option(UVW_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." ON)
|
||||||
set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
|
option(UVW_USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF)
|
||||||
|
option(UVW_USE_UBSAN "Use address sanitizer by adding -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer flags" OFF)
|
||||||
|
option(UVW_USE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF)
|
||||||
|
option(UVW_BUILD_LIBS "Prepare targets for static library rather than for a header-only library." OFF)
|
||||||
|
option(UVW_BUILD_SHARED_LIB "Prepare targets for shared library rather than for a header-only library." OFF)
|
||||||
|
option(UVW_FIND_LIBUV "Try finding libuv library development files in the system" OFF)
|
||||||
|
|
||||||
message("*")
|
if(UVW_BUILD_SHARED_LIB)
|
||||||
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
set(UVW_BUILD_LIBS BOOL:ON)
|
||||||
message("* Copyright (c) 2016-2018 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
|
|
||||||
message("*")
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
if(NOT MSVC)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -DDEBUG")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -DRELEASE")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# CMake configuration
|
# Compiler stuff
|
||||||
#
|
#
|
||||||
|
|
||||||
set(PROJECT_CMAKE_IN ${uvw_SOURCE_DIR}/cmake/in)
|
if(NOT WIN32 AND UVW_USE_LIBCPP)
|
||||||
set(PROJECT_DEPS_DIR ${uvw_SOURCE_DIR}/deps)
|
include(CheckCXXSourceCompiles)
|
||||||
set(PROJECT_SRC_DIR ${uvw_SOURCE_DIR}/src)
|
include(CMakePushCheckState)
|
||||||
|
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
|
cmake_push_check_state()
|
||||||
|
|
||||||
#
|
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||||
# Referenced packages
|
|
||||||
#
|
|
||||||
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
check_cxx_source_compiles("
|
||||||
|
#include<type_traits>
|
||||||
|
int main() { return std::is_same_v<int, char>; }
|
||||||
|
" UVW_HAS_LIBCPP)
|
||||||
|
|
||||||
include(FindThreads)
|
if(NOT UVW_HAS_LIBCPP)
|
||||||
find_package(Doxygen 1.8)
|
message(WARNING "The option UVW_USE_LIBCPP is set (by default) but libc++ is not available. The flag will not be added to the target.")
|
||||||
|
endif()
|
||||||
|
|
||||||
#
|
cmake_pop_check_state()
|
||||||
# Referenced directories and targets
|
|
||||||
#
|
|
||||||
|
|
||||||
if(DOXYGEN_FOUND)
|
|
||||||
add_subdirectory(docs)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
if(UVW_USE_CLANG_TIDY)
|
||||||
set(BUILD_TESTING OFF)
|
find_program(UVW_CLANG_TIDY_EXECUTABLE "clang-tidy")
|
||||||
|
|
||||||
set(GOOGLETEST_DEPS_DIR ${PROJECT_DEPS_DIR}/googletest)
|
if(NOT UVW_CLANG_TIDY_EXECUTABLE)
|
||||||
set(LIBUV_DEPS_DIR ${PROJECT_DEPS_DIR}/libuv)
|
message(VERBOSE "The option UVW_USE_CLANG_TIDY is set but clang-tidy executable is not available.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
configure_file(${PROJECT_CMAKE_IN}/deps.in ${PROJECT_DEPS_DIR}/CMakeLists.txt)
|
# Required minimal libuv version
|
||||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${PROJECT_DEPS_DIR})
|
set(UVW_LIBUV_VERSION 1.49.0)
|
||||||
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${PROJECT_DEPS_DIR})
|
|
||||||
|
|
||||||
# gtest, gtest_main, gmock and gmock_main targets are available from now on
|
function(fetch_libuv)
|
||||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
if (UVW_FETCH_LIBUV)
|
||||||
add_subdirectory(${GOOGLETEST_DEPS_DIR})
|
include(FetchContent)
|
||||||
|
|
||||||
# uv and uv_a targets are available from now on
|
FetchContent_Declare(
|
||||||
add_subdirectory(${LIBUV_DEPS_DIR})
|
libuv
|
||||||
include_directories(${LIBUV_DEPS_DIR}/include)
|
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
||||||
|
GIT_TAG "v${UVW_LIBUV_VERSION}"
|
||||||
|
GIT_SHALLOW 1
|
||||||
|
)
|
||||||
|
|
||||||
set(BUILD_TESTING ON)
|
FetchContent_GetProperties(libuv)
|
||||||
enable_testing()
|
|
||||||
|
|
||||||
add_subdirectory(test)
|
if(NOT libuv_POPULATED)
|
||||||
|
FetchContent_Populate(libuv)
|
||||||
|
add_subdirectory(${libuv_SOURCE_DIR} ${libuv_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UVW_BUILD_SHARED_LIB)
|
||||||
|
add_library(uv::uv-shared ALIAS uv)
|
||||||
|
set_target_properties(uv PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||||
|
else()
|
||||||
|
add_library(uv::uv-static ALIAS uv_a)
|
||||||
|
set_target_properties(uv_a PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||||
|
endif()
|
||||||
|
endif(UVW_FETCH_LIBUV)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(use_libuv)
|
||||||
|
set(UVW_FETCH_LIBUV_DEFAULT ON)
|
||||||
|
|
||||||
|
if (UVW_FIND_LIBUV)
|
||||||
|
find_package(libuv ${LIBUV_VERSION} QUIET)
|
||||||
|
if (libuv_FOUND)
|
||||||
|
add_library(uv::uv-shared ALIAS uv)
|
||||||
|
set(UVW_FETCH_LIBUV_DEFAULT OFF)
|
||||||
|
message(STATUS "libuv ${libuv_VERSION} found via cmake")
|
||||||
|
else(libuv_FOUND)
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if (PkgConfig_FOUND)
|
||||||
|
pkg_check_modules(libuv IMPORTED_TARGET libuv>=${LIBUV_VERSION})
|
||||||
|
if (libuv_FOUND)
|
||||||
|
add_library(uv::uv-shared ALIAS PkgConfig::libuv)
|
||||||
|
set(UVW_FETCH_LIBUV_DEFAULT OFF)
|
||||||
|
message(STATUS "libuv ${libuv_VERSION} found via pkg-config")
|
||||||
|
endif(libuv_FOUND)
|
||||||
|
endif(PkgConfig_FOUND)
|
||||||
|
endif(libuv_FOUND)
|
||||||
|
endif(UVW_FIND_LIBUV)
|
||||||
|
|
||||||
|
option(UVW_FETCH_LIBUV "Fetch the libuv repo using CMake FetchContent facility" ${UVW_FETCH_LIBUV_DEFAULT})
|
||||||
|
|
||||||
|
fetch_libuv()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add uvw target
|
||||||
|
#
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
if(UVW_BUILD_LIBS)
|
||||||
|
use_libuv()
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
file(GLOB HEADERS src/uvw/*.h src/uvw/*.hpp)
|
||||||
|
else()
|
||||||
|
add_library(uvw INTERFACE)
|
||||||
|
add_library(uvw::uvw ALIAS uvw)
|
||||||
|
|
||||||
|
target_compile_features(uvw INTERFACE cxx_std_17)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
uvw
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${uvw_SOURCE_DIR}/src>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UVW_USE_ASAN)
|
||||||
|
target_compile_options(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||||
|
target_link_libraries(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=address>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UVW_USE_UBSAN)
|
||||||
|
target_compile_options(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer>)
|
||||||
|
target_link_libraries(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=undefined>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UVW_CLANG_TIDY_EXECUTABLE)
|
||||||
|
set(CMAKE_CXX_CLANG_TIDY "${UVW_CLANG_TIDY_EXECUTABLE};--config-file=${uvw_SOURCE_DIR}/.clang-tidy;--header-filter=${uvw_SOURCE_DIR}/src/uvw/.*")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UVW_HAS_LIBCPP)
|
||||||
|
target_compile_options(uvw BEFORE INTERFACE -stdlib=libc++)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(GLOB HEADERS src/uvw/*.h src/uvw/*.hpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Keep your stuff and go further away, foolish.
|
# Install targets
|
||||||
#
|
#
|
||||||
|
|
||||||
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
|
|
||||||
set(CPACK_PACKAGE_VENDOR ${PROJECT_AUTHOR})
|
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
|
||||||
set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
|
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_NAME})
|
|
||||||
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION})
|
|
||||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME}-src)
|
|
||||||
set(CPACK_RESOURCE_FILE_LICENSE ${uvw_SOURCE_DIR}/LICENSE)
|
|
||||||
set(CPACK_RESOURCE_FILE_README ${uvw_SOURCE_DIR}/README.md)
|
|
||||||
set(CPACK_GENERATOR TGZ)
|
|
||||||
set(CPACK_SOURCE_GENERATOR TGZ)
|
|
||||||
set(CPACK_PACKAGING_INSTALL_DIRECTORY "uvw-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
|
||||||
|
|
||||||
include(CPack)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Install headers
|
|
||||||
#
|
|
||||||
|
|
||||||
INCLUDE(GNUInstallDirs)
|
|
||||||
|
|
||||||
IF(NOT DEFINED INCLUDE_INSTALL_DIR)
|
|
||||||
SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
file(GLOB HEADERS src/uvw/*.hpp)
|
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES ${HEADERS}
|
FILES ${HEADERS}
|
||||||
COMPONENT ${PROJECT_NAME}
|
COMPONENT ${PROJECT_NAME}
|
||||||
DESTINATION ${INCLUDE_INSTALL_DIR}/uvw
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/uvw
|
||||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES src/uvw.hpp
|
FILES src/uvw.hpp
|
||||||
COMPONENT ${PROJECT_NAME}
|
COMPONENT ${PROJECT_NAME}
|
||||||
DESTINATION ${INCLUDE_INSTALL_DIR}
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
# AOB
|
# Install targets
|
||||||
#
|
#
|
||||||
|
|
||||||
add_custom_target(
|
if (UVW_BUILD_LIBS)
|
||||||
uvw_aob
|
set_target_properties(
|
||||||
SOURCES
|
uvw PROPERTIES
|
||||||
appveyor.yml
|
VERSION ${UVW_VERSION_MAJOR}.${UVW_VERSION_MINOR}.${UVW_VERSION_PATCH}
|
||||||
AUTHORS
|
SOVERSION ${UVW_VERSION_MAJOR}
|
||||||
LICENSE
|
)
|
||||||
README.md
|
endif()
|
||||||
.travis.yml
|
|
||||||
|
install(
|
||||||
|
EXPORT uvwConfig
|
||||||
|
NAMESPACE uvw::
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/uvw
|
||||||
)
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS uvw
|
||||||
|
EXPORT uvwConfig
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UVW_FETCH_LIBUV AND UVW_BUILD_LIBS)
|
||||||
|
# libuv is only fetched when both above conditions are true
|
||||||
|
install(DIRECTORY ${libuv_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/uvw/uv/include)
|
||||||
|
if (UVW_BUILD_SHARED_LIB)
|
||||||
|
install(TARGETS uv EXPORT uvwConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/uvw)
|
||||||
|
else()
|
||||||
|
install(TARGETS uv_a EXPORT uvwConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/uvw)
|
||||||
|
endif()
|
||||||
|
endif(UVW_FETCH_LIBUV AND UVW_BUILD_LIBS)
|
||||||
|
|
||||||
|
export(EXPORT uvwConfig)
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
option(UVW_BUILD_TESTING "Enable testing with ctest." OFF)
|
||||||
|
|
||||||
|
if(UVW_BUILD_TESTING)
|
||||||
|
option(UVW_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
|
||||||
|
|
||||||
|
if (NOT UVW_BUILD_LIBS)
|
||||||
|
use_libuv()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
option(UVW_BUILD_DOCS "Enable building with documentation." OFF)
|
||||||
|
|
||||||
|
if(UVW_BUILD_DOCS)
|
||||||
|
find_package(Doxygen 1.10)
|
||||||
|
|
||||||
|
if(DOXYGEN_FOUND)
|
||||||
|
add_subdirectory(docs)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|||||||
59
CMakePresets.json
Normal file
59
CMakePresets.json
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 13,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "cmake-pedantic",
|
||||||
|
"description": "Enables all CMake warnings.`",
|
||||||
|
"hidden": true,
|
||||||
|
"warnings": {
|
||||||
|
"dev": true,
|
||||||
|
"deprecated": true,
|
||||||
|
"uninitialized": true,
|
||||||
|
"unusedCli": true,
|
||||||
|
"systemVars": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dev-mode",
|
||||||
|
"hidden": true,
|
||||||
|
"description": "Common (non-OS specific) mode for development",
|
||||||
|
"inherits": "cmake-pedantic",
|
||||||
|
"cacheVariables": {
|
||||||
|
"UVW_BUILD_TESTING": true,
|
||||||
|
"libuv_buildtests": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flags-linux",
|
||||||
|
"hidden": true,
|
||||||
|
"description": "Compiler flags for GNU and Clang compilers. When compiling in DEBUG mode, all warnings will be converted into errors.",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wimplicit-fallthrough -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast",
|
||||||
|
"CMAKE_CXX_FLAGS_DEBUG": "-Werror"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-linux",
|
||||||
|
"generator": "Unix Makefiles",
|
||||||
|
"hidden": true,
|
||||||
|
"inherits": ["flags-linux"],
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-build",
|
||||||
|
"binaryDir": "${sourceDir}/build",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-ubuntu",
|
||||||
|
"inherits": ["ci-build", "ci-linux", "dev-mode"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2016-2018 Michele Caini
|
Copyright (c) 2016-2024 Michele Caini
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
397
README.md
397
README.md
@ -1,27 +1,34 @@
|
|||||||

|

|
||||||
|
|
||||||
<!--
|
[](https://github.com/skypjack/uvw/actions)
|
||||||
@cond TURN_OFF_DOXYGEN
|
[](https://codecov.io/gh/skypjack/uvw)
|
||||||
-->
|
[](https://skypjack.github.io/uvw/)
|
||||||
[](https://travis-ci.org/skypjack/uvw)
|
[](https://vcpkg.link/ports/uvw)
|
||||||
[](https://ci.appveyor.com/project/skypjack/uvw)
|
|
||||||
[](https://coveralls.io/github/skypjack/uvw?branch=master)
|
|
||||||
[](https://bintray.com/skypjack/conan/uvw%3Askypjack/_latestVersion)
|
|
||||||
[](https://gitter.im/skypjack/uvw)
|
[](https://gitter.im/skypjack/uvw)
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=W2HF9FESD5LJY&lc=IT&item_name=Michele%20Caini¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted)
|
[](https://www.paypal.me/skypjack)
|
||||||
|
|
||||||
[](https://www.patreon.com/bePatron?u=11330786)
|
Do you have a **question** that doesn't require you to open an issue? Join the
|
||||||
|
[gitter channel](https://gitter.im/skypjack/uvw).<br/>
|
||||||
<!--
|
If you use `uvw` and you want to say thanks or support the project, please
|
||||||
@endcond TURN_OFF_DOXYGEN
|
**consider becoming a
|
||||||
-->
|
[sponsor](https://github.com/users/skypjack/sponsorship)**.<br/>
|
||||||
|
You can help me make the difference.
|
||||||
|
[Many thanks](https://skypjack.github.io/sponsorship/) to those who supported me
|
||||||
|
and still support me today.
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
`uvw` is a header-only, event based, tiny and easy to use *libuv* wrapper in modern C++.<br/>
|
`uvw` started as a header-only, event based, tiny and easy to use wrapper for
|
||||||
The basic idea is to hide completely the *C-ish* interface of *libuv* behind a graceful C++ API. Currently, no `uv_*_t` data structure is actually exposed by the library.<br/>
|
[`libuv`](https://github.com/libuv/libuv) written in modern C++.<br/>
|
||||||
Note that `uvw` stays true to the API of *libuv* and it doesn't add anything to its interface. For the same reasons, users of the library must follow the same rules who are used to follow with *libuv*.<br/>
|
Now it's finally available also as a compilable static library.
|
||||||
As an example, a *handle* should be initialized before any other operation and closed once it is no longer in use.
|
|
||||||
|
The basic idea is to wrap the *C-ish* interface of `libuv` behind a graceful C++
|
||||||
|
API.<br/>
|
||||||
|
Note that `uvw` stays true to the API of `libuv` and it doesn't add anything to
|
||||||
|
its interface. For the same reasons, users of the library must follow the same
|
||||||
|
rules which are used with `libuv`.<br/>
|
||||||
|
As an example, a *handle* should be initialized before any other operation and
|
||||||
|
closed once it is no longer in use.
|
||||||
|
|
||||||
## Code Example
|
## Code Example
|
||||||
|
|
||||||
@ -29,15 +36,15 @@ As an example, a *handle* should be initialized before any other operation and c
|
|||||||
#include <uvw.hpp>
|
#include <uvw.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
void listen(uvw::Loop &loop) {
|
void listen(uvw::loop &loop) {
|
||||||
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>();
|
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
|
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
||||||
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
|
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
|
client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
|
||||||
|
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
||||||
|
|
||||||
auto ptr = srv.shared_from_this();
|
|
||||||
client->on<uvw::CloseEvent>([ptr](const uvw::CloseEvent &, uvw::TCPHandle &) { ptr->close(); });
|
|
||||||
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); });
|
|
||||||
srv.accept(*client);
|
srv.accept(*client);
|
||||||
client->read();
|
client->read();
|
||||||
});
|
});
|
||||||
@ -46,12 +53,12 @@ void listen(uvw::Loop &loop) {
|
|||||||
tcp->listen();
|
tcp->listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void conn(uvw::Loop &loop) {
|
void conn(uvw::loop &loop) {
|
||||||
auto tcp = loop.resource<uvw::TCPHandle>();
|
auto tcp = loop.resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* handle errors */ });
|
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
|
||||||
|
|
||||||
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &tcp) {
|
tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
|
||||||
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
|
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
|
||||||
tcp.write(std::move(dataWrite), 2);
|
tcp.write(std::move(dataWrite), 2);
|
||||||
tcp.close();
|
tcp.close();
|
||||||
@ -61,7 +68,7 @@ void conn(uvw::Loop &loop) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
auto loop = uvw::Loop::getDefault();
|
auto loop = uvw::loop::get_default();
|
||||||
listen(*loop);
|
listen(*loop);
|
||||||
conn(*loop);
|
conn(*loop);
|
||||||
loop->run();
|
loop->run();
|
||||||
@ -70,7 +77,8 @@ int main() {
|
|||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
The main reason for which `uvw` has been written is the fact that it does not exist a valid *libuv* wrapper in C++. That's all.
|
The main reason for which `uvw` has been written is the fact that there does not
|
||||||
|
exist a valid `libuv` wrapper in C++. That's all.
|
||||||
|
|
||||||
# Build Instructions
|
# Build Instructions
|
||||||
|
|
||||||
@ -78,79 +86,130 @@ The main reason for which `uvw` has been written is the fact that it does not ex
|
|||||||
|
|
||||||
To be able to use `uvw`, users must provide the following system-wide tools:
|
To be able to use `uvw`, users must provide the following system-wide tools:
|
||||||
|
|
||||||
* A full-featured compiler that supports at least C++11.
|
* A full-featured compiler that supports at least C++17.
|
||||||
* `libuv` (which version depends on the tag of `uvw` in use).
|
* `libuv` (which version depends on the tag of `uvw` in use)
|
||||||
|
* If you use `meson`, libuv will be downloaded for you
|
||||||
|
|
||||||
The requirements below are mandatory to compile the tests and to extract the documentation:
|
The requirements below are mandatory to compile the tests and to extract the
|
||||||
|
documentation:
|
||||||
|
|
||||||
* CMake version 3.2 or later.
|
* CMake version 3.13 or later.
|
||||||
* Doxygen version 1.8 or later.
|
* Doxygen version 1.8 or later.
|
||||||
|
|
||||||
Note that `libuv` is part of the dependencies of the project and it will be cloned by `cmake` (see below for further details).<br/>
|
Note that `libuv` is part of the dependencies of the project and may be cloned
|
||||||
Because of that, users have not to install it to compile and execute the tests.
|
by `CMake` in some cases (see below for further details).<br/>
|
||||||
|
Because of that, users don't have to install it to run the tests or when `uvw`
|
||||||
|
libraries are compiled through `CMake`.
|
||||||
|
|
||||||
|
## Meson
|
||||||
|
|
||||||
|
You can use `uvw` with [meson](https://mesonbuild.com/) by simply adding it to
|
||||||
|
your `subprojects` directory in your project.
|
||||||
|
|
||||||
|
To compile `uvw` from source without using it as a subproject, in the `uvw`
|
||||||
|
source directory, run:
|
||||||
|
|
||||||
|
* `$ meson setup build`
|
||||||
|
* If you want a static library, add `--default-library=static`
|
||||||
|
* `$ cd build`
|
||||||
|
* `$ meson compile`
|
||||||
|
|
||||||
## Library
|
## Library
|
||||||
|
|
||||||
`uvw` is a header-only library.<br/>
|
`uvw` is a dual-mode library. It can be used in its header-only form or as a
|
||||||
This means that including the `uvw.hpp` header or one of the other `uvw/*.hpp` headers is enough to use it.<br/>
|
compiled static library.<br/>
|
||||||
|
The following sections describe what to do in both cases to get `uvw` up and
|
||||||
|
runningin your own project.
|
||||||
|
|
||||||
|
### Header-only
|
||||||
|
|
||||||
|
To use `uvw` as a header-only library, all is needed is to include the `uvw.hpp`
|
||||||
|
header or one of the other `uvw/*.hpp` files.<br/>
|
||||||
It's a matter of adding the following line at the top of a file:
|
It's a matter of adding the following line at the top of a file:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <uvw.hpp>
|
#include <uvw.hpp>
|
||||||
```
|
```
|
||||||
|
|
||||||
Then pass the proper `-I` argument to the compiler to add the `src` directory to the include paths.<br/>
|
Then pass the proper `-I` argument to the compiler to add the `src` directory to
|
||||||
Note that users are demanded to correctly setup include directories and libraries search paths for *libuv*.
|
the include paths.<br/>
|
||||||
|
Note that users are required to correctly setup the include directories and
|
||||||
|
libraries search paths for `libuv` in this case.
|
||||||
|
|
||||||
|
When used through `CMake`, the `uvw::uvw` target is exported for convenience.
|
||||||
|
|
||||||
|
### Static
|
||||||
|
|
||||||
|
To use `uvw` as a compiled library, set the `UVW_BUILD_LIBS` options in cmake
|
||||||
|
before including the project.<br/>
|
||||||
|
This option triggers the generation of a targets named
|
||||||
|
`uvw::uvw-static`. The matching version of `libuv` is also
|
||||||
|
compiled and exported as `uv::uv-static` for convenience.
|
||||||
|
|
||||||
|
In case you don't use or don't want to use `CMake`, you can still compile all
|
||||||
|
`.cpp` files and include all `.h` files to get the job done. In this case, users
|
||||||
|
are required to correctly setup the include directories and libraries search
|
||||||
|
paths for `libuv`.
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
Starting with tag _v1.12.0_ of `libuv`, `uvw` follows the [semantic versioning](http://semver.org/) scheme.<br/>
|
Starting with tag _v1.12.0_ of `libuv`, `uvw` follows the
|
||||||
The problem is that any version of `uvw` also requires to track explicitly the version of `libuv` to which it is bound.<br/>
|
[semantic versioning](http://semver.org/) scheme.<br/>
|
||||||
Because of that, the latter wil be appended to the version of `uvw`. As an example:
|
The problem is that any version of `uvw` also requires to track explicitly the
|
||||||
|
version of `libuv` to which it is bound.<br/>
|
||||||
|
Because of that, the latter wil be appended to the version of `uvw`. As an
|
||||||
|
example:
|
||||||
|
|
||||||
vU.V.W_libuv-vX.Y
|
vU.V.W_libuv-vX.Y
|
||||||
|
|
||||||
In particular, the following applies:
|
In particular, the following applies:
|
||||||
|
|
||||||
* _U.V.W_ are major, minor and patch versions of `uvw`.
|
* _U.V.W_ are major, minor and patch versions of `uvw`.
|
||||||
* _X.Y_ is the version of `libuv` to which to refer (where any patch version is valid).
|
* _X.Y_ is the version of `libuv` to which to refer (where any patch version is
|
||||||
|
valid).
|
||||||
|
|
||||||
In other terms, tags will look like this from now on:
|
In other terms, tags will look like this from now on:
|
||||||
|
|
||||||
v1.0.0_libuv-v1.12
|
v1.0.0_libuv-v1.12
|
||||||
|
|
||||||
Branch `master` of `uvw` will be a work in progress branch that follows branch _v1.x_ of `libuv` (at least as long as it remains their _master_ branch).<br/>
|
Branch `master` of `uvw` will be a work in progress branch that follows branch
|
||||||
|
_v1.x_ of `libuv` (at least as long as it remains their _master_ branch).<br/>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The documentation is based on [`doxygen`](http://www.stack.nl/~dimitri/doxygen/). To build it:
|
The documentation is based on
|
||||||
|
[`doxygen`](https://www.doxygen.nl/). To build it:
|
||||||
|
|
||||||
* `$ cd build`
|
* `$ cd build`
|
||||||
* `$ cmake ..`
|
* `$ cmake ..`
|
||||||
* `$ make docs`
|
* `$ make docs`
|
||||||
|
|
||||||
The API reference will be created in HTML format within the directory `build/docs/html`.<br/>
|
The API reference will be created in HTML format within the directory
|
||||||
|
`build/docs/html`.<br/>
|
||||||
To navigate it with your favorite browser:
|
To navigate it with your favorite browser:
|
||||||
|
|
||||||
* `$ cd build`
|
* `$ cd build`
|
||||||
* `$ your_favorite_browser docs/html/index.html`
|
* `$ your_favorite_browser docs/html/index.html`
|
||||||
|
|
||||||
The API reference is also available [online](https://skypjack.github.io/uvw/) for the latest version.
|
The same version is also available [online](https://skypjack.github.io/uvw/)
|
||||||
|
for the latest release, that is the last stable tag.
|
||||||
|
|
||||||
### Note
|
### Note
|
||||||
|
|
||||||
The documentation is mostly inspired by the official [libuv API documentation](http://docs.libuv.org/en/v1.x/) for obvious reasons.<br/>
|
The documentation is mostly inspired by the official
|
||||||
If you are mainly interested in the way `uvw` imports `libuv` in a `cmake` based project, I suggest you to take a look at [this](https://github.com/skypjack/libuv_cmake) repository instead.
|
[libuv API documentation](http://docs.libuv.org/en/v1.x/) for obvious
|
||||||
|
reasons.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
To compile and run the tests, `uvw` requires *libuv* and *googletest*.<br/>
|
To compile and run the tests, `uvw` requires `libuv` and `googletest`.<br/>
|
||||||
`cmake` will download and compile both the libraries before to compile anything else.
|
`CMake` will download and compile both the libraries before compiling anything
|
||||||
|
else.
|
||||||
|
|
||||||
To build the tests:
|
To build the tests:
|
||||||
|
|
||||||
* `$ cd build`
|
* `$ cd build`
|
||||||
* `$ cmake .. -DBUILD_TESTING=ON`
|
* `$ cmake .. -DUVW_BUILD_TESTING=ON`
|
||||||
* `$ make`
|
* `$ make`
|
||||||
* `$ ctest -j4 -R uvw`
|
* `$ ctest -j4 -R uvw`
|
||||||
|
|
||||||
@ -160,63 +219,83 @@ Omit `-R uvw` if you also want to test `libuv` and other dependencies.
|
|||||||
|
|
||||||
## Vademecum
|
## Vademecum
|
||||||
|
|
||||||
There is only one rule when using `uvw`: always initialize the resources and terminate them.
|
There is only one rule when using `uvw`: always initialize the resources and
|
||||||
|
terminate them.
|
||||||
|
|
||||||
Resources belong mainly to two families: _handles_ and _requests_.<br/>
|
Resources belong mainly to two families: _handles_ and _requests_.<br/>
|
||||||
Handles represent long-lived objects capable of performing certain operations while active.<br/>
|
Handles represent long-lived objects capable of performing certain operations
|
||||||
Requests represent (typically) short-lived operations performed either over a handle or standalone.
|
while active.<br/>
|
||||||
|
Requests represent (typically) short-lived operations performed either over a
|
||||||
|
handle or standalone.
|
||||||
|
|
||||||
The following sections will explain in short what it means to initialize and terminate these kinds of resources.<br/>
|
The following sections will explain in short what it means to initialize and
|
||||||
For more details, please refer to the [online documentation](https://skypjack.github.io/uvw/).
|
terminate these kinds of resources.<br/>
|
||||||
|
For more details, please refer to the
|
||||||
|
[online documentation](https://skypjack.github.io/uvw/).
|
||||||
|
|
||||||
## Handles
|
## Handles
|
||||||
|
|
||||||
Initialization is usually performed under the hood and can be even passed over, as far as handles are created using the `Loop::resource` member function.<br/>
|
Initialization is usually performed under the hood and can be even passed over,
|
||||||
On the other side, handles keep themselves alive until one explicitly closes them. Because of that, memory usage will grow up if users simply forget about a handle.<br/>
|
as far as handles are created using the `loop::resource` member function.<br/>
|
||||||
Therefore the rule quickly becomes *always close your handles*. It's as simple as calling the `close` member function on them.
|
On the other side, handles keep themselves alive until one explicitly closes
|
||||||
|
them. Because of that, memory usage will grow if users simply forget about a
|
||||||
|
handle.<br/>
|
||||||
|
Therefore the rule quickly becomes *always close your handles*. It's as simple
|
||||||
|
as calling the `close` member function on them.
|
||||||
|
|
||||||
## Requests
|
## Requests
|
||||||
|
|
||||||
Usually initializing a request object is not required. Anyway, the recommended way to create a request is still through the `Loop::resource` member function.<br/>
|
Usually initializing a request object is not required. Anyway, the recommended
|
||||||
Requests will keep themselves alive as long as they are bound to unfinished underlying activities. This means that users have not to discard explicitly a request.<br/>
|
way to create a request is still through the `loop::resource` member
|
||||||
Therefore the rule quickly becomes *feel free to make a request and forget about it*. It's as simple as calling a member function on them.
|
function.<br/>
|
||||||
|
Requests will keep themselves alive as long as they are bound to unfinished
|
||||||
|
underlying activities. This means that users don't have to discard a
|
||||||
|
request explicitly .<br/>
|
||||||
|
Therefore the rule quickly becomes *feel free to make a request and forget about
|
||||||
|
it*. It's as simple as calling a member function on them.
|
||||||
|
|
||||||
## The Loop and the Resource
|
## The Loop and the Resource
|
||||||
|
|
||||||
The first thing to do to use `uvw` is to create a loop. In case the default one is enough, it's easy as doing this:
|
The first thing to do to use `uvw` is to create a loop. In case the default one
|
||||||
|
is enough, it's easy as doing this:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto loop = uvw::Loop::getDefault();
|
auto loop = uvw::loop::get_default();
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that loop objects don't require to be closed explicitly, even if they offer the `close` member function in case an user wants to do that.<br/>
|
Note that loop objects don't require being closed explicitly, even if they offer
|
||||||
Loops can be started using the `run` member function. The two calls below are equivalent:
|
the `close` member function in case a user wants to do that.<br/>
|
||||||
|
Loops can be started using the `run` member function. The two calls below are
|
||||||
|
equivalent:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
loop->run();
|
loop->run();
|
||||||
loop->run<uvw::Loop::Mode::DEFAULT>();
|
loop->run(uvw::loop::run_mode::DEFAULT);
|
||||||
```
|
```
|
||||||
|
|
||||||
Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the documentation of *libuv* for further details.
|
Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the
|
||||||
|
documentation of `libuv` for further details.
|
||||||
|
|
||||||
In order to create a resource and to bind it to the given loop, just do the following:
|
In order to create a resource and to bind it to the given loop, just do the
|
||||||
|
following:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto tcp = loop.resource<uvw::TCPHandle>();
|
auto tcp = loop->resource<uvw::tcp_handle>();
|
||||||
```
|
```
|
||||||
|
|
||||||
The line above will create and initialize a tcp handle, then a shared pointer to that resource will be returned.<br/>
|
The line above creates and initializes a tcp handle, then a shared pointer to
|
||||||
Users should check if pointers have been correctly initialized: in case of errors, they won't be.<br/>
|
that resource is returned.<br/>
|
||||||
Another way to create a resource is:
|
Users should check if pointers have been correctly initialized: in case of
|
||||||
|
errors, they won't be.<br/>
|
||||||
|
It also is possible to create uninitialized resources to init later on as:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto tcp = TCPHandle::create(loop);
|
auto tcp = loop->uninitialized_resource<uvw::tcp_handle>();
|
||||||
tcp->init();
|
tcp->init();
|
||||||
```
|
```
|
||||||
|
|
||||||
Pretty annoying indeed. Using a loop is the recommended approach.
|
All resources also accept arbitrary user-data that won't be touched in any
|
||||||
|
case.<br/>
|
||||||
The resources also accept arbitrary user-data that won't be touched in any case.<br/>
|
|
||||||
Users can set and get them through the `data` member function as it follows:
|
Users can set and get them through the `data` member function as it follows:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@ -224,73 +303,86 @@ resource->data(std::make_shared<int>(42));
|
|||||||
std::shared_ptr<void> data = resource->data();
|
std::shared_ptr<void> data = resource->data();
|
||||||
```
|
```
|
||||||
|
|
||||||
Resources expect a `std::shared_pointer<void>` and return it, therefore any kind of data is welcome.<br/>
|
Resources expect a `std::shared_pointer<void>` and return it, therefore any kind
|
||||||
Users can explicitly specify a type other than `void` when calling the `data` member function:
|
of data is welcome.<br/>
|
||||||
|
Users can explicitly specify a type other than `void` when calling the `data`
|
||||||
|
member function:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::shared_ptr<int> data = resource->data<int>();
|
std::shared_ptr<int> data = resource->data<int>();
|
||||||
```
|
```
|
||||||
|
|
||||||
Remember from the previous section that a handle will keep itself alive until one invokes the `close` member function on it.<br/>
|
Remember from the previous section that a handle will keep itself alive until
|
||||||
To know what are the handles that are still alive and bound to a given loop, just do the following:
|
one invokes the `close` member function on it.<br/>
|
||||||
|
To know what are the handles that are still alive and bound to a given loop,
|
||||||
|
there exists the `walk` member function. It returns handles with their types.
|
||||||
|
Therefore, the use of `overloaded` is recommended to be able to intercept all
|
||||||
|
types of interest:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
loop.walk([](uvw::BaseHandle &){ /* application code here */ });
|
handle.parent().walk(uvw::overloaded{
|
||||||
|
[](uvw::timer_handle &h){ /* application code for timers here */ },
|
||||||
|
[](auto &&){ /* ignore all other types */ }
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
`BaseHandle` exposes a few methods and cannot be promoted to the original type of the handle (even though `type` and `category` member functions fill the gap somehow).<br/>
|
This function can also be used for a completely generic approach. For example,
|
||||||
Anyway, it can be used to close the handle that originated from it. As an example, all the pending handles can be closed easily as it follows:
|
all the pending handles can be closed easily as it follows:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
loop.walk([](uvw::BaseHandle &h){ h.close(); });
|
loop->walk([](auto &&h){ h.close(); });
|
||||||
```
|
```
|
||||||
|
|
||||||
No need to keep track of them.
|
No need to keep track of them.
|
||||||
|
|
||||||
To know what are the available resources' types, please refer the API reference.
|
|
||||||
|
|
||||||
## The event-based approach
|
## The event-based approach
|
||||||
|
|
||||||
For `uvw` offers an event-based approach, resources are small event emitters to which listeners can be attached.<br/>
|
`uvw` offers an event-based approach where resources are small event emitters to
|
||||||
Attaching a listener to a resource is the recommended way to be notified about changes.<br/>
|
which listeners are attached.<br/>
|
||||||
Listeners must be callable objects of type `void(EventType &, ResourceType &)`, where:
|
Attaching listeners to resources is the recommended way to receive notifications
|
||||||
|
about their operations.<br/>
|
||||||
|
Listeners are callable objects of type `void(event_type &, resource_type &)`,
|
||||||
|
where:
|
||||||
|
|
||||||
* `EventType` is the type of the event for which they have been designed.
|
* `event_type` is the type of the event for which they have been designed.
|
||||||
* `ResourceType` is the type of the resource that has originated the event.
|
* `resource_type` is the type of the resource that has originated the event.
|
||||||
|
|
||||||
It means that the following function types are all valid:
|
It means that the following function types are all valid:
|
||||||
|
|
||||||
* `void(EventType &, ResourceType &)`
|
* `void(event_type &, resource_type &)`
|
||||||
* `void(const EventType &, ResourceType &)`
|
* `void(const event_type &, resource_type &)`
|
||||||
* `void(EventType &, const ResourceType &)`
|
* `void(event_type &, const resource_type &)`
|
||||||
* `void(const EventType &, const ResourceType &)`
|
* `void(const event_type &, const resource_type &)`
|
||||||
|
|
||||||
Once more, please note that there is no need to keep around references to the resources: they will pass themselves as an argument whenever an event is published.
|
Please note that there is no need to keep around references to the resources,
|
||||||
|
since they pass themselves as an argument whenever an event is published.<br/>
|
||||||
|
The `on` member function is the way to go to register long-running listeners:
|
||||||
|
|
||||||
There exist two methods to attach an event to a resource:
|
```cpp
|
||||||
|
resource.on<event_type>(listener)
|
||||||
|
```
|
||||||
|
|
||||||
* `resource.once<EventType>(listener)`: the listener will be automatically removed after the first event of the given type.
|
To know if a listener exists for a given type, the class offers a `has` function
|
||||||
* `resource.on<EventType>(listener)`: to be used for long-running listeners.
|
template. Similarly, the `reset` function template is be used to reset and thus
|
||||||
|
disconnect listeners, if any. A non-template version of `reset` also exists to
|
||||||
|
clear an emitter as a whole.
|
||||||
|
|
||||||
Both of them return an object of type `ResourceType::Connection` (as an example, `TCPHandle::Connection`).<br/>
|
Almost all the resources emit `error_event` in case of errors.<br/>
|
||||||
A connection object can be used later as an argument to the `erase` member function of the resource to remove the listener.<br/>
|
All the other events are specific for the given resource and documented in the
|
||||||
There exists also the `clear` member function to drop all the listeners at once.
|
API reference.
|
||||||
|
|
||||||
Almost all the resources use to emit `ErrorEvent` events in case of errors.<br/>
|
|
||||||
All the other events are specific for the given resource and documented in the API reference.
|
|
||||||
|
|
||||||
The code below shows how to create a simple tcp server using `uvw`:
|
The code below shows how to create a simple tcp server using `uvw`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto loop = uvw::Loop::getDefault();
|
auto loop = uvw::loop::get_default();
|
||||||
auto tcp = loop.resource<uvw::TCPHandle>();
|
auto tcp = loop->resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* something went wrong */ });
|
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* something went wrong */ });
|
||||||
|
|
||||||
tcp->on<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
|
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
||||||
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
|
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
||||||
client->once<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); });
|
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
||||||
client->on<uvw::DataEvent>([](const uvw::DataEvent &, uvw::TCPHandle &) { /* data received */ });
|
client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data received */ });
|
||||||
srv.accept(*client);
|
srv.accept(*client);
|
||||||
client->read();
|
client->read();
|
||||||
});
|
});
|
||||||
@ -299,10 +391,9 @@ tcp->bind("127.0.0.1", 4242);
|
|||||||
tcp->listen();
|
tcp->listen();
|
||||||
```
|
```
|
||||||
|
|
||||||
Note also that `uvw::TCPHandle` already supports _IPv6_ out-of-the-box. The statement above is equivalent to `tcp->bind<uvw::IPv4>("127.0.0.1", 4242)`.<br/>
|
Note also that `uvw::tcp_handle` already supports _IPv6_ out-of-the-box.<br/>
|
||||||
It's suffice to explicitly specify `uvw::IPv6` as the underlying protocol to use it.
|
The API reference is the recommended documentation for further details about
|
||||||
|
resources and their methods.
|
||||||
The API reference is the recommended documentation for further details about resources and their methods.
|
|
||||||
|
|
||||||
## Going raw
|
## Going raw
|
||||||
|
|
||||||
@ -312,14 +403,14 @@ reasons, almost all the classes in `uvw` give direct access to them.<br/>
|
|||||||
Please, note that this functions should not be used directly unless users know
|
Please, note that this functions should not be used directly unless users know
|
||||||
exactly what they are doing and what are the risks. Going raw is dangerous,
|
exactly what they are doing and what are the risks. Going raw is dangerous,
|
||||||
mainly because the lifetime management of a loop, a handle or a request is
|
mainly because the lifetime management of a loop, a handle or a request is
|
||||||
completely in charge to the library and working around it could quickly break
|
completely controlled by the library and working around it could quickly break
|
||||||
things.
|
things.
|
||||||
|
|
||||||
That being said, _going raw_ is a matter of using the `raw` member functions:
|
That being said, _going raw_ is a matter of using the `raw` member functions:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto loop = uvw::Loop::getDefault();
|
auto loop = uvw::loop::get_default();
|
||||||
auto tcp = loop.resource<uvw::TCPHandle>();
|
auto tcp = loop->resource<uvw::tcp_handle>();
|
||||||
|
|
||||||
uv_loop_t *raw = loop->raw();
|
uv_loop_t *raw = loop->raw();
|
||||||
uv_tcp_t *handle = tcp->raw();
|
uv_tcp_t *handle = tcp->raw();
|
||||||
@ -327,51 +418,39 @@ uv_tcp_t *handle = tcp->raw();
|
|||||||
|
|
||||||
Go the raw way at your own risk, but do not expect any support in case of bugs.
|
Go the raw way at your own risk, but do not expect any support in case of bugs.
|
||||||
|
|
||||||
|
|
||||||
|
# Related projects
|
||||||
|
|
||||||
|
Interested in additional tools and libraries that build upon `uvw`? You might
|
||||||
|
find the following useful then:
|
||||||
|
|
||||||
|
- [`uvw_net`](https://github.com/mincequi/uvw_net): a networking library with a
|
||||||
|
collection of clients (HTTP/Modbus/SunSpec) that also includes discovery
|
||||||
|
impementations like dns-sd/mdns.
|
||||||
|
|
||||||
|
Feel free to add your tool to the list if you like.
|
||||||
|
|
||||||
# Contributors
|
# Contributors
|
||||||
|
|
||||||
If you want to contribute, please send patches as pull requests against the branch master.<br/>
|
If you want to contribute, please send patches as pull requests against the
|
||||||
Check the [contributors list](https://github.com/skypjack/uvw/blob/master/AUTHORS) to see who has partecipated so far.
|
branch master.<br/>
|
||||||
|
Check the
|
||||||
|
[contributors list](https://github.com/skypjack/uvw/blob/master/AUTHORS) to see
|
||||||
|
who has partecipated so far.
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
Code and documentation Copyright (c) 2016-2018 Michele Caini.<br/>
|
Code and documentation Copyright (c) 2016-2024 Michele Caini.<br/>
|
||||||
Logo Copyright (c) 2018 Richard Caseres.
|
Logo Copyright (c) 2018-2021 Richard Caseres.
|
||||||
|
|
||||||
Code released under
|
Code and documentation released under
|
||||||
[the MIT license](https://github.com/skypjack/uvw/blob/master/LICENSE).
|
[the MIT license](https://github.com/skypjack/uvw/blob/master/LICENSE).<br/>
|
||||||
Documentation released under
|
|
||||||
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).<br/>
|
|
||||||
Logo released under
|
Logo released under
|
||||||
[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||||
|
|
||||||
<!--
|
|
||||||
@cond TURN_OFF_DOXYGEN
|
|
||||||
-->
|
|
||||||
# Support
|
# Support
|
||||||
|
|
||||||
## Patreon
|
If you want to support this project, you can
|
||||||
|
[offer me](https://github.com/users/skypjack/sponsorship) an espresso.<br/>
|
||||||
Become a [patron](https://www.patreon.com/bePatron?c=1772573) and get access to
|
If you find that it's not enough, feel free to
|
||||||
extra content, help me spend more time on the projects you love and create new
|
[help me](https://www.paypal.me/skypjack) the way you prefer.
|
||||||
ones for you. Your support will help me to continue the work done so far and
|
|
||||||
make it more professional and feature-rich every day.<br/>
|
|
||||||
It takes very little to
|
|
||||||
[become a patron](https://www.patreon.com/bePatron?c=1772573) and thus help the
|
|
||||||
software you use every day. Don't miss the chance.
|
|
||||||
|
|
||||||
## Donation
|
|
||||||
|
|
||||||
Developing and maintaining `uvw` takes some time and lots of coffee. It still lacks a proper test suite, documentation is partially incomplete and not all functionalities have been fully implemented yet.<br/>
|
|
||||||
If you want to support this project, you can offer me an espresso. I'm from Italy, we're used to turning the best coffee ever in code. If you find that it's not enough, feel free to support me the way you prefer.<br/>
|
|
||||||
Take a look at the donation button at the top of the page for more details or just click [here](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=W2HF9FESD5LJY&lc=IT&item_name=Michele%20Caini¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted).
|
|
||||||
|
|
||||||
## Hire me
|
|
||||||
|
|
||||||
If you start using `uvw` and need help, if you want a new feature and want me
|
|
||||||
to give it the highest priority, if you have any other reason to contact me:
|
|
||||||
do not hesitate. I'm available for hiring.<br/>
|
|
||||||
Feel free to take a look at my [profile](https://github.com/skypjack) and
|
|
||||||
contact me by mail.
|
|
||||||
<!--
|
|
||||||
@endcond TURN_OFF_DOXYGEN
|
|
||||||
-->
|
|
||||||
|
|||||||
5
TODO
Normal file
5
TODO
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
* do not send error events when the return value is enough (still wip)
|
||||||
|
* also cleanup error event mentions in the doc
|
||||||
|
* Make all tests pass on all platforms
|
||||||
|
* add iwyu and clean up everything
|
||||||
|
* Allocator support
|
||||||
22
appveyor.yml
22
appveyor.yml
@ -1,22 +0,0 @@
|
|||||||
# can use variables like {build} and {branch}
|
|
||||||
version: 1.0.{build}
|
|
||||||
|
|
||||||
image: Visual Studio 2017
|
|
||||||
|
|
||||||
environment:
|
|
||||||
BUILD_DIR: "%APPVEYOR_BUILD_FOLDER%\\build"
|
|
||||||
|
|
||||||
platform:
|
|
||||||
- Win32
|
|
||||||
|
|
||||||
configuration:
|
|
||||||
- Release
|
|
||||||
|
|
||||||
before_build:
|
|
||||||
- cd %BUILD_DIR%
|
|
||||||
- cmake .. -DBUILD_TESTING=ON -G"Visual Studio 15 2017"
|
|
||||||
|
|
||||||
build:
|
|
||||||
parallel: true
|
|
||||||
project: build/uvw.sln
|
|
||||||
verbosity: minimal
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
project(deps-download NONE)
|
|
||||||
cmake_minimum_required(VERSION 3.2)
|
|
||||||
|
|
||||||
include(ExternalProject)
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
googletest
|
|
||||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
|
||||||
GIT_TAG master
|
|
||||||
SOURCE_DIR @GOOGLETEST_DEPS_DIR@
|
|
||||||
CONFIGURE_COMMAND ""
|
|
||||||
BUILD_COMMAND ""
|
|
||||||
INSTALL_COMMAND ""
|
|
||||||
TEST_COMMAND ""
|
|
||||||
)
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
libuv
|
|
||||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
|
||||||
GIT_TAG v1.23.2
|
|
||||||
SOURCE_DIR @LIBUV_DEPS_DIR@
|
|
||||||
CONFIGURE_COMMAND ""
|
|
||||||
BUILD_COMMAND ""
|
|
||||||
INSTALL_COMMAND ""
|
|
||||||
TEST_COMMAND ""
|
|
||||||
)
|
|
||||||
@ -2,18 +2,18 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from conans import ConanFile
|
from conans import ConanFile
|
||||||
|
|
||||||
|
class UVWConan(ConanFile):
|
||||||
class UVMConan(ConanFile):
|
|
||||||
name = "uvw"
|
name = "uvw"
|
||||||
description = "Header-only, event based, tiny and easy to use libuv wrapper in modern C++"
|
description = "Header-only, event based, tiny and easy to use libuv wrapper in modern C++"
|
||||||
homepage = "https://github.com/skypjack/uvw"
|
homepage = "https://github.com/skypjack/uvw"
|
||||||
url = homepage
|
url = homepage
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
topics = ("conan", "uvw", "libuv", "header-only", "wrapper", "event-loop")
|
||||||
author = "Michele Caini <michele.caini@gmail.com>"
|
author = "Michele Caini <michele.caini@gmail.com>"
|
||||||
exports = "LICENSE"
|
exports = "LICENSE"
|
||||||
exports_sources = "src/*"
|
exports_sources = "src/*"
|
||||||
no_copy_source = True
|
no_copy_source = True
|
||||||
requires = "libuv/1.23.2@bincrafters/stable"
|
requires = "libuv/1.49.0@bincrafters/stable"
|
||||||
|
|
||||||
def package(self):
|
def package(self):
|
||||||
self.copy(pattern="LICENSE", dst="licenses")
|
self.copy(pattern="LICENSE", dst="licenses")
|
||||||
|
|||||||
@ -2,23 +2,19 @@
|
|||||||
# Doxygen configuration (documentation)
|
# Doxygen configuration (documentation)
|
||||||
#
|
#
|
||||||
|
|
||||||
set(TARGET_DOCS docs)
|
set(DOXY_DEPS_DIRECTORY ${uvw_SOURCE_DIR}/deps)
|
||||||
|
set(DOXY_SOURCE_DIRECTORY ${uvw_SOURCE_DIR}/src)
|
||||||
set(DOXY_IN_FILE doxy.in)
|
|
||||||
|
|
||||||
set(DOXY_SOURCE_DIRECTORY ${PROJECT_SRC_DIR})
|
|
||||||
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
set(DOXY_CFG_FILE doxy.cfg)
|
|
||||||
|
|
||||||
configure_file(${DOXY_IN_FILE} ${DOXY_CFG_FILE} @ONLY)
|
configure_file(doxy.in doxy.cfg @ONLY)
|
||||||
|
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
${TARGET_DOCS}
|
docs ALL
|
||||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/${DOXY_CFG_FILE}
|
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
|
||||||
WORKING_DIRECTORY ${uvw_SOURCE_DIR}
|
WORKING_DIRECTORY ${uvw_SOURCE_DIR}
|
||||||
VERBATIM
|
VERBATIM
|
||||||
SOURCES ${DOXY_IN_FILE}
|
SOURCES doxy.in
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
|||||||
1063
docs/doxy.in
1063
docs/doxy.in
File diff suppressed because it is too large
Load Diff
54
meson.build
Normal file
54
meson.build
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
project(
|
||||||
|
'uvw',
|
||||||
|
'cpp',
|
||||||
|
version: '3.3.0',
|
||||||
|
license: 'MIT',
|
||||||
|
default_options: ['cpp_std=c++17'],
|
||||||
|
)
|
||||||
|
|
||||||
|
libuv_dep = dependency('libuv', version: '1.48.0', required: true)
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'src/uvw/async.cpp',
|
||||||
|
'src/uvw/check.cpp',
|
||||||
|
'src/uvw/dns.cpp',
|
||||||
|
'src/uvw/emitter.cpp',
|
||||||
|
'src/uvw/fs.cpp',
|
||||||
|
'src/uvw/fs_event.cpp',
|
||||||
|
'src/uvw/fs_poll.cpp',
|
||||||
|
'src/uvw/idle.cpp',
|
||||||
|
'src/uvw/lib.cpp',
|
||||||
|
'src/uvw/loop.cpp',
|
||||||
|
'src/uvw/pipe.cpp',
|
||||||
|
'src/uvw/poll.cpp',
|
||||||
|
'src/uvw/prepare.cpp',
|
||||||
|
'src/uvw/process.cpp',
|
||||||
|
'src/uvw/signal.cpp',
|
||||||
|
'src/uvw/stream.cpp',
|
||||||
|
'src/uvw/tcp.cpp',
|
||||||
|
'src/uvw/thread.cpp',
|
||||||
|
'src/uvw/timer.cpp',
|
||||||
|
'src/uvw/tty.cpp',
|
||||||
|
'src/uvw/udp.cpp',
|
||||||
|
'src/uvw/util.cpp',
|
||||||
|
'src/uvw/work.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
|
uvw_lib = library(
|
||||||
|
'uvw',
|
||||||
|
sources,
|
||||||
|
include_directories: 'src',
|
||||||
|
dependencies: [libuv_dep],
|
||||||
|
cpp_args: ['-DUVW_AS_LIB'],
|
||||||
|
install: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
uvw_dep = declare_dependency(
|
||||||
|
include_directories: ['src'],
|
||||||
|
dependencies: [libuv_dep],
|
||||||
|
link_with: [uvw_lib],
|
||||||
|
)
|
||||||
|
|
||||||
|
if meson.version().version_compare('>=0.54.0')
|
||||||
|
meson.override_dependency('uvw', uvw_dep)
|
||||||
|
endif
|
||||||
82
src/CMakeLists.txt
Normal file
82
src/CMakeLists.txt
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#
|
||||||
|
# Setup libraries
|
||||||
|
#
|
||||||
|
|
||||||
|
function(add_uvw_library LIB_NAME)
|
||||||
|
target_sources(
|
||||||
|
${LIB_NAME}
|
||||||
|
PRIVATE
|
||||||
|
uvw/async.cpp
|
||||||
|
uvw/check.cpp
|
||||||
|
uvw/dns.cpp
|
||||||
|
uvw/emitter.cpp
|
||||||
|
uvw/fs.cpp
|
||||||
|
uvw/fs_event.cpp
|
||||||
|
uvw/fs_poll.cpp
|
||||||
|
uvw/idle.cpp
|
||||||
|
uvw/lib.cpp
|
||||||
|
uvw/loop.cpp
|
||||||
|
uvw/pipe.cpp
|
||||||
|
uvw/poll.cpp
|
||||||
|
uvw/prepare.cpp
|
||||||
|
uvw/process.cpp
|
||||||
|
uvw/signal.cpp
|
||||||
|
uvw/stream.cpp
|
||||||
|
uvw/tcp.cpp
|
||||||
|
uvw/thread.cpp
|
||||||
|
uvw/timer.cpp
|
||||||
|
uvw/tty.cpp
|
||||||
|
uvw/udp.cpp
|
||||||
|
uvw/util.cpp
|
||||||
|
uvw/work.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||||
|
target_compile_definitions(${LIB_NAME} PUBLIC UVW_AS_LIB)
|
||||||
|
target_compile_features(${LIB_NAME} PUBLIC cxx_std_17)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
${LIB_NAME}
|
||||||
|
PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UVW_USE_ASAN)
|
||||||
|
target_compile_options(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||||
|
target_link_libraries(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=address>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UVW_USE_UBSAN)
|
||||||
|
target_compile_options(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer>)
|
||||||
|
target_link_libraries(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=undefined>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UVW_HAS_LIBCPP)
|
||||||
|
target_compile_options(${LIB_NAME} BEFORE PUBLIC -stdlib=libc++)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build and install libraries
|
||||||
|
#
|
||||||
|
|
||||||
|
if (UVW_BUILD_SHARED_LIB)
|
||||||
|
add_library(uvw SHARED)
|
||||||
|
add_library(uvw::uvw-shared ALIAS uvw)
|
||||||
|
# If libuv is not fetched by ourselves, it's the caller's responsibility to make sure of the linkage.
|
||||||
|
if(UVW_FETCH_LIBUV OR libuv_FOUND)
|
||||||
|
target_link_libraries(uvw PUBLIC uv::uv-shared)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
add_library(uvw STATIC)
|
||||||
|
add_library(uvw::uvw-static ALIAS uvw)
|
||||||
|
# If libuv is not fetched by ourselves, it's the caller's responsibility to make sure of the linkage.
|
||||||
|
if(UVW_FETCH_LIBUV OR libuv_FOUND)
|
||||||
|
target_link_libraries(uvw PUBLIC uv::uv-static)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(uvw::uvw ALIAS uvw)
|
||||||
|
set_target_properties(uvw PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
|
||||||
|
add_uvw_library(uvw)
|
||||||
49
src/uvw.hpp
49
src/uvw.hpp
@ -1,21 +1,28 @@
|
|||||||
#include "uvw/async.hpp"
|
#include "uvw/async.h"
|
||||||
#include "uvw/check.hpp"
|
#include "uvw/check.h"
|
||||||
#include "uvw/dns.hpp"
|
#include "uvw/config.h"
|
||||||
#include "uvw/fs.hpp"
|
#include "uvw/dns.h"
|
||||||
#include "uvw/fs_event.hpp"
|
#include "uvw/emitter.h"
|
||||||
#include "uvw/fs_poll.hpp"
|
#include "uvw/enum.hpp"
|
||||||
#include "uvw/idle.hpp"
|
#include "uvw/fs.h"
|
||||||
#include "uvw/lib.hpp"
|
#include "uvw/fs_event.h"
|
||||||
#include "uvw/loop.hpp"
|
#include "uvw/fs_poll.h"
|
||||||
#include "uvw/pipe.hpp"
|
#include "uvw/handle.hpp"
|
||||||
#include "uvw/poll.hpp"
|
#include "uvw/idle.h"
|
||||||
#include "uvw/prepare.hpp"
|
#include "uvw/lib.h"
|
||||||
#include "uvw/process.hpp"
|
#include "uvw/loop.h"
|
||||||
#include "uvw/signal.hpp"
|
#include "uvw/pipe.h"
|
||||||
#include "uvw/tcp.hpp"
|
#include "uvw/poll.h"
|
||||||
#include "uvw/thread.hpp"
|
#include "uvw/prepare.h"
|
||||||
#include "uvw/timer.hpp"
|
#include "uvw/process.h"
|
||||||
#include "uvw/tty.hpp"
|
#include "uvw/request.hpp"
|
||||||
#include "uvw/udp.hpp"
|
#include "uvw/resource.hpp"
|
||||||
#include "uvw/util.hpp"
|
#include "uvw/signal.h"
|
||||||
#include "uvw/work.hpp"
|
#include "uvw/tcp.h"
|
||||||
|
#include "uvw/thread.h"
|
||||||
|
#include "uvw/timer.h"
|
||||||
|
#include "uvw/tty.h"
|
||||||
|
#include "uvw/udp.h"
|
||||||
|
#include "uvw/util.h"
|
||||||
|
#include "uvw/uv_type.hpp"
|
||||||
|
#include "uvw/work.h"
|
||||||
|
|||||||
2
src/uvw/async.cpp
Normal file
2
src/uvw/async.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "async.h"
|
||||||
|
#include "async.ipp"
|
||||||
58
src/uvw/async.h
Normal file
58
src/uvw/async.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef UVW_ASYNC_INCLUDE_H
|
||||||
|
#define UVW_ASYNC_INCLUDE_H
|
||||||
|
|
||||||
|
#include <uv.h>
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Async event. */
|
||||||
|
struct async_event {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The async handle.
|
||||||
|
*
|
||||||
|
* Async handles allow the user to _wakeup_ the event loop and get an event
|
||||||
|
* emitted from another thread.
|
||||||
|
*
|
||||||
|
* To create an `async_handle` through a `loop`, no arguments are required.
|
||||||
|
*/
|
||||||
|
class async_handle final: public handle<async_handle, uv_async_t, async_event> {
|
||||||
|
static void send_callback(uv_async_t *hndl);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using handle::handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
*
|
||||||
|
* Unlike other handle initialization functions, it immediately starts the
|
||||||
|
* handle.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wakeups the event loop and emits the async event.
|
||||||
|
*
|
||||||
|
* It’s safe to call this function from any thread.<br/>
|
||||||
|
* An async event is emitted on the loop thread.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int send();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "async.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_ASYNC_INCLUDE_H
|
||||||
@ -1,67 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AsyncEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by AsyncHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct AsyncEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The AsyncHandle handle.
|
|
||||||
*
|
|
||||||
* Async handles allow the user to _wakeup_ the event loop and get an event
|
|
||||||
* emitted from another thread.
|
|
||||||
*
|
|
||||||
* To create an `AsyncHandle` through a `Loop`, no arguments are required.
|
|
||||||
*/
|
|
||||||
class AsyncHandle final: public Handle<AsyncHandle, uv_async_t> {
|
|
||||||
static void sendCallback(uv_async_t *handle) {
|
|
||||||
AsyncHandle &async = *(static_cast<AsyncHandle*>(handle->data));
|
|
||||||
async.publish(AsyncEvent{});
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Handle::Handle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
*
|
|
||||||
* Unlike other handle initialization functions, it immediately starts the
|
|
||||||
* handle.
|
|
||||||
*
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return initialize(&uv_async_init, &sendCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Wakeups the event loop and emits the AsyncEvent event.
|
|
||||||
*
|
|
||||||
* It’s safe to call this function from any thread.<br/>
|
|
||||||
* An AsyncEvent event will be emitted on the loop thread.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
void send() {
|
|
||||||
invoke(&uv_async_send, get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
18
src/uvw/async.ipp
Normal file
18
src/uvw/async.ipp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE void async_handle::send_callback(uv_async_t *hndl) {
|
||||||
|
async_handle &async = *(static_cast<async_handle *>(hndl->data));
|
||||||
|
async.publish(async_event{});
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int async_handle::init() {
|
||||||
|
return leak_if(uv_async_init(parent().raw(), raw(), &send_callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int async_handle::send() {
|
||||||
|
return uv_async_send(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/check.cpp
Normal file
2
src/uvw/check.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "check.h"
|
||||||
|
#include "check.ipp"
|
||||||
56
src/uvw/check.h
Normal file
56
src/uvw/check.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef UVW_CHECK_INCLUDE_H
|
||||||
|
#define UVW_CHECK_INCLUDE_H
|
||||||
|
|
||||||
|
#include <uv.h>
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Check event. */
|
||||||
|
struct check_event {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The check handle.
|
||||||
|
*
|
||||||
|
* Check handles will emit a check event once per loop iteration, right after
|
||||||
|
* polling for I/O.
|
||||||
|
*
|
||||||
|
* To create a `check_handle` through a `loop`, no arguments are required.
|
||||||
|
*/
|
||||||
|
class check_handle final: public handle<check_handle, uv_check_t, check_event> {
|
||||||
|
static void start_callback(uv_check_t *hndl);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using handle::handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts the handle.
|
||||||
|
*
|
||||||
|
* A check event will be emitted once per loop iteration, right after
|
||||||
|
* polling for I/O.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "check.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_CHECK_INCLUDE_H
|
||||||
@ -1,66 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief CheckEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by CheckHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct CheckEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The CheckHandle handle.
|
|
||||||
*
|
|
||||||
* Check handles will emit a CheckEvent event once per loop iteration, right
|
|
||||||
* after polling for I/O.
|
|
||||||
*
|
|
||||||
* To create a `CheckHandle` through a `Loop`, no arguments are required.
|
|
||||||
*/
|
|
||||||
class CheckHandle final: public Handle<CheckHandle, uv_check_t> {
|
|
||||||
static void startCallback(uv_check_t *handle) {
|
|
||||||
CheckHandle &check = *(static_cast<CheckHandle*>(handle->data));
|
|
||||||
check.publish(CheckEvent{});
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Handle::Handle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return initialize(&uv_check_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the handle.
|
|
||||||
*
|
|
||||||
* A CheckEvent event will be emitted once per loop iteration, right after
|
|
||||||
* polling for I/O.
|
|
||||||
*/
|
|
||||||
void start() {
|
|
||||||
invoke(&uv_check_start, get(), &startCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops the handle.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
invoke(&uv_check_stop, get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
22
src/uvw/check.ipp
Normal file
22
src/uvw/check.ipp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE void check_handle::start_callback(uv_check_t *hndl) {
|
||||||
|
check_handle &check = *(static_cast<check_handle *>(hndl->data));
|
||||||
|
check.publish(check_event{});
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int check_handle::init() {
|
||||||
|
return leak_if(uv_check_init(parent().raw(), raw()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int check_handle::start() {
|
||||||
|
return uv_check_start(raw(), &start_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int check_handle::stop() {
|
||||||
|
return uv_check_stop(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
10
src/uvw/config.h
Normal file
10
src/uvw/config.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef UVW_CONFIG_H
|
||||||
|
#define UVW_CONFIG_H
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# define UVW_INLINE inline
|
||||||
|
#else
|
||||||
|
# define UVW_INLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
2
src/uvw/dns.cpp
Normal file
2
src/uvw/dns.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "dns.h"
|
||||||
|
#include "dns.ipp"
|
||||||
@ -1,29 +1,21 @@
|
|||||||
#pragma once
|
#ifndef UVW_DNS_INCLUDE_H
|
||||||
|
#define UVW_DNS_INCLUDE_H
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
#include "loop.h"
|
||||||
#include "request.hpp"
|
#include "request.hpp"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief The addrinfo event. */
|
||||||
|
struct addr_info_event {
|
||||||
|
using deleter = void (*)(addrinfo *);
|
||||||
|
|
||||||
/**
|
addr_info_event(std::unique_ptr<addrinfo, deleter> addr);
|
||||||
* @brief AddrInfoEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by GetAddrInfoReq according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct AddrInfoEvent {
|
|
||||||
using Deleter = void(*)(addrinfo *);
|
|
||||||
|
|
||||||
AddrInfoEvent(std::unique_ptr<addrinfo, Deleter> addr)
|
|
||||||
: data{std::move(addr)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief An initialized instance of `addrinfo`.
|
* @brief An initialized instance of `addrinfo`.
|
||||||
@ -31,19 +23,12 @@ struct AddrInfoEvent {
|
|||||||
* See [getaddrinfo](http://linux.die.net/man/3/getaddrinfo) for further
|
* See [getaddrinfo](http://linux.die.net/man/3/getaddrinfo) for further
|
||||||
* details.
|
* details.
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<addrinfo, Deleter> data;
|
std::unique_ptr<addrinfo, deleter> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! @brief The nameinfo event. */
|
||||||
/**
|
struct name_info_event {
|
||||||
* @brief NameInfoEvent event.
|
name_info_event(const char *host, const char *serv);
|
||||||
*
|
|
||||||
* It will be emitted by GetNameInfoReq according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct NameInfoEvent {
|
|
||||||
NameInfoEvent(const char *host, const char *serv)
|
|
||||||
: hostname{host}, service{serv}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A valid hostname.
|
* @brief A valid hostname.
|
||||||
@ -51,7 +36,7 @@ struct NameInfoEvent {
|
|||||||
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
||||||
* details.
|
* details.
|
||||||
*/
|
*/
|
||||||
const char * hostname;
|
const char *hostname;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A valid service name.
|
* @brief A valid service name.
|
||||||
@ -59,57 +44,35 @@ struct NameInfoEvent {
|
|||||||
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
||||||
* details.
|
* details.
|
||||||
*/
|
*/
|
||||||
const char * service;
|
const char *service;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The GetAddrInfoReq request.
|
* @brief The getaddrinfo request.
|
||||||
*
|
*
|
||||||
* Wrapper for [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).<br/>
|
* Wrapper for [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).<br/>
|
||||||
* It offers either asynchronous and synchronous access methods.
|
* It offers either asynchronous and synchronous access methods.
|
||||||
*
|
*
|
||||||
* To create a `GetAddrInfoReq` through a `Loop`, no arguments are required.
|
* To create a `get_addr_info_req` through a `loop`, no arguments are required.
|
||||||
*/
|
*/
|
||||||
class GetAddrInfoReq final: public Request<GetAddrInfoReq, uv_getaddrinfo_t> {
|
class get_addr_info_req final: public request<get_addr_info_req, uv_getaddrinfo_t, addr_info_event> {
|
||||||
static void addrInfoCallback(uv_getaddrinfo_t *req, int status, addrinfo *res) {
|
static void addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res);
|
||||||
auto ptr = reserve(req);
|
int node_addr_info(const char *node, const char *service, addrinfo *hints = nullptr);
|
||||||
|
auto node_addr_info_sync(const char *node, const char *service, addrinfo *hints = nullptr);
|
||||||
if(status) {
|
|
||||||
ptr->publish(ErrorEvent{status});
|
|
||||||
} else {
|
|
||||||
auto data = std::unique_ptr<addrinfo, void(*)(addrinfo *)>{
|
|
||||||
res, [](addrinfo *addr){ uv_freeaddrinfo(addr); }};
|
|
||||||
|
|
||||||
ptr->publish(AddrInfoEvent{std::move(data)});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nodeAddrInfo(const char *node, const char *service, addrinfo *hints = nullptr) {
|
|
||||||
invoke(&uv_getaddrinfo, parent(), get(), &addrInfoCallback, node, service, hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nodeAddrInfoSync(const char *node, const char *service, addrinfo *hints = nullptr) -> std::pair<int, std::unique_ptr<addrinfo, void(*)(addrinfo *)>> {
|
|
||||||
auto req = get();
|
|
||||||
auto err = uv_getaddrinfo(parent(), req, nullptr, node, service, hints);
|
|
||||||
auto data = std::unique_ptr<addrinfo, void(*)(addrinfo *)>{req->addrinfo, [](addrinfo *addr){ uv_freeaddrinfo(addr); }};
|
|
||||||
return std::make_pair(!err, std::move(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Deleter = void(*)(addrinfo *);
|
using deleter = void (*)(addrinfo *);
|
||||||
|
|
||||||
using Request::Request;
|
using request::request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||||
* @param node Either a numerical network address or a network hostname.
|
* @param node Either a numerical network address or a network hostname.
|
||||||
* @param hints Optional `addrinfo` data structure with additional address
|
* @param hints Optional `addrinfo` data structure with additional address
|
||||||
* type constraints.
|
* type constraints.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
void nodeAddrInfo(std::string node, addrinfo *hints = nullptr) {
|
int node_addr_info(const std::string &node, addrinfo *hints = nullptr);
|
||||||
nodeAddrInfo(node.data(), nullptr, hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||||
@ -120,22 +83,18 @@ public:
|
|||||||
*
|
*
|
||||||
* @return A `std::pair` composed as it follows:
|
* @return A `std::pair` composed as it follows:
|
||||||
* * A boolean value that is true in case of success, false otherwise.
|
* * A boolean value that is true in case of success, false otherwise.
|
||||||
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested.
|
* * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
std::pair<bool, std::unique_ptr<addrinfo, deleter>> node_addr_info_sync(const std::string &node, addrinfo *hints = nullptr);
|
||||||
nodeAddrInfoSync(std::string node, addrinfo *hints = nullptr) {
|
|
||||||
return nodeAddrInfoSync(node.data(), nullptr, hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||||
* @param service Either a service name or a port number as a string.
|
* @param service Either a service name or a port number as a string.
|
||||||
* @param hints Optional `addrinfo` data structure with additional address
|
* @param hints Optional `addrinfo` data structure with additional address
|
||||||
* type constraints.
|
* type constraints.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
void serviceAddrInfo(std::string service, addrinfo *hints = nullptr) {
|
int service_addr_info(const std::string &service, addrinfo *hints = nullptr);
|
||||||
nodeAddrInfo(nullptr, service.data(), hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||||
@ -146,12 +105,9 @@ public:
|
|||||||
*
|
*
|
||||||
* @return A `std::pair` composed as it follows:
|
* @return A `std::pair` composed as it follows:
|
||||||
* * A boolean value that is true in case of success, false otherwise.
|
* * A boolean value that is true in case of success, false otherwise.
|
||||||
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested.
|
* * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
std::pair<bool, std::unique_ptr<addrinfo, deleter>> service_addr_info_sync(const std::string &service, addrinfo *hints = nullptr);
|
||||||
serviceAddrInfoSync(std::string service, addrinfo *hints = nullptr) {
|
|
||||||
return nodeAddrInfoSync(nullptr, service.data(), hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||||
@ -159,10 +115,9 @@ public:
|
|||||||
* @param service Either a service name or a port number as a string.
|
* @param service Either a service name or a port number as a string.
|
||||||
* @param hints Optional `addrinfo` data structure with additional address
|
* @param hints Optional `addrinfo` data structure with additional address
|
||||||
* type constraints.
|
* type constraints.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
void addrInfo(std::string node, std::string service, addrinfo *hints = nullptr) {
|
int addr_info(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
|
||||||
nodeAddrInfo(node.data(), service.data(), hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||||
@ -174,64 +129,49 @@ public:
|
|||||||
*
|
*
|
||||||
* @return A `std::pair` composed as it follows:
|
* @return A `std::pair` composed as it follows:
|
||||||
* * A boolean value that is true in case of success, false otherwise.
|
* * A boolean value that is true in case of success, false otherwise.
|
||||||
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested.
|
* * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
std::pair<bool, std::unique_ptr<addrinfo, deleter>> addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
|
||||||
addrInfoSync(std::string node, std::string service, addrinfo *hints = nullptr) {
|
|
||||||
return nodeAddrInfoSync(node.data(), service.data(), hints);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The GetNameInfoReq request.
|
* @brief The getnameinfo request.
|
||||||
*
|
*
|
||||||
* Wrapper for [getnameinfo](http://linux.die.net/man/3/getnameinfo).<br/>
|
* Wrapper for [getnameinfo](http://linux.die.net/man/3/getnameinfo).<br/>
|
||||||
* It offers either asynchronous and synchronous access methods.
|
* It offers either asynchronous and synchronous access methods.
|
||||||
*
|
*
|
||||||
* To create a `GetNameInfoReq` through a `Loop`, no arguments are required.
|
* To create a `get_name_info_req` through a `loop`, no arguments are required.
|
||||||
*/
|
*/
|
||||||
class GetNameInfoReq final: public Request<GetNameInfoReq, uv_getnameinfo_t> {
|
class get_name_info_req final: public request<get_name_info_req, uv_getnameinfo_t, name_info_event> {
|
||||||
static void nameInfoCallback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) {
|
static void name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service);
|
||||||
auto ptr = reserve(req);
|
|
||||||
if(status) { ptr->publish(ErrorEvent{status}); }
|
|
||||||
else { ptr->publish(NameInfoEvent{hostname, service}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Request::Request;
|
using request::request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
void nameInfo(const sockaddr &addr, int flags = 0) {
|
int name_info(const sockaddr &addr, int flags = 0);
|
||||||
invoke(&uv_getnameinfo, parent(), get(), &nameInfoCallback, &addr, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||||
* @param ip A valid IP address.
|
* @param ip A valid IP address.
|
||||||
* @param port A valid port number.
|
* @param port A valid port number.
|
||||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
template<typename I = IPv4>
|
int name_info(const std::string &ip, unsigned int port, int flags = 0);
|
||||||
void nameInfo(std::string ip, unsigned int port, int flags = 0) {
|
|
||||||
typename details::IpTraits<I>::Type addr;
|
|
||||||
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
|
|
||||||
nameInfo(reinterpret_cast<const sockaddr &>(addr), flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||||
* @param addr A valid instance of Addr.
|
* @param addr A valid instance of socket_address.
|
||||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
template<typename I = IPv4>
|
int name_info(const socket_address &addr, int flags = 0);
|
||||||
void nameInfo(Addr addr, int flags = 0) {
|
|
||||||
nameInfo<I>(std::move(addr.ip), addr.port, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||||
@ -245,12 +185,7 @@ public:
|
|||||||
* * A `const char *` containing a valid hostname.
|
* * A `const char *` containing a valid hostname.
|
||||||
* * A `const char *` containing a valid service name.
|
* * A `const char *` containing a valid service name.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, std::pair<const char *, const char *>>
|
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const sockaddr &addr, int flags = 0);
|
||||||
nameInfoSync(const sockaddr &addr, int flags = 0) {
|
|
||||||
auto req = get();
|
|
||||||
auto err = uv_getnameinfo(parent(), req, nullptr, &addr, flags);
|
|
||||||
return std::make_pair(!err, std::make_pair(req->host, req->service));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||||
@ -265,18 +200,12 @@ public:
|
|||||||
* * A `const char *` containing a valid hostname.
|
* * A `const char *` containing a valid hostname.
|
||||||
* * A `const char *` containing a valid service name.
|
* * A `const char *` containing a valid service name.
|
||||||
*/
|
*/
|
||||||
template<typename I = IPv4>
|
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const std::string &ip, unsigned int port, int flags = 0);
|
||||||
std::pair<bool, std::pair<const char *, const char *>>
|
|
||||||
nameInfoSync(std::string ip, unsigned int port, int flags = 0) {
|
|
||||||
typename details::IpTraits<I>::Type addr;
|
|
||||||
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
|
|
||||||
return nameInfoSync(reinterpret_cast<const sockaddr &>(addr), flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||||
*
|
*
|
||||||
* @param addr A valid instance of Addr.
|
* @param addr A valid instance of socket_address.
|
||||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||||
*
|
*
|
||||||
* @return A `std::pair` composed as it follows:
|
* @return A `std::pair` composed as it follows:
|
||||||
@ -285,12 +214,13 @@ public:
|
|||||||
* * A `const char *` containing a valid hostname.
|
* * A `const char *` containing a valid hostname.
|
||||||
* * A `const char *` containing a valid service name.
|
* * A `const char *` containing a valid service name.
|
||||||
*/
|
*/
|
||||||
template<typename I = IPv4>
|
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const socket_address &addr, int flags = 0);
|
||||||
std::pair<bool, std::pair<const char *, const char *>>
|
|
||||||
nameInfoSync(Addr addr, int flags = 0) {
|
|
||||||
return nameInfoSync<I>(std::move(addr.ip), addr.port, flags);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
}
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "dns.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_DNS_INCLUDE_H
|
||||||
89
src/uvw/dns.ipp
Normal file
89
src/uvw/dns.ipp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE addr_info_event::addr_info_event(std::unique_ptr<addrinfo, deleter> addr)
|
||||||
|
: data{std::move(addr)} {}
|
||||||
|
|
||||||
|
UVW_INLINE name_info_event::name_info_event(const char *host, const char *serv)
|
||||||
|
: hostname{host}, service{serv} {}
|
||||||
|
|
||||||
|
UVW_INLINE void get_addr_info_req::addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res) {
|
||||||
|
if(auto ptr = reserve(req); status) {
|
||||||
|
ptr->publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{res, [](addrinfo *addr) { uv_freeaddrinfo(addr); }};
|
||||||
|
ptr->publish(addr_info_event{std::move(data)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int get_addr_info_req::node_addr_info(const char *node, const char *service, addrinfo *hints) {
|
||||||
|
return this->leak_if(uv_getaddrinfo(parent().raw(), raw(), &addr_info_callback, node, service, hints));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE auto get_addr_info_req::node_addr_info_sync(const char *node, const char *service, addrinfo *hints) {
|
||||||
|
auto req = raw();
|
||||||
|
auto err = uv_getaddrinfo(parent().raw(), req, nullptr, node, service, hints);
|
||||||
|
auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{req->addrinfo, [](addrinfo *addr) { uv_freeaddrinfo(addr); }};
|
||||||
|
return std::make_pair(!err, std::move(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int get_addr_info_req::node_addr_info(const std::string &node, addrinfo *hints) {
|
||||||
|
return node_addr_info(node.data(), nullptr, hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::node_addr_info_sync(const std::string &node, addrinfo *hints) {
|
||||||
|
return node_addr_info_sync(node.data(), nullptr, hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int get_addr_info_req::service_addr_info(const std::string &service, addrinfo *hints) {
|
||||||
|
return node_addr_info(nullptr, service.data(), hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::service_addr_info_sync(const std::string &service, addrinfo *hints) {
|
||||||
|
return node_addr_info_sync(nullptr, service.data(), hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int get_addr_info_req::addr_info(const std::string &node, const std::string &service, addrinfo *hints) {
|
||||||
|
return node_addr_info(node.data(), service.data(), hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints) {
|
||||||
|
return node_addr_info_sync(node.data(), service.data(), hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void get_name_info_req::name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) {
|
||||||
|
if(auto ptr = reserve(req); status) {
|
||||||
|
ptr->publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
ptr->publish(name_info_event{hostname, service});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int get_name_info_req::name_info(const sockaddr &addr, int flags) {
|
||||||
|
return this->leak_if(uv_getnameinfo(parent().raw(), raw(), &name_info_callback, &addr, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int get_name_info_req::name_info(const std::string &ip, unsigned int port, int flags) {
|
||||||
|
return name_info(details::ip_addr(ip.data(), port), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int get_name_info_req::name_info(const socket_address &addr, int flags) {
|
||||||
|
return name_info(addr.ip, addr.port, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const sockaddr &addr, int flags) {
|
||||||
|
auto req = raw();
|
||||||
|
auto err = uv_getnameinfo(parent().raw(), req, nullptr, &addr, flags);
|
||||||
|
return std::make_pair(!err, std::make_pair(req->host, req->service));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const std::string &ip, unsigned int port, int flags) {
|
||||||
|
return name_info_sync(details::ip_addr(ip.data(), port), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const socket_address &addr, int flags) {
|
||||||
|
return name_info_sync(addr.ip, addr.port, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/emitter.cpp
Normal file
2
src/uvw/emitter.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "emitter.h"
|
||||||
|
#include "emitter.ipp"
|
||||||
159
src/uvw/emitter.h
Normal file
159
src/uvw/emitter.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#ifndef UVW_EMITTER_INCLUDE_H
|
||||||
|
#define UVW_EMITTER_INCLUDE_H
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "type_info.hpp"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Error event.
|
||||||
|
*
|
||||||
|
* Custom wrapper around error constants of `libuv`.
|
||||||
|
*/
|
||||||
|
struct error_event {
|
||||||
|
template<typename Type, typename = std::enable_if_t<std::is_integral_v<Type>>>
|
||||||
|
explicit error_event(Type val) noexcept
|
||||||
|
: ec{static_cast<int>(val)} {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the `libuv` error code equivalent to the given platform dependent error code.
|
||||||
|
*
|
||||||
|
* It returns:
|
||||||
|
* * POSIX error codes on Unix (the ones stored in errno).
|
||||||
|
* * Win32 error codes on Windows (those returned by GetLastError() or WSAGetLastError()).
|
||||||
|
*
|
||||||
|
* If `sys` is already a `libuv` error code, it is simply returned.
|
||||||
|
*
|
||||||
|
* @param sys A platform dependent error code.
|
||||||
|
* @return The `libuv` error code equivalent to the given platform dependent error code.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] static int translate(int sys) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the error message for the given error code.
|
||||||
|
*
|
||||||
|
* Leaks a few bytes of memory when you call it with an unknown error code.
|
||||||
|
*
|
||||||
|
* @return The error message for the given error code.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const char *what() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the error name for the given error code.
|
||||||
|
*
|
||||||
|
* Leaks a few bytes of memory when you call it with an unknown error code.
|
||||||
|
*
|
||||||
|
* @return The error name for the given error code.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const char *name() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the underlying error code, that is an error constant of `libuv`.
|
||||||
|
* @return The underlying error code.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] int code() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the event contains a valid error code.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
|
explicit operator bool() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int ec;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Event emitter base class.
|
||||||
|
*
|
||||||
|
* Almost everything in `uvw` is an event emitter.<br/>
|
||||||
|
* This is the base class from which resources and loops inherit.
|
||||||
|
*/
|
||||||
|
template<typename Elem, typename... Event>
|
||||||
|
class emitter {
|
||||||
|
public:
|
||||||
|
template<typename Type>
|
||||||
|
using listener_t = std::function<void(Type &, Elem &)>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] const auto &handler() const noexcept {
|
||||||
|
return std::get<listener_t<Type>>(handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] auto &handler() noexcept {
|
||||||
|
return std::get<listener_t<Type>>(handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<typename Type>
|
||||||
|
void publish(Type event) {
|
||||||
|
if(auto &listener = handler<Type>(); listener) {
|
||||||
|
listener(event, *static_cast<Elem *>(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~emitter() noexcept {
|
||||||
|
static_assert(std::is_base_of_v<emitter<Elem, Event...>, Elem>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Registers a long-lived listener with the event emitter.
|
||||||
|
*
|
||||||
|
* This method is used to register a listener with the emitter.<br/>
|
||||||
|
* A listener is usually defined as a callable object assignable to a
|
||||||
|
* `std::function<void(const Event &, Elem &)`, where `Event` is the type of
|
||||||
|
* the event and `Elem` is the type of the resource.
|
||||||
|
*
|
||||||
|
* @param f A valid listener to be registered.
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
void on(listener_t<Type> f) {
|
||||||
|
handler<Type>() = std::move(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Disconnects the listener for the given event type. */
|
||||||
|
template<typename Type>
|
||||||
|
void reset() noexcept {
|
||||||
|
handler<Type>() = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Disconnects all listeners. */
|
||||||
|
void reset() noexcept {
|
||||||
|
reset<error_event>();
|
||||||
|
(reset<Event>(), ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if there is a listener registered for the specific event.
|
||||||
|
* @return True if there is a listener registered for the specific event,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] bool has() const noexcept {
|
||||||
|
return static_cast<bool>(handler<Type>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::tuple<listener_t<error_event>, listener_t<Event>...> handlers{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "emitter.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_EMITTER_INCLUDE_H
|
||||||
@ -1,318 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <utility>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <list>
|
|
||||||
#include <uv.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The ErrorEvent event.
|
|
||||||
*
|
|
||||||
* Custom wrapper around error constants of `libuv`.
|
|
||||||
*/
|
|
||||||
struct ErrorEvent {
|
|
||||||
template<typename U, typename V = typename std::enable_if<std::is_integral<U>::value>::type>
|
|
||||||
explicit ErrorEvent(U val) noexcept
|
|
||||||
: ec{static_cast<int>(val)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the `libuv` error code equivalent to the given platform dependent error code.
|
|
||||||
*
|
|
||||||
* It returns:
|
|
||||||
* * POSIX error codes on Unix (the ones stored in errno).
|
|
||||||
* * Win32 error codes on Windows (those returned by GetLastError() or WSAGetLastError()).
|
|
||||||
*
|
|
||||||
* If `sys` is already a `libuv` error code, it is simply returned.
|
|
||||||
*
|
|
||||||
* @param sys A platform dependent error code.
|
|
||||||
* @return The `libuv` error code equivalent to the given platform dependent error code.
|
|
||||||
*/
|
|
||||||
static int translate(int sys) noexcept {
|
|
||||||
return uv_translate_sys_error(sys);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the error message for the given error code.
|
|
||||||
*
|
|
||||||
* Leaks a few bytes of memory when you call it with an unknown error code.
|
|
||||||
*
|
|
||||||
* @return The error message for the given error code.
|
|
||||||
*/
|
|
||||||
const char * what() const noexcept { return uv_strerror(ec); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the error name for the given error code.
|
|
||||||
*
|
|
||||||
* Leaks a few bytes of memory when you call it with an unknown error code.
|
|
||||||
*
|
|
||||||
* @return The error name for the given error code.
|
|
||||||
*/
|
|
||||||
const char * name() const noexcept { return uv_err_name(ec); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the underlying error code, that is an error constant of `libuv`.
|
|
||||||
* @return The underlying error code.
|
|
||||||
*/
|
|
||||||
int code() const noexcept { return ec; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the event contains a valid error code.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
explicit operator bool() const noexcept { return ec < 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const int ec;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Event emitter base class.
|
|
||||||
*
|
|
||||||
* Almost everything in `uvw` is an event emitter.<br/>
|
|
||||||
* This is the base class from which resources and loops inherit.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
class Emitter {
|
|
||||||
struct BaseHandler {
|
|
||||||
virtual ~BaseHandler() noexcept = default;
|
|
||||||
virtual bool empty() const noexcept = 0;
|
|
||||||
virtual void clear() noexcept = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename E>
|
|
||||||
struct Handler final: BaseHandler {
|
|
||||||
using Listener = std::function<void(E &, T &)>;
|
|
||||||
using Element = std::pair<bool, Listener>;
|
|
||||||
using ListenerList = std::list<Element>;
|
|
||||||
using Connection = typename ListenerList::iterator;
|
|
||||||
|
|
||||||
bool empty() const noexcept override {
|
|
||||||
auto pred = [](const Element &element){ return element.first; };
|
|
||||||
|
|
||||||
return std::all_of(onceL.cbegin(), onceL.cend(), pred) &&
|
|
||||||
std::all_of(onL.cbegin(), onL.cend(), pred);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() noexcept override {
|
|
||||||
if(publishing) {
|
|
||||||
auto func = [](Element &element){ element.first = true; };
|
|
||||||
std::for_each(onceL.begin(), onceL.end(), func);
|
|
||||||
std::for_each(onL.begin(), onL.end(), func);
|
|
||||||
} else {
|
|
||||||
onceL.clear();
|
|
||||||
onL.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection once(Listener f) {
|
|
||||||
return onceL.emplace(onceL.end(), false, std::move(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection on(Listener f) {
|
|
||||||
return onL.emplace(onL.end(), false, std::move(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
void erase(Connection conn) noexcept {
|
|
||||||
conn->first = true;
|
|
||||||
|
|
||||||
if(!publishing) {
|
|
||||||
auto pred = [](const Element &element){ return element.first; };
|
|
||||||
onceL.remove_if(pred);
|
|
||||||
onL.remove_if(pred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void publish(E event, T &ref) {
|
|
||||||
ListenerList currentL;
|
|
||||||
onceL.swap(currentL);
|
|
||||||
|
|
||||||
auto func = [&event, &ref](Element &element) {
|
|
||||||
return element.first ? void() : element.second(event, ref);
|
|
||||||
};
|
|
||||||
|
|
||||||
publishing = true;
|
|
||||||
|
|
||||||
std::for_each(onL.rbegin(), onL.rend(), func);
|
|
||||||
std::for_each(currentL.rbegin(), currentL.rend(), func);
|
|
||||||
|
|
||||||
publishing = false;
|
|
||||||
|
|
||||||
onL.remove_if([](const Element &element){ return element.first; });
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool publishing{false};
|
|
||||||
ListenerList onceL{};
|
|
||||||
ListenerList onL{};
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::size_t next_type() noexcept {
|
|
||||||
static std::size_t counter = 0;
|
|
||||||
return counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename>
|
|
||||||
static std::size_t event_type() noexcept {
|
|
||||||
static std::size_t value = next_type();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename E>
|
|
||||||
Handler<E> & handler() noexcept {
|
|
||||||
std::size_t type = event_type<E>();
|
|
||||||
|
|
||||||
if(!(type < handlers.size())) {
|
|
||||||
handlers.resize(type+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!handlers[type]) {
|
|
||||||
handlers[type] = std::unique_ptr<Handler<E>>(new(std::nothrow) Handler<E>);
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<Handler<E>&>(*handlers[type]);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
template<typename E>
|
|
||||||
void publish(E event) {
|
|
||||||
handler<E>().publish(std::move(event), *static_cast<T*>(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
template<typename E>
|
|
||||||
using Listener = typename Handler<E>::Listener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Connection type for a given event type.
|
|
||||||
*
|
|
||||||
* Given an event type `E`, `Connection<E>` is the type of the connection
|
|
||||||
* object returned by the event emitter whenever a listener for the given
|
|
||||||
* type is registered.
|
|
||||||
*/
|
|
||||||
template<typename E>
|
|
||||||
struct Connection: private Handler<E>::Connection {
|
|
||||||
template<typename> friend class Emitter;
|
|
||||||
|
|
||||||
Connection() = default;
|
|
||||||
Connection(const Connection &) = default;
|
|
||||||
Connection(Connection &&) = default;
|
|
||||||
|
|
||||||
Connection(typename Handler<E>::Connection conn)
|
|
||||||
: Handler<E>::Connection{std::move(conn)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
Connection & operator=(const Connection &) = default;
|
|
||||||
Connection & operator=(Connection &&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~Emitter() noexcept {
|
|
||||||
static_assert(std::is_base_of<Emitter<T>, T>::value, "!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Registers a long-lived listener with the event emitter.
|
|
||||||
*
|
|
||||||
* This method can be used to register a listener that is meant to be
|
|
||||||
* invoked more than once for the given event type.<br/>
|
|
||||||
* The Connection object returned by the method can be freely discarded. It
|
|
||||||
* can be used later to disconnect the listener, if needed.
|
|
||||||
*
|
|
||||||
* Listener is usually defined as a callable object assignable to a
|
|
||||||
* `std::function<void(const E &, T &)`, where `E` is the type of the event
|
|
||||||
* and `T` is the type of the resource.
|
|
||||||
*
|
|
||||||
* @param f A valid listener to be registered.
|
|
||||||
* @return Connection object to be used later to disconnect the listener.
|
|
||||||
*/
|
|
||||||
template<typename E>
|
|
||||||
Connection<E> on(Listener<E> f) {
|
|
||||||
return handler<E>().on(std::move(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Registers a short-lived listener with the event emitter.
|
|
||||||
*
|
|
||||||
* This method can be used to register a listener that is meant to be
|
|
||||||
* invoked only once for the given event type.<br/>
|
|
||||||
* The Connection object returned by the method can be freely discarded. It
|
|
||||||
* can be used later to disconnect the listener, if needed.
|
|
||||||
*
|
|
||||||
* Listener is usually defined as a callable object assignable to a
|
|
||||||
* `std::function<void(const E &, T &)`, where `E` is the type of the event
|
|
||||||
* and `T` is the type of the resource.
|
|
||||||
*
|
|
||||||
* @param f A valid listener to be registered.
|
|
||||||
* @return Connection object to be used later to disconnect the listener.
|
|
||||||
*/
|
|
||||||
template<typename E>
|
|
||||||
Connection<E> once(Listener<E> f) {
|
|
||||||
return handler<E>().once(std::move(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disconnects a listener from the event emitter.
|
|
||||||
* @param conn A valid Connection object
|
|
||||||
*/
|
|
||||||
template<typename E>
|
|
||||||
void erase(Connection<E> conn) noexcept {
|
|
||||||
handler<E>().erase(std::move(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disconnects all the listeners for the given event type.
|
|
||||||
*/
|
|
||||||
template<typename E>
|
|
||||||
void clear() noexcept {
|
|
||||||
handler<E>().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disconnects all the listeners.
|
|
||||||
*/
|
|
||||||
void clear() noexcept {
|
|
||||||
std::for_each(handlers.begin(), handlers.end(),
|
|
||||||
[](std::unique_ptr<BaseHandler> &hdlr){ if(hdlr) { hdlr->clear(); } });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if there are listeners registered for the specific event.
|
|
||||||
* @return True if there are no listeners registered for the specific event,
|
|
||||||
* false otherwise.
|
|
||||||
*/
|
|
||||||
template<typename E>
|
|
||||||
bool empty() const noexcept {
|
|
||||||
std::size_t type = event_type<E>();
|
|
||||||
|
|
||||||
return (!(type < handlers.size()) ||
|
|
||||||
!handlers[type] ||
|
|
||||||
static_cast<Handler<E>&>(*handlers[type]).empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if there are listeners registered with the event emitter.
|
|
||||||
* @return True if there are no listeners registered with the event emitter,
|
|
||||||
* false otherwise.
|
|
||||||
*/
|
|
||||||
bool empty() const noexcept {
|
|
||||||
return std::all_of(handlers.cbegin(), handlers.cend(),
|
|
||||||
[](const std::unique_ptr<BaseHandler> &hdlr){ return !hdlr || hdlr->empty(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::unique_ptr<BaseHandler>> handlers{};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
25
src/uvw/emitter.ipp
Normal file
25
src/uvw/emitter.ipp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE int error_event::translate(int sys) noexcept {
|
||||||
|
return uv_translate_sys_error(sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE const char *error_event::what() const noexcept {
|
||||||
|
return uv_strerror(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE const char *error_event::name() const noexcept {
|
||||||
|
return uv_err_name(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int error_event::code() const noexcept {
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE error_event::operator bool() const noexcept {
|
||||||
|
return ec < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
76
src/uvw/enum.hpp
Normal file
76
src/uvw/enum.hpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#ifndef UVW_ENUM_INCLUDE_HPP
|
||||||
|
#define UVW_ENUM_INCLUDE_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Operator available for enums for which bitmask support is enabled.
|
||||||
|
* @tparam Type Enum class type.
|
||||||
|
* @param lhs The first value to use.
|
||||||
|
* @param rhs The second value to use.
|
||||||
|
* @return The result of invoking the operator on the underlying types of the
|
||||||
|
* two values provided.
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||||
|
operator|(const Type lhs, const Type rhs) noexcept {
|
||||||
|
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @copydoc operator| */
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||||
|
operator&(const Type lhs, const Type rhs) noexcept {
|
||||||
|
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @copydoc operator| */
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||||
|
operator^(const Type lhs, const Type rhs) noexcept {
|
||||||
|
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Operator available for enums for which bitmask support is enabled.
|
||||||
|
* @tparam Type Enum class type.
|
||||||
|
* @param value The value to use.
|
||||||
|
* @return The result of invoking the operator on the underlying types of the
|
||||||
|
* value provided.
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||||
|
operator~(const Type value) noexcept {
|
||||||
|
return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @copydoc operator~ */
|
||||||
|
template<typename Type>
|
||||||
|
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM, bool{})>
|
||||||
|
operator!(const Type value) noexcept {
|
||||||
|
return !static_cast<std::underlying_type_t<Type>>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @copydoc operator| */
|
||||||
|
template<typename Type>
|
||||||
|
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM) &>
|
||||||
|
operator|=(Type &lhs, const Type rhs) noexcept {
|
||||||
|
return (lhs = (lhs | rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @copydoc operator| */
|
||||||
|
template<typename Type>
|
||||||
|
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM) &>
|
||||||
|
operator&=(Type &lhs, const Type rhs) noexcept {
|
||||||
|
return (lhs = (lhs & rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @copydoc operator| */
|
||||||
|
template<typename Type>
|
||||||
|
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM) &>
|
||||||
|
operator^=(Type &lhs, const Type rhs) noexcept {
|
||||||
|
return (lhs = (lhs ^ rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
2
src/uvw/fs.cpp
Normal file
2
src/uvw/fs.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "fs.h"
|
||||||
|
#include "fs.ipp"
|
||||||
1235
src/uvw/fs.h
Normal file
1235
src/uvw/fs.h
Normal file
File diff suppressed because it is too large
Load Diff
1448
src/uvw/fs.hpp
1448
src/uvw/fs.hpp
File diff suppressed because it is too large
Load Diff
550
src/uvw/fs.ipp
Normal file
550
src/uvw/fs.ipp
Normal file
@ -0,0 +1,550 @@
|
|||||||
|
#include <array>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::fs_open_callback(uv_fs_t *req) {
|
||||||
|
if(auto ptr = reserve(req); req->result < 0) {
|
||||||
|
ptr->publish(error_event{req->result});
|
||||||
|
} else {
|
||||||
|
ptr->file = static_cast<uv_file>(req->result);
|
||||||
|
ptr->publish(fs_event{*req});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::fs_close_callback(uv_fs_t *req) {
|
||||||
|
if(auto ptr = reserve(req); req->result < 0) {
|
||||||
|
ptr->publish(error_event{req->result});
|
||||||
|
} else {
|
||||||
|
ptr->file = BAD_FD;
|
||||||
|
ptr->publish(fs_event{*req});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::fs_read_callback(uv_fs_t *req) {
|
||||||
|
if(auto ptr = reserve(req); req->result < 0) {
|
||||||
|
ptr->publish(error_event{req->result});
|
||||||
|
} else {
|
||||||
|
ptr->publish(fs_event{*req, std::move(ptr->current)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE file_req::~file_req() noexcept {
|
||||||
|
uv_fs_req_cleanup(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::close() {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_close(parent().raw(), raw(), file, &fs_close_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::close_sync() {
|
||||||
|
auto req = raw();
|
||||||
|
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_close(parent().raw(), req, file, nullptr);
|
||||||
|
|
||||||
|
if(req->result >= 0) {
|
||||||
|
file = BAD_FD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::open(const std::string &path, file_open_flags flags, int mode) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_open(parent().raw(), raw(), path.data(), static_cast<int>(flags), mode, &fs_open_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::open_sync(const std::string &path, file_open_flags flags, int mode) {
|
||||||
|
auto req = raw();
|
||||||
|
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_open(parent().raw(), req, path.data(), static_cast<int>(flags), mode, nullptr);
|
||||||
|
|
||||||
|
if(req->result >= 0) {
|
||||||
|
file = static_cast<uv_file>(req->result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::read(int64_t offset, unsigned int len) {
|
||||||
|
current = std::make_unique<char[]>(len);
|
||||||
|
buffer = uv_buf_init(current.get(), len);
|
||||||
|
std::array bufs{buffer};
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_read(parent().raw(), raw(), file, bufs.data(), 1, offset, &fs_read_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<std::unique_ptr<const char[]>, std::size_t>> file_req::read_sync(int64_t offset, unsigned int len) {
|
||||||
|
current = std::make_unique<char[]>(len);
|
||||||
|
buffer = uv_buf_init(current.get(), len);
|
||||||
|
std::array bufs{buffer};
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_read(parent().raw(), req, file, bufs.data(), 1, offset, nullptr);
|
||||||
|
bool err = req->result < 0;
|
||||||
|
return std::make_pair(!err, std::make_pair(std::move(current), err ? 0 : std::size_t(req->result)));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::write(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
|
||||||
|
current = std::move(buf);
|
||||||
|
std::array bufs{uv_buf_init(current.get(), len)};
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_write(parent().raw(), raw(), file, bufs.data(), 1, offset, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::write(char *buf, unsigned int len, int64_t offset) {
|
||||||
|
std::array bufs{uv_buf_init(buf, len)};
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_write(parent().raw(), raw(), file, bufs.data(), 1, offset, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::size_t> file_req::write_sync(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
|
||||||
|
current = std::move(buf);
|
||||||
|
std::array bufs{uv_buf_init(current.get(), len)};
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_write(parent().raw(), req, file, bufs.data(), 1, offset, nullptr);
|
||||||
|
bool err = req->result < 0;
|
||||||
|
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::stat() {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fstat(parent().raw(), raw(), file, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, file_info> file_req::stat_sync() {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fstat(parent().raw(), req, file, nullptr);
|
||||||
|
return std::make_pair(!(req->result < 0), req->statbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::sync() {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fsync(parent().raw(), raw(), file, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::sync_sync() {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fsync(parent().raw(), req, file, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::datasync() {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fdatasync(parent().raw(), raw(), file, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::datasync_sync() {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fdatasync(parent().raw(), req, file, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::truncate(int64_t offset) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_ftruncate(parent().raw(), raw(), file, offset, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::truncate_sync(int64_t offset) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_ftruncate(parent().raw(), req, file, offset, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::sendfile(file_handle out, int64_t offset, std::size_t length) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_sendfile(parent().raw(), raw(), out, file, offset, length, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::size_t> file_req::sendfile_sync(file_handle out, int64_t offset, std::size_t length) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_sendfile(parent().raw(), req, out, file, offset, length, nullptr);
|
||||||
|
bool err = req->result < 0;
|
||||||
|
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::chmod(int mode) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fchmod(parent().raw(), raw(), file, mode, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::chmod_sync(int mode) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fchmod(parent().raw(), req, file, mode, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::futime(fs_request::time atime, fs_request::time mtime) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_futime(parent().raw(), raw(), file, atime.count(), mtime.count(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::futime_sync(fs_request::time atime, fs_request::time mtime) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_futime(parent().raw(), req, file, atime.count(), mtime.count(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void file_req::chown(uid_type uid, gid_type gid) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fchown(parent().raw(), raw(), file, uid, gid, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool file_req::chown_sync(uid_type uid, gid_type gid) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_fchown(parent().raw(), req, file, uid, gid, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE file_req::operator file_handle() const noexcept {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE fs_req::~fs_req() noexcept {
|
||||||
|
uv_fs_req_cleanup(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::unlink(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_unlink(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::unlink_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_unlink(parent().raw(), req, path.data(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::mkdir(const std::string &path, int mode) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_mkdir(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::mkdir_sync(const std::string &path, int mode) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_mkdir(parent().raw(), req, path.data(), mode, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::mkdtemp(const std::string &tpl) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_mkdtemp(parent().raw(), raw(), tpl.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, const char *> fs_req::mkdtemp_sync(const std::string &tpl) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_mkdtemp(parent().raw(), req, tpl.data(), nullptr);
|
||||||
|
return std::make_pair(!(req->result < 0), req->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::mkstemp(const std::string &tpl) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_mkstemp(parent().raw(), raw(), tpl.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<std::string, std::size_t>> fs_req::mkstemp_sync(const std::string &tpl) {
|
||||||
|
std::pair<bool, std::pair<std::string, std::size_t>> ret{false, {}};
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_mkstemp(parent().raw(), req, tpl.data(), nullptr);
|
||||||
|
ret.first = !(req->result < 0);
|
||||||
|
|
||||||
|
if(ret.first) {
|
||||||
|
ret.second.first = req->path;
|
||||||
|
ret.second.second = static_cast<std::size_t>(req->result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::lutime(const std::string &path, time atime, time mtime) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_lutime(parent().raw(), raw(), path.data(), atime.count(), mtime.count(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::lutime_sync(const std::string &path, time atime, time mtime) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_lutime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::rmdir(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_rmdir(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::rmdir_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_rmdir(parent().raw(), req, path.data(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::scandir(const std::string &path, int flags) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_scandir(parent().raw(), raw(), path.data(), flags, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::size_t> fs_req::scandir_sync(const std::string &path, int flags) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_scandir(parent().raw(), req, path.data(), flags, nullptr);
|
||||||
|
bool err = req->result < 0;
|
||||||
|
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::scandir_next() {
|
||||||
|
std::pair<bool, std::pair<entry_type, const char *>> ret{false, {entry_type::UNKNOWN, nullptr}};
|
||||||
|
|
||||||
|
uv_fs_req_cleanup(raw());
|
||||||
|
auto res = uv_fs_scandir_next(raw(), &dirents);
|
||||||
|
|
||||||
|
if(UV_EOF != res) {
|
||||||
|
ret.second.first = static_cast<entry_type>(dirents.type);
|
||||||
|
ret.second.second = dirents.name;
|
||||||
|
ret.first = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::stat(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_stat(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, file_info> fs_req::stat_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_stat(parent().raw(), req, path.data(), nullptr);
|
||||||
|
return std::make_pair(!(req->result < 0), req->statbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::lstat(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_lstat(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, file_info> fs_req::lstat_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_lstat(parent().raw(), req, path.data(), nullptr);
|
||||||
|
return std::make_pair(!(req->result < 0), req->statbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::statfs(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_statfs(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, fs_info> fs_req::statfs_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_statfs(parent().raw(), req, path.data(), nullptr);
|
||||||
|
return std::make_pair(!(req->result < 0), *static_cast<uv_statfs_t *>(req->ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::rename(const std::string &old, const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_rename(parent().raw(), raw(), old.data(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::rename_sync(const std::string &old, const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_rename(parent().raw(), req, old.data(), path.data(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::copyfile(const std::string &old, const std::string &path, copy_file_flags flags) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_copyfile(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::copyfile_sync(const std::string &old, const std::string &path, copy_file_flags flags) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_copyfile(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::access(const std::string &path, int mode) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_access(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::access_sync(const std::string &path, int mode) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_access(parent().raw(), req, path.data(), mode, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::chmod(const std::string &path, int mode) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_chmod(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::chmod_sync(const std::string &path, int mode) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_chmod(parent().raw(), req, path.data(), mode, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::utime(const std::string &path, fs_request::time atime, fs_request::time mtime) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_utime(parent().raw(), raw(), path.data(), atime.count(), mtime.count(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::utime_sync(const std::string &path, fs_request::time atime, fs_request::time mtime) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_utime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::link(const std::string &old, const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_link(parent().raw(), raw(), old.data(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::link_sync(const std::string &old, const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_link(parent().raw(), req, old.data(), path.data(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::symlink(const std::string &old, const std::string &path, symlink_flags flags) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_symlink(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::symlink_sync(const std::string &old, const std::string &path, symlink_flags flags) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_symlink(parent().raw(), req, old.data(), path.data(), static_cast<int>(flags), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::readlink(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_readlink(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<const char *, std::size_t>> fs_req::readlink_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_readlink(parent().raw(), req, path.data(), nullptr);
|
||||||
|
bool err = req->result < 0;
|
||||||
|
return std::make_pair(!err, std::make_pair(static_cast<char *>(req->ptr), err ? 0 : std::size_t(req->result)));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::realpath(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_realpath(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, const char *> fs_req::realpath_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_realpath(parent().raw(), req, path.data(), nullptr);
|
||||||
|
return std::make_pair(!(req->result < 0), req->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::chown(const std::string &path, uid_type uid, gid_type gid) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_chown(parent().raw(), raw(), path.data(), uid, gid, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::chown_sync(const std::string &path, uid_type uid, gid_type gid) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_chown(parent().raw(), req, path.data(), uid, gid, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::lchown(const std::string &path, uid_type uid, gid_type gid) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_lchown(parent().raw(), raw(), path.data(), uid, gid, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::lchown_sync(const std::string &path, uid_type uid, gid_type gid) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_lchown(parent().raw(), req, path.data(), uid, gid, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::opendir(const std::string &path) {
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_opendir(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::opendir_sync(const std::string &path) {
|
||||||
|
auto req = raw();
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_opendir(parent().raw(), req, path.data(), nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::closedir() {
|
||||||
|
auto req = raw();
|
||||||
|
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_closedir(parent().raw(), req, dir, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool fs_req::closedir_sync() {
|
||||||
|
auto req = raw();
|
||||||
|
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_closedir(parent().raw(), req, dir, nullptr);
|
||||||
|
return !(req->result < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_req::readdir() {
|
||||||
|
auto req = raw();
|
||||||
|
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||||
|
dir->dirents = &dirents;
|
||||||
|
dir->nentries = 1;
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_readdir(parent().raw(), req, dir, &fs_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::readdir_sync() {
|
||||||
|
auto req = raw();
|
||||||
|
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||||
|
dir->dirents = &dirents;
|
||||||
|
dir->nentries = 1;
|
||||||
|
uv_fs_req_cleanup(this->raw());
|
||||||
|
uv_fs_readdir(parent().raw(), req, dir, nullptr);
|
||||||
|
return {req->result != 0, {static_cast<entry_type>(dirents.type), dirents.name}};
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE os_file_descriptor fs_helper::handle(file_handle file) noexcept {
|
||||||
|
return uv_get_osfhandle(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE file_handle fs_helper::open(os_file_descriptor descriptor) noexcept {
|
||||||
|
return uv_open_osfhandle(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/fs_event.cpp
Normal file
2
src/uvw/fs_event.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "fs_event.h"
|
||||||
|
#include "fs_event.ipp"
|
||||||
120
src/uvw/fs_event.h
Normal file
120
src/uvw/fs_event.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#ifndef UVW_FS_EVENT_INCLUDE_H
|
||||||
|
#define UVW_FS_EVENT_INCLUDE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "enum.hpp"
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
enum class uvw_fs_event_flags : std::underlying_type_t<uv_fs_event_flags> {
|
||||||
|
WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY,
|
||||||
|
STAT = UV_FS_EVENT_STAT,
|
||||||
|
RECURSIVE = UV_FS_EVENT_RECURSIVE,
|
||||||
|
UVW_ENUM = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class uvw_fs_event : std::underlying_type_t<uv_fs_event> {
|
||||||
|
RENAME = UV_RENAME,
|
||||||
|
CHANGE = UV_CHANGE
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
/*! @brief Fs event event. */
|
||||||
|
struct fs_event_event {
|
||||||
|
fs_event_event(const char *pathname, details::uvw_fs_event events);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The path to the file being monitored.
|
||||||
|
*
|
||||||
|
* If the handle was started with a directory, the filename parameter will
|
||||||
|
* be a relative path to a file contained in the directory.
|
||||||
|
*/
|
||||||
|
const char *filename;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Detected events all in one.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `fs_event_handle::watch::RENAME`
|
||||||
|
* * `fs_event_handle::watch::CHANGE`
|
||||||
|
*/
|
||||||
|
details::uvw_fs_event flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The fs event handle.
|
||||||
|
*
|
||||||
|
* These handles allow the user to monitor a given path for changes, for
|
||||||
|
* example, if the file was renamed or there was a generic change in it. The
|
||||||
|
* best backend for the job on each platform is chosen by the handle.
|
||||||
|
*
|
||||||
|
* To create a `fs_event_handle` through a `loop`, no arguments are required.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/fs_event.html)
|
||||||
|
* for further details.
|
||||||
|
*/
|
||||||
|
class fs_event_handle final: public handle<fs_event_handle, uv_fs_event_t, fs_event_event> {
|
||||||
|
static void start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using watch = details::uvw_fs_event;
|
||||||
|
using event_flags = details::uvw_fs_event_flags;
|
||||||
|
|
||||||
|
using handle::handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts watching the specified path.
|
||||||
|
*
|
||||||
|
* It will watch the specified path for changes.<br/>
|
||||||
|
* As soon as a change is observed, a fs_event_event is emitted by the
|
||||||
|
* handle.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `fs_event_handle::event_flags::WATCH_ENTRY`
|
||||||
|
* * `fs_event_handle::event_flags::STAT`
|
||||||
|
* * `fs_event_handle::event_flags::RECURSIVE`
|
||||||
|
*
|
||||||
|
* @param path The file or directory to be monitored.
|
||||||
|
* @param flags Additional flags to control the behavior.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int start(const std::string &path, event_flags flags = event_flags::UVW_ENUM);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops polling the file descriptor.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the path being monitored.
|
||||||
|
* @return The path being monitored, an empty string in case of errors.
|
||||||
|
*/
|
||||||
|
std::string path() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "fs_event.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_FS_EVENT_INCLUDE_H
|
||||||
@ -1,158 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "util.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVFsEventFlags: typename std::underlying_type<uv_fs_event_flags>::type {
|
|
||||||
WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY,
|
|
||||||
STAT = UV_FS_EVENT_STAT,
|
|
||||||
RECURSIVE = UV_FS_EVENT_RECURSIVE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVFsEvent: typename std::underlying_type<uv_fs_event>::type {
|
|
||||||
RENAME = UV_RENAME,
|
|
||||||
CHANGE = UV_CHANGE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief FsEventEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by FsEventHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct FsEventEvent {
|
|
||||||
FsEventEvent(const char * pathname, Flags<details::UVFsEvent> events)
|
|
||||||
: filename{pathname}, flags{std::move(events)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The path to the file being monitored.
|
|
||||||
*
|
|
||||||
* If the handle was started with a directory, the filename parameter will
|
|
||||||
* be a relative path to a file contained in the directory.
|
|
||||||
*/
|
|
||||||
const char * filename;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Detected events all in one.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `FsEventHandle::Watch::RENAME`
|
|
||||||
* * `FsEventHandle::Watch::CHANGE`
|
|
||||||
*/
|
|
||||||
Flags<details::UVFsEvent> flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The FsEventHandle handle.
|
|
||||||
*
|
|
||||||
* These handles allow the user to monitor a given path for changes, for
|
|
||||||
* example, if the file was renamed or there was a generic change in it. The
|
|
||||||
* best backend for the job on each platform is chosen by the handle.
|
|
||||||
*
|
|
||||||
* To create a `FsEventHandle` through a `Loop`, no arguments are required.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/fs_event.html)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
class FsEventHandle final: public Handle<FsEventHandle, uv_fs_event_t> {
|
|
||||||
static void startCallback(uv_fs_event_t *handle, const char *filename, int events, int status) {
|
|
||||||
FsEventHandle &fsEvent = *(static_cast<FsEventHandle*>(handle->data));
|
|
||||||
if(status) { fsEvent.publish(ErrorEvent{status}); }
|
|
||||||
else { fsEvent.publish(FsEventEvent{filename, static_cast<typename std::underlying_type<details::UVFsEvent>::type>(events)}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Watch = details::UVFsEvent;
|
|
||||||
using Event = details::UVFsEventFlags;
|
|
||||||
|
|
||||||
using Handle::Handle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return initialize(&uv_fs_event_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts watching the specified path.
|
|
||||||
*
|
|
||||||
* It will watch the specified path for changes.<br/>
|
|
||||||
* As soon as a change is observed, a FsEventEvent is emitted by the
|
|
||||||
* handle.<br>
|
|
||||||
* It could happen that ErrorEvent events are emitted while running.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `FsEventHandle::Event::WATCH_ENTRY`
|
|
||||||
* * `FsEventHandle::Event::STAT`
|
|
||||||
* * `FsEventHandle::Event::RECURSIVE`
|
|
||||||
*
|
|
||||||
* @param path The file or directory to be monitored.
|
|
||||||
* @param flags Additional flags to control the behavior.
|
|
||||||
*/
|
|
||||||
void start(std::string path, Flags<Event> flags = Flags<Event>{}) {
|
|
||||||
invoke(&uv_fs_event_start, get(), &startCallback, path.data(), flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts watching the specified path.
|
|
||||||
*
|
|
||||||
* It will watch the specified path for changes.<br/>
|
|
||||||
* As soon as a change is observed, a FsEventEvent is emitted by the
|
|
||||||
* handle.<br>
|
|
||||||
* It could happen that ErrorEvent events are emitted while running.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `FsEventHandle::Event::WATCH_ENTRY`
|
|
||||||
* * `FsEventHandle::Event::STAT`
|
|
||||||
* * `FsEventHandle::Event::RECURSIVE`
|
|
||||||
*
|
|
||||||
* @param path The file or directory to be monitored.
|
|
||||||
* @param flag Additional flag to control the behavior.
|
|
||||||
*/
|
|
||||||
void start(std::string path, Event flag) {
|
|
||||||
start(std::move(path), Flags<Event>{flag});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops polling the file descriptor.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
invoke(&uv_fs_event_stop, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the path being monitored.
|
|
||||||
* @return The path being monitored, an empty string in case of errors.
|
|
||||||
*/
|
|
||||||
std::string path() noexcept {
|
|
||||||
return details::tryRead(&uv_fs_event_getpath, get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
33
src/uvw/fs_event.ipp
Normal file
33
src/uvw/fs_event.ipp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE fs_event_event::fs_event_event(const char *pathname, details::uvw_fs_event events)
|
||||||
|
: filename{pathname}, flags{events} {}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||||
|
UVW_INLINE void fs_event_handle::start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status) {
|
||||||
|
if(fs_event_handle &fsEvent = *(static_cast<fs_event_handle *>(hndl->data)); status) {
|
||||||
|
fsEvent.publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
fsEvent.publish(fs_event_event{filename, details::uvw_fs_event(events)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int fs_event_handle::init() {
|
||||||
|
return leak_if(uv_fs_event_init(parent().raw(), raw()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int fs_event_handle::start(const std::string &path, event_flags flags) {
|
||||||
|
return uv_fs_event_start(raw(), &start_callback, path.data(), static_cast<uv_fs_event_flags>(flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int fs_event_handle::stop() {
|
||||||
|
return uv_fs_event_stop(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::string fs_event_handle::path() noexcept {
|
||||||
|
return details::try_read(&uv_fs_event_getpath, raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/fs_poll.cpp
Normal file
2
src/uvw/fs_poll.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "fs_poll.h"
|
||||||
|
#include "fs_poll.ipp"
|
||||||
76
src/uvw/fs_poll.h
Normal file
76
src/uvw/fs_poll.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#ifndef UVW_FS_POLL_INCLUDE_H
|
||||||
|
#define UVW_FS_POLL_INCLUDE_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Fs pos event. */
|
||||||
|
struct fs_poll_event {
|
||||||
|
explicit fs_poll_event(file_info previous, file_info current) noexcept;
|
||||||
|
|
||||||
|
file_info prev; /*!< The old file_info struct. */
|
||||||
|
file_info curr; /*!< The new file_info struct. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The fs poll handle.
|
||||||
|
*
|
||||||
|
* It allows users to monitor a given path for changes. Unlike fs_event_handle,
|
||||||
|
* fs_poll_handle uses stat to detect when a file has changed so it can work on
|
||||||
|
* file systems where fs_event_handle handles can’t.
|
||||||
|
*
|
||||||
|
* To create a `fs_poll_handle` through a `loop`, no arguments are required.
|
||||||
|
*/
|
||||||
|
class fs_poll_handle final: public handle<fs_poll_handle, uv_fs_poll_t, fs_poll_event> {
|
||||||
|
static void start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using time = std::chrono::duration<unsigned int, std::milli>;
|
||||||
|
|
||||||
|
using handle::handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts the handle.
|
||||||
|
*
|
||||||
|
* The handle will start emitting fs_poll_event when needed.
|
||||||
|
*
|
||||||
|
* @param file The path to the file to be checked.
|
||||||
|
* @param interval Milliseconds between successive checks.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int start(const std::string &file, time interval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the path being monitored by the handle.
|
||||||
|
* @return The path being monitored by the handle, an empty string in case
|
||||||
|
* of errors.
|
||||||
|
*/
|
||||||
|
std::string path() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "fs_poll.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_FS_POLL_INCLUDE_H
|
||||||
@ -1,91 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <chrono>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "util.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief FsPollEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by FsPollHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct FsPollEvent {
|
|
||||||
explicit FsPollEvent(Stat previous, Stat current) noexcept
|
|
||||||
: prev(std::move(previous)), curr(std::move(current))
|
|
||||||
{}
|
|
||||||
|
|
||||||
Stat prev; /*!< The old Stat struct. */
|
|
||||||
Stat curr; /*!< The new Stat struct. */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The FsPollHandle handle.
|
|
||||||
*
|
|
||||||
* It allows the user to monitor a given path for changes. Unlike FsEventHandle
|
|
||||||
* handles, FsPollHandle handles use stat to detect when a file has changed so
|
|
||||||
* they can work on file systems where FsEventHandle handles can’t.
|
|
||||||
*
|
|
||||||
* To create a `FsPollHandle` through a `Loop`, no arguments are required.
|
|
||||||
*/
|
|
||||||
class FsPollHandle final: public Handle<FsPollHandle, uv_fs_poll_t> {
|
|
||||||
static void startCallback(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr) {
|
|
||||||
FsPollHandle &fsPoll = *(static_cast<FsPollHandle*>(handle->data));
|
|
||||||
if(status) { fsPoll.publish(ErrorEvent{status}); }
|
|
||||||
else { fsPoll.publish(FsPollEvent{ *prev, *curr }); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Time = std::chrono::duration<unsigned int, std::milli>;
|
|
||||||
|
|
||||||
using Handle::Handle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return initialize(&uv_fs_poll_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the handle.
|
|
||||||
*
|
|
||||||
* The handle will start emitting FsPollEvent when needed.
|
|
||||||
*
|
|
||||||
* @param file The path to the file to be checked.
|
|
||||||
* @param interval Milliseconds between successive checks.
|
|
||||||
*/
|
|
||||||
void start(std::string file, Time interval) {
|
|
||||||
invoke(&uv_fs_poll_start, get(), &startCallback, file.data(), interval.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops the handle.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
invoke(&uv_fs_poll_stop, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the path being monitored by the handle.
|
|
||||||
* @return The path being monitored by the handle, an empty string in case
|
|
||||||
* of errors.
|
|
||||||
*/
|
|
||||||
std::string path() noexcept {
|
|
||||||
return details::tryRead(&uv_fs_poll_getpath, get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
32
src/uvw/fs_poll.ipp
Normal file
32
src/uvw/fs_poll.ipp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE fs_poll_event::fs_poll_event(file_info previous, file_info current) noexcept
|
||||||
|
: prev{previous}, curr{current} {}
|
||||||
|
|
||||||
|
UVW_INLINE void fs_poll_handle::start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr) {
|
||||||
|
if(fs_poll_handle &fsPoll = *(static_cast<fs_poll_handle *>(hndl->data)); status) {
|
||||||
|
fsPoll.publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
fsPoll.publish(fs_poll_event{*prev, *curr});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int fs_poll_handle::init() {
|
||||||
|
return leak_if(uv_fs_poll_init(parent().raw(), raw()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int fs_poll_handle::start(const std::string &file, fs_poll_handle::time interval) {
|
||||||
|
return uv_fs_poll_start(raw(), &start_callback, file.data(), interval.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int fs_poll_handle::stop() {
|
||||||
|
return uv_fs_poll_stop(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::string fs_poll_handle::path() noexcept {
|
||||||
|
return details::try_read(&uv_fs_poll_getpath, raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
@ -1,70 +1,44 @@
|
|||||||
#pragma once
|
#ifndef UVW_HANDLE_INCLUDE_H
|
||||||
|
#define UVW_HANDLE_INCLUDE_H
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
#include "resource.hpp"
|
#include "resource.hpp"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Close event. */
|
||||||
/**
|
struct close_event {};
|
||||||
* @brief CloseEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by the handles according with their functionalities.
|
|
||||||
*/
|
|
||||||
struct CloseEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle base class.
|
* @brief Handle base class.
|
||||||
*
|
*
|
||||||
* Base type for all `uvw` handle types.
|
* Base type for all `uvw` handle types.
|
||||||
*/
|
*/
|
||||||
template<typename T, typename U>
|
template<typename T, typename U, typename... E>
|
||||||
class Handle: public BaseHandle, public Resource<T, U>
|
class handle: public resource<T, U, close_event, E...> {
|
||||||
{
|
|
||||||
static void closeCallback(uv_handle_t *handle) {
|
|
||||||
Handle<T, U> &ref = *(static_cast<T*>(handle->data));
|
|
||||||
auto ptr = ref.shared_from_this();
|
|
||||||
(void)ptr;
|
|
||||||
ref.reset();
|
|
||||||
ref.publish(CloseEvent{});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void allocCallback(uv_handle_t *, std::size_t suggested, uv_buf_t *buf) {
|
static void close_callback(uv_handle_t *hndl) {
|
||||||
auto size = static_cast<unsigned int>(suggested);
|
handle<T, U, E...> &ref = *(static_cast<T *>(hndl->data));
|
||||||
*buf = uv_buf_init(new char[size], size);
|
[[maybe_unused]] auto ptr = ref.shared_from_this();
|
||||||
|
ref.self_reset();
|
||||||
|
ref.publish(close_event{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
[[nodiscard]] uv_handle_t *as_uv_handle() {
|
||||||
bool initialize(F &&f, Args&&... args) {
|
return reinterpret_cast<uv_handle_t *>(this->raw());
|
||||||
if(!this->self()) {
|
|
||||||
auto err = std::forward<F>(f)(this->parent(), this->get(), std::forward<Args>(args)...);
|
|
||||||
|
|
||||||
if(err) {
|
|
||||||
this->publish(ErrorEvent{err});
|
|
||||||
} else {
|
|
||||||
this->leak();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->self();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
[[nodiscard]] const uv_handle_t *as_uv_handle() const {
|
||||||
void invoke(F &&f, Args&&... args) {
|
return reinterpret_cast<const uv_handle_t *>(this->raw());
|
||||||
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
|
||||||
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Resource<T, U>::Resource;
|
using resource<T, U, close_event, E...>::resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the category of the handle.
|
* @brief Gets the category of the handle.
|
||||||
@ -75,8 +49,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The actual category of the handle.
|
* @return The actual category of the handle.
|
||||||
*/
|
*/
|
||||||
HandleCategory category() const noexcept override {
|
[[nodiscard]] handle_category category() const noexcept {
|
||||||
return HandleCategory{this->template get<uv_handle_t>()->type};
|
return handle_category{as_uv_handle()->type};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,12 +58,12 @@ public:
|
|||||||
*
|
*
|
||||||
* A base handle offers no functionality to promote it to the actual handle
|
* A base handle offers no functionality to promote it to the actual handle
|
||||||
* type. By means of this function, the type of the underlying handle as
|
* type. By means of this function, the type of the underlying handle as
|
||||||
* specified by HandleType is made available to the users.
|
* specified by handle_type is made available to the users.
|
||||||
*
|
*
|
||||||
* @return The actual type of the handle.
|
* @return The actual type of the handle.
|
||||||
*/
|
*/
|
||||||
HandleType type() const noexcept override {
|
[[nodiscard]] handle_type type() const noexcept {
|
||||||
return Utilities::guessHandle(category());
|
return utilities::guess_handle(category());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,22 +71,22 @@ public:
|
|||||||
*
|
*
|
||||||
* What _active_ means depends on the type of handle:
|
* What _active_ means depends on the type of handle:
|
||||||
*
|
*
|
||||||
* * An AsyncHandle handle is always active and cannot be deactivated,
|
* * An async_handle handle is always active and cannot be deactivated,
|
||||||
* except by closing it with uv_close().
|
* except by closing it with uv_close().
|
||||||
* * A PipeHandle, TCPHandle, UDPHandle, etc. handle - basically any handle
|
* * A pipe, tcp, udp, etc. handle - basically any handle that deals with
|
||||||
* that deals with I/O - is active when it is doing something that involves
|
* I/O - is active when it is doing something that involves I/O, like
|
||||||
* I/O, like reading, writing, connecting, accepting new connections, etc.
|
* reading, writing, connecting, accepting new connections, etc.
|
||||||
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
|
* * A check, idle, timer, etc. handle is active when it has been started
|
||||||
* has been started with a call to `start()`.
|
* with a call to `start()`.
|
||||||
*
|
*
|
||||||
* Rule of thumb: if a handle of type `FooHandle` has a `start()` member
|
* Rule of thumb: if a handle of type `foo_handle` has a `start()` member
|
||||||
* method, then it’s active from the moment that method is called. Likewise,
|
* method, then it’s active from the moment that method is called. Likewise,
|
||||||
* `stop()` deactivates the handle again.
|
* `stop()` deactivates the handle again.
|
||||||
*
|
*
|
||||||
* @return True if the handle is active, false otherwise.
|
* @return True if the handle is active, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool active() const noexcept override {
|
[[nodiscard]] bool active() const noexcept {
|
||||||
return !(uv_is_active(this->template get<uv_handle_t>()) == 0);
|
return !!uv_is_active(as_uv_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,22 +97,21 @@ public:
|
|||||||
*
|
*
|
||||||
* @return True if the handle is closing or closed, false otherwise.
|
* @return True if the handle is closing or closed, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool closing() const noexcept override {
|
[[nodiscard]] bool closing() const noexcept {
|
||||||
return !(uv_is_closing(this->template get<uv_handle_t>()) == 0);
|
return !!uv_is_closing(as_uv_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Request handle to be closed.
|
* @brief Request handle to be closed.
|
||||||
*
|
*
|
||||||
* This **must** be called on each handle before memory is released.<br/>
|
* This **must** be called on each handle before memory is released.<br/>
|
||||||
* In-progress requests are cancelled and this can result in an ErrorEvent
|
* In-progress requests are cancelled and this can result in errors.
|
||||||
* emitted.
|
|
||||||
*
|
*
|
||||||
* The handle will emit a CloseEvent when finished.
|
* The handle will emit a close event when finished.
|
||||||
*/
|
*/
|
||||||
void close() noexcept override {
|
void close() noexcept {
|
||||||
if(!closing()) {
|
if(!closing()) {
|
||||||
uv_close(this->template get<uv_handle_t>(), &Handle<T, U>::closeCallback);
|
uv_close(as_uv_handle(), &handle<T, U, E...>::close_callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,8 +121,8 @@ public:
|
|||||||
* References are idempotent, that is, if a handle is already referenced
|
* References are idempotent, that is, if a handle is already referenced
|
||||||
* calling this function again will have no effect.
|
* calling this function again will have no effect.
|
||||||
*/
|
*/
|
||||||
void reference() noexcept override {
|
void reference() noexcept {
|
||||||
uv_ref(this->template get<uv_handle_t>());
|
uv_ref(as_uv_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -158,24 +131,24 @@ public:
|
|||||||
* References are idempotent, that is, if a handle is not referenced calling
|
* References are idempotent, that is, if a handle is not referenced calling
|
||||||
* this function again will have no effect.
|
* this function again will have no effect.
|
||||||
*/
|
*/
|
||||||
void unreference() noexcept override {
|
void unreference() noexcept {
|
||||||
uv_unref(this->template get<uv_handle_t>());
|
uv_unref(as_uv_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if the given handle referenced.
|
* @brief Checks if the given handle referenced.
|
||||||
* @return True if the handle referenced, false otherwise.
|
* @return True if the handle referenced, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool referenced() const noexcept override {
|
[[nodiscard]] bool referenced() const noexcept {
|
||||||
return !(uv_has_ref(this->template get<uv_handle_t>()) == 0);
|
return !!uv_has_ref(as_uv_handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the size of the underlying handle type.
|
* @brief Returns the size of the underlying handle type.
|
||||||
* @return The size of the underlying handle type.
|
* @return The size of the underlying handle type.
|
||||||
*/
|
*/
|
||||||
std::size_t size() const noexcept {
|
[[nodiscard]] std::size_t size() const noexcept {
|
||||||
return uv_handle_size(this->template get<uv_handle_t>()->type);
|
return uv_handle_size(as_uv_handle()->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,16 +156,17 @@ public:
|
|||||||
*
|
*
|
||||||
* Gets the size of the send buffer that the operating system uses for the
|
* Gets the size of the send buffer that the operating system uses for the
|
||||||
* socket.<br/>
|
* socket.<br/>
|
||||||
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
* This function works for tcp, pipeand udp handles on Unix and for tcp and
|
||||||
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
|
* udp handles on Windows.<br/>
|
||||||
* Note that Linux will return double the size of the original set value.
|
* Note that Linux will return double the size of the original set value.
|
||||||
*
|
*
|
||||||
* @return The size of the send buffer, 0 in case of errors.
|
* @return The size of the send buffer, the underlying return value in case
|
||||||
|
* of errors.
|
||||||
*/
|
*/
|
||||||
int sendBufferSize() {
|
[[nodiscard]] int send_buffer_size() {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
auto err = uv_send_buffer_size(this->template get<uv_handle_t>(), &value);
|
auto err = uv_send_buffer_size(as_uv_handle(), &value);
|
||||||
return err ? 0 : value;
|
return err ? err : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,14 +174,14 @@ public:
|
|||||||
*
|
*
|
||||||
* Sets the size of the send buffer that the operating system uses for the
|
* Sets the size of the send buffer that the operating system uses for the
|
||||||
* socket.<br/>
|
* socket.<br/>
|
||||||
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
* This function works for tcp, pipe and udp handles on Unix and for tcp and
|
||||||
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
|
* udp handles on Windows.<br/>
|
||||||
* Note that Linux will set double the size.
|
* Note that Linux will set double the size.
|
||||||
*
|
*
|
||||||
* @return True in case of success, false otherwise.
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
bool sendBufferSize(int value) {
|
[[nodiscard]] int send_buffer_size(int value) {
|
||||||
return (0 == uv_send_buffer_size(this->template get<uv_handle_t>(), &value));
|
return uv_send_buffer_size(as_uv_handle(), &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -215,16 +189,17 @@ public:
|
|||||||
*
|
*
|
||||||
* Gets the size of the receive buffer that the operating system uses for
|
* Gets the size of the receive buffer that the operating system uses for
|
||||||
* the socket.<br/>
|
* the socket.<br/>
|
||||||
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
* This function works for tcp, pipe and udp handles on Unix and for tcp and
|
||||||
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
|
* udp handles on Windows.<br/>
|
||||||
* Note that Linux will return double the size of the original set value.
|
* Note that Linux will return double the size of the original set value.
|
||||||
*
|
*
|
||||||
* @return The size of the receive buffer, 0 in case of errors.
|
* @return The size of the receive buffer, the underlying return value in
|
||||||
|
* case of errors.
|
||||||
*/
|
*/
|
||||||
int recvBufferSize() {
|
[[nodiscard]] int recv_buffer_size() {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
auto err = uv_recv_buffer_size(this->template get<uv_handle_t>(), &value);
|
auto err = uv_recv_buffer_size(as_uv_handle(), &value);
|
||||||
return err ? 0 : value;
|
return err ? err : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -232,14 +207,14 @@ public:
|
|||||||
*
|
*
|
||||||
* Sets the size of the receive buffer that the operating system uses for
|
* Sets the size of the receive buffer that the operating system uses for
|
||||||
* the socket.<br/>
|
* the socket.<br/>
|
||||||
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
* This function works for tcp, pipe and udp handles on Unix and for tcp and
|
||||||
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
|
* udp handles on Windows.<br/>
|
||||||
* Note that Linux will set double the size.
|
* Note that Linux will set double the size.
|
||||||
*
|
*
|
||||||
* @return True in case of success, false otherwise.
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
bool recvBufferSize(int value) {
|
[[nodiscard]] int recv_buffer_size(int value) {
|
||||||
return (0 == uv_recv_buffer_size(this->template get<uv_handle_t>(), &value));
|
return uv_recv_buffer_size(as_uv_handle(), &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -247,15 +222,14 @@ public:
|
|||||||
*
|
*
|
||||||
* Supported handles:
|
* Supported handles:
|
||||||
*
|
*
|
||||||
* * TCPHandle
|
* * tcp_handle
|
||||||
* * PipeHandle
|
* * pipe_handle
|
||||||
* * TTYHandle
|
* * tty_handle
|
||||||
* * UDPHandle
|
* * udp_handle
|
||||||
* * PollHandle
|
* * poll_handle
|
||||||
*
|
*
|
||||||
* It will emit an ErrorEvent event if invoked on any other handle.<br/>
|
* If invoked on a different handle, one that doesn’t have an attached file
|
||||||
* If a handle doesn’t have an attached file descriptor yet or the handle
|
* descriptor yet or one which was closed, an invalid value is returned.
|
||||||
* itself has been closed, an ErrorEvent event will be emitted.
|
|
||||||
*
|
*
|
||||||
* See the official
|
* See the official
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/handle.html#c.uv_fileno)
|
* [documentation](http://docs.libuv.org/en/v1.x/handle.html#c.uv_fileno)
|
||||||
@ -264,12 +238,13 @@ public:
|
|||||||
* @return The file descriptor attached to the hande or a negative value in
|
* @return The file descriptor attached to the hande or a negative value in
|
||||||
* case of errors.
|
* case of errors.
|
||||||
*/
|
*/
|
||||||
OSFileDescriptor fileno() const {
|
[[nodiscard]] os_file_descriptor fd() const {
|
||||||
uv_os_fd_t fd;
|
uv_os_fd_t fd;
|
||||||
uv_fileno(this->template get<uv_handle_t>(), &fd);
|
uv_fileno(as_uv_handle(), &fd);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
}
|
#endif // UVW_HANDLE_INCLUDE_H
|
||||||
|
|||||||
2
src/uvw/idle.cpp
Normal file
2
src/uvw/idle.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "idle.h"
|
||||||
|
#include "idle.ipp"
|
||||||
65
src/uvw/idle.h
Normal file
65
src/uvw/idle.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#ifndef UVW_IDLE_INCLUDE_H
|
||||||
|
#define UVW_IDLE_INCLUDE_H
|
||||||
|
|
||||||
|
#include <uv.h>
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Idle event. */
|
||||||
|
struct idle_event {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The idle handle.
|
||||||
|
*
|
||||||
|
* Idle handles will emit a idle event once per loop iteration, right before the
|
||||||
|
* prepare handles.
|
||||||
|
*
|
||||||
|
* The notable difference with prepare handles is that when there are active
|
||||||
|
* idle handles, the loop will perform a zero timeout poll instead of blocking
|
||||||
|
* for I/O.
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Despite the name, idle handles will emit events on every loop iteration, not
|
||||||
|
* when the loop is actually _idle_.
|
||||||
|
*
|
||||||
|
* To create an `idle_handle` through a `loop`, no arguments are required.
|
||||||
|
*/
|
||||||
|
class idle_handle final: public handle<idle_handle, uv_idle_t, idle_event> {
|
||||||
|
static void start_callback(uv_idle_t *hndl);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using handle::handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts the handle.
|
||||||
|
*
|
||||||
|
* An idle event will be emitted once per loop iteration, right before
|
||||||
|
* polling the prepare handles.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the handle.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "idle.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_IDLE_INCLUDE_H
|
||||||
@ -1,74 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief IdleEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by IdleHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct IdleEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The IdleHandle handle.
|
|
||||||
*
|
|
||||||
* Idle handles will emit a IdleEvent event once per loop iteration, right
|
|
||||||
* before the PrepareHandle handles.
|
|
||||||
*
|
|
||||||
* The notable difference with prepare handles is that when there are active
|
|
||||||
* idle handles, the loop will perform a zero timeout poll instead of blocking
|
|
||||||
* for I/O.
|
|
||||||
*
|
|
||||||
* @note
|
|
||||||
* Despite the name, idle handles will emit events on every loop iteration, not
|
|
||||||
* when the loop is actually _idle_.
|
|
||||||
*
|
|
||||||
* To create an `IdleHandle` through a `Loop`, no arguments are required.
|
|
||||||
*/
|
|
||||||
class IdleHandle final: public Handle<IdleHandle, uv_idle_t> {
|
|
||||||
static void startCallback(uv_idle_t *handle) {
|
|
||||||
IdleHandle &idle = *(static_cast<IdleHandle*>(handle->data));
|
|
||||||
idle.publish(IdleEvent{});
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Handle::Handle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return initialize(&uv_idle_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the handle.
|
|
||||||
*
|
|
||||||
* A IdleEvent event will be emitted once per loop iteration, right before
|
|
||||||
* polling the PrepareHandle handles.
|
|
||||||
*/
|
|
||||||
void start() {
|
|
||||||
invoke(&uv_idle_start, get(), &startCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops the handle.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
invoke(&uv_idle_stop, get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
22
src/uvw/idle.ipp
Normal file
22
src/uvw/idle.ipp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE void idle_handle::start_callback(uv_idle_t *hndl) {
|
||||||
|
idle_handle &idle = *(static_cast<idle_handle *>(hndl->data));
|
||||||
|
idle.publish(idle_event{});
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int idle_handle::init() {
|
||||||
|
return leak_if(uv_idle_init(parent().raw(), raw()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int idle_handle::start() {
|
||||||
|
return uv_idle_start(raw(), &start_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int idle_handle::stop() {
|
||||||
|
return uv_idle_stop(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/lib.cpp
Normal file
2
src/uvw/lib.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
#include "lib.ipp"
|
||||||
@ -1,41 +1,33 @@
|
|||||||
#pragma once
|
#ifndef UVW_LIB_INCLUDE_H
|
||||||
|
#define UVW_LIB_INCLUDE_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
#include "loop.hpp"
|
#include "config.h"
|
||||||
#include "underlying_type.hpp"
|
#include "loop.h"
|
||||||
|
#include "uv_type.hpp"
|
||||||
|
|
||||||
namespace uvw {
|
namespace uvw {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The SharedLib class.
|
* @brief The shared lib class.
|
||||||
*
|
*
|
||||||
* `uvw` provides cross platform utilities for loading shared libraries and
|
* `uvw` provides cross platform utilities for loading shared libraries and
|
||||||
* retrieving symbols from them, by means of the API offered by `libuv`.
|
* retrieving symbols from them, by means of the API offered by `libuv`.
|
||||||
*/
|
*/
|
||||||
class SharedLib final: public UnderlyingType<SharedLib, uv_lib_t> {
|
class shared_lib final: public uv_type<uv_lib_t> {
|
||||||
public:
|
public:
|
||||||
explicit SharedLib(ConstructorAccess ca, std::shared_ptr<Loop> ref, std::string filename) noexcept
|
explicit shared_lib(loop::token token, std::shared_ptr<loop> ref, const std::string &filename) noexcept;
|
||||||
: UnderlyingType{ca, std::move(ref)}
|
|
||||||
{
|
|
||||||
opened = (0 == uv_dlopen(filename.data(), get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
~SharedLib() noexcept {
|
~shared_lib() noexcept;
|
||||||
uv_dlclose(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if the library has been correctly opened.
|
* @brief Checks if the library has been correctly opened.
|
||||||
* @return True if the library is opened, false otherwise.
|
* @return True if the library is opened, false otherwise.
|
||||||
*/
|
*/
|
||||||
explicit operator bool() const noexcept { return opened; }
|
explicit operator bool() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves a data pointer from a dynamic library.
|
* @brief Retrieves a data pointer from a dynamic library.
|
||||||
@ -47,11 +39,13 @@ public:
|
|||||||
* @return A valid function pointer in case of success, `nullptr` otherwise.
|
* @return A valid function pointer in case of success, `nullptr` otherwise.
|
||||||
*/
|
*/
|
||||||
template<typename F>
|
template<typename F>
|
||||||
F * sym(std::string name) {
|
F *sym(const std::string &name) {
|
||||||
static_assert(std::is_function<F>::value, "!");
|
static_assert(std::is_function_v<F>);
|
||||||
F *func;
|
F *func;
|
||||||
auto err = uv_dlsym(get(), name.data(), reinterpret_cast<void**>(&func));
|
auto err = uv_dlsym(raw(), name.data(), reinterpret_cast<void **>(&func));
|
||||||
if(err) { func = nullptr; }
|
if(err) {
|
||||||
|
func = nullptr;
|
||||||
|
}
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,13 +53,16 @@ public:
|
|||||||
* @brief Returns the last error message, if any.
|
* @brief Returns the last error message, if any.
|
||||||
* @return The last error message, if any.
|
* @return The last error message, if any.
|
||||||
*/
|
*/
|
||||||
const char * error() const noexcept {
|
[[nodiscard]] const char *error() const noexcept;
|
||||||
return uv_dlerror(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool opened;
|
bool opened;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
}
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "lib.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_LIB_INCLUDE_H
|
||||||
23
src/uvw/lib.ipp
Normal file
23
src/uvw/lib.ipp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <utility>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE shared_lib::shared_lib(loop::token token, std::shared_ptr<loop> ref, const std::string &filename) noexcept
|
||||||
|
: uv_type{token, std::move(ref)} {
|
||||||
|
opened = (0 == uv_dlopen(filename.data(), raw()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE shared_lib::~shared_lib() noexcept {
|
||||||
|
uv_dlclose(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE shared_lib::operator bool() const noexcept {
|
||||||
|
return opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE const char *shared_lib::error() const noexcept {
|
||||||
|
return uv_dlerror(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/loop.cpp
Normal file
2
src/uvw/loop.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "loop.h"
|
||||||
|
#include "loop.ipp"
|
||||||
439
src/uvw/loop.h
Normal file
439
src/uvw/loop.h
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
#ifndef UVW_LOOP_INCLUDE_H
|
||||||
|
#define UVW_LOOP_INCLUDE_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# include <ciso646>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "emitter.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
class async_handle;
|
||||||
|
class check_handle;
|
||||||
|
class fs_event_handle;
|
||||||
|
class fs_poll_handle;
|
||||||
|
class idle_handle;
|
||||||
|
class pipe_handle;
|
||||||
|
class poll_handle;
|
||||||
|
class prepare_handle;
|
||||||
|
class process_handle;
|
||||||
|
class signal_handle;
|
||||||
|
class tcp_handle;
|
||||||
|
class timer_handle;
|
||||||
|
class tty_handle;
|
||||||
|
class udp_handle;
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
enum class uvw_loop_option : std::underlying_type_t<uv_loop_option> {
|
||||||
|
BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL,
|
||||||
|
IDLE_TIME = UV_METRICS_IDLE_TIME
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class uvw_run_mode : std::underlying_type_t<uv_run_mode> {
|
||||||
|
DEFAULT = UV_RUN_DEFAULT,
|
||||||
|
ONCE = UV_RUN_ONCE,
|
||||||
|
NOWAIT = UV_RUN_NOWAIT
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
using metrics_type = uv_metrics_t; /*!< Library equivalent for uv_metrics_t. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The loop class.
|
||||||
|
*
|
||||||
|
* The event loop is the central part of `uvw`'s functionalities, as well as
|
||||||
|
* `libuv`'s ones.<br/>
|
||||||
|
* It takes care of polling for I/O and scheduling callbacks to be run based on
|
||||||
|
* different sources of events.
|
||||||
|
*/
|
||||||
|
class loop final: public emitter<loop>, public std::enable_shared_from_this<loop> {
|
||||||
|
using deleter = void (*)(uv_loop_t *);
|
||||||
|
|
||||||
|
template<typename, typename, typename...>
|
||||||
|
friend class resource;
|
||||||
|
|
||||||
|
class uv_token {
|
||||||
|
friend class loop;
|
||||||
|
explicit uv_token(int) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
auto init(int, Type &value) -> decltype(value.init()) {
|
||||||
|
return value.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
int init(char, Type &) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop(std::unique_ptr<uv_loop_t, deleter> ptr) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using token = uv_token;
|
||||||
|
using time = std::chrono::duration<uint64_t, std::milli>;
|
||||||
|
using option = details::uvw_loop_option;
|
||||||
|
using run_mode = details::uvw_run_mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a new loop instance.
|
||||||
|
* @return A pointer to the newly created loop.
|
||||||
|
*/
|
||||||
|
static std::shared_ptr<loop> create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a new loop instance from an existing resource.
|
||||||
|
*
|
||||||
|
* The lifetime of the resource must exceed that of the instance to which
|
||||||
|
* it's associated. Management of the memory associated with the resource is
|
||||||
|
* in charge of the user.
|
||||||
|
*
|
||||||
|
* @param res A valid pointer to a correctly initialized resource.
|
||||||
|
* @return A pointer to the newly created loop.
|
||||||
|
*/
|
||||||
|
static std::shared_ptr<loop> create(uv_loop_t *res);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the initialized default loop.
|
||||||
|
*
|
||||||
|
* It may return an empty pointer in case of failure.<br>
|
||||||
|
* This function is just a convenient way for having a global loop
|
||||||
|
* throughout an application, the default loop is in no way different than
|
||||||
|
* the ones initialized with `create()`.<br>
|
||||||
|
* As such, the default loop can be closed with `close()` so the resources
|
||||||
|
* associated with it are freed (even if it is not strictly necessary).
|
||||||
|
*
|
||||||
|
* @return The initialized default loop.
|
||||||
|
*/
|
||||||
|
static std::shared_ptr<loop> get_default();
|
||||||
|
|
||||||
|
loop(const loop &) = delete;
|
||||||
|
loop(loop &&other) = delete;
|
||||||
|
|
||||||
|
loop &operator=(const loop &) = delete;
|
||||||
|
loop &operator=(loop &&other) = delete;
|
||||||
|
|
||||||
|
~loop() noexcept override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets additional loop options.
|
||||||
|
*
|
||||||
|
* You should normally call this before the first call to uv_run() unless
|
||||||
|
* mentioned otherwise.<br/>
|
||||||
|
* Supported options:
|
||||||
|
*
|
||||||
|
* * `loop::option::BLOCK_SIGNAL`: Block a signal when polling for new
|
||||||
|
* events. A second argument is required and it is the signal number.
|
||||||
|
* * `loop::option::IDLE_TIME`: Accumulate the amount of idle time the event
|
||||||
|
* loop spends in the event provider. This option is necessary to use
|
||||||
|
* `idle_time()`.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
int configure(option flag, Args &&...args) {
|
||||||
|
return uv_loop_configure(uv_loop.get(), static_cast<uv_loop_option>(flag), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates resources of any type.
|
||||||
|
*
|
||||||
|
* This should be used as a default method to create resources.<br/>
|
||||||
|
* The arguments are the ones required for the specific resource.
|
||||||
|
*
|
||||||
|
* Use it as `loop->resource<uvw::timer_handle>()`.
|
||||||
|
*
|
||||||
|
* @return A pointer to the newly created resource.
|
||||||
|
*/
|
||||||
|
template<typename R, typename... Args>
|
||||||
|
std::shared_ptr<R> resource(Args &&...args) {
|
||||||
|
auto ptr = uninitialized_resource<R>(std::forward<Args>(args)...);
|
||||||
|
return (init(0, *ptr) == 0) ? ptr : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates uninitialized resources of any type.
|
||||||
|
* @return A pointer to the newly created resource.
|
||||||
|
*/
|
||||||
|
template<typename R, typename... Args>
|
||||||
|
std::shared_ptr<R> uninitialized_resource(Args &&...args) {
|
||||||
|
return std::make_shared<R>(token{0}, shared_from_this(), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Releases all internal loop resources.
|
||||||
|
*
|
||||||
|
* Call this function only when the loop has finished executing and all open
|
||||||
|
* handles and requests have been closed, or the loop will error.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Runs the event loop.
|
||||||
|
*
|
||||||
|
* Available modes are:
|
||||||
|
*
|
||||||
|
* * `loop::run_mode::DEFAULT`: Runs the event loop until there are no more
|
||||||
|
* active and referenced handles or requests.
|
||||||
|
* * `loop::run_mode::ONCE`: Poll for i/o once. Note that this function
|
||||||
|
* blocks if there are no pending callbacks.
|
||||||
|
* * `loop::run_mode::NOWAIT`: Poll for i/o once but don’t block if there
|
||||||
|
* are no pending callbacks.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int run(run_mode mode = run_mode::DEFAULT) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if there are active resources.
|
||||||
|
* @return True if there are active resources in the loop.
|
||||||
|
*/
|
||||||
|
bool alive() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the event loop.
|
||||||
|
*
|
||||||
|
* It causes `run()` to end as soon as possible.<br/>
|
||||||
|
* This will happen not sooner than the next loop iteration.<br/>
|
||||||
|
* If this function was called before blocking for I/O, the loop won’t block
|
||||||
|
* for I/O on this iteration.
|
||||||
|
*/
|
||||||
|
void stop() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get backend file descriptor.
|
||||||
|
*
|
||||||
|
* Only kqueue, epoll and event ports are supported.<br/>
|
||||||
|
* This can be used in conjunction with `run(loop::run_mode::NOWAIT)` to
|
||||||
|
* poll in one thread and run the event loop’s callbacks in another.
|
||||||
|
*
|
||||||
|
* @return The backend file descriptor.
|
||||||
|
*/
|
||||||
|
int descriptor() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the poll timeout.
|
||||||
|
* @return A `std::pair` composed as it follows:
|
||||||
|
* * A boolean value that is true in case of valid timeout, false otherwise.
|
||||||
|
* * Milliseconds (`std::chrono::duration<uint64_t, std::milli>`).
|
||||||
|
*/
|
||||||
|
std::pair<bool, time> timeout() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the amount of time the event loop has been idle. The call
|
||||||
|
* is thread safe.
|
||||||
|
* @return The accumulated time spent idle.
|
||||||
|
*/
|
||||||
|
time idle_time() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracks various internal operations of the event loop.
|
||||||
|
* @return Event loop metrics.
|
||||||
|
*/
|
||||||
|
metrics_type metrics() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the current timestamp in milliseconds.
|
||||||
|
*
|
||||||
|
* The timestamp is cached at the start of the event loop tick.<br/>
|
||||||
|
* The timestamp increases monotonically from some arbitrary point in
|
||||||
|
* time.<br/>
|
||||||
|
* Don’t make assumptions about the starting point, you will only get
|
||||||
|
* disappointed.
|
||||||
|
*
|
||||||
|
* @return The current timestamp in milliseconds (actual type is
|
||||||
|
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||||
|
*/
|
||||||
|
time now() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates the event loop’s concept of _now_.
|
||||||
|
*
|
||||||
|
* The current time is cached at the start of the event loop tick in order
|
||||||
|
* to reduce the number of time-related system calls.<br/>
|
||||||
|
* You won’t normally need to call this function unless you have callbacks
|
||||||
|
* that block the event loop for longer periods of time, where _longer_ is
|
||||||
|
* somewhat subjective but probably on the order of a millisecond or more.
|
||||||
|
*/
|
||||||
|
void update() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Walks the list of handles.
|
||||||
|
*
|
||||||
|
* The callback is invoked once for each handle that is still active.
|
||||||
|
*
|
||||||
|
* @param callback A function to invoke once for each active handle.
|
||||||
|
*/
|
||||||
|
template<typename Func>
|
||||||
|
void walk(Func callback) {
|
||||||
|
auto func = [](uv_handle_t *hndl, void *callback_func) {
|
||||||
|
if(hndl->data) {
|
||||||
|
auto &cb = *static_cast<Func *>(callback_func);
|
||||||
|
|
||||||
|
switch(utilities::guess_handle(handle_category{hndl->type})) {
|
||||||
|
case handle_type::ASYNC:
|
||||||
|
cb(*static_cast<async_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::CHECK:
|
||||||
|
cb(*static_cast<check_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::FS_EVENT:
|
||||||
|
cb(*static_cast<fs_event_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::FS_POLL:
|
||||||
|
cb(*static_cast<fs_poll_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::IDLE:
|
||||||
|
cb(*static_cast<idle_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::PIPE:
|
||||||
|
cb(*static_cast<pipe_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::POLL:
|
||||||
|
cb(*static_cast<poll_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::PREPARE:
|
||||||
|
cb(*static_cast<prepare_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::PROCESS:
|
||||||
|
cb(*static_cast<process_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::SIGNAL:
|
||||||
|
cb(*static_cast<signal_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::TCP:
|
||||||
|
cb(*static_cast<tcp_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::TIMER:
|
||||||
|
cb(*static_cast<timer_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::TTY:
|
||||||
|
cb(*static_cast<tty_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
case handle_type::UDP:
|
||||||
|
cb(*static_cast<udp_handle *>(hndl->data));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// this handle isn't managed by uvw, let it be...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uv_walk(uv_loop.get(), func, &callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reinitialize any kernel state necessary in the child process after
|
||||||
|
* a fork(2) system call.
|
||||||
|
*
|
||||||
|
* Previously started watchers will continue to be started in the child
|
||||||
|
* process.
|
||||||
|
*
|
||||||
|
* It is necessary to explicitly call this function on every event loop
|
||||||
|
* created in the parent process that you plan to continue to use in the
|
||||||
|
* child, including the default loop (even if you don’t continue to use it
|
||||||
|
* in the parent). This function must be called before calling any API
|
||||||
|
* function using the loop in the child. Failure to do so will result in
|
||||||
|
* undefined behaviour, possibly including duplicate events delivered to
|
||||||
|
* both parent and child or aborting the child process.
|
||||||
|
*
|
||||||
|
* When possible, it is preferred to create a new loop in the child process
|
||||||
|
* instead of reusing a loop created in the parent. New loops created in the
|
||||||
|
* child process after the fork should not use this function.
|
||||||
|
*
|
||||||
|
* Note that this function is not implemented on Windows.<br/>
|
||||||
|
* Note also that this function is experimental in `libuv`. It may contain
|
||||||
|
* bugs, and is subject to change or removal. API and ABI stability is not
|
||||||
|
* guaranteed.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int fork() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets user-defined data. `uvw` won't use this field in any case.
|
||||||
|
* @return User-defined data if any, an invalid pointer otherwise.
|
||||||
|
*/
|
||||||
|
template<typename R = void>
|
||||||
|
std::shared_ptr<R> data() const {
|
||||||
|
return std::static_pointer_cast<R>(user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets arbitrary data. `uvw` won't use this field in any case.
|
||||||
|
* @param ud User-defined arbitrary data.
|
||||||
|
*/
|
||||||
|
void data(std::shared_ptr<void> ud);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the underlying raw data structure.
|
||||||
|
*
|
||||||
|
* This function should not be used, unless you know exactly what you are
|
||||||
|
* doing and what are the risks.<br/>
|
||||||
|
* Going raw is dangerous, mainly because the lifetime management of a loop,
|
||||||
|
* a handle or a request is in charge to the library itself and users should
|
||||||
|
* not work around it.
|
||||||
|
*
|
||||||
|
* @warning
|
||||||
|
* Use this function at your own risk, but do not expect any support in case
|
||||||
|
* of bugs.
|
||||||
|
*
|
||||||
|
* @return The underlying raw data structure.
|
||||||
|
*/
|
||||||
|
const uv_loop_t *raw() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the underlying raw data structure.
|
||||||
|
*
|
||||||
|
* This function should not be used, unless you know exactly what you are
|
||||||
|
* doing and what are the risks.<br/>
|
||||||
|
* Going raw is dangerous, mainly because the lifetime management of a loop,
|
||||||
|
* a handle or a request is in charge to the library itself and users should
|
||||||
|
* not work around it.
|
||||||
|
*
|
||||||
|
* @warning
|
||||||
|
* Use this function at your own risk, but do not expect any support in case
|
||||||
|
* of bugs.
|
||||||
|
*
|
||||||
|
* @return The underlying raw data structure.
|
||||||
|
*/
|
||||||
|
uv_loop_t *raw() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<uv_loop_t, deleter> uv_loop;
|
||||||
|
std::shared_ptr<void> user_data{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "loop.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_LOOP_INCLUDE_H
|
||||||
496
src/uvw/loop.hpp
496
src/uvw/loop.hpp
@ -1,496 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <ciso646>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <chrono>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "emitter.hpp"
|
|
||||||
#include "util.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVLoopOption: typename std::underlying_type<uv_loop_option>::type {
|
|
||||||
BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVRunMode: typename std::underlying_type<uv_run_mode>::type {
|
|
||||||
DEFAULT = UV_RUN_DEFAULT,
|
|
||||||
ONCE = UV_RUN_ONCE,
|
|
||||||
NOWAIT = UV_RUN_NOWAIT
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Untyped handle class
|
|
||||||
*
|
|
||||||
* Handles' types are unknown from the point of view of the loop.<br/>
|
|
||||||
* Anyway, a loop maintains a list of all the associated handles and let the
|
|
||||||
* users walk them as untyped instances.<br/>
|
|
||||||
* This can help to end all the pending requests by closing the handles.
|
|
||||||
*/
|
|
||||||
struct BaseHandle {
|
|
||||||
/**
|
|
||||||
* @brief Gets the category of the handle.
|
|
||||||
*
|
|
||||||
* A base handle offers no functionality to promote it to the actual handle
|
|
||||||
* type. By means of this function, an opaque value that identifies the
|
|
||||||
* category of the handle is made available to the users.
|
|
||||||
*
|
|
||||||
* @return The actual category of the handle.
|
|
||||||
*/
|
|
||||||
virtual HandleCategory category() const noexcept = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the type of the handle.
|
|
||||||
*
|
|
||||||
* A base handle offers no functionality to promote it to the actual handle
|
|
||||||
* type. By means of this function, the type of the underlying handle as
|
|
||||||
* specified by HandleType is made available to the user.
|
|
||||||
*
|
|
||||||
* @return The actual type of the handle.
|
|
||||||
*/
|
|
||||||
virtual HandleType type() const noexcept = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the handle is active.
|
|
||||||
*
|
|
||||||
* What _active_ means depends on the type of handle:
|
|
||||||
*
|
|
||||||
* * An AsyncHandle handle is always active and cannot be deactivated,
|
|
||||||
* except by closing it with uv_close().
|
|
||||||
* * A PipeHandle, TCPHandle, UDPHandle, etc. handle - basically any handle
|
|
||||||
* that deals with I/O - is active when it is doing something that involves
|
|
||||||
* I/O, like reading, writing, connecting, accepting new connections, etc.
|
|
||||||
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
|
|
||||||
* has been started with a call to `start()`.
|
|
||||||
*
|
|
||||||
* Rule of thumb: if a handle of type `FooHandle` has a `start()` member
|
|
||||||
* method, then it’s active from the moment that method is called. Likewise,
|
|
||||||
* `stop()` deactivates the handle again.
|
|
||||||
*
|
|
||||||
* @return True if the handle is active, false otherwise.
|
|
||||||
*/
|
|
||||||
virtual bool active() const noexcept = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a handle is closing or closed.
|
|
||||||
*
|
|
||||||
* This function should only be used between the initialization of the
|
|
||||||
* handle and the arrival of the close callback.
|
|
||||||
*
|
|
||||||
* @return True if the handle is closing or closed, false otherwise.
|
|
||||||
*/
|
|
||||||
virtual bool closing() const noexcept = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reference the given handle.
|
|
||||||
*
|
|
||||||
* References are idempotent, that is, if a handle is already referenced
|
|
||||||
* calling this function again will have no effect.
|
|
||||||
*/
|
|
||||||
virtual void reference() noexcept = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unreference the given handle.
|
|
||||||
*
|
|
||||||
* References are idempotent, that is, if a handle is not referenced calling
|
|
||||||
* this function again will have no effect.
|
|
||||||
*/
|
|
||||||
virtual void unreference() noexcept = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the given handle referenced.
|
|
||||||
* @return True if the handle referenced, false otherwise.
|
|
||||||
*/
|
|
||||||
virtual bool referenced() const noexcept = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Request handle to be closed.
|
|
||||||
*
|
|
||||||
* This **must** be called on each handle before memory is released.<br/>
|
|
||||||
* In-progress requests are cancelled and this can result in an ErrorEvent
|
|
||||||
* emitted.
|
|
||||||
*/
|
|
||||||
virtual void close() noexcept = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The Loop class.
|
|
||||||
*
|
|
||||||
* The event loop is the central part of `uvw`'s functionalities, as well as
|
|
||||||
* `libuv`'s ones.<br/>
|
|
||||||
* It takes care of polling for I/O and scheduling callbacks to be run based on
|
|
||||||
* different sources of events.
|
|
||||||
*/
|
|
||||||
class Loop final: public Emitter<Loop>, public std::enable_shared_from_this<Loop> {
|
|
||||||
using Deleter = void(*)(uv_loop_t *);
|
|
||||||
|
|
||||||
template<typename, typename>
|
|
||||||
friend class Resource;
|
|
||||||
|
|
||||||
Loop(std::unique_ptr<uv_loop_t, Deleter> ptr) noexcept
|
|
||||||
: loop{std::move(ptr)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Time = std::chrono::duration<uint64_t, std::milli>;
|
|
||||||
using Configure = details::UVLoopOption;
|
|
||||||
using Mode = details::UVRunMode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes a new Loop instance.
|
|
||||||
* @return A pointer to the newly created loop.
|
|
||||||
*/
|
|
||||||
static std::shared_ptr<Loop> create() {
|
|
||||||
auto ptr = std::unique_ptr<uv_loop_t, Deleter>{new uv_loop_t, [](uv_loop_t *l){ delete l; }};
|
|
||||||
auto loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}};
|
|
||||||
|
|
||||||
if(uv_loop_init(loop->loop.get())) {
|
|
||||||
loop = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the initialized default loop.
|
|
||||||
*
|
|
||||||
* It may return an empty pointer in case of failure.<br>
|
|
||||||
* This function is just a convenient way for having a global loop
|
|
||||||
* throughout an application, the default loop is in no way different than
|
|
||||||
* the ones initialized with `create()`.<br>
|
|
||||||
* As such, the default loop can be closed with `close()` so the resources
|
|
||||||
* associated with it are freed (even if it is not strictly necessary).
|
|
||||||
*
|
|
||||||
* @return The initialized default loop.
|
|
||||||
*/
|
|
||||||
static std::shared_ptr<Loop> getDefault() {
|
|
||||||
static std::weak_ptr<Loop> ref;
|
|
||||||
std::shared_ptr<Loop> loop;
|
|
||||||
|
|
||||||
if(ref.expired()) {
|
|
||||||
auto def = uv_default_loop();
|
|
||||||
|
|
||||||
if(def) {
|
|
||||||
auto ptr = std::unique_ptr<uv_loop_t, Deleter>(def, [](uv_loop_t *){});
|
|
||||||
loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}};
|
|
||||||
}
|
|
||||||
|
|
||||||
ref = loop;
|
|
||||||
} else {
|
|
||||||
loop = ref.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
return loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
Loop(const Loop &) = delete;
|
|
||||||
Loop(Loop &&other) = delete;
|
|
||||||
Loop & operator=(const Loop &) = delete;
|
|
||||||
Loop & operator=(Loop &&other) = delete;
|
|
||||||
|
|
||||||
~Loop() noexcept {
|
|
||||||
if(loop) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets additional loop options.
|
|
||||||
*
|
|
||||||
* You should normally call this before the first call to uv_run() unless
|
|
||||||
* mentioned otherwise.<br/>
|
|
||||||
* Supported options:
|
|
||||||
*
|
|
||||||
* * `Loop::Configure::BLOCK_SIGNAL`: Block a signal when polling for new
|
|
||||||
* events. A second argument is required and it is the signal number.
|
|
||||||
*
|
|
||||||
* An ErrorEvent will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
template<typename... Args>
|
|
||||||
void configure(Configure flag, Args&&... args) {
|
|
||||||
auto option = static_cast<typename std::underlying_type<Configure>::type>(flag);
|
|
||||||
auto err = uv_loop_configure(loop.get(), static_cast<uv_loop_option>(option), std::forward<Args>(args)...);
|
|
||||||
if(err) { publish(ErrorEvent{err}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates resources of handles' types.
|
|
||||||
*
|
|
||||||
* This should be used as a default method to create resources.<br/>
|
|
||||||
* The arguments are the ones required for the specific resource.
|
|
||||||
*
|
|
||||||
* Use it as `loop->resource<uvw::TimerHandle>()`.
|
|
||||||
*
|
|
||||||
* @return A pointer to the newly created resource.
|
|
||||||
*/
|
|
||||||
template<typename R, typename... Args>
|
|
||||||
typename std::enable_if<std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>::type
|
|
||||||
resource(Args&&... args) {
|
|
||||||
auto ptr = R::create(shared_from_this(), std::forward<Args>(args)...);
|
|
||||||
ptr = ptr->init() ? ptr : nullptr;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates resources of types other than handles' ones.
|
|
||||||
*
|
|
||||||
* This should be used as a default method to create resources.<br/>
|
|
||||||
* The arguments are the ones required for the specific resource.
|
|
||||||
*
|
|
||||||
* Use it as `loop->resource<uvw::WorkReq>()`.
|
|
||||||
*
|
|
||||||
* @return A pointer to the newly created resource.
|
|
||||||
*/
|
|
||||||
template<typename R, typename... Args>
|
|
||||||
typename std::enable_if<not std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>::type
|
|
||||||
resource(Args&&... args) {
|
|
||||||
return R::create(shared_from_this(), std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Releases all internal loop resources.
|
|
||||||
*
|
|
||||||
* Call this function only when the loop has finished executing and all open
|
|
||||||
* handles and requests have been closed, or the loop will emit an error.
|
|
||||||
*
|
|
||||||
* An ErrorEvent will be emitted in case of errors.
|
|
||||||
*/
|
|
||||||
void close() {
|
|
||||||
auto err = uv_loop_close(loop.get());
|
|
||||||
if(err) { publish(ErrorEvent{err}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Runs the event loop.
|
|
||||||
*
|
|
||||||
* Available modes are:
|
|
||||||
*
|
|
||||||
* * `Loop::Mode::DEFAULT`: Runs the event loop until there are no more
|
|
||||||
* active and referenced handles or requests.
|
|
||||||
* * `Loop::Mode::ONCE`: Poll for i/o once. Note that this function blocks
|
|
||||||
* if there are no pending callbacks.
|
|
||||||
* * `Loop::Mode::NOWAIT`: Poll for i/o once but don’t block if there are no
|
|
||||||
* pending callbacks.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run)
|
|
||||||
* for further details.
|
|
||||||
*
|
|
||||||
* @return True when done, false in all other cases.
|
|
||||||
*/
|
|
||||||
template<Mode mode = Mode::DEFAULT>
|
|
||||||
bool run() noexcept {
|
|
||||||
auto utm = static_cast<typename std::underlying_type<Mode>::type>(mode);
|
|
||||||
auto uvrm = static_cast<uv_run_mode>(utm);
|
|
||||||
return (uv_run(loop.get(), uvrm) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if there are active resources.
|
|
||||||
* @return True if there are active resources in the loop.
|
|
||||||
*/
|
|
||||||
bool alive() const noexcept {
|
|
||||||
return !(uv_loop_alive(loop.get()) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops the event loop.
|
|
||||||
*
|
|
||||||
* It causes `run()` to end as soon as possible.<br/>
|
|
||||||
* This will happen not sooner than the next loop iteration.<br/>
|
|
||||||
* If this function was called before blocking for I/O, the loop won’t block
|
|
||||||
* for I/O on this iteration.
|
|
||||||
*/
|
|
||||||
void stop() noexcept {
|
|
||||||
uv_stop(loop.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get backend file descriptor.
|
|
||||||
*
|
|
||||||
* Only kqueue, epoll and event ports are supported.<br/>
|
|
||||||
* This can be used in conjunction with `run<Loop::Mode::NOWAIT>()` to poll
|
|
||||||
* in one thread and run the event loop’s callbacks in another.
|
|
||||||
*
|
|
||||||
* @return The backend file descriptor.
|
|
||||||
*/
|
|
||||||
int descriptor() const noexcept {
|
|
||||||
return uv_backend_fd(loop.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the poll timeout.
|
|
||||||
* @return A `std::pair` composed as it follows:
|
|
||||||
* * A boolean value that is true in case of valid timeout, false otherwise.
|
|
||||||
* * Milliseconds (`std::chrono::duration<uint64_t, std::milli>`).
|
|
||||||
*/
|
|
||||||
std::pair<bool, Time> timeout() const noexcept {
|
|
||||||
auto to = uv_backend_timeout(loop.get());
|
|
||||||
return std::make_pair(to == -1, Time{to});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the current timestamp in milliseconds.
|
|
||||||
*
|
|
||||||
* The timestamp is cached at the start of the event loop tick.<br/>
|
|
||||||
* The timestamp increases monotonically from some arbitrary point in
|
|
||||||
* time.<br/>
|
|
||||||
* Don’t make assumptions about the starting point, you will only get
|
|
||||||
* disappointed.
|
|
||||||
*
|
|
||||||
* @return The current timestamp in milliseconds (actual type is
|
|
||||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
|
||||||
*/
|
|
||||||
Time now() const noexcept {
|
|
||||||
return Time{uv_now(loop.get())};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Updates the event loop’s concept of _now_.
|
|
||||||
*
|
|
||||||
* The current time is cached at the start of the event loop tick in order
|
|
||||||
* to reduce the number of time-related system calls.<br/>
|
|
||||||
* You won’t normally need to call this function unless you have callbacks
|
|
||||||
* that block the event loop for longer periods of time, where _longer_ is
|
|
||||||
* somewhat subjective but probably on the order of a millisecond or more.
|
|
||||||
*/
|
|
||||||
void update() const noexcept {
|
|
||||||
return uv_update_time(loop.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Walks the list of handles.
|
|
||||||
*
|
|
||||||
* The callback will be executed once for each handle that is still active.
|
|
||||||
*
|
|
||||||
* @param callback A function to be invoked once for each active handle.
|
|
||||||
*/
|
|
||||||
void walk(std::function<void(BaseHandle &)> callback) {
|
|
||||||
// remember: non-capturing lambdas decay to pointers to functions
|
|
||||||
uv_walk(loop.get(), [](uv_handle_t *handle, void *func) {
|
|
||||||
BaseHandle &ref = *static_cast<BaseHandle*>(handle->data);
|
|
||||||
std::function<void(BaseHandle &)> &f =
|
|
||||||
*static_cast<std::function<void(BaseHandle &)>*>(func);
|
|
||||||
f(ref);
|
|
||||||
}, &callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reinitialize any kernel state necessary in the child process after
|
|
||||||
* a fork(2) system call.
|
|
||||||
*
|
|
||||||
* Previously started watchers will continue to be started in the child
|
|
||||||
* process.
|
|
||||||
*
|
|
||||||
* It is necessary to explicitly call this function on every event loop
|
|
||||||
* created in the parent process that you plan to continue to use in the
|
|
||||||
* child, including the default loop (even if you don’t continue to use it
|
|
||||||
* in the parent). This function must be called before calling any API
|
|
||||||
* function using the loop in the child. Failure to do so will result in
|
|
||||||
* undefined behaviour, possibly including duplicate events delivered to
|
|
||||||
* both parent and child or aborting the child process.
|
|
||||||
*
|
|
||||||
* When possible, it is preferred to create a new loop in the child process
|
|
||||||
* instead of reusing a loop created in the parent. New loops created in the
|
|
||||||
* child process after the fork should not use this function.
|
|
||||||
*
|
|
||||||
* Note that this function is not implemented on Windows.<br/>
|
|
||||||
* Note also that this function is experimental in `libuv`. It may contain
|
|
||||||
* bugs, and is subject to change or removal. API and ABI stability is not
|
|
||||||
* guaranteed.
|
|
||||||
*
|
|
||||||
* An ErrorEvent will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
void fork() noexcept {
|
|
||||||
auto err = uv_loop_fork(loop.get());
|
|
||||||
if(err) { publish(ErrorEvent{err}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets user-defined data. `uvw` won't use this field in any case.
|
|
||||||
* @return User-defined data if any, an invalid pointer otherwise.
|
|
||||||
*/
|
|
||||||
template<typename R = void>
|
|
||||||
std::shared_ptr<R> data() const {
|
|
||||||
return std::static_pointer_cast<R>(userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets arbitrary data. `uvw` won't use this field in any case.
|
|
||||||
* @param uData User-defined arbitrary data.
|
|
||||||
*/
|
|
||||||
void data(std::shared_ptr<void> uData) {
|
|
||||||
userData = std::move(uData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the underlying raw data structure.
|
|
||||||
*
|
|
||||||
* This function should not be used, unless you know exactly what you are
|
|
||||||
* doing and what are the risks.<br/>
|
|
||||||
* Going raw is dangerous, mainly because the lifetime management of a loop,
|
|
||||||
* a handle or a request is in charge to the library itself and users should
|
|
||||||
* not work around it.
|
|
||||||
*
|
|
||||||
* @warning
|
|
||||||
* Use this function at your own risk, but do not expect any support in case
|
|
||||||
* of bugs.
|
|
||||||
*
|
|
||||||
* @return The underlying raw data structure.
|
|
||||||
*/
|
|
||||||
const uv_loop_t * raw() const noexcept {
|
|
||||||
return loop.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the underlying raw data structure.
|
|
||||||
*
|
|
||||||
* This function should not be used, unless you know exactly what you are
|
|
||||||
* doing and what are the risks.<br/>
|
|
||||||
* Going raw is dangerous, mainly because the lifetime management of a loop,
|
|
||||||
* a handle or a request is in charge to the library itself and users should
|
|
||||||
* not work around it.
|
|
||||||
*
|
|
||||||
* @warning
|
|
||||||
* Use this function at your own risk, but do not expect any support in case
|
|
||||||
* of bugs.
|
|
||||||
*
|
|
||||||
* @return The underlying raw data structure.
|
|
||||||
*/
|
|
||||||
uv_loop_t * raw() noexcept {
|
|
||||||
return const_cast<uv_loop_t *>(const_cast<const Loop *>(this)->raw());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<uv_loop_t, Deleter> loop;
|
|
||||||
std::shared_ptr<void> userData{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
116
src/uvw/loop.ipp
Normal file
116
src/uvw/loop.ipp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE loop::loop(std::unique_ptr<uv_loop_t, deleter> ptr) noexcept
|
||||||
|
: uv_loop{std::move(ptr)} {}
|
||||||
|
|
||||||
|
UVW_INLINE std::shared_ptr<loop> loop::create() {
|
||||||
|
auto ptr = std::unique_ptr<uv_loop_t, deleter>{new uv_loop_t, [](uv_loop_t *l) { delete l; }};
|
||||||
|
auto curr = std::shared_ptr<loop>{new loop{std::move(ptr)}};
|
||||||
|
|
||||||
|
if(uv_loop_init(curr->uv_loop.get())) {
|
||||||
|
curr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::shared_ptr<loop> loop::create(uv_loop_t *res) {
|
||||||
|
auto ptr = std::unique_ptr<uv_loop_t, deleter>{res, [](uv_loop_t *) {}};
|
||||||
|
return std::shared_ptr<loop>{new loop{std::move(ptr)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::shared_ptr<loop> loop::get_default() {
|
||||||
|
static std::weak_ptr<loop> ref;
|
||||||
|
std::shared_ptr<loop> curr;
|
||||||
|
|
||||||
|
if(ref.expired()) {
|
||||||
|
auto def = uv_default_loop();
|
||||||
|
|
||||||
|
if(def) {
|
||||||
|
auto ptr = std::unique_ptr<uv_loop_t, deleter>(def, [](uv_loop_t *) {});
|
||||||
|
curr = std::shared_ptr<loop>{new loop{std::move(ptr)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
ref = curr;
|
||||||
|
} else {
|
||||||
|
curr = ref.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE loop::~loop() noexcept {
|
||||||
|
if(uv_loop) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int loop::close() {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if(uv_loop) {
|
||||||
|
ret = uv_loop_close(uv_loop.get());
|
||||||
|
uv_loop.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int loop::run(run_mode mode) noexcept {
|
||||||
|
return uv_run(uv_loop.get(), static_cast<uv_run_mode>(mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool loop::alive() const noexcept {
|
||||||
|
return !!uv_loop_alive(uv_loop.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void loop::stop() noexcept {
|
||||||
|
uv_stop(uv_loop.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int loop::descriptor() const noexcept {
|
||||||
|
return uv_backend_fd(uv_loop.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::pair<bool, loop::time> loop::timeout() const noexcept {
|
||||||
|
auto to = uv_backend_timeout(uv_loop.get());
|
||||||
|
return std::make_pair(to == -1, time{to});
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE loop::time loop::idle_time() const noexcept {
|
||||||
|
return time{uv_metrics_idle_time(uv_loop.get())};
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE metrics_type loop::metrics() const noexcept {
|
||||||
|
metrics_type res{};
|
||||||
|
uv_metrics_info(uv_loop.get(), &res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE loop::time loop::now() const noexcept {
|
||||||
|
return time{uv_now(uv_loop.get())};
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void loop::update() const noexcept {
|
||||||
|
return uv_update_time(uv_loop.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int loop::fork() noexcept {
|
||||||
|
return uv_loop_fork(uv_loop.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void loop::data(std::shared_ptr<void> ud) {
|
||||||
|
user_data = std::move(ud);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE const uv_loop_t *loop::raw() const noexcept {
|
||||||
|
return uv_loop.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE uv_loop_t *loop::raw() noexcept {
|
||||||
|
return const_cast<uv_loop_t *>(const_cast<const loop *>(this)->raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/pipe.cpp
Normal file
2
src/uvw/pipe.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "pipe.h"
|
||||||
|
#include "pipe.ipp"
|
||||||
@ -1,117 +1,93 @@
|
|||||||
#pragma once
|
#ifndef UVW_PIPE_INCLUDE_H
|
||||||
|
#define UVW_PIPE_INCLUDE_H
|
||||||
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "enum.hpp"
|
||||||
|
#include "loop.h"
|
||||||
#include "request.hpp"
|
#include "request.hpp"
|
||||||
#include "stream.hpp"
|
#include "stream.h"
|
||||||
#include "util.hpp"
|
#include "util.h"
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
namespace uvw {
|
||||||
|
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
|
enum class uvw_chmod_flags : std::underlying_type_t<uv_poll_event> {
|
||||||
enum class UVChmodFlags: typename std::underlying_type<uv_poll_event>::type {
|
|
||||||
READABLE = UV_READABLE,
|
READABLE = UV_READABLE,
|
||||||
WRITABLE = UV_WRITABLE
|
WRITABLE = UV_WRITABLE,
|
||||||
|
UVW_ENUM = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The PipeHandle handle.
|
* @brief The pipe handle.
|
||||||
*
|
*
|
||||||
* Pipe handles provide an abstraction over local domain sockets on Unix and
|
* Pipe handles provide an abstraction over local domain sockets on Unix and
|
||||||
* named pipes on Windows.
|
* named pipes on Windows.
|
||||||
*
|
*
|
||||||
* To create a `PipeHandle` through a `Loop`, arguments follow:
|
* To create a `pipe_handle` through a `loop`, arguments follow:
|
||||||
*
|
*
|
||||||
* * An optional boolean value that indicates if this pipe will be used for
|
* * An optional boolean value that indicates if this pipe will be used for
|
||||||
* handle passing between processes.
|
* handle passing between processes.
|
||||||
*/
|
*/
|
||||||
class PipeHandle final: public StreamHandle<PipeHandle, uv_pipe_t> {
|
class pipe_handle final: public stream_handle<pipe_handle, uv_pipe_t> {
|
||||||
public:
|
public:
|
||||||
using Chmod = details::UVChmodFlags;
|
using chmod_flags = details::uvw_chmod_flags;
|
||||||
|
|
||||||
explicit PipeHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool pass = false)
|
explicit pipe_handle(loop::token token, std::shared_ptr<loop> ref, bool pass = false);
|
||||||
: StreamHandle{ca, std::move(ref)}, ipc{pass}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the handle.
|
* @brief Initializes the handle.
|
||||||
* @return True in case of success, false otherwise.
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
bool init() {
|
int init();
|
||||||
return initialize(&uv_pipe_init, ipc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Opens an existing file descriptor or HANDLE as a pipe.
|
* @brief Opens an existing file descriptor or HANDLE as a pipe.
|
||||||
*
|
*
|
||||||
* The passed file descriptor or HANDLE is not checked for its type, but
|
* The passed file descriptor or HANDLE is not checked for its type, but
|
||||||
* it’s required that it represents a valid pipe.<br/>
|
* it’s required that it represents a valid pipe.
|
||||||
* An ErrorEvent event is emitted in case of errors.
|
|
||||||
*
|
*
|
||||||
* @param file A valid file handle (either a file descriptor or a HANDLE).
|
* @param file A valid file handle (either a file descriptor or a HANDLE).
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
void open(FileHandle file) {
|
int open(file_handle file);
|
||||||
invoke(&uv_pipe_open, get(), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief bind Binds the pipe to a file path (Unix) or a name (Windows).
|
* @brief bind Binds the pipe to a file path (Unix) or a name (Windows).
|
||||||
*
|
*
|
||||||
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
|
* Paths on Unix get truncated typically between 92 and 108 bytes.
|
||||||
* An ErrorEvent event is emitted in case of errors.
|
|
||||||
*
|
*
|
||||||
* @param name A valid file path.
|
* @param name A valid file path.
|
||||||
|
* @param no_truncate Force an error rather than allow truncating a path.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
void bind(std::string name) {
|
int bind(const std::string &name, const bool no_truncate = false);
|
||||||
invoke(&uv_pipe_bind, get(), name.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Connects to the Unix domain socket or the named pipe.
|
* @brief Connects to the Unix domain socket or the named pipe.
|
||||||
*
|
*
|
||||||
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
|
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
|
||||||
* A ConnectEvent event is emitted when the connection has been
|
* A connect event is emitted when the connection has been
|
||||||
* established.<br/>
|
* established.
|
||||||
* An ErrorEvent event is emitted in case of errors during the connection.
|
|
||||||
*
|
*
|
||||||
* @param name A valid domain socket or named pipe.
|
* @param name A valid domain socket or named pipe.
|
||||||
|
* @param no_truncate Force an error rather than allow truncating a path.
|
||||||
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
void connect(std::string name) {
|
int connect(const std::string &name, const bool no_truncate = false);
|
||||||
auto ptr = shared_from_this();
|
|
||||||
auto errorEventListener = [ptr](const ErrorEvent &event, const details::ConnectReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
auto connectEventListener = [ptr](const ConnectEvent &event, const details::ConnectReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto connect = loop().resource<details::ConnectReq>();
|
|
||||||
connect->once<ErrorEvent>(errorEventListener);
|
|
||||||
connect->once<ConnectEvent>(connectEventListener);
|
|
||||||
connect->connect(&uv_pipe_connect, get(), name.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the name of the Unix domain socket or the named pipe.
|
* @brief Gets the name of the Unix domain socket or the named pipe.
|
||||||
* @return The name of the Unix domain socket or the named pipe, an empty
|
* @return The name of the Unix domain socket or the named pipe, an empty
|
||||||
* string in case of errors.
|
* string in case of errors.
|
||||||
*/
|
*/
|
||||||
std::string sock() const noexcept {
|
std::string sock() const noexcept;
|
||||||
return details::tryRead(&uv_pipe_getsockname, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the name of the Unix domain socket or the named pipe to which
|
* @brief Gets the name of the Unix domain socket or the named pipe to which
|
||||||
@ -119,9 +95,7 @@ public:
|
|||||||
* @return The name of the Unix domain socket or the named pipe to which
|
* @return The name of the Unix domain socket or the named pipe to which
|
||||||
* the handle is connected, an empty string in case of errors.
|
* the handle is connected, an empty string in case of errors.
|
||||||
*/
|
*/
|
||||||
std::string peer() const noexcept {
|
std::string peer() const noexcept;
|
||||||
return details::tryRead(&uv_pipe_getpeername, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the number of pending pipe this instance can handle.
|
* @brief Sets the number of pending pipe this instance can handle.
|
||||||
@ -132,17 +106,13 @@ public:
|
|||||||
*
|
*
|
||||||
* @param count The number of accepted pending pipe.
|
* @param count The number of accepted pending pipe.
|
||||||
*/
|
*/
|
||||||
void pending(int count) noexcept {
|
void pending(int count) noexcept;
|
||||||
uv_pipe_pending_instances(get(), count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the number of pending pipe this instance can handle.
|
* @brief Gets the number of pending pipe this instance can handle.
|
||||||
* @return The number of pending pipe this instance can handle.
|
* @return The number of pending pipe this instance can handle.
|
||||||
*/
|
*/
|
||||||
int pending() noexcept {
|
int pending() noexcept;
|
||||||
return uv_pipe_pending_count(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Used to receive handles over IPC pipes.
|
* @brief Used to receive handles over IPC pipes.
|
||||||
@ -155,15 +125,12 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The type of the pending handle. Possible values are:
|
* @return The type of the pending handle. Possible values are:
|
||||||
*
|
*
|
||||||
* * `HandleType::PIPE`
|
* * `handle_type::PIPE`
|
||||||
* * `HandleType::TCP`
|
* * `handle_type::TCP`
|
||||||
* * `HandleType::UDP`
|
* * `handle_type::UDP`
|
||||||
* * `HandleType::UNKNOWN`
|
* * `handle_type::UNKNOWN`
|
||||||
*/
|
*/
|
||||||
HandleType receive() noexcept {
|
handle_type receive() noexcept;
|
||||||
HandleCategory category = uv_pipe_pending_type(get());
|
|
||||||
return Utilities::guessHandle(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Alters pipe permissions.
|
* @brief Alters pipe permissions.
|
||||||
@ -172,23 +139,26 @@ public:
|
|||||||
*
|
*
|
||||||
* Available flags are:
|
* Available flags are:
|
||||||
*
|
*
|
||||||
* * `PipeHandle::Chmod::READABLE`
|
* * `pipe_handle::chmod_flags::READABLE`
|
||||||
* * `PipeHandle::Chmod::WRITABLE`
|
* * `pipe_handle::chmod_flags::WRITABLE`
|
||||||
*
|
*
|
||||||
* See the official
|
* See the official
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod)
|
* [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod)
|
||||||
* for further details.
|
* for further details.
|
||||||
*
|
*
|
||||||
* @param flags A valid set of flags.
|
* @param flags A valid set of flags.
|
||||||
* @return True in case of success, false otherwise.
|
* @return Underlying return value.
|
||||||
*/
|
*/
|
||||||
bool chmod(Flags<Chmod> flags) noexcept {
|
int chmod(chmod_flags flags) noexcept;
|
||||||
return (0 == uv_pipe_chmod(get(), flags));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ipc;
|
bool ipc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
}
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "pipe.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_PIPE_INCLUDE_H
|
||||||
59
src/uvw/pipe.ipp
Normal file
59
src/uvw/pipe.ipp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include <utility>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE pipe_handle::pipe_handle(loop::token token, std::shared_ptr<loop> ref, bool pass)
|
||||||
|
: stream_handle{token, std::move(ref)}, ipc{pass} {}
|
||||||
|
|
||||||
|
UVW_INLINE int pipe_handle::init() {
|
||||||
|
return leak_if(uv_pipe_init(parent().raw(), raw(), ipc));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int pipe_handle::open(file_handle file) {
|
||||||
|
return uv_pipe_open(raw(), file);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int pipe_handle::bind(const std::string &name, const bool no_truncate) {
|
||||||
|
return uv_pipe_bind2(raw(), name.data(), name.size(), no_truncate * UV_PIPE_NO_TRUNCATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int pipe_handle::connect(const std::string &name, const bool no_truncate) {
|
||||||
|
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
|
||||||
|
ptr->publish(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto connect = parent().resource<details::connect_req>();
|
||||||
|
connect->on<error_event>(listener);
|
||||||
|
connect->on<connect_event>(listener);
|
||||||
|
|
||||||
|
unsigned int flags = no_truncate * UV_PIPE_NO_TRUNCATE;
|
||||||
|
return connect->connect(&uv_pipe_connect2, raw(), name.data(), name.size(), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::string pipe_handle::sock() const noexcept {
|
||||||
|
return details::try_read(&uv_pipe_getsockname, raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE std::string pipe_handle::peer() const noexcept {
|
||||||
|
return details::try_read(&uv_pipe_getpeername, raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void pipe_handle::pending(int count) noexcept {
|
||||||
|
uv_pipe_pending_instances(raw(), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int pipe_handle::pending() noexcept {
|
||||||
|
return uv_pipe_pending_count(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE handle_type pipe_handle::receive() noexcept {
|
||||||
|
handle_category category = uv_pipe_pending_type(raw());
|
||||||
|
return utilities::guess_handle(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int pipe_handle::chmod(chmod_flags flags) noexcept {
|
||||||
|
return uv_pipe_chmod(raw(), static_cast<uv_poll_event>(flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/poll.cpp
Normal file
2
src/uvw/poll.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "poll.h"
|
||||||
|
#include "poll.ipp"
|
||||||
119
src/uvw/poll.h
Normal file
119
src/uvw/poll.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#ifndef UVW_POLL_INCLUDE_H
|
||||||
|
#define UVW_POLL_INCLUDE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "enum.hpp"
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
enum class uvw_poll_event : std::underlying_type_t<uv_poll_event> {
|
||||||
|
READABLE = UV_READABLE,
|
||||||
|
WRITABLE = UV_WRITABLE,
|
||||||
|
DISCONNECT = UV_DISCONNECT,
|
||||||
|
PRIORITIZED = UV_PRIORITIZED,
|
||||||
|
UVW_ENUM = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Poll event. */
|
||||||
|
struct poll_event {
|
||||||
|
explicit poll_event(details::uvw_poll_event events) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Detected events all in one.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `poll_handle::event::READABLE`
|
||||||
|
* * `poll_handle::event::WRITABLE`
|
||||||
|
* * `poll_handle::event::DISCONNECT`
|
||||||
|
* * `poll_handle::event::PRIORITIZED`
|
||||||
|
*/
|
||||||
|
details::uvw_poll_event flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The poll handle.
|
||||||
|
*
|
||||||
|
* Poll handles are used to watch file descriptors for readability, writability
|
||||||
|
* and disconnection.
|
||||||
|
*
|
||||||
|
* To create a `poll_handle` through a `loop`, arguments follow:
|
||||||
|
*
|
||||||
|
* * A descriptor that can be:
|
||||||
|
* * either an `int` file descriptor
|
||||||
|
* * or a `os_socket_handle` socket descriptor
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/poll.html)
|
||||||
|
* for further details.
|
||||||
|
*/
|
||||||
|
class poll_handle final: public handle<poll_handle, uv_poll_t, poll_event> {
|
||||||
|
static void start_callback(uv_poll_t *hndl, int status, int events);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using poll_event_flags = details::uvw_poll_event;
|
||||||
|
|
||||||
|
explicit poll_handle(loop::token token, std::shared_ptr<loop> ref, int desc);
|
||||||
|
explicit poll_handle(loop::token token, std::shared_ptr<loop> ref, os_socket_handle sock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts polling the file descriptor.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `poll_handle::event::READABLE`
|
||||||
|
* * `poll_handle::event::WRITABLE`
|
||||||
|
* * `poll_handle::event::DISCONNECT`
|
||||||
|
* * `poll_handle::event::PRIORITIZED`
|
||||||
|
*
|
||||||
|
* As soon as an event is detected, a poll event is emitted by the
|
||||||
|
* handle.
|
||||||
|
*
|
||||||
|
* Calling more than once this method will update the flags to which the
|
||||||
|
* caller is interested.
|
||||||
|
*
|
||||||
|
* @param flags The events to which the caller is interested.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int start(poll_event_flags flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops polling the file descriptor.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
FD,
|
||||||
|
SOCKET
|
||||||
|
} tag;
|
||||||
|
|
||||||
|
union {
|
||||||
|
int file_desc;
|
||||||
|
os_socket_handle socket;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "poll.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_POLL_INCLUDE_H
|
||||||
159
src/uvw/poll.hpp
159
src/uvw/poll.hpp
@ -1,159 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "util.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVPollEvent: typename std::underlying_type<uv_poll_event>::type {
|
|
||||||
READABLE = UV_READABLE,
|
|
||||||
WRITABLE = UV_WRITABLE,
|
|
||||||
DISCONNECT = UV_DISCONNECT,
|
|
||||||
PRIORITIZED = UV_PRIORITIZED
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief PollEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by PollHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct PollEvent {
|
|
||||||
explicit PollEvent(Flags<details::UVPollEvent> events) noexcept
|
|
||||||
: flags{std::move(events)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Detected events all in one.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `PollHandle::Event::READABLE`
|
|
||||||
* * `PollHandle::Event::WRITABLE`
|
|
||||||
* * `PollHandle::Event::DISCONNECT`
|
|
||||||
* * `PollHandle::Event::PRIORITIZED`
|
|
||||||
*/
|
|
||||||
Flags<details::UVPollEvent> flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The PollHandle handle.
|
|
||||||
*
|
|
||||||
* Poll handles are used to watch file descriptors for readability, writability
|
|
||||||
* and disconnection.
|
|
||||||
*
|
|
||||||
* To create a `PollHandle` through a `Loop`, arguments follow:
|
|
||||||
*
|
|
||||||
* * A descriptor that can be:
|
|
||||||
* * either an `int` file descriptor
|
|
||||||
* * or a `OSSocketHandle` socket descriptor
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/poll.html)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
class PollHandle final: public Handle<PollHandle, uv_poll_t> {
|
|
||||||
static void startCallback(uv_poll_t *handle, int status, int events) {
|
|
||||||
PollHandle &poll = *(static_cast<PollHandle*>(handle->data));
|
|
||||||
if(status) { poll.publish(ErrorEvent{status}); }
|
|
||||||
else { poll.publish(PollEvent{static_cast<typename std::underlying_type<Event>::type>(events)}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Event = details::UVPollEvent;
|
|
||||||
|
|
||||||
explicit PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, int desc)
|
|
||||||
: Handle{ca, std::move(ref)}, tag{FD}, fd{desc}
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, OSSocketHandle sock)
|
|
||||||
: Handle{ca, std::move(ref)}, tag{SOCKET}, socket{sock}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return (tag == SOCKET)
|
|
||||||
? initialize(&uv_poll_init_socket, socket)
|
|
||||||
: initialize(&uv_poll_init, fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts polling the file descriptor.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `PollHandle::Event::READABLE`
|
|
||||||
* * `PollHandle::Event::WRITABLE`
|
|
||||||
* * `PollHandle::Event::DISCONNECT`
|
|
||||||
* * `PollHandle::Event::PRIORITIZED`
|
|
||||||
*
|
|
||||||
* As soon as an event is detected, a PollEvent is emitted by the
|
|
||||||
* handle.<br>
|
|
||||||
* It could happen that ErrorEvent events are emitted while running.
|
|
||||||
*
|
|
||||||
* Calling more than once this method will update the flags to which the
|
|
||||||
* caller is interested.
|
|
||||||
*
|
|
||||||
* @param flags The events to which the caller is interested.
|
|
||||||
*/
|
|
||||||
void start(Flags<Event> flags) {
|
|
||||||
invoke(&uv_poll_start, get(), flags, &startCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts polling the file descriptor.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `PollHandle::Event::READABLE`
|
|
||||||
* * `PollHandle::Event::WRITABLE`
|
|
||||||
* * `PollHandle::Event::DISCONNECT`
|
|
||||||
* * `PollHandle::Event::PRIORITIZED`
|
|
||||||
*
|
|
||||||
* As soon as an event is detected, a PollEvent is emitted by the
|
|
||||||
* handle.<br>
|
|
||||||
* It could happen that ErrorEvent events are emitted while running.
|
|
||||||
*
|
|
||||||
* Calling more than once this method will update the flags to which the
|
|
||||||
* caller is interested.
|
|
||||||
*
|
|
||||||
* @param event The event to which the caller is interested.
|
|
||||||
*/
|
|
||||||
void start(Event event) {
|
|
||||||
start(Flags<Event>{event});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops polling the file descriptor.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
invoke(&uv_poll_stop, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { FD, SOCKET } tag;
|
|
||||||
union {
|
|
||||||
int fd;
|
|
||||||
OSSocketHandle::Type socket;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
40
src/uvw/poll.ipp
Normal file
40
src/uvw/poll.ipp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <utility>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE poll_event::poll_event(details::uvw_poll_event events) noexcept
|
||||||
|
: flags{events} {}
|
||||||
|
|
||||||
|
UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr<loop> ref, int desc)
|
||||||
|
: handle{token, std::move(ref)}, tag{FD}, file_desc{desc} {}
|
||||||
|
|
||||||
|
UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr<loop> ref, os_socket_handle sock)
|
||||||
|
: handle{token, std::move(ref)}, tag{SOCKET}, socket{sock} {}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||||
|
UVW_INLINE void poll_handle::start_callback(uv_poll_t *hndl, int status, int events) {
|
||||||
|
if(poll_handle &poll = *(static_cast<poll_handle *>(hndl->data)); status) {
|
||||||
|
poll.publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
poll.publish(poll_event{poll_event_flags(events)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int poll_handle::init() {
|
||||||
|
if(tag == SOCKET) {
|
||||||
|
return leak_if(uv_poll_init_socket(parent().raw(), raw(), socket));
|
||||||
|
} else {
|
||||||
|
return leak_if(uv_poll_init(parent().raw(), raw(), file_desc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int poll_handle::start(poll_event_flags flags) {
|
||||||
|
return uv_poll_start(raw(), static_cast<uv_poll_event>(flags), &start_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int poll_handle::stop() {
|
||||||
|
return uv_poll_stop(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/prepare.cpp
Normal file
2
src/uvw/prepare.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "prepare.h"
|
||||||
|
#include "prepare.ipp"
|
||||||
58
src/uvw/prepare.h
Normal file
58
src/uvw/prepare.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef UVW_PREPARE_INCLUDE_H
|
||||||
|
#define UVW_PREPARE_INCLUDE_H
|
||||||
|
|
||||||
|
#include <uv.h>
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Prepare event. */
|
||||||
|
struct prepare_event {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The prepare handle.
|
||||||
|
*
|
||||||
|
* Prepare handles will emit a prepare event once per loop iteration, right
|
||||||
|
* before polling for I/O.
|
||||||
|
*
|
||||||
|
* To create a `prepare_handle` through a `loop`, no arguments are required.
|
||||||
|
*/
|
||||||
|
class prepare_handle final: public handle<prepare_handle, uv_prepare_t, prepare_event> {
|
||||||
|
static void start_callback(uv_prepare_t *hndl);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using handle::handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts the handle.
|
||||||
|
*
|
||||||
|
* A prepare event will be emitted once per loop iteration, right before
|
||||||
|
* polling for I/O.
|
||||||
|
*
|
||||||
|
* The handle will start emitting prepare events when needed.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "prepare.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_PREPARE_INCLUDE_H
|
||||||
@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief PrepareEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by PrepareHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct PrepareEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The PrepareHandle handle.
|
|
||||||
*
|
|
||||||
* Prepare handles will emit a PrepareEvent event once per loop iteration, right
|
|
||||||
* before polling for I/O.
|
|
||||||
*
|
|
||||||
* To create a `PrepareHandle` through a `Loop`, no arguments are required.
|
|
||||||
*/
|
|
||||||
class PrepareHandle final: public Handle<PrepareHandle, uv_prepare_t> {
|
|
||||||
static void startCallback(uv_prepare_t *handle) {
|
|
||||||
PrepareHandle &prepare = *(static_cast<PrepareHandle*>(handle->data));
|
|
||||||
prepare.publish(PrepareEvent{});
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Handle::Handle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return initialize(&uv_prepare_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the handle.
|
|
||||||
*
|
|
||||||
* A PrepareEvent event will be emitted once per loop iteration, right
|
|
||||||
* before polling for I/O.
|
|
||||||
*
|
|
||||||
* The handle will start emitting PrepareEvent when needed.
|
|
||||||
*/
|
|
||||||
void start() {
|
|
||||||
invoke(&uv_prepare_start, get(), &startCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops the handle.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
invoke(&uv_prepare_stop, get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
22
src/uvw/prepare.ipp
Normal file
22
src/uvw/prepare.ipp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE void prepare_handle::start_callback(uv_prepare_t *hndl) {
|
||||||
|
prepare_handle &prepare = *(static_cast<prepare_handle *>(hndl->data));
|
||||||
|
prepare.publish(prepare_event{});
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int prepare_handle::init() {
|
||||||
|
return leak_if(uv_prepare_init(parent().raw(), raw()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int prepare_handle::start() {
|
||||||
|
return uv_prepare_start(raw(), &start_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int prepare_handle::stop() {
|
||||||
|
return uv_prepare_stop(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/process.cpp
Normal file
2
src/uvw/process.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "process.h"
|
||||||
|
#include "process.ipp"
|
||||||
245
src/uvw/process.h
Normal file
245
src/uvw/process.h
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
#ifndef UVW_PROCESS_INCLUDE_H
|
||||||
|
#define UVW_PROCESS_INCLUDE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "enum.hpp"
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
#include "stream.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
enum class uvw_process_flags : std::underlying_type_t<uv_process_flags> {
|
||||||
|
SETUID = UV_PROCESS_SETUID,
|
||||||
|
SETGID = UV_PROCESS_SETGID,
|
||||||
|
WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
|
||||||
|
DETACHED = UV_PROCESS_DETACHED,
|
||||||
|
WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE,
|
||||||
|
WINDOWS_HIDE_CONSOLE = UV_PROCESS_WINDOWS_HIDE_CONSOLE,
|
||||||
|
WINDOWS_HIDE_GUI = UV_PROCESS_WINDOWS_HIDE_GUI,
|
||||||
|
WINDOWS_FILE_PATH_EXACT_NAME = UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME,
|
||||||
|
UVW_ENUM = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class uvw_stdio_flags : std::underlying_type_t<uv_stdio_flags> {
|
||||||
|
IGNORE_STREAM = UV_IGNORE,
|
||||||
|
CREATE_PIPE = UV_CREATE_PIPE,
|
||||||
|
INHERIT_FD = UV_INHERIT_FD,
|
||||||
|
INHERIT_STREAM = UV_INHERIT_STREAM,
|
||||||
|
READABLE_PIPE = UV_READABLE_PIPE,
|
||||||
|
WRITABLE_PIPE = UV_WRITABLE_PIPE,
|
||||||
|
OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE,
|
||||||
|
UVW_ENUM = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
/*! @brief Exit event. */
|
||||||
|
struct exit_event {
|
||||||
|
explicit exit_event(int64_t code, int sig) noexcept;
|
||||||
|
|
||||||
|
int64_t status; /*!< The exit status. */
|
||||||
|
int signal; /*!< The signal that caused the process to terminate, if any. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The process handle.
|
||||||
|
*
|
||||||
|
* Process handles will spawn a new process and allow the user to control it and
|
||||||
|
* establish communication channels with it using streams.
|
||||||
|
*/
|
||||||
|
class process_handle final: public handle<process_handle, uv_process_t, exit_event> {
|
||||||
|
static void exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using process_flags = details::uvw_process_flags;
|
||||||
|
using stdio_flags = details::uvw_stdio_flags;
|
||||||
|
|
||||||
|
process_handle(loop::token token, std::shared_ptr<loop> ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disables inheritance for file descriptors/handles.
|
||||||
|
*
|
||||||
|
* Disables inheritance for file descriptors/handles that this process
|
||||||
|
* inherited from its parent. The effect is that child processes spawned by
|
||||||
|
* this process don’t accidentally inherit these handles.<br/>
|
||||||
|
* It is recommended to call this function as early in your program as
|
||||||
|
* possible, before the inherited file descriptors can be closed or
|
||||||
|
* duplicated.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
|
||||||
|
* for further details.
|
||||||
|
*/
|
||||||
|
static void disable_stdio_inheritance() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief kill Sends the specified signal to the given PID.
|
||||||
|
* @param pid A valid process id.
|
||||||
|
* @param signum A valid signal identifier.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool kill(int pid, int signum) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief spawn Starts the process.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/process.html)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @param file Path pointing to the program to be executed.
|
||||||
|
* @param args Command line arguments.
|
||||||
|
* @param env Optional environment for the new process.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int spawn(const char *file, char **args, char **env = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends the specified signal to the internal process handle.
|
||||||
|
* @param signum A valid signal identifier.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int kill(int signum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the PID of the spawned process.
|
||||||
|
*
|
||||||
|
* It’s set after calling `spawn()`.
|
||||||
|
*
|
||||||
|
* @return The PID of the spawned process.
|
||||||
|
*/
|
||||||
|
int pid() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the current working directory for the subprocess.
|
||||||
|
* @param path The working directory to be used when `spawn()` is invoked.
|
||||||
|
* @return A reference to this process handle.
|
||||||
|
*/
|
||||||
|
process_handle &cwd(const std::string &path) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets flags that control how `spawn()` behaves.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `process_handle::process_flags::SETUID`
|
||||||
|
* * `process_handle::process_flags::SETGID`
|
||||||
|
* * `process_handle::process_flags::WINDOWS_VERBATIM_ARGUMENTS`
|
||||||
|
* * `process_handle::process_flags::DETACHED`
|
||||||
|
* * `process_handle::process_flags::WINDOWS_HIDE`
|
||||||
|
* * `process_handle::process_flags::WINDOWS_HIDE_CONSOLE`
|
||||||
|
* * `process_handle::process_flags::WINDOWS_HIDE_GUI`
|
||||||
|
* * `process_handle::process_flags::WINDOWS_FILE_PATH_EXACT_NAME`
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @param flags A valid set of flags.
|
||||||
|
* @return A reference to this process handle.
|
||||||
|
*/
|
||||||
|
process_handle &flags(process_flags flags) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Makes a `stdio` handle available to the child process.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `process_handle::stdio_flags::IGNORE_STREAM`
|
||||||
|
* * `process_handle::stdio_flags::CREATE_PIPE`
|
||||||
|
* * `process_handle::stdio_flags::INHERIT_FD`
|
||||||
|
* * `process_handle::stdio_flags::INHERIT_STREAM`
|
||||||
|
* * `process_handle::stdio_flags::READABLE_PIPE`
|
||||||
|
* * `process_handle::stdio_flags::WRITABLE_PIPE`
|
||||||
|
* * `process_handle::stdio_flags::OVERLAPPED_PIPE`
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @param stream A valid `stdio` handle.
|
||||||
|
* @param flags A valid set of flags.
|
||||||
|
* @return A reference to this process handle.
|
||||||
|
*/
|
||||||
|
template<typename T, typename U, typename... E>
|
||||||
|
process_handle &stdio(stream_handle<T, U, E...> &stream, stdio_flags flags) {
|
||||||
|
uv_stdio_container_t container;
|
||||||
|
container.flags = static_cast<uv_stdio_flags>(flags);
|
||||||
|
container.data.stream = reinterpret_cast<uv_stream_t *>(stream.raw());
|
||||||
|
po_stream_stdio.push_back(container);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Makes a file descriptor available to the child process.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `process_handle::stdio_flags::IGNORE_STREAM`
|
||||||
|
* * `process_handle::stdio_flags::CREATE_PIPE`
|
||||||
|
* * `process_handle::stdio_flags::INHERIT_FD`
|
||||||
|
* * `process_handle::stdio_flags::INHERIT_STREAM`
|
||||||
|
* * `process_handle::stdio_flags::READABLE_PIPE`
|
||||||
|
* * `process_handle::stdio_flags::WRITABLE_PIPE`
|
||||||
|
* * `process_handle::stdio_flags::OVERLAPPED_PIPE`
|
||||||
|
*
|
||||||
|
* Default file descriptors are:
|
||||||
|
* * `uvw::std_in` for `stdin`
|
||||||
|
* * `uvw::std_out` for `stdout`
|
||||||
|
* * `uvw::std_err` for `stderr`
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @param fd A valid file descriptor.
|
||||||
|
* @param flags A valid set of flags.
|
||||||
|
* @return A reference to this process handle.
|
||||||
|
*/
|
||||||
|
process_handle &stdio(file_handle fd, stdio_flags flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the child process' user id.
|
||||||
|
* @param id A valid user id to be used.
|
||||||
|
* @return A reference to this process handle.
|
||||||
|
*/
|
||||||
|
process_handle &uid(uid_type id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the child process' group id.
|
||||||
|
* @param id A valid group id to be used.
|
||||||
|
* @return A reference to this process handle.
|
||||||
|
*/
|
||||||
|
process_handle &gid(gid_type id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string po_cwd;
|
||||||
|
process_flags po_flags;
|
||||||
|
std::vector<uv_stdio_container_t> po_fd_stdio;
|
||||||
|
std::vector<uv_stdio_container_t> po_stream_stdio;
|
||||||
|
uid_type po_uid;
|
||||||
|
gid_type po_gid;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "process.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_PROCESS_INCLUDE_H
|
||||||
@ -1,319 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "stream.hpp"
|
|
||||||
#include "util.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVProcessFlags: typename std::underlying_type<uv_process_flags>::type {
|
|
||||||
SETUID = UV_PROCESS_SETUID,
|
|
||||||
SETGID = UV_PROCESS_SETGID,
|
|
||||||
WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
|
|
||||||
DETACHED = UV_PROCESS_DETACHED,
|
|
||||||
WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVStdIOFlags: typename std::underlying_type<uv_stdio_flags>::type {
|
|
||||||
IGNORE_STREAM = UV_IGNORE,
|
|
||||||
CREATE_PIPE = UV_CREATE_PIPE,
|
|
||||||
INHERIT_FD = UV_INHERIT_FD,
|
|
||||||
INHERIT_STREAM = UV_INHERIT_STREAM,
|
|
||||||
READABLE_PIPE = UV_READABLE_PIPE,
|
|
||||||
WRITABLE_PIPE = UV_WRITABLE_PIPE,
|
|
||||||
OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ExitEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by ProcessHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct ExitEvent {
|
|
||||||
explicit ExitEvent(int64_t code, int sig) noexcept
|
|
||||||
: status{code}, signal{sig}
|
|
||||||
{}
|
|
||||||
|
|
||||||
int64_t status; /*!< The exit status. */
|
|
||||||
int signal; /*!< The signal that caused the process to terminate, if any. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The ProcessHandle handle.
|
|
||||||
*
|
|
||||||
* Process handles will spawn a new process and allow the user to control it and
|
|
||||||
* establish communication channels with it using streams.
|
|
||||||
*/
|
|
||||||
class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
|
|
||||||
static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) {
|
|
||||||
ProcessHandle &process = *(static_cast<ProcessHandle*>(handle->data));
|
|
||||||
process.publish(ExitEvent{exitStatus, termSignal});
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Process = details::UVProcessFlags;
|
|
||||||
using StdIO = details::UVStdIOFlags;
|
|
||||||
|
|
||||||
ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref)
|
|
||||||
: Handle{ca, std::move(ref)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disables inheritance for file descriptors/handles.
|
|
||||||
*
|
|
||||||
* Disables inheritance for file descriptors/handles that this process
|
|
||||||
* inherited from its parent. The effect is that child processes spawned by
|
|
||||||
* this process don’t accidentally inherit these handles.<br/>
|
|
||||||
* It is recommended to call this function as early in your program as
|
|
||||||
* possible, before the inherited file descriptors can be closed or
|
|
||||||
* duplicated.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
static void disableStdIOInheritance() noexcept {
|
|
||||||
uv_disable_stdio_inheritance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief kill Sends the specified signal to the given PID.
|
|
||||||
* @param pid A valid process id.
|
|
||||||
* @param signum A valid signal identifier.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool kill(int pid, int signum) noexcept {
|
|
||||||
return (0 == uv_kill(pid, signum));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
// deferred initialization: libuv initializes process handles only when
|
|
||||||
// uv_spawn is invoked and uvw stays true to the underlying library
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief spawn Starts the process.
|
|
||||||
*
|
|
||||||
* If the process isn't successfully spawned, an ErrorEvent event will be
|
|
||||||
* emitted by the handle.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html)
|
|
||||||
* for further details.
|
|
||||||
*
|
|
||||||
* @param file Path pointing to the program to be executed.
|
|
||||||
* @param args Command line arguments.
|
|
||||||
* @param env Optional environment for the new process.
|
|
||||||
*/
|
|
||||||
void spawn(const char *file, char **args, char **env = nullptr) {
|
|
||||||
uv_process_options_t po;
|
|
||||||
|
|
||||||
po.exit_cb = &exitCallback;
|
|
||||||
po.file = file;
|
|
||||||
po.args = args;
|
|
||||||
po.env = env;
|
|
||||||
po.cwd = poCwd.empty() ? nullptr : poCwd.data();
|
|
||||||
po.flags = poFlags;
|
|
||||||
po.uid = poUid;
|
|
||||||
po.gid = poGid;
|
|
||||||
|
|
||||||
std::vector<uv_stdio_container_t> poStdio;
|
|
||||||
poStdio.reserve(poFdStdio.size() + poStreamStdio.size());
|
|
||||||
poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());
|
|
||||||
poStdio.insert(poStdio.end(), poStreamStdio.cbegin(), poStreamStdio.cend());
|
|
||||||
|
|
||||||
po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
|
|
||||||
po.stdio = poStdio.data();
|
|
||||||
|
|
||||||
// fake initialization so as to have leak invoked
|
|
||||||
// see init member function for more details
|
|
||||||
initialize([](uv_loop_t*, uv_process_t*){ return 0; });
|
|
||||||
|
|
||||||
invoke(&uv_spawn, parent(), get(), &po);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sends the specified signal to the internal process handle.
|
|
||||||
* @param signum A valid signal identifier.
|
|
||||||
*/
|
|
||||||
void kill(int signum) {
|
|
||||||
invoke(&uv_process_kill, get(), signum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the PID of the spawned process.
|
|
||||||
*
|
|
||||||
* It’s set after calling `spawn()`.
|
|
||||||
*
|
|
||||||
* @return The PID of the spawned process.
|
|
||||||
*/
|
|
||||||
int pid() noexcept {
|
|
||||||
return get()->pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the current working directory for the subprocess.
|
|
||||||
* @param path The working directory to be used when `spawn()` is invoked.
|
|
||||||
* @return A reference to this process handle.
|
|
||||||
*/
|
|
||||||
ProcessHandle & cwd(std::string path) noexcept {
|
|
||||||
poCwd = path;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets flags that control how `spawn()` behaves.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `ProcessHandle::Process::SETUID`
|
|
||||||
* * `ProcessHandle::Process::SETGID`
|
|
||||||
* * `ProcessHandle::Process::WINDOWS_VERBATIM_ARGUMENTS`
|
|
||||||
* * `ProcessHandle::Process::DETACHED`
|
|
||||||
* * `ProcessHandle::Process::WINDOWS_HIDE`
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags)
|
|
||||||
* for further details.
|
|
||||||
*
|
|
||||||
* @param flags A valid set of flags.
|
|
||||||
* @return A reference to this process handle.
|
|
||||||
*/
|
|
||||||
ProcessHandle & flags(Flags<Process> flags) noexcept {
|
|
||||||
poFlags = flags;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Makes a `stdio` handle available to the child process.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `ProcessHandle::StdIO::IGNORE_STREAM`
|
|
||||||
* * `ProcessHandle::StdIO::CREATE_PIPE`
|
|
||||||
* * `ProcessHandle::StdIO::INHERIT_FD`
|
|
||||||
* * `ProcessHandle::StdIO::INHERIT_STREAM`
|
|
||||||
* * `ProcessHandle::StdIO::READABLE_PIPE`
|
|
||||||
* * `ProcessHandle::StdIO::WRITABLE_PIPE`
|
|
||||||
* * `ProcessHandle::StdIO::OVERLAPPED_PIPE`
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
|
||||||
* for further details.
|
|
||||||
*
|
|
||||||
* @param stream A valid `stdio` handle.
|
|
||||||
* @param flags A valid set of flags.
|
|
||||||
* @return A reference to this process handle.
|
|
||||||
*/
|
|
||||||
template<typename T, typename U>
|
|
||||||
ProcessHandle & stdio(StreamHandle<T, U> &stream, Flags<StdIO> flags) {
|
|
||||||
uv_stdio_container_t container;
|
|
||||||
Flags<StdIO>::Type fgs = flags;
|
|
||||||
container.flags = static_cast<uv_stdio_flags>(fgs);
|
|
||||||
container.data.stream = get<uv_stream_t>(stream);
|
|
||||||
poStreamStdio.push_back(std::move(container));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Makes a file descriptor available to the child process.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `ProcessHandle::StdIO::IGNORE_STREAM`
|
|
||||||
* * `ProcessHandle::StdIO::CREATE_PIPE`
|
|
||||||
* * `ProcessHandle::StdIO::INHERIT_FD`
|
|
||||||
* * `ProcessHandle::StdIO::INHERIT_STREAM`
|
|
||||||
* * `ProcessHandle::StdIO::READABLE_PIPE`
|
|
||||||
* * `ProcessHandle::StdIO::WRITABLE_PIPE`
|
|
||||||
* * `ProcessHandle::StdIO::OVERLAPPED_PIPE`
|
|
||||||
*
|
|
||||||
* Default file descriptors are:
|
|
||||||
* * `uvw::StdIN` for `stdin`
|
|
||||||
* * `uvw::StdOUT` for `stdout`
|
|
||||||
* * `uvw::StdERR` for `stderr`
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
|
||||||
* for further details.
|
|
||||||
*
|
|
||||||
* @param fd A valid file descriptor.
|
|
||||||
* @param flags A valid set of flags.
|
|
||||||
* @return A reference to this process handle.
|
|
||||||
*/
|
|
||||||
ProcessHandle & stdio(FileHandle fd, Flags<StdIO> flags) {
|
|
||||||
auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});
|
|
||||||
|
|
||||||
auto actual = FileHandle::Type{fd};
|
|
||||||
|
|
||||||
auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](const uv_stdio_container_t &container){
|
|
||||||
return container.data.fd == actual;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(it == poFdStdio.cend()) {
|
|
||||||
uv_stdio_container_t container;
|
|
||||||
container.flags = fgs;
|
|
||||||
container.data.fd = actual;
|
|
||||||
poFdStdio.push_back(std::move(container));
|
|
||||||
} else {
|
|
||||||
it->flags = fgs;
|
|
||||||
it->data.fd = actual;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the child process' user id.
|
|
||||||
* @param id A valid user id to be used.
|
|
||||||
* @return A reference to this process handle.
|
|
||||||
*/
|
|
||||||
ProcessHandle & uid(Uid id) {
|
|
||||||
poUid = id;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the child process' group id.
|
|
||||||
* @param id A valid group id to be used.
|
|
||||||
* @return A reference to this process handle.
|
|
||||||
*/
|
|
||||||
ProcessHandle & gid(Gid id) {
|
|
||||||
poGid = id;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string poCwd;
|
|
||||||
Flags<Process> poFlags;
|
|
||||||
std::vector<uv_stdio_container_t> poFdStdio;
|
|
||||||
std::vector<uv_stdio_container_t> poStreamStdio;
|
|
||||||
Uid poUid;
|
|
||||||
Gid poGid;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
107
src/uvw/process.ipp
Normal file
107
src/uvw/process.ipp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE exit_event::exit_event(int64_t code, int sig) noexcept
|
||||||
|
: status{code}, signal{sig} {}
|
||||||
|
|
||||||
|
UVW_INLINE void process_handle::exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal) {
|
||||||
|
process_handle &process = *(static_cast<process_handle *>(hndl->data));
|
||||||
|
process.publish(exit_event{exit_status, term_signal});
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE process_handle::process_handle(loop::token token, std::shared_ptr<loop> ref)
|
||||||
|
: handle{token, std::move(ref)} {}
|
||||||
|
|
||||||
|
UVW_INLINE void process_handle::disable_stdio_inheritance() noexcept {
|
||||||
|
uv_disable_stdio_inheritance();
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE bool process_handle::kill(int pid, int signum) noexcept {
|
||||||
|
return (0 == uv_kill(pid, signum));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int process_handle::init() {
|
||||||
|
// deferred initialization: libuv initializes process handles only when
|
||||||
|
// uv_spawn is invoked and uvw stays true to the underlying library
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int process_handle::spawn(const char *file, char **args, char **env) {
|
||||||
|
uv_process_options_t po;
|
||||||
|
|
||||||
|
po.exit_cb = &exit_callback;
|
||||||
|
po.file = file;
|
||||||
|
po.args = args;
|
||||||
|
po.env = env;
|
||||||
|
po.cwd = po_cwd.empty() ? nullptr : po_cwd.data();
|
||||||
|
po.flags = static_cast<uv_process_flags>(po_flags);
|
||||||
|
po.uid = po_uid;
|
||||||
|
po.gid = po_gid;
|
||||||
|
|
||||||
|
std::vector<uv_stdio_container_t> poStdio;
|
||||||
|
poStdio.reserve(po_fd_stdio.size() + po_stream_stdio.size());
|
||||||
|
poStdio.insert(poStdio.begin(), po_fd_stdio.cbegin(), po_fd_stdio.cend());
|
||||||
|
poStdio.insert(poStdio.end(), po_stream_stdio.cbegin(), po_stream_stdio.cend());
|
||||||
|
|
||||||
|
po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
|
||||||
|
po.stdio = poStdio.data();
|
||||||
|
|
||||||
|
// see init member function for more details
|
||||||
|
static_cast<void>(leak_if(0));
|
||||||
|
|
||||||
|
return uv_spawn(parent().raw(), raw(), &po);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int process_handle::kill(int signum) {
|
||||||
|
return uv_process_kill(raw(), signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int process_handle::pid() noexcept {
|
||||||
|
return raw()->pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE process_handle &process_handle::cwd(const std::string &path) noexcept {
|
||||||
|
po_cwd = path;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE process_handle &process_handle::flags(process_flags flags) noexcept {
|
||||||
|
po_flags = flags;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE process_handle &process_handle::stdio(file_handle fd, stdio_flags flags) {
|
||||||
|
auto fgs = static_cast<uv_stdio_flags>(flags);
|
||||||
|
|
||||||
|
auto actual = uvw::file_handle{fd};
|
||||||
|
|
||||||
|
auto it = std::find_if(po_fd_stdio.begin(), po_fd_stdio.end(), [actual](auto &&container) {
|
||||||
|
return static_cast<const uvw::details::uv_type_wrapper<int>>(container.data.fd) == static_cast<const uvw::details::uv_type_wrapper<int>>(actual);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(it == po_fd_stdio.cend()) {
|
||||||
|
uv_stdio_container_t container;
|
||||||
|
container.flags = fgs;
|
||||||
|
container.data.fd = actual;
|
||||||
|
po_fd_stdio.push_back(container);
|
||||||
|
} else {
|
||||||
|
it->flags = fgs;
|
||||||
|
it->data.fd = actual;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE process_handle &process_handle::uid(uid_type id) {
|
||||||
|
po_uid = id;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE process_handle &process_handle::gid(gid_type id) {
|
||||||
|
po_gid = id;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
@ -1,75 +1,57 @@
|
|||||||
#pragma once
|
#ifndef UVW_REQUEST_INCLUDE_H
|
||||||
|
#define UVW_REQUEST_INCLUDE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
#include "resource.hpp"
|
#include "resource.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
namespace uvw {
|
||||||
|
|
||||||
|
/**
|
||||||
template<typename T, typename U>
|
* @brief Request base class.
|
||||||
class Request: public Resource<T, U> {
|
*
|
||||||
|
* Base type for all `uvw` request types.
|
||||||
|
*/
|
||||||
|
template<typename T, typename U, typename... E>
|
||||||
|
class request: public resource<T, U, E...> {
|
||||||
protected:
|
protected:
|
||||||
static auto reserve(U *req) -> std::shared_ptr<T> {
|
[[nodiscard]] static auto reserve(U *req) {
|
||||||
auto ptr = static_cast<T*>(req->data)->shared_from_this();
|
auto ptr = static_cast<T *>(req->data)->shared_from_this();
|
||||||
ptr->reset();
|
ptr->self_reset();
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename E>
|
|
||||||
static void defaultCallback(U *req, int status) {
|
|
||||||
auto ptr = reserve(req);
|
|
||||||
if(status) { ptr->publish(ErrorEvent{status}); }
|
|
||||||
else { ptr->publish(E{}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
|
||||||
auto invoke(F &&f, Args&&... args)
|
|
||||||
-> typename std::enable_if<not std::is_void<typename std::result_of<F(Args...)>::type>::value>::type {
|
|
||||||
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
|
||||||
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
|
|
||||||
else { this->leak(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
|
||||||
auto invoke(F &&f, Args&&... args)
|
|
||||||
-> typename std::enable_if<std::is_void<typename std::result_of<F(Args...)>::type>::value>::type {
|
|
||||||
std::forward<F>(f)(std::forward<Args>(args)...);
|
|
||||||
this->leak();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Resource<T, U>::Resource;
|
using resource<T, U, E...>::resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cancels a pending request.
|
* @brief Cancels a pending request.
|
||||||
*
|
*
|
||||||
* This method fails if the request is executing or has finished
|
* This method fails if the request is executing or has finished
|
||||||
* executing.<br/>
|
* executing.
|
||||||
* It can emit an ErrorEvent event in case of errors.
|
*
|
||||||
*
|
* See the official
|
||||||
* See the official
|
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
|
* for further details.
|
||||||
* for further details.
|
*
|
||||||
*
|
* @return Underlying return value.
|
||||||
* @return True in case of success, false otherwise.
|
*/
|
||||||
*/
|
int cancel() {
|
||||||
bool cancel() {
|
return uv_cancel(reinterpret_cast<uv_req_t *>(this->raw()));
|
||||||
return (0 == uv_cancel(this->template get<uv_req_t>()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the size of the underlying request type.
|
* @brief Returns the size of the underlying request type.
|
||||||
* @return The size of the underlying request type.
|
* @return The size of the underlying request type.
|
||||||
*/
|
*/
|
||||||
std::size_t size() const noexcept {
|
[[nodiscard]] std::size_t size() const noexcept {
|
||||||
return uv_req_size(this->template get<uv_req_t>()->type);
|
return uv_req_size(reinterpret_cast<const uv_req_t *>(this->raw())->type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
}
|
#endif // UVW_REQUEST_INCLUDE_H
|
||||||
|
|||||||
@ -1,48 +1,42 @@
|
|||||||
#pragma once
|
#ifndef UVW_RESOURCE_INCLUDE_H
|
||||||
|
#define UVW_RESOURCE_INCLUDE_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "emitter.hpp"
|
#include "config.h"
|
||||||
#include "underlying_type.hpp"
|
#include "emitter.h"
|
||||||
|
#include "uv_type.hpp"
|
||||||
|
|
||||||
namespace uvw {
|
namespace uvw {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Common class for almost all the resources available in `uvw`.
|
* @brief Common class for almost all the resources available in `uvw`.
|
||||||
*
|
*
|
||||||
* This is the base class for handles and requests.
|
* This is the base class for handles and requests.
|
||||||
*/
|
*/
|
||||||
template<typename T, typename U>
|
template<typename T, typename U, typename... E>
|
||||||
class Resource: public UnderlyingType<T, U>, public Emitter<T>, public std::enable_shared_from_this<T> {
|
class resource: public uv_type<U>, public emitter<T, E...>, public std::enable_shared_from_this<T> {
|
||||||
protected:
|
protected:
|
||||||
using ConstructorAccess = typename UnderlyingType<T, U>::ConstructorAccess;
|
[[nodiscard]] int leak_if(int err) noexcept {
|
||||||
|
if(err == 0) {
|
||||||
|
self_ptr = this->shared_from_this();
|
||||||
|
}
|
||||||
|
|
||||||
auto parent() const noexcept -> uv_loop_t * {
|
return err;
|
||||||
return this->loop().loop.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void leak() noexcept {
|
void self_reset() noexcept {
|
||||||
sPtr = this->shared_from_this();
|
self_ptr.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() noexcept {
|
[[nodiscard]] bool has_self() const noexcept {
|
||||||
sPtr.reset();
|
return static_cast<bool>(self_ptr);
|
||||||
}
|
|
||||||
|
|
||||||
bool self() const noexcept {
|
|
||||||
return static_cast<bool>(sPtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Resource(ConstructorAccess ca, std::shared_ptr<Loop> ref)
|
explicit resource(loop::token token, std::shared_ptr<loop> ref)
|
||||||
: UnderlyingType<T, U>{ca, std::move(ref)},
|
: uv_type<U>{token, std::move(ref)} {
|
||||||
Emitter<T>{},
|
this->raw()->data = this;
|
||||||
std::enable_shared_from_this<T>{}
|
|
||||||
{
|
|
||||||
this->get()->data = static_cast<T*>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,22 +44,23 @@ public:
|
|||||||
* @return User-defined data if any, an invalid pointer otherwise.
|
* @return User-defined data if any, an invalid pointer otherwise.
|
||||||
*/
|
*/
|
||||||
template<typename R = void>
|
template<typename R = void>
|
||||||
std::shared_ptr<R> data() const {
|
[[nodiscard]] std::shared_ptr<R> data() const {
|
||||||
return std::static_pointer_cast<R>(userData);
|
return std::static_pointer_cast<R>(user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets arbitrary data. `uvw` won't use this field in any case.
|
* @brief Sets arbitrary data. `uvw` won't use this field in any case.
|
||||||
* @param uData User-defined arbitrary data.
|
* @param udata User-defined arbitrary data.
|
||||||
*/
|
*/
|
||||||
void data(std::shared_ptr<void> uData) {
|
void data(std::shared_ptr<void> udata) {
|
||||||
userData = std::move(uData);
|
user_data = std::move(udata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<void> userData{nullptr};
|
std::shared_ptr<void> user_data{nullptr};
|
||||||
std::shared_ptr<void> sPtr{nullptr};
|
std::shared_ptr<void> self_ptr{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
}
|
#endif // UVW_RESOURCE_INCLUDE_H
|
||||||
|
|||||||
2
src/uvw/signal.cpp
Normal file
2
src/uvw/signal.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "signal.h"
|
||||||
|
#include "signal.ipp"
|
||||||
83
src/uvw/signal.h
Normal file
83
src/uvw/signal.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#ifndef UVW_SIGNAL_INCLUDE_H
|
||||||
|
#define UVW_SIGNAL_INCLUDE_H
|
||||||
|
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Signal event. */
|
||||||
|
struct signal_event {
|
||||||
|
explicit signal_event(int sig) noexcept;
|
||||||
|
|
||||||
|
int signum; /*!< The signal being monitored by this handle. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The signal handle.
|
||||||
|
*
|
||||||
|
* Signal handles implement Unix style signal handling on a per-event loop
|
||||||
|
* bases.<br/>
|
||||||
|
* Reception of some signals is emulated on Windows.
|
||||||
|
*
|
||||||
|
* To create a `signal_handle` through a `loop`, no arguments are required.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/signal.html)
|
||||||
|
* for further details.
|
||||||
|
*/
|
||||||
|
class signal_handle final: public handle<signal_handle, uv_signal_t, signal_event> {
|
||||||
|
static void start_callback(uv_signal_t *hndl, int signum);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using handle::handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts the handle.
|
||||||
|
*
|
||||||
|
* The handle will start emitting signal events when needed.
|
||||||
|
*
|
||||||
|
* @param signum The signal to be monitored.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int start(int signum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts the handle.
|
||||||
|
*
|
||||||
|
* Same functionality as signal_handle::start but the signal handler is
|
||||||
|
* reset the moment the signal is received.
|
||||||
|
*
|
||||||
|
* @param signum The signal to be monitored.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int one_shot(int signum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the handle.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the signal being monitored.
|
||||||
|
* @return The signal being monitored.
|
||||||
|
*/
|
||||||
|
int signal() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "signal.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_SIGNAL_INCLUDE_H
|
||||||
@ -1,96 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SignalEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by SignalHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct SignalEvent {
|
|
||||||
explicit SignalEvent(int sig) noexcept: signum{sig} {}
|
|
||||||
|
|
||||||
int signum; /*!< The signal being monitored by this handle. */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The SignalHandle handle.
|
|
||||||
*
|
|
||||||
* Signal handles implement Unix style signal handling on a per-event loop
|
|
||||||
* bases.<br/>
|
|
||||||
* Reception of some signals is emulated on Windows.
|
|
||||||
*
|
|
||||||
* To create a `SignalHandle` through a `Loop`, no arguments are required.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/signal.html)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
class SignalHandle final: public Handle<SignalHandle, uv_signal_t> {
|
|
||||||
static void startCallback(uv_signal_t *handle, int signum) {
|
|
||||||
SignalHandle &signal = *(static_cast<SignalHandle*>(handle->data));
|
|
||||||
signal.publish(SignalEvent{signum});
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Handle::Handle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return initialize(&uv_signal_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the handle.
|
|
||||||
*
|
|
||||||
* The handle will start emitting SignalEvent when needed.
|
|
||||||
*
|
|
||||||
* @param signum The signal to be monitored.
|
|
||||||
*/
|
|
||||||
void start(int signum) {
|
|
||||||
invoke(&uv_signal_start, get(), &startCallback, signum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the handle.
|
|
||||||
*
|
|
||||||
* Same functionality as SignalHandle::start but the signal handler is reset
|
|
||||||
* the moment the signal is received.
|
|
||||||
*
|
|
||||||
* @param signum
|
|
||||||
*/
|
|
||||||
void oneShot(int signum) {
|
|
||||||
invoke(&uv_signal_start_oneshot, get(), &startCallback, signum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops the handle.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
invoke(&uv_signal_stop, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the signal being monitored.
|
|
||||||
* @return The signal being monitored.
|
|
||||||
*/
|
|
||||||
int signal() const noexcept {
|
|
||||||
return get()->signum;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
33
src/uvw/signal.ipp
Normal file
33
src/uvw/signal.ipp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE signal_event::signal_event(int sig) noexcept
|
||||||
|
: signum{sig} {}
|
||||||
|
|
||||||
|
UVW_INLINE void signal_handle::start_callback(uv_signal_t *hndl, int signum) {
|
||||||
|
signal_handle &signal = *(static_cast<signal_handle *>(hndl->data));
|
||||||
|
signal.publish(signal_event{signum});
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int signal_handle::init() {
|
||||||
|
return leak_if(uv_signal_init(parent().raw(), raw()));
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int signal_handle::start(int signum) {
|
||||||
|
return uv_signal_start(raw(), &start_callback, signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int signal_handle::one_shot(int signum) {
|
||||||
|
return uv_signal_start_oneshot(raw(), &start_callback, signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int signal_handle::stop() {
|
||||||
|
return uv_signal_stop(raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int signal_handle::signal() const noexcept {
|
||||||
|
return raw()->signum;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/stream.cpp
Normal file
2
src/uvw/stream.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "stream.h"
|
||||||
|
#include "stream.ipp"
|
||||||
482
src/uvw/stream.h
Normal file
482
src/uvw/stream.h
Normal file
@ -0,0 +1,482 @@
|
|||||||
|
#ifndef UVW_STREAM_INCLUDE_H
|
||||||
|
#define UVW_STREAM_INCLUDE_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "handle.hpp"
|
||||||
|
#include "loop.h"
|
||||||
|
#include "request.hpp"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
/*! @brief Connect event. */
|
||||||
|
struct connect_event {};
|
||||||
|
|
||||||
|
/*! @brief End event. */
|
||||||
|
struct end_event {};
|
||||||
|
|
||||||
|
/*! @brief Listen event. */
|
||||||
|
struct listen_event {};
|
||||||
|
|
||||||
|
/*! @brief Shutdown event. */
|
||||||
|
struct shutdown_event {};
|
||||||
|
|
||||||
|
/*! @brief Write event. */
|
||||||
|
struct write_event {};
|
||||||
|
|
||||||
|
/*! @brief Data event. */
|
||||||
|
struct data_event {
|
||||||
|
explicit data_event(std::unique_ptr<char[]> buf, std::size_t len) noexcept;
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> data; /*!< A bunch of data read on the stream. */
|
||||||
|
std::size_t length; /*!< The amount of data read on the stream. */
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
class connect_req final: public request<connect_req, uv_connect_t, connect_event> {
|
||||||
|
static void connect_callback(uv_connect_t *req, int status);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using request::request;
|
||||||
|
|
||||||
|
template<typename F, typename... Args>
|
||||||
|
auto connect(F &&f, Args &&...args) -> std::enable_if_t<std::is_same_v<decltype(std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback)), void>, int> {
|
||||||
|
std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback);
|
||||||
|
return this->leak_if(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename... Args>
|
||||||
|
auto connect(F &&f, Args &&...args) -> std::enable_if_t<!std::is_same_v<decltype(std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback)), void>, int> {
|
||||||
|
return this->leak_if(std::forward<F>(f)(raw(), std::forward<Args>(args)..., &connect_callback));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class shutdown_req final: public request<shutdown_req, uv_shutdown_t, shutdown_event> {
|
||||||
|
static void shoutdown_callback(uv_shutdown_t *req, int status);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using request::request;
|
||||||
|
|
||||||
|
int shutdown(uv_stream_t *hndl);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Deleter>
|
||||||
|
class write_req final: public request<write_req<Deleter>, uv_write_t, write_event> {
|
||||||
|
static void write_callback(uv_write_t *req, int status) {
|
||||||
|
if(auto ptr = request<write_req<Deleter>, uv_write_t, write_event>::reserve(req); status) {
|
||||||
|
ptr->publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
ptr->publish(write_event{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
write_req(loop::token token, std::shared_ptr<loop> parent, std::unique_ptr<char[], Deleter> dt, unsigned int len)
|
||||||
|
: request<write_req<Deleter>, uv_write_t, write_event>{token, std::move(parent)},
|
||||||
|
data{std::move(dt)},
|
||||||
|
buf{uv_buf_init(data.get(), len)} {}
|
||||||
|
|
||||||
|
int write(uv_stream_t *hndl) {
|
||||||
|
return this->leak_if(uv_write(this->raw(), hndl, &buf, 1, &write_callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
int write(uv_stream_t *hndl, uv_stream_t *send) {
|
||||||
|
return this->leak_if(uv_write2(this->raw(), hndl, &buf, 1, send, &write_callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<char[], Deleter> data;
|
||||||
|
uv_buf_t buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The stream handle.
|
||||||
|
*
|
||||||
|
* Stream handles provide an abstraction of a duplex communication channel.
|
||||||
|
* The stream handle is an intermediate type, `uvw` provides three stream
|
||||||
|
* implementations: tcp, pipe and tty handles.
|
||||||
|
*/
|
||||||
|
template<typename T, typename U, typename... E>
|
||||||
|
class stream_handle: public handle<T, U, listen_event, end_event, connect_event, shutdown_event, data_event, write_event, E...> {
|
||||||
|
using base = handle<T, U, listen_event, end_event, connect_event, shutdown_event, data_event, write_event, E...>;
|
||||||
|
|
||||||
|
template<typename, typename, typename...>
|
||||||
|
friend class stream_handle;
|
||||||
|
|
||||||
|
static constexpr unsigned int DEFAULT_BACKLOG = 128;
|
||||||
|
|
||||||
|
static void read_callback(uv_stream_t *hndl, ssize_t nread, const uv_buf_t *buf) {
|
||||||
|
T &ref = *(static_cast<T *>(hndl->data));
|
||||||
|
// data will be destroyed no matter of what the value of nread is
|
||||||
|
std::unique_ptr<char[]> data{buf->base};
|
||||||
|
|
||||||
|
// nread == 0 is ignored (see http://docs.libuv.org/en/v1.x/stream.html)
|
||||||
|
// equivalent to EAGAIN/EWOULDBLOCK, it shouldn't be treated as an error
|
||||||
|
// for we don't have data to emit though, it's fine to suppress it
|
||||||
|
|
||||||
|
if(nread == UV_EOF) {
|
||||||
|
// end of stream
|
||||||
|
ref.publish(end_event{});
|
||||||
|
} else if(nread > 0) {
|
||||||
|
// data available
|
||||||
|
ref.publish(data_event{std::move(data), static_cast<std::size_t>(nread)});
|
||||||
|
} else if(nread < 0) {
|
||||||
|
// transmission error
|
||||||
|
ref.publish(error_event(nread));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void listen_callback(uv_stream_t *hndl, int status) {
|
||||||
|
if(T &ref = *(static_cast<T *>(hndl->data)); status) {
|
||||||
|
ref.publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
ref.publish(listen_event{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] uv_stream_t *as_uv_stream() {
|
||||||
|
return reinterpret_cast<uv_stream_t *>(this->raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const uv_stream_t *as_uv_stream() const {
|
||||||
|
return reinterpret_cast<const uv_stream_t *>(this->raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
stream_handle(loop::token token, std::shared_ptr<loop> ref)
|
||||||
|
: base{token, std::move(ref)} {}
|
||||||
|
#else
|
||||||
|
using base::base;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shutdowns the outgoing (write) side of a duplex stream.
|
||||||
|
*
|
||||||
|
* It waits for pending write requests to complete. The handle should refer
|
||||||
|
* to a initialized stream.<br/>
|
||||||
|
* A shutdown event will be emitted after shutdown is complete.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int shutdown() {
|
||||||
|
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
|
||||||
|
ptr->publish(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto shutdown = this->parent().template resource<details::shutdown_req>();
|
||||||
|
shutdown->template on<error_event>(listener);
|
||||||
|
shutdown->template on<shutdown_event>(listener);
|
||||||
|
|
||||||
|
return shutdown->shutdown(as_uv_stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts listening for incoming connections.
|
||||||
|
*
|
||||||
|
* When a new incoming connection is received, a listen event is
|
||||||
|
* emitted.
|
||||||
|
*
|
||||||
|
* @param backlog Indicates the number of connections the kernel might
|
||||||
|
* queue, same as listen(2).
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int listen(int backlog = DEFAULT_BACKLOG) {
|
||||||
|
return uv_listen(as_uv_stream(), backlog, &listen_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Accepts incoming connections.
|
||||||
|
*
|
||||||
|
* This call is used in conjunction with `listen()` to accept incoming
|
||||||
|
* connections. Call this function after receiving a listen event to accept
|
||||||
|
* the connection. Before calling this function, the submitted handle must
|
||||||
|
* be initialized.
|
||||||
|
*
|
||||||
|
* When the listen event is emitted it is guaranteed that this function will
|
||||||
|
* complete successfully the first time. If you attempt to use it more than
|
||||||
|
* once, it may fail.<br/>
|
||||||
|
* It is suggested to only call this function once per listen event.
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Both the handles must be running on the same loop.
|
||||||
|
*
|
||||||
|
* @param ref An initialized handle to be used to accept the connection.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<typename S>
|
||||||
|
int accept(S &ref) {
|
||||||
|
return uv_accept(as_uv_stream(), ref.as_uv_stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts reading data from an incoming stream.
|
||||||
|
*
|
||||||
|
* A data event will be emitted several times until there is no more data to
|
||||||
|
* read or `stop()` is called.<br/>
|
||||||
|
* An end event will be emitted when there is no more data to read.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int read() {
|
||||||
|
return uv_read_start(as_uv_stream(), &details::common_alloc_callback, &read_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts reading data from an incoming stream.
|
||||||
|
* @sa read
|
||||||
|
* @tparam Alloc Custom allocation function.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<auto Alloc>
|
||||||
|
int read() {
|
||||||
|
return uv_read_start(as_uv_stream(), &details::common_alloc_callback<T, Alloc>, &read_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops reading data from the stream.
|
||||||
|
*
|
||||||
|
* This function is idempotent and may be safely called on a stopped stream.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int stop() {
|
||||||
|
return uv_read_stop(as_uv_stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes data to the stream.
|
||||||
|
*
|
||||||
|
* Data are written in order. The handle takes the ownership of the data and
|
||||||
|
* it is in charge of delete them.
|
||||||
|
*
|
||||||
|
* A write event will be emitted when the data have been written.
|
||||||
|
*
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<typename Deleter>
|
||||||
|
int write(std::unique_ptr<char[], Deleter> data, unsigned int len) {
|
||||||
|
auto req = this->parent().template resource<details::write_req<Deleter>>(std::move(data), len);
|
||||||
|
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
|
||||||
|
ptr->publish(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
req->template on<error_event>(listener);
|
||||||
|
req->template on<write_event>(listener);
|
||||||
|
|
||||||
|
return req->write(as_uv_stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes data to the stream.
|
||||||
|
*
|
||||||
|
* Data are written in order. The handle doesn't take the ownership of the
|
||||||
|
* data. Be sure that their lifetime overcome the one of the request.
|
||||||
|
*
|
||||||
|
* A write event will be emitted when the data have been written.
|
||||||
|
*
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int write(char *data, unsigned int len) {
|
||||||
|
auto req = this->parent().template resource<details::write_req<void (*)(char *)>>(std::unique_ptr<char[], void (*)(char *)>{data, [](char *) {}}, len);
|
||||||
|
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
|
||||||
|
ptr->publish(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
req->template on<error_event>(listener);
|
||||||
|
req->template on<write_event>(listener);
|
||||||
|
|
||||||
|
return req->write(as_uv_stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extended write function for sending handles over a pipe handle.
|
||||||
|
*
|
||||||
|
* The pipe must be initialized with `ipc == true`.
|
||||||
|
*
|
||||||
|
* `send` must be a tcp or pipe handle, which is a server or a connection
|
||||||
|
* (listening or connected state). Bound sockets or pipes will be assumed to
|
||||||
|
* be servers.
|
||||||
|
*
|
||||||
|
* The handle takes the ownership of the data and it is in charge of delete
|
||||||
|
* them.
|
||||||
|
*
|
||||||
|
* A write event will be emitted when the data have been written.
|
||||||
|
*
|
||||||
|
* @param send The handle over which to write data.
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<typename S, typename Deleter>
|
||||||
|
int write(S &send, std::unique_ptr<char[], Deleter> data, unsigned int len) {
|
||||||
|
auto req = this->parent().template resource<details::write_req<Deleter>>(std::move(data), len);
|
||||||
|
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
|
||||||
|
ptr->publish(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
req->template on<error_event>(listener);
|
||||||
|
req->template on<write_event>(listener);
|
||||||
|
|
||||||
|
return req->write(as_uv_stream(), send.as_uv_stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extended write function for sending handles over a pipe handle.
|
||||||
|
*
|
||||||
|
* The pipe must be initialized with `ipc == true`.
|
||||||
|
*
|
||||||
|
* `send` must be a tcp or pipe handle, which is a server or a connection
|
||||||
|
* (listening or connected state). Bound sockets or pipes will be assumed to
|
||||||
|
* be servers.
|
||||||
|
*
|
||||||
|
* The handle doesn't take the ownership of the data. Be sure that their
|
||||||
|
* lifetime overcome the one of the request.
|
||||||
|
*
|
||||||
|
* A write event will be emitted when the data have been written.
|
||||||
|
*
|
||||||
|
* @param send The handle over which to write data.
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<typename S>
|
||||||
|
int write(S &send, char *data, unsigned int len) {
|
||||||
|
auto req = this->parent().template resource<details::write_req<void (*)(char *)>>(std::unique_ptr<char[], void (*)(char *)>{data, [](char *) {}}, len);
|
||||||
|
auto listener = [ptr = this->shared_from_this()](const auto &event, const auto &) {
|
||||||
|
ptr->publish(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
req->template on<error_event>(listener);
|
||||||
|
req->template on<write_event>(listener);
|
||||||
|
|
||||||
|
return req->write(as_uv_stream(), send.as_uv_stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Queues a write request if it can be completed immediately.
|
||||||
|
*
|
||||||
|
* Same as `write()`, but won’t queue a write request if it can’t be
|
||||||
|
* completed immediately.
|
||||||
|
*
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int try_write(std::unique_ptr<char[]> data, unsigned int len) {
|
||||||
|
std::array bufs{uv_buf_init(data.get(), len)};
|
||||||
|
return uv_try_write(as_uv_stream(), bufs.data(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Queues a write request if it can be completed immediately.
|
||||||
|
*
|
||||||
|
* Same as `try_write` for sending handles over a pipe.
|
||||||
|
*
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @param send A valid handle suitable for the purpose.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<typename V, typename W>
|
||||||
|
int try_write(std::unique_ptr<char[]> data, unsigned int len, stream_handle<V, W> &send) {
|
||||||
|
std::array bufs{uv_buf_init(data.get(), len)};
|
||||||
|
return uv_try_write2(as_uv_stream(), bufs.data(), 1, send.raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Queues a write request if it can be completed immediately.
|
||||||
|
*
|
||||||
|
* Same as `write()`, but won’t queue a write request if it can’t be
|
||||||
|
* completed immediately.
|
||||||
|
*
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int try_write(char *data, unsigned int len) {
|
||||||
|
std::array bufs{uv_buf_init(data, len)};
|
||||||
|
return uv_try_write(as_uv_stream(), bufs.data(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Queues a write request if it can be completed immediately.
|
||||||
|
*
|
||||||
|
* Same as `try_write` for sending handles over a pipe.
|
||||||
|
*
|
||||||
|
* @param data The data to be written to the stream.
|
||||||
|
* @param len The lenght of the submitted data.
|
||||||
|
* @param send A valid handle suitable for the purpose.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
template<typename V, typename W>
|
||||||
|
int try_write(char *data, unsigned int len, stream_handle<V, W> &send) {
|
||||||
|
std::array bufs{uv_buf_init(data, len)};
|
||||||
|
return uv_try_write2(as_uv_stream(), bufs.data(), 1, send.raw());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the stream is readable.
|
||||||
|
* @return True if the stream is readable, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool readable() const noexcept {
|
||||||
|
return (uv_is_readable(as_uv_stream()) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the stream is writable.
|
||||||
|
* @return True if the stream is writable, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool writable() const noexcept {
|
||||||
|
return (uv_is_writable(as_uv_stream()) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables or disables blocking mode for a stream.
|
||||||
|
*
|
||||||
|
* When blocking mode is enabled all writes complete synchronously. The
|
||||||
|
* interface remains unchanged otherwise, e.g. completion or failure of the
|
||||||
|
* operation will still be reported through events which are emitted
|
||||||
|
* asynchronously.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/stream.html#c.uv_stream_set_blocking)
|
||||||
|
* for further details.
|
||||||
|
*
|
||||||
|
* @param enable True to enable blocking mode, false otherwise.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
|
bool blocking(bool enable = false) {
|
||||||
|
return (0 == uv_stream_set_blocking(as_uv_stream(), enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the amount of queued bytes waiting to be sent.
|
||||||
|
* @return Amount of queued bytes waiting to be sent.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] size_t write_queue_size() const noexcept {
|
||||||
|
return uv_stream_get_write_queue_size(as_uv_stream());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "stream.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_STREAM_INCLUDE_H
|
||||||
@ -1,481 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iterator>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "request.hpp"
|
|
||||||
#include "handle.hpp"
|
|
||||||
#include "loop.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ConnectEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by StreamHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct ConnectEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief EndEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by StreamHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct EndEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ListenEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by StreamHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct ListenEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ShutdownEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by StreamHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct ShutdownEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief WriteEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by StreamHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct WriteEvent {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief DataEvent event.
|
|
||||||
*
|
|
||||||
* It will be emitted by StreamHandle according with its functionalities.
|
|
||||||
*/
|
|
||||||
struct DataEvent {
|
|
||||||
explicit DataEvent(std::unique_ptr<char[]> buf, std::size_t len) noexcept
|
|
||||||
: data{std::move(buf)}, length{len}
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::unique_ptr<char[]> data; /*!< A bunch of data read on the stream. */
|
|
||||||
std::size_t length; /*!< The amount of data read on the stream. */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
|
|
||||||
struct ConnectReq final: public Request<ConnectReq, uv_connect_t> {
|
|
||||||
using Request::Request;
|
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
|
||||||
void connect(F &&f, Args&&... args) {
|
|
||||||
invoke(std::forward<F>(f), get(), std::forward<Args>(args)..., &defaultCallback<ConnectEvent>);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct ShutdownReq final: public Request<ShutdownReq, uv_shutdown_t> {
|
|
||||||
using Request::Request;
|
|
||||||
|
|
||||||
void shutdown(uv_stream_t *handle) {
|
|
||||||
invoke(&uv_shutdown, get(), handle, &defaultCallback<ShutdownEvent>);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class WriteReq final: public Request<WriteReq, uv_write_t> {
|
|
||||||
public:
|
|
||||||
using Deleter = void(*)(char *);
|
|
||||||
|
|
||||||
WriteReq(ConstructorAccess ca, std::shared_ptr<Loop> loop, std::unique_ptr<char[], Deleter> dt, unsigned int len)
|
|
||||||
: Request<WriteReq, uv_write_t>{ca, std::move(loop)},
|
|
||||||
data{std::move(dt)},
|
|
||||||
buf(uv_buf_init(data.get(), len))
|
|
||||||
{}
|
|
||||||
|
|
||||||
void write(uv_stream_t *handle) {
|
|
||||||
invoke(&uv_write, get(), handle, &buf, 1, &defaultCallback<WriteEvent>);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(uv_stream_t *handle, uv_stream_t *send) {
|
|
||||||
invoke(&uv_write2, get(), handle, &buf, 1, send, &defaultCallback<WriteEvent>);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<char[], Deleter> data;
|
|
||||||
uv_buf_t buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The StreamHandle handle.
|
|
||||||
*
|
|
||||||
* Stream handles provide an abstraction of a duplex communication channel.
|
|
||||||
* StreamHandle is an intermediate type, `uvw` provides three stream
|
|
||||||
* implementations: TCPHandle, PipeHandle and TTYHandle.
|
|
||||||
*/
|
|
||||||
template<typename T, typename U>
|
|
||||||
class StreamHandle: public Handle<T, U> {
|
|
||||||
static constexpr unsigned int DEFAULT_BACKLOG = 128;
|
|
||||||
|
|
||||||
static void readCallback(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) {
|
|
||||||
T &ref = *(static_cast<T*>(handle->data));
|
|
||||||
// data will be destroyed no matter of what the value of nread is
|
|
||||||
std::unique_ptr<char[]> data{buf->base};
|
|
||||||
|
|
||||||
// nread == 0 is ignored (see http://docs.libuv.org/en/v1.x/stream.html)
|
|
||||||
// equivalent to EAGAIN/EWOULDBLOCK, it shouldn't be treated as an error
|
|
||||||
// for we don't have data to emit though, it's fine to suppress it
|
|
||||||
|
|
||||||
if(nread == UV_EOF) {
|
|
||||||
// end of stream
|
|
||||||
ref.publish(EndEvent{});
|
|
||||||
} else if(nread > 0) {
|
|
||||||
// data available
|
|
||||||
ref.publish(DataEvent{std::move(data), static_cast<std::size_t>(nread)});
|
|
||||||
} else if(nread < 0) {
|
|
||||||
// transmission error
|
|
||||||
ref.publish(ErrorEvent(nread));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void listenCallback(uv_stream_t *handle, int status) {
|
|
||||||
T &ref = *(static_cast<T*>(handle->data));
|
|
||||||
if(status) { ref.publish(ErrorEvent{status}); }
|
|
||||||
else { ref.publish(ListenEvent{}); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
StreamHandle(typename Handle<T, U>::ConstructorAccess ca, std::shared_ptr<Loop> ref)
|
|
||||||
: Handle<T, U>{ca, std::move(ref)}
|
|
||||||
{}
|
|
||||||
#else
|
|
||||||
using Handle<T, U>::Handle;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Shutdowns the outgoing (write) side of a duplex stream.
|
|
||||||
*
|
|
||||||
* It waits for pending write requests to complete. The handle should refer
|
|
||||||
* to a initialized stream.<br/>
|
|
||||||
* A ShutdownEvent event will be emitted after shutdown is complete.
|
|
||||||
*/
|
|
||||||
void shutdown() {
|
|
||||||
auto ptr = this->shared_from_this();
|
|
||||||
auto errorEventListener = [ptr](const ErrorEvent &event, const details::ShutdownReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
auto shutdownEventListener = [ptr](const ShutdownEvent &event, const details::ShutdownReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto shutdown = this->loop().template resource<details::ShutdownReq>();
|
|
||||||
shutdown->template once<ErrorEvent>(errorEventListener);
|
|
||||||
shutdown->template once<ShutdownEvent>(shutdownEventListener);
|
|
||||||
shutdown->shutdown(this->template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts listening for incoming connections.
|
|
||||||
*
|
|
||||||
* When a new incoming connection is received, a ListenEvent event is
|
|
||||||
* emitted.<br/>
|
|
||||||
* An ErrorEvent event will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* @param backlog Indicates the number of connections the kernel might
|
|
||||||
* queue, same as listen(2).
|
|
||||||
*/
|
|
||||||
void listen(int backlog = DEFAULT_BACKLOG) {
|
|
||||||
this->invoke(&uv_listen, this->template get<uv_stream_t>(), backlog, &listenCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Accepts incoming connections.
|
|
||||||
*
|
|
||||||
* This call is used in conjunction with `listen()` to accept incoming
|
|
||||||
* connections. Call this function after receiving a ListenEvent event to
|
|
||||||
* accept the connection. Before calling this function, the submitted handle
|
|
||||||
* must be initialized.<br>
|
|
||||||
* An ErrorEvent event will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* When the ListenEvent event is emitted it is guaranteed that this
|
|
||||||
* function will complete successfully the first time. If you attempt to use
|
|
||||||
* it more than once, it may fail.<br/>
|
|
||||||
* It is suggested to only call this function once per ListenEvent event.
|
|
||||||
*
|
|
||||||
* @note
|
|
||||||
* Both the handles must be running on the same loop.
|
|
||||||
*
|
|
||||||
* @param ref An initialized handle to be used to accept the connection.
|
|
||||||
*/
|
|
||||||
template<typename S>
|
|
||||||
void accept(S &ref) {
|
|
||||||
this->invoke(&uv_accept, this->template get<uv_stream_t>(), ref.template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts reading data from an incoming stream.
|
|
||||||
*
|
|
||||||
* A DataEvent event will be emitted several times until there is no more
|
|
||||||
* data to read or `stop()` is called.<br/>
|
|
||||||
* An EndEvent event will be emitted when there is no more data to read.
|
|
||||||
*/
|
|
||||||
void read() {
|
|
||||||
this->invoke(&uv_read_start, this->template get<uv_stream_t>(), &this->allocCallback, &readCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops reading data from the stream.
|
|
||||||
*
|
|
||||||
* This function is idempotent and may be safely called on a stopped stream.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
this->invoke(&uv_read_stop, this->template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Writes data to the stream.
|
|
||||||
*
|
|
||||||
* Data are written in order. The handle takes the ownership of the data and
|
|
||||||
* it is in charge of delete them.
|
|
||||||
*
|
|
||||||
* A WriteEvent event will be emitted when the data have been written.<br/>
|
|
||||||
* An ErrorEvent event will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* @param data The data to be written to the stream.
|
|
||||||
* @param len The lenght of the submitted data.
|
|
||||||
*/
|
|
||||||
void write(std::unique_ptr<char[]> data, unsigned int len) {
|
|
||||||
auto req = this->loop().template resource<details::WriteReq>(
|
|
||||||
std::unique_ptr<char[], details::WriteReq::Deleter>{
|
|
||||||
data.release(), [](char *ptr) { delete[] ptr; }
|
|
||||||
}, len);
|
|
||||||
|
|
||||||
auto ptr = this->shared_from_this();
|
|
||||||
auto errorEventListener = [ptr](const ErrorEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
auto writeEventListener = [ptr](const WriteEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
req->template once<ErrorEvent>(errorEventListener);
|
|
||||||
req->template once<WriteEvent>(writeEventListener);
|
|
||||||
req->write(this->template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Writes data to the stream.
|
|
||||||
*
|
|
||||||
* Data are written in order. The handle doesn't take the ownership of the
|
|
||||||
* data. Be sure that their lifetime overcome the one of the request.
|
|
||||||
*
|
|
||||||
* A WriteEvent event will be emitted when the data have been written.<br/>
|
|
||||||
* An ErrorEvent event will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* @param data The data to be written to the stream.
|
|
||||||
* @param len The lenght of the submitted data.
|
|
||||||
*/
|
|
||||||
void write(char *data, unsigned int len) {
|
|
||||||
auto req = this->loop().template resource<details::WriteReq>(
|
|
||||||
std::unique_ptr<char[], details::WriteReq::Deleter>{
|
|
||||||
data, [](char *) {}
|
|
||||||
}, len);
|
|
||||||
|
|
||||||
auto ptr = this->shared_from_this();
|
|
||||||
auto errorEventListener = [ptr](const ErrorEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
auto writeEventListener = [ptr](const WriteEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
req->template once<ErrorEvent>(errorEventListener);
|
|
||||||
req->template once<WriteEvent>(writeEventListener);
|
|
||||||
req->write(this->template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Extended write function for sending handles over a pipe handle.
|
|
||||||
*
|
|
||||||
* The pipe must be initialized with `ipc == true`.
|
|
||||||
*
|
|
||||||
* `send` must be a TCPHandle or PipeHandle handle, which is a server or a
|
|
||||||
* connection (listening or connected state). Bound sockets or pipes will be
|
|
||||||
* assumed to be servers.
|
|
||||||
*
|
|
||||||
* The handle takes the ownership of the data and it is in charge of delete
|
|
||||||
* them.
|
|
||||||
*
|
|
||||||
* A WriteEvent event will be emitted when the data have been written.<br/>
|
|
||||||
* An ErrorEvent wvent will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* @param send The handle over which to write data.
|
|
||||||
* @param data The data to be written to the stream.
|
|
||||||
* @param len The lenght of the submitted data.
|
|
||||||
*/
|
|
||||||
template<typename S>
|
|
||||||
void write(S &send, std::unique_ptr<char[]> data, unsigned int len) {
|
|
||||||
auto req = this->loop().template resource<details::WriteReq>(
|
|
||||||
std::unique_ptr<char[], details::WriteReq::Deleter>{
|
|
||||||
data.release(), [](char *ptr) { delete[] ptr; }
|
|
||||||
}, len);
|
|
||||||
|
|
||||||
auto ptr = this->shared_from_this();
|
|
||||||
auto errorEventListener = [ptr](const ErrorEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
auto writeEventListener = [ptr](const WriteEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
req->template once<ErrorEvent>(errorEventListener);
|
|
||||||
req->template once<WriteEvent>(writeEventListener);
|
|
||||||
req->write(this->template get<uv_stream_t>(), send.template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Extended write function for sending handles over a pipe handle.
|
|
||||||
*
|
|
||||||
* The pipe must be initialized with `ipc == true`.
|
|
||||||
*
|
|
||||||
* `send` must be a TCPHandle or PipeHandle handle, which is a server or a
|
|
||||||
* connection (listening or connected state). Bound sockets or pipes will be
|
|
||||||
* assumed to be servers.
|
|
||||||
*
|
|
||||||
* The handle doesn't take the ownership of the data. Be sure that their
|
|
||||||
* lifetime overcome the one of the request.
|
|
||||||
*
|
|
||||||
* A WriteEvent event will be emitted when the data have been written.<br/>
|
|
||||||
* An ErrorEvent wvent will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* @param send The handle over which to write data.
|
|
||||||
* @param data The data to be written to the stream.
|
|
||||||
* @param len The lenght of the submitted data.
|
|
||||||
*/
|
|
||||||
template<typename S>
|
|
||||||
void write(S &send, char *data, unsigned int len) {
|
|
||||||
auto req = this->loop().template resource<details::WriteReq>(
|
|
||||||
std::unique_ptr<char[], details::WriteReq::Deleter>{
|
|
||||||
data, [](char *) {}
|
|
||||||
}, len);
|
|
||||||
|
|
||||||
auto ptr = this->shared_from_this();
|
|
||||||
auto errorEventListener = [ptr](const ErrorEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
auto writeEventListener = [ptr](const WriteEvent &event, const details::WriteReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
req->template once<ErrorEvent>(errorEventListener);
|
|
||||||
req->template once<WriteEvent>(writeEventListener);
|
|
||||||
req->write(this->template get<uv_stream_t>(), send.template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Queues a write request if it can be completed immediately.
|
|
||||||
*
|
|
||||||
* Same as `write()`, but won’t queue a write request if it can’t be
|
|
||||||
* completed immediately.<br/>
|
|
||||||
* An ErrorEvent event will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* @param data The data to be written to the stream.
|
|
||||||
* @param len The lenght of the submitted data.
|
|
||||||
* @return Number of bytes written.
|
|
||||||
*/
|
|
||||||
int tryWrite(std::unique_ptr<char[]> data, unsigned int len) {
|
|
||||||
uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
|
|
||||||
auto bw = uv_try_write(this->template get<uv_stream_t>(), bufs, 1);
|
|
||||||
|
|
||||||
if(bw < 0) {
|
|
||||||
this->publish(ErrorEvent{bw});
|
|
||||||
bw = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Queues a write request if it can be completed immediately.
|
|
||||||
*
|
|
||||||
* Same as `write()`, but won’t queue a write request if it can’t be
|
|
||||||
* completed immediately.<br/>
|
|
||||||
* An ErrorEvent event will be emitted in case of errors.
|
|
||||||
*
|
|
||||||
* @param data The data to be written to the stream.
|
|
||||||
* @param len The lenght of the submitted data.
|
|
||||||
* @return Number of bytes written.
|
|
||||||
*/
|
|
||||||
int tryWrite(char *data, unsigned int len) {
|
|
||||||
uv_buf_t bufs[] = { uv_buf_init(data, len) };
|
|
||||||
auto bw = uv_try_write(this->template get<uv_stream_t>(), bufs, 1);
|
|
||||||
|
|
||||||
if(bw < 0) {
|
|
||||||
this->publish(ErrorEvent{bw});
|
|
||||||
bw = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the stream is readable.
|
|
||||||
* @return True if the stream is readable, false otherwise.
|
|
||||||
*/
|
|
||||||
bool readable() const noexcept {
|
|
||||||
return (uv_is_readable(this->template get<uv_stream_t>()) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the stream is writable.
|
|
||||||
* @return True if the stream is writable, false otherwise.
|
|
||||||
*/
|
|
||||||
bool writable() const noexcept {
|
|
||||||
return (uv_is_writable(this->template get<uv_stream_t>()) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enables or disables blocking mode for a stream.
|
|
||||||
*
|
|
||||||
* When blocking mode is enabled all writes complete synchronously. The
|
|
||||||
* interface remains unchanged otherwise, e.g. completion or failure of the
|
|
||||||
* operation will still be reported through events which are emitted
|
|
||||||
* asynchronously.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/stream.html#c.uv_stream_set_blocking)
|
|
||||||
* for further details.
|
|
||||||
*
|
|
||||||
* @param enable True to enable blocking mode, false otherwise.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool blocking(bool enable = false) {
|
|
||||||
return (0 == uv_stream_set_blocking(this->template get<uv_stream_t>(), enable));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the amount of queued bytes waiting to be sent.
|
|
||||||
* @return Amount of queued bytes waiting to be sent.
|
|
||||||
*/
|
|
||||||
size_t writeQueueSize() const noexcept {
|
|
||||||
return uv_stream_get_write_queue_size(this->template get<uv_stream_t>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
29
src/uvw/stream.ipp
Normal file
29
src/uvw/stream.ipp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
UVW_INLINE data_event::data_event(std::unique_ptr<char[]> buf, std::size_t len) noexcept
|
||||||
|
: data{std::move(buf)},
|
||||||
|
length{len} {}
|
||||||
|
|
||||||
|
UVW_INLINE void details::connect_req::connect_callback(uv_connect_t *req, int status) {
|
||||||
|
if(auto ptr = reserve(req); status) {
|
||||||
|
ptr->publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
ptr->publish(connect_event{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE void details::shutdown_req::shoutdown_callback(uv_shutdown_t *req, int status) {
|
||||||
|
if(auto ptr = reserve(req); status) {
|
||||||
|
ptr->publish(error_event{status});
|
||||||
|
} else {
|
||||||
|
ptr->publish(shutdown_event{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UVW_INLINE int details::shutdown_req::shutdown(uv_stream_t *hndl) {
|
||||||
|
return this->leak_if(uv_shutdown(raw(), hndl, &shoutdown_callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
2
src/uvw/tcp.cpp
Normal file
2
src/uvw/tcp.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "tcp.h"
|
||||||
|
#include "tcp.ipp"
|
||||||
233
src/uvw/tcp.h
Normal file
233
src/uvw/tcp.h
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#ifndef UVW_TCP_INCLUDE_H
|
||||||
|
#define UVW_TCP_INCLUDE_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "enum.hpp"
|
||||||
|
#include "request.hpp"
|
||||||
|
#include "stream.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace uvw {
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
enum class uvw_tcp_flags : std::underlying_type_t<uv_tcp_flags> {
|
||||||
|
IPV6ONLY = UV_TCP_IPV6ONLY,
|
||||||
|
UVW_ENUM = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The TCP handle.
|
||||||
|
*
|
||||||
|
* TCP handles are used to represent both TCP streams and servers.<br/>
|
||||||
|
* By default, _ipv4_ is used as a template parameter. The handle already
|
||||||
|
* supports _IPv6_ out-of-the-box by using `uvw::ipv6`.
|
||||||
|
*
|
||||||
|
* To create a `tcp_handle` through a `loop`, arguments follow:
|
||||||
|
*
|
||||||
|
* * An optional integer value that indicates the flags used to initialize
|
||||||
|
* the socket.
|
||||||
|
*
|
||||||
|
* See the official
|
||||||
|
* [documentation](http://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_init_ex)
|
||||||
|
* for further details.
|
||||||
|
*/
|
||||||
|
class tcp_handle final: public stream_handle<tcp_handle, uv_tcp_t> {
|
||||||
|
public:
|
||||||
|
using time = std::chrono::duration<unsigned int>;
|
||||||
|
using tcp_flags = details::uvw_tcp_flags;
|
||||||
|
using ipv4 = uvw::ipv4;
|
||||||
|
using ipv6 = uvw::ipv6;
|
||||||
|
|
||||||
|
explicit tcp_handle(loop::token token, std::shared_ptr<loop> ref, unsigned int f = {});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the handle. No socket is created as of yet.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Opens an existing file descriptor or SOCKET as a TCP handle.
|
||||||
|
*
|
||||||
|
* The passed file descriptor or SOCKET is not checked for its type, but
|
||||||
|
* it’s required that it represents a valid stream socket.
|
||||||
|
*
|
||||||
|
* @param socket A valid socket handle (either a file descriptor or a
|
||||||
|
* SOCKET).
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int open(os_socket_handle socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables/Disables Nagle’s algorithm.
|
||||||
|
* @param value True to enable it, false otherwise.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
|
bool no_delay(bool value = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables/Disables TCP keep-alive.
|
||||||
|
* @param enable True to enable it, false otherwise.
|
||||||
|
* @param val Initial delay in seconds (use
|
||||||
|
* `std::chrono::duration<unsigned int>`).
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
|
bool keep_alive(bool enable = false, time val = time{0});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables/Disables simultaneous asynchronous accept requests.
|
||||||
|
*
|
||||||
|
* Enables/Disables simultaneous asynchronous accept requests that are
|
||||||
|
* queued by the operating system when listening for new TCP
|
||||||
|
* connections.<br/>
|
||||||
|
* This setting is used to tune a TCP server for the desired performance.
|
||||||
|
* Having simultaneous accepts can significantly improve the rate of
|
||||||
|
* accepting connections (which is why it is enabled by default) but may
|
||||||
|
* lead to uneven load distribution in multi-process setups.
|
||||||
|
*
|
||||||
|
* @param enable True to enable it, false otherwise.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
|
bool simultaneous_accepts(bool enable = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Binds the handle to an address and port.
|
||||||
|
*
|
||||||
|
* A successful call to this function does not guarantee that the call to
|
||||||
|
* `listen()` or `connect()` will work properly.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
|
||||||
|
* only IPv6 is used.
|
||||||
|
*
|
||||||
|
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||||
|
* @param opts Optional additional flags.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int bind(const sockaddr &addr, tcp_flags opts = tcp_flags::UVW_ENUM);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Binds the handle to an address and port.
|
||||||
|
*
|
||||||
|
* A successful call to this function does not guarantee that the call to
|
||||||
|
* `listen()` or `connect()` will work properly.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
|
||||||
|
* only IPv6 is used.
|
||||||
|
*
|
||||||
|
* @param ip The address to which to bind.
|
||||||
|
* @param port The port to which to bind.
|
||||||
|
* @param opts Optional additional flags.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int bind(const std::string &ip, unsigned int port, tcp_flags opts = tcp_flags::UVW_ENUM);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Binds the handle to an address and port.
|
||||||
|
*
|
||||||
|
* A successful call to this function does not guarantee that the call to
|
||||||
|
* `listen()` or `connect()` will work properly.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and
|
||||||
|
* only IPv6 is used.
|
||||||
|
*
|
||||||
|
* @param addr A valid instance of socket_address.
|
||||||
|
* @param opts Optional additional flags.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int bind(const socket_address &addr, tcp_flags opts = tcp_flags::UVW_ENUM);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current address to which the handle is bound.
|
||||||
|
* @return A valid instance of socket_address, an empty one in case of
|
||||||
|
* errors.
|
||||||
|
*/
|
||||||
|
socket_address sock() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the address of the peer connected to the handle.
|
||||||
|
* @return A valid instance of socket_address, an empty one in case of
|
||||||
|
* errors.
|
||||||
|
*/
|
||||||
|
socket_address peer() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Establishes an IPv4 or IPv6 TCP connection.
|
||||||
|
*
|
||||||
|
* On Windows if the addr is initialized to point to an unspecified address
|
||||||
|
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
||||||
|
* done to match the behavior of Linux systems.
|
||||||
|
*
|
||||||
|
* A connect event is emitted when the connection has been established.
|
||||||
|
*
|
||||||
|
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int connect(const sockaddr &addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Establishes an IPv4 or IPv6 TCP connection.
|
||||||
|
*
|
||||||
|
* A connect event is emitted when the connection has been established.
|
||||||
|
*
|
||||||
|
* @param ip The address to which to bind.
|
||||||
|
* @param port The port to which to bind.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int connect(const std::string &ip, unsigned int port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Establishes an IPv4 or IPv6 TCP connection.
|
||||||
|
*
|
||||||
|
* A connect event is emitted when the connection has been established.
|
||||||
|
*
|
||||||
|
* @param addr A valid instance of socket_address.
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int connect(const socket_address &addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets a TCP connection by sending a RST packet.
|
||||||
|
*
|
||||||
|
* This is accomplished by setting the `SO_LINGER` socket option with a
|
||||||
|
* linger interval of zero and then calling `close`.<br/>
|
||||||
|
* Due to some platform inconsistencies, mixing of `shutdown` and
|
||||||
|
* `close_reset` calls is not allowed.
|
||||||
|
*
|
||||||
|
* A close event is emitted when the connection has been reset.
|
||||||
|
*
|
||||||
|
* @return Underlying return value.
|
||||||
|
*/
|
||||||
|
int close_reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
DEFAULT,
|
||||||
|
FLAGS
|
||||||
|
} tag;
|
||||||
|
|
||||||
|
unsigned int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace uvw
|
||||||
|
|
||||||
|
#ifndef UVW_AS_LIB
|
||||||
|
# include "tcp.ipp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UVW_TCP_INCLUDE_H
|
||||||
265
src/uvw/tcp.hpp
265
src/uvw/tcp.hpp
@ -1,265 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <chrono>
|
|
||||||
#include <uv.h>
|
|
||||||
#include "request.hpp"
|
|
||||||
#include "stream.hpp"
|
|
||||||
#include "util.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace uvw {
|
|
||||||
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
|
|
||||||
enum class UVTCPFlags: typename std::underlying_type<uv_tcp_flags>::type {
|
|
||||||
IPV6ONLY = UV_TCP_IPV6ONLY
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The TCPHandle handle.
|
|
||||||
*
|
|
||||||
* TCP handles are used to represent both TCP streams and servers.<br/>
|
|
||||||
* By default, _IPv4_ is used as a template parameter. The handle already
|
|
||||||
* supports _IPv6_ out-of-the-box by using `uvw::IPv6`.
|
|
||||||
*
|
|
||||||
* To create a `TCPHandle` through a `Loop`, arguments follow:
|
|
||||||
*
|
|
||||||
* * An optional integer value that indicates the flags used to initialize
|
|
||||||
* the socket.
|
|
||||||
*
|
|
||||||
* See the official
|
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_init_ex)
|
|
||||||
* for further details.
|
|
||||||
*/
|
|
||||||
class TCPHandle final: public StreamHandle<TCPHandle, uv_tcp_t> {
|
|
||||||
public:
|
|
||||||
using Time = std::chrono::duration<unsigned int>;
|
|
||||||
using Bind = details::UVTCPFlags;
|
|
||||||
using IPv4 = uvw::IPv4;
|
|
||||||
using IPv6 = uvw::IPv6;
|
|
||||||
|
|
||||||
explicit TCPHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int f = {})
|
|
||||||
: StreamHandle{ca, std::move(ref)}, tag{f ? FLAGS : DEFAULT}, flags{f}
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the handle. No socket is created as of yet.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool init() {
|
|
||||||
return (tag == FLAGS)
|
|
||||||
? initialize(&uv_tcp_init_ex, flags)
|
|
||||||
: initialize(&uv_tcp_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Opens an existing file descriptor or SOCKET as a TCP handle.
|
|
||||||
*
|
|
||||||
* The passed file descriptor or SOCKET is not checked for its type, but
|
|
||||||
* it’s required that it represents a valid stream socket.
|
|
||||||
*
|
|
||||||
* @param socket A valid socket handle (either a file descriptor or a SOCKET).
|
|
||||||
*/
|
|
||||||
void open(OSSocketHandle socket) {
|
|
||||||
invoke(&uv_tcp_open, get(), socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enables/Disables Nagle’s algorithm.
|
|
||||||
* @param value True to enable it, false otherwise.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool noDelay(bool value = false) {
|
|
||||||
return (0 == uv_tcp_nodelay(get(), value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enables/Disables TCP keep-alive.
|
|
||||||
* @param enable True to enable it, false otherwise.
|
|
||||||
* @param time Initial delay in seconds (use
|
|
||||||
* `std::chrono::duration<unsigned int>`).
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool keepAlive(bool enable = false, Time time = Time{0}) {
|
|
||||||
return (0 == uv_tcp_keepalive(get(), enable, time.count()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enables/Disables simultaneous asynchronous accept requests.
|
|
||||||
*
|
|
||||||
* Enables/Disables simultaneous asynchronous accept requests that are
|
|
||||||
* queued by the operating system when listening for new TCP
|
|
||||||
* connections.<br/>
|
|
||||||
* This setting is used to tune a TCP server for the desired performance.
|
|
||||||
* Having simultaneous accepts can significantly improve the rate of
|
|
||||||
* accepting connections (which is why it is enabled by default) but may
|
|
||||||
* lead to uneven load distribution in multi-process setups.
|
|
||||||
*
|
|
||||||
* @param enable True to enable it, false otherwise.
|
|
||||||
* @return True in case of success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool simultaneousAccepts(bool enable = true) {
|
|
||||||
return (0 == uv_tcp_simultaneous_accepts(get(), enable));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Binds the handle to an address and port.
|
|
||||||
*
|
|
||||||
* A successful call to this function does not guarantee that the call to
|
|
||||||
* `listen()` or `connect()` will work properly.<br/>
|
|
||||||
* ErrorEvent events can be emitted because of either this function or the
|
|
||||||
* ones mentioned above.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only
|
|
||||||
* IPv6 is used.
|
|
||||||
*
|
|
||||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
|
||||||
* @param opts Optional additional flags.
|
|
||||||
*/
|
|
||||||
void bind(const sockaddr &addr, Flags<Bind> opts = Flags<Bind>{}) {
|
|
||||||
invoke(&uv_tcp_bind, get(), &addr, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Binds the handle to an address and port.
|
|
||||||
*
|
|
||||||
* A successful call to this function does not guarantee that the call to
|
|
||||||
* `listen()` or `connect()` will work properly.<br/>
|
|
||||||
* ErrorEvent events can be emitted because of either this function or the
|
|
||||||
* ones mentioned above.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only
|
|
||||||
* IPv6 is used.
|
|
||||||
*
|
|
||||||
* @param ip The address to which to bind.
|
|
||||||
* @param port The port to which to bind.
|
|
||||||
* @param opts Optional additional flags.
|
|
||||||
*/
|
|
||||||
template<typename I = IPv4>
|
|
||||||
void bind(std::string ip, unsigned int port, Flags<Bind> opts = Flags<Bind>{}) {
|
|
||||||
typename details::IpTraits<I>::Type addr;
|
|
||||||
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
|
|
||||||
bind(reinterpret_cast<const sockaddr &>(addr), std::move(opts));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Binds the handle to an address and port.
|
|
||||||
*
|
|
||||||
* A successful call to this function does not guarantee that the call to
|
|
||||||
* `listen()` or `connect()` will work properly.<br/>
|
|
||||||
* ErrorEvent events can be emitted because of either this function or the
|
|
||||||
* ones mentioned above.
|
|
||||||
*
|
|
||||||
* Available flags are:
|
|
||||||
*
|
|
||||||
* * `TCPHandle::Bind::IPV6ONLY`: it disables dual-stack support and only
|
|
||||||
* IPv6 is used.
|
|
||||||
*
|
|
||||||
* @param addr A valid instance of Addr.
|
|
||||||
* @param opts Optional additional flags.
|
|
||||||
*/
|
|
||||||
template<typename I = IPv4>
|
|
||||||
void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{}) {
|
|
||||||
bind<I>(std::move(addr.ip), addr.port, std::move(opts));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the current address to which the handle is bound.
|
|
||||||
* @return A valid instance of Addr, an empty one in case of errors.
|
|
||||||
*/
|
|
||||||
template<typename I = IPv4>
|
|
||||||
Addr sock() const noexcept {
|
|
||||||
return details::address<I>(&uv_tcp_getsockname, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the address of the peer connected to the handle.
|
|
||||||
* @return A valid instance of Addr, an empty one in case of errors.
|
|
||||||
*/
|
|
||||||
template<typename I = IPv4>
|
|
||||||
Addr peer() const noexcept {
|
|
||||||
return details::address<I>(&uv_tcp_getpeername, get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Establishes an IPv4 or IPv6 TCP connection.
|
|
||||||
*
|
|
||||||
* On Windows if the addr is initialized to point to an unspecified address
|
|
||||||
* (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
|
|
||||||
* done to match the behavior of Linux systems.
|
|
||||||
*
|
|
||||||
* A ConnectEvent event is emitted when the connection has been
|
|
||||||
* established.<br/>
|
|
||||||
* An ErrorEvent event is emitted in case of errors during the connection.
|
|
||||||
*
|
|
||||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
|
||||||
*/
|
|
||||||
void connect(const sockaddr &addr) {
|
|
||||||
auto ptr = shared_from_this();
|
|
||||||
auto errorEventListener = [ptr](const ErrorEvent &event, const details::ConnectReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
auto connectEventListener = [ptr](const ConnectEvent &event, const details::ConnectReq &) {
|
|
||||||
ptr->publish(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
auto req = loop().resource<details::ConnectReq>();
|
|
||||||
req->once<ErrorEvent>(errorEventListener);
|
|
||||||
req->once<ConnectEvent>(connectEventListener);
|
|
||||||
req->connect(&uv_tcp_connect, get(), &addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Establishes an IPv4 or IPv6 TCP connection.
|
|
||||||
*
|
|
||||||
* A ConnectEvent event is emitted when the connection has been
|
|
||||||
* established.<br/>
|
|
||||||
* An ErrorEvent event is emitted in case of errors during the connection.
|
|
||||||
*
|
|
||||||
* @param ip The address to which to bind.
|
|
||||||
* @param port The port to which to bind.
|
|
||||||
*/
|
|
||||||
template<typename I = IPv4>
|
|
||||||
void connect(std::string ip, unsigned int port) {
|
|
||||||
typename details::IpTraits<I>::Type addr;
|
|
||||||
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
|
|
||||||
connect(reinterpret_cast<const sockaddr &>(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Establishes an IPv4 or IPv6 TCP connection.
|
|
||||||
*
|
|
||||||
* A ConnectEvent event is emitted when the connection has been
|
|
||||||
* established.<br/>
|
|
||||||
* An ErrorEvent event is emitted in case of errors during the connection.
|
|
||||||
*
|
|
||||||
* @param addr A valid instance of Addr.
|
|
||||||
*/
|
|
||||||
template<typename I = IPv4>
|
|
||||||
void connect(Addr addr) {
|
|
||||||
connect<I>(std::move(addr.ip), addr.port);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { DEFAULT, FLAGS } tag;
|
|
||||||
unsigned int flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user