Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68ed09d929 | ||
|
|
1c930cdcb5 |
@ -1,41 +0,0 @@
|
|||||||
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
12
.clang-tidy
@ -1,12 +0,0 @@
|
|||||||
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,9 +13,7 @@ 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)
|
||||||
tag_version = os.getenv("GITHUB_REF")
|
return os.getenv("TRAVIS_BRANCH", "master")
|
||||||
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")
|
||||||
@ -30,7 +28,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("GITHUB_REF") else False
|
default_upload = url if os.getenv("TRAVIS_TAG") else False
|
||||||
return os.getenv("CONAN_UPLOAD", default_upload)
|
return os.getenv("CONAN_UPLOAD", default_upload)
|
||||||
|
|
||||||
|
|
||||||
@ -43,6 +41,7 @@ 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,6 +4,8 @@
|
|||||||
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::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
|
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
|
||||||
std::shared_ptr<uvw::tcp_handle> client = srv.loop().resource<uvw::tcp_handle>();
|
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
|
client->on<uvw::CloseEvent>([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::TCPHandle &) { ptr->close(); });
|
||||||
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &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::tcp_handle>();
|
auto tcp = loop.resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
|
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* handle errors */ });
|
||||||
|
|
||||||
tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
|
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &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::get_default();
|
auto loop = uvw::Loop::getDefault();
|
||||||
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
12
.github/FUNDING.yml
vendored
@ -1,12 +0,0 @@
|
|||||||
# 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
21
.github/workflows/build-macos.yml
vendored
@ -1,21 +0,0 @@
|
|||||||
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
25
.github/workflows/build-meson.yml
vendored
@ -1,25 +0,0 @@
|
|||||||
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
39
.github/workflows/build-ubuntu-20.04.yml
vendored
@ -1,39 +0,0 @@
|
|||||||
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
38
.github/workflows/build-ubuntu-latest.yml
vendored
@ -1,38 +0,0 @@
|
|||||||
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
22
.github/workflows/build-win.yml
vendored
@ -1,22 +0,0 @@
|
|||||||
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
33
.github/workflows/coverage.yml
vendored
@ -1,33 +0,0 @@
|
|||||||
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
32
.github/workflows/deploy.yml
vendored
@ -1,32 +0,0 @@
|
|||||||
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
30
.github/workflows/sanitizer.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
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
78
.github/workflows/tools.yml
vendored
@ -1,78 +0,0 @@
|
|||||||
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,9 +1,2 @@
|
|||||||
*.user
|
*.user
|
||||||
CMakeSettings.json
|
|
||||||
.conan/test_package/build
|
.conan/test_package/build
|
||||||
cmake-build-debug/
|
|
||||||
.idea/
|
|
||||||
.vs/
|
|
||||||
.vscode/
|
|
||||||
.cache/
|
|
||||||
out/
|
|
||||||
|
|||||||
71
.travis.yml
Normal file
71
.travis.yml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
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,29 +1,27 @@
|
|||||||
# Author
|
# Author
|
||||||
|
|
||||||
skypjack
|
Michele Caini aka skypjack
|
||||||
|
|
||||||
# Collaborators
|
# Collaborators
|
||||||
|
|
||||||
morbo84
|
Paolo Monteverde aka morbo84
|
||||||
stefanofiorentino
|
|
||||||
|
|
||||||
# Contributors
|
# Contributors
|
||||||
|
|
||||||
lessness
|
Federico Bertolucci aka lessness
|
||||||
lordlukas
|
Luca Martini aka lordlukas
|
||||||
lpmi-13
|
Elia Mazzuoli aka Zikoel
|
||||||
Zikoel
|
Francesco De Felice aka fradefe
|
||||||
fradefe
|
Tushar Maheshwari aka tusharpm
|
||||||
tusharpm
|
Jan Vcelak aka fcelda
|
||||||
fcelda
|
Raoul Hecky aka raoul
|
||||||
raoul
|
Daniel Filonik aka filonik
|
||||||
filonik
|
Wojciech Bartnik aka yisonPylkita
|
||||||
yisonPylkita
|
Miigon aka Miigon
|
||||||
Miigon
|
Slyshyk Oleksiy aka slyshykO
|
||||||
slyshykO
|
bmagistro aka bmagistro
|
||||||
bmagistro
|
Richard Caseres aka richardbmx
|
||||||
richardbmx
|
|
||||||
wnsgml972
|
# Special thanks for patrons
|
||||||
ffontaine
|
|
||||||
elindsey
|
Arn aka ArnCarveris
|
||||||
erez-o
|
|
||||||
|
|||||||
292
CMakeLists.txt
292
CMakeLists.txt
@ -2,7 +2,7 @@
|
|||||||
# uvw
|
# uvw
|
||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
#
|
#
|
||||||
# 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,250 +15,138 @@ endif()
|
|||||||
#
|
#
|
||||||
# Project configuration
|
# Project configuration
|
||||||
#
|
#
|
||||||
set(UVW_VERSION_MAJOR 3)
|
|
||||||
set(UVW_VERSION_MINOR 5)
|
|
||||||
set(UVW_VERSION_PATCH 0)
|
|
||||||
|
|
||||||
project(
|
project(uvw VERSION 1.11.3)
|
||||||
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()
|
||||||
|
|
||||||
option(UVW_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." ON)
|
set(PROJECT_AUTHOR "Michele Caini")
|
||||||
option(UVW_USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF)
|
set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
|
||||||
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)
|
|
||||||
|
|
||||||
if(UVW_BUILD_SHARED_LIB)
|
message("*")
|
||||||
set(UVW_BUILD_LIBS BOOL:ON)
|
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||||
|
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()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Compiler stuff
|
# CMake configuration
|
||||||
#
|
#
|
||||||
|
|
||||||
if(NOT WIN32 AND UVW_USE_LIBCPP)
|
set(PROJECT_CMAKE_IN ${uvw_SOURCE_DIR}/cmake/in)
|
||||||
include(CheckCXXSourceCompiles)
|
set(PROJECT_DEPS_DIR ${uvw_SOURCE_DIR}/deps)
|
||||||
include(CMakePushCheckState)
|
set(PROJECT_SRC_DIR ${uvw_SOURCE_DIR}/src)
|
||||||
|
|
||||||
cmake_push_check_state()
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
#
|
||||||
|
# Referenced packages
|
||||||
|
#
|
||||||
|
|
||||||
check_cxx_source_compiles("
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
#include<type_traits>
|
|
||||||
int main() { return std::is_same_v<int, char>; }
|
|
||||||
" UVW_HAS_LIBCPP)
|
|
||||||
|
|
||||||
if(NOT UVW_HAS_LIBCPP)
|
include(FindThreads)
|
||||||
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.")
|
find_package(Doxygen 1.8)
|
||||||
endif()
|
|
||||||
|
|
||||||
cmake_pop_check_state()
|
#
|
||||||
|
# Referenced directories and targets
|
||||||
|
#
|
||||||
|
|
||||||
|
if(DOXYGEN_FOUND)
|
||||||
|
add_subdirectory(docs)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UVW_USE_CLANG_TIDY)
|
if(BUILD_TESTING)
|
||||||
find_program(UVW_CLANG_TIDY_EXECUTABLE "clang-tidy")
|
set(BUILD_TESTING OFF)
|
||||||
|
|
||||||
if(NOT UVW_CLANG_TIDY_EXECUTABLE)
|
set(GOOGLETEST_DEPS_DIR ${PROJECT_DEPS_DIR}/googletest)
|
||||||
message(VERBOSE "The option UVW_USE_CLANG_TIDY is set but clang-tidy executable is not available.")
|
set(LIBUV_DEPS_DIR ${PROJECT_DEPS_DIR}/libuv)
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Required minimal libuv version
|
configure_file(${PROJECT_CMAKE_IN}/deps.in ${PROJECT_DEPS_DIR}/CMakeLists.txt)
|
||||||
set(UVW_LIBUV_VERSION 1.49.0)
|
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${PROJECT_DEPS_DIR})
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${PROJECT_DEPS_DIR})
|
||||||
|
|
||||||
function(fetch_libuv)
|
# gtest, gtest_main, gmock and gmock_main targets are available from now on
|
||||||
if (UVW_FETCH_LIBUV)
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
include(FetchContent)
|
add_subdirectory(${GOOGLETEST_DEPS_DIR})
|
||||||
|
|
||||||
FetchContent_Declare(
|
# uv and uv_a targets are available from now on
|
||||||
libuv
|
add_subdirectory(${LIBUV_DEPS_DIR})
|
||||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
include_directories(${LIBUV_DEPS_DIR}/include)
|
||||||
GIT_TAG "v${UVW_LIBUV_VERSION}"
|
|
||||||
GIT_SHALLOW 1
|
|
||||||
)
|
|
||||||
|
|
||||||
FetchContent_GetProperties(libuv)
|
set(BUILD_TESTING ON)
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
if(NOT libuv_POPULATED)
|
add_subdirectory(test)
|
||||||
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()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Install targets
|
# Keep your stuff and go further away, foolish.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
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 ${CMAKE_INSTALL_INCLUDEDIR}/uvw
|
DESTINATION ${INCLUDE_INSTALL_DIR}/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 ${CMAKE_INSTALL_INCLUDEDIR}
|
DESTINATION ${INCLUDE_INSTALL_DIR}
|
||||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Install targets
|
# AOB
|
||||||
#
|
#
|
||||||
|
|
||||||
if (UVW_BUILD_LIBS)
|
add_custom_target(
|
||||||
set_target_properties(
|
uvw_aob
|
||||||
uvw PROPERTIES
|
SOURCES
|
||||||
VERSION ${UVW_VERSION_MAJOR}.${UVW_VERSION_MINOR}.${UVW_VERSION_PATCH}
|
appveyor.yml
|
||||||
SOVERSION ${UVW_VERSION_MAJOR}
|
AUTHORS
|
||||||
)
|
LICENSE
|
||||||
endif()
|
README.md
|
||||||
|
.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()
|
|
||||||
|
|||||||
@ -1,59 +0,0 @@
|
|||||||
{
|
|
||||||
"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-2024 Michele Caini
|
Copyright (c) 2016-2018 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,34 +1,27 @@
|
|||||||

|

|
||||||
|
|
||||||
[](https://github.com/skypjack/uvw/actions)
|
<!--
|
||||||
[](https://codecov.io/gh/skypjack/uvw)
|
@cond TURN_OFF_DOXYGEN
|
||||||
[](https://skypjack.github.io/uvw/)
|
-->
|
||||||
[](https://vcpkg.link/ports/uvw)
|
[](https://travis-ci.org/skypjack/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.me/skypjack)
|
[](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)
|
||||||
|
|
||||||
Do you have a **question** that doesn't require you to open an issue? Join the
|
[](https://www.patreon.com/bePatron?u=11330786)
|
||||||
[gitter channel](https://gitter.im/skypjack/uvw).<br/>
|
|
||||||
If you use `uvw` and you want to say thanks or support the project, please
|
<!--
|
||||||
**consider becoming a
|
@endcond TURN_OFF_DOXYGEN
|
||||||
[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` started as a header-only, event based, tiny and easy to use wrapper for
|
`uvw` is a header-only, event based, tiny and easy to use *libuv* wrapper in modern C++.<br/>
|
||||||
[`libuv`](https://github.com/libuv/libuv) written in modern C++.<br/>
|
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/>
|
||||||
Now it's finally available also as a compilable static library.
|
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/>
|
||||||
|
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
|
||||||
|
|
||||||
@ -36,15 +29,15 @@ closed once it is no longer in use.
|
|||||||
#include <uvw.hpp>
|
#include <uvw.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
void listen(uvw::loop &loop) {
|
void listen(uvw::Loop &loop) {
|
||||||
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
|
std::shared_ptr<uvw::TCPHandle> tcp = loop.resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
|
||||||
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
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();
|
||||||
});
|
});
|
||||||
@ -53,12 +46,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::tcp_handle>();
|
auto tcp = loop.resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
|
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* handle errors */ });
|
||||||
|
|
||||||
tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
|
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &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();
|
||||||
@ -68,7 +61,7 @@ void conn(uvw::loop &loop) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
auto loop = uvw::loop::get_default();
|
auto loop = uvw::Loop::getDefault();
|
||||||
listen(*loop);
|
listen(*loop);
|
||||||
conn(*loop);
|
conn(*loop);
|
||||||
loop->run();
|
loop->run();
|
||||||
@ -77,8 +70,7 @@ int main() {
|
|||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
The main reason for which `uvw` has been written is the fact that there does not
|
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.
|
||||||
exist a valid `libuv` wrapper in C++. That's all.
|
|
||||||
|
|
||||||
# Build Instructions
|
# Build Instructions
|
||||||
|
|
||||||
@ -86,130 +78,79 @@ exist a valid `libuv` wrapper in C++. That's all.
|
|||||||
|
|
||||||
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++17.
|
* A full-featured compiler that supports at least C++11.
|
||||||
* `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
|
The requirements below are mandatory to compile the tests and to extract the documentation:
|
||||||
documentation:
|
|
||||||
|
|
||||||
* CMake version 3.13 or later.
|
* CMake version 3.2 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 may be cloned
|
Note that `libuv` is part of the dependencies of the project and it will be cloned by `cmake` (see below for further details).<br/>
|
||||||
by `CMake` in some cases (see below for further details).<br/>
|
Because of that, users have not to install it to compile and execute the tests.
|
||||||
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 dual-mode library. It can be used in its header-only form or as a
|
`uvw` is a header-only library.<br/>
|
||||||
compiled static library.<br/>
|
This means that including the `uvw.hpp` header or one of the other `uvw/*.hpp` headers is enough to use it.<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
|
Then pass the proper `-I` argument to the compiler to add the `src` directory to the include paths.<br/>
|
||||||
the include paths.<br/>
|
Note that users are demanded to correctly setup include directories and libraries search paths for *libuv*.
|
||||||
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
|
Starting with tag _v1.12.0_ of `libuv`, `uvw` follows the [semantic versioning](http://semver.org/) scheme.<br/>
|
||||||
[semantic versioning](http://semver.org/) scheme.<br/>
|
The problem is that any version of `uvw` also requires to track explicitly the version of `libuv` to which it is bound.<br/>
|
||||||
The problem is that any version of `uvw` also requires to track explicitly the
|
Because of that, the latter wil be appended to the version of `uvw`. As an example:
|
||||||
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
|
* _X.Y_ is the version of `libuv` to which to refer (where any patch version is valid).
|
||||||
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
|
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/>
|
||||||
_v1.x_ of `libuv` (at least as long as it remains their _master_ branch).<br/>
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The documentation is based on
|
The documentation is based on [`doxygen`](http://www.stack.nl/~dimitri/doxygen/). To build it:
|
||||||
[`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
|
The API reference will be created in HTML format within the directory `build/docs/html`.<br/>
|
||||||
`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 same version is also available [online](https://skypjack.github.io/uvw/)
|
The API reference is also available [online](https://skypjack.github.io/uvw/) for the latest version.
|
||||||
for the latest release, that is the last stable tag.
|
|
||||||
|
|
||||||
### Note
|
### Note
|
||||||
|
|
||||||
The documentation is mostly inspired by the official
|
The documentation is mostly inspired by the official [libuv API documentation](http://docs.libuv.org/en/v1.x/) for obvious reasons.<br/>
|
||||||
[libuv API documentation](http://docs.libuv.org/en/v1.x/) for obvious
|
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.
|
||||||
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 compiling anything
|
`cmake` will download and compile both the libraries before to compile anything else.
|
||||||
else.
|
|
||||||
|
|
||||||
To build the tests:
|
To build the tests:
|
||||||
|
|
||||||
* `$ cd build`
|
* `$ cd build`
|
||||||
* `$ cmake .. -DUVW_BUILD_TESTING=ON`
|
* `$ cmake .. -DBUILD_TESTING=ON`
|
||||||
* `$ make`
|
* `$ make`
|
||||||
* `$ ctest -j4 -R uvw`
|
* `$ ctest -j4 -R uvw`
|
||||||
|
|
||||||
@ -219,83 +160,63 @@ 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
|
There is only one rule when using `uvw`: always initialize the resources and terminate them.
|
||||||
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
|
Handles represent long-lived objects capable of performing certain operations while active.<br/>
|
||||||
while active.<br/>
|
Requests represent (typically) short-lived operations performed either over a handle or standalone.
|
||||||
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
|
The following sections will explain in short what it means to initialize and terminate these kinds of resources.<br/>
|
||||||
terminate these kinds of resources.<br/>
|
For more details, please refer to the [online documentation](https://skypjack.github.io/uvw/).
|
||||||
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,
|
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/>
|
||||||
as far as handles are created using the `loop::resource` member function.<br/>
|
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/>
|
||||||
On the other side, handles keep themselves alive until one explicitly closes
|
Therefore the rule quickly becomes *always close your handles*. It's as simple as calling the `close` member function on them.
|
||||||
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
|
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/>
|
||||||
way to create a request is still through the `loop::resource` member
|
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/>
|
||||||
function.<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.
|
||||||
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
|
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:
|
||||||
is enough, it's easy as doing this:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto loop = uvw::loop::get_default();
|
auto loop = uvw::Loop::getDefault();
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that loop objects don't require being closed explicitly, even if they offer
|
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/>
|
||||||
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:
|
||||||
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::run_mode::DEFAULT);
|
loop->run<uvw::Loop::Mode::DEFAULT>();
|
||||||
```
|
```
|
||||||
|
|
||||||
Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the
|
Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the documentation of *libuv* for further details.
|
||||||
documentation of `libuv` for further details.
|
|
||||||
|
|
||||||
In order to create a resource and to bind it to the given loop, just do the
|
In order to create a resource and to bind it to the given loop, just do the following:
|
||||||
following:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto tcp = loop->resource<uvw::tcp_handle>();
|
auto tcp = loop.resource<uvw::TCPHandle>();
|
||||||
```
|
```
|
||||||
|
|
||||||
The line above creates and initializes a tcp handle, then a shared pointer to
|
The line above will create and initialize a tcp handle, then a shared pointer to that resource will be returned.<br/>
|
||||||
that resource is returned.<br/>
|
Users should check if pointers have been correctly initialized: in case of errors, they won't be.<br/>
|
||||||
Users should check if pointers have been correctly initialized: in case of
|
Another way to create a resource is:
|
||||||
errors, they won't be.<br/>
|
|
||||||
It also is possible to create uninitialized resources to init later on as:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
auto tcp = loop->uninitialized_resource<uvw::tcp_handle>();
|
auto tcp = TCPHandle::create(loop);
|
||||||
tcp->init();
|
tcp->init();
|
||||||
```
|
```
|
||||||
|
|
||||||
All resources also accept arbitrary user-data that won't be touched in any
|
Pretty annoying indeed. Using a loop is the recommended approach.
|
||||||
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
|
||||||
@ -303,86 +224,73 @@ 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
|
Resources expect a `std::shared_pointer<void>` and return it, therefore any kind of data is welcome.<br/>
|
||||||
of data is welcome.<br/>
|
Users can explicitly specify a type other than `void` when calling the `data` member function:
|
||||||
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
|
Remember from the previous section that a handle will keep itself alive until one invokes the `close` member function on it.<br/>
|
||||||
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, just do the following:
|
||||||
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
|
||||||
handle.parent().walk(uvw::overloaded{
|
loop.walk([](uvw::BaseHandle &){ /* application code here */ });
|
||||||
[](uvw::timer_handle &h){ /* application code for timers here */ },
|
|
||||||
[](auto &&){ /* ignore all other types */ }
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This function can also be used for a completely generic approach. For example,
|
`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/>
|
||||||
all the pending handles can be closed easily as it follows:
|
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:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
loop->walk([](auto &&h){ h.close(); });
|
loop.walk([](uvw::BaseHandle &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
|
||||||
|
|
||||||
`uvw` offers an event-based approach where resources are small event emitters to
|
For `uvw` offers an event-based approach, resources are small event emitters to which listeners can be attached.<br/>
|
||||||
which listeners are attached.<br/>
|
Attaching a listener to a resource is the recommended way to be notified about changes.<br/>
|
||||||
Attaching listeners to resources is the recommended way to receive notifications
|
Listeners must be callable objects of type `void(EventType &, ResourceType &)`, where:
|
||||||
about their operations.<br/>
|
|
||||||
Listeners are callable objects of type `void(event_type &, resource_type &)`,
|
|
||||||
where:
|
|
||||||
|
|
||||||
* `event_type` is the type of the event for which they have been designed.
|
* `EventType` is the type of the event for which they have been designed.
|
||||||
* `resource_type` is the type of the resource that has originated the event.
|
* `ResourceType` 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(event_type &, resource_type &)`
|
* `void(EventType &, ResourceType &)`
|
||||||
* `void(const event_type &, resource_type &)`
|
* `void(const EventType &, ResourceType &)`
|
||||||
* `void(event_type &, const resource_type &)`
|
* `void(EventType &, const ResourceType &)`
|
||||||
* `void(const event_type &, const resource_type &)`
|
* `void(const EventType &, const ResourceType &)`
|
||||||
|
|
||||||
Please note that there is no need to keep around references to the resources,
|
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.
|
||||||
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:
|
|
||||||
|
|
||||||
```cpp
|
There exist two methods to attach an event to a resource:
|
||||||
resource.on<event_type>(listener)
|
|
||||||
```
|
|
||||||
|
|
||||||
To know if a listener exists for a given type, the class offers a `has` function
|
* `resource.once<EventType>(listener)`: the listener will be automatically removed after the first event of the given type.
|
||||||
template. Similarly, the `reset` function template is be used to reset and thus
|
* `resource.on<EventType>(listener)`: to be used for long-running listeners.
|
||||||
disconnect listeners, if any. A non-template version of `reset` also exists to
|
|
||||||
clear an emitter as a whole.
|
|
||||||
|
|
||||||
Almost all the resources emit `error_event` in case of errors.<br/>
|
Both of them return an object of type `ResourceType::Connection` (as an example, `TCPHandle::Connection`).<br/>
|
||||||
All the other events are specific for the given resource and documented in the
|
A connection object can be used later as an argument to the `erase` member function of the resource to remove the listener.<br/>
|
||||||
API reference.
|
There exists also the `clear` member function to drop all the listeners at once.
|
||||||
|
|
||||||
|
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::get_default();
|
auto loop = uvw::Loop::getDefault();
|
||||||
auto tcp = loop->resource<uvw::tcp_handle>();
|
auto tcp = loop.resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* something went wrong */ });
|
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TCPHandle &) { /* something went wrong */ });
|
||||||
|
|
||||||
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
tcp->on<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
|
||||||
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
|
||||||
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
client->once<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { client.close(); });
|
||||||
client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data received */ });
|
client->on<uvw::DataEvent>([](const uvw::DataEvent &, uvw::TCPHandle &) { /* data received */ });
|
||||||
srv.accept(*client);
|
srv.accept(*client);
|
||||||
client->read();
|
client->read();
|
||||||
});
|
});
|
||||||
@ -391,9 +299,10 @@ tcp->bind("127.0.0.1", 4242);
|
|||||||
tcp->listen();
|
tcp->listen();
|
||||||
```
|
```
|
||||||
|
|
||||||
Note also that `uvw::tcp_handle` already supports _IPv6_ out-of-the-box.<br/>
|
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/>
|
||||||
The API reference is the recommended documentation for further details about
|
It's suffice to explicitly specify `uvw::IPv6` as the underlying protocol to use it.
|
||||||
resources and their methods.
|
|
||||||
|
The API reference is the recommended documentation for further details about resources and their methods.
|
||||||
|
|
||||||
## Going raw
|
## Going raw
|
||||||
|
|
||||||
@ -403,14 +312,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 controlled by the library and working around it could quickly break
|
completely in charge to 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::get_default();
|
auto loop = uvw::Loop::getDefault();
|
||||||
auto tcp = loop->resource<uvw::tcp_handle>();
|
auto tcp = loop.resource<uvw::TCPHandle>();
|
||||||
|
|
||||||
uv_loop_t *raw = loop->raw();
|
uv_loop_t *raw = loop->raw();
|
||||||
uv_tcp_t *handle = tcp->raw();
|
uv_tcp_t *handle = tcp->raw();
|
||||||
@ -418,39 +327,51 @@ 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
|
If you want to contribute, please send patches as pull requests against the branch master.<br/>
|
||||||
branch master.<br/>
|
Check the [contributors list](https://github.com/skypjack/uvw/blob/master/AUTHORS) to see who has partecipated so far.
|
||||||
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-2024 Michele Caini.<br/>
|
Code and documentation Copyright (c) 2016-2018 Michele Caini.<br/>
|
||||||
Logo Copyright (c) 2018-2021 Richard Caseres.
|
Logo Copyright (c) 2018 Richard Caseres.
|
||||||
|
|
||||||
Code and documentation released under
|
Code released under
|
||||||
[the MIT license](https://github.com/skypjack/uvw/blob/master/LICENSE).<br/>
|
[the MIT license](https://github.com/skypjack/uvw/blob/master/LICENSE).
|
||||||
|
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
|
||||||
|
|
||||||
If you want to support this project, you can
|
## Patreon
|
||||||
[offer me](https://github.com/users/skypjack/sponsorship) an espresso.<br/>
|
|
||||||
If you find that it's not enough, feel free to
|
Become a [patron](https://www.patreon.com/bePatron?c=1772573) and get access to
|
||||||
[help me](https://www.paypal.me/skypjack) the way you prefer.
|
extra content, help me spend more time on the projects you love and create new
|
||||||
|
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
5
TODO
@ -1,5 +0,0 @@
|
|||||||
* 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
Normal file
22
appveyor.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 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
|
||||||
26
cmake/in/deps.in
Normal file
26
cmake/in/deps.in
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
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.49.0@bincrafters/stable"
|
requires = "libuv/1.23.2@bincrafters/stable"
|
||||||
|
|
||||||
def package(self):
|
def package(self):
|
||||||
self.copy(pattern="LICENSE", dst="licenses")
|
self.copy(pattern="LICENSE", dst="licenses")
|
||||||
|
|||||||
1
subprojects/.gitignore → deps/.gitignore
vendored
1
subprojects/.gitignore → deps/.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
*
|
*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
!*.wrap
|
|
||||||
@ -2,19 +2,23 @@
|
|||||||
# Doxygen configuration (documentation)
|
# Doxygen configuration (documentation)
|
||||||
#
|
#
|
||||||
|
|
||||||
set(DOXY_DEPS_DIRECTORY ${uvw_SOURCE_DIR}/deps)
|
set(TARGET_DOCS docs)
|
||||||
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 doxy.cfg @ONLY)
|
configure_file(${DOXY_IN_FILE} ${DOXY_CFG_FILE} @ONLY)
|
||||||
|
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
docs ALL
|
${TARGET_DOCS}
|
||||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
|
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/${DOXY_CFG_FILE}
|
||||||
WORKING_DIRECTORY ${uvw_SOURCE_DIR}
|
WORKING_DIRECTORY ${uvw_SOURCE_DIR}
|
||||||
VERBATIM
|
VERBATIM
|
||||||
SOURCES doxy.in
|
SOURCES ${DOXY_IN_FILE}
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
|||||||
1063
docs/doxy.in
1063
docs/doxy.in
File diff suppressed because it is too large
Load Diff
54
meson.build
54
meson.build
@ -1,54 +0,0 @@
|
|||||||
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
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
#
|
|
||||||
# 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,28 +1,21 @@
|
|||||||
#include "uvw/async.h"
|
#include "uvw/async.hpp"
|
||||||
#include "uvw/check.h"
|
#include "uvw/check.hpp"
|
||||||
#include "uvw/config.h"
|
#include "uvw/dns.hpp"
|
||||||
#include "uvw/dns.h"
|
#include "uvw/fs.hpp"
|
||||||
#include "uvw/emitter.h"
|
#include "uvw/fs_event.hpp"
|
||||||
#include "uvw/enum.hpp"
|
#include "uvw/fs_poll.hpp"
|
||||||
#include "uvw/fs.h"
|
#include "uvw/idle.hpp"
|
||||||
#include "uvw/fs_event.h"
|
#include "uvw/lib.hpp"
|
||||||
#include "uvw/fs_poll.h"
|
#include "uvw/loop.hpp"
|
||||||
#include "uvw/handle.hpp"
|
#include "uvw/pipe.hpp"
|
||||||
#include "uvw/idle.h"
|
#include "uvw/poll.hpp"
|
||||||
#include "uvw/lib.h"
|
#include "uvw/prepare.hpp"
|
||||||
#include "uvw/loop.h"
|
#include "uvw/process.hpp"
|
||||||
#include "uvw/pipe.h"
|
#include "uvw/signal.hpp"
|
||||||
#include "uvw/poll.h"
|
#include "uvw/tcp.hpp"
|
||||||
#include "uvw/prepare.h"
|
#include "uvw/thread.hpp"
|
||||||
#include "uvw/process.h"
|
#include "uvw/timer.hpp"
|
||||||
#include "uvw/request.hpp"
|
#include "uvw/tty.hpp"
|
||||||
#include "uvw/resource.hpp"
|
#include "uvw/udp.hpp"
|
||||||
#include "uvw/signal.h"
|
#include "uvw/util.hpp"
|
||||||
#include "uvw/tcp.h"
|
#include "uvw/work.hpp"
|
||||||
#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"
|
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
#include "async.h"
|
|
||||||
#include "async.ipp"
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
#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
|
|
||||||
67
src/uvw/async.hpp
Normal file
67
src/uvw/async.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,18 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "check.h"
|
|
||||||
#include "check.ipp"
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
#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
|
|
||||||
66
src/uvw/check.hpp
Normal file
66
src/uvw/check.hpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#ifndef UVW_CONFIG_H
|
|
||||||
#define UVW_CONFIG_H
|
|
||||||
|
|
||||||
#ifndef UVW_AS_LIB
|
|
||||||
# define UVW_INLINE inline
|
|
||||||
#else
|
|
||||||
# define UVW_INLINE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "dns.h"
|
|
||||||
#include "dns.ipp"
|
|
||||||
@ -1,21 +1,29 @@
|
|||||||
#ifndef UVW_DNS_INCLUDE_H
|
#pragma once
|
||||||
#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.h"
|
#include "util.hpp"
|
||||||
|
#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`.
|
||||||
@ -23,12 +31,19 @@ struct addr_info_event {
|
|||||||
* 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 {
|
/**
|
||||||
name_info_event(const char *host, const char *serv);
|
* @brief NameInfoEvent event.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
@ -36,7 +51,7 @@ struct name_info_event {
|
|||||||
* 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.
|
||||||
@ -44,35 +59,57 @@ struct name_info_event {
|
|||||||
* 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 getaddrinfo request.
|
* @brief The GetAddrInfoReq 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 `get_addr_info_req` through a `loop`, no arguments are required.
|
* To create a `GetAddrInfoReq` through a `Loop`, no arguments are required.
|
||||||
*/
|
*/
|
||||||
class get_addr_info_req final: public request<get_addr_info_req, uv_getaddrinfo_t, addr_info_event> {
|
class GetAddrInfoReq final: public Request<GetAddrInfoReq, uv_getaddrinfo_t> {
|
||||||
static void addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res);
|
static void addrInfoCallback(uv_getaddrinfo_t *req, int status, addrinfo *res) {
|
||||||
int node_addr_info(const char *node, const char *service, addrinfo *hints = nullptr);
|
auto ptr = reserve(req);
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
int node_addr_info(const std::string &node, addrinfo *hints = nullptr);
|
void nodeAddrInfo(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).
|
||||||
@ -83,18 +120,22 @@ 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>> node_addr_info_sync(const std::string &node, addrinfo *hints = nullptr);
|
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
||||||
|
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.
|
|
||||||
*/
|
*/
|
||||||
int service_addr_info(const std::string &service, addrinfo *hints = nullptr);
|
void serviceAddrInfo(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).
|
||||||
@ -105,9 +146,12 @@ 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>> service_addr_info_sync(const std::string &service, addrinfo *hints = nullptr);
|
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
||||||
|
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).
|
||||||
@ -115,9 +159,10 @@ 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.
|
|
||||||
*/
|
*/
|
||||||
int addr_info(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
|
void addrInfo(std::string node, 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).
|
||||||
@ -129,49 +174,64 @@ 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>> addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
|
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
||||||
|
addrInfoSync(std::string node, std::string service, addrinfo *hints = nullptr) {
|
||||||
|
return nodeAddrInfoSync(node.data(), service.data(), hints);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The getnameinfo request.
|
* @brief The GetNameInfoReq 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 `get_name_info_req` through a `loop`, no arguments are required.
|
* To create a `GetNameInfoReq` through a `Loop`, no arguments are required.
|
||||||
*/
|
*/
|
||||||
class get_name_info_req final: public request<get_name_info_req, uv_getnameinfo_t, name_info_event> {
|
class GetNameInfoReq final: public Request<GetNameInfoReq, uv_getnameinfo_t> {
|
||||||
static void name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service);
|
static void nameInfoCallback(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.
|
|
||||||
*/
|
*/
|
||||||
int name_info(const sockaddr &addr, int flags = 0);
|
void nameInfo(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.
|
|
||||||
*/
|
*/
|
||||||
int name_info(const std::string &ip, unsigned int port, int flags = 0);
|
template<typename I = IPv4>
|
||||||
|
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 socket_address.
|
* @param addr A valid instance of Addr.
|
||||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||||
* @return Underlying return value.
|
|
||||||
*/
|
*/
|
||||||
int name_info(const socket_address &addr, int flags = 0);
|
template<typename I = IPv4>
|
||||||
|
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).
|
||||||
@ -185,7 +245,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.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const sockaddr &addr, int flags = 0);
|
std::pair<bool, std::pair<const char *, const char *>>
|
||||||
|
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).
|
||||||
@ -200,12 +265,18 @@ 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 *>> name_info_sync(const std::string &ip, unsigned int port, int flags = 0);
|
template<typename I = IPv4>
|
||||||
|
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 socket_address.
|
* @param addr A valid instance of Addr.
|
||||||
* @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:
|
||||||
@ -214,13 +285,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.
|
||||||
*/
|
*/
|
||||||
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const socket_address &addr, int flags = 0);
|
template<typename I = IPv4>
|
||||||
|
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
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "emitter.h"
|
|
||||||
#include "emitter.ipp"
|
|
||||||
@ -1,159 +0,0 @@
|
|||||||
#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
|
|
||||||
318
src/uvw/emitter.hpp
Normal file
318
src/uvw/emitter.hpp
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
#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{};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,25 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "fs.h"
|
|
||||||
#include "fs.ipp"
|
|
||||||
1235
src/uvw/fs.h
1235
src/uvw/fs.h
File diff suppressed because it is too large
Load Diff
1448
src/uvw/fs.hpp
Normal file
1448
src/uvw/fs.hpp
Normal file
File diff suppressed because it is too large
Load Diff
550
src/uvw/fs.ipp
550
src/uvw/fs.ipp
@ -1,550 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "fs_event.h"
|
|
||||||
#include "fs_event.ipp"
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
#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
|
|
||||||
158
src/uvw/fs_event.hpp
Normal file
158
src/uvw/fs_event.hpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "fs_poll.h"
|
|
||||||
#include "fs_poll.ipp"
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
#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
|
|
||||||
91
src/uvw/fs_poll.hpp
Normal file
91
src/uvw/fs_poll.hpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,32 +0,0 @@
|
|||||||
#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,44 +1,70 @@
|
|||||||
#ifndef UVW_HANDLE_INCLUDE_H
|
#pragma once
|
||||||
#define UVW_HANDLE_INCLUDE_H
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
#include "config.h"
|
|
||||||
#include "resource.hpp"
|
#include "resource.hpp"
|
||||||
#include "util.h"
|
#include "util.hpp"
|
||||||
|
|
||||||
|
|
||||||
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, typename... E>
|
template<typename T, typename U>
|
||||||
class handle: public resource<T, U, close_event, E...> {
|
class Handle: public BaseHandle, public Resource<T, U>
|
||||||
|
{
|
||||||
|
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 close_callback(uv_handle_t *hndl) {
|
static void allocCallback(uv_handle_t *, std::size_t suggested, uv_buf_t *buf) {
|
||||||
handle<T, U, E...> &ref = *(static_cast<T *>(hndl->data));
|
auto size = static_cast<unsigned int>(suggested);
|
||||||
[[maybe_unused]] auto ptr = ref.shared_from_this();
|
*buf = uv_buf_init(new char[size], size);
|
||||||
ref.self_reset();
|
|
||||||
ref.publish(close_event{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uv_handle_t *as_uv_handle() {
|
template<typename F, typename... Args>
|
||||||
return reinterpret_cast<uv_handle_t *>(this->raw());
|
bool initialize(F &&f, Args&&... args) {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const uv_handle_t *as_uv_handle() const {
|
template<typename F, typename... Args>
|
||||||
return reinterpret_cast<const uv_handle_t *>(this->raw());
|
void invoke(F &&f, Args&&... args) {
|
||||||
|
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
||||||
|
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using resource<T, U, close_event, E...>::resource;
|
using Resource<T, U>::Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the category of the handle.
|
* @brief Gets the category of the handle.
|
||||||
@ -49,8 +75,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The actual category of the handle.
|
* @return The actual category of the handle.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] handle_category category() const noexcept {
|
HandleCategory category() const noexcept override {
|
||||||
return handle_category{as_uv_handle()->type};
|
return HandleCategory{this->template get<uv_handle_t>()->type};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,12 +84,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 handle_type is made available to the users.
|
* specified by HandleType is made available to the users.
|
||||||
*
|
*
|
||||||
* @return The actual type of the handle.
|
* @return The actual type of the handle.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] handle_type type() const noexcept {
|
HandleType type() const noexcept override {
|
||||||
return utilities::guess_handle(category());
|
return Utilities::guessHandle(category());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,22 +97,22 @@ public:
|
|||||||
*
|
*
|
||||||
* What _active_ means depends on the type of handle:
|
* What _active_ means depends on the type of handle:
|
||||||
*
|
*
|
||||||
* * An async_handle handle is always active and cannot be deactivated,
|
* * An AsyncHandle handle is always active and cannot be deactivated,
|
||||||
* except by closing it with uv_close().
|
* except by closing it with uv_close().
|
||||||
* * A pipe, tcp, udp, etc. handle - basically any handle that deals with
|
* * A PipeHandle, TCPHandle, UDPHandle, etc. handle - basically any handle
|
||||||
* I/O - is active when it is doing something that involves I/O, like
|
* that deals with I/O - is active when it is doing something that involves
|
||||||
* reading, writing, connecting, accepting new connections, etc.
|
* I/O, like reading, writing, connecting, accepting new connections, etc.
|
||||||
* * A check, idle, timer, etc. handle is active when it has been started
|
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
|
||||||
* with a call to `start()`.
|
* has been started with a call to `start()`.
|
||||||
*
|
*
|
||||||
* Rule of thumb: if a handle of type `foo_handle` has a `start()` member
|
* 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,
|
* 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.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] bool active() const noexcept {
|
bool active() const noexcept override {
|
||||||
return !!uv_is_active(as_uv_handle());
|
return !(uv_is_active(this->template get<uv_handle_t>()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,21 +123,22 @@ public:
|
|||||||
*
|
*
|
||||||
* @return True if the handle is closing or closed, false otherwise.
|
* @return True if the handle is closing or closed, false otherwise.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] bool closing() const noexcept {
|
bool closing() const noexcept override {
|
||||||
return !!uv_is_closing(as_uv_handle());
|
return !(uv_is_closing(this->template get<uv_handle_t>()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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 errors.
|
* In-progress requests are cancelled and this can result in an ErrorEvent
|
||||||
|
* emitted.
|
||||||
*
|
*
|
||||||
* The handle will emit a close event when finished.
|
* The handle will emit a CloseEvent when finished.
|
||||||
*/
|
*/
|
||||||
void close() noexcept {
|
void close() noexcept override {
|
||||||
if(!closing()) {
|
if(!closing()) {
|
||||||
uv_close(as_uv_handle(), &handle<T, U, E...>::close_callback);
|
uv_close(this->template get<uv_handle_t>(), &Handle<T, U>::closeCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,8 +148,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 {
|
void reference() noexcept override {
|
||||||
uv_ref(as_uv_handle());
|
uv_ref(this->template get<uv_handle_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,24 +158,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 {
|
void unreference() noexcept override {
|
||||||
uv_unref(as_uv_handle());
|
uv_unref(this->template get<uv_handle_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] bool referenced() const noexcept {
|
bool referenced() const noexcept override {
|
||||||
return !!uv_has_ref(as_uv_handle());
|
return !(uv_has_ref(this->template get<uv_handle_t>()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::size_t size() const noexcept {
|
std::size_t size() const noexcept {
|
||||||
return uv_handle_size(as_uv_handle()->type);
|
return uv_handle_size(this->template get<uv_handle_t>()->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,17 +183,16 @@ 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 tcp, pipeand udp handles on Unix and for tcp and
|
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
||||||
* udp handles on Windows.<br/>
|
* Unix and for TCPHandle and UDPHandle 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, the underlying return value in case
|
* @return The size of the send buffer, 0 in case of errors.
|
||||||
* of errors.
|
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int send_buffer_size() {
|
int sendBufferSize() {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
auto err = uv_send_buffer_size(as_uv_handle(), &value);
|
auto err = uv_send_buffer_size(this->template get<uv_handle_t>(), &value);
|
||||||
return err ? err : value;
|
return err ? 0 : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,14 +200,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 tcp, pipe and udp handles on Unix and for tcp and
|
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
||||||
* udp handles on Windows.<br/>
|
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
|
||||||
* Note that Linux will set double the size.
|
* Note that Linux will set double the size.
|
||||||
*
|
*
|
||||||
* @return Underlying return value.
|
* @return True in case of success, false otherwise.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int send_buffer_size(int value) {
|
bool sendBufferSize(int value) {
|
||||||
return uv_send_buffer_size(as_uv_handle(), &value);
|
return (0 == uv_send_buffer_size(this->template get<uv_handle_t>(), &value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,17 +215,16 @@ 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 tcp, pipe and udp handles on Unix and for tcp and
|
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
||||||
* udp handles on Windows.<br/>
|
* Unix and for TCPHandle and UDPHandle 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, the underlying return value in
|
* @return The size of the receive buffer, 0 in case of errors.
|
||||||
* case of errors.
|
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int recv_buffer_size() {
|
int recvBufferSize() {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
auto err = uv_recv_buffer_size(as_uv_handle(), &value);
|
auto err = uv_recv_buffer_size(this->template get<uv_handle_t>(), &value);
|
||||||
return err ? err : value;
|
return err ? 0 : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,14 +232,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 tcp, pipe and udp handles on Unix and for tcp and
|
* This function works for TCPHandle, PipeHandle and UDPHandle handles on
|
||||||
* udp handles on Windows.<br/>
|
* Unix and for TCPHandle and UDPHandle handles on Windows.<br/>
|
||||||
* Note that Linux will set double the size.
|
* Note that Linux will set double the size.
|
||||||
*
|
*
|
||||||
* @return Underlying return value.
|
* @return True in case of success, false otherwise.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] int recv_buffer_size(int value) {
|
bool recvBufferSize(int value) {
|
||||||
return uv_recv_buffer_size(as_uv_handle(), &value);
|
return (0 == uv_recv_buffer_size(this->template get<uv_handle_t>(), &value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -222,14 +247,15 @@ public:
|
|||||||
*
|
*
|
||||||
* Supported handles:
|
* Supported handles:
|
||||||
*
|
*
|
||||||
* * tcp_handle
|
* * TCPHandle
|
||||||
* * pipe_handle
|
* * PipeHandle
|
||||||
* * tty_handle
|
* * TTYHandle
|
||||||
* * udp_handle
|
* * UDPHandle
|
||||||
* * poll_handle
|
* * PollHandle
|
||||||
*
|
*
|
||||||
* If invoked on a different handle, one that doesn’t have an attached file
|
* It will emit an ErrorEvent event if invoked on any other handle.<br/>
|
||||||
* descriptor yet or one which was closed, an invalid value is returned.
|
* If a handle doesn’t have an attached file descriptor yet or the handle
|
||||||
|
* 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)
|
||||||
@ -238,13 +264,12 @@ 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.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] os_file_descriptor fd() const {
|
OSFileDescriptor fileno() const {
|
||||||
uv_os_fd_t fd;
|
uv_os_fd_t fd;
|
||||||
uv_fileno(as_uv_handle(), &fd);
|
uv_fileno(this->template get<uv_handle_t>(), &fd);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace uvw
|
|
||||||
|
|
||||||
#endif // UVW_HANDLE_INCLUDE_H
|
}
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
#include "idle.h"
|
|
||||||
#include "idle.ipp"
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
#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
|
|
||||||
74
src/uvw/idle.hpp
Normal file
74
src/uvw/idle.hpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "lib.h"
|
|
||||||
#include "lib.ipp"
|
|
||||||
@ -1,33 +1,41 @@
|
|||||||
#ifndef UVW_LIB_INCLUDE_H
|
#pragma once
|
||||||
#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 "config.h"
|
#include "loop.hpp"
|
||||||
#include "loop.h"
|
#include "underlying_type.hpp"
|
||||||
#include "uv_type.hpp"
|
|
||||||
|
|
||||||
namespace uvw {
|
namespace uvw {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The shared lib class.
|
* @brief The SharedLib 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 shared_lib final: public uv_type<uv_lib_t> {
|
class SharedLib final: public UnderlyingType<SharedLib, uv_lib_t> {
|
||||||
public:
|
public:
|
||||||
explicit shared_lib(loop::token token, std::shared_ptr<loop> ref, const std::string &filename) noexcept;
|
explicit SharedLib(ConstructorAccess ca, std::shared_ptr<Loop> ref, std::string filename) noexcept
|
||||||
|
: UnderlyingType{ca, std::move(ref)}
|
||||||
|
{
|
||||||
|
opened = (0 == uv_dlopen(filename.data(), get()));
|
||||||
|
}
|
||||||
|
|
||||||
~shared_lib() noexcept;
|
~SharedLib() 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;
|
explicit operator bool() const noexcept { return opened; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves a data pointer from a dynamic library.
|
* @brief Retrieves a data pointer from a dynamic library.
|
||||||
@ -39,13 +47,11 @@ 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(const std::string &name) {
|
F * sym(std::string name) {
|
||||||
static_assert(std::is_function_v<F>);
|
static_assert(std::is_function<F>::value, "!");
|
||||||
F *func;
|
F *func;
|
||||||
auto err = uv_dlsym(raw(), name.data(), reinterpret_cast<void **>(&func));
|
auto err = uv_dlsym(get(), name.data(), reinterpret_cast<void**>(&func));
|
||||||
if(err) {
|
if(err) { func = nullptr; }
|
||||||
func = nullptr;
|
|
||||||
}
|
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,16 +59,13 @@ 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.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] const char *error() const noexcept;
|
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
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "loop.h"
|
|
||||||
#include "loop.ipp"
|
|
||||||
439
src/uvw/loop.h
439
src/uvw/loop.h
@ -1,439 +0,0 @@
|
|||||||
#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
Normal file
496
src/uvw/loop.hpp
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
#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
116
src/uvw/loop.ipp
@ -1,116 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "pipe.h"
|
|
||||||
#include "pipe.ipp"
|
|
||||||
@ -1,93 +1,117 @@
|
|||||||
#ifndef UVW_PIPE_INCLUDE_H
|
#pragma once
|
||||||
#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.h"
|
#include "stream.hpp"
|
||||||
#include "util.h"
|
#include "util.hpp"
|
||||||
|
#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 pipe handle.
|
* @brief The PipeHandle 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 `pipe_handle` through a `loop`, arguments follow:
|
* To create a `PipeHandle` 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 pipe_handle final: public stream_handle<pipe_handle, uv_pipe_t> {
|
class PipeHandle final: public StreamHandle<PipeHandle, uv_pipe_t> {
|
||||||
public:
|
public:
|
||||||
using chmod_flags = details::uvw_chmod_flags;
|
using Chmod = details::UVChmodFlags;
|
||||||
|
|
||||||
explicit pipe_handle(loop::token token, std::shared_ptr<loop> ref, bool pass = false);
|
explicit PipeHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool pass = false)
|
||||||
|
: StreamHandle{ca, std::move(ref)}, ipc{pass}
|
||||||
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the handle.
|
* @brief Initializes the handle.
|
||||||
* @return Underlying return value.
|
* @return True in case of success, false otherwise.
|
||||||
*/
|
*/
|
||||||
int init();
|
bool 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.
|
* it’s required that it represents a valid pipe.<br/>
|
||||||
|
* 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.
|
|
||||||
*/
|
*/
|
||||||
int open(file_handle file);
|
void open(FileHandle 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.
|
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
|
||||||
|
* 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.
|
|
||||||
*/
|
*/
|
||||||
int bind(const std::string &name, const bool no_truncate = false);
|
void bind(std::string name) {
|
||||||
|
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 connect event is emitted when the connection has been
|
* A ConnectEvent event is emitted when the connection has been
|
||||||
* established.
|
* established.<br/>
|
||||||
|
* 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.
|
|
||||||
*/
|
*/
|
||||||
int connect(const std::string &name, const bool no_truncate = false);
|
void connect(std::string name) {
|
||||||
|
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
|
||||||
@ -95,7 +119,9 @@ 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.
|
||||||
@ -106,13 +132,17 @@ 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.
|
||||||
@ -125,12 +155,15 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The type of the pending handle. Possible values are:
|
* @return The type of the pending handle. Possible values are:
|
||||||
*
|
*
|
||||||
* * `handle_type::PIPE`
|
* * `HandleType::PIPE`
|
||||||
* * `handle_type::TCP`
|
* * `HandleType::TCP`
|
||||||
* * `handle_type::UDP`
|
* * `HandleType::UDP`
|
||||||
* * `handle_type::UNKNOWN`
|
* * `HandleType::UNKNOWN`
|
||||||
*/
|
*/
|
||||||
handle_type receive() noexcept;
|
HandleType receive() noexcept {
|
||||||
|
HandleCategory category = uv_pipe_pending_type(get());
|
||||||
|
return Utilities::guessHandle(category);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Alters pipe permissions.
|
* @brief Alters pipe permissions.
|
||||||
@ -139,26 +172,23 @@ public:
|
|||||||
*
|
*
|
||||||
* Available flags are:
|
* Available flags are:
|
||||||
*
|
*
|
||||||
* * `pipe_handle::chmod_flags::READABLE`
|
* * `PipeHandle::Chmod::READABLE`
|
||||||
* * `pipe_handle::chmod_flags::WRITABLE`
|
* * `PipeHandle::Chmod::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 Underlying return value.
|
* @return True in case of success, false otherwise.
|
||||||
*/
|
*/
|
||||||
int chmod(chmod_flags flags) noexcept;
|
bool chmod(Flags<Chmod> 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
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "poll.h"
|
|
||||||
#include "poll.ipp"
|
|
||||||
119
src/uvw/poll.h
119
src/uvw/poll.h
@ -1,119 +0,0 @@
|
|||||||
#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
Normal file
159
src/uvw/poll.hpp
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,40 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "prepare.h"
|
|
||||||
#include "prepare.ipp"
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
#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
|
|
||||||
68
src/uvw/prepare.hpp
Normal file
68
src/uvw/prepare.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "process.h"
|
|
||||||
#include "process.ipp"
|
|
||||||
@ -1,245 +0,0 @@
|
|||||||
#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
|
|
||||||
319
src/uvw/process.hpp
Normal file
319
src/uvw/process.hpp
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,107 +0,0 @@
|
|||||||
#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,57 +1,75 @@
|
|||||||
#ifndef UVW_REQUEST_INCLUDE_H
|
#pragma once
|
||||||
#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 {
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Request base class.
|
template<typename T, typename U>
|
||||||
*
|
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:
|
||||||
[[nodiscard]] static auto reserve(U *req) {
|
static auto reserve(U *req) -> std::shared_ptr<T> {
|
||||||
auto ptr = static_cast<T *>(req->data)->shared_from_this();
|
auto ptr = static_cast<T*>(req->data)->shared_from_this();
|
||||||
ptr->self_reset();
|
ptr->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, E...>::resource;
|
using Resource<T, U>::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.
|
* executing.<br/>
|
||||||
*
|
* It can emit an ErrorEvent event in case of errors.
|
||||||
* See the official
|
*
|
||||||
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
|
* See the official
|
||||||
* for further details.
|
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
|
||||||
*
|
* for further details.
|
||||||
* @return Underlying return value.
|
*
|
||||||
*/
|
* @return True in case of success, false otherwise.
|
||||||
int cancel() {
|
*/
|
||||||
return uv_cancel(reinterpret_cast<uv_req_t *>(this->raw()));
|
bool cancel() {
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::size_t size() const noexcept {
|
std::size_t size() const noexcept {
|
||||||
return uv_req_size(reinterpret_cast<const uv_req_t *>(this->raw())->type);
|
return uv_req_size(this->template get<uv_req_t>()->type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace uvw
|
|
||||||
|
|
||||||
#endif // UVW_REQUEST_INCLUDE_H
|
}
|
||||||
|
|||||||
@ -1,42 +1,48 @@
|
|||||||
#ifndef UVW_RESOURCE_INCLUDE_H
|
#pragma once
|
||||||
#define UVW_RESOURCE_INCLUDE_H
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "config.h"
|
#include "emitter.hpp"
|
||||||
#include "emitter.h"
|
#include "underlying_type.hpp"
|
||||||
#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, typename... E>
|
template<typename T, typename U>
|
||||||
class resource: public uv_type<U>, public emitter<T, E...>, public std::enable_shared_from_this<T> {
|
class Resource: public UnderlyingType<T, U>, public Emitter<T>, public std::enable_shared_from_this<T> {
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]] int leak_if(int err) noexcept {
|
using ConstructorAccess = typename UnderlyingType<T, U>::ConstructorAccess;
|
||||||
if(err == 0) {
|
|
||||||
self_ptr = this->shared_from_this();
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
auto parent() const noexcept -> uv_loop_t * {
|
||||||
|
return this->loop().loop.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void self_reset() noexcept {
|
void leak() noexcept {
|
||||||
self_ptr.reset();
|
sPtr = this->shared_from_this();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool has_self() const noexcept {
|
void reset() noexcept {
|
||||||
return static_cast<bool>(self_ptr);
|
sPtr.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool self() const noexcept {
|
||||||
|
return static_cast<bool>(sPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit resource(loop::token token, std::shared_ptr<loop> ref)
|
explicit Resource(ConstructorAccess ca, std::shared_ptr<Loop> ref)
|
||||||
: uv_type<U>{token, std::move(ref)} {
|
: UnderlyingType<T, U>{ca, std::move(ref)},
|
||||||
this->raw()->data = this;
|
Emitter<T>{},
|
||||||
|
std::enable_shared_from_this<T>{}
|
||||||
|
{
|
||||||
|
this->get()->data = static_cast<T*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,23 +50,22 @@ 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>
|
||||||
[[nodiscard]] std::shared_ptr<R> data() const {
|
std::shared_ptr<R> data() const {
|
||||||
return std::static_pointer_cast<R>(user_data);
|
return std::static_pointer_cast<R>(userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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) {
|
||||||
user_data = std::move(udata);
|
userData = std::move(uData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<void> user_data{nullptr};
|
std::shared_ptr<void> userData{nullptr};
|
||||||
std::shared_ptr<void> self_ptr{nullptr};
|
std::shared_ptr<void> sPtr{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace uvw
|
|
||||||
|
|
||||||
#endif // UVW_RESOURCE_INCLUDE_H
|
}
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
#include "signal.h"
|
|
||||||
#include "signal.ipp"
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
#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
|
|
||||||
96
src/uvw/signal.hpp
Normal file
96
src/uvw/signal.hpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "stream.h"
|
|
||||||
#include "stream.ipp"
|
|
||||||
482
src/uvw/stream.h
482
src/uvw/stream.h
@ -1,482 +0,0 @@
|
|||||||
#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
|
|
||||||
481
src/uvw/stream.hpp
Normal file
481
src/uvw/stream.hpp
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
#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>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,29 +0,0 @@
|
|||||||
#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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#include "tcp.h"
|
|
||||||
#include "tcp.ipp"
|
|
||||||
233
src/uvw/tcp.h
233
src/uvw/tcp.h
@ -1,233 +0,0 @@
|
|||||||
#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
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user