mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-05 17:52:29 +00:00
Compare commits
97 Commits
v0.16.11
...
9ab73352e1
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ab73352e1 | |||
| f90a96d57a | |||
| 247ae7621a | |||
| 05831942a7 | |||
| ee18a1f3fc | |||
| f52f20f1b6 | |||
| 41eef969ea | |||
| 1def5e8b36 | |||
| 8355870586 | |||
| ba2bc7e64d | |||
| 0c11deac50 | |||
| f6b3ad0efd | |||
| 5d350f0bcc | |||
| 86fa0d195f | |||
| 2354c9cdb5 | |||
| 1b25bc7f56 | |||
| c6bde213b4 | |||
| 959448acda | |||
| 3b6da6feac | |||
| ea2d22cb87 | |||
| fa351c017d | |||
| 1e1bdd551a | |||
| a07f57a703 | |||
| 0494ce70c8 | |||
| cfad36bf12 | |||
| 123c327a8f | |||
| 9884c9dd9b | |||
| d99cd5eb73 | |||
| 786f1234d2 | |||
| 23921cc97c | |||
| 6558f0ad42 | |||
| 9431dd5acc | |||
| 8598873627 | |||
| ce4cd27697 | |||
| 59fe93515e | |||
| 8249070ff1 | |||
| 517454b413 | |||
| a79aaad9ab | |||
| c6de871a77 | |||
| acb02379b8 | |||
| bf74686c29 | |||
| dbe7997131 | |||
| d595ebf7d8 | |||
| 08828045f5 | |||
| 662d67e861 | |||
| d08d7de20d | |||
| 83bdc271a4 | |||
| 29edda2f15 | |||
| fd69baa2c1 | |||
| 1603ba0573 | |||
| 19305ab662 | |||
| 5b2e202452 | |||
| c63db9cf97 | |||
| 72f2197add | |||
| e96f594afc | |||
| bc8d0da70f | |||
| 75377817b4 | |||
| 595617c408 | |||
| 578fe03ad6 | |||
| efe258a137 | |||
| 44d39713d5 | |||
| 49625ab5e5 | |||
| cc15e9308a | |||
| a5a96236df | |||
| f1cfe8ad72 | |||
| d0fc48cf7b | |||
| 5725eb3773 | |||
| ca706c21c0 | |||
| 14edd68653 | |||
| 50a609ade9 | |||
| 2cf8f2351b | |||
| add305f90c | |||
| 880510073a | |||
| 0989b2218d | |||
| 3d7e6cb077 | |||
| 64881317c6 | |||
| a5ecd89a54 | |||
| 84229a85be | |||
| e03ab27cf0 | |||
| e41b066555 | |||
| 8318133c79 | |||
| 088bf40bdf | |||
| 2f7a984992 | |||
| 840a57915e | |||
| 5e211c3a28 | |||
| 797a194abc | |||
| 501853cfbc | |||
| b0ef95592b | |||
| 26a7e9f545 | |||
| 0ed10984b3 | |||
| 5f09bb74de | |||
| c368b2de1e | |||
| 71ac256cb5 | |||
| b05b65bd65 | |||
| f05b48e228 | |||
| 1279bd9f7a | |||
| 981184574d |
@@ -0,0 +1,65 @@
|
||||
name: "Lint Commit Message Size"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check-commit-bounds:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Validate Line Count, Width, and Spacing
|
||||
run: |
|
||||
# Fetch commit hashes unique to this PR branch
|
||||
COMMITS=$(git log --no-merges --pretty=format:"%H" origin/${{ github.base_ref }}..HEAD)
|
||||
|
||||
MAX_LINES=3
|
||||
MAX_CHARS=90
|
||||
FAILED=0
|
||||
|
||||
for commit in $COMMITS; do
|
||||
SUBJECT=$(git log --format="%s" -n 1 $commit)
|
||||
|
||||
# Extract clean commit message, trimming trailing blank lines
|
||||
RAW_MSG=$(git log --format="%B" -n 1 $commit)
|
||||
CLEAN_MSG=$(echo "$RAW_MSG" | awk '{msg[NR]=$0} END {while(NR>0 && msg[NR]=="") NR--; for(i=1;i<=NR;i++) print msg[i]}')
|
||||
|
||||
# 1. Check total line count
|
||||
LINE_COUNT=$(echo "$CLEAN_MSG" | wc -l)
|
||||
if [ "$LINE_COUNT" -gt "$MAX_LINES" ]; then
|
||||
echo "❌ Error: Commit message has too many lines ($LINE_COUNT/$MAX_LINES)."
|
||||
echo " Commit: '$SUBJECT'"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# 2. Check for multiple consecutive blank lines
|
||||
# This regex looks for 2 or more empty lines anywhere in the message
|
||||
if echo "$CLEAN_MSG" | grep -pz '(\r?\n){3,}'; then
|
||||
echo "❌ Error: Commit message contains multiple consecutive line breaks."
|
||||
echo " Commit: '$SUBJECT'"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
# 3. Check maximum width of any individual line
|
||||
while IFS= read -r line; do
|
||||
LINE_LENGTH=${#line}
|
||||
if [ "$LINE_LENGTH" -gt "$MAX_CHARS" ]; then
|
||||
echo "❌ Error: Line length exceeds limit ($LINE_LENGTH / $MAX_CHARS chars)."
|
||||
echo " Offending line: '$line'"
|
||||
FAILED=1
|
||||
fi
|
||||
done <<< "$CLEAN_MSG"
|
||||
|
||||
done
|
||||
|
||||
# Fail the job if any check failed
|
||||
if [ "$FAILED" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ All commit messages passed style rules!"
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
permissions:
|
||||
pull-requests: write
|
||||
# OPTIONAL: auto-closing conversations requires the `contents` permission
|
||||
contents: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Sleep for 30 seconds
|
||||
run: sleep 30s
|
||||
|
||||
@@ -4,9 +4,8 @@ on: pull_request
|
||||
|
||||
jobs:
|
||||
|
||||
unit-tests:
|
||||
ubuntu-base:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Update Packages
|
||||
run: |
|
||||
@@ -23,43 +22,86 @@ jobs:
|
||||
- name: Build libtorrent
|
||||
run: |
|
||||
cd libtorrent
|
||||
libtoolize
|
||||
aclocal -I scripts
|
||||
autoconf -i
|
||||
autoheader
|
||||
automake --add-missing
|
||||
autoreconf -fiv
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
cd ..
|
||||
rm -rf libtorrent
|
||||
- uses: actions/checkout@v4
|
||||
sudo make install DESTDIR=$GITHUB_WORKSPACE/libtorrent-dist
|
||||
- name: Upload Build Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
- name: Fetch base branch
|
||||
name: installed-libtorrent
|
||||
path: libtorrent-dist/
|
||||
|
||||
|
||||
unit-tests-default:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: ubuntu-base
|
||||
steps:
|
||||
- name: Update Packages
|
||||
run: |
|
||||
git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}"
|
||||
git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}"
|
||||
sudo apt-get update
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get install -y \
|
||||
libcppunit-dev \
|
||||
zlib1g-dev \
|
||||
libcurl4-openssl-dev
|
||||
- name: Download Libtorrent Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: installed-libtorrent
|
||||
path: ./libtorrent-dist
|
||||
- name: Move Artifacts to System Path
|
||||
run: |
|
||||
# Elevate permissions with sudo to safely place the files
|
||||
sudo cp -r ./libtorrent-dist/usr/local/* /usr/local/
|
||||
rm -rf ./libtorrent-dist
|
||||
- uses: actions/checkout@v4
|
||||
- name: Configure Project
|
||||
run: |
|
||||
libtoolize
|
||||
aclocal -I scripts
|
||||
autoconf -i
|
||||
autoheader
|
||||
automake --add-missing
|
||||
autoreconf -fiv
|
||||
./configure
|
||||
- name: Build Project
|
||||
run: |
|
||||
make
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
ls /usr/local/lib/
|
||||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
|
||||
make check
|
||||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" make check
|
||||
- name: Archive test/test-suite.log
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-suite.log
|
||||
path: test/test-suite.log
|
||||
|
||||
unit-tests-variants:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: unit-tests-default
|
||||
strategy:
|
||||
matrix:
|
||||
config_flag: ["--with-xmlrpc-c", "--with-xmlrpc-tinyxml2"]
|
||||
steps:
|
||||
- name: Update Packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get install -y \
|
||||
libcppunit-dev \
|
||||
zlib1g-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libxmlrpc-c++8-dev
|
||||
- name: Download Libtorrent Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: installed-libtorrent
|
||||
path: ./libtorrent-dist
|
||||
- name: Move Artifacts to System Path
|
||||
run: |
|
||||
sudo cp -r ./libtorrent-dist/usr/local/* /usr/local/
|
||||
rm -rf ./libtorrent-dist
|
||||
- uses: actions/checkout@v4
|
||||
- name: Configure Project
|
||||
run: |
|
||||
autoreconf -fiv
|
||||
./configure ${{ matrix.config_flag }}
|
||||
make
|
||||
ls /usr/local/lib/
|
||||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" make check
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
.libs
|
||||
Makefile
|
||||
aclocal.m4
|
||||
actmp.*
|
||||
ar-lib
|
||||
autom4te.cache
|
||||
compile
|
||||
@@ -69,4 +70,5 @@ TAGS
|
||||
###########################
|
||||
src/rtorrent
|
||||
test/rtorrent_Test*
|
||||
test/test-suite.log.tmp
|
||||
test-driver
|
||||
|
||||
@@ -7,7 +7,6 @@ nobase_dist_pkgdata_DATA = \
|
||||
lua/rtorrent.lua
|
||||
|
||||
EXTRA_DIST= \
|
||||
rak/regex.h \
|
||||
scripts/checks.m4 \
|
||||
scripts/common.m4 \
|
||||
scripts/attributes.m4
|
||||
|
||||
+19
-17
@@ -1,6 +1,6 @@
|
||||
m4_pattern_allow([PKG_CHECK_EXISTS])
|
||||
|
||||
AC_INIT([rtorrent],[0.16.11],[sundell.software@gmail.com])
|
||||
AC_INIT([rtorrent],[0.16.19],[sundell.software@gmail.com])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIRS([scripts])
|
||||
@@ -10,15 +10,11 @@ AM_PROG_AR
|
||||
LT_INIT
|
||||
|
||||
AC_PROG_CXX
|
||||
AX_CXX_COMPILE_STDCXX(20, noext, mandatory)
|
||||
|
||||
AC_DEFINE([API_VERSION], [20], [api version])
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
# Filter out unwanted flags added by autoconf on some systems, e.g. MacOS.
|
||||
TORRENT_REMOVE_UNWANTED(CXX, $CXX, -std=c++11 -std=gnu++11)
|
||||
|
||||
AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory])
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
AC_DEFINE([API_VERSION], [24], [api version])
|
||||
|
||||
RAK_CHECK_CFLAGS
|
||||
RAK_CHECK_CXXFLAGS
|
||||
@@ -26,9 +22,6 @@ RAK_ENABLE_DEBUG
|
||||
RAK_ENABLE_EXTRA_DEBUG
|
||||
RAK_ENABLE_WERROR
|
||||
|
||||
TORRENT_ENABLE_ARCH
|
||||
TORRENT_WITH_SYSROOT
|
||||
|
||||
AC_ARG_ENABLE(execinfo,
|
||||
AS_HELP_STRING([--disable-execinfo],
|
||||
[disable libexecinfo [[default=enable]]]),
|
||||
@@ -41,20 +34,28 @@ AC_ARG_ENABLE(execinfo,
|
||||
])
|
||||
|
||||
AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
|
||||
AX_WITH_CURSES
|
||||
|
||||
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
TORRENT_WITHOUT_NCURSES
|
||||
|
||||
if test "x$with_ncurses" != xno; then
|
||||
AX_WITH_CURSES
|
||||
|
||||
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
fi
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||
PKG_CHECK_MODULES([ZLIB], [zlib])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.11])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.19])
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
dnl We don't have LuaJIT support, and the script breaks if not disabled.
|
||||
AM_CONDITIONAL([LUAJIT], [false])
|
||||
|
||||
TORRENT_WITH_LUA
|
||||
TORRENT_WITH_TINYXML2
|
||||
TORRENT_WITH_SYSTEMD
|
||||
@@ -63,7 +64,7 @@ if test ${with_xmlrpc_c+y} && test ${with_xmlrpc_tinyxml2+y}; then
|
||||
AC_MSG_ERROR([--with-xmlrpc-c and --with-xmlrpc-tinyxml2 cannot be used together. Please choose only one])
|
||||
fi
|
||||
|
||||
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent)
|
||||
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION)], Http user agent)
|
||||
|
||||
dnl Only update global build variables immediately before generating the output,
|
||||
dnl to avoid affecting the global build environment for other autoconf checks.
|
||||
@@ -71,7 +72,8 @@ LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $ZLIB_LIBS $DEPENDENCIES_LIBS $LIBS
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS"
|
||||
|
||||
TORRENT_CHECK_POPCOUNT()
|
||||
TORRENT_CHECK_CACHELINE
|
||||
TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
|
||||
+5
-1
@@ -46,8 +46,12 @@
|
||||
#session.path.set = ./session
|
||||
|
||||
# Watch a directory for new torrents, and stop those that have been
|
||||
# deleted.
|
||||
# deleted. Use directory.watch.ready for network shares or other watch
|
||||
# directories where files may be copied or written directly into place.
|
||||
# Do not mix directory.watch.ready and directory.watch.added on the same
|
||||
# watch directory.
|
||||
#
|
||||
#directory.watch.ready = ./watch, load.start
|
||||
#schedule2 = watch_directory,5,5,load.start=./watch/*.torrent
|
||||
|
||||
# Close torrents when disk-space is low.
|
||||
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
// This is a hacked up whole string pattern matching. Replace with
|
||||
// TR1's regex when that becomes widely available. It is intended for
|
||||
// small strings.
|
||||
|
||||
#ifndef RAK_REGEX_H
|
||||
#define RAK_REGEX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class regex {
|
||||
public:
|
||||
regex() {}
|
||||
regex(const std::string& p) : m_pattern(p) {}
|
||||
|
||||
const std::string& pattern() const { return m_pattern; }
|
||||
|
||||
bool operator () (const std::string& p) const;
|
||||
|
||||
private:
|
||||
std::string m_pattern;
|
||||
};
|
||||
|
||||
// This isn't optimized, or very clean. A simple hack that should work.
|
||||
inline bool
|
||||
regex::operator () (const std::string& text) const {
|
||||
if (m_pattern.empty() ||
|
||||
text.empty() ||
|
||||
(m_pattern[0] != '*' && m_pattern[0] != text[0]))
|
||||
return false;
|
||||
|
||||
// Replace with unordered_vector?
|
||||
std::list<unsigned int> paths;
|
||||
paths.push_front(0);
|
||||
|
||||
for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) {
|
||||
|
||||
for (std::list<unsigned int>::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) {
|
||||
|
||||
unsigned int next = *itrPaths + 1;
|
||||
|
||||
if (m_pattern[*itrPaths] != '*')
|
||||
itrPaths = paths.erase(itrPaths);
|
||||
else
|
||||
itrPaths++;
|
||||
|
||||
// When we reach the end of 'm_pattern', we don't have a whole
|
||||
// match of 'text'.
|
||||
if (next == m_pattern.size())
|
||||
continue;
|
||||
|
||||
// Push to the back so that '*' will match zero length strings.
|
||||
if (m_pattern[next] == '*')
|
||||
paths.push_back(next);
|
||||
|
||||
if (m_pattern[next] == *itrText)
|
||||
paths.push_front(next);
|
||||
}
|
||||
|
||||
if (paths.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -10,8 +10,8 @@
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the specified
|
||||
# version of the C++ standard. If necessary, add switches to CXX and
|
||||
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
|
||||
# or '14' (for the C++14 standard).
|
||||
# CXXCPP to enable support. VERSION may be '11', '14', '17', '20', or
|
||||
# '23' for the respective C++ standard version.
|
||||
#
|
||||
# The second argument, if specified, indicates whether you insist on an
|
||||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||
@@ -36,13 +36,15 @@
|
||||
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
|
||||
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
|
||||
# Copyright (c) 2020 Jason Merrill <jason@redhat.com>
|
||||
# Copyright (c) 2021, 2024 Jörn Heusipp <osmanx@problemloesungsmaschine.de>
|
||||
# Copyright (c) 2015, 2022, 2023, 2024 Olly Betts
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 12
|
||||
#serial 25
|
||||
|
||||
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
|
||||
dnl (serial version number 13).
|
||||
@@ -51,6 +53,8 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
|
||||
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
|
||||
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
|
||||
[$1], [20], [ax_cxx_compile_alternatives="20"],
|
||||
[$1], [23], [ax_cxx_compile_alternatives="23"],
|
||||
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$2], [], [],
|
||||
[$2], [ext], [],
|
||||
@@ -102,9 +106,18 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
dnl HP's aCC needs +std=c++11 according to:
|
||||
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
|
||||
dnl Cray's crayCC needs "-h std=c++11"
|
||||
dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
|
||||
for alternative in ${ax_cxx_compile_alternatives}; do
|
||||
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
|
||||
if test x"$switch" = xMSVC; then
|
||||
dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
|
||||
dnl with -std=c++17. We suffix the cache variable name with _MSVC to
|
||||
dnl avoid this.
|
||||
switch=-std:c++${alternative}
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
|
||||
else
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
fi
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
@@ -148,23 +161,44 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
dnl Test body for checking C++11 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11]
|
||||
)
|
||||
|
||||
|
||||
dnl Test body for checking C++14 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14]
|
||||
)
|
||||
|
||||
dnl Test body for checking C++17 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17]
|
||||
)
|
||||
|
||||
dnl Test body for checking C++20 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_20]
|
||||
)
|
||||
|
||||
dnl Test body for checking C++23 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23],
|
||||
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_20
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_23]
|
||||
)
|
||||
|
||||
|
||||
dnl Tests for new features in C++11
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
@@ -176,7 +210,21 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201103L
|
||||
// MSVC always sets __cplusplus to 199711L in older versions; newer versions
|
||||
// only set it correctly if /Zc:__cplusplus is specified as well as a
|
||||
// /std:c++NN switch:
|
||||
//
|
||||
// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
|
||||
//
|
||||
// The value __cplusplus ought to have is available in _MSVC_LANG since
|
||||
// Visual Studio 2015 Update 3:
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
//
|
||||
// This was also the first MSVC version to support C++14 so we can't use the
|
||||
// value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having
|
||||
// C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later.
|
||||
#elif __cplusplus < 201103L && !defined _MSC_VER
|
||||
|
||||
#error "This is not a C++11 compiler"
|
||||
|
||||
@@ -467,7 +515,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201402L
|
||||
#elif __cplusplus < 201402L && !defined _MSC_VER
|
||||
|
||||
#error "This is not a C++14 compiler"
|
||||
|
||||
@@ -591,7 +639,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201703L
|
||||
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
|
||||
|
||||
#error "This is not a C++17 compiler"
|
||||
|
||||
@@ -957,6 +1005,66 @@ namespace cxx17
|
||||
|
||||
} // namespace cxx17
|
||||
|
||||
#endif // __cplusplus < 201703L
|
||||
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++20
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
|
||||
|
||||
#error "This is not a C++20 compiler"
|
||||
|
||||
#else
|
||||
|
||||
#include <version>
|
||||
|
||||
namespace cxx20
|
||||
{
|
||||
|
||||
// As C++20 supports feature test macros in the standard, there is no
|
||||
// immediate need to actually test for feature availability on the
|
||||
// Autoconf side.
|
||||
|
||||
} // namespace cxx20
|
||||
|
||||
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++23
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L
|
||||
|
||||
#error "This is not a C++23 compiler"
|
||||
|
||||
#else
|
||||
|
||||
#include <version>
|
||||
|
||||
namespace cxx23
|
||||
{
|
||||
|
||||
// As C++23 supports feature test macros in the standard, there is no
|
||||
// immediate need to actually test for feature availability on the
|
||||
// Autoconf side.
|
||||
|
||||
} // namespace cxx23
|
||||
|
||||
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L
|
||||
|
||||
]])
|
||||
|
||||
+83
-34
@@ -19,7 +19,7 @@
|
||||
# header is checked to match the Lua interpreter version exactly. When
|
||||
# searching for Lua libraries, the version number is used as a suffix.
|
||||
# This is done with the goal of supporting multiple Lua installs (5.1,
|
||||
# 5.2, and 5.3 side-by-side).
|
||||
# 5.2, 5.3, and 5.4 side-by-side).
|
||||
#
|
||||
# A note on compatibility with previous versions: This file has been
|
||||
# mostly rewritten for serial 18. Most developers should be able to use
|
||||
@@ -49,6 +49,14 @@
|
||||
# interpreter. If LUA is blank, the user's path is searched for an
|
||||
# suitable interpreter.
|
||||
#
|
||||
# Optionally a LUAJIT option may be set ahead of time to look for and
|
||||
# validate a LuaJIT install instead of PUC Lua. Usage might look like:
|
||||
#
|
||||
# AC_ARG_WITH(luajit, [AS_HELP_STRING([--with-luajit],
|
||||
# [Prefer LuaJIT over PUC Lua, even if the latter is newer. Default: no])
|
||||
# ])
|
||||
# AM_CONDITIONAL([LUAJIT], [test "x$with_luajit" != 'xno'])
|
||||
#
|
||||
# If MINIMUM-VERSION is supplied, then only Lua interpreters with a
|
||||
# version number greater or equal to MINIMUM-VERSION will be accepted. If
|
||||
# TOO-BIG-VERSION is also supplied, then only Lua interpreters with a
|
||||
@@ -82,7 +90,7 @@
|
||||
# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES.
|
||||
#
|
||||
# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is
|
||||
# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT-
|
||||
# performed, otherwise ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-
|
||||
# FOUND is blank, then it will default to printing an error. To prevent
|
||||
# the default behavior, give ':' as an action.
|
||||
#
|
||||
@@ -152,6 +160,7 @@
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2023 Caleb Maclennan <caleb@alerque.com>
|
||||
# Copyright (c) 2015 Reuben Thomas <rrt@sc3d.org>
|
||||
# Copyright (c) 2014 Tim Perkins <tprk77@gmail.com>
|
||||
#
|
||||
@@ -181,7 +190,7 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 42
|
||||
#serial 47
|
||||
|
||||
dnl =========================================================================
|
||||
dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
|
||||
@@ -197,13 +206,14 @@ AC_DEFUN([AX_PROG_LUA],
|
||||
AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
|
||||
|
||||
dnl Find a Lua interpreter.
|
||||
m4_define_default([_AX_LUA_INTERPRETER_LIST],
|
||||
[lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50])
|
||||
AM_COND_IF([LUAJIT],
|
||||
[_ax_lua_interpreter_list='luajit luajit-2.1.0-beta3 luajit-2.0.5 luajit-2.0.4 luajit-2.0.3'],
|
||||
[_ax_lua_interpreter_list='lua lua5.4 lua54 lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua5.0 lua50'])
|
||||
|
||||
m4_if([$1], [],
|
||||
[ dnl No version check is needed. Find any Lua interpreter.
|
||||
AS_IF([test "x$LUA" = 'x'],
|
||||
[AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])])
|
||||
[AC_PATH_PROGS([LUA], [$_ax_lua_interpreter_list], [:])])
|
||||
ax_display_LUA='lua'
|
||||
|
||||
AS_IF([test "x$LUA" != 'x:'],
|
||||
@@ -242,7 +252,7 @@ AC_DEFUN([AX_PROG_LUA],
|
||||
[_ax_check_text="for a Lua interpreter with version >= $1, < $2"])
|
||||
AC_CACHE_CHECK([$_ax_check_text],
|
||||
[ax_cv_pathless_LUA],
|
||||
[ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do
|
||||
[ for ax_cv_pathless_LUA in $_ax_lua_interpreter_list none; do
|
||||
test "x$ax_cv_pathless_LUA" = 'xnone' && break
|
||||
_AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue])
|
||||
_AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break])
|
||||
@@ -268,13 +278,25 @@ AC_DEFUN([AX_PROG_LUA],
|
||||
ax_cv_lua_version=[`$LUA -e '
|
||||
-- return a version number in X.Y format
|
||||
local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)")
|
||||
print(ver)'`]
|
||||
print(ver or "")'`]
|
||||
])
|
||||
AS_IF([test "x$ax_cv_lua_version" = 'x'],
|
||||
[AC_MSG_ERROR([invalid Lua version number])])
|
||||
AC_SUBST([LUA_VERSION], [$ax_cv_lua_version])
|
||||
AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`])
|
||||
|
||||
AM_COND_IF([LUAJIT], [
|
||||
AC_CACHE_CHECK([for $ax_display_LUA jit version], [ax_cv_luajit_version],
|
||||
[ ax_cv_luajit_version=[`$LUA -e '
|
||||
local _, _, ver = string.find(jit and jit.version, "(%d+%..+)")
|
||||
print(ver or "")'`]
|
||||
])
|
||||
AS_IF([test "x$ax_cv_luajit_version" = 'x'],
|
||||
[AC_MSG_ERROR([invalid Lua jit version number])])
|
||||
AC_SUBST([LUAJIT_VERSION], [$ax_cv_luajit_version])
|
||||
AC_SUBST([LUAJIT_SHORT_VERSION], [$(echo "$LUAJIT_VERSION" | $SED 's|\.|§|;s|\..*||;s|§|.|')])
|
||||
])
|
||||
|
||||
dnl The following check is not supported:
|
||||
dnl At times (like when building shared libraries) you may want to know
|
||||
dnl which OS platform Lua thinks this is.
|
||||
@@ -464,33 +486,50 @@ AC_DEFUN([AX_LUA_HEADERS],
|
||||
AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION])
|
||||
])
|
||||
|
||||
AM_COND_IF([LUAJIT],[
|
||||
dnl Check for LUAJIT_VERSION.
|
||||
AC_MSG_CHECKING([if LUAJIT_VERSION is defined])
|
||||
AS_IF([test "x$LUAJIT_VERSION" != 'x'],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[ AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([cannot check Lua jit headers without knowing LUAJIT_VERSION])
|
||||
])
|
||||
])
|
||||
|
||||
dnl Make LUA_INCLUDE a precious variable.
|
||||
AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1])
|
||||
|
||||
dnl Some default directories to search.
|
||||
LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'`
|
||||
m4_define_default([_AX_LUA_INCLUDE_LIST],
|
||||
[ /usr/include/lua$LUA_VERSION \
|
||||
/usr/include/lua-$LUA_VERSION \
|
||||
/usr/include/lua/$LUA_VERSION \
|
||||
/usr/include/lua$LUA_SHORT_VERSION \
|
||||
/usr/local/include/lua$LUA_VERSION \
|
||||
/usr/local/include/lua-$LUA_VERSION \
|
||||
/usr/local/include/lua/$LUA_VERSION \
|
||||
/usr/local/include/lua$LUA_SHORT_VERSION \
|
||||
])
|
||||
dnl Some default directories to search.
|
||||
AM_COND_IF([LUAJIT],
|
||||
[_ax_lua_include_list="
|
||||
/usr/include/luajit-$LUAJIT_VERSION
|
||||
/usr/include/luajit-$LUAJIT_SHORT_VERSION
|
||||
/usr/local/include/luajit-$LUAJIT_VERSION
|
||||
/usr/local/include/luajit-$LUAJIT_SHORT_VERSION"],
|
||||
[_ax_lua_include_list="
|
||||
/usr/include/lua$LUA_VERSION
|
||||
/usr/include/lua-$LUA_VERSION
|
||||
/usr/include/lua/$LUA_VERSION
|
||||
/usr/include/lua$LUA_SHORT_VERSION
|
||||
/usr/local/include/lua$LUA_VERSION
|
||||
/usr/local/include/lua-$LUA_VERSION
|
||||
/usr/local/include/lua/$LUA_VERSION
|
||||
/usr/local/include/lua$LUA_SHORT_VERSION"])
|
||||
|
||||
dnl Try to find the headers.
|
||||
_ax_lua_saved_cppflags=$CPPFLAGS
|
||||
CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
|
||||
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
|
||||
AM_COND_IF([LUAJIT], [AC_CHECK_HEADERS([luajit.h])])
|
||||
CPPFLAGS=$_ax_lua_saved_cppflags
|
||||
|
||||
dnl Try some other directories if LUA_INCLUDE was not set.
|
||||
AS_IF([test "x$LUA_INCLUDE" = 'x' &&
|
||||
test "x$ac_cv_header_lua_h" != 'xyes'],
|
||||
test "x$ac_cv_header_lua_h" != 'xyes' ||
|
||||
test "x$with_luajit" != 'xno' &&
|
||||
test "x$ac_cv_header_luajit_h" != 'xyes'],
|
||||
[ dnl Try some common include paths.
|
||||
for _ax_include_path in _AX_LUA_INCLUDE_LIST; do
|
||||
for _ax_include_path in $_ax_lua_include_list; do
|
||||
test ! -d "$_ax_include_path" && continue
|
||||
|
||||
AC_MSG_CHECKING([for Lua headers in])
|
||||
@@ -500,10 +539,12 @@ AC_DEFUN([AX_LUA_HEADERS],
|
||||
AS_UNSET([ac_cv_header_lualib_h])
|
||||
AS_UNSET([ac_cv_header_lauxlib_h])
|
||||
AS_UNSET([ac_cv_header_luaconf_h])
|
||||
AS_UNSET([ac_cv_header_luajit_h])
|
||||
|
||||
_ax_lua_saved_cppflags=$CPPFLAGS
|
||||
CPPFLAGS="$CPPFLAGS -I$_ax_include_path"
|
||||
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
|
||||
AM_COND_IF([LUAJIT], [AC_CHECK_HEADERS([luajit.h])])
|
||||
CPPFLAGS=$_ax_lua_saved_cppflags
|
||||
|
||||
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
|
||||
@@ -621,18 +662,26 @@ AC_DEFUN([AX_LUA_LIBS],
|
||||
dnl Try to find the Lua libs.
|
||||
_ax_lua_saved_libs=$LIBS
|
||||
LIBS="$LIBS $LUA_LIB"
|
||||
AC_SEARCH_LIBS([lua_load],
|
||||
[ lua$LUA_VERSION \
|
||||
lua$LUA_SHORT_VERSION \
|
||||
lua-$LUA_VERSION \
|
||||
lua-$LUA_SHORT_VERSION \
|
||||
:liblua-$LUA_VERSION.so.0 \
|
||||
:liblua-$LUA_SHORT_VERSION.so.0 \
|
||||
lua \
|
||||
],
|
||||
[_ax_found_lua_libs='yes'],
|
||||
[_ax_found_lua_libs='no'],
|
||||
[$_ax_lua_extra_libs])
|
||||
AM_COND_IF([LUAJIT],
|
||||
[AC_SEARCH_LIBS([lua_load],
|
||||
[ luajit$LUA_VERSION \
|
||||
luajit$LUA_SHORT_VERSION \
|
||||
luajit-$LUA_VERSION \
|
||||
luajit-$LUA_SHORT_VERSION \
|
||||
luajit],
|
||||
[_ax_found_lua_libs='yes'],
|
||||
[_ax_found_lua_libs='no'],
|
||||
[$_ax_lua_extra_libs])],
|
||||
[AC_SEARCH_LIBS([lua_load],
|
||||
[ lua$LUA_VERSION \
|
||||
lua$LUA_SHORT_VERSION \
|
||||
lua-$LUA_VERSION \
|
||||
lua-$LUA_SHORT_VERSION \
|
||||
lua \
|
||||
],
|
||||
[_ax_found_lua_libs='yes'],
|
||||
[_ax_found_lua_libs='no'],
|
||||
[$_ax_lua_extra_libs])])
|
||||
LIBS=$_ax_lua_saved_libs
|
||||
|
||||
AS_IF([test "x$ac_cv_search_lua_load" != 'xno' &&
|
||||
|
||||
+100
-127
@@ -1,48 +1,3 @@
|
||||
AC_DEFUN([TORRENT_CHECK_XFS], [
|
||||
AC_MSG_CHECKING(for XFS support)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <xfs/libxfs.h>
|
||||
#include <sys/ioctl.h>
|
||||
int main() {
|
||||
struct xfs_flock64 l;
|
||||
ioctl(0, XFS_IOC_RESVSP64, &l);
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[
|
||||
AC_DEFINE(USE_XFS, 1, Use XFS filesystem stuff.)
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_XFS], [
|
||||
AC_ARG_WITH(xfs,
|
||||
AS_HELP_STRING([--without-xfs],[do not check for XFS filesystem support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_XFS
|
||||
fi
|
||||
], [
|
||||
TORRENT_CHECK_XFS
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_XFS], [
|
||||
AC_ARG_WITH(xfs,
|
||||
AS_HELP_STRING([--with-xfs],[check for XFS filesystem support]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_XFS
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_EPOLL], [
|
||||
AC_MSG_CHECKING(for epoll support)
|
||||
|
||||
@@ -54,6 +9,8 @@ AC_DEFUN([TORRENT_CHECK_EPOLL], [
|
||||
}
|
||||
])],
|
||||
[
|
||||
use_epoll=yes
|
||||
|
||||
AC_DEFINE(USE_EPOLL, 1, Use epoll.)
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
@@ -86,6 +43,8 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
|
||||
}
|
||||
])],
|
||||
[
|
||||
use_kqueue=yes
|
||||
|
||||
AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
@@ -118,48 +77,9 @@ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
|
||||
AC_MSG_CHECKING(for fallocate)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
]], [[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
|
||||
]])],[
|
||||
AC_DEFINE(HAVE_FALLOCATE, 1, Linux's fallocate supported.)
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POSIX_FALLOCATE], [
|
||||
AC_MSG_CHECKING(for posix_fallocate)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <fcntl.h>
|
||||
]], [[ posix_fallocate(0, 0, 0);
|
||||
]])],[
|
||||
AC_DEFINE(USE_POSIX_FALLOCATE, 1, posix_fallocate supported.)
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
|
||||
AC_ARG_WITH(posix-fallocate,
|
||||
AS_HELP_STRING([--with-posix-fallocate],[check for and use posix_fallocate to allocate files]),
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
TORRENT_CHECK_POSIX_FALLOCATE
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
|
||||
AC_ARG_WITH(address-space,
|
||||
AS_HELP_STRING([--with-address-space=MB],[change the default address space size [[default=1024mb]]]),
|
||||
AS_HELP_STRING([--with-address-space=MB],[change the default address space size [default=1024mb-or-32768mb]]),
|
||||
[
|
||||
if test ! -z $withval -a "$withval" != "yes" -a "$withval" != "no"; then
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ADDRESS_SPACE_SIZE, [$withval])
|
||||
@@ -171,51 +91,48 @@ AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
|
||||
AC_CHECK_SIZEOF(long)
|
||||
|
||||
if test $ac_cv_sizeof_long = 8; then
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 4096, Default address space size.)
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 32768, Default address space size.)
|
||||
else
|
||||
AC_DEFINE(DEFAULT_ADDRESS_SPACE_SIZE, 1024, Default address space size.)
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_FASTCGI], [
|
||||
AC_ARG_WITH(fastcgi,
|
||||
AS_HELP_STRING([--with-fastcgi=PATH],[enable FastCGI RPC support (DO NOT USE)]),
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_ATOMIC], [
|
||||
AC_MSG_CHECKING([whether 64-bit atomic operations require -latomic])
|
||||
AC_LANG_PUSH(C++)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <cstdint>
|
||||
#include <atomic>]],
|
||||
[[std::atomic<uint64_t> x(0);
|
||||
return x.load();]])],
|
||||
[
|
||||
AC_MSG_CHECKING([for FastCGI (DO NOT USE)])
|
||||
AC_MSG_RESULT([no])
|
||||
ATOMIC_LIBS=""
|
||||
],
|
||||
[
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS -latomic"
|
||||
|
||||
if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
elif test "$withval" = "yes"; then
|
||||
CXXFLAGS="$CXXFLAGS"
|
||||
LIBS="$LIBS -lfcgi"
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <fcgiapp.h>
|
||||
]], [[ FCGX_Init(); ]])],[
|
||||
AC_MSG_RESULT(ok)
|
||||
],[
|
||||
AC_MSG_RESULT(not found)
|
||||
AC_MSG_ERROR(Could not compile FastCGI test.)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <cstdint>
|
||||
#include <atomic>]],
|
||||
[[std::atomic<uint64_t> x(0);
|
||||
return x.load();]])],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
ATOMIC_LIBS="-latomic"
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([unsupported])
|
||||
AC_MSG_ERROR([Compiler target lacks proper 64-bit atomic support.])
|
||||
])
|
||||
|
||||
AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.)
|
||||
|
||||
else
|
||||
CXXFLAGS="$CXXFLAGS -I$withval/include"
|
||||
LIBS="$LIBS -lfcgi -L$withval/lib"
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <fcgiapp.h>
|
||||
]], [[ FCGX_Init(); ]])],[
|
||||
AC_MSG_RESULT(ok)
|
||||
],[
|
||||
AC_MSG_RESULT(not found)
|
||||
AC_MSG_ERROR(Could not compile FastCGI test.)
|
||||
])
|
||||
|
||||
AC_DEFINE(HAVE_FASTCGI, 1, Support for FastCGI.)
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
])
|
||||
|
||||
AC_LANG_POP(C++)
|
||||
AC_SUBST([ATOMIC_LIBS])
|
||||
])
|
||||
|
||||
|
||||
@@ -260,6 +177,7 @@ AC_DEFUN([TORRENT_WITH_XMLRPC_C], [
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_TINYXML2], [
|
||||
AC_MSG_CHECKING(for tinyxml2)
|
||||
|
||||
@@ -273,6 +191,7 @@ AC_DEFUN([TORRENT_WITH_TINYXML2], [
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_LUA], [
|
||||
AC_ARG_WITH(lua,
|
||||
AS_HELP_STRING([--with-lua],[enable LUA support]),
|
||||
@@ -281,29 +200,45 @@ AC_DEFUN([TORRENT_WITH_LUA], [
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
AX_PROG_LUA
|
||||
AX_LUA_LIBS
|
||||
AX_LUA_HEADERS
|
||||
AC_DEFINE(HAVE_LUA, 1, Use LUA.)
|
||||
AC_DEFINE(LUA_DATADIR, [PACKAGE_DATADIR "/lua"], [LUA data directory])
|
||||
LIBS="$LIBS $LUA_LIB"
|
||||
CXXFLAGS="$CXXFLAGS $LUA_INCLUDE"
|
||||
|
||||
# 1. Override AX_LUA_LIBS default crash behavior
|
||||
AX_LUA_LIBS([have_lua_libs=yes], [have_lua_libs=no])
|
||||
|
||||
# 2. Override AX_LUA_HEADERS default crash behavior
|
||||
AX_LUA_HEADERS([have_lua_headers=yes], [have_lua_headers=no])
|
||||
|
||||
# 3. Only inject if both checks completely pass
|
||||
if test "x$have_lua_libs" = "xyes" && test "x$have_lua_headers" = "xyes"; then
|
||||
AC_DEFINE(HAVE_LUA, 1, Use LUA.)
|
||||
AC_DEFINE(LUA_DATADIR, [PACKAGE_DATADIR "/lua"], [LUA data directory])
|
||||
LIBS="$LIBS $LUA_LIB"
|
||||
CXXFLAGS="$CXXFLAGS $LUA_INCLUDE"
|
||||
else
|
||||
# Throw fatal error ONLY if user strictly ran --with-lua=yes
|
||||
if test "$withval" = "yes"; then
|
||||
AC_MSG_ERROR([Lua support explicitly requested, but compatible Lua 5.3 libs/headers were not found.])
|
||||
else
|
||||
AC_MSG_WARN([Lua 5.3 libs or headers missing. Proceeding without Lua support.])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
],[
|
||||
AC_MSG_RESULT(ignored)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_INOTIFY], [
|
||||
AC_LANG_PUSH(C++)
|
||||
|
||||
AC_CHECK_HEADERS([sys/inotify.h mcheck.h])
|
||||
AC_CHECK_HEADERS([sys/inotify.h])
|
||||
AC_MSG_CHECKING([whether sys/inotify.h actually works])
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <sys/inotify.h>
|
||||
int main(int,const char**) { return (-1 == inotify_init()); }])
|
||||
],[
|
||||
AC_DEFINE(HAVE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
|
||||
AC_DEFINE(USE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
|
||||
AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_RESULT(failed)]
|
||||
)
|
||||
@@ -311,12 +246,14 @@ AC_DEFUN([TORRENT_WITH_INOTIFY], [
|
||||
AC_LANG_POP(C++)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
|
||||
AC_CHECK_HEADERS(pthread.h)
|
||||
|
||||
AC_MSG_CHECKING(for pthread_setname_np type)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
]], [[
|
||||
@@ -341,6 +278,7 @@ AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
|
||||
AC_MSG_CHECKING([for pthread_setname_no])
|
||||
|
||||
@@ -360,6 +298,24 @@ AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP], [
|
||||
AC_MSG_CHECKING(for posix_spawn_file_actions_addclosefrom_np)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#define _GNU_SOURCE
|
||||
#include <spawn.h>
|
||||
]], [[
|
||||
posix_spawn_file_actions_t actions;
|
||||
posix_spawn_file_actions_addclosefrom_np(&actions, 3);
|
||||
]])],[
|
||||
AC_DEFINE(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP, 1, [Define if posix_spawn_file_actions_addclosefrom_np is available.])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_SYSTEMD], [
|
||||
AC_ARG_WITH(systemd,
|
||||
AS_HELP_STRING([--with-systemd],[enable systemd socket activation support [[default=no]]]),
|
||||
@@ -375,3 +331,20 @@ AC_DEFUN([TORRENT_WITH_SYSTEMD], [
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITHOUT_NCURSES], [
|
||||
AC_ARG_WITH([ncurses],
|
||||
[AS_HELP_STRING([--without-ncurses], [build without ncurses (daemon-only mode)])],
|
||||
[with_ncurses=$withval],
|
||||
[with_ncurses=yes])
|
||||
|
||||
if test "x$with_ncurses" = xno; then
|
||||
AC_DEFINE([HAVE_NO_NCURSES], [1], [Define to 1 if building without ncurses])
|
||||
CURSES_LIBS=""
|
||||
CURSES_CFLAGS=""
|
||||
CURSES_LIB=""
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([NO_NCURSES], [test "x$with_ncurses" = xno])
|
||||
])
|
||||
|
||||
+169
-145
@@ -1,67 +1,3 @@
|
||||
AC_DEFUN([TORRENT_WITH_SYSROOT], [
|
||||
AC_ARG_WITH(sysroot,
|
||||
AS_HELP_STRING([--with-sysroot=PATH],
|
||||
[compile and link with a specific sysroot]),
|
||||
[
|
||||
AC_MSG_CHECKING(for sysroot)
|
||||
|
||||
if test "$withval" = "no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
elif test "$withval" = "yes"; then
|
||||
AC_MSG_RESULT(not a path)
|
||||
AC_MSG_ERROR(The sysroot option must point to a directory, like f.ex "/Developer/SDKs/MacOSX10.4u.sdk".)
|
||||
else
|
||||
AC_MSG_RESULT($withval)
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -isysroot $withval"
|
||||
LDFLAGS="$LDFLAGS -Wl,-syslibroot,$withval"
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_REMOVE_UNWANTED],
|
||||
[
|
||||
AC_REQUIRE([AC_PROG_GREP])
|
||||
values_to_check=`for i in $2; do echo $i; done`
|
||||
unwanted_values=`for i in $3; do echo $i; done`
|
||||
if test -z "${unwanted_values}"; then
|
||||
$1="$2"
|
||||
else
|
||||
result=`echo "${values_to_check}" | $GREP -Fvx -- "${unwanted_values}" | $GREP -v '^$'`
|
||||
# join with spaces, squeeze repeats, and trim trailing space
|
||||
$1=$(printf '%s\n' "$result" | tr '\n' ' ' | sed 's/ */ /g; s/ *$//')
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_ARCH], [
|
||||
AC_ARG_ENABLE(arch,
|
||||
AS_HELP_STRING([--enable-arch=ARCH],
|
||||
[comma seprated list of architectures to compile for]),
|
||||
[
|
||||
AC_MSG_CHECKING(for target architectures)
|
||||
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_MSG_ERROR(no arch supplied)
|
||||
|
||||
elif test "$enableval" = "no"; then
|
||||
AC_MSG_RESULT(using default)
|
||||
|
||||
else
|
||||
AC_MSG_RESULT($enableval)
|
||||
|
||||
for i in `IFS=,; echo $enableval`; do
|
||||
CFLAGS="$CFLAGS -march=$i"
|
||||
CXXFLAGS="$CXXFLAGS -march=$i"
|
||||
LDFLAGS="$LDFLAGS -march=$i"
|
||||
done
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING(signedness of mincore parameter)
|
||||
@@ -90,7 +26,7 @@ AC_DEFUN([TORRENT_MINCORE_SIGNEDNESS], [
|
||||
AC_MSG_RESULT(signed)
|
||||
],
|
||||
[
|
||||
AC_MSG_ERROR([failed, do *not* attempt fix this with --disable-mincore unless you are running Win32.])
|
||||
AC_MSG_ERROR([failed, do *not* attempt fix this with --disable-mincore unless you are running Win32 or OpenBSD.])
|
||||
])
|
||||
])
|
||||
|
||||
@@ -144,108 +80,196 @@ AC_DEFUN([TORRENT_CHECK_POSIX_FADVISE], [
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POPCOUNT], [
|
||||
AC_MSG_CHECKING(for __builtin_popcount)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int f() { return __builtin_popcount(0); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(USE_BUILTIN_POPCOUNT, 1, Use __builtin_popcount.)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_CACHELINE], [
|
||||
AC_MSG_CHECKING(for cacheline)
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_MSG_CHECKING([for target cacheline size])
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <stdlib.h>
|
||||
#include <linux/cache.h>
|
||||
void* vptr __cacheline_aligned;
|
||||
void f() { posix_memalign(&vptr, SMP_CACHE_BYTES, 42); }
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(found builtin)
|
||||
dnl Need to fix this so that it uses the stuff defined by the system.
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
# REGION: Linux Kernel Extraction Loop
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <stdlib.h>
|
||||
#include <linux/cache.h>
|
||||
void* vptr;
|
||||
void f() {
|
||||
int res = posix_memalign(&vptr, SMP_CACHE_BYTES, 42);
|
||||
(void)res;
|
||||
}
|
||||
]])],[
|
||||
# We need an explicit variable fallback condition inside AC_COMPUTE_INT
|
||||
AC_COMPUTE_INT([torrent_cv_cacheline_size], [SMP_CACHE_BYTES], [#include <linux/cache.h>], [torrent_cv_cacheline_size=0])
|
||||
|
||||
AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.)
|
||||
], [
|
||||
AC_MSG_RESULT(using default 128 bytes)
|
||||
AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.)
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_ALIGNED], [
|
||||
AC_MSG_CHECKING(the byte alignment)
|
||||
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([
|
||||
#include <inttypes.h>
|
||||
int main() {
|
||||
char buf@<:@8@:>@ = { 0, 0, 0, 0, 1, 0, 0, 0 };
|
||||
int i;
|
||||
for (i = 1; i < 4; ++i)
|
||||
if (*(uint32_t*)(buf + i) == 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[
|
||||
AC_MSG_RESULT(none needed)
|
||||
], [
|
||||
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
|
||||
AC_MSG_RESULT(required)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_ALIGNED], [
|
||||
AC_ARG_ENABLE(aligned,
|
||||
AS_HELP_STRING([--enable-aligned],
|
||||
[enable alignment safe code [[default=check]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_ALIGNED, 1, Require byte alignment)
|
||||
if test "$torrent_cv_cacheline_size" -gt 0; then
|
||||
AC_MSG_RESULT([linux builtin ($torrent_cv_cacheline_size bytes)])
|
||||
AC_DEFINE_UNQUOTED([LT_SMP_CACHE_BYTES], [$torrent_cv_cacheline_size], [System-defined Linux L1 SMP cacheline size.])
|
||||
else
|
||||
# Handle scenarios where macro maps to a complex runtime expression or fails
|
||||
AC_MSG_RESULT([failed to parse SMP_CACHE_BYTES value])
|
||||
AC_MSG_FAILURE([Linux kernel headers found, but cacheline constant could not be computed at compile-time.])
|
||||
fi
|
||||
],[
|
||||
TORRENT_CHECK_ALIGNED
|
||||
])
|
||||
],[
|
||||
# Explicitly validate the CPU type even on Linux if the header check fails
|
||||
case "$host_cpu" in
|
||||
x86_64*|amd64*|i386*|i486*|i586*|i686*)
|
||||
AC_MSG_RESULT([linux fallback x86 64 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux x86 hardware.])
|
||||
;;
|
||||
arm*|aarch64*|powerpc*|ppc*|s390x*)
|
||||
AC_MSG_RESULT([linux fallback enterprise 128 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 128, [Fallback 128-byte alignment for Linux enterprise hardware.])
|
||||
;;
|
||||
riscv32*|riscv64*)
|
||||
AC_MSG_RESULT([linux fallback RISC-V 64 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux RISC-V hardware.])
|
||||
;;
|
||||
loongarch32*|loongarch64*)
|
||||
AC_MSG_RESULT([linux fallback LoongArch 64 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux LoongArch hardware.])
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([unrecognized CPU arch on Linux header fallback])
|
||||
AC_MSG_FAILURE([Unrecognized CPU architecture ($host_cpu) on Linux fallback path. Aborting build.])
|
||||
;;
|
||||
esac
|
||||
])
|
||||
;;
|
||||
|
||||
*)
|
||||
# REGION: Cross-Platform Strict Hardware Mapping (macOS, FreeBSD, OpenBSD, NetBSD)
|
||||
case "$host_cpu" in
|
||||
x86_64*|amd64*|i386*|i486*|i586*|i686*)
|
||||
# Explicit x86 desktop hardware baseline block
|
||||
AC_MSG_RESULT([$host_os ($host_cpu) standard x86 64 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Standard 64-byte alignment for stable x86 hardware layout.])
|
||||
;;
|
||||
arm*|aarch64*|powerpc*|ppc*|s390x*)
|
||||
# Explicit modern enterprise and Apple Silicon hardware baseline block
|
||||
AC_MSG_RESULT([$host_os ($host_cpu) stable enterprise 128 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 128, [Optimized 128-byte alignment for newer high-performance chipsets.])
|
||||
;;
|
||||
*)
|
||||
# STRICT ENFORCEMENT: Fail the build immediately if the CPU isn't explicitly known
|
||||
AC_MSG_RESULT([unrecognized architecture])
|
||||
AC_MSG_FAILURE([The target CPU architecture ($host_cpu) is unrecognized. Aborting configuration to prevent fatal runtime false-sharing or memory misalignment errors.])
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_INSTRUMENTATION], [
|
||||
AC_DEFUN([TORRENT_CHECK_CUSTOM_ENDIAN64], [
|
||||
AC_CHECK_HEADERS([endian.h sys/endian.h libkern/OSByteOrder.h])
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
AH_TEMPLATE([CUSTOM_ENDIAN_HEADER], [The system header to include for endian conversions.])
|
||||
AH_TEMPLATE([custom_ntohll], [Convert 64-bit integer from network to host byte order.])
|
||||
AH_TEMPLATE([custom_htonll], [Convert 64-bit integer from host to network byte order.])
|
||||
|
||||
dnl 1. Initialize our header variable tracking
|
||||
endian_header_file='<stdint.h>'
|
||||
|
||||
dnl 2. Test if native be64toh works natively via <endian.h> (Standard Linux/glibc)
|
||||
AC_MSG_CHECKING([for native be64toh via endian.h])
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([
|
||||
#include <stdint.h>
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h>
|
||||
#endif
|
||||
int main() { uint64_t x = be64toh(1); return 0; }
|
||||
])],
|
||||
[has_native_be64=yes; endian_header_file='<endian.h>'],
|
||||
[has_native_be64=no]
|
||||
)
|
||||
AC_MSG_RESULT([$has_native_be64])
|
||||
|
||||
dnl 3. If missing, test if it works via <sys/endian.h> (True BSD systems like FreeBSD)
|
||||
if test "$has_native_be64" = "no"; then
|
||||
AC_MSG_CHECKING([for native be64toh via sys/endian.h])
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([
|
||||
#include <stdint.h>
|
||||
#ifdef HAVE_SYS_ENDIAN_H
|
||||
# include <sys/endian.h>
|
||||
#endif
|
||||
int main() { uint64_t x = be64toh(1); return 0; }
|
||||
])],
|
||||
[has_native_be64=yes; endian_header_file='<sys/endian.h>'],
|
||||
[has_native_be64=no]
|
||||
)
|
||||
AC_MSG_RESULT([$has_native_be64])
|
||||
fi
|
||||
|
||||
dnl 4. Route definitions cleanly based on actual testing results
|
||||
if test "$has_native_be64" = "yes"; then
|
||||
dnl Linux or true BSD environment
|
||||
AC_DEFINE_UNQUOTED([CUSTOM_ENDIAN_HEADER], [$endian_header_file], [The header containing native endian macros.])
|
||||
AC_DEFINE([custom_ntohll(x)], [(be64toh(x))], [Use native platform be64toh])
|
||||
AC_DEFINE([custom_htonll(x)], [(htobe64(x))], [Use native platform htobe64])
|
||||
else
|
||||
dnl Fallback block: Check if we are on macOS using Apple's optimized hardware libraries
|
||||
if test "$ac_cv_header_libkern_OSByteOrder_h" = "yes"; then
|
||||
AC_DEFINE([CUSTOM_ENDIAN_HEADER], [<libkern/OSByteOrder.h>], [The header containing native endian macros.])
|
||||
AC_DEFINE([custom_ntohll(x)], [(OSSwapBigToHostInt64(x))], [Map missing be64toh to macOS native swap])
|
||||
AC_DEFINE([custom_htonll(x)], [(OSSwapHostToBigInt64(x))], [Map missing htobe64 to macOS native swap])
|
||||
else
|
||||
dnl Fallback for platforms with no built-in architecture macros (compiler built-ins)
|
||||
AC_DEFINE([CUSTOM_ENDIAN_HEADER], [<stdint.h>], [The header containing native endian macros.])
|
||||
if test "$ac_cv_c_bigendian" = "yes"; then
|
||||
AC_DEFINE([custom_ntohll(x)], [((uint64_t)(x))], [Fallback 64-bit conversion.])
|
||||
AC_DEFINE([custom_htonll(x)], [((uint64_t)(x))], [Fallback 64-bit conversion.])
|
||||
else
|
||||
AC_DEFINE([custom_ntohll(x)], [(__builtin_bswap64((uint64_t)(x)))], [Fallback 64-bit conversion.])
|
||||
AC_DEFINE([custom_htonll(x)], [(__builtin_bswap64((uint64_t)(x)))], [Fallback 64-bit conversion.])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_INSTRUMENTATION], [
|
||||
AC_MSG_CHECKING([if instrumentation should be included])
|
||||
|
||||
AC_ARG_ENABLE(instrumentation,
|
||||
AS_HELP_STRING([--disable-instrumentation],
|
||||
[disable instrumentation [[default=enabled]]]),
|
||||
AS_HELP_STRING([--enable-instrumentation],
|
||||
[enable instrumentation [[default=disabled]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
],[
|
||||
AC_DEFINE(LT_INSTRUMENTATION, 1, enable instrumentation)
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_ENABLE_INTERRUPT_SOCKET], [
|
||||
AC_ARG_ENABLE(interrupt-socket,
|
||||
AS_HELP_STRING([--enable-interrupt-socket],
|
||||
[enable interrupt socket [[default=no]]]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_DEFINE(USE_INTERRUPT_SOCKET, 1, Use interrupt socket instead of pthread_kill)
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_DEFUN([TORRENT_ENABLE_CUSTOM_STACK_SIZE], [
|
||||
AC_ARG_ENABLE([pthread-setstacksize],
|
||||
[AS_HELP_STRING([--enable-pthread-setstacksize], [explicitly set pthread stack size (auto-enabled for musl)])],
|
||||
[enable_pthread_setstacksize=$enableval],
|
||||
[enable_pthread_setstacksize=auto])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
if test "x$enable_pthread_setstacksize" = "xauto"; then
|
||||
case "$host" in
|
||||
*-musl*)
|
||||
enable_pthread_setstacksize=yes
|
||||
;;
|
||||
*)
|
||||
enable_pthread_setstacksize=no
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "x$enable_pthread_setstacksize" = "xyes"; then
|
||||
AC_DEFINE([USE_PTHREAD_SETSTACKSIZE], [1], [Use explicit pthread stack size])
|
||||
AC_DEFINE([DEFAULT_PTHREAD_STACKSIZE], [(8 * 1024 * 1024)], [Default pthread stack size in bytes])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_DISABLE_IPV6], [
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AS_HELP_STRING([--enable-ipv6],
|
||||
|
||||
@@ -174,6 +174,10 @@ libsub_root_a_SOURCES = \
|
||||
utils/list_focus.h \
|
||||
utils/lockfile.cc \
|
||||
utils/lockfile.h \
|
||||
utils/waitpid_queue.cc \
|
||||
utils/waitpid_queue.h \
|
||||
utils/watch_ready_queue.cc \
|
||||
utils/watch_ready_queue.h \
|
||||
\
|
||||
command_download.cc \
|
||||
command_dynamic.cc \
|
||||
@@ -203,4 +207,8 @@ libsub_root_a_SOURCES = \
|
||||
signal_handler.h
|
||||
|
||||
|
||||
if NO_NCURSES
|
||||
libsub_root_a_SOURCES += display/curses_stub.cc display/curses_stub.h
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -DPACKAGE_DATADIR=\"$(pkgdatadir)\"
|
||||
|
||||
+102
-67
@@ -5,11 +5,10 @@
|
||||
#include <functional>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <rak/regex.h>
|
||||
#include <fnmatch.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/tracker/tracker.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/data/download_data.h>
|
||||
#include <torrent/data/file.h>
|
||||
#include <torrent/data/file_list.h>
|
||||
@@ -18,6 +17,7 @@
|
||||
#include <torrent/net/types.h>
|
||||
#include <torrent/peer/connection_list.h>
|
||||
#include <torrent/peer/peer_list.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/utils/file_stat.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
@@ -32,31 +32,34 @@
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
std::string
|
||||
torrent::string_utf8
|
||||
retrieve_d_base_path(core::Download* download) {
|
||||
if (download->file_list()->is_multi_file())
|
||||
return download->file_list()->frozen_root_dir();
|
||||
else
|
||||
return download->file_list()->empty() ? std::string() : download->file_list()->at(0)->frozen_path();
|
||||
|
||||
if (download->file_list()->empty())
|
||||
return {};
|
||||
|
||||
return download->file_list()->at(0)->frozen_path();
|
||||
}
|
||||
|
||||
std::string
|
||||
torrent::string_utf8
|
||||
retrieve_d_base_filename(core::Download* download) {
|
||||
const std::string* base;
|
||||
torrent::string_utf8 base_path;
|
||||
|
||||
if (download->file_list()->is_multi_file())
|
||||
base = &download->file_list()->frozen_root_dir();
|
||||
else if (download->file_list()->empty())
|
||||
return std::string();
|
||||
base_path = download->file_list()->frozen_root_dir();
|
||||
else if (!download->file_list()->empty())
|
||||
base_path = download->file_list()->at(0)->frozen_path();
|
||||
else
|
||||
base = &download->file_list()->at(0)->frozen_path();
|
||||
return {};
|
||||
|
||||
std::string::size_type split = base->rfind('/');
|
||||
auto split = base_path.str().rfind('/');
|
||||
|
||||
if (split == std::string::npos)
|
||||
return *base;
|
||||
else
|
||||
return base->substr(split + 1);
|
||||
return base_path;
|
||||
|
||||
return torrent::string_utf8::from_string(base_path.str().substr(split + 1));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -144,9 +147,9 @@ apply_d_directory(core::Download* download, const std::string& name) {
|
||||
if (!download->file_list()->is_multi_file())
|
||||
download->set_root_directory(name);
|
||||
else if (name.empty() || *name.rbegin() == '/')
|
||||
download->set_root_directory(name + download->info()->name());
|
||||
download->set_root_directory(name + download->info()->name().str());
|
||||
else
|
||||
download->set_root_directory(name + "/" + download->info()->name());
|
||||
download->set_root_directory(name + "/" + download->info()->name().str());
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -160,8 +163,8 @@ apply_d_connection_type(core::Download* download, const std::string& name) {
|
||||
|
||||
torrent::Object
|
||||
apply_d_choke_heuristics(core::Download* download, const std::string& name, bool is_down) {
|
||||
torrent::Download::HeuristicType t =
|
||||
(torrent::Download::HeuristicType)torrent::option_find_string(torrent::OPTION_CHOKE_HEURISTICS, name.c_str());
|
||||
torrent::heuristics_enum t =
|
||||
static_cast<torrent::heuristics_enum>(torrent::option_find_string(torrent::OPTION_CHOKE_HEURISTICS, name.c_str()));
|
||||
|
||||
if (is_down)
|
||||
download->download()->set_download_choke_heuristic(t);
|
||||
@@ -271,16 +274,6 @@ retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::O
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_bitfield(core::Download* download) {
|
||||
const torrent::Bitfield* bitField = download->download()->file_list()->bitfield();
|
||||
|
||||
if (bitField->empty())
|
||||
return torrent::Object("");
|
||||
|
||||
return torrent::Object(torrent::utils::transform_to_hex_str(*bitField));
|
||||
}
|
||||
|
||||
void
|
||||
apply_d_add_peer(core::Download* download, const std::string& arg) {
|
||||
int port, ret;
|
||||
@@ -305,8 +298,10 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
|
||||
|
||||
assert(std::this_thread::get_id() == torrent::main_thread::thread_id());
|
||||
|
||||
auto callback_id = torrent::system::make_callback_id();
|
||||
|
||||
// Currently discarding SOCK_STREAM.
|
||||
torrent::this_thread::resolver()->resolve_preferred(NULL, host, AF_UNSPEC, AF_INET, [download, port](torrent::c_sa_shared_ptr sa, int err) {
|
||||
torrent::this_thread::resolver()->resolve_preferred(callback_id, host, AF_UNSPEC, AF_INET, [download, port](torrent::c_sa_shared_ptr sa, int err) {
|
||||
if (sa == nullptr) {
|
||||
lt_log_print(torrent::LOG_TORRENT_WARN, "could not resolve hostname for added peer: %s", gai_strerror(err));
|
||||
return;
|
||||
@@ -345,7 +340,7 @@ f_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
std::vector<rak::regex> regex_list;
|
||||
std::vector<std::string> regex_list;
|
||||
|
||||
bool use_regex = true;
|
||||
|
||||
@@ -359,7 +354,7 @@ f_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
|
||||
for (const auto& file : *download->file_list()) {
|
||||
if (use_regex &&
|
||||
std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& r) { return r(file->path()->as_string()); }))
|
||||
std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& pattern) { return fnmatch(pattern.c_str(), file->path()->as_string().c_str(), 0) == 0; }))
|
||||
continue;
|
||||
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
@@ -383,18 +378,19 @@ t_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object result_raw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = result_raw.as_list();
|
||||
|
||||
auto result_raw = torrent::Object::create_list();
|
||||
auto& result = result_raw.as_list();
|
||||
|
||||
for (uint32_t idx = 0, last = download->tracker_list_size(); idx < last; idx++) {
|
||||
auto& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
auto& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
auto tracker = download->tracker_controller().at(idx);
|
||||
|
||||
if (!tracker.is_valid())
|
||||
continue;
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
auto& cmd = cItr->as_string();
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(&tracker), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
@@ -413,13 +409,13 @@ p_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
|
||||
// Add some pre-parsing of the commands, so we don't spend time
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
auto resultRaw = torrent::Object::create_list();
|
||||
auto& result = resultRaw.as_list();
|
||||
|
||||
for (const auto& connection : *download->connection_list()) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(connection), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
@@ -648,30 +644,48 @@ void cg_d_group_set(core::Download* download, const torrent::Objec
|
||||
|
||||
void
|
||||
initialize_command_download() {
|
||||
CMD2_DL("d.hash", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->hash()); });
|
||||
CMD2_DL("d.local_id", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->local_id()); });
|
||||
CMD2_DL("d.local_id_html", [](auto* download, auto) { return torrent::utils::copy_escape_html_str(download->info()->local_id()); });
|
||||
CMD2_DL("d.bitfield", std::bind(&retrieve_d_bitfield, std::placeholders::_1));
|
||||
CMD2_DL("d.base_path", std::bind(&retrieve_d_base_path, std::placeholders::_1));
|
||||
CMD2_DL("d.base_filename", std::bind(&retrieve_d_base_filename, std::placeholders::_1));
|
||||
CMD2_DL("d.hash", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->hash()); });
|
||||
CMD2_DL("d.local_id", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->local_id()); });
|
||||
CMD2_DL("d.local_id_html", [](auto* download, auto) { return torrent::utils::copy_escape_html_str(download->info()->local_id()); });
|
||||
CMD2_DL("d.bitfield", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(*download->download()->file_list()->bitfield()); });
|
||||
CMD2_DL("d.base_path", [](auto* download, auto) { return retrieve_d_base_path(download).str(); });
|
||||
CMD2_DL("d.base_path.hex", [](auto* download, auto) { return retrieve_d_base_path(download).object_hex(); });
|
||||
CMD2_DL("d.base_path.base64", [](auto* download, auto) { return retrieve_d_base_path(download).object_base64(); });
|
||||
CMD2_DL("d.base_path.base64_as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_base64_as_binary(); });
|
||||
CMD2_DL("d.base_path.as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_as_binary(); });
|
||||
CMD2_DL("d.base_path.or_base64", [](auto* download, auto) { return retrieve_d_base_path(download).object_utf8_or_base64(); });
|
||||
CMD2_DL("d.base_path.or_as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_utf8_or_as_binary(); });
|
||||
CMD2_DL("d.base_filename", [](auto* download, auto) { return retrieve_d_base_filename(download).str(); });
|
||||
CMD2_DL("d.base_filename.hex", [](auto* download, auto) { return retrieve_d_base_filename(download).object_hex(); });
|
||||
CMD2_DL("d.base_filename.base64", [](auto* download, auto) { return retrieve_d_base_filename(download).object_base64(); });
|
||||
CMD2_DL("d.base_filename.base64_as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_base64_as_binary(); });
|
||||
CMD2_DL("d.base_filename.as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_as_binary(); });
|
||||
CMD2_DL("d.base_filename.or_base64", [](auto* download, auto) { return retrieve_d_base_filename(download).object_utf8_or_base64(); });
|
||||
CMD2_DL("d.base_filename.or_as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_utf8_or_as_binary(); });
|
||||
|
||||
CMD2_DL("d.name", CMD2_ON_INFO(name));
|
||||
CMD2_DL("d.creation_date", CMD2_ON_INFO(creation_date));
|
||||
CMD2_DL("d.load_date", CMD2_ON_INFO(load_date));
|
||||
CMD2_DL("d.name", [](auto* download, auto) { return download->info()->name().str(); });
|
||||
CMD2_DL("d.name.hex", [](auto* download, auto) { return download->info()->name().object_hex(); });
|
||||
CMD2_DL("d.name.base64", [](auto* download, auto) { return download->info()->name().object_base64(); });
|
||||
CMD2_DL("d.name.base64_as_binary", [](auto* download, auto) { return download->info()->name().object_base64_as_binary(); });
|
||||
CMD2_DL("d.name.as_binary", [](auto* download, auto) { return download->info()->name().object_as_binary(); });
|
||||
CMD2_DL("d.name.or_base64", [](auto* download, auto) { return download->info()->name().object_utf8_or_base64(); });
|
||||
CMD2_DL("d.name.or_as_binary", [](auto* download, auto) { return download->info()->name().object_utf8_or_as_binary(); });
|
||||
CMD2_DL("d.creation_date", [](auto* download, auto) { return download->info()->creation_date(); });
|
||||
CMD2_DL("d.load_date", [](auto* download, auto) { return download->info()->load_date(); });
|
||||
|
||||
//
|
||||
// Network related:
|
||||
//
|
||||
|
||||
CMD2_DL ("d.up.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(up_rate)));
|
||||
CMD2_DL ("d.up.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(up_rate)));
|
||||
CMD2_DL ("d.down.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(down_rate)));
|
||||
CMD2_DL ("d.down.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(down_rate)));
|
||||
CMD2_DL ("d.skip.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(skip_rate)));
|
||||
CMD2_DL ("d.skip.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(skip_rate)));
|
||||
CMD2_DL ("d.up.rate", [](auto* download, auto) { return download->info()->up_rate()->rate(); });
|
||||
CMD2_DL ("d.up.total", [](auto* download, auto) { return download->info()->up_rate()->total(); });
|
||||
CMD2_DL ("d.down.rate", [](auto* download, auto) { return download->info()->down_rate()->rate(); });
|
||||
CMD2_DL ("d.down.total", [](auto* download, auto) { return download->info()->down_rate()->total(); });
|
||||
CMD2_DL ("d.skip.rate", [](auto* download, auto) { return download->info()->skip_rate()->rate(); });
|
||||
CMD2_DL ("d.skip.total", [](auto* download, auto) { return download->info()->skip_rate()->total(); });
|
||||
|
||||
CMD2_DL ("d.peer_exchange", CMD2_ON_INFO(is_pex_enabled));
|
||||
CMD2_DL_VALUE_V ("d.peer_exchange.set", std::bind(&torrent::Download::set_pex_enabled, CMD2_BIND_DL, std::placeholders::_2));
|
||||
CMD2_DL ("d.peer_exchange", [](auto* download, auto) { return download->info()->is_pex_enabled(); });
|
||||
CMD2_DL_VALUE_V ("d.peer_exchange.set", [](auto* download, auto value) { download->download()->set_pex_enabled(value); });
|
||||
|
||||
CMD2_DL_LIST ("d.create_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_DL_LIST ("d.delete_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 1));
|
||||
@@ -687,16 +701,16 @@ initialize_command_download() {
|
||||
// Control functinos:
|
||||
//
|
||||
|
||||
CMD2_DL ("d.is_open", CMD2_ON_INFO(is_open));
|
||||
CMD2_DL ("d.is_active", CMD2_ON_INFO(is_active));
|
||||
CMD2_DL ("d.is_open", [](auto* download, auto) { return download->info()->is_open(); });
|
||||
CMD2_DL ("d.is_active", [](auto* download, auto) { return download->info()->is_active(); });
|
||||
CMD2_DL ("d.is_hash_checked", std::bind(&torrent::Download::is_hash_checked, CMD2_BIND_DL));
|
||||
CMD2_DL ("d.is_hash_checking", std::bind(&torrent::Download::is_hash_checking, CMD2_BIND_DL));
|
||||
CMD2_DL ("d.is_multi_file", std::bind(&torrent::FileList::is_multi_file, CMD2_BIND_FL));
|
||||
CMD2_DL ("d.is_private", CMD2_ON_INFO(is_private));
|
||||
CMD2_DL ("d.is_pex_active", CMD2_ON_INFO(is_pex_active));
|
||||
CMD2_DL ("d.is_private", [](auto* download, auto) { return download->info()->is_private(); });
|
||||
CMD2_DL ("d.is_pex_active", [](auto* download, auto) { return download->info()->is_pex_active(); });
|
||||
CMD2_DL ("d.is_partially_done", CMD2_ON_DATA(is_partially_done));
|
||||
CMD2_DL ("d.is_not_partially_done", CMD2_ON_DATA(is_not_partially_done));
|
||||
CMD2_DL ("d.is_meta", CMD2_ON_INFO(is_meta_download));
|
||||
CMD2_DL ("d.is_meta", [](auto* download, auto) { return download->info()->is_meta_download(); });
|
||||
|
||||
CMD2_DL_V ("d.resume", std::bind(&core::DownloadList::resume_default, control->core()->download_list(), std::placeholders::_1));
|
||||
CMD2_DL_V ("d.pause", std::bind(&core::DownloadList::pause_default, control->core()->download_list(), std::placeholders::_1));
|
||||
@@ -767,15 +781,15 @@ initialize_command_download() {
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.started", "rtorrent", "timestamp.started");
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.finished", "rtorrent", "timestamp.finished");
|
||||
|
||||
CMD2_DL ("d.connection_current", std::bind(&torrent::option_as_string, torrent::OPTION_CONNECTION_TYPE, CMD2_ON_DL(connection_type)));
|
||||
CMD2_DL_STRING("d.connection_current.set", std::bind(&apply_d_connection_type, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL ("d.connection_current", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CONNECTION_TYPE, d->download()->connection_type()); });
|
||||
CMD2_DL_STRING_V("d.connection_current.set", [](auto* d, auto arg) { apply_d_connection_type(d, arg); });
|
||||
|
||||
CMD2_DL_VAR_STRING("d.connection_leech", "rtorrent", "connection_leech");
|
||||
CMD2_DL_VAR_STRING("d.connection_seed", "rtorrent", "connection_seed");
|
||||
|
||||
CMD2_DL ("d.up.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(upload_choke_heuristic)));
|
||||
CMD2_DL ("d.up.choke_heuristics", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, d->download()->upload_choke_heuristic()); });
|
||||
CMD2_DL_STRING("d.up.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, false));
|
||||
CMD2_DL ("d.down.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(download_choke_heuristic)));
|
||||
CMD2_DL ("d.down.choke_heuristics", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, d->download()->download_choke_heuristic()); });
|
||||
CMD2_DL_STRING("d.down.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, true));
|
||||
|
||||
CMD2_DL_VAR_STRING("d.up.choke_heuristics.leech", "rtorrent", "choke_heuristics.up.leech");
|
||||
@@ -830,7 +844,7 @@ initialize_command_download() {
|
||||
CMD2_DL ("d.bytes_done", CMD2_ON_DL(bytes_done));
|
||||
CMD2_DL ("d.ratio", std::bind(&retrieve_d_ratio, std::placeholders::_1));
|
||||
CMD2_DL ("d.chunks_hashed", CMD2_ON_DL(chunks_hashed));
|
||||
CMD2_DL ("d.free_diskspace", CMD2_ON_FL(free_diskspace));
|
||||
CMD2_DL ("d.free_diskspace", [](auto* download, auto) { return download->file_list()->free_diskspace_no_cache(); });
|
||||
|
||||
CMD2_DL ("d.size_files", CMD2_ON_FL(size_files));
|
||||
CMD2_DL ("d.size_bytes", CMD2_ON_FL(size_bytes));
|
||||
@@ -898,8 +912,26 @@ initialize_command_download() {
|
||||
rpc::rpc.mark_safe("d.local_id_html");
|
||||
rpc::rpc.mark_safe("d.bitfield");
|
||||
rpc::rpc.mark_safe("d.base_path");
|
||||
rpc::rpc.mark_safe("d.base_path.hex");
|
||||
rpc::rpc.mark_safe("d.base_path.base64");
|
||||
rpc::rpc.mark_safe("d.base_path.base64_as_binary");
|
||||
rpc::rpc.mark_safe("d.base_path.as_binary");
|
||||
rpc::rpc.mark_safe("d.base_path.or_base64");
|
||||
rpc::rpc.mark_safe("d.base_path.or_as_binary");
|
||||
rpc::rpc.mark_safe("d.base_filename");
|
||||
rpc::rpc.mark_safe("d.base_filename.hex");
|
||||
rpc::rpc.mark_safe("d.base_filename.base64");
|
||||
rpc::rpc.mark_safe("d.base_filename.base64_as_binary");
|
||||
rpc::rpc.mark_safe("d.base_filename.as_binary");
|
||||
rpc::rpc.mark_safe("d.base_filename.or_base64");
|
||||
rpc::rpc.mark_safe("d.base_filename.or_as_binary");
|
||||
rpc::rpc.mark_safe("d.name");
|
||||
rpc::rpc.mark_safe("d.name.hex");
|
||||
rpc::rpc.mark_safe("d.name.base64");
|
||||
rpc::rpc.mark_safe("d.name.base64_as_binary");
|
||||
rpc::rpc.mark_safe("d.name.as_binary");
|
||||
rpc::rpc.mark_safe("d.name.or_base64");
|
||||
rpc::rpc.mark_safe("d.name.or_as_binary");
|
||||
rpc::rpc.mark_safe("d.directory");
|
||||
rpc::rpc.mark_safe("d.directory_base");
|
||||
rpc::rpc.mark_safe("d.creation_date");
|
||||
@@ -941,6 +973,9 @@ initialize_command_download() {
|
||||
rpc::rpc.mark_safe("d.size_chunks");
|
||||
rpc::rpc.mark_safe("d.size_pex");
|
||||
rpc::rpc.mark_safe("d.completed_bytes");
|
||||
rpc::rpc.mark_safe("d.complete");
|
||||
rpc::rpc.mark_safe("d.timestamp.started");
|
||||
rpc::rpc.mark_safe("d.timestamp.finished");
|
||||
rpc::rpc.mark_safe("d.bytes_done");
|
||||
rpc::rpc.mark_safe("d.peers_accounted");
|
||||
rpc::rpc.mark_safe("d.chunks_hashed");
|
||||
|
||||
+16
-10
@@ -444,16 +444,20 @@ initialize_command_dynamic() {
|
||||
|
||||
CMD2_ANY ("catch", std::bind(&cmd_catch, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("strings.choke_heuristics", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS));
|
||||
CMD2_ANY ("strings.choke_heuristics.upload", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_UPLOAD));
|
||||
CMD2_ANY ("strings.choke_heuristics.download", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD));
|
||||
CMD2_ANY ("strings.connection_type", std::bind(&torrent::option_list_strings, torrent::OPTION_CONNECTION_TYPE));
|
||||
CMD2_ANY ("strings.encryption", std::bind(&torrent::option_list_strings, torrent::OPTION_ENCRYPTION));
|
||||
CMD2_ANY ("strings.ip_filter", std::bind(&torrent::option_list_strings, torrent::OPTION_IP_FILTER));
|
||||
CMD2_ANY ("strings.ip_tos", std::bind(&torrent::option_list_strings, torrent::OPTION_IP_TOS));
|
||||
CMD2_ANY ("strings.log_group", std::bind(&torrent::option_list_strings, torrent::OPTION_LOG_GROUP));
|
||||
CMD2_ANY ("strings.tracker_event", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_EVENT));
|
||||
CMD2_ANY ("strings.tracker_mode", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_MODE));
|
||||
CMD2_ANY_STRING ("enum.log_group", [](auto, const auto& str) { return torrent::option_find_string_str(torrent::OPTION_LOG_GROUP, str); });
|
||||
|
||||
CMD2_ANY ("strings.choke_heuristics", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS); });
|
||||
CMD2_ANY ("strings.choke_heuristics.upload", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS_UPLOAD); });
|
||||
CMD2_ANY ("strings.choke_heuristics.download", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD); });
|
||||
CMD2_ANY ("strings.connection_type", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CONNECTION_TYPE); });
|
||||
CMD2_ANY ("strings.encryption", [](auto, auto) { return torrent::Object::create_list(); });
|
||||
CMD2_ANY ("strings.encryption.handshake", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_ENCRYPTION_HANDSHAKE); });
|
||||
CMD2_ANY ("strings.encryption.stream", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_ENCRYPTION_STREAM); });
|
||||
CMD2_ANY ("strings.ip_filter", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_IP_FILTER); });
|
||||
CMD2_ANY ("strings.ip_tos", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_IP_TOS); });
|
||||
CMD2_ANY ("strings.log_group", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_LOG_GROUP); });
|
||||
CMD2_ANY ("strings.tracker_event", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_TRACKER_EVENT); });
|
||||
CMD2_ANY ("strings.tracker_mode", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_TRACKER_MODE); });
|
||||
// clang-format on
|
||||
|
||||
#ifdef HAVE_XMLRPC_TINYXML2
|
||||
@@ -468,6 +472,8 @@ initialize_command_dynamic() {
|
||||
rpc::rpc.mark_safe("method.rlookup");
|
||||
rpc::rpc.mark_safe("catch");
|
||||
|
||||
rpc::rpc.mark_safe("enum.log_group");
|
||||
|
||||
rpc::rpc.mark_safe("strings.choke_heuristics");
|
||||
rpc::rpc.mark_safe("strings.choke_heuristics.upload");
|
||||
rpc::rpc.mark_safe("strings.choke_heuristics.download");
|
||||
|
||||
+61
-39
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/hash_string.h>
|
||||
#include <torrent/utils/log.h>
|
||||
@@ -19,6 +21,7 @@
|
||||
#include "rpc/command_scheduler.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "utils/watch_ready_queue.h"
|
||||
|
||||
torrent::Object
|
||||
apply_on_ratio(const torrent::Object& rawArgs) {
|
||||
@@ -165,12 +168,14 @@ torrent::Object
|
||||
apply_close_low_diskspace(int64_t arg, uint32_t skip_priority) {
|
||||
bool closed = false;
|
||||
|
||||
torrent::FileList::cache_list cache;
|
||||
|
||||
for (auto download : *control->core()->download_list()) {
|
||||
if (!download->is_downloading())
|
||||
continue;
|
||||
if (download->priority() >= skip_priority)
|
||||
continue;
|
||||
if (download->file_list()->free_diskspace() >= (uint64_t)arg)
|
||||
if (download->file_list()->free_diskspace(cache) >= (uint64_t)arg)
|
||||
continue;
|
||||
|
||||
control->core()->download_list()->close(download);
|
||||
@@ -253,11 +258,12 @@ torrent::Object
|
||||
d_multicall_filtered(const torrent::Object::list_type& args) {
|
||||
if (args.size() < 2)
|
||||
throw torrent::input_error("d.multicall.filtered requires at least 2 arguments.");
|
||||
torrent::Object::list_const_iterator arg = args.begin();
|
||||
|
||||
auto arg = args.begin();
|
||||
|
||||
// Find the given view
|
||||
core::ViewManager* viewManager = control->view_manager();
|
||||
core::ViewManager::iterator view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
|
||||
auto* viewManager = control->view_manager();
|
||||
auto view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
|
||||
|
||||
if (view_itr == viewManager->end())
|
||||
throw torrent::input_error("Could not find view '" + arg->as_string() + "'.");
|
||||
@@ -267,8 +273,9 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
|
||||
(*view_itr)->filter_by(*++arg, dlist);
|
||||
|
||||
// Generate result by iterating over all items
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
auto resultRaw = torrent::Object::create_list();
|
||||
auto& result = resultRaw.as_list();
|
||||
|
||||
++arg; // skip to first command
|
||||
|
||||
for (const auto& item : dlist) {
|
||||
@@ -291,59 +298,74 @@ call_watch_command(const std::string& command, const std::string& path) {
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
directory_watch_added(const torrent::Object::list_type& args) {
|
||||
directory_watch(const torrent::Object::list_type& args, int flags) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
auto& path = args.front().as_string();
|
||||
auto& command = args.back().as_string();
|
||||
std::string expanded_path = expand_path(path);
|
||||
|
||||
if (!control->directory_events()->open())
|
||||
throw torrent::input_error("Could not open inotify:" + std::string(std::strerror(errno)));
|
||||
|
||||
control->directory_events()->notify_on(path.c_str(),
|
||||
torrent::directory_events::flag_on_added | torrent::directory_events::flag_on_updated,
|
||||
std::bind(&call_watch_command, command, std::placeholders::_1));
|
||||
torrent::watch_descriptor::slot_string slot =
|
||||
flags == torrent::directory_events::flag_on_ready ?
|
||||
torrent::watch_descriptor::slot_string([command](const auto& arg) { control->watch_ready_queue()->push(command, arg); }) :
|
||||
torrent::watch_descriptor::slot_string(std::bind(&call_watch_command, command, std::placeholders::_1));
|
||||
|
||||
control->directory_events()->notify_on(expanded_path.c_str(), flags, slot);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
directory_watch_added(const torrent::Object::list_type& args) {
|
||||
return directory_watch(args,
|
||||
torrent::directory_events::flag_on_added |
|
||||
torrent::directory_events::flag_on_updated);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
directory_watch_ready(const torrent::Object::list_type& args) {
|
||||
return directory_watch(args,
|
||||
torrent::directory_events::flag_on_ready);
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_events() {
|
||||
CMD2_ANY_STRING ("on_ratio", std::bind(&apply_on_ratio, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("on_ratio", [](auto, auto& args) { return apply_on_ratio(args); });
|
||||
|
||||
CMD2_ANY ("start_tied", std::bind(&apply_start_tied));
|
||||
CMD2_ANY ("stop_untied", std::bind(&apply_stop_untied));
|
||||
CMD2_ANY ("close_untied", std::bind(&apply_close_untied));
|
||||
CMD2_ANY ("remove_untied", std::bind(&apply_remove_untied));
|
||||
CMD2_ANY ("start_tied", [](auto, auto) { return apply_start_tied(); });
|
||||
CMD2_ANY ("stop_untied", [](auto, auto) { return apply_stop_untied(); });
|
||||
CMD2_ANY ("close_untied", [](auto, auto) { return apply_close_untied(); });
|
||||
CMD2_ANY ("remove_untied", [](auto, auto) { return apply_remove_untied(); });
|
||||
|
||||
// TODO: Deprecate schedule2 in the future.
|
||||
CMD2_ANY_LIST ("schedule", std::bind(&apply_schedule, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("schedule2", std::bind(&apply_schedule, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("schedule.remove", std::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("schedule_remove2", std::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("schedule", [](auto, auto& args) { return apply_schedule(args); });
|
||||
CMD2_ANY_STRING_V("schedule.remove", [](auto, auto& str) { return control->command_scheduler()->erase_str(str); });
|
||||
|
||||
CMD2_ANY_STRING_V("import", std::bind(&apply_import, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("try_import", std::bind(&apply_try_import, std::placeholders::_2));
|
||||
CMD2_ANY_STRING_V("import", [](auto, auto& str) { return apply_import(str); });
|
||||
CMD2_ANY_STRING_V("try_import", [](auto, auto& str) { return apply_try_import(str); });
|
||||
|
||||
CMD2_ANY_LIST ("load.normal", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied));
|
||||
CMD2_ANY_LIST ("load.verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_tied));
|
||||
CMD2_ANY_LIST ("load.start", std::bind(&apply_load, std::placeholders::_2,
|
||||
core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start));
|
||||
CMD2_ANY_LIST ("load.start_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_tied | core::Manager::create_start));
|
||||
CMD2_ANY_LIST ("load.raw", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_quiet | core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_start", std::bind(&apply_load, std::placeholders::_2,
|
||||
core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.raw_start_verbose", std::bind(&apply_load, std::placeholders::_2, core::Manager::create_start | core::Manager::create_raw_data));
|
||||
CMD2_ANY_LIST ("load.normal", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied); });
|
||||
CMD2_ANY_LIST ("load.verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied); });
|
||||
CMD2_ANY_LIST ("load.start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start); });
|
||||
CMD2_ANY_LIST ("load.start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied | core::Manager::create_start); });
|
||||
CMD2_ANY_LIST ("load.raw", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
|
||||
CMD2_ANY_LIST ("load.raw_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_raw_data); });
|
||||
CMD2_ANY_LIST ("load.raw_start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
|
||||
CMD2_ANY_LIST ("load.raw_start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_start | core::Manager::create_raw_data); });
|
||||
|
||||
CMD2_ANY_VALUE ("close_low_diskspace", std::bind(&apply_close_low_diskspace, std::placeholders::_2, 99));
|
||||
CMD2_ANY_VALUE ("close_low_diskspace.normal", std::bind(&apply_close_low_diskspace, std::placeholders::_2, 3));
|
||||
CMD2_ANY_VALUE ("close_low_diskspace", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 99); });
|
||||
CMD2_ANY_VALUE ("close_low_diskspace.normal", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 3); });
|
||||
|
||||
CMD2_ANY_LIST ("download_list", std::bind(&apply_download_list, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("d.multicall2", std::bind(&d_multicall, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("d.multicall.filtered", std::bind(&d_multicall_filtered, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("download_list", [](auto, auto& args) { return apply_download_list(args); });
|
||||
|
||||
CMD2_ANY_LIST ("directory.watch.added", std::bind(&directory_watch_added, std::placeholders::_2));
|
||||
// TODO: Deprecate d.multicall2. (6/2026)
|
||||
CMD2_ANY_LIST ("d.multicall", [](auto, auto& args) { return d_multicall(args); });
|
||||
CMD2_ANY_LIST ("d.multicall.filtered", [](auto, auto& args) { return d_multicall_filtered(args); });
|
||||
|
||||
CMD2_ANY_LIST ("directory.watch.added", [](auto, auto& args) { return directory_watch_added(args); });
|
||||
CMD2_ANY_LIST ("directory.watch.ready", [](auto, auto& args) { return directory_watch_ready(args); });
|
||||
|
||||
rpc::rpc.mark_safe("start_tied");
|
||||
rpc::rpc.mark_safe("stop_untied");
|
||||
@@ -353,6 +375,6 @@ initialize_command_events() {
|
||||
rpc::rpc.mark_safe("close_low_diskspace");
|
||||
rpc::rpc.mark_safe("close_low_diskspace.normal");
|
||||
rpc::rpc.mark_safe("download_list");
|
||||
rpc::rpc.mark_safe("d.multicall2");
|
||||
rpc::rpc.mark_safe("d.multicall");
|
||||
rpc::rpc.mark_safe("d.multicall.filtered");
|
||||
}
|
||||
|
||||
+50
-23
@@ -24,24 +24,34 @@ apply_f_path(torrent::File* file) {
|
||||
if (file->path()->empty())
|
||||
return std::string();
|
||||
|
||||
torrent::Object resultRaw(*file->path()->begin());
|
||||
torrent::Object::string_type& result = resultRaw.as_string();
|
||||
torrent::Object result_raw(file->path()->begin()->str());
|
||||
auto& result = result_raw.as_string();
|
||||
|
||||
for (torrent::Path::const_iterator itr = ++file->path()->begin(), last = file->path()->end(); itr != last; itr++)
|
||||
result += '/' + *itr;
|
||||
result += '/' + itr->str();
|
||||
|
||||
return resultRaw;
|
||||
return result_raw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_f_path_components(torrent::File* file) {
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
apply_f_path_components(torrent::File* file, int output_type) {
|
||||
auto result_raw = torrent::Object::create_list();
|
||||
auto& result = result_raw.as_list();
|
||||
|
||||
for (const auto& itr : *file->path())
|
||||
result.push_back(itr);
|
||||
for (const auto& itr : *file->path()) {
|
||||
switch (output_type) {
|
||||
case 0: result.push_back(itr.str()); break;
|
||||
case 1: result.push_back(itr.object_hex()); break;
|
||||
case 2: result.push_back(itr.object_base64()); break;
|
||||
case 3: result.push_back(itr.object_base64_as_binary()); break;
|
||||
case 4: result.push_back(itr.object_as_binary()); break;
|
||||
case 5: result.push_back(itr.object_utf8_or_base64()); break;
|
||||
case 6: result.push_back(itr.object_utf8_or_as_binary()); break;
|
||||
default: throw torrent::input_error("apply_f_path_components(): invalid output type");
|
||||
};
|
||||
}
|
||||
|
||||
return resultRaw;
|
||||
return result_raw;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -57,7 +67,7 @@ apply_fi_filename_last(torrent::FileListIterator* itr) {
|
||||
if (itr->depth() >= itr->file()->path()->size())
|
||||
return "ERROR";
|
||||
|
||||
return itr->file()->path()->at(itr->depth());
|
||||
return itr->file()->path()->at(itr->depth()).str();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -80,21 +90,32 @@ initialize_command_file() {
|
||||
CMD2_FILE_V("f.prioritize_last.enable", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
|
||||
CMD2_FILE_V("f.prioritize_last.disable", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
|
||||
|
||||
CMD2_FILE("f.size_bytes", std::bind(&torrent::File::size_bytes, std::placeholders::_1));
|
||||
CMD2_FILE("f.size_chunks", std::bind(&torrent::File::size_chunks, std::placeholders::_1));
|
||||
CMD2_FILE("f.completed_chunks", std::bind(&torrent::File::completed_chunks, std::placeholders::_1));
|
||||
CMD2_FILE("f.size_bytes", [](auto* file, auto) { return file->size_bytes(); });
|
||||
CMD2_FILE("f.size_chunks", [](auto* file, auto) { return file->size_chunks(); });
|
||||
CMD2_FILE("f.completed_chunks", [](auto* file, auto) { return file->completed_chunks(); });
|
||||
|
||||
CMD2_FILE("f.offset", std::bind(&torrent::File::offset, std::placeholders::_1));
|
||||
CMD2_FILE("f.range_first", std::bind(&torrent::File::range_first, std::placeholders::_1));
|
||||
CMD2_FILE("f.range_second", std::bind(&torrent::File::range_second, std::placeholders::_1));
|
||||
CMD2_FILE("f.offset", [](auto* file, auto) { return file->offset(); });
|
||||
CMD2_FILE("f.range_first", [](auto* file, auto) { return file->range_first(); });
|
||||
CMD2_FILE("f.range_second", [](auto* file, auto) { return file->range_second(); });
|
||||
|
||||
CMD2_FILE("f.priority", std::bind(&torrent::File::priority, std::placeholders::_1));
|
||||
CMD2_FILE_VALUE_V("f.priority.set", std::bind(&apply_f_set_priority, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_FILE("f.priority", [](auto* file, auto) { return file->priority(); });
|
||||
CMD2_FILE_VALUE_V("f.priority.set", [](auto* file, auto v) { apply_f_set_priority(file, v); });
|
||||
|
||||
CMD2_FILE("f.path", std::bind(&apply_f_path, std::placeholders::_1));
|
||||
CMD2_FILE("f.path_components", std::bind(&apply_f_path_components, std::placeholders::_1));
|
||||
CMD2_FILE("f.path_depth", std::bind(&apply_f_path_depth, std::placeholders::_1));
|
||||
CMD2_FILE("f.frozen_path", std::bind(&torrent::File::frozen_path, std::placeholders::_1));
|
||||
CMD2_FILE("f.path", [](auto* file, auto) { return apply_f_path(file); });
|
||||
CMD2_FILE("f.path_components", [](auto* file, auto) { return apply_f_path_components(file, 0); });
|
||||
CMD2_FILE("f.path_components.hex", [](auto* file, auto) { return apply_f_path_components(file, 1); });
|
||||
CMD2_FILE("f.path_components.base64", [](auto* file, auto) { return apply_f_path_components(file, 2); });
|
||||
CMD2_FILE("f.path_components.base64_as_binary", [](auto* file, auto) { return apply_f_path_components(file, 3); });
|
||||
CMD2_FILE("f.path_components.as_binary", [](auto* file, auto) { return apply_f_path_components(file, 4); });
|
||||
CMD2_FILE("f.path_components.or_base64", [](auto* file, auto) { return apply_f_path_components(file, 5); });
|
||||
CMD2_FILE("f.path_components.or_as_binary", [](auto* file, auto) { return apply_f_path_components(file, 6); });
|
||||
CMD2_FILE("f.path_depth", [](auto* file, auto) { return apply_f_path_depth(file); });
|
||||
CMD2_FILE("f.frozen_path", [](auto* file, auto) { return file->frozen_path().str(); });
|
||||
CMD2_FILE("f.frozen_path.hex", [](auto* file, auto) { return file->frozen_path().object_hex(); });
|
||||
CMD2_FILE("f.frozen_path.base64", [](auto* file, auto) { return file->frozen_path().object_base64(); });
|
||||
CMD2_FILE("f.frozen_path.as_binary", [](auto* file, auto) { return file->frozen_path().object_as_binary(); });
|
||||
CMD2_FILE("f.frozen_path.or_base64", [](auto* file, auto) { return file->frozen_path().object_utf8_or_base64(); });
|
||||
CMD2_FILE("f.frozen_path.or_as_binary", [](auto* file, auto) { return file->frozen_path().object_utf8_or_as_binary(); });
|
||||
|
||||
CMD2_FILE("f.match_depth_prev", std::bind(&torrent::File::match_depth_prev, std::placeholders::_1));
|
||||
CMD2_FILE("f.match_depth_next", std::bind(&torrent::File::match_depth_next, std::placeholders::_1));
|
||||
@@ -108,6 +129,12 @@ initialize_command_file() {
|
||||
rpc::rpc.mark_safe("f.path_components");
|
||||
rpc::rpc.mark_safe("f.path_depth");
|
||||
rpc::rpc.mark_safe("f.frozen_path");
|
||||
rpc::rpc.mark_safe("f.frozen_path.hex");
|
||||
rpc::rpc.mark_safe("f.frozen_path.base64");
|
||||
rpc::rpc.mark_safe("f.frozen_path.base64_as_binary");
|
||||
rpc::rpc.mark_safe("f.frozen_path.as_binary");
|
||||
rpc::rpc.mark_safe("f.frozen_path.or_base64");
|
||||
rpc::rpc.mark_safe("f.frozen_path.or_as_binary");
|
||||
rpc::rpc.mark_safe("f.offset");
|
||||
rpc::rpc.mark_safe("f.size_bytes");
|
||||
rpc::rpc.mark_safe("f.size_chunks");
|
||||
|
||||
+31
-34
@@ -186,8 +186,8 @@ apply_cg_insert(const std::string& arg) {
|
||||
cg_list_hack.push_back(new torrent::choke_group());
|
||||
cg_list_hack.back()->set_name(arg);
|
||||
|
||||
cg_list_hack.back()->up_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_UPLOAD_LEECH);
|
||||
cg_list_hack.back()->down_queue()->set_heuristics(torrent::choke_queue::HEURISTICS_DOWNLOAD_LEECH);
|
||||
cg_list_hack.back()->up_queue()->set_heuristics(torrent::HEURISTICS_UPLOAD_LEECH);
|
||||
cg_list_hack.back()->down_queue()->set_heuristics(torrent::HEURISTICS_DOWNLOAD_LEECH);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
@@ -337,54 +337,51 @@ options.
|
||||
|
||||
void
|
||||
initialize_command_groups() {
|
||||
CMD2_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD2_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
|
||||
|
||||
#if USE_CHOKE_GROUP
|
||||
CMD2_ANY ("choke_group.size", std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
|
||||
CMD2_ANY_STRING ("choke_group.index_of", std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.size", std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
|
||||
CMD_ANY_STRING ("choke_group.index_of", std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));
|
||||
#else
|
||||
apply_cg_insert("default");
|
||||
|
||||
CMD2_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
|
||||
CMD2_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
|
||||
CMD_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
|
||||
#endif
|
||||
|
||||
// Commands specific for a group. Supports as the first argument the
|
||||
// name, the index or a negative index.
|
||||
CMD2_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
|
||||
|
||||
CMD2_ANY ("choke_group.tracker.mode", std::bind(&torrent::option_as_string, torrent::OPTION_TRACKER_MODE,
|
||||
std::bind(&torrent::choke_group::tracker_mode, CG_GROUP_AT())));
|
||||
CMD2_ANY_LIST ("choke_group.tracker.mode.set", std::bind(&apply_cg_tracker_mode_set, std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.tracker.mode", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_TRACKER_MODE, cg_get_group(arg)->tracker_mode()); });
|
||||
CMD_ANY_LIST ("choke_group.tracker.mode.set", [](auto, auto arg) { return apply_cg_tracker_mode_set(arg); });
|
||||
|
||||
CMD2_ANY ("choke_group.all.up.update_balance", std::bind(&apply_cg_all_update_balance, true));
|
||||
CMD2_ANY ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));
|
||||
CMD_ANY ("choke_group.all.up.update_balance", std::bind(&apply_cg_all_update_balance, true));
|
||||
CMD_ANY ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));
|
||||
|
||||
CMD2_ANY ("choke_group.up.rate", std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
|
||||
CMD2_ANY ("choke_group.down.rate", std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.up.rate", std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.down.rate", std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
|
||||
|
||||
CMD2_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
|
||||
CMD_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
|
||||
|
||||
CMD2_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::up_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.up.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, true));
|
||||
CMD_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->up_queue()->heuristics()); });
|
||||
CMD_ANY_LIST ("choke_group.up.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, true); });
|
||||
|
||||
CMD2_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
|
||||
CMD_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
|
||||
|
||||
CMD2_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.down.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, false));
|
||||
CMD_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->down_queue()->heuristics()); });
|
||||
CMD_ANY_LIST ("choke_group.down.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, false); });
|
||||
|
||||
rpc::rpc.mark_safe("choke_group.list");
|
||||
rpc::rpc.mark_safe("choke_group.size");
|
||||
|
||||
+19
-1
@@ -7,6 +7,25 @@
|
||||
|
||||
void initialize_commands();
|
||||
|
||||
//
|
||||
// Aliases with CMD_* for the below
|
||||
//
|
||||
|
||||
#define CMD_ANY(key, slot) CMD2_ANY(key, slot)
|
||||
#define CMD_ANY_P(key, slot) CMD2_ANY_P(key, slot)
|
||||
#define CMD_REDIRECT(key, slot) CMD2_REDIRECT(key, slot)
|
||||
#define CMD_REDIRECT_NO_EXPORT(key, slot) CMD2_REDIRECT_NO_EXPORT(key, slot)
|
||||
#define CMD_ANY_STRING(key, slot) CMD2_ANY_STRING(key, slot)
|
||||
#define CMD_ANY_STRING_V(key, slot) CMD2_ANY_STRING_V(key, slot)
|
||||
#define CMD_ANY_LIST(key, slot) CMD2_ANY_LIST(key, slot)
|
||||
#define CMD_VAR_VALUE(key, value) CMD2_VAR_VALUE(key, value)
|
||||
#define CMD_VAR_BOOL(key, value) CMD2_VAR_BOOL(key, value)
|
||||
#define CMD_VAR_STRING(key, value) CMD2_VAR_STRING(key, value)
|
||||
#define CMD_VAR_C_STRING(key, value) CMD2_VAR_C_STRING(key, value)
|
||||
#define CMD_VAR_LIST(key) CMD2_VAR_LIST(key)
|
||||
#define CMD_ANY_V(key, slot) CMD2_ANY_V(key, slot)
|
||||
#define CMD_ANY_VALUE_V(key, slot) CMD2_ANY_VALUE_V(key, slot)
|
||||
|
||||
//
|
||||
// New std::function based command_base helper functions:
|
||||
//
|
||||
@@ -115,7 +134,6 @@ void initialize_commands();
|
||||
#define CMD2_REDIRECT_TRACKER(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_tracker_target | rpc::CommandMap::flag_dont_delete);
|
||||
|
||||
|
||||
//
|
||||
// Conversion of return types:
|
||||
//
|
||||
|
||||
+1
-1
@@ -353,7 +353,7 @@ apply_ipv4_filter_dump() {
|
||||
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
|
||||
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_as_string(torrent::OPTION_IP_FILTER, value));
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_to_c_str_or_throw(torrent::OPTION_IP_FILTER, value));
|
||||
|
||||
result.push_back((std::string)buffer);
|
||||
|
||||
|
||||
+133
-114
@@ -8,9 +8,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/chunk_manager.h>
|
||||
#include <torrent/data/file_manager.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/runtime/memory_manager.h>
|
||||
#include <torrent/runtime/socket_manager.h>
|
||||
#include <torrent/utils/chrono.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
@@ -113,9 +115,9 @@ group_insert(const torrent::Object::list_type& args) {
|
||||
const std::string& view = check_name(post_increment(itr, last)->as_string());
|
||||
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.enable", "simple",
|
||||
"schedule2=group." + name + ".ratio,5,60,on_ratio=" + name));
|
||||
"schedule=group." + name + ".ratio,5,60,on_ratio=" + name));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.disable", "simple",
|
||||
"schedule_remove2=group." + name + ".ratio"));
|
||||
"schedule.remove=group." + name + ".ratio"));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.command", "simple",
|
||||
"d.try_close= ;d.ignore_commands.set=1"));
|
||||
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".view", "string", view));
|
||||
@@ -132,19 +134,6 @@ group_insert(const torrent::Object::list_type& args) {
|
||||
rpc::rpc.mark_safe("group." + name + ".ratio.upload");
|
||||
rpc::rpc.mark_safe("group." + name + ".ratio.upload.set");
|
||||
|
||||
if (rpc::call_command_value("method.use_intermediate") == 3) {
|
||||
// Cleaned up in 0.16.1:
|
||||
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".view", "group." + name + ".view");
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".view.set", "group." + name + ".view.set");
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.min", "group." + name + ".ratio.min");
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.min.set", "group." + name + ".ratio.min.set");
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.max", "group." + name + ".ratio.max");
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.max.set", "group." + name + ".ratio.max.set");
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.upload", "group." + name + ".ratio.upload");
|
||||
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.upload.set", "group." + name + ".ratio.upload.set");
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -199,142 +188,156 @@ cmd_file_append(const torrent::Object::list_type& args) {
|
||||
void
|
||||
initialize_command_local() {
|
||||
core::DownloadList* dList = control->core()->download_list();
|
||||
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
|
||||
CMD2_ANY ("system.hostname", std::bind(&system_hostname));
|
||||
CMD2_ANY ("system.pid", std::bind(&getpid));
|
||||
CMD_ANY ("system.hostname", std::bind(&system_hostname));
|
||||
CMD_ANY ("system.pid", std::bind(&getpid));
|
||||
|
||||
CMD2_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
|
||||
CMD2_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
|
||||
CMD2_VAR_C_STRING("system.library_version", torrent::version());
|
||||
CMD_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
|
||||
CMD_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
|
||||
CMD_VAR_C_STRING("system.library_version", torrent::runtime::version());
|
||||
|
||||
CMD2_VAR_VALUE ("system.file.allocate", 0);
|
||||
CMD2_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
|
||||
CMD2_VAR_VALUE ("system.file.split_size", -1);
|
||||
CMD2_VAR_STRING ("system.file.split_suffix", ".part");
|
||||
CMD_VAR_VALUE ("system.file.allocate", 0);
|
||||
CMD_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
|
||||
CMD_VAR_VALUE ("system.file.split_size", -1);
|
||||
CMD_VAR_STRING ("system.file.split_suffix", ".part");
|
||||
|
||||
CMD2_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
|
||||
CMD_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
|
||||
(utils::FileStatusCache::base_type*)control->core()->file_status_cache()));
|
||||
CMD2_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
|
||||
CMD_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
|
||||
|
||||
CMD2_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.first");
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.last");
|
||||
CMD_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
CMD_VAR_LIST ("file.prioritize_toc.first");
|
||||
CMD_VAR_LIST ("file.prioritize_toc.last");
|
||||
|
||||
CMD2_ANY ("system.files.advise_random", std::bind(&FM_t::advise_random, fileManager));
|
||||
CMD2_ANY_VALUE_V ("system.files.advise_random.set", std::bind(&FM_t::set_advise_random, fileManager, std::placeholders::_2));
|
||||
CMD2_ANY ("system.files.advise_random.hashing", std::bind(&FM_t::advise_random_hashing, fileManager));
|
||||
CMD2_ANY_VALUE_V ("system.files.advise_random.hashing.set", std::bind(&FM_t::set_advise_random_hashing, fileManager, std::placeholders::_2));
|
||||
CMD2_ANY ("system.files.session.fdatasync", [](auto, auto) { return session_thread::manager()->use_fsyncdisk(); });
|
||||
CMD2_ANY_VALUE_V ("system.files.session.fdatasync.set", [](auto, auto& value) { return session_thread::manager()->set_use_fsyncdisk(value); });
|
||||
CMD_ANY ("system.files.advise_random", std::bind(&FM_t::advise_random, fileManager));
|
||||
CMD_ANY_VALUE_V ("system.files.advise_random.set", std::bind(&FM_t::set_advise_random, fileManager, std::placeholders::_2));
|
||||
CMD_ANY ("system.files.advise_random.hashing", std::bind(&FM_t::advise_random_hashing, fileManager));
|
||||
CMD_ANY_VALUE_V ("system.files.advise_random.hashing.set", std::bind(&FM_t::set_advise_random_hashing, fileManager, std::placeholders::_2));
|
||||
CMD_ANY ("system.files.session.fdatasync", [](auto, auto) { return session_thread::manager()->use_fsyncdisk(); });
|
||||
CMD_ANY_VALUE_V ("system.files.session.fdatasync.set", [](auto, auto& value) { return session_thread::manager()->set_use_fsyncdisk(value); });
|
||||
|
||||
CMD2_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
|
||||
CMD2_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
|
||||
CMD2_ANY ("system.files.failed_counter", std::bind(&FM_t::files_failed_counter, fileManager));
|
||||
CMD_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
|
||||
CMD_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
|
||||
CMD_ANY ("system.files.failed_counter", std::bind(&FM_t::files_failed_counter, fileManager));
|
||||
|
||||
CMD2_ANY_STRING ("system.env", std::bind(&system_env, std::placeholders::_2));
|
||||
CMD_ANY_STRING ("system.env", [](auto, auto& str) { return system_env(str); });
|
||||
|
||||
CMD2_ANY ("system.time", []([[maybe_unused]] auto t, [[maybe_unused]] auto o) -> torrent::Object {
|
||||
return torrent::this_thread::cached_seconds().count();
|
||||
});
|
||||
CMD2_ANY ("system.time_seconds", []([[maybe_unused]] auto t, [[maybe_unused]] auto o) -> torrent::Object {
|
||||
return torrent::utils::cast_seconds(torrent::utils::time_since_epoch()).count();
|
||||
});
|
||||
CMD2_ANY ("system.time_usec", []([[maybe_unused]] auto t, [[maybe_unused]] auto o) -> torrent::Object {
|
||||
return torrent::utils::time_since_epoch().count();
|
||||
});
|
||||
CMD_ANY ("system.time", [](auto, auto) { return torrent::this_thread::cached_seconds().count(); });
|
||||
CMD_ANY ("system.time_seconds", [](auto, auto) { return torrent::utils::cast_seconds(torrent::utils::time_since_epoch()).count(); });
|
||||
CMD_ANY ("system.time_usec", [](auto, auto) { return torrent::utils::time_since_epoch().count(); });
|
||||
|
||||
CMD2_ANY_VALUE_V ("system.umask.set", std::bind(&umask, std::placeholders::_2));
|
||||
CMD_ANY_VALUE_V ("system.umask.set", [](auto, auto& value) { return ::umask(value); });
|
||||
|
||||
CMD2_VAR_BOOL ("system.daemon", false);
|
||||
CMD_VAR_BOOL ("system.daemon", false);
|
||||
|
||||
CMD2_ANY_V ("system.shutdown.normal", std::bind(&Control::receive_normal_shutdown, control));
|
||||
CMD2_ANY_V ("system.shutdown.quick", std::bind(&Control::receive_quick_shutdown, control));
|
||||
CMD2_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
|
||||
CMD_ANY_V ("system.shutdown.normal", [](auto, auto) { control->receive_normal_shutdown(); });
|
||||
CMD_ANY_V ("system.shutdown.quick", [](auto, auto) { control->receive_quick_shutdown(); });
|
||||
|
||||
CMD2_ANY ("system.cwd", std::bind(&system_get_cwd));
|
||||
CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::placeholders::_2));
|
||||
CMD_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
|
||||
|
||||
CMD2_ANY ("pieces.sync.always_safe", std::bind(&CM_t::safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.always_safe.set", std::bind(&CM_t::set_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.safe_free_diskspace", std::bind(&CM_t::safe_free_diskspace, chunkManager));
|
||||
CMD2_ANY ("pieces.sync.timeout", std::bind(&CM_t::timeout_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout.set", std::bind(&CM_t::set_timeout_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.timeout_safe", std::bind(&CM_t::timeout_safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout_safe.set", std::bind(&CM_t::set_timeout_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.queue_size", std::bind(&CM_t::sync_queue_size, chunkManager));
|
||||
CMD_ANY ("system.cwd", [](auto, auto) { return system_get_cwd(); });
|
||||
CMD_ANY_STRING ("system.cwd.set", [](auto, auto& str) { return system_set_cwd(str); });
|
||||
|
||||
CMD2_ANY ("pieces.preload.type", std::bind(&CM_t::preload_type, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.type.set", std::bind(&CM_t::set_preload_type, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_size", std::bind(&CM_t::preload_min_size, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_size.set", std::bind(&CM_t::set_preload_min_size, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_rate", std::bind(&CM_t::preload_required_rate, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_rate.set", std::bind(&CM_t::set_preload_required_rate, chunkManager, std::placeholders::_2));
|
||||
CMD_ANY ("system.sockets.size", [](auto, auto) { return torrent::runtime::socket_manager()->size(); });
|
||||
CMD_ANY ("system.sockets.max_size", [](auto, auto) { return torrent::runtime::socket_manager()->max_size(); });
|
||||
CMD_ANY_VALUE_V ("system.sockets.max_size.set", [](auto, auto& value) { return torrent::runtime::socket_manager()->set_max_size_and_adjust(value); });
|
||||
CMD_ANY_V ("system.sockets.adjust_alloc", [](auto, auto) { torrent::runtime::socket_manager()->adjust_allocation(); });
|
||||
|
||||
CMD2_ANY ("pieces.memory.current", std::bind(&CM_t::memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.sync_queue", std::bind(&CM_t::sync_queue_memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.block_count", std::bind(&CM_t::memory_block_count, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.max", std::bind(&CM_t::max_memory_usage, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.memory.max.set", std::bind(&CM_t::set_max_memory_usage, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.stats_preloaded", std::bind(&CM_t::stats_preloaded, chunkManager));
|
||||
CMD2_ANY ("pieces.stats_not_preloaded", std::bind(&CM_t::stats_not_preloaded, chunkManager));
|
||||
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
|
||||
auto category = static_cast<torrent::runtime::socket_manager_category_t>(i);
|
||||
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
|
||||
|
||||
CMD2_ANY ("pieces.stats.total_size", std::bind(&apply_pieces_stats_total_size));
|
||||
CMD_ANY (category_name + ".size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_managed_size(category); });
|
||||
CMD_ANY (category_name + ".max_size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_size(category); });
|
||||
|
||||
CMD2_ANY ("pieces.hash.queue_size", std::bind(&torrent::main_thread::hash_queue_size));
|
||||
CMD2_VAR_BOOL ("pieces.hash.on_completion", true);
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
CMD2_VAR_STRING ("directory.default", "./");
|
||||
CMD_ANY (category_name + ".min_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_min_allocation(category); });
|
||||
CMD_ANY (category_name + ".max_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_allocation(category); });
|
||||
CMD_ANY_VALUE_V(category_name + ".min_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_min_allocation(category, value); });
|
||||
CMD_ANY_VALUE_V(category_name + ".max_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_max_allocation(category, value); });
|
||||
}
|
||||
|
||||
CMD2_VAR_STRING ("session.name", "");
|
||||
CMD2_ANY ("session.path", [](auto, auto) { return session_thread::manager()->path(); });
|
||||
CMD2_ANY_STRING_V("session.path.set", [](auto, auto& str) { return session_thread::manager()->set_path(str); });
|
||||
CMD2_ANY ("session.use_lock", [](auto, auto) { return session_thread::manager()->use_lock(); });
|
||||
CMD2_ANY_VALUE_V ("session.use_lock.set", [](auto, auto& value) { return session_thread::manager()->set_use_lock(value); });
|
||||
CMD2_VAR_BOOL ("session.on_completion", true);
|
||||
CMD_ANY ("pieces.sync.always_safe", [](auto, auto) { return torrent::runtime::memory_manager()->safe_sync(); });
|
||||
CMD_ANY_VALUE_V ("pieces.sync.always_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_safe_sync(value); });
|
||||
CMD_ANY ("pieces.sync.safe_free_diskspace", [](auto, auto) { return torrent::runtime::memory_manager()->sync_safe_free_diskspace(); });
|
||||
CMD_ANY ("pieces.sync.timeout", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_sync().count(); });
|
||||
CMD_ANY_VALUE_V ("pieces.sync.timeout.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_sync(value); });
|
||||
// CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_safe_sync(); });
|
||||
// CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_safe_sync(value); });
|
||||
CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return 0; });
|
||||
CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto) { });
|
||||
CMD_ANY ("pieces.sync.queue_size", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_block_count(); });
|
||||
|
||||
CMD2_ANY_V ("session.save", [dList](auto, auto) { return dList->session_save(); });
|
||||
CMD_ANY ("pieces.preload.type", [](auto, auto) { return torrent::runtime::memory_manager()->preload_type(); });
|
||||
CMD_ANY_VALUE_V ("pieces.preload.type.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_type(value); });
|
||||
CMD_ANY ("pieces.preload.min_size", [](auto, auto) { return torrent::runtime::memory_manager()->preload_min_size(); });
|
||||
CMD_ANY_VALUE_V ("pieces.preload.min_size.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_min_size(value); });
|
||||
CMD_ANY ("pieces.preload.min_rate", [](auto, auto) { return torrent::runtime::memory_manager()->preload_required_rate(); });
|
||||
CMD_ANY_VALUE_V ("pieces.preload.min_rate.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_required_rate(value); });
|
||||
|
||||
CMD2_ANY ("magnet.path", [](auto, auto) { return control->core()->magnet_path(); });
|
||||
CMD2_ANY_STRING_V("magnet.path.set", [](auto, auto& str) { return control->core()->set_magnet_path(str); });
|
||||
CMD_ANY ("pieces.stats_preloaded", [](auto, auto) { return torrent::runtime::memory_manager()->stats_preloaded(); });
|
||||
CMD_ANY ("pieces.stats_not_preloaded", [](auto, auto) { return torrent::runtime::memory_manager()->stats_not_preloaded(); });
|
||||
CMD_ANY ("pieces.stats.total_size", std::bind(&apply_pieces_stats_total_size));
|
||||
|
||||
CMD_ANY ("pieces.memory.current", [](auto, auto) { return torrent::runtime::memory_manager()->memory_usage(); });
|
||||
CMD_ANY ("pieces.memory.sync_queue", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_memory_usage(); });
|
||||
CMD_ANY ("pieces.memory.block_count", [](auto, auto) { return torrent::runtime::memory_manager()->memory_block_count(); });
|
||||
CMD_ANY ("pieces.memory.max", [](auto, auto) { return torrent::runtime::memory_manager()->max_memory_usage(); });
|
||||
CMD_ANY_VALUE_V ("pieces.memory.max.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_max_memory_usage(value); });
|
||||
|
||||
CMD_ANY ("pieces.hash.queue_size", std::bind(&torrent::main_thread::hash_queue_size));
|
||||
CMD_VAR_BOOL ("pieces.hash.on_completion", true);
|
||||
|
||||
CMD_VAR_STRING ("directory.default", "./");
|
||||
|
||||
CMD_VAR_STRING ("session.name", "");
|
||||
CMD_ANY ("session.path", [](auto, auto) { return session_thread::manager()->path(); });
|
||||
CMD_ANY_STRING_V("session.path.set", [](auto, auto& str) { return session_thread::manager()->set_path(str); });
|
||||
CMD_ANY ("session.use_lock", [](auto, auto) { return session_thread::manager()->use_lock(); });
|
||||
CMD_ANY_VALUE_V ("session.use_lock.set", [](auto, auto& value) { return session_thread::manager()->set_use_lock(value); });
|
||||
CMD_VAR_BOOL ("session.on_completion", true);
|
||||
|
||||
CMD_ANY_V ("session.save", [dList](auto, auto) { return dList->session_save(); });
|
||||
|
||||
CMD_ANY ("magnet.path", [](auto, auto) { return control->core()->magnet_path(); });
|
||||
CMD_ANY_STRING_V("magnet.path.set", [](auto, auto& str) { return control->core()->set_magnet_path(str); });
|
||||
|
||||
#ifdef HAVE_LUA
|
||||
rpc::LuaEngine* lua_engine = control->lua_engine();
|
||||
|
||||
CMD2_ANY ("lua.execute", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string));
|
||||
CMD_ANY ("lua.execute", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string));
|
||||
#endif
|
||||
|
||||
#define CMD2_EXECUTE(key, flags) \
|
||||
CMD2_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags));
|
||||
#define CMD_EXECUTE(key, flags) \
|
||||
CMD_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags));
|
||||
|
||||
CMD2_EXECUTE ("execute", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute2", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde);
|
||||
CMD2_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.raw_nothrow", 0);
|
||||
CMD2_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
CMD2_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
|
||||
CMD2_ANY_LIST ("file.append", std::bind(&cmd_file_append, std::placeholders::_2));
|
||||
CMD_EXECUTE ("execute", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde);
|
||||
CMD_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw);
|
||||
CMD_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.raw_nothrow", 0);
|
||||
CMD_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
CMD_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
|
||||
// TODO: Convert to new command types:
|
||||
*rpc::command_base::argument(0) = "placeholder.0";
|
||||
*rpc::command_base::argument(1) = "placeholder.1";
|
||||
*rpc::command_base::argument(2) = "placeholder.2";
|
||||
*rpc::command_base::argument(3) = "placeholder.3";
|
||||
CMD2_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
|
||||
CMD2_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
|
||||
CMD2_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
|
||||
CMD2_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
|
||||
CMD_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
|
||||
CMD_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
|
||||
CMD_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
|
||||
CMD_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
|
||||
|
||||
CMD2_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
|
||||
CMD_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
|
||||
|
||||
rpc::rpc.mark_safe("system.api_version");
|
||||
rpc::rpc.mark_safe("system.client_version");
|
||||
@@ -343,6 +346,22 @@ initialize_command_local() {
|
||||
rpc::rpc.mark_safe("system.file.split_size");
|
||||
rpc::rpc.mark_safe("system.file.split_suffix");
|
||||
|
||||
rpc::rpc.mark_safe("system.sockets.size");
|
||||
rpc::rpc.mark_safe("system.sockets.max_size");
|
||||
|
||||
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
|
||||
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
|
||||
|
||||
rpc::rpc.mark_safe(category_name + ".size");
|
||||
rpc::rpc.mark_safe(category_name + ".max_size");
|
||||
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
rpc::rpc.mark_safe(category_name + ".min_alloc");
|
||||
rpc::rpc.mark_safe(category_name + ".max_alloc");
|
||||
}
|
||||
|
||||
rpc::rpc.mark_safe("directory.default");
|
||||
rpc::rpc.mark_safe("session.path");
|
||||
rpc::rpc.mark_safe("session.use_lock");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <iterator>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
@@ -15,6 +16,7 @@
|
||||
#include "core/download.h"
|
||||
#include "core/download_list.h"
|
||||
#include "core/manager.h"
|
||||
#include "rpc/parse.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
torrent::Object
|
||||
@@ -38,6 +40,32 @@ apply_log_add_output(const torrent::Object::list_type& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_log_print(const torrent::Object::list_type& args) {
|
||||
if (args.size() < 2)
|
||||
throw torrent::input_error("Invalid number of arguments.");
|
||||
|
||||
torrent::Object::value_type group;
|
||||
|
||||
if (args.front().is_value())
|
||||
group = args.front().as_value();
|
||||
else if (args.front().is_string())
|
||||
group = torrent::option_find_string_str(torrent::OPTION_LOG_GROUP, args.front().as_string());
|
||||
else
|
||||
throw torrent::input_error("Invalid log group.");
|
||||
|
||||
if (group < 0 || group >= torrent::LOG_GROUP_MAX_SIZE)
|
||||
throw torrent::input_error("Invalid log group.");
|
||||
|
||||
std::string message;
|
||||
|
||||
for (auto itr = std::next(args.begin()); itr != args.end(); ++itr)
|
||||
rpc::print_object_std(&message, &*itr, 0);
|
||||
|
||||
torrent::log_groups[group].internal_print(message);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
// TODO: Deprecated.
|
||||
torrent::Object
|
||||
apply_log(const torrent::Object::string_type& arg, int logType) {
|
||||
@@ -112,6 +140,7 @@ initialize_command_logging() {
|
||||
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("log.print", std::bind(&apply_log_print, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
|
||||
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
|
||||
|
||||
+204
-106
@@ -8,8 +8,13 @@
|
||||
#include <torrent/data/file_manager.h>
|
||||
#include <torrent/download/resource_manager.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/net/network_config.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
#include <torrent/runtime/client_config.h>
|
||||
#include <torrent/runtime/network_config.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/runtime/proxy_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/runtime/socket_manager.h>
|
||||
#include <torrent/tracker/tracker.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
@@ -30,21 +35,115 @@
|
||||
#endif
|
||||
|
||||
torrent::Object
|
||||
apply_encryption(const torrent::Object::list_type& args) {
|
||||
uint32_t options_mask = torrent::net::NetworkConfig::encryption_none;
|
||||
listen_port_range() {
|
||||
auto port_range = torrent::runtime::client_config()->listen_port_range();
|
||||
|
||||
for (const auto& arg : args) {
|
||||
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, arg.as_string().c_str());
|
||||
return std::to_string(port_range.first) + "-" + std::to_string(port_range.second);
|
||||
}
|
||||
|
||||
if (opt == torrent::net::NetworkConfig::encryption_none)
|
||||
options_mask = torrent::net::NetworkConfig::encryption_none;
|
||||
else
|
||||
options_mask |= opt;
|
||||
void
|
||||
set_listen_port_range(const std::string& arg) {
|
||||
unsigned int port_first{}, port_last{};
|
||||
|
||||
if (std::sscanf(arg.c_str(), "%i-%i", &port_first, &port_last) != 2)
|
||||
throw torrent::input_error("Invalid port_range argument.");
|
||||
|
||||
if (port_first >= (1 << 16) || port_last >= (1 << 16))
|
||||
throw torrent::input_error("Port range out-of-bounds.");
|
||||
|
||||
torrent::runtime::client_config()->set_listen_port_range(port_first, port_last);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
get_encryption() {
|
||||
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
|
||||
|
||||
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_HANDSHAKE, encryption_modes.first) + "," +
|
||||
torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_STREAM, encryption_modes.second);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
get_handshake_encryption() {
|
||||
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
|
||||
|
||||
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_MODE, encryption_modes.first);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
get_stream_encryption() {
|
||||
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
|
||||
|
||||
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_MODE, encryption_modes.second);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_obsolete_encryption(const torrent::Object::list_type& args) {
|
||||
torrent::encryption_mode handshake_mode{torrent::ENCRYPTION_MODE_ALLOW};
|
||||
torrent::encryption_mode stream_mode{torrent::ENCRYPTION_MODE_ALLOW};
|
||||
|
||||
for (auto& itr : args) {
|
||||
auto arg = itr.as_string();
|
||||
|
||||
if (arg == "none") {
|
||||
handshake_mode = torrent::ENCRYPTION_MODE_DENY;
|
||||
stream_mode = torrent::ENCRYPTION_MODE_DENY;
|
||||
break;
|
||||
|
||||
} else if (arg == "allow_incoming") {
|
||||
} else if (arg == "try_outgoing") {
|
||||
} else if (arg == "require") {
|
||||
handshake_mode = torrent::ENCRYPTION_MODE_REQUIRE;
|
||||
|
||||
} else if (arg == "require_RC4" || arg == "require_rc4") {
|
||||
handshake_mode = torrent::ENCRYPTION_MODE_REQUIRE;
|
||||
stream_mode = torrent::ENCRYPTION_MODE_REQUIRE;
|
||||
break;
|
||||
|
||||
} else if (arg == "enable_retry") {
|
||||
} else if (arg == "prefer_plaintext") {
|
||||
} else {
|
||||
throw torrent::input_error("Invalid encryption option: '" + arg + "'");
|
||||
}
|
||||
}
|
||||
|
||||
torrent::config::network_config()->set_encryption_options(options_mask);
|
||||
lt_log_print(torrent::LOG_WARN, "Obsolete encryption options used, use 'handshake_{deny,allow,prefer,require}, stream_{deny,allow,prefer,require}' instead.");
|
||||
|
||||
return torrent::Object();
|
||||
torrent::runtime::network_config()->set_encryption_modes(handshake_mode, stream_mode);
|
||||
return {};
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_encryption(const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("No encryption options specified.");
|
||||
|
||||
torrent::encryption_mode encryption_mode, handshake_mode, stream_mode;
|
||||
|
||||
if (args.size() == 1) {
|
||||
try {
|
||||
encryption_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_MODE, args.front().as_string()));
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
return apply_obsolete_encryption(args);
|
||||
}
|
||||
|
||||
torrent::runtime::network_config()->set_encryption_modes(encryption_mode, encryption_mode);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (args.size() != 2)
|
||||
return apply_obsolete_encryption(args);
|
||||
|
||||
try {
|
||||
handshake_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_HANDSHAKE, args.front().as_string()));
|
||||
stream_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_STREAM, args.back().as_string()));
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
return apply_obsolete_encryption(args);
|
||||
}
|
||||
|
||||
torrent::runtime::network_config()->set_encryption_modes(handshake_mode, stream_mode);
|
||||
return {};
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -54,13 +153,11 @@ apply_tos(const torrent::Object::string_type& arg) {
|
||||
if (!rpc::parse_whole_value_nothrow(arg.c_str(), &value, 16, 1))
|
||||
value = torrent::option_find_string(torrent::OPTION_IP_TOS, arg.c_str());
|
||||
|
||||
torrent::config::network_config()->set_priority(value);
|
||||
torrent::runtime::network_config()->set_priority(value);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); return torrent::Object(); }
|
||||
|
||||
void
|
||||
initialize_rpc_handlers() {
|
||||
rpc::rpc.initialize_handlers();
|
||||
@@ -215,111 +312,111 @@ apply_xmlrpc_dialect(const std::string& arg) {
|
||||
|
||||
void
|
||||
initialize_command_network() {
|
||||
auto cm = torrent::connection_manager();
|
||||
auto file_manager = torrent::file_manager();
|
||||
auto http_stack = torrent::net_thread::http_stack();
|
||||
auto nw_config = torrent::config::network_config();
|
||||
auto file_manager = torrent::file_manager();
|
||||
auto http_stack = torrent::net_thread::http_stack();
|
||||
auto nw_config = torrent::runtime::network_config();
|
||||
|
||||
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
|
||||
CMD_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::network_manager()->listen_port(); });
|
||||
CMD_ANY_VALUE_V ("network.listen.port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_listen_port(value); });
|
||||
CMD_ANY ("network.listen.port.random", [](auto, auto) { return torrent::runtime::client_config()->listen_port_random(); });
|
||||
CMD_ANY_VALUE_V ("network.listen.port.random.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_listen_port_random(value); });
|
||||
CMD_ANY ("network.listen.port.range", [](auto, auto) { return listen_port_range(); });
|
||||
CMD_ANY_STRING_V("network.listen.port.range.set", [](auto, auto& value) { return set_listen_port_range(value); });
|
||||
CMD_ANY ("network.listen.backlog", [](auto, auto) { return torrent::runtime::network_config()->listen_backlog(); });
|
||||
CMD_ANY_VALUE_V ("network.listen.backlog.set", [](auto, auto& value) { return torrent::runtime::network_config()->set_listen_backlog(value); });
|
||||
|
||||
// Isn't port_open used?
|
||||
CMD2_VAR_BOOL ("network.port_open", true);
|
||||
CMD2_VAR_BOOL ("network.port_random", true);
|
||||
CMD2_VAR_STRING ("network.port_range", "6881-6999");
|
||||
CMD_ANY ("protocol.pex", [](auto, auto) { return torrent::runtime::client_config()->is_pex_enabled(); });
|
||||
CMD_ANY_VALUE_V ("protocol.pex.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_pex_enabled(value); });
|
||||
|
||||
CMD2_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::listen_port(); });
|
||||
CMD2_ANY ("network.listen.backlog", [nw_config](auto, auto) { return nw_config->listen_backlog(); });
|
||||
CMD2_ANY_VALUE_V ("network.listen.backlog.set", [nw_config](auto, auto& value) { return nw_config->set_listen_backlog(value); });
|
||||
CMD_ANY_LIST ("protocol.encryption", [](auto, auto) { return get_encryption(); });
|
||||
CMD_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); });
|
||||
CMD_ANY_LIST ("protocol.encryption.handshake", [](auto, auto) { return get_handshake_encryption(); });
|
||||
CMD_ANY_LIST ("protocol.encryption.stream", [](auto, auto) { return get_stream_encryption(); });
|
||||
|
||||
CMD2_VAR_BOOL ("protocol.pex", true);
|
||||
CMD2_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); });
|
||||
CMD_VAR_STRING ("protocol.connection.leech", "leech");
|
||||
CMD_VAR_STRING ("protocol.connection.seed", "seed");
|
||||
|
||||
CMD2_VAR_STRING ("protocol.connection.leech", "leech");
|
||||
CMD2_VAR_STRING ("protocol.connection.seed", "seed");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
|
||||
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
|
||||
CMD_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); });
|
||||
CMD_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); });
|
||||
CMD_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); });
|
||||
CMD_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); });
|
||||
CMD_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); });
|
||||
CMD_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); });
|
||||
CMD_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); });
|
||||
CMD_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); });
|
||||
CMD_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); });
|
||||
CMD_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
|
||||
CMD_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
|
||||
CMD_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
|
||||
|
||||
CMD2_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); });
|
||||
CMD2_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); });
|
||||
CMD2_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); });
|
||||
CMD2_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); });
|
||||
CMD2_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); });
|
||||
CMD2_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); });
|
||||
CMD2_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); });
|
||||
CMD2_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
|
||||
CMD2_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.max_total_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_total_connections(value); });
|
||||
CMD2_ANY ("network.http.proxy_address", [http_stack](auto, auto) { return http_stack->http_proxy(); });
|
||||
CMD2_ANY_STRING_V("network.http.proxy_address.set", [http_stack](auto, auto& str) { return http_stack->set_http_proxy(str); });
|
||||
CMD2_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); });
|
||||
CMD2_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); });
|
||||
CMD_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
|
||||
CMD_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); });
|
||||
CMD_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); });
|
||||
CMD_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); });
|
||||
|
||||
CMD2_ANY ("network.send_buffer.size", [nw_config](auto, auto) { return nw_config->send_buffer_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_send_buffer_size(value); });
|
||||
CMD2_ANY ("network.receive_buffer.size", [nw_config](auto, auto) { return nw_config->receive_buffer_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_receive_buffer_size(value); });
|
||||
CMD2_ANY_STRING ("network.tos.set", [](auto, auto& str) { return apply_tos(str); });
|
||||
CMD_ANY ("network.send_buffer.size", [nw_config](auto, auto) { return nw_config->send_buffer_size(); });
|
||||
CMD_ANY_VALUE_V ("network.send_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_send_buffer_size(value); });
|
||||
CMD_ANY ("network.receive_buffer.size", [nw_config](auto, auto) { return nw_config->receive_buffer_size(); });
|
||||
CMD_ANY_VALUE_V ("network.receive_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_receive_buffer_size(value); });
|
||||
CMD_ANY_STRING ("network.tos.set", [](auto, auto& str) { return apply_tos(str); });
|
||||
|
||||
CMD2_ANY ("network.bind_address", [nw_config](auto, auto) { return nw_config->bind_address_best_match_str(); });
|
||||
CMD2_ANY_STRING_V("network.bind_address.set", [nw_config](auto, auto& str) { return nw_config->set_bind_address_str(str); });
|
||||
CMD2_ANY ("network.bind_address.ipv4", [nw_config](auto, auto) { return nw_config->bind_inet_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.bind_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet_address_str(str); });
|
||||
CMD2_ANY ("network.bind_address.ipv6", [nw_config](auto, auto) { return nw_config->bind_inet6_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.bind_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet6_address_str(str); });
|
||||
CMD_ANY ("network.bind_address", [nw_config](auto, auto) { return nw_config->bind_address_best_match_str(); });
|
||||
CMD_ANY_STRING_V("network.bind_address.set", [nw_config](auto, auto& str) { return nw_config->set_bind_address_str(str); });
|
||||
CMD_ANY ("network.bind_address.ipv4", [nw_config](auto, auto) { return nw_config->bind_inet_address_str(); });
|
||||
CMD_ANY_STRING_V("network.bind_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet_address_str(str); });
|
||||
CMD_ANY ("network.bind_address.ipv6", [nw_config](auto, auto) { return nw_config->bind_inet6_address_str(); });
|
||||
CMD_ANY_STRING_V("network.bind_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet6_address_str(str); });
|
||||
|
||||
CMD2_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); });
|
||||
CMD2_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); });
|
||||
CMD2_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); });
|
||||
CMD2_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address_str(str); });
|
||||
CMD_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); });
|
||||
CMD_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); });
|
||||
CMD_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); });
|
||||
CMD_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); });
|
||||
CMD_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); });
|
||||
CMD_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address_str(str); });
|
||||
|
||||
CMD2_ANY ("network.proxy_address", [nw_config](auto, auto) { return nw_config->proxy_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.proxy_address.set", [](auto, auto& str) { return control->core()->set_proxy_address(str); });
|
||||
CMD_ANY ("network.proxy.global", [](auto, auto) { return torrent::runtime::proxy_manager()->proxy_url(); });
|
||||
CMD_ANY_STRING_V("network.proxy.global.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_proxy_url(str); });
|
||||
CMD_ANY ("network.proxy.http", [](auto, auto) { return torrent::runtime::proxy_manager()->http_proxy_url(); });
|
||||
CMD_ANY_STRING_V("network.proxy.http.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_http_proxy_url(str); });
|
||||
|
||||
CMD2_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
|
||||
CMD2_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
|
||||
CMD2_ANY_VALUE_V ("network.max_open_files.set", [file_manager](auto, auto& value) { return file_manager->set_max_open_files(value); });
|
||||
CMD2_ANY ("network.total_handshakes", [](auto, auto) { return torrent::total_handshakes(); });
|
||||
CMD2_ANY ("network.open_sockets", [cm](auto, auto) { return cm->size(); });
|
||||
CMD2_ANY ("network.max_open_sockets", [cm](auto, auto) { return cm->max_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", [cm](auto, auto& value) { return cm->set_max_size(value); });
|
||||
CMD_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
|
||||
CMD_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
|
||||
CMD_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); });
|
||||
|
||||
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
|
||||
CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2));
|
||||
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
CMD2_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); });
|
||||
CMD_ANY_STRING ("network.scgi.open_port", [](auto, auto& arg) { return apply_scgi(arg, 1); });
|
||||
CMD_ANY_STRING ("network.scgi.open_local", [](auto, auto& arg) { return apply_scgi(arg, 2); });
|
||||
CMD_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
CMD_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); });
|
||||
|
||||
CMD2_ANY ("network.scgi.use_gzip", [](const auto&, const auto&) { return rpc::rpc.scgi_allow_compression(); });
|
||||
CMD2_ANY_VALUE_V ("network.scgi.use_gzip.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); });
|
||||
CMD2_ANY ("network.scgi.gzip.min_size", [](const auto&, const auto&) { return rpc::rpc.scgi_min_compress_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); });
|
||||
CMD_ANY ("network.scgi.use_gzip", [](auto, auto) { return rpc::rpc.scgi_allow_compression(); });
|
||||
CMD_ANY_VALUE_V ("network.scgi.use_gzip.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); });
|
||||
CMD_ANY ("network.scgi.gzip.min_size", [](auto, auto) { return rpc::rpc.scgi_min_compress_size(); });
|
||||
CMD_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); });
|
||||
|
||||
CMD2_ANY_STRING ("network.xmlrpc.dialect.set", [](const auto&, const auto& arg) { return apply_xmlrpc_dialect(arg); })
|
||||
CMD2_ANY ("network.xmlrpc.size_limit", [](const auto&, const auto&) { return rpc::rpc.size_limit(); });
|
||||
CMD2_ANY_VALUE_V ("network.xmlrpc.size_limit.set", [](const auto&, const auto& arg) { return rpc::rpc.set_size_limit(arg); });
|
||||
CMD_ANY_STRING ("network.xmlrpc.dialect.set", [](auto, auto& arg) { return apply_xmlrpc_dialect(arg); })
|
||||
CMD_ANY ("network.xmlrpc.size_limit", [](auto, auto) { return rpc::rpc.size_limit(); });
|
||||
CMD_ANY_VALUE_V ("network.xmlrpc.size_limit.set", [](auto, auto& arg) { return rpc::rpc.set_size_limit(arg); });
|
||||
|
||||
CMD2_VAR_BOOL ("network.rpc.use_xmlrpc", true);
|
||||
CMD2_VAR_BOOL ("network.rpc.use_jsonrpc", true);
|
||||
CMD_ANY ("network.rpc.use_xmlrpc", [](auto, auto) { return rpc::rpc.use_xmlrpc(); });
|
||||
CMD_ANY_VALUE_V ("network.rpc.use_xmlrpc.set", [](auto, auto& arg) { return rpc::rpc.set_use_xmlrpc(arg); });
|
||||
CMD_ANY ("network.rpc.use_jsonrpc", [](auto, auto) { return rpc::rpc.use_jsonrpc(); });
|
||||
CMD_ANY_VALUE_V ("network.rpc.use_jsonrpc.set", [](auto, auto& arg) { return rpc::rpc.set_use_jsonrpc(arg); });
|
||||
|
||||
CMD2_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); });
|
||||
CMD2_ANY ("network.block.ipv6", [nw_config](auto, auto) { return nw_config->is_block_ipv6(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv6(value); });
|
||||
CMD2_ANY ("network.block.ipv4in6", [nw_config](auto, auto) { return nw_config->is_block_ipv4in6(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv4in6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4in6(value); });
|
||||
CMD2_ANY ("network.block.outgoing", [nw_config](auto, auto) { return nw_config->is_block_outgoing(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.outgoing.set", [nw_config](auto, auto& value) { return nw_config->set_block_outgoing(value); });
|
||||
CMD2_ANY ("network.prefer.ipv6", [nw_config](auto, auto) { return nw_config->is_prefer_ipv6(); });
|
||||
CMD2_ANY_VALUE_V ("network.prefer.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_prefer_ipv6(value); });
|
||||
CMD_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); });
|
||||
CMD_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); });
|
||||
CMD_ANY ("network.block.ipv6", [nw_config](auto, auto) { return nw_config->is_block_ipv6(); });
|
||||
CMD_ANY_VALUE_V ("network.block.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv6(value); });
|
||||
CMD_ANY ("network.block.ipv4in6", [nw_config](auto, auto) { return nw_config->is_block_ipv4in6(); });
|
||||
CMD_ANY_VALUE_V ("network.block.ipv4in6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4in6(value); });
|
||||
CMD_ANY ("network.block.outgoing", [nw_config](auto, auto) { return nw_config->is_block_outgoing(); });
|
||||
CMD_ANY_VALUE_V ("network.block.outgoing.set", [nw_config](auto, auto& value) { return nw_config->set_block_outgoing(value); });
|
||||
CMD_ANY ("network.prefer.ipv6", [nw_config](auto, auto) { return nw_config->is_prefer_ipv6(); });
|
||||
CMD_ANY_VALUE_V ("network.prefer.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_prefer_ipv6(value); });
|
||||
|
||||
rpc::rpc.mark_safe("network.port_open");
|
||||
rpc::rpc.mark_safe("network.port_random");
|
||||
@@ -332,10 +429,9 @@ initialize_command_network() {
|
||||
rpc::rpc.mark_safe("network.http.max_host_connections");
|
||||
rpc::rpc.mark_safe("network.http.max_total_connections");
|
||||
|
||||
rpc::rpc.mark_safe("network.total_handshakes");
|
||||
rpc::rpc.mark_safe("network.open_files");
|
||||
rpc::rpc.mark_safe("network.max_open_files");
|
||||
rpc::rpc.mark_safe("network.max_open_sockets");
|
||||
rpc::rpc.mark_safe("network.total_handshakes");
|
||||
|
||||
rpc::rpc.mark_safe("network.send_buffer.size");
|
||||
rpc::rpc.mark_safe("network.receive_buffer.size");
|
||||
@@ -343,11 +439,13 @@ initialize_command_network() {
|
||||
rpc::rpc.mark_safe("network.local_address");
|
||||
rpc::rpc.mark_safe("network.xmlrpc.size_limit");
|
||||
rpc::rpc.mark_safe("network.open_sockets");
|
||||
|
||||
rpc::rpc.mark_safe("network.http.cacert");
|
||||
rpc::rpc.mark_safe("network.http.capath");
|
||||
rpc::rpc.mark_safe("network.http.proxy_address");
|
||||
rpc::rpc.mark_safe("network.proxy_address");
|
||||
rpc::rpc.mark_safe("network.proxy.global");
|
||||
rpc::rpc.mark_safe("network.proxy.http");
|
||||
rpc::rpc.mark_safe("network.scgi.dont_route");
|
||||
|
||||
rpc::rpc.mark_safe("protocol.pex");
|
||||
|
||||
rpc::rpc.mark_safe("network.rpc.use_xmlrpc");
|
||||
|
||||
+17
-30
@@ -70,33 +70,35 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
|
||||
|
||||
torrent::Object
|
||||
apply_throttle(const torrent::Object::list_type& args, bool up) {
|
||||
torrent::Object::list_const_iterator argItr = args.begin();
|
||||
auto arg_itr = args.begin();
|
||||
|
||||
if (argItr == args.end())
|
||||
if (arg_itr == args.end())
|
||||
throw torrent::input_error("Missing throttle name.");
|
||||
|
||||
const std::string& name = argItr->as_string();
|
||||
const std::string& name = arg_itr->as_string();
|
||||
if (name.empty() || name == "NULL")
|
||||
throw torrent::input_error("Invalid throttle name '" + name + "'.");
|
||||
|
||||
if (++argItr == args.end() || argItr->as_string().empty())
|
||||
if (++arg_itr == args.end() || arg_itr->as_string().empty())
|
||||
throw torrent::input_error("Missing throttle rate for '" + name + "'.");
|
||||
|
||||
int64_t rate;
|
||||
rpc::parse_whole_value_nothrow(argItr->as_string().c_str(), &rate);
|
||||
rpc::parse_whole_value_nothrow(arg_itr->as_string().c_str(), &rate);
|
||||
|
||||
if (rate < 0)
|
||||
throw torrent::input_error("Throttle rate must be non-negative.");
|
||||
|
||||
core::ThrottleMap::iterator itr = control->core()->throttles().find(name);
|
||||
if (itr == control->core()->throttles().end())
|
||||
itr = control->core()->throttles().insert(std::make_pair(name, torrent::ThrottlePair(NULL, NULL))).first;
|
||||
auto itr = control->core()->throttles().find(name);
|
||||
|
||||
torrent::Throttle*& throttle = up ? itr->second.first : itr->second.second;
|
||||
if (rate != 0 && throttle == NULL)
|
||||
if (itr == control->core()->throttles().end())
|
||||
itr = control->core()->throttles().insert(std::make_pair(name, core::ThrottlePair(nullptr, nullptr))).first;
|
||||
|
||||
auto*& throttle = up ? itr->second.first : itr->second.second;
|
||||
|
||||
if (rate != 0 && throttle == nullptr)
|
||||
throttle = (up ? torrent::up_throttle_global() : torrent::down_throttle_global())->create_slave();
|
||||
|
||||
if (throttle != NULL)
|
||||
if (throttle != nullptr)
|
||||
throttle->set_max_rate(rate * 1024);
|
||||
|
||||
return torrent::Object();
|
||||
@@ -109,10 +111,10 @@ static const int throttle_info_rate = (1 << 3);
|
||||
|
||||
torrent::Object
|
||||
retrieve_throttle_info(const torrent::Object::string_type& name, int flags) {
|
||||
core::ThrottleMap::iterator itr = control->core()->throttles().find(name);
|
||||
torrent::ThrottlePair throttles = itr == control->core()->throttles().end() ? torrent::ThrottlePair(NULL, NULL) : itr->second;
|
||||
torrent::Throttle* throttle = flags & throttle_info_down ? throttles.second : throttles.first;
|
||||
torrent::Throttle* global = flags & throttle_info_down ? torrent::down_throttle_global() : torrent::up_throttle_global();
|
||||
auto itr = control->core()->throttles().find(name);
|
||||
auto throttles = (itr == control->core()->throttles().end()) ? core::ThrottlePair(nullptr, nullptr) : itr->second;
|
||||
auto* throttle = flags & throttle_info_down ? throttles.second : throttles.first;
|
||||
auto* global = flags & throttle_info_down ? torrent::down_throttle_global() : torrent::up_throttle_global();
|
||||
|
||||
if (throttle == NULL && name.empty())
|
||||
throttle = global;
|
||||
@@ -127,20 +129,6 @@ retrieve_throttle_info(const torrent::Object::string_type& name, int flags) {
|
||||
return (int64_t)throttle->max_rate();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_address_throttle(const torrent::Object::list_type& args) {
|
||||
if (args.size() < 2 || args.size() > 3)
|
||||
throw torrent::input_error("Incorrect number of arguments.");
|
||||
|
||||
std::pair<uint32_t, uint32_t> range = parse_address_range(args, ++args.begin());
|
||||
core::ThrottleMap::iterator throttleItr = control->core()->throttles().find(args.begin()->as_string().c_str());
|
||||
if (throttleItr == control->core()->throttles().end())
|
||||
throw torrent::input_error("Throttle not found.");
|
||||
|
||||
control->core()->set_address_throttle(range.first, range.second, throttleItr->second);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
throttle_update(const char* variable, int64_t value) {
|
||||
rpc::commands.call_command(variable, value);
|
||||
@@ -198,7 +186,6 @@ initialize_command_throttle() {
|
||||
// than kB.
|
||||
CMD2_ANY_LIST ("throttle.up", std::bind(&apply_throttle, std::placeholders::_2, true));
|
||||
CMD2_ANY_LIST ("throttle.down", std::bind(&apply_throttle, std::placeholders::_2, false));
|
||||
CMD2_ANY_LIST ("throttle.ip", std::bind(&apply_address_throttle, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING ("throttle.up.max", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_up | throttle_info_max));
|
||||
CMD2_ANY_STRING ("throttle.up.rate", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_up | throttle_info_rate));
|
||||
|
||||
+50
-55
@@ -3,9 +3,10 @@
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <netdb.h>
|
||||
#include <torrent/net/network_config.h>
|
||||
#include <torrent/net/resolver.h>
|
||||
#include <torrent/runtime/network_config.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/tracker/dht_controller.h>
|
||||
#include <torrent/tracker/tracker.h>
|
||||
#include <torrent/utils/log.h>
|
||||
@@ -48,8 +49,10 @@ apply_dht_add_node(const std::string& arg) {
|
||||
|
||||
// TODO: Move this lookup to DhtController.
|
||||
|
||||
auto callback_id = torrent::system::make_callback_id();
|
||||
|
||||
// Currently discarding SOCK_STREAM.
|
||||
torrent::this_thread::resolver()->resolve_specific(nullptr, host_str, PF_INET, [host_str, port](torrent::c_sa_shared_ptr sa, int err) {
|
||||
torrent::this_thread::resolver()->resolve_specific(callback_id, host_str, PF_INET, [host_str, port](torrent::c_sa_shared_ptr sa, int err) {
|
||||
if (sa == nullptr) {
|
||||
lt_log_print(torrent::LOG_DHT_ERROR, "dht.add_node : could not resolve host : %s (%s)", gai_strerror(err), host_str.c_str());
|
||||
return;
|
||||
@@ -68,16 +71,6 @@ apply_enable_trackers(int64_t arg) {
|
||||
for (auto download : *control->core()->download_list())
|
||||
download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
|
||||
|
||||
} else if (rpc::call_command_value("trackers.use_udp") == 0) {
|
||||
for (auto download : *control->core()->download_list()) {
|
||||
download->tracker_controller().for_each([](auto& tracker) {
|
||||
if (tracker.type() == torrent::TRACKER_UDP)
|
||||
tracker.disable();
|
||||
else
|
||||
tracker.enable();
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
for (auto download : *control->core()->download_list())
|
||||
download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
|
||||
@@ -88,69 +81,71 @@ apply_enable_trackers(int64_t arg) {
|
||||
|
||||
void
|
||||
initialize_command_tracker() {
|
||||
CMD2_TRACKER ("t.is_busy", std::bind(&torrent::tracker::Tracker::is_busy, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_enabled", std::bind(&torrent::tracker::Tracker::is_enabled, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_extra_tracker", std::bind(&torrent::tracker::Tracker::is_extra_tracker, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_open", std::bind(&torrent::tracker::Tracker::is_busy, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_scrapable", std::bind(&torrent::tracker::Tracker::is_scrapable, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_usable", std::bind(&torrent::tracker::Tracker::is_usable, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.is_busy", [](auto* tracker, auto) { return tracker->is_requesting(); });
|
||||
CMD2_TRACKER ("t.is_enabled", [](auto* tracker, auto) { return tracker->is_enabled(); });
|
||||
CMD2_TRACKER ("t.is_extra_tracker", [](auto* tracker, auto) { return tracker->is_extra_tracker(); });
|
||||
CMD2_TRACKER ("t.is_open", [](auto* tracker, auto) { return tracker->is_requesting(); });
|
||||
CMD2_TRACKER ("t.is_scrapable", [](auto* tracker, auto) { return tracker->is_scrapable(); });
|
||||
CMD2_TRACKER ("t.is_usable", [](auto* tracker, auto) { return tracker->is_usable(); });
|
||||
|
||||
// TODO: Deprecate.
|
||||
CMD2_TRACKER ("t.can_scrape", std::bind(&torrent::tracker::Tracker::is_scrapable, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.can_scrape", [](auto* tracker, auto) { return tracker->is_scrapable(); });
|
||||
|
||||
CMD2_TRACKER_V ("t.enable", std::bind(&torrent::tracker::Tracker::enable, std::placeholders::_1));
|
||||
CMD2_TRACKER_V ("t.disable", std::bind(&torrent::tracker::Tracker::disable, std::placeholders::_1));
|
||||
CMD2_TRACKER_V ("t.enable", [](auto* tracker, auto) { tracker->enable(); });
|
||||
CMD2_TRACKER_V ("t.disable", [](auto* tracker, auto) { tracker->disable(); });
|
||||
|
||||
CMD2_TRACKER_VALUE_V("t.is_enabled.set", std::bind(&tracker_set_enabled, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_TRACKER_VALUE_V("t.is_enabled.set", [](auto* tracker, auto& value) { return tracker_set_enabled(tracker, value); });
|
||||
|
||||
CMD2_TRACKER ("t.url", std::bind(&torrent::tracker::Tracker::url, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.group", std::bind(&torrent::tracker::Tracker::group, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.type", std::bind(&torrent::tracker::Tracker::type, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.id", std::bind(&torrent::tracker::Tracker::tracker_id, std::placeholders::_1));
|
||||
CMD2_TRACKER ("t.url", [](auto* tracker, auto) { return tracker->url(); });
|
||||
CMD2_TRACKER ("t.group", [](auto* tracker, auto) { return tracker->group(); });
|
||||
CMD2_TRACKER ("t.type", [](auto* tracker, auto) { return tracker->type(); });
|
||||
CMD2_TRACKER ("t.id", [](auto* tracker, auto) { return tracker->tracker_id(); });
|
||||
|
||||
CMD2_TRACKER ("t.latest_event", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().latest_event(); });
|
||||
CMD2_TRACKER ("t.latest_new_peers", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().latest_new_peers(); });
|
||||
CMD2_TRACKER ("t.latest_sum_peers", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().latest_sum_peers(); });
|
||||
CMD2_TRACKER ("t.latest_event", [](auto* tracker, auto) { return tracker->state().latest_event(); });
|
||||
CMD2_TRACKER ("t.latest_new_peers", [](auto* tracker, auto) { return tracker->state().latest_new_peers(); });
|
||||
CMD2_TRACKER ("t.latest_sum_peers", [](auto* tracker, auto) { return tracker->state().latest_sum_peers(); });
|
||||
|
||||
CMD2_TRACKER ("t.normal_interval", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().normal_interval(); });
|
||||
CMD2_TRACKER ("t.min_interval", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().min_interval(); });
|
||||
CMD2_TRACKER ("t.normal_interval", [](auto* tracker, auto) { return tracker->state().normal_interval().count(); });
|
||||
CMD2_TRACKER ("t.min_interval", [](auto* tracker, auto) { return tracker->state().min_interval().count(); });
|
||||
|
||||
CMD2_TRACKER ("t.activity_time_next", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().activity_time_next(); });
|
||||
CMD2_TRACKER ("t.activity_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().activity_time_last(); });
|
||||
CMD2_TRACKER ("t.activity_time_next", [](auto* tracker, auto) { return tracker->state().activity_time_next().count(); });
|
||||
CMD2_TRACKER ("t.activity_time_last", [](auto* tracker, auto) { return tracker->state().activity_time_last().count(); });
|
||||
|
||||
CMD2_TRACKER ("t.success_time_next", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().success_time_next(); });
|
||||
CMD2_TRACKER ("t.success_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().success_time_last(); });
|
||||
CMD2_TRACKER ("t.success_counter", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().success_counter(); });
|
||||
CMD2_TRACKER ("t.success_time_next", [](auto* tracker, auto) { return tracker->state().success_time_next().count(); });
|
||||
CMD2_TRACKER ("t.success_time_last", [](auto* tracker, auto) { return tracker->state().success_time_last().count(); });
|
||||
CMD2_TRACKER ("t.success_counter", [](auto* tracker, auto) { return tracker->state().success_counter(); });
|
||||
|
||||
CMD2_TRACKER ("t.failed_time_next", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().failed_time_next(); });
|
||||
CMD2_TRACKER ("t.failed_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().failed_time_last(); });
|
||||
CMD2_TRACKER ("t.failed_counter", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().failed_counter(); });
|
||||
CMD2_TRACKER ("t.failed_time_next", [](auto* tracker, auto) { return tracker->state().failed_time_next().count(); });
|
||||
CMD2_TRACKER ("t.failed_time_last", [](auto* tracker, auto) { return tracker->state().failed_time_last().count(); });
|
||||
CMD2_TRACKER ("t.failed_counter", [](auto* tracker, auto) { return tracker->state().failed_counter(); });
|
||||
|
||||
CMD2_TRACKER ("t.scrape_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_time_last(); });
|
||||
CMD2_TRACKER ("t.scrape_counter", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_counter(); });
|
||||
CMD2_TRACKER ("t.scrape_time_last", [](auto* tracker, auto) { return tracker->state().scrape_time_last().count(); });
|
||||
CMD2_TRACKER ("t.scrape_counter", [](auto* tracker, auto) { return tracker->state().scrape_counter(); });
|
||||
|
||||
CMD2_TRACKER ("t.scrape_complete", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_complete(); });
|
||||
CMD2_TRACKER ("t.scrape_incomplete", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_incomplete(); });
|
||||
CMD2_TRACKER ("t.scrape_downloaded", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_downloaded(); });
|
||||
CMD2_TRACKER ("t.scrape_complete", [](auto* tracker, auto) { return tracker->state().scrape_complete(); });
|
||||
CMD2_TRACKER ("t.scrape_incomplete", [](auto* tracker, auto) { return tracker->state().scrape_incomplete(); });
|
||||
CMD2_TRACKER ("t.scrape_downloaded", [](auto* tracker, auto) { return tracker->state().scrape_downloaded(); });
|
||||
|
||||
CMD2_ANY_VALUE ("trackers.enable", std::bind(&apply_enable_trackers, int64_t(1)));
|
||||
CMD2_ANY_VALUE ("trackers.disable", std::bind(&apply_enable_trackers, int64_t(0)));
|
||||
CMD2_ANY_VALUE ("trackers.enable", [](auto, auto) { return apply_enable_trackers(1); });
|
||||
CMD2_ANY_VALUE ("trackers.disable", [](auto, auto) { return apply_enable_trackers(0); });
|
||||
CMD2_VAR_BOOL ("trackers.delay_scrape", false);
|
||||
CMD2_VAR_VALUE ("trackers.numwant", -1);
|
||||
CMD2_VAR_BOOL ("trackers.use_udp", true);
|
||||
CMD2_VAR_VALUE ("trackers.numwant", -1);
|
||||
|
||||
auto dht_manager = control->dht_manager();
|
||||
CMD2_ANY ("trackers.use_udp", [](auto, auto) { return true; });
|
||||
CMD2_ANY_VALUE_V ("trackers.use_udp.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_ERROR, "trackers.use_udp.set is no longer supported", 0);
|
||||
})
|
||||
|
||||
CMD2_ANY_STRING_V ("dht.mode.set", std::bind(&core::DhtManager::set_mode, control->dht_manager(), std::placeholders::_2));
|
||||
CMD2_ANY ("dht.port", [](auto, auto) { return torrent::runtime::network_manager()->dht_controller()->port(); });
|
||||
CMD2_ANY_STRING_V ("dht.mode.set", [](auto, auto& str) { return control->dht_manager()->set_mode_by_user(str); });
|
||||
CMD2_ANY ("dht.port", [](auto, auto) { return torrent::runtime::network_manager()->dht_controller()->port(); });
|
||||
CMD2_ANY_VALUE_V ("dht.port.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_DHT_ERROR, "dht.port.set is no longer supported, use dht.override_port.set", 0);
|
||||
});
|
||||
CMD2_ANY ("dht.override_port", std::bind(&torrent::net::NetworkConfig::override_dht_port, torrent::config::network_config()));
|
||||
CMD2_ANY_VALUE_V ("dht.override_port.set", std::bind(&torrent::net::NetworkConfig::set_override_dht_port, torrent::config::network_config(), std::placeholders::_2));
|
||||
CMD2_ANY ("dht.override_port", [](auto, auto) { return torrent::runtime::network_config()->override_dht_port(); });
|
||||
CMD2_ANY_VALUE_V ("dht.override_port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_dht_port(value); });
|
||||
|
||||
CMD2_ANY_STRING ("dht.add_node", std::bind(&apply_dht_add_node, std::placeholders::_2));
|
||||
CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, dht_manager));
|
||||
CMD2_ANY_STRING ("dht.add_node", [](auto, auto& str) { return apply_dht_add_node(str); });
|
||||
CMD2_ANY ("dht.statistics", [](auto, auto) { return control->dht_manager()->dht_statistics(); });
|
||||
|
||||
rpc::rpc.mark_safe("t.url");
|
||||
rpc::rpc.mark_safe("t.group");
|
||||
|
||||
+63
-58
@@ -472,11 +472,14 @@ apply_to_throttle(const torrent::Object& rawArgs) {
|
||||
// if (cond1) { branch1 } else if (cond2) { branch2 } else { branch3 }
|
||||
// <cond1>,<branch1>,<cond2>,<branch2>,<branch3>
|
||||
torrent::Object
|
||||
apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
|
||||
const torrent::Object::list_type& args = rawArgs.as_list();
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
apply_if(rpc::target_type target, const torrent::Object& raw_args, int flags) {
|
||||
auto& args = raw_args.as_list();
|
||||
auto itr = args.begin();
|
||||
|
||||
while (itr != args.end() && itr != --args.end()) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Empty argument list to " + std::string((flags & 0x1) ? "branch" : "if") + ".");
|
||||
|
||||
{
|
||||
torrent::Object tmp;
|
||||
const torrent::Object* conditional;
|
||||
|
||||
@@ -500,40 +503,44 @@ apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
|
||||
result = false;
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Type not supported by 'if'.");
|
||||
throw torrent::input_error("Type not supported by " + std::string((flags & 0x1) ? "branch" : "if") + ".");
|
||||
};
|
||||
|
||||
itr++;
|
||||
|
||||
if (result)
|
||||
break;
|
||||
|
||||
itr++;
|
||||
if (!result && itr != args.end())
|
||||
itr++;
|
||||
}
|
||||
|
||||
if (itr == args.end())
|
||||
return torrent::Object();
|
||||
|
||||
if (flags & 0x1 && itr->is_string()) {
|
||||
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
|
||||
if (flags & 0x1) {
|
||||
if (itr->is_string())
|
||||
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
|
||||
|
||||
} else if (flags & 0x1 && itr->is_dict_key()) {
|
||||
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
|
||||
if (itr->is_dict_key())
|
||||
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
|
||||
|
||||
} else if (flags & 0x1 && itr->is_list()) {
|
||||
// Move this into a special function or something. Also, might be
|
||||
// nice to have a parse_command function that takes list
|
||||
// iterator...
|
||||
if (itr->is_list()) {
|
||||
for (const auto& cmd_itr : itr->as_list()) {
|
||||
if (cmd_itr.is_string())
|
||||
rpc::parse_command(target, cmd_itr.as_string().c_str(), cmd_itr.as_string().c_str() + cmd_itr.as_string().size());
|
||||
|
||||
for (const auto& cmdItr : itr->as_list())
|
||||
if (cmdItr.is_string())
|
||||
rpc::parse_command(target, cmdItr.as_string().c_str(), cmdItr.as_string().c_str() + cmdItr.as_string().size());
|
||||
else if (cmd_itr.is_dict_key())
|
||||
rpc::commands.call_command(cmd_itr.as_dict_key().c_str(), cmd_itr.as_dict_obj(), target);
|
||||
|
||||
return torrent::Object();
|
||||
else
|
||||
throw torrent::input_error("Invalid command type in branch list.");
|
||||
}
|
||||
|
||||
} else {
|
||||
return *itr;
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
throw torrent::input_error("Invalid command type in branch.");
|
||||
}
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -795,61 +802,59 @@ apply_set_color(int color_id, const torrent::Object::string_type& color_str) {
|
||||
|
||||
void
|
||||
initialize_command_ui() {
|
||||
CMD2_VAR_STRING("keys.layout", "qwerty");
|
||||
CMD2_VAR_STRING ("keys.layout", "qwerty");
|
||||
|
||||
CMD2_ANY_STRING("view.add", object_convert_void(std::bind(&core::ViewManager::insert_throw, control->view_manager(), std::placeholders::_2)));
|
||||
CMD2_ANY_STRING ("view.add", object_convert_void(std::bind(&core::ViewManager::insert_throw, control->view_manager(), std::placeholders::_2)));
|
||||
|
||||
CMD2_ANY_L ("view.list", std::bind(&apply_view_list));
|
||||
CMD2_ANY_LIST("view.set", std::bind(&apply_view_set, std::placeholders::_2));
|
||||
CMD2_ANY_L ("view.list", std::bind(&apply_view_list));
|
||||
CMD2_ANY_LIST ("view.set", std::bind(&apply_view_set, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("view.filter", std::bind(&apply_view_event, &core::ViewManager::set_filter, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.filter_on", std::bind(&apply_view_filter_on, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.filter.temp", std::bind(&apply_view_event, &core::ViewManager::set_filter_temp, std::placeholders::_2));
|
||||
CMD2_VAR_STRING("view.filter.temp.excluded", "default,started,stopped");
|
||||
CMD2_VAR_BOOL ("view.filter.temp.log", 0);
|
||||
CMD2_ANY_LIST ("view.filter", std::bind(&apply_view_event, &core::ViewManager::set_filter, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.filter_on", std::bind(&apply_view_filter_on, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.filter.temp", std::bind(&apply_view_event, &core::ViewManager::set_filter_temp, std::placeholders::_2));
|
||||
CMD2_VAR_STRING ("view.filter.temp.excluded", "default,started,stopped");
|
||||
CMD2_VAR_BOOL ("view.filter.temp.log", 0);
|
||||
|
||||
CMD2_ANY_LIST("view.sort", std::bind(&apply_view_sort, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.sort_new", std::bind(&apply_view_event, &core::ViewManager::set_sort_new, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.sort_current", std::bind(&apply_view_event, &core::ViewManager::set_sort_current, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.sort", std::bind(&apply_view_sort, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.sort_new", std::bind(&apply_view_event, &core::ViewManager::set_sort_new, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.sort_current", std::bind(&apply_view_event, &core::ViewManager::set_sort_current, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST("view.event_added", std::bind(&apply_view_event, &core::ViewManager::set_event_added, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.event_removed", std::bind(&apply_view_event, &core::ViewManager::set_event_removed, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.event_added", std::bind(&apply_view_event, &core::ViewManager::set_event_added, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("view.event_removed", std::bind(&apply_view_event, &core::ViewManager::set_event_removed, std::placeholders::_2));
|
||||
|
||||
// Cleanup and add . to view.
|
||||
|
||||
CMD2_ANY_STRING("view.size", std::bind(&cmd_view_size, std::placeholders::_2));
|
||||
CMD2_ANY_STRING("view.size_not_visible", std::bind(&cmd_view_size_not_visible, std::placeholders::_2));
|
||||
CMD2_ANY_STRING("view.persistent", std::bind(&cmd_view_persistent, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("view.size", std::bind(&cmd_view_size, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("view.size_not_visible", std::bind(&cmd_view_size_not_visible, std::placeholders::_2));
|
||||
CMD2_ANY_STRING ("view.persistent", std::bind(&cmd_view_persistent, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_STRING_V("view.filter_all", std::bind(&core::View::filter, std::bind(&core::ViewManager::find_ptr_throw, control->view_manager(), std::placeholders::_2)));
|
||||
|
||||
CMD2_DL_STRING ("view.filter_download", std::bind(&cmd_view_filter_download, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING ("view.set_visible", std::bind(&cmd_view_set_visible, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING ("view.set_not_visible", std::bind(&cmd_view_set_not_visible, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING ("view.filter_download", std::bind(&cmd_view_filter_download, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING ("view.set_visible", std::bind(&cmd_view_set_visible, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING ("view.set_not_visible", std::bind(&cmd_view_set_not_visible, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
// Commands that affect the default rtorrent UI.
|
||||
CMD2_DL ("ui.unfocus_download", std::bind(&cmd_ui_unfocus_download, std::placeholders::_1));
|
||||
CMD2_ANY ("ui.current_view", std::bind(&cmd_ui_current_view));
|
||||
CMD2_ANY_STRING("ui.current_view.set", std::bind(&cmd_ui_set_view, std::placeholders::_2));
|
||||
CMD2_DL ("ui.unfocus_download", std::bind(&cmd_ui_unfocus_download, std::placeholders::_1));
|
||||
CMD2_ANY ("ui.current_view", std::bind(&cmd_ui_current_view));
|
||||
CMD2_ANY_STRING ("ui.current_view.set", std::bind(&cmd_ui_set_view, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("ui.input.history.size", std::bind(&ui::Root::get_input_history_size, control->ui()));
|
||||
CMD2_ANY_VALUE_V("ui.input.history.size.set", std::bind(&ui::Root::set_input_history_size, control->ui(), std::placeholders::_2));
|
||||
CMD2_ANY_V ("ui.input.history.clear", std::bind(&ui::Root::clear_input_history, control->ui()));
|
||||
CMD2_ANY ("ui.input.history.size", std::bind(&ui::Root::get_input_history_size, control->ui()));
|
||||
CMD2_ANY_VALUE_V ("ui.input.history.size.set", std::bind(&ui::Root::set_input_history_size, control->ui(), std::placeholders::_2));
|
||||
CMD2_ANY_V ("ui.input.history.clear", std::bind(&ui::Root::clear_input_history, control->ui()));
|
||||
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.small", 5);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.medium", 50);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.large", 500);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.small", 5);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.medium", 50);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.large", 500);
|
||||
|
||||
CMD2_VAR_VALUE ("ui.focus.page_size", 0);
|
||||
CMD2_VAR_VALUE ("ui.focus.page_size", 0);
|
||||
|
||||
CMD2_ANY_LIST ("ui.status.throttle.up.set", std::bind(&cmd_status_throttle_names, true, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ui.status.throttle.down.set", std::bind(&cmd_status_throttle_names, false, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ui.status.throttle.up.set", std::bind(&cmd_status_throttle_names, true, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("ui.status.throttle.down.set", std::bind(&cmd_status_throttle_names, false, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY ("ui.keymap.style", std::bind(&ui::Root::keymap_style, control->ui()));
|
||||
CMD2_ANY_STRING_V("ui.keymap.style.set", std::bind(&ui::Root::set_keymap_style, control->ui(), std::placeholders::_2));
|
||||
|
||||
// TODO: Add 'option_string' for rtorrent-specific options.
|
||||
CMD2_VAR_STRING("ui.torrent_list.layout", "full");
|
||||
CMD2_VAR_STRING ("ui.torrent_list.layout", "full");
|
||||
|
||||
// Move.
|
||||
CMD2_ANY("print", &apply_print);
|
||||
|
||||
+33
-12
@@ -6,6 +6,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/utils/directory_events.h>
|
||||
|
||||
#include "core/dht_manager.h"
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "rpc/object_storage.h"
|
||||
#include "session/session_manager.h"
|
||||
#include "ui/root.h"
|
||||
#include "utils/watch_ready_queue.h"
|
||||
|
||||
Control::Control()
|
||||
: m_ui(new ui::Root()),
|
||||
@@ -36,7 +38,8 @@ Control::Control()
|
||||
m_commandScheduler(new rpc::CommandScheduler()),
|
||||
m_objectStorage(new rpc::object_storage()),
|
||||
m_lua_engine(new rpc::LuaEngine()),
|
||||
m_directory_events(new torrent::directory_events()) {
|
||||
m_directory_events(new torrent::directory_events()),
|
||||
m_watch_ready_queue(new utils::WatchReadyQueue()) {
|
||||
|
||||
m_core = std::make_unique<core::Manager>();
|
||||
m_view_manager = std::make_unique<core::ViewManager>();
|
||||
@@ -44,7 +47,8 @@ Control::Control()
|
||||
|
||||
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
|
||||
|
||||
m_task_shutdown.slot() = std::bind(&Control::handle_shutdown, this);
|
||||
m_task_shutdown.slot() = [this] { handle_shutdown(); };
|
||||
m_task_shutdown_clear_requests.slot() = [this] { handle_shutdown_clear_requests(); };
|
||||
|
||||
m_commandScheduler->set_slot_error_message([this](const std::string& msg) { m_core->push_log_std(msg); });
|
||||
}
|
||||
@@ -66,15 +70,12 @@ Control::initialize() {
|
||||
display::Window::slot_unschedule([this](display::Window* w) { m_display->unschedule(w); });
|
||||
display::Window::slot_adjust([this]() { m_display->adjust_layout(); });
|
||||
|
||||
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
|
||||
|
||||
m_core->listen_open();
|
||||
m_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
|
||||
|
||||
m_ui->init(this);
|
||||
|
||||
if(!display::Canvas::daemon())
|
||||
m_inputStdin->insert(torrent::this_thread::poll());
|
||||
m_inputStdin->insert();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -82,9 +83,12 @@ Control::cleanup() {
|
||||
rpc::rpc.cleanup();
|
||||
|
||||
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
|
||||
torrent::this_thread::scheduler()->erase(&m_task_shutdown_clear_requests);
|
||||
|
||||
if(!display::Canvas::daemon())
|
||||
m_inputStdin->remove(torrent::this_thread::poll());
|
||||
m_inputStdin->remove();
|
||||
|
||||
m_directory_events->close();
|
||||
|
||||
if (scgi_thread::thread()->is_active())
|
||||
scgi_thread::thread()->stop_thread_wait();
|
||||
@@ -109,7 +113,7 @@ Control::cleanup_exception() {
|
||||
|
||||
bool
|
||||
Control::is_shutdown_completed() {
|
||||
if (!m_shutdownQuick)
|
||||
if (!m_shutdown_quick)
|
||||
return false;
|
||||
|
||||
// Tracker requests can be disowned, so wait for these to
|
||||
@@ -121,18 +125,21 @@ Control::is_shutdown_completed() {
|
||||
if (torrent::net_thread::http_stack()->size() != 0 || !core()->http_queue()->empty())
|
||||
return false;
|
||||
|
||||
return torrent::is_inactive();
|
||||
return core()->is_download_shutdown_completed();
|
||||
}
|
||||
|
||||
void
|
||||
Control::handle_shutdown() {
|
||||
m_watch_ready_queue->shutdown();
|
||||
|
||||
rpc::commands.call_catch("event.system.shutdown", rpc::make_target(), "shutdown", "System shutdown event action failed: ");
|
||||
|
||||
if (scgi_thread::thread()->is_active())
|
||||
scgi_thread::thread()->stop_thread_wait();
|
||||
|
||||
if (!m_shutdownQuick) {
|
||||
if (!m_shutdown_quick) {
|
||||
torrent::runtime::network_manager()->listen_close();
|
||||
torrent::runtime::shutdown();
|
||||
|
||||
m_directory_events->close();
|
||||
m_core->shutdown(false);
|
||||
@@ -141,10 +148,24 @@ Control::handle_shutdown() {
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s);
|
||||
|
||||
} else {
|
||||
torrent::runtime::quick_shutdown();
|
||||
m_core->shutdown(true);
|
||||
}
|
||||
|
||||
m_shutdownQuick = true;
|
||||
m_shutdownReceived = false;
|
||||
if (!m_task_shutdown_clear_requests.is_scheduled())
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown_clear_requests, 10s);
|
||||
|
||||
m_shutdown_quick = true;
|
||||
m_shutdown_received = false;
|
||||
}
|
||||
|
||||
void
|
||||
Control::handle_shutdown_clear_requests() {
|
||||
torrent::net_thread::http_stack()->clear_requests();
|
||||
|
||||
// Use 5s for the initial wait to ensure trackers get a chance to finish both IPv4 and IPv6 requests.
|
||||
if (m_clear_requests_count++ == 0)
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 5s);
|
||||
else
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 1s);
|
||||
}
|
||||
|
||||
+20
-8
@@ -6,7 +6,7 @@
|
||||
#include <memory>
|
||||
#include <sys/types.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
#include <torrent/system/scheduler.h>
|
||||
|
||||
namespace ui {
|
||||
class Root;
|
||||
@@ -38,23 +38,28 @@ namespace torrent {
|
||||
class directory_events;
|
||||
}
|
||||
|
||||
namespace utils {
|
||||
class WatchReadyQueue;
|
||||
}
|
||||
|
||||
class Control {
|
||||
public:
|
||||
Control();
|
||||
~Control();
|
||||
|
||||
bool is_shutdown_completed();
|
||||
bool is_shutdown_received() { return m_shutdownReceived; }
|
||||
bool is_shutdown_started() { return m_shutdownQuick; }
|
||||
bool is_shutdown_received() { return m_shutdown_received; }
|
||||
bool is_shutdown_started() { return m_shutdown_quick; }
|
||||
|
||||
void initialize();
|
||||
void cleanup();
|
||||
void cleanup_exception();
|
||||
|
||||
void handle_shutdown();
|
||||
void handle_shutdown_clear_requests();
|
||||
|
||||
void receive_normal_shutdown() { m_shutdownReceived = true; }
|
||||
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; }
|
||||
void receive_normal_shutdown() { m_shutdown_received = true; }
|
||||
void receive_quick_shutdown() { m_shutdown_received = true; m_shutdown_quick = true; }
|
||||
|
||||
core::Manager* core() { return m_core.get(); }
|
||||
core::ViewManager* view_manager() { return m_view_manager.get(); }
|
||||
@@ -70,6 +75,7 @@ public:
|
||||
rpc::LuaEngine* lua_engine() { return m_lua_engine.get(); }
|
||||
|
||||
torrent::directory_events* directory_events() { return m_directory_events.get(); }
|
||||
utils::WatchReadyQueue* watch_ready_queue() { return m_watch_ready_queue.get(); }
|
||||
|
||||
uint64_t tick() const { return m_tick; }
|
||||
void inc_tick() { m_tick++; }
|
||||
@@ -94,16 +100,22 @@ private:
|
||||
std::unique_ptr<rpc::object_storage> m_objectStorage;
|
||||
std::unique_ptr<rpc::LuaEngine> m_lua_engine;
|
||||
std::unique_ptr<torrent::directory_events> m_directory_events;
|
||||
std::unique_ptr<utils::WatchReadyQueue> m_watch_ready_queue;
|
||||
|
||||
uint64_t m_tick{};
|
||||
|
||||
mode_t m_umask;
|
||||
std::string m_workingDirectory;
|
||||
|
||||
torrent::utils::SchedulerEntry m_task_shutdown;
|
||||
torrent::system::SchedulerEntry m_task_shutdown;
|
||||
torrent::system::SchedulerEntry m_task_shutdown_clear_requests;
|
||||
|
||||
std::atomic<bool> m_shutdownReceived{};
|
||||
std::atomic<bool> m_shutdownQuick{};
|
||||
int m_clear_requests_count{};
|
||||
|
||||
align_cacheline
|
||||
|
||||
std::atomic<bool> m_shutdown_received{};
|
||||
std::atomic<bool> m_shutdown_quick{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+42
-9
@@ -8,6 +8,7 @@
|
||||
#include <torrent/object_stream.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/tracker/dht_controller.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
@@ -140,17 +141,32 @@ DhtManager::save_dht_cache() {
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::set_mode(const std::string& arg) {
|
||||
int i;
|
||||
for (i = 0; i < dht_settings_num; i++) {
|
||||
if (arg == dht_settings[i]) {
|
||||
m_start = i;
|
||||
break;
|
||||
}
|
||||
DhtManager::set_mode_by_user(const std::string& arg) {
|
||||
unsigned int mode = [arg]() {
|
||||
for (int i = 0; i < dht_settings_num; i++) {
|
||||
if (arg == dht_settings[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
throw torrent::input_error("Invalid dht mode: " + arg);
|
||||
}();
|
||||
|
||||
m_set_by_user = true;
|
||||
|
||||
if (!torrent::runtime::is_network_initialized()) {
|
||||
m_start = mode;
|
||||
return;
|
||||
}
|
||||
|
||||
if (i == dht_settings_num)
|
||||
throw torrent::input_error("Invalid argument.");
|
||||
set_mode_directly(mode);
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::set_mode_directly(unsigned int mode) {
|
||||
if (mode >= dht_settings_num)
|
||||
throw torrent::input_error("Invalid dht mode.");
|
||||
|
||||
m_start = mode;
|
||||
|
||||
if (m_start == dht_off)
|
||||
stop_dht();
|
||||
@@ -158,6 +174,23 @@ DhtManager::set_mode(const std::string& arg) {
|
||||
start_dht();
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::set_auto_if_untouched_and_has_session() {
|
||||
if (m_set_by_user) {
|
||||
set_mode_directly(m_start);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpc::call_command_string("session.path").empty()) {
|
||||
LT_LOG("DHT auto-start disabled, session path not set.", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
set_mode_directly(dht_auto);
|
||||
|
||||
LT_LOG("DHT auto-start enabled.", 0);
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::update() {
|
||||
if (!torrent::runtime::network_manager()->is_dht_active())
|
||||
|
||||
+15
-11
@@ -2,12 +2,17 @@
|
||||
#define RTORRENT_CORE_DHT_MANAGER_H
|
||||
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
#include <torrent/system/scheduler.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
class DhtManager {
|
||||
public:
|
||||
static constexpr int dht_disable = 0;
|
||||
static constexpr int dht_off = 1;
|
||||
static constexpr int dht_auto = 2;
|
||||
static constexpr int dht_on = 3;
|
||||
|
||||
~DhtManager();
|
||||
|
||||
void load_dht_cache();
|
||||
@@ -18,16 +23,14 @@ public:
|
||||
void stop_dht();
|
||||
void auto_start() { if (m_start == dht_auto) start_dht(); }
|
||||
|
||||
void set_mode(const std::string& arg);
|
||||
void set_mode_by_user(const std::string& arg);
|
||||
void set_mode_directly(unsigned int mode);
|
||||
|
||||
void set_auto_if_untouched_and_has_session();
|
||||
|
||||
private:
|
||||
static const int dht_disable = 0;
|
||||
static const int dht_off = 1;
|
||||
static const int dht_auto = 2;
|
||||
static const int dht_on = 3;
|
||||
|
||||
static const int dht_settings_num = 4;
|
||||
static const char* dht_settings[dht_settings_num];
|
||||
static constexpr int dht_settings_num = 4;
|
||||
static const char* dht_settings[dht_settings_num];
|
||||
|
||||
void update();
|
||||
bool log_statistics(bool force);
|
||||
@@ -39,10 +42,11 @@ private:
|
||||
uint64_t m_dhtPrevBytesUp;
|
||||
uint64_t m_dhtPrevBytesDown;
|
||||
|
||||
torrent::utils::SchedulerEntry m_update_timeout;
|
||||
torrent::utils::SchedulerEntry m_stop_timeout;
|
||||
torrent::system::SchedulerEntry m_update_timeout;
|
||||
torrent::system::SchedulerEntry m_stop_timeout;
|
||||
|
||||
bool m_warned{};
|
||||
bool m_set_by_user{};
|
||||
int m_start{dht_off};
|
||||
};
|
||||
|
||||
|
||||
+5
-19
@@ -32,21 +32,6 @@ Download::~Download() {
|
||||
m_download = download_type();
|
||||
}
|
||||
|
||||
void
|
||||
Download::enable_udp_trackers(bool state) {
|
||||
for (int idx = 0, end = m_download.tracker_controller().size(); idx < end; ++idx) {
|
||||
auto tracker = m_download.tracker_controller().at(idx);
|
||||
|
||||
if (tracker.type() != torrent::TRACKER_UDP)
|
||||
continue;
|
||||
|
||||
if (state)
|
||||
tracker.enable();
|
||||
else
|
||||
tracker.disable();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Download::priority() {
|
||||
return bencode()->get_key("rtorrent").get_key_value("priority");
|
||||
@@ -103,15 +88,16 @@ Download::distributed_copies() const {
|
||||
}
|
||||
|
||||
void
|
||||
Download::set_throttle_name(const std::string& throttleName) {
|
||||
Download::set_throttle_name(const std::string& name) {
|
||||
if (m_download.info()->is_active())
|
||||
throw torrent::input_error("Cannot set throttle on active download.");
|
||||
|
||||
torrent::ThrottlePair throttles = control->core()->get_throttle(throttleName);
|
||||
auto throttles = control->core()->get_throttle(name);
|
||||
|
||||
m_download.set_upload_throttle(throttles.first);
|
||||
m_download.set_download_throttle(throttles.second);
|
||||
|
||||
m_download.bencode()->get_key("rtorrent").insert_key("throttle_name", throttleName);
|
||||
m_download.bencode()->get_key("rtorrent").insert_key("throttle_name", name);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -131,7 +117,7 @@ Download::set_root_directory(const std::string& path) {
|
||||
|
||||
(file_list->is_multi_file() ?
|
||||
!file_list->is_root_dir_created() :
|
||||
!file_stat.update(file_list->front()->frozen_path()))) {
|
||||
!file_stat.update(file_list->front()->frozen_path().str()))) {
|
||||
|
||||
set_message("Cannot change the directory of an open download after the files have been moved.");
|
||||
rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(this));
|
||||
|
||||
+4
-4
@@ -22,6 +22,8 @@ public:
|
||||
typedef torrent::ConnectionList connection_list_type;
|
||||
typedef download_type::ConnectionType connection_type;
|
||||
|
||||
static constexpr uint32_t default_resume_flags = ~uint32_t{} & ~torrent::Download::open_enable_fallocate;
|
||||
|
||||
static const int variable_hashing_stopped = 0;
|
||||
static const int variable_hashing_initial = 1;
|
||||
static const int variable_hashing_last = 2;
|
||||
@@ -70,8 +72,6 @@ public:
|
||||
const std::string& message() const { return m_message; }
|
||||
void set_message(const std::string& msg) { m_message = msg; }
|
||||
|
||||
void enable_udp_trackers(bool state);
|
||||
|
||||
uint32_t priority();
|
||||
void set_priority(uint32_t p);
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
|
||||
void set_root_directory(const std::string& path);
|
||||
|
||||
void set_throttle_name(const std::string& throttleName);
|
||||
void set_throttle_name(const std::string& name);
|
||||
|
||||
bool operator == (const std::string& str) const;
|
||||
|
||||
@@ -102,7 +102,7 @@ private:
|
||||
download_type m_download;
|
||||
bool m_hashFailed{};
|
||||
std::string m_message;
|
||||
uint32_t m_resumeFlags{~uint32_t{}};
|
||||
uint32_t m_resumeFlags{default_resume_flags};
|
||||
unsigned int m_group{};
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/data/file_utils.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/runtime/client_config.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
#include "control.h"
|
||||
@@ -104,40 +105,42 @@ DownloadFactory::receive_load() {
|
||||
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
|
||||
|
||||
if (is_network_uri(m_uri)) {
|
||||
// Http handling here.
|
||||
m_stream.reset(new std::stringstream);
|
||||
|
||||
HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream);
|
||||
auto done_fn = [this]() { receive_loaded(); };
|
||||
auto failed_fn = [this](const std::string& error) { receive_failed(error); };
|
||||
|
||||
itr->add_done_slot([this]() { receive_loaded(); });
|
||||
itr->add_failed_slot([this](const std::string& error) { receive_failed(error); });
|
||||
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
|
||||
|
||||
m_variables["tied_to_file"] = (int64_t)false;
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (is_magnet_uri(m_uri)) {
|
||||
if (is_magnet_uri(m_uri)) {
|
||||
// DEBUG: Use m_object.
|
||||
m_stream.reset(new std::stringstream());
|
||||
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
|
||||
|
||||
m_variables["tied_to_file"] = (int64_t)false;
|
||||
receive_loaded();
|
||||
|
||||
} else {
|
||||
std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
if (!stream.is_open())
|
||||
return receive_failed("Could not open file");
|
||||
|
||||
m_object = new torrent::Object;
|
||||
stream >> *m_object;
|
||||
|
||||
if (!stream.good())
|
||||
return receive_failed("Reading torrent file failed");
|
||||
|
||||
m_isFile = true;
|
||||
|
||||
receive_loaded();
|
||||
return;
|
||||
}
|
||||
|
||||
std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
if (!stream.is_open())
|
||||
return receive_failed("Could not open file");
|
||||
|
||||
m_object = new torrent::Object;
|
||||
stream >> *m_object;
|
||||
|
||||
if (!stream.good())
|
||||
return receive_failed("Reading torrent file failed");
|
||||
|
||||
m_isFile = true;
|
||||
|
||||
receive_loaded();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -238,9 +241,6 @@ DownloadFactory::receive_success() {
|
||||
rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download));
|
||||
}
|
||||
|
||||
if (!rpc::call_command_value("trackers.use_udp"))
|
||||
download->enable_udp_trackers(false);
|
||||
|
||||
// Skip forcing trackers to scrape when rtorrent starts
|
||||
if (m_initLoad && rpc::call_command_value("trackers.delay_scrape"))
|
||||
download->set_resume_flags(torrent::Download::start_skip_tracker);
|
||||
@@ -272,7 +272,7 @@ DownloadFactory::receive_success() {
|
||||
if (!m_session && m_variables["tied_to_file"].as_value())
|
||||
rpc::call_command("d.tied_to_file.set", m_uri.empty() ? m_variables["tied_file"] : m_uri, rpc::make_target(download));
|
||||
|
||||
rpc::call_command("d.peer_exchange.set", rpc::call_command_value("protocol.pex"), rpc::make_target(download));
|
||||
rpc::call_command("d.peer_exchange.set", torrent::runtime::client_config()->is_pex_enabled(), rpc::make_target(download));
|
||||
|
||||
torrent::resume_load_addresses(*download->download(), resumeObject);
|
||||
torrent::resume_load_file_priorities(*download->download(), resumeObject);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <iosfwd>
|
||||
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
#include <torrent/system/scheduler.h>
|
||||
|
||||
#include "http_queue.h"
|
||||
|
||||
@@ -79,9 +79,9 @@ private:
|
||||
command_list_type m_commands;
|
||||
torrent::Object::map_type m_variables;
|
||||
|
||||
slot_void m_slot_finished;
|
||||
torrent::utils::SchedulerEntry m_task_load;
|
||||
torrent::utils::SchedulerEntry m_task_commit;
|
||||
slot_void m_slot_finished;
|
||||
torrent::system::SchedulerEntry m_task_load;
|
||||
torrent::system::SchedulerEntry m_task_commit;
|
||||
};
|
||||
|
||||
bool is_network_uri(const std::string& uri);
|
||||
|
||||
@@ -331,7 +331,7 @@ DownloadList::resume(Download* download, int flags) {
|
||||
|
||||
// We need to make sure the flags aren't reset if someone decideds
|
||||
// to call resume() while it is hashing, etc.
|
||||
if (download->resume_flags() == ~uint32_t())
|
||||
if (download->resume_flags() == Download::default_resume_flags)
|
||||
download->set_resume_flags(flags);
|
||||
|
||||
// Manual or end-of-download rehashing clears the resume data so
|
||||
@@ -404,7 +404,7 @@ DownloadList::resume(Download* download, int flags) {
|
||||
download->set_priority(download->priority());
|
||||
download->download()->start(download->resume_flags());
|
||||
|
||||
download->set_resume_flags(~uint32_t());
|
||||
download->set_resume_flags(Download::default_resume_flags);
|
||||
|
||||
DL_TRIGGER_EVENT(download, "event.download.resumed");
|
||||
|
||||
@@ -421,7 +421,7 @@ DownloadList::pause(Download* download, int flags) {
|
||||
|
||||
try {
|
||||
|
||||
download->set_resume_flags(~uint32_t());
|
||||
download->set_resume_flags(Download::default_resume_flags);
|
||||
|
||||
rpc::parse_command_single(rpc::make_target(download), "view.set_not_visible=active");
|
||||
|
||||
@@ -492,7 +492,11 @@ DownloadList::hash_done(Download* download) {
|
||||
|
||||
if (!download->is_hash_checked()) {
|
||||
download->set_hash_failed(true);
|
||||
|
||||
|
||||
auto& msg = download->download()->hash_error_message();
|
||||
if (!msg.empty())
|
||||
download->set_message(msg);
|
||||
|
||||
DL_TRIGGER_EVENT(download, "event.download.hash_failed");
|
||||
return;
|
||||
}
|
||||
@@ -656,8 +660,8 @@ DownloadList::confirm_finished(Download* download) {
|
||||
if (find(infohash) == end())
|
||||
return;
|
||||
|
||||
// if (download->resume_flags() != ~uint32_t())
|
||||
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t().");
|
||||
// if (download->resume_flags() != Download::default_resume_flags)
|
||||
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != Download::default_resume_flags.");
|
||||
|
||||
// See #1292.
|
||||
//
|
||||
@@ -667,7 +671,7 @@ DownloadList::confirm_finished(Download* download) {
|
||||
//
|
||||
// TODO: Add a check when setting the flags to see if the torrent is
|
||||
// being hashed.
|
||||
download->set_resume_flags(~uint32_t());
|
||||
download->set_resume_flags(Download::default_resume_flags);
|
||||
|
||||
if (!download->is_active() && rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
|
||||
resume(download,
|
||||
@@ -683,8 +687,10 @@ DownloadList::process_meta_download(Download* download) {
|
||||
rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download));
|
||||
rpc::call_command("d.close", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
std::string metafile = (*download->file_list()->begin())->frozen_path();
|
||||
std::string metafile = (*download->file_list()->begin())->frozen_path().str();
|
||||
|
||||
std::fstream file(metafile.c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
if (!file.is_open()) {
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not read download metadata.");
|
||||
return;
|
||||
@@ -692,11 +698,13 @@ DownloadList::process_meta_download(Download* download) {
|
||||
|
||||
torrent::Object* bencode = new torrent::Object(torrent::Object::create_map());
|
||||
file >> bencode->insert_key("info", torrent::Object());
|
||||
|
||||
if (file.fail()) {
|
||||
delete bencode;
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent.");
|
||||
return;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Steal the keys we still need. The old download has no use for them.
|
||||
@@ -707,6 +715,7 @@ DownloadList::process_meta_download(Download* download) {
|
||||
bencode->insert_key("announce-list", torrent::Object()).swap(download->bencode()->get_key("announce-list"));
|
||||
|
||||
erase_ptr(download);
|
||||
|
||||
control->core()->try_create_download_from_meta_download(bencode, metafile);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,17 +9,21 @@
|
||||
namespace core {
|
||||
|
||||
HttpQueue::iterator
|
||||
HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream) {
|
||||
HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream,
|
||||
std::function<void()> done_fn, std::function<void(const std::string&)> failed_fn) {
|
||||
auto itr = base_type::insert(end(), torrent::net::HttpGet(url, stream));
|
||||
|
||||
itr->set_max_file_size(15 << 20);
|
||||
itr->set_redirect_only_http_https();
|
||||
|
||||
for (auto& slot : m_signal_insert)
|
||||
slot(*itr);
|
||||
|
||||
itr->add_done_slot([this, itr]() { erase(itr); });
|
||||
itr->add_failed_slot([this, itr](auto) { erase(itr); });
|
||||
itr->add_done_slot(torrent::this_thread::thread(), std::move(done_fn));
|
||||
itr->add_done_slot(torrent::this_thread::thread(), [this, itr]() { erase(itr); });
|
||||
|
||||
// TODO: Downloading http torrents doesn't seem to work.
|
||||
// TODO: Quitting no longer works.
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), std::move(failed_fn));
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), [this, itr](auto) { erase(itr); });
|
||||
|
||||
torrent::net_thread::http_stack()->start_get(*itr);
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ public:
|
||||
//
|
||||
// Consider adding a flag to indicate whetever HttpQueue should
|
||||
// delete the stream.
|
||||
iterator insert(const std::string& url, std::shared_ptr<std::ostream> stream);
|
||||
iterator insert(const std::string& url, std::shared_ptr<std::ostream> stream,
|
||||
std::function<void()> done_fn, std::function<void(const std::string&)> failed_fn);
|
||||
void erase(iterator itr);
|
||||
|
||||
void clear();
|
||||
|
||||
+28
-91
@@ -8,17 +8,15 @@
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <rak/regex.h>
|
||||
#include <fnmatch.h>
|
||||
#include <torrent/utils/resume.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/error.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/object_stream.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/net/network_config.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
#include <torrent/runtime/network_config.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
@@ -35,6 +33,8 @@
|
||||
#include "core/http_queue.h"
|
||||
#include "core/view.h"
|
||||
|
||||
#include <torrent/runtime/client_config.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
const int Manager::create_start;
|
||||
@@ -65,6 +65,20 @@ Manager::~Manager() {
|
||||
torrent::Throttle::destroy_throttle(m_throttles["NULL"].first);
|
||||
}
|
||||
|
||||
bool
|
||||
Manager::is_download_shutdown_completed() {
|
||||
for (const auto& download : *download_list()) {
|
||||
// TODO: Why is this being checked?
|
||||
// if (download->tracker_controller().is_active())
|
||||
// return false;
|
||||
|
||||
if (download->tracker_controller().has_active_trackers_not_dht_scrape_disownable())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_hashing_view(View* v) {
|
||||
if (v == nullptr || m_hashingView != nullptr)
|
||||
@@ -74,10 +88,10 @@ Manager::set_hashing_view(View* v) {
|
||||
m_hashingView->signal_changed().push_back(std::bind(&Manager::receive_hashing_changed, this));
|
||||
}
|
||||
|
||||
torrent::ThrottlePair
|
||||
ThrottlePair
|
||||
Manager::get_throttle(const std::string& name) {
|
||||
ThrottleMap::const_iterator itr = m_throttles.find(name);
|
||||
torrent::ThrottlePair throttles = (itr == m_throttles.end() ? torrent::ThrottlePair(nullptr, nullptr) : itr->second);
|
||||
auto itr = m_throttles.find(name);
|
||||
auto throttles = (itr == m_throttles.end() ? ThrottlePair(nullptr, nullptr) : itr->second);
|
||||
|
||||
if (throttles.first == nullptr)
|
||||
throttles.first = torrent::up_throttle_global();
|
||||
@@ -88,20 +102,6 @@ Manager::get_throttle(const std::string& name) {
|
||||
return throttles;
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles) {
|
||||
m_addressThrottles.set_merge(begin, end, throttles);
|
||||
torrent::connection_manager()->address_throttle() = std::bind(&core::Manager::get_address_throttle, control->core(), std::placeholders::_1);
|
||||
}
|
||||
|
||||
torrent::ThrottlePair
|
||||
Manager::get_address_throttle(const sockaddr* addr) {
|
||||
if (addr->sa_family != AF_INET)
|
||||
return torrent::ThrottlePair(nullptr, nullptr);
|
||||
|
||||
return m_addressThrottles.get(ntohl(reinterpret_cast<const sockaddr_in*>(addr)->sin_addr.s_addr), torrent::ThrottlePair(nullptr, nullptr));
|
||||
}
|
||||
|
||||
int64_t
|
||||
Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool rate, bool up) {
|
||||
ThrottleMap::iterator itr = throttles().find(name);
|
||||
@@ -153,76 +153,12 @@ Manager::cleanup() {
|
||||
|
||||
void
|
||||
Manager::shutdown(bool force) {
|
||||
if (!force)
|
||||
if (!force) {
|
||||
for (auto d : *m_download_list)
|
||||
m_download_list->pause_default(d);
|
||||
else
|
||||
} else {
|
||||
for (auto d : *m_download_list)
|
||||
m_download_list->close_quick(d);
|
||||
}
|
||||
|
||||
void
|
||||
Manager::listen_open() {
|
||||
// This stuff really should be moved outside of manager, make it
|
||||
// part of the init script.
|
||||
if (!rpc::call_command_value("network.port_open"))
|
||||
return;
|
||||
|
||||
int portFirst, portLast;
|
||||
torrent::Object portRange = rpc::call_command("network.port_range");
|
||||
|
||||
if (!portRange.is_string())
|
||||
throw torrent::input_error("Invalid port_range argument type.");
|
||||
|
||||
if (std::sscanf(portRange.as_string().c_str(), "%i-%i", &portFirst, &portLast) != 2)
|
||||
throw torrent::input_error("Invalid port_range argument.");
|
||||
|
||||
if (portFirst > portLast || portLast >= (1 << 16))
|
||||
throw torrent::input_error("Invalid port range.");
|
||||
|
||||
if (rpc::call_command_value("network.port_random")) {
|
||||
int boundary = portFirst + random() % (portLast - portFirst + 1);
|
||||
|
||||
if (torrent::runtime::network_manager()->listen_open(boundary, portLast) ||
|
||||
torrent::runtime::network_manager()->listen_open(portFirst, boundary))
|
||||
return;
|
||||
|
||||
} else {
|
||||
if (torrent::runtime::network_manager()->listen_open(portFirst, portLast))
|
||||
return;
|
||||
}
|
||||
|
||||
throw torrent::input_error("Could not open/bind port for listening: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_proxy_address(const std::string& addr) {
|
||||
int port;
|
||||
torrent::sa_unique_ptr sa;
|
||||
|
||||
std::string buf(addr.length() + 1, '\0');
|
||||
|
||||
int err = std::sscanf(addr.c_str(), "%[^:]:%i", buf.data(), &port);
|
||||
|
||||
if (err <= 0)
|
||||
throw torrent::input_error("Could not parse proxy address.");
|
||||
|
||||
if (err == 1)
|
||||
port = 80;
|
||||
|
||||
try {
|
||||
sa = torrent::sa_copy(torrent::sa_lookup_address(buf, AF_INET).get());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
throw torrent::input_error("Could not resolve proxy address: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
try {
|
||||
torrent::sa_set_port(sa.get(), port);
|
||||
torrent::config::network_config()->set_proxy_address(sa.get());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,9 +330,9 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
// Might be an idea to use depth-first search instead.
|
||||
|
||||
for (; first != last; ++first) {
|
||||
rak::regex r(*first);
|
||||
const std::string& pattern = *first;
|
||||
|
||||
if (r.pattern().empty())
|
||||
if (pattern.empty())
|
||||
continue;
|
||||
|
||||
// Special case for ".."?
|
||||
@@ -404,8 +340,8 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
for (auto& itr : currentCache) {
|
||||
// Only include filenames starting with '.' if the pattern
|
||||
// starts with the same.
|
||||
itr.update((r.pattern()[0] != '.') ? utils::Directory::update_hide_dot : 0);
|
||||
itr.erase(std::remove_if(itr.begin(), itr.end(), [r](const utils::directory_entry& entry) { return !r(entry.s_name); }), itr.end());
|
||||
itr.update((pattern[0] != '.') ? utils::Directory::update_hide_dot : 0);
|
||||
itr.erase(std::remove_if(itr.begin(), itr.end(), [&pattern](const utils::directory_entry& entry) { return fnmatch(pattern.c_str(), entry.s_name.c_str(), 0) != 0; }), itr.end());
|
||||
|
||||
for (const auto& cache : itr)
|
||||
nextCache.push_back(path_expand_transform(itr.path() + (itr.path() == "/" ? "" : "/"), cache));
|
||||
@@ -500,6 +436,7 @@ Manager::receive_hashing_changed() {
|
||||
|
||||
} else {
|
||||
(*itr)->set_hash_failed(true);
|
||||
(*itr)->set_message("Hashing failed: " + std::string(e.what()));
|
||||
lt_log_print(torrent::LOG_TORRENT_ERROR, "Hashing failed: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
+12
-21
@@ -5,7 +5,6 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <torrent/utils/log_buffer.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/object.h>
|
||||
|
||||
#include "download_list.h"
|
||||
@@ -23,7 +22,8 @@ namespace core {
|
||||
|
||||
class HttpQueue;
|
||||
|
||||
typedef std::map<std::string, torrent::ThrottlePair> ThrottleMap;
|
||||
using ThrottlePair = std::pair<torrent::Throttle*, torrent::Throttle*>;
|
||||
using ThrottleMap = std::map<std::string, ThrottlePair>;
|
||||
|
||||
class View;
|
||||
|
||||
@@ -35,32 +35,26 @@ public:
|
||||
Manager();
|
||||
~Manager();
|
||||
|
||||
DownloadList* download_list() { return m_download_list.get(); }
|
||||
FileStatusCache* file_status_cache() { return m_file_status_cache.get(); }
|
||||
bool is_download_shutdown_completed();
|
||||
|
||||
HttpQueue* http_queue() { return m_http_queue.get(); }
|
||||
DownloadList* download_list() { return m_download_list.get(); }
|
||||
FileStatusCache* file_status_cache() { return m_file_status_cache.get(); }
|
||||
|
||||
View* hashing_view() { return m_hashingView; }
|
||||
HttpQueue* http_queue() { return m_http_queue.get(); }
|
||||
|
||||
View* hashing_view() { return m_hashingView; }
|
||||
void set_hashing_view(View* v);
|
||||
|
||||
torrent::log_buffer* log_important() { return m_log_important.get(); }
|
||||
torrent::log_buffer* log_complete() { return m_log_complete.get(); }
|
||||
auto* log_important() { return m_log_important.get(); }
|
||||
auto* log_complete() { return m_log_complete.get(); }
|
||||
|
||||
ThrottleMap& throttles() { return m_throttles; }
|
||||
torrent::ThrottlePair get_throttle(const std::string& name);
|
||||
ThrottleMap& throttles() { return m_throttles; }
|
||||
ThrottlePair get_throttle(const std::string& name);
|
||||
|
||||
int64_t retrieve_throttle_value(const torrent::Object::string_type& name, bool rate, bool up);
|
||||
|
||||
// Use custom throttle for the given range of IP addresses.
|
||||
void set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles);
|
||||
torrent::ThrottlePair get_address_throttle(const sockaddr* addr);
|
||||
|
||||
void cleanup();
|
||||
|
||||
void listen_open();
|
||||
|
||||
void set_proxy_address(const std::string& addr);
|
||||
|
||||
const std::string& magnet_path();
|
||||
void set_magnet_path(const std::string& path);
|
||||
|
||||
@@ -85,8 +79,6 @@ public:
|
||||
void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile);
|
||||
|
||||
private:
|
||||
typedef RangeMap<uint32_t, torrent::ThrottlePair> AddressThrottleMap;
|
||||
|
||||
void create_http(const std::string& uri);
|
||||
void create_final(std::istream* s);
|
||||
|
||||
@@ -102,7 +94,6 @@ private:
|
||||
View* m_hashingView{};
|
||||
|
||||
ThrottleMap m_throttles;
|
||||
AddressThrottleMap m_addressThrottles;
|
||||
|
||||
torrent::log_buffer_ptr m_log_important;
|
||||
torrent::log_buffer_ptr m_log_complete;
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
#include <torrent/system/scheduler.h>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
@@ -153,8 +153,8 @@ private:
|
||||
|
||||
std::chrono::microseconds m_last_changed{};
|
||||
|
||||
signal_void m_signal_changed;
|
||||
torrent::utils::SchedulerEntry m_delay_changed;
|
||||
signal_void m_signal_changed;
|
||||
torrent::system::SchedulerEntry m_delay_changed;
|
||||
};
|
||||
|
||||
} // namespace core
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(HAVE_NCURSESW_CURSES_H)
|
||||
#if defined(HAVE_NO_NCURSES)
|
||||
#include "curses_stub.h"
|
||||
#elif defined(HAVE_NCURSESW_CURSES_H)
|
||||
#include <ncursesw/curses.h>
|
||||
#elif defined(HAVE_NCURSESW_H)
|
||||
#include <ncursesw.h>
|
||||
|
||||
@@ -132,8 +132,7 @@ Canvas::resize_term(std::pair<int, int> dim) {
|
||||
|
||||
inline unsigned int
|
||||
Canvas::get_x() {
|
||||
int x;
|
||||
[[maybe_unused]] int y;
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getyx(m_window, y, x);
|
||||
} else {
|
||||
@@ -144,7 +143,7 @@ Canvas::get_x() {
|
||||
|
||||
inline unsigned int
|
||||
Canvas::get_y() {
|
||||
int x, y;
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getyx(m_window, y, x);
|
||||
} else {
|
||||
@@ -155,8 +154,7 @@ Canvas::get_y() {
|
||||
|
||||
inline unsigned int
|
||||
Canvas::width() {
|
||||
int x;
|
||||
[[maybe_unused]] int y;
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(m_window, y, x);
|
||||
} else {
|
||||
@@ -167,7 +165,7 @@ Canvas::width() {
|
||||
|
||||
inline unsigned int
|
||||
Canvas::height() {
|
||||
int x, y;
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(m_window, y, x);
|
||||
} else {
|
||||
@@ -257,8 +255,7 @@ Canvas::set_default_attributes(int attr) {
|
||||
|
||||
inline int
|
||||
Canvas::get_screen_width() {
|
||||
int x;
|
||||
[[maybe_unused]] int y;
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(stdscr, y, x);
|
||||
} else {
|
||||
@@ -269,7 +266,7 @@ Canvas::get_screen_width() {
|
||||
|
||||
inline int
|
||||
Canvas::get_screen_height() {
|
||||
int x, y;
|
||||
[[maybe_unused]] int x, y;
|
||||
if (!m_daemon) {
|
||||
getmaxyx(stdscr, y, x);
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#if defined(HAVE_NO_NCURSES)
|
||||
#include "curses_stub.h"
|
||||
#else
|
||||
#include <curses.h>
|
||||
#endif
|
||||
|
||||
namespace display {
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// Dummy ncurses stub: provides the stdscr symbol expected by the codebase.
|
||||
|
||||
#include "curses_stub.h"
|
||||
|
||||
// Define stdscr as a null pointer; all ncurses calls are no-ops in this stub.
|
||||
WINDOW* stdscr = nullptr;
|
||||
@@ -0,0 +1,108 @@
|
||||
// Dummy ncurses stub header for building rtorrent without ncurses.
|
||||
// Provides types, macros, and no-op function stubs so the codebase
|
||||
// compiles without a real curses library. All display functions become
|
||||
// no-ops; use with system.daemon.set = true.
|
||||
|
||||
#ifndef RTORRENT_DISPLAY_CURSES_STUB_H
|
||||
#define RTORRENT_DISPLAY_CURSES_STUB_H
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstddef>
|
||||
|
||||
// Opaque window type
|
||||
typedef void* WINDOW;
|
||||
|
||||
// Character type used by curses
|
||||
typedef unsigned int chtype;
|
||||
typedef unsigned int attr_t;
|
||||
|
||||
// The standard screen
|
||||
extern WINDOW* stdscr;
|
||||
|
||||
// Boolean constants and return codes
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef ERR
|
||||
#define ERR (-1)
|
||||
#endif
|
||||
|
||||
// Attribute constants
|
||||
#define A_NORMAL 0
|
||||
#define A_STANDOUT (1U << 8)
|
||||
#define A_UNDERLINE (1U << 9)
|
||||
#define A_REVERSE (1U << 10)
|
||||
#define A_BLINK (1U << 11)
|
||||
#define A_DIM (1U << 12)
|
||||
#define A_BOLD (1U << 13)
|
||||
|
||||
// Color support
|
||||
#define COLORS 0
|
||||
#define COLOR_BLACK 0
|
||||
#define COLOR_RED 1
|
||||
#define COLOR_GREEN 2
|
||||
#define COLOR_YELLOW 3
|
||||
#define COLOR_BLUE 4
|
||||
#define COLOR_MAGENTA 5
|
||||
#define COLOR_CYAN 6
|
||||
#define COLOR_WHITE 7
|
||||
|
||||
#define COLOR_PAIR(n) 0
|
||||
|
||||
// Key constants
|
||||
#define KEY_DOWN 0x102
|
||||
#define KEY_UP 0x103
|
||||
#define KEY_LEFT 0x104
|
||||
#define KEY_RIGHT 0x105
|
||||
#define KEY_HOME 0x106
|
||||
#define KEY_BACKSPACE 0x107
|
||||
#define KEY_DC 0x14a
|
||||
#define KEY_ENTER 0x157
|
||||
#define KEY_NPAGE 0x152
|
||||
#define KEY_PPAGE 0x153
|
||||
#define KEY_END 0x168
|
||||
#define KEY_MOUSE 0x199
|
||||
#define KEY_RESIZE 0x19a
|
||||
|
||||
// Stubbed functions
|
||||
inline WINDOW* initscr() { return nullptr; }
|
||||
inline int endwin() { return 0; }
|
||||
inline WINDOW* newwin(int, int, int, int) { return nullptr; }
|
||||
inline int delwin(WINDOW*) { return 0; }
|
||||
inline int wresize(WINDOW*, int, int) { return 0; }
|
||||
inline int mvwin(WINDOW*, int, int) { return 0; }
|
||||
inline int wnoutrefresh(WINDOW*) { return 0; }
|
||||
inline int redrawwin(WINDOW*) { return 0; }
|
||||
inline int werase(WINDOW*) { return 0; }
|
||||
inline int wmove(WINDOW*, int, int) { return 0; }
|
||||
inline int vw_printw(WINDOW*, char*, va_list) { return 0; }
|
||||
inline int waddch(WINDOW*, const chtype) { return 0; }
|
||||
inline int mvwaddch(WINDOW*, int, int, const chtype) { return 0; }
|
||||
inline int mvwchgat(WINDOW*, int, int, int, attr_t, short, const void*) { return 0; }
|
||||
inline int wattrset(WINDOW*, int) { return 0; }
|
||||
inline int wattr_get(WINDOW*, attr_t*, short*, void*) { return 0; }
|
||||
inline int wattr_set(WINDOW*, attr_t, short, void*) { return 0; }
|
||||
inline int doupdate() { return 0; }
|
||||
inline int start_color() { return 0; }
|
||||
inline int use_default_colors() { return 0; }
|
||||
inline int raw() { return 0; }
|
||||
inline int noraw() { return 0; }
|
||||
inline int noecho() { return 0; }
|
||||
inline int nodelay(WINDOW*, bool) { return 0; }
|
||||
inline int keypad(WINDOW*, bool) { return 0; }
|
||||
inline int curs_set(int) { return 0; }
|
||||
inline int init_pair(short, short, short) { return 0; }
|
||||
inline int pair_content(short, short*, short*) { return 0; }
|
||||
inline int resizeterm(int, int) { return 0; }
|
||||
inline int getch() { return ERR; }
|
||||
inline int set_escdelay(int) { return 0; }
|
||||
|
||||
// getyx / getmaxyx are macros in real ncurses; stub them as no-ops
|
||||
#define getyx(w, y, x) do { (y) = 0; (x) = 0; } while (0)
|
||||
#define getmaxyx(w, y, x) do { (y) = 24; (x) = 80; } while (0)
|
||||
|
||||
#endif // RTORRENT_DISPLAY_CURSES_STUB_H
|
||||
@@ -80,10 +80,14 @@ Manager::schedule_update(std::chrono::microseconds min_interval) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_task_update.is_scheduled() && m_task_update.time() <= m_scheduler.front()->time())
|
||||
auto cached = torrent::this_thread::cached_time();
|
||||
m_scheduler.external_set_cached_time(cached);
|
||||
auto next = cached + m_scheduler.next_timeout(cached);
|
||||
|
||||
if (m_task_update.is_scheduled() && m_task_update.time_or_zero() <= next)
|
||||
return;
|
||||
|
||||
torrent::this_thread::scheduler()->update_wait_until(&m_task_update, std::max(m_scheduler.front()->time(), m_time_last_update + min_interval));
|
||||
torrent::this_thread::scheduler()->update_wait_until(&m_task_update, std::max(next, m_time_last_update + min_interval));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef RTORRENT_DISPLAY_MANAGER_H
|
||||
#define RTORRENT_DISPLAY_MANAGER_H
|
||||
|
||||
#include <torrent/utils/scheduler.h>
|
||||
#include <torrent/system/scheduler.h>
|
||||
|
||||
#include "display/frame.h"
|
||||
|
||||
@@ -31,9 +31,9 @@ private:
|
||||
bool m_force_redraw{false};
|
||||
Frame m_root_frame;
|
||||
|
||||
std::chrono::microseconds m_time_last_update{};
|
||||
torrent::utils::ExternalScheduler m_scheduler;
|
||||
torrent::utils::SchedulerEntry m_task_update;
|
||||
std::chrono::microseconds m_time_last_update{};
|
||||
torrent::system::ExternalScheduler m_scheduler;
|
||||
torrent::system::SchedulerEntry m_task_update;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+10
-9
@@ -7,7 +7,6 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/torrent.h>
|
||||
@@ -16,9 +15,11 @@
|
||||
#include <torrent/data/file_manager.h>
|
||||
#include <torrent/download/resource_manager.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/net/network_config.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
#include <torrent/peer/client_info.h>
|
||||
#include <torrent/runtime/network_config.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/runtime/socket_manager.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
@@ -154,7 +155,7 @@ print_download_status(char* first, char* last, core::Download* d) {
|
||||
|
||||
} else if (d->tracker_controller().has_active_trackers_not_scrape()) {
|
||||
auto tracker = d->tracker_controller().find_if([](const auto& t) {
|
||||
return t.is_busy_not_scrape();
|
||||
return t.is_requesting_not_scrape();
|
||||
});
|
||||
|
||||
if (tracker.is_valid()) {
|
||||
@@ -376,7 +377,7 @@ print_status_info(char* first, char* last) {
|
||||
first = print_buffer(first, last, " KB]");
|
||||
first = print_buffer(first, last, " [Port: %i]", (unsigned int)torrent::runtime::listen_port());
|
||||
|
||||
auto local_address = torrent::config::network_config()->local_address_best_match();
|
||||
auto local_address = torrent::runtime::network_config()->local_address_best_match();
|
||||
|
||||
if (!torrent::sa_is_any(local_address.get())) {
|
||||
first = print_buffer(first, last, " [Local ");
|
||||
@@ -387,8 +388,8 @@ print_status_info(char* first, char* last) {
|
||||
if (first > last)
|
||||
throw torrent::internal_error("print_status_info(...) wrote past end of the buffer.");
|
||||
|
||||
auto bind_inet_address = torrent::config::network_config()->bind_inet_address();
|
||||
auto bind_inet6_address = torrent::config::network_config()->bind_inet6_address();
|
||||
auto bind_inet_address = torrent::runtime::network_config()->bind_inet_address();
|
||||
auto bind_inet6_address = torrent::runtime::network_config()->bind_inet6_address();
|
||||
bool show_bind_inet = !torrent::sa_is_any(bind_inet_address.get());
|
||||
bool show_bind_inet6 = !torrent::sa_is_any(bind_inet6_address.get());
|
||||
|
||||
@@ -426,9 +427,9 @@ print_status_extra(char* first, char* last) {
|
||||
torrent::net_thread::http_stack()->max_total_connections());
|
||||
|
||||
first = print_buffer(first, last, " [S %i/%i/%i]",
|
||||
torrent::total_handshakes(),
|
||||
torrent::connection_manager()->size(),
|
||||
torrent::connection_manager()->max_size());
|
||||
torrent::runtime::total_handshakes(),
|
||||
torrent::runtime::socket_manager()->size(),
|
||||
torrent::runtime::socket_manager()->max_size());
|
||||
|
||||
first = print_buffer(first, last, " [F %i/%i]",
|
||||
torrent::file_manager()->open_files(),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define RTORRENT_WINDOW_BASE_H
|
||||
|
||||
#include <functional>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
#include <torrent/system/scheduler.h>
|
||||
#include <torrent/system/thread.h>
|
||||
|
||||
#include "canvas.h"
|
||||
@@ -99,7 +99,7 @@ protected:
|
||||
extent_type m_max_width;
|
||||
extent_type m_max_height;
|
||||
|
||||
torrent::utils::SchedulerEntry m_task_update;
|
||||
torrent::system::SchedulerEntry m_task_update;
|
||||
};
|
||||
|
||||
// Return a range with a distance of no more than __distance and
|
||||
|
||||
@@ -135,8 +135,11 @@ WindowFileList::redraw() {
|
||||
m_canvas->print(0, pos, "%*c%-*s", 16, ' ', filenameWidth, "EMPTY");
|
||||
|
||||
} else if (itr.is_entering()) {
|
||||
m_canvas->print(0, pos, "%*c %ls", 16 + itr.depth(), '\\',
|
||||
itr.depth() < itr.file()->path()->size() ? wstring_width(itr.file()->path()->at(itr.depth()), filenameWidth - itr.depth() - 1).c_str() : L"UNKNOWN");
|
||||
if (itr.depth() < itr.file()->path()->size())
|
||||
m_canvas->print(0, pos, "%*c %ls", 16 + itr.depth(), '\\',
|
||||
wstring_width(itr.file()->path()->at(itr.depth()).str(), filenameWidth - itr.depth() - 1).c_str());
|
||||
else
|
||||
m_canvas->print(0, pos, "%*c %ls", 16 + itr.depth(), '\\', L"UNKNOWN");
|
||||
|
||||
} else if (itr.is_leaving()) {
|
||||
m_canvas->print(0, pos, "%*c %-*s", 16 + (itr.depth() - 1), '/', filenameWidth - (itr.depth() - 1), "");
|
||||
@@ -166,8 +169,12 @@ WindowFileList::redraw() {
|
||||
else
|
||||
m_canvas->print(8, pos, "%5.1f T", (double)val / (int64_t(1) << 40));
|
||||
|
||||
m_canvas->print(15, pos, "%*c %ls", 1 + itr.depth(), '|',
|
||||
itr.depth() < itr.file()->path()->size() ? wstring_width(itr.file()->path()->at(itr.depth()), filenameWidth - itr.depth() - 1).c_str() : L"UNKNOWN");
|
||||
if (itr.depth() < itr.file()->path()->size())
|
||||
m_canvas->print(15, pos, "%*c %ls", 1 + itr.depth(), '|',
|
||||
wstring_width(itr.file()->path()->at(itr.depth()).str(), filenameWidth - itr.depth() - 1).c_str());
|
||||
else
|
||||
m_canvas->print(15, pos, "%*c %ls", 1 + itr.depth(), '|', L"UNKNOWN");
|
||||
|
||||
|
||||
} else {
|
||||
m_canvas->print(0, pos, "BORK BORK");
|
||||
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
signal_curl_get::iterator m_conn_insert;
|
||||
signal_curl_get::iterator m_conn_erase;
|
||||
|
||||
torrent::utils::SchedulerEntry m_task_deactivate;
|
||||
torrent::system::SchedulerEntry m_task_deactivate;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <ctime>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/system/thread.h>
|
||||
|
||||
#include "canvas.h"
|
||||
@@ -14,16 +15,18 @@ WindowLog::WindowLog(torrent::log_buffer* l) :
|
||||
Window(new Canvas, 0, 0, 0, extent_full, extent_static),
|
||||
m_log(l) {
|
||||
|
||||
m_task_update.slot() = std::bind(&WindowLog::receive_update, this);
|
||||
m_task_update.slot() = [this]() { receive_update(); };
|
||||
|
||||
unsigned int signal_index = torrent::main_thread::thread()->signal_bitfield()->add_signal(std::bind(&WindowLog::receive_update, this));
|
||||
m_log->lock_and_set_update_slot([this]() {
|
||||
if (m_log_updating.exchange(true) == true)
|
||||
return;
|
||||
|
||||
m_log->lock_and_set_update_slot([signal_index]() {
|
||||
torrent::main_thread::thread()->send_event_signal(signal_index, false);
|
||||
});
|
||||
torrent::main_thread::callback([this]() { receive_update(); });
|
||||
});
|
||||
}
|
||||
|
||||
WindowLog::~WindowLog() {
|
||||
m_log->lock_and_set_update_slot(nullptr);
|
||||
torrent::this_thread::scheduler()->erase(&m_task_update);
|
||||
}
|
||||
|
||||
@@ -52,11 +55,13 @@ WindowLog::redraw() {
|
||||
// gets updated.
|
||||
void
|
||||
WindowLog::receive_update() {
|
||||
m_log_updating = false;
|
||||
|
||||
if (!is_active())
|
||||
return;
|
||||
|
||||
iterator itr = find_older();
|
||||
extent_type height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
|
||||
auto itr = find_older();
|
||||
auto height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
|
||||
|
||||
if (height != m_max_height) {
|
||||
m_min_height = height != 0 ? 1 : 0;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef RTORRENT_DISPLAY_WINDOW_LOG_H
|
||||
#define RTORRENT_DISPLAY_WINDOW_LOG_H
|
||||
|
||||
#include <torrent/system/scheduler.h>
|
||||
#include <torrent/utils/log_buffer.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
|
||||
#include "window.h"
|
||||
|
||||
@@ -22,8 +22,12 @@ public:
|
||||
private:
|
||||
inline iterator find_older();
|
||||
|
||||
torrent::log_buffer* m_log;
|
||||
torrent::utils::SchedulerEntry m_task_update;
|
||||
torrent::log_buffer* m_log;
|
||||
torrent::system::SchedulerEntry m_task_update;
|
||||
|
||||
align_cacheline
|
||||
|
||||
std::atomic<bool> m_log_updating{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ WindowTrackerList::redraw() {
|
||||
if (pos < m_canvas->height()) {
|
||||
const char* state;
|
||||
|
||||
if (tracker.is_busy_not_scrape())
|
||||
if (tracker.is_requesting_not_scrape())
|
||||
state = "req ";
|
||||
else if (tracker.is_busy())
|
||||
else if (tracker.is_requesting())
|
||||
state = "scr ";
|
||||
else
|
||||
state = " ";
|
||||
@@ -79,7 +79,7 @@ WindowTrackerList::redraw() {
|
||||
m_canvas->set_attr(4, pos - 1, m_canvas->width(), is_focused() ? A_REVERSE : A_BOLD, COLOR_PAIR(0));
|
||||
}
|
||||
|
||||
if (tracker.is_busy()) {
|
||||
if (tracker.is_requesting()) {
|
||||
m_canvas->set_attr(0, pos - 2, 4, A_REVERSE, COLOR_PAIR(0));
|
||||
m_canvas->set_attr(0, pos - 1, 4, A_REVERSE, COLOR_PAIR(0));
|
||||
}
|
||||
|
||||
+7
-9
@@ -25,13 +25,11 @@ namespace scgi_thread {
|
||||
torrent::system::Thread* thread();
|
||||
std::thread::id thread_id();
|
||||
|
||||
void callback(void* target, std::function<void ()>&& fn);
|
||||
void cancel_callback(void* target);
|
||||
void cancel_callback_and_wait(void* target);
|
||||
void callback_interrupt(torrent::system::callback_id& id, std::function<void ()>&& fn);
|
||||
|
||||
rpc::SCgi* scgi();
|
||||
void set_scgi(rpc::SCgi* scgi);
|
||||
void set_rpc_log(const std::string& filename);
|
||||
rpc::SCgi* scgi();
|
||||
void set_scgi(rpc::SCgi* scgi);
|
||||
void set_rpc_log(const std::string& filename);
|
||||
|
||||
} // namespace torrent::scgi_thread
|
||||
|
||||
@@ -41,9 +39,9 @@ namespace session_thread {
|
||||
torrent::system::Thread* thread();
|
||||
std::thread::id thread_id();
|
||||
|
||||
void callback(void* target, std::function<void ()>&& fn);
|
||||
void cancel_callback(void* target);
|
||||
void cancel_callback_and_wait(void* target);
|
||||
void callback(std::function<void ()>&& fn);
|
||||
void callback(torrent::system::callback_id& id, std::function<void ()>&& fn);
|
||||
void cancel_callback(torrent::system::callback_id& id);
|
||||
|
||||
session::SessionManager* manager();
|
||||
std::string session_path();
|
||||
|
||||
@@ -2,20 +2,26 @@
|
||||
|
||||
#include "input_event.h"
|
||||
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/system/poll.h>
|
||||
|
||||
#include "display/attributes.h"
|
||||
|
||||
namespace input {
|
||||
|
||||
void
|
||||
InputEvent::insert(torrent::net::Poll* p) {
|
||||
p->open(this);
|
||||
p->insert_read(this);
|
||||
InputEvent::insert() {
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
}
|
||||
|
||||
void
|
||||
InputEvent::remove(torrent::net::Poll* p) {
|
||||
p->remove_read(this);
|
||||
p->close(this);
|
||||
InputEvent::remove() {
|
||||
if (!is_open())
|
||||
return;
|
||||
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
set_file_descriptor(-1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -32,6 +38,8 @@ InputEvent::event_write() {
|
||||
|
||||
void
|
||||
InputEvent::event_error() {
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
set_file_descriptor(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,22 +2,20 @@
|
||||
#define RTORRENT_INPUT_INPUT_EVENT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <torrent/event.h>
|
||||
#include <torrent/net/poll.h>
|
||||
#include <torrent/system/event.h>
|
||||
|
||||
namespace input {
|
||||
|
||||
class InputEvent : public torrent::Event {
|
||||
class InputEvent : public torrent::system::Event {
|
||||
public:
|
||||
typedef std::function<void (int)> slot_int;
|
||||
|
||||
InputEvent(int fd) { m_fileDesc = fd; }
|
||||
InputEvent(int fd) { set_file_descriptor(fd); }
|
||||
|
||||
const char* type_name() const override { return "input"; }
|
||||
|
||||
void insert(torrent::net::Poll* p);
|
||||
void remove(torrent::net::Poll* p);
|
||||
void insert();
|
||||
void remove();
|
||||
|
||||
void event_read() override;
|
||||
void event_write() override;
|
||||
|
||||
+143
-100
@@ -11,6 +11,9 @@
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
#include <torrent/net/fd.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/runtime/memory_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/utils/chrono.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
@@ -112,7 +115,16 @@ main(int argc, char** argv) {
|
||||
// TODO: Create a fake thread object for initializing other processes and enabling logging.
|
||||
torrent::initialize_main_thread();
|
||||
|
||||
SignalHandler::set_ignore(SIGPIPE);
|
||||
// Block SIGCHLD until all threads are created, then unblock on main-thread, to avoid SIGCHLD
|
||||
// interrupting other threads.
|
||||
//
|
||||
// This means only main-thread can fork and wait for child processes.
|
||||
|
||||
SignalHandler::set_block(SIGALRM);
|
||||
SignalHandler::set_block(SIGPIPE);
|
||||
SignalHandler::set_block(SIGCHLD);
|
||||
|
||||
// All signal handlers must restore errno if they return.
|
||||
SignalHandler::set_handler(SIGSEGV, std::bind(&do_panic, SIGSEGV));
|
||||
SignalHandler::set_handler(SIGILL, std::bind(&do_panic, SIGILL));
|
||||
SignalHandler::set_handler(SIGFPE, std::bind(&do_panic, SIGFPE));
|
||||
@@ -140,18 +152,8 @@ main(int argc, char** argv) {
|
||||
|
||||
SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus);
|
||||
|
||||
// SIGUSR1 is used for interrupting polling, forcing the target
|
||||
// thread to process new non-socket events.
|
||||
//
|
||||
// LibTorrent uses sockets for this purpose on Solaris and other
|
||||
// platforms that do not properly pass signals to the target
|
||||
// threads. Use '--enable-interrupt-socket' when configuring
|
||||
// LibTorrent to enable this workaround.
|
||||
if (torrent::system::Thread::should_handle_sigusr1())
|
||||
SignalHandler::set_handler(SIGUSR1, []() {});
|
||||
|
||||
torrent::log_add_group_output(torrent::LOG_NOTICE, "important");
|
||||
torrent::log_add_group_output(torrent::LOG_DHT_ERROR, "important");
|
||||
torrent::log_add_group_output(torrent::LOG_NOTICE, "important");
|
||||
torrent::log_add_group_output(torrent::LOG_DHT_ERROR, "important");
|
||||
|
||||
torrent::log_add_group_output(torrent::LOG_INFO, "complete");
|
||||
torrent::log_add_group_output(torrent::LOG_DHT_ERROR, "complete");
|
||||
@@ -160,11 +162,13 @@ main(int argc, char** argv) {
|
||||
initialize_rpc_slots();
|
||||
|
||||
torrent::initialize();
|
||||
torrent::set_main_thread_slots(std::bind(&client_perform));
|
||||
torrent::main_thread::set_client_callback(&client_perform);
|
||||
|
||||
scgi::ThreadScgi::create_thread();
|
||||
session::ThreadSession::create_thread();
|
||||
|
||||
SignalHandler::set_unblock(SIGCHLD);
|
||||
|
||||
// Initialize option handlers after libtorrent to ensure
|
||||
// torrent::ConnectionManager* are valid etc.
|
||||
initialize_commands();
|
||||
@@ -209,7 +213,14 @@ main(int argc, char** argv) {
|
||||
"method.insert = event.download.hash_queued,multi|rlookup|static\n"
|
||||
|
||||
"method.set_key = event.download.inserted, 1_send_scrape, ((d.tracker.send_scrape,30))\n"
|
||||
"method.set_key = event.download.inserted_new, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) ),(d.save_full_session)}\n"
|
||||
"method.set_key = event.download.inserted_new, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) )}\n"
|
||||
// d.save_full_session runs LAST (~ prefix is ASCII 0x7E, sorts after all alphanumerics,
|
||||
// matching the existing ~_delete_tied precedent on event.download.erased) so the on-disk
|
||||
// snapshot includes custom fields written by other inserted_new handlers (addtime,
|
||||
// seedingtime, etc.). Was previously inside 1_prepare alongside view setup, which
|
||||
// snapshotted bencode before later handlers ran, so d.set_custom=addtime did not reach
|
||||
// .rtorrent until the next periodic resume save — a window where rtorrent restart lost them.
|
||||
"method.set_key = event.download.inserted_new, ~_save_full, ((d.save_full_session))\n"
|
||||
"method.set_key = event.download.inserted_session, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) )}\n"
|
||||
|
||||
"method.set_key = event.download.inserted, 1_prioritize_toc, \"branch=file.prioritize_toc=,{\\\"f.multicall=(file.prioritize_toc.first),f.prioritize_first.enable=\\\",\\\"f.multicall=(file.prioritize_toc.last),f.prioritize_last.enable=\\\",d.update_priorities=}\"\n"
|
||||
@@ -283,14 +294,12 @@ main(int argc, char** argv) {
|
||||
"view.filter = leeching,((and,((d.state)),((not,((d.complete))))))\n"
|
||||
"view.filter_on = leeching,event.download.resumed,event.download.paused,event.download.finished\n"
|
||||
|
||||
"schedule2 = view.main,10,10,((view.sort,main,20))\n"
|
||||
"schedule2 = view.name,10,10,((view.sort,name,20))\n"
|
||||
"schedule = view.main,10,10,((view.sort,main,20))\n"
|
||||
"schedule = view.name,10,10,((view.sort,name,20))\n"
|
||||
|
||||
"schedule2 = session_save,1200,1200,((session.save))\n"
|
||||
"schedule2 = low_diskspace,5,60,((close_low_diskspace,500M))\n"
|
||||
"schedule2 = prune_file_status,3600,86400,((system.file_status_cache.prune))\n"
|
||||
|
||||
"protocol.encryption.set=allow_incoming,prefer_plaintext,enable_retry\n"
|
||||
"schedule = session_save,1200,1200,((session.save))\n"
|
||||
"schedule = low_diskspace,5,60,((close_low_diskspace,500M))\n"
|
||||
"schedule = prune_file_status,3600,86400,((system.file_status_cache.prune))\n"
|
||||
|
||||
"ui.color.focus.set=reverse\n"
|
||||
);
|
||||
@@ -298,101 +307,131 @@ main(int argc, char** argv) {
|
||||
// Functions that might not get depracted as they are nice for
|
||||
// configuration files, and thus might do with just some
|
||||
// cleanup.
|
||||
CMD2_REDIRECT("upload_rate", "throttle.global_up.max_rate.set_kb");
|
||||
CMD2_REDIRECT("download_rate", "throttle.global_down.max_rate.set_kb");
|
||||
CMD_REDIRECT("upload_rate", "throttle.global_up.max_rate.set_kb");
|
||||
CMD_REDIRECT("download_rate", "throttle.global_down.max_rate.set_kb");
|
||||
|
||||
CMD2_REDIRECT("ratio.enable", "group.seeding.ratio.enable");
|
||||
CMD2_REDIRECT("ratio.disable", "group.seeding.ratio.disable");
|
||||
CMD2_REDIRECT("ratio.min", "group.seeding.ratio.min");
|
||||
CMD2_REDIRECT("ratio.max", "group.seeding.ratio.max");
|
||||
CMD2_REDIRECT("ratio.upload", "group.seeding.ratio.upload");
|
||||
CMD2_REDIRECT("ratio.min.set", "group.seeding.ratio.min.set");
|
||||
CMD2_REDIRECT("ratio.max.set", "group.seeding.ratio.max.set");
|
||||
CMD2_REDIRECT("ratio.upload.set", "group.seeding.ratio.upload.set");
|
||||
CMD_REDIRECT("ratio.enable", "group.seeding.ratio.enable");
|
||||
CMD_REDIRECT("ratio.disable", "group.seeding.ratio.disable");
|
||||
CMD_REDIRECT("ratio.min", "group.seeding.ratio.min");
|
||||
CMD_REDIRECT("ratio.max", "group.seeding.ratio.max");
|
||||
CMD_REDIRECT("ratio.upload", "group.seeding.ratio.upload");
|
||||
CMD_REDIRECT("ratio.min.set", "group.seeding.ratio.min.set");
|
||||
CMD_REDIRECT("ratio.max.set", "group.seeding.ratio.max.set");
|
||||
CMD_REDIRECT("ratio.upload.set", "group.seeding.ratio.upload.set");
|
||||
|
||||
CMD2_REDIRECT("encryption", "protocol.encryption.set");
|
||||
CMD2_REDIRECT("encoding_list", "encoding.add");
|
||||
CMD_REDIRECT("encryption", "protocol.encryption.set");
|
||||
|
||||
CMD2_REDIRECT("connection_leech", "protocol.connection.leech.set");
|
||||
CMD2_REDIRECT("connection_seed", "protocol.connection.seed.set");
|
||||
CMD_REDIRECT("check_hash", "pieces.hash.on_completion.set");
|
||||
|
||||
CMD2_REDIRECT("min_peers", "throttle.min_peers.normal.set");
|
||||
CMD2_REDIRECT("max_peers", "throttle.max_peers.normal.set");
|
||||
CMD2_REDIRECT("min_peers_seed", "throttle.min_peers.seed.set");
|
||||
CMD2_REDIRECT("max_peers_seed", "throttle.max_peers.seed.set");
|
||||
CMD_REDIRECT("connection_leech", "protocol.connection.leech.set");
|
||||
CMD_REDIRECT("connection_seed", "protocol.connection.seed.set");
|
||||
|
||||
CMD2_REDIRECT("min_uploads", "throttle.min_uploads.set");
|
||||
CMD2_REDIRECT("max_uploads", "throttle.max_uploads.set");
|
||||
CMD2_REDIRECT("min_downloads", "throttle.min_downloads.set");
|
||||
CMD2_REDIRECT("max_downloads", "throttle.max_downloads.set");
|
||||
CMD_REDIRECT("min_peers", "throttle.min_peers.normal.set");
|
||||
CMD_REDIRECT("max_peers", "throttle.max_peers.normal.set");
|
||||
CMD_REDIRECT("min_peers_seed", "throttle.min_peers.seed.set");
|
||||
CMD_REDIRECT("max_peers_seed", "throttle.max_peers.seed.set");
|
||||
|
||||
CMD2_REDIRECT("max_uploads_div", "throttle.max_uploads.div.set");
|
||||
CMD2_REDIRECT("max_uploads_global", "throttle.max_uploads.global.set");
|
||||
CMD2_REDIRECT("max_downloads_div", "throttle.max_downloads.div.set");
|
||||
CMD2_REDIRECT("max_downloads_global", "throttle.max_downloads.global.set");
|
||||
CMD_REDIRECT("min_uploads", "throttle.min_uploads.set");
|
||||
CMD_REDIRECT("max_uploads", "throttle.max_uploads.set");
|
||||
CMD_REDIRECT("min_downloads", "throttle.min_downloads.set");
|
||||
CMD_REDIRECT("max_downloads", "throttle.max_downloads.set");
|
||||
|
||||
CMD2_REDIRECT("max_memory_usage", "pieces.memory.max.set");
|
||||
CMD_REDIRECT("max_uploads_div", "throttle.max_uploads.div.set");
|
||||
CMD_REDIRECT("max_uploads_global", "throttle.max_uploads.global.set");
|
||||
CMD_REDIRECT("max_downloads_div", "throttle.max_downloads.div.set");
|
||||
CMD_REDIRECT("max_downloads_global", "throttle.max_downloads.global.set");
|
||||
|
||||
CMD2_REDIRECT("bind", "network.bind_address.set");
|
||||
CMD2_REDIRECT("ip", "network.local_address.set");
|
||||
CMD2_REDIRECT("port_range", "network.port_range.set");
|
||||
CMD_REDIRECT("directory", "directory.default.set");
|
||||
CMD_REDIRECT("session", "session.path.set");
|
||||
|
||||
CMD2_REDIRECT("dht", "dht.mode.set");
|
||||
CMD_REDIRECT_NO_EXPORT("port_range", "network.listen.port.range.set");
|
||||
CMD_REDIRECT_NO_EXPORT("scgi_port", "network.scgi.open_port");
|
||||
CMD_REDIRECT_NO_EXPORT("scgi_local", "network.scgi.open_local");
|
||||
|
||||
CMD2_REDIRECT("port_random", "network.port_random.set");
|
||||
CMD2_REDIRECT("proxy_address", "network.proxy_address.set");
|
||||
CMD_REDIRECT("to_gm_time", "convert.gm_time");
|
||||
CMD_REDIRECT("to_gm_date", "convert.gm_date");
|
||||
CMD_REDIRECT("to_time", "convert.time");
|
||||
CMD_REDIRECT("to_date", "convert.date");
|
||||
CMD_REDIRECT("to_elapsed_time", "convert.elapsed_time");
|
||||
CMD_REDIRECT("to_kb", "convert.kb");
|
||||
CMD_REDIRECT("to_mb", "convert.mb");
|
||||
CMD_REDIRECT("to_xb", "convert.xb");
|
||||
CMD_REDIRECT("to_throttle", "convert.throttle");
|
||||
|
||||
CMD2_REDIRECT("scgi_port", "network.scgi.open_port");
|
||||
CMD2_REDIRECT("scgi_local", "network.scgi.open_local");
|
||||
// TODO: Deprecate these at some point a while after 1.1 release.
|
||||
|
||||
CMD2_REDIRECT("directory", "directory.default.set");
|
||||
CMD2_REDIRECT("session", "session.path.set");
|
||||
CMD_REDIRECT("d.multicall2", "d.multicall");
|
||||
CMD_REDIRECT("network.open_sockets", "system.sockets.size");
|
||||
CMD_REDIRECT("network.max_open_sockets", "system.sockets.max_size");
|
||||
CMD_REDIRECT("network.max_open_sockets.set", "system.sockets.max_size.set");
|
||||
CMD_REDIRECT("network.http.proxy_address", "network.proxy.http");
|
||||
CMD_REDIRECT("network.http.proxy_address.set", "network.proxy.http.set");
|
||||
|
||||
CMD2_REDIRECT("check_hash", "pieces.hash.on_completion.set");
|
||||
rpc::rpc.mark_safe("d.multicall2");
|
||||
rpc::rpc.mark_safe("network.max_open_sockets");
|
||||
rpc::rpc.mark_safe("network.http.proxy_address");
|
||||
|
||||
CMD2_REDIRECT("key_layout", "keys.layout.set");
|
||||
CMD2_ANY_VALUE_V("network.http.max_total_connections.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "network.http.max_total_connections.set is deprecated, use system.sockets.http.min_alloc.set instead.");
|
||||
});
|
||||
|
||||
CMD2_REDIRECT("to_gm_time", "convert.gm_time");
|
||||
CMD2_REDIRECT("to_gm_date", "convert.gm_date");
|
||||
CMD2_REDIRECT("to_time", "convert.time");
|
||||
CMD2_REDIRECT("to_date", "convert.date");
|
||||
CMD2_REDIRECT("to_elapsed_time", "convert.elapsed_time");
|
||||
CMD2_REDIRECT("to_kb", "convert.kb");
|
||||
CMD2_REDIRECT("to_mb", "convert.mb");
|
||||
CMD2_REDIRECT("to_xb", "convert.xb");
|
||||
CMD2_REDIRECT("to_throttle", "convert.throttle");
|
||||
|
||||
CMD2_REDIRECT("torrent_list_layout", "ui.torrent_list.layout.set");
|
||||
|
||||
// Deprecate:
|
||||
|
||||
CMD2_VAR_STRING("dht.throttle.name", "deprecated");
|
||||
rpc::rpc.mark_safe("dht.throttle.name");
|
||||
|
||||
CMD2_REDIRECT("network.http.max_open", "network.http.max_total_connections");
|
||||
CMD2_REDIRECT("network.http.max_open.set", "network.http.max_total_connections.set");
|
||||
|
||||
// Deprecated commands. Don't use these anymore.
|
||||
//
|
||||
// It has been so long that we now re-create these commands with the new (old by now) command
|
||||
// call style, where the first argument is the target.
|
||||
CMD2_ANY_VALUE_V("network.max_open_files.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "network.max_open_files.set is deprecated, use system.sockets.files.min_alloc.set instead.");
|
||||
});
|
||||
|
||||
// if (rpc::call_command_value("method.use_intermediate") == 1) {
|
||||
// CMD2_REDIRECT("execute", "execute2");
|
||||
|
||||
// CMD2_REDIRECT("schedule", "schedule2");
|
||||
// CMD2_REDIRECT("schedule_remove", "schedule_remove2");
|
||||
|
||||
// } else if (rpc::call_command_value("method.use_intermediate") == 2) {
|
||||
// Allow for use in config files, etc, just don't export it.
|
||||
// CMD2_REDIRECT_NO_EXPORT("execute", "execute2");
|
||||
|
||||
// CMD2_REDIRECT_NO_EXPORT("schedule", "schedule2");
|
||||
// CMD2_REDIRECT_NO_EXPORT("schedule_remove", "schedule_remove2");
|
||||
// }
|
||||
|
||||
// if (rpc::call_command_value("method.use_deprecated") == 1) {
|
||||
// }
|
||||
if (rpc::call_command_value("method.use_deprecated") == 1) {
|
||||
CMD_REDIRECT("execute2", "execute");
|
||||
CMD_REDIRECT("schedule2", "schedule");
|
||||
CMD_REDIRECT("schedule_remove2", "schedule.remove");
|
||||
|
||||
CMD_REDIRECT("bind", "network.bind_address.set");
|
||||
CMD_REDIRECT("ip", "network.local_address.set");
|
||||
CMD_REDIRECT("port_range", "network.port_range.set");
|
||||
|
||||
// TODO: Check if dht is on by default.
|
||||
CMD_REDIRECT("dht", "dht.mode.set");
|
||||
|
||||
CMD_REDIRECT("port_random", "network.port_random.set");
|
||||
CMD_REDIRECT("proxy_address", "network.proxy_address.set");
|
||||
|
||||
CMD_REDIRECT("key_layout", "keys.layout.set");
|
||||
|
||||
CMD_REDIRECT("torrent_list_layout", "ui.torrent_list.layout.set");
|
||||
|
||||
CMD2_VAR_STRING("dht.throttle.name", "deprecated");
|
||||
rpc::rpc.mark_safe("dht.throttle.name");
|
||||
|
||||
CMD_REDIRECT("network.http.max_open", "network.http.max_total_connections");
|
||||
CMD_REDIRECT("network.http.max_open.set", "network.http.max_total_connections.set");
|
||||
|
||||
// Users should check their setups to see if they need to modify their use of these options.
|
||||
CMD_REDIRECT("max_memory_usage", "pieces.memory.max.set");
|
||||
|
||||
CMD_ANY_LIST("throttle.ip", []( auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "The 'throttle.ip' command is deprecated and does nothing.");
|
||||
return torrent::Object();
|
||||
});
|
||||
|
||||
CMD_ANY("network.port_open", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "The 'network.port_open' command is deprecated and does nothing.");
|
||||
return torrent::Object();
|
||||
});
|
||||
CMD_ANY("network.port_open.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "The 'network.port_open.set' command is deprecated and does nothing.");
|
||||
return torrent::Object();
|
||||
});
|
||||
|
||||
CMD_REDIRECT("network.port_random", "network.listen.port.random");
|
||||
CMD_REDIRECT("network.port_random.set", "network.listen.port.random.set");
|
||||
CMD_REDIRECT("network.port_range", "network.listen.port.range");
|
||||
CMD_REDIRECT("network.port_range.set", "network.listen.port.range.set");
|
||||
}
|
||||
|
||||
{
|
||||
auto fd = torrent::fd_open_family(torrent::fd_flag_stream, AF_INET6);
|
||||
@@ -419,20 +458,24 @@ main(int argc, char** argv) {
|
||||
});
|
||||
|
||||
LT_LOG("seeded srandom and srand48 (seed:%u)", random_seed);
|
||||
LT_LOG("max memory usage: %" PRIu64, torrent::runtime::memory_manager()->max_memory_usage());
|
||||
|
||||
control->initialize();
|
||||
control->ui()->load_input_history();
|
||||
|
||||
// Load session torrents and perform scheduled tasks to ensure
|
||||
// session torrents are loaded before arg torrents.
|
||||
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
|
||||
torrent::runtime::initialize_network();
|
||||
|
||||
// Load session torrents and perform scheduled tasks to ensure session torrents are loaded
|
||||
// before arg torrents.
|
||||
control->dht_manager()->set_auto_if_untouched_and_has_session();
|
||||
control->dht_manager()->load_dht_cache();
|
||||
|
||||
load_session_torrents(session_thread::manager()->path());
|
||||
load_arg_torrents(argv + firstArg, argv + argc);
|
||||
|
||||
// Make sure we update the display before any scheduled tasks can
|
||||
// run, so that loading of torrents doesn't look like it hangs on
|
||||
// startup.
|
||||
// Make sure we update the display before any scheduled tasks can run, so that loading of
|
||||
// torrents doesn't look like it hangs on startup.
|
||||
control->display()->adjust_layout();
|
||||
control->display()->receive_update();
|
||||
|
||||
|
||||
+31
-31
@@ -6,31 +6,31 @@
|
||||
#include "command.h"
|
||||
|
||||
#define COMMAND_BASE_TEMPLATE_DEFINE(func_name) \
|
||||
template const torrent::Object func_name<target_type>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<core::Download*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::Peer*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::tracker::Tracker*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::File*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::FileListIterator*>(command_base* rawCommand, target_type target, const torrent::Object& args);
|
||||
template const torrent::Object func_name<target_type>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<core::Download*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::Peer*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::tracker::Tracker*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::File*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::FileListIterator*>(command_base* command_raw, target_type target, const torrent::Object& args);
|
||||
|
||||
namespace rpc {
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call(command_base* rawCommand, target_type target, const torrent::Object& args) {
|
||||
command_base_call(command_base* command_raw, target_type target, const torrent::Object& args) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to generic command.");
|
||||
|
||||
return command_base::_call<typename command_function<T>::type, T>(rawCommand, target, args);
|
||||
return command_base::_call<typename command_function<T>::type, T>(command_raw, target, args);
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call);
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_value_base(command_base* rawCommand, target_type target, const torrent::Object& rawArgs, int base, int unit) {
|
||||
command_base_call_value_base(command_base* command_raw, target_type target, const torrent::Object& args_raw, int base, int unit) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to value command.");
|
||||
|
||||
const torrent::Object& arg = convert_to_single_argument(rawArgs);
|
||||
auto& arg = convert_to_single_argument(args_raw);
|
||||
|
||||
if (arg.type() == torrent::Object::TYPE_STRING) {
|
||||
torrent::Object::value_type val;
|
||||
@@ -38,55 +38,55 @@ command_base_call_value_base(command_base* rawCommand, target_type target, const
|
||||
if (!parse_whole_value_nothrow(arg.as_string().c_str(), &val, base, unit))
|
||||
throw torrent::input_error("Not a value.");
|
||||
|
||||
return command_base::_call<typename command_value_function<T>::type, T>(rawCommand, target, val);
|
||||
return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, val);
|
||||
}
|
||||
|
||||
return command_base::_call<typename command_value_function<T>::type, T>(rawCommand, target, unit * arg.as_value());
|
||||
return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, unit * arg.as_value());
|
||||
}
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_value(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
return command_base_call_value_base<T>(rawCommand, target, rawArgs, 0, 1);
|
||||
command_base_call_value(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
return command_base_call_value_base<T>(command_raw, target, args_raw, 0, 1);
|
||||
}
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_value_kb(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
return command_base_call_value_base<T>(rawCommand, target, rawArgs, 0, 1024);
|
||||
command_base_call_value_kb(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
return command_base_call_value_base<T>(command_raw, target, args_raw, 0, 1024);
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value);
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value_kb);
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_string(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
command_base_call_string(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to string command.");
|
||||
|
||||
const torrent::Object& arg = convert_to_single_argument(rawArgs);
|
||||
auto& arg = convert_to_single_argument(args_raw);
|
||||
|
||||
if (arg.type() == torrent::Object::TYPE_RAW_STRING)
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(rawCommand, target, arg.as_raw_string().as_string());
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(command_raw, target, arg.as_raw_string().as_string());
|
||||
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(rawCommand, target, arg.as_string());
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(command_raw, target, arg.as_string());
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_string);
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_list(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
command_base_call_list(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to list command.");
|
||||
|
||||
if (rawArgs.type() != torrent::Object::TYPE_LIST) {
|
||||
if (args_raw.type() != torrent::Object::TYPE_LIST) {
|
||||
torrent::Object::list_type arg;
|
||||
|
||||
if (!rawArgs.is_empty())
|
||||
arg.push_back(rawArgs);
|
||||
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(rawCommand, target, arg);
|
||||
if (!args_raw.is_empty())
|
||||
arg.push_back(args_raw);
|
||||
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(command_raw, target, arg);
|
||||
}
|
||||
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(rawCommand, target, rawArgs.as_list());
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(command_raw, target, args_raw.as_list());
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_list);
|
||||
|
||||
+80
-51
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/data/file_list_iterator.h>
|
||||
@@ -28,7 +29,6 @@ struct target_wrapper<void> {
|
||||
typedef no_type* cleaned_type;
|
||||
};
|
||||
|
||||
// Since c++0x isn't out yet...
|
||||
template <typename T1, typename T2, typename T3>
|
||||
struct rt_triple : private std::pair<T1, T2> {
|
||||
typedef std::pair<T1, T2> base_type;
|
||||
@@ -55,15 +55,11 @@ struct rt_triple : private std::pair<T1, T2> {
|
||||
base_type(src.first, src.second), third(src.third) {}
|
||||
};
|
||||
|
||||
// Since it gets used so many places we might as well put it in the
|
||||
// rpc namespace.
|
||||
//typedef std::pair<int, void*> target_type;
|
||||
typedef rt_triple<int, void*, void*> target_type;
|
||||
|
||||
class command_base;
|
||||
|
||||
typedef const torrent::Object (*command_base_call_type)(command_base*, target_type, const torrent::Object&);
|
||||
typedef std::function<torrent::Object (target_type, const torrent::Object&)> base_function;
|
||||
using target_type = rt_triple<int, void*, void*>;
|
||||
using base_function = std::function<torrent::Object (target_type, const torrent::Object&)>;
|
||||
using command_base_call_type = const torrent::Object (command_base*, target_type, const torrent::Object&);
|
||||
|
||||
template <typename tmpl> struct command_base_is_valid {};
|
||||
template <command_base_call_type tmpl_func> struct command_base_is_type {};
|
||||
@@ -87,17 +83,18 @@ public:
|
||||
|
||||
typedef const torrent::Object (*download_pair_slot) (command_base*, core::Download*, core::Download*, const torrent::Object&);
|
||||
|
||||
static const int target_generic = 0;
|
||||
static const int target_any = 1;
|
||||
static const int target_download = 2;
|
||||
static const int target_peer = 3;
|
||||
static const int target_tracker = 4;
|
||||
static const int target_file = 5;
|
||||
static const int target_file_itr = 6;
|
||||
static constexpr int target_generic = 0;
|
||||
static constexpr int target_any = 1;
|
||||
static constexpr int target_download = 2;
|
||||
static constexpr int target_peer = 3;
|
||||
static constexpr int target_tracker = 4;
|
||||
static constexpr int target_file = 5;
|
||||
static constexpr int target_file_itr = 6;
|
||||
static constexpr int target_download_pair = 7;
|
||||
|
||||
static const int target_download_pair = 7;
|
||||
static constexpr unsigned int max_arguments = 10;
|
||||
|
||||
static const unsigned int max_arguments = 10;
|
||||
static constexpr std::size_t optimal_alignment = std::max(alignof(std::max_align_t), alignof(base_function));
|
||||
|
||||
struct stack_type {
|
||||
torrent::Object* begin() { return reinterpret_cast<torrent::Object*>(buffer); }
|
||||
@@ -114,10 +111,48 @@ public:
|
||||
char buffer[sizeof(torrent::Object) * max_arguments];
|
||||
};
|
||||
|
||||
command_base() { new (&_pod<base_function>()) base_function(); }
|
||||
command_base(const command_base& src) { new (&_pod<base_function>()) base_function(src._pod<base_function>()); }
|
||||
command_base() : m_copy_helper(nullptr), m_dest_helper(nullptr) {}
|
||||
|
||||
~command_base() { _pod<base_function>().~base_function(); }
|
||||
command_base(const command_base& src) {
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
|
||||
command_base& operator=(const command_base& src) {
|
||||
if (this != &src) {
|
||||
if (m_dest_helper) m_dest_helper(t_pod);
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
command_base(command_base&& src) noexcept {
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
|
||||
command_base& operator=(command_base&& src) noexcept {
|
||||
if (this != &src) {
|
||||
if (m_dest_helper) m_dest_helper(t_pod);
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~command_base() {
|
||||
if (m_dest_helper)
|
||||
m_dest_helper(t_pod);
|
||||
}
|
||||
|
||||
static torrent::Object* argument(unsigned int index) { return current_stack.begin() + index; }
|
||||
static torrent::Object& argument_ref(unsigned int index) { return *(current_stack.begin() + index); }
|
||||
@@ -132,55 +167,51 @@ public:
|
||||
static void pop_stack(stack_type* stack, torrent::Object* last_stack);
|
||||
|
||||
template <typename T>
|
||||
void set_function(T s, [[maybe_unused]] int value = command_base_is_valid<T>::value) { _pod<T>() = s; }
|
||||
void set_function(T s, [[maybe_unused]] int value = command_base_is_valid<T>::value) {
|
||||
static_assert(sizeof(T) <= sizeof(t_pod), "t_pod storage overflow");
|
||||
static_assert(optimal_alignment >= alignof(T), "t_pod alignment insufficient for type");
|
||||
|
||||
if (m_dest_helper)
|
||||
m_dest_helper(t_pod);
|
||||
|
||||
::new (t_pod) T(std::move(s));
|
||||
|
||||
m_copy_helper = [](void* dest, const void* src) {
|
||||
::new (dest) T(*static_cast<const T*>(src));
|
||||
};
|
||||
m_dest_helper = [](void* ptr) {
|
||||
static_cast<T*>(ptr)->~T();
|
||||
};
|
||||
}
|
||||
|
||||
template <command_base_call_type T>
|
||||
void set_function_2(typename command_base_is_type<T>::type s, [[maybe_unused]] int value = command_base_is_valid<typename command_base_is_type<T>::type>::value) {
|
||||
_pod<typename command_base_is_type<T>::type>() = s;
|
||||
set_function<typename command_base_is_type<T>::type>(std::move(s));
|
||||
}
|
||||
|
||||
// The std::function object in GCC is castable between types with a
|
||||
// pointer to a struct of ctor/dtor/calls for non-POD slots. As such
|
||||
// it should be safe to cast between different std::function
|
||||
// template types, yet what the C++0x standard will say about this I
|
||||
// have no idea atm.
|
||||
template <typename tmpl> tmpl& _pod() { return reinterpret_cast<tmpl&>(t_pod); }
|
||||
template <typename tmpl> const tmpl& _pod() const { return reinterpret_cast<const tmpl&>(t_pod); }
|
||||
|
||||
template <typename Func, typename T, typename Args>
|
||||
static const torrent::Object _call(command_base* cmd, target_type target, Args args);
|
||||
|
||||
command_base& operator = (const command_base& src) {
|
||||
_pod<base_function>() = src._pod<base_function>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
// For use by functions that need to use placeholders to arguments
|
||||
// within commands. E.d. callable command strings where one of the
|
||||
// arguments within the command needs to be supplied by the caller.
|
||||
using copy_fn_t = void (*)(void* dest, const void* src);
|
||||
using dest_fn_t = void (*)(void* ptr);
|
||||
|
||||
#ifdef HAVE_CXX11
|
||||
union {
|
||||
base_function t_pod;
|
||||
// char t_pod[sizeof(base_function)];
|
||||
};
|
||||
#else
|
||||
union {
|
||||
char t_pod[sizeof(base_function)];
|
||||
};
|
||||
#endif
|
||||
alignas(optimal_alignment) char t_pod[sizeof(base_function)];
|
||||
|
||||
copy_fn_t m_copy_helper;
|
||||
dest_fn_t m_dest_helper;
|
||||
};
|
||||
|
||||
template <typename T1 = void, typename T2 = void>
|
||||
struct target_type_id {
|
||||
// Nothing here, so we cause an error.
|
||||
};
|
||||
|
||||
template <typename T> inline bool
|
||||
is_target_compatible(const target_type& target) { return target.first == target_type_id<T>::value; }
|
||||
|
||||
// Splitting pairs into separate targets.
|
||||
inline bool is_target_pair(const target_type& target) { return target.first >= command_base::target_download_pair; }
|
||||
|
||||
template <typename T> inline T
|
||||
@@ -203,7 +234,7 @@ command_base::_call(command_base* cmd, target_type target, Args args) {
|
||||
|
||||
#define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \
|
||||
template <typename T, int proper = target_type_id<T>::proper_type> struct func_type { typedef std::function<func_parm> type; }; \
|
||||
\
|
||||
\
|
||||
template <> struct command_base_is_valid<func_type<target_type>::type> { static const int value = 1; }; \
|
||||
template <> struct command_base_is_valid<func_type<core::Download*>::type> { static const int value = 1; }; \
|
||||
template <> struct command_base_is_valid<func_type<torrent::Peer*>::type> { static const int value = 1; }; \
|
||||
@@ -211,8 +242,6 @@ command_base::_call(command_base* cmd, target_type target, Args args) {
|
||||
template <> struct command_base_is_valid<func_type<torrent::File*>::type> { static const int value = 1; }; \
|
||||
template <> struct command_base_is_valid<func_type<torrent::FileListIterator*>::type> { static const int value = 1; };
|
||||
|
||||
// template <typename Q> struct command_base_is_valid<typename func_type<Q>::type > { static const int value = 1; };
|
||||
|
||||
COMMAND_BASE_TEMPLATE_TYPE(command_function, torrent::Object (T, const torrent::Object&));
|
||||
COMMAND_BASE_TEMPLATE_TYPE(command_value_function, torrent::Object (T, const torrent::Object::value_type&));
|
||||
COMMAND_BASE_TEMPLATE_TYPE(command_string_function, torrent::Object (T, const std::string&));
|
||||
@@ -220,7 +249,7 @@ COMMAND_BASE_TEMPLATE_TYPE(command_list_function, torrent::Object (T, const to
|
||||
|
||||
#define COMMAND_BASE_TEMPLATE_CALL(func_name, func_type) \
|
||||
template <typename T> const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
\
|
||||
\
|
||||
template <> struct command_base_is_type<func_name<target_type> > { static const int value = 1; typedef func_type<target_type>::type type; }; \
|
||||
template <> struct command_base_is_type<func_name<core::Download*> > { static const int value = 1; typedef func_type<core::Download*>::type type; }; \
|
||||
template <> struct command_base_is_type<func_name<torrent::Peer*> > { static const int value = 1; typedef func_type<torrent::Peer*>::type type; }; \
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/scheduler.h>
|
||||
#include <torrent/system/scheduler.h>
|
||||
|
||||
namespace rpc {
|
||||
|
||||
@@ -43,7 +43,7 @@ private:
|
||||
uint32_t m_interval{};
|
||||
std::chrono::microseconds m_time_scheduled;
|
||||
|
||||
torrent::utils::SchedulerEntry m_task;
|
||||
torrent::system::SchedulerEntry m_task;
|
||||
|
||||
// Flags for various things.
|
||||
};
|
||||
|
||||
+53
-124
@@ -1,16 +1,22 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <torrent/system/thread.h>
|
||||
#include "rpc/exec_file.h"
|
||||
|
||||
#include "exec_file.h"
|
||||
#include "parse.h"
|
||||
// #include <cassert>
|
||||
// #include <cerrno>
|
||||
// #include <cstring>
|
||||
// #include <fcntl.h>
|
||||
// #include <spawn.h>
|
||||
// #include <string>
|
||||
#include <unistd.h>
|
||||
// #include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
// #include <torrent/net/fd.h>
|
||||
#include <torrent/system/thread.h>
|
||||
#include <torrent/system/spawn_process.h>
|
||||
#include <torrent/system/types.h>
|
||||
|
||||
#include "rpc/parse.h"
|
||||
|
||||
namespace rpc {
|
||||
|
||||
@@ -18,133 +24,56 @@ namespace rpc {
|
||||
|
||||
int
|
||||
ExecFile::execute(const char* file, char* const* argv, int flags) {
|
||||
// Write the executed command and its parameters to the log fd.
|
||||
[[maybe_unused]] int result;
|
||||
torrent::system::SpawnProcess spawn_process;
|
||||
|
||||
spawn_process.set_log_fd(m_log_fd);
|
||||
spawn_process.set_background(flags & flag_background);
|
||||
spawn_process.set_capture_output(flags & flag_capture);
|
||||
|
||||
if (m_log_fd != -1) {
|
||||
for (char* const* itr = argv; *itr != NULL; itr++) {
|
||||
if (itr == argv)
|
||||
result = write(m_log_fd, "\n---\n", sizeof("\n---\n"));
|
||||
else
|
||||
result = write(m_log_fd, " ", 1);
|
||||
std::vector<struct iovec> iovecs;
|
||||
iovecs.reserve(32);
|
||||
iovecs.push_back({const_cast<char*>("\n---\n"), 5});
|
||||
|
||||
result = write(m_log_fd, *itr, std::strlen(*itr));
|
||||
for (auto* itr = argv; *itr != nullptr; itr++) {
|
||||
if (itr != argv)
|
||||
iovecs.push_back({const_cast<char*>(" "), 1});
|
||||
|
||||
iovecs.push_back({*itr, std::strlen(*itr)});
|
||||
}
|
||||
|
||||
result = write(m_log_fd, "\n---\n", sizeof("\n---\n"));
|
||||
iovecs.push_back({const_cast<char*>("\n---\n"), 5});
|
||||
|
||||
[[maybe_unused]] int result = ::writev(m_log_fd, iovecs.data(), iovecs.size());
|
||||
}
|
||||
|
||||
int pipeFd[2];
|
||||
|
||||
if ((flags & flag_capture) && pipe(pipeFd))
|
||||
throw torrent::input_error("ExecFile::execute(...) Pipe creation failed.");
|
||||
|
||||
pid_t childPid = fork();
|
||||
|
||||
if (childPid == -1) {
|
||||
if (flags & flag_capture) {
|
||||
::close(pipeFd[0]);
|
||||
::close(pipeFd[1]);
|
||||
}
|
||||
throw torrent::input_error("ExecFile::execute(...) Fork failed.");
|
||||
}
|
||||
|
||||
if (childPid == 0) {
|
||||
if (flags & flag_background) {
|
||||
pid_t detached_pid = fork();
|
||||
|
||||
if (detached_pid == -1)
|
||||
_exit(-1);
|
||||
|
||||
if (detached_pid != 0) {
|
||||
if (m_log_fd != -1)
|
||||
result = write(m_log_fd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n"));
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
m_log_fd = -1;
|
||||
flags &= ~flag_capture;
|
||||
}
|
||||
|
||||
int devNull = open("/dev/null", O_RDWR);
|
||||
|
||||
if (devNull != -1)
|
||||
dup2(devNull, 0);
|
||||
else
|
||||
::close(0);
|
||||
|
||||
if (flags & flag_capture)
|
||||
dup2(pipeFd[1], 1);
|
||||
else if (m_log_fd != -1)
|
||||
dup2(m_log_fd, 1);
|
||||
else if (devNull != -1)
|
||||
dup2(devNull, 1);
|
||||
else
|
||||
::close(1);
|
||||
|
||||
if (m_log_fd != -1)
|
||||
dup2(m_log_fd, 2);
|
||||
else if (devNull != -1)
|
||||
dup2(devNull, 2);
|
||||
else
|
||||
::close(2);
|
||||
|
||||
// Close all fd's.
|
||||
for (int i = 3, last = sysconf(_SC_OPEN_MAX); i != last; i++)
|
||||
::close(i);
|
||||
|
||||
result = execvp(file, argv);
|
||||
|
||||
_exit(result);
|
||||
}
|
||||
|
||||
if (flags & flag_capture) {
|
||||
m_capture = std::string();
|
||||
::close(pipeFd[1]);
|
||||
|
||||
char buffer[4096];
|
||||
ssize_t length;
|
||||
|
||||
do {
|
||||
length = read(pipeFd[0], buffer, sizeof(buffer));
|
||||
|
||||
if (length > 0)
|
||||
m_capture += std::string(buffer, length);
|
||||
} while (length > 0);
|
||||
|
||||
::close(pipeFd[0]);
|
||||
int spawn_status = spawn_process.execute(file, argv);
|
||||
|
||||
if (spawn_status != 0) {
|
||||
if (m_log_fd != -1) {
|
||||
result = write(m_log_fd, "Captured output:\n", sizeof("Captured output:\n"));
|
||||
result = write(m_log_fd, m_capture.data(), m_capture.length());
|
||||
auto prefix = "\n--- posix_spawn failed: ";
|
||||
auto errno_str = torrent::system::errno_enum_str(spawn_status) + " ---\n";
|
||||
|
||||
struct iovec iovecs[2] = {
|
||||
{const_cast<char*>(prefix), std::strlen(prefix)},
|
||||
{const_cast<char*>(errno_str.c_str()), errno_str.size()},
|
||||
};
|
||||
|
||||
[[maybe_unused]] int result = ::writev(m_log_fd, iovecs, 2);
|
||||
}
|
||||
|
||||
throw torrent::input_error("ExecFile::execute() posix_spawn failed: " + torrent::system::errno_enum_str(spawn_status));
|
||||
}
|
||||
|
||||
int status;
|
||||
|
||||
while (waitpid(childPid, &status, 0) == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case ECHILD:
|
||||
throw torrent::internal_error("ExecFile::execute(...) waitpid failed with ECHILD, child process not found.");
|
||||
case EINVAL:
|
||||
throw torrent::internal_error("ExecFile::execute(...) waitpid failed with EINVAL.");
|
||||
default:
|
||||
throw torrent::internal_error("ExecFile::execute(...) waitpid failed with unexpected error: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
};
|
||||
|
||||
// Check return value?
|
||||
if (m_log_fd != -1) {
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
||||
result = write(m_log_fd, "\n--- Success ---\n", sizeof("\n--- Success ---\n"));
|
||||
else
|
||||
result = write(m_log_fd, "\n--- Error ---\n", sizeof("\n--- Error ---\n"));
|
||||
if (flags & flag_background) {
|
||||
m_waitpid_queue.close_pid(spawn_process.child_pid());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
if (flags & flag_capture)
|
||||
m_capture = spawn_process.capture_child_output();
|
||||
|
||||
return spawn_process.wait_for_child();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -204,4 +133,4 @@ ExecFile::execute_object(const torrent::Object& rawArgs, int flags) {
|
||||
return torrent::Object((int64_t)status);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace rpc
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <torrent/object.h>
|
||||
|
||||
#include "utils/waitpid_queue.h"
|
||||
|
||||
namespace rpc {
|
||||
|
||||
class ExecFile {
|
||||
@@ -24,6 +26,8 @@ public:
|
||||
private:
|
||||
int m_log_fd{-1};
|
||||
std::string m_capture;
|
||||
|
||||
utils::WaitpidQueue m_waitpid_queue;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+34
-5
@@ -6,6 +6,7 @@
|
||||
#include <string>
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
#include "rpc/rpc_manager.h"
|
||||
#include "rpc/command.h"
|
||||
@@ -33,24 +34,29 @@ json_to_object(const json& value) {
|
||||
case json::value_t::number_unsigned:
|
||||
case json::value_t::number_integer:
|
||||
return torrent::Object(value.get<int64_t>());
|
||||
|
||||
case json::value_t::boolean:
|
||||
return value.get<bool>() ? torrent::Object(int64_t(1)) : torrent::Object(int64_t(0));
|
||||
|
||||
case json::value_t::string:
|
||||
return torrent::Object(value.get<std::string>());
|
||||
|
||||
case json::value_t::array: {
|
||||
auto array_raw = torrent::Object::create_list();
|
||||
auto& array = array_raw.as_list();
|
||||
for (const auto& entry : value) {
|
||||
|
||||
for (const auto& entry : value)
|
||||
array.push_back(json_to_object(entry));
|
||||
}
|
||||
|
||||
return array_raw;
|
||||
}
|
||||
case json::value_t::object: {
|
||||
auto map_raw = torrent::Object::create_map();
|
||||
auto& map = map_raw.as_map();
|
||||
for (const auto& entry : value.items()) {
|
||||
|
||||
for (const auto& entry : value.items())
|
||||
map[entry.key()] = json_to_object(entry.value());
|
||||
}
|
||||
|
||||
return map_raw;
|
||||
}
|
||||
case json::value_t::number_float:
|
||||
@@ -61,17 +67,38 @@ json_to_object(const json& value) {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Only throw rpc_errors here.
|
||||
|
||||
json
|
||||
object_to_json(const torrent::Object& object) noexcept {
|
||||
object_to_json(const torrent::Object& object) {
|
||||
switch (object.type()) {
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
return object.as_value();
|
||||
|
||||
case torrent::Object::TYPE_STRING:
|
||||
if (object.flags() & torrent::Object::flag_as_binary) {
|
||||
|
||||
// We should optimize our imported json library to support copying base64 strings directly.
|
||||
if (object.flags() & torrent::Object::flag_base64) {
|
||||
auto binary_data = torrent::utils::transform_from_base64_unsafe(object.as_string());
|
||||
|
||||
if (!binary_data.has_value())
|
||||
throw rpc_error(JSONRPC_INTERNAL_ERROR, "invalid base64 string in base64-as-binary object");
|
||||
|
||||
return json::binary(*binary_data);
|
||||
}
|
||||
|
||||
return json::binary({object.as_string().begin(), object.as_string().end()});
|
||||
}
|
||||
|
||||
return object.as_string();
|
||||
|
||||
case torrent::Object::TYPE_LIST: {
|
||||
json result = json::array();
|
||||
|
||||
for (const auto& obj : object.as_list())
|
||||
result.push_back(object_to_json(obj));
|
||||
|
||||
return result;
|
||||
}
|
||||
case torrent::Object::TYPE_MAP: {
|
||||
@@ -135,7 +162,9 @@ jsonrpc_call_command(const std::string& method, const json& params) {
|
||||
|
||||
try {
|
||||
const auto& result = rpc::commands.call_command(itr, params_object, target);
|
||||
|
||||
return object_to_json(result);
|
||||
|
||||
} catch (untrusted_error& e) {
|
||||
throw rpc_error(JSONRPC_METHOD_NOT_FOUND_ERROR, e.what());
|
||||
}
|
||||
|
||||
+5
-1
@@ -10,6 +10,10 @@
|
||||
|
||||
#ifdef HAVE_LUA
|
||||
#include <lua.hpp>
|
||||
// LUA_OK was introduced in Lua 5.2; define for Lua 5.1 and LuaJIT2.0.
|
||||
#ifndef LUA_OK
|
||||
#define LUA_OK 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <torrent/object.h>
|
||||
@@ -211,7 +215,7 @@ object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* t
|
||||
auto tracker = new torrent::tracker::Tracker(rpc.slot_find_tracker()(download, std::stoi(std::string(index))));
|
||||
|
||||
*deleter = [tracker]() { delete tracker; };
|
||||
*target = rpc::make_target(command_base::target_tracker, target);
|
||||
*target = rpc::make_target(command_base::target_tracker, tracker);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+234
-135
@@ -1,9 +1,9 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/****************************************************************************\
|
||||
@@ -34,10 +34,10 @@
|
||||
// #include <nlohmann/adl_serializer.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -59,15 +59,15 @@
|
||||
|
||||
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0
|
||||
#warning "Already included a different version of the library!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum)
|
||||
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
@@ -160,10 +160,10 @@
|
||||
// #include <nlohmann/detail/conversions/from_json.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -186,10 +186,10 @@
|
||||
// #include <nlohmann/detail/exceptions.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -206,10 +206,10 @@
|
||||
// #include <nlohmann/detail/value_t.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -222,10 +222,10 @@
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -234,10 +234,10 @@
|
||||
// #include <nlohmann/detail/meta/detected.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -247,10 +247,10 @@
|
||||
// #include <nlohmann/detail/meta/void_t.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -334,10 +334,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson <evan@nemerson.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
@@ -2398,15 +2398,20 @@ JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
|
||||
// C++ language standard detection
|
||||
// if the user manually specified the used c++ version this is skipped
|
||||
#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
|
||||
#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
||||
#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
|
||||
#if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L)
|
||||
#define JSON_HAS_CPP_23
|
||||
#define JSON_HAS_CPP_20
|
||||
#define JSON_HAS_CPP_17
|
||||
#define JSON_HAS_CPP_14
|
||||
#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
|
||||
#elif (defined(__cplusplus) && __cplusplus > 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L)
|
||||
#define JSON_HAS_CPP_20
|
||||
#define JSON_HAS_CPP_17
|
||||
#define JSON_HAS_CPP_14
|
||||
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
|
||||
#elif (defined(__cplusplus) && __cplusplus > 201402L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
|
||||
#define JSON_HAS_CPP_17
|
||||
#define JSON_HAS_CPP_14
|
||||
#elif (defined(__cplusplus) && __cplusplus > 201103L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
|
||||
#define JSON_HAS_CPP_14
|
||||
#endif
|
||||
// the cpp 11 flag is always specified because it is the minimal required version
|
||||
@@ -2767,88 +2772,140 @@ JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
|
||||
@since version 3.9.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
|
||||
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
|
||||
@since version 3.11.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
|
||||
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE
|
||||
@since version 3.11.x
|
||||
@since version 3.11.3
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
|
||||
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
|
||||
@since version 3.9.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
|
||||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
|
||||
@since version 3.11.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
|
||||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
|
||||
@since version 3.11.x
|
||||
@since version 3.11.3
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
|
||||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE
|
||||
@since version 3.11.x
|
||||
@since version 3.12.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \
|
||||
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT
|
||||
@since version 3.12.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \
|
||||
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE
|
||||
@since version 3.12.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
|
||||
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE
|
||||
@since version 3.11.x
|
||||
@since version 3.12.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \
|
||||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT
|
||||
@since version 3.12.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \
|
||||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
|
||||
@since version 3.12.0
|
||||
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
|
||||
*/
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
|
||||
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||
|
||||
// inspired from https://stackoverflow.com/a/26745591
|
||||
// allows to call any std function as if (e.g. with begin):
|
||||
// allows calling any std function as if (e.g., with begin):
|
||||
// using std::begin; begin(x);
|
||||
//
|
||||
// it allows using the detected idiom to retrieve the return type
|
||||
@@ -3009,10 +3066,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/string_escape.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -3084,10 +3141,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/input/position_t.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -3126,10 +3183,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2018 The Abseil Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
@@ -3300,10 +3357,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/meta/type_traits.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -3317,10 +3374,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -3385,10 +3442,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/meta/call_std/begin.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -3405,10 +3462,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/meta/call_std/end.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -3429,10 +3486,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/json_fwd.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
@@ -4280,10 +4337,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/string_concat.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -4534,16 +4591,34 @@ class exception : public std::exception
|
||||
{
|
||||
return concat(a, '/', detail::escape(b));
|
||||
});
|
||||
return concat('(', str, ") ");
|
||||
|
||||
return concat('(', str, ") ", get_byte_positions(leaf_element));
|
||||
#else
|
||||
static_cast<void>(leaf_element);
|
||||
return "";
|
||||
return get_byte_positions(leaf_element);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
/// an exception object as storage for error messages
|
||||
std::runtime_error m;
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
template<typename BasicJsonType>
|
||||
static std::string get_byte_positions(const BasicJsonType* leaf_element)
|
||||
{
|
||||
if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos))
|
||||
{
|
||||
return concat("(bytes ", std::to_string(leaf_element->start_pos()), "-", std::to_string(leaf_element->end_pos()), ") ");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
template<typename BasicJsonType>
|
||||
static std::string get_byte_positions(const BasicJsonType* leaf_element)
|
||||
{
|
||||
static_cast<void>(leaf_element);
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @brief exception indicating a parse error
|
||||
@@ -4682,10 +4757,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/meta/identity_tag.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -4706,10 +4781,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/meta/std_fs.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -5158,6 +5233,12 @@ std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<
|
||||
return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, class A1, class A2 >
|
||||
std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
|
||||
{
|
||||
@@ -5243,7 +5324,12 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||
{
|
||||
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
||||
}
|
||||
p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
#ifdef JSON_HAS_CPP_20
|
||||
p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size()));
|
||||
#else
|
||||
p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5278,10 +5364,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/conversions/to_json.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -5304,10 +5390,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -5328,10 +5414,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/string_utils.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -5987,6 +6073,13 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<
|
||||
j = { std::get<Idx>(t)... };
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Tuple>
|
||||
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/)
|
||||
{
|
||||
using array_t = typename BasicJsonType::array_t;
|
||||
j = array_t();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
|
||||
inline void to_json(BasicJsonType& j, const T& t)
|
||||
{
|
||||
@@ -5997,7 +6090,12 @@ inline void to_json(BasicJsonType& j, const T& t)
|
||||
template<typename BasicJsonType>
|
||||
inline void to_json(BasicJsonType& j, const std_fs::path& p)
|
||||
{
|
||||
j = p.string();
|
||||
#ifdef JSON_HAS_CPP_20
|
||||
const std::u8string s = p.u8string();
|
||||
j = std::string(s.begin(), s.end());
|
||||
#else
|
||||
j = p.u8string(); // returns std::string in C++17
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6072,10 +6170,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/byte_container_with_subtype.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -6184,10 +6282,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/hash.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -6317,10 +6415,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/input/binary_reader.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -6346,10 +6444,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/input/input_adapters.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -6901,10 +6999,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/input/json_sax.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -6920,10 +7018,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/input/lexer.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -8171,7 +8269,7 @@ scan_number_done:
|
||||
// we are done scanning a number)
|
||||
unget();
|
||||
|
||||
char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
errno = 0;
|
||||
|
||||
// try to parse integers first and fall back to floats
|
||||
@@ -9544,10 +9642,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/meta/is_sax.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -12752,10 +12850,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/input/parser.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -13281,10 +13379,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -13294,10 +13392,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -13453,10 +13551,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/iterators/iter_impl.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -14224,10 +14322,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -14359,10 +14457,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/json_custom_base_class.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -14401,10 +14499,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/json_pointer.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -14634,7 +14732,7 @@ class json_pointer
|
||||
}
|
||||
|
||||
const char* p = s.c_str();
|
||||
char* p_end = nullptr;
|
||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||
errno = 0; // strtoull doesn't reset errno
|
||||
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
|
||||
if (p == p_end // invalid input or empty string
|
||||
@@ -15156,7 +15254,7 @@ class json_pointer
|
||||
// iterate array and use index as reference string
|
||||
for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
|
||||
{
|
||||
flatten(detail::concat(reference_string, '/', std::to_string(i)),
|
||||
flatten(detail::concat<string_t>(reference_string, '/', std::to_string(i)),
|
||||
value.m_data.m_value.array->operator[](i), result);
|
||||
}
|
||||
}
|
||||
@@ -15175,7 +15273,7 @@ class json_pointer
|
||||
// iterate object and use keys as reference string
|
||||
for (const auto& element : *value.m_data.m_value.object)
|
||||
{
|
||||
flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
|
||||
flatten(detail::concat<string_t>(reference_string, '/', detail::escape(element.first)), element.second, result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -15396,10 +15494,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/json_ref.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -15490,10 +15588,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/output/binary_writer.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -15516,10 +15614,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/output/output_adapters.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -17496,11 +17594,11 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/output/serializer.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2008 - 2009 Björn Hoehrmann <bjoern@hoehrmann.de>
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -17521,11 +17619,11 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/conversions/to_chars.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -19617,10 +19715,10 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/ordered_map.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -20168,7 +20266,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
basic_json result;
|
||||
|
||||
result["copyright"] = "(C) 2013-2023 Niels Lohmann";
|
||||
result["copyright"] = "(C) 2013-2025 Niels Lohmann";
|
||||
result["name"] = "JSON for Modern C++";
|
||||
result["url"] = "https://github.com/nlohmann/json";
|
||||
result["version"]["string"] =
|
||||
@@ -20433,7 +20531,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
object = nullptr; // silence warning, see #821
|
||||
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
|
||||
{
|
||||
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
|
||||
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -25220,10 +25318,10 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
|
||||
// #include <nlohmann/detail/macro_unscope.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
@@ -25254,6 +25352,7 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
|
||||
#undef JSON_HAS_CPP_14
|
||||
#undef JSON_HAS_CPP_17
|
||||
#undef JSON_HAS_CPP_20
|
||||
#undef JSON_HAS_CPP_23
|
||||
#undef JSON_HAS_FILESYSTEM
|
||||
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
#undef JSON_HAS_THREE_WAY_COMPARISON
|
||||
@@ -25265,10 +25364,10 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
|
||||
// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.11.3
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace rpc {
|
||||
|
||||
struct object_storage_node {
|
||||
torrent::Object object;
|
||||
char flags;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<fixed_key_type<64>, object_storage_node, hash_fixed_key_type> object_storage_base_type;
|
||||
|
||||
+6
-37
@@ -113,25 +113,20 @@ bool
|
||||
RpcManager::process(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback) {
|
||||
switch (type) {
|
||||
case RPCType::XML:
|
||||
// TODO: 'network.rpc.use_xmlrpc' should be a bool in RpcManager, not a command variable.
|
||||
if (m_xmlrpc.is_valid() && rpc::call_command_value("network.rpc.use_xmlrpc")) {
|
||||
return m_xmlrpc.process(in_buffer, length, callback);
|
||||
|
||||
} else {
|
||||
if (!m_xmlrpc.is_valid() || !m_use_xmlrpc) {
|
||||
const std::string response = "<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><i8>-501</i8></value></member><member><name>faultString</name><value><string>XML-RPC not supported</string></value></member></struct></value></fault></methodResponse>";
|
||||
return callback(response.c_str(), response.size());
|
||||
}
|
||||
break;
|
||||
|
||||
return m_xmlrpc.process(in_buffer, length, callback);
|
||||
|
||||
case RPCType::JSON:
|
||||
if (rpc::call_command_value("network.rpc.use_jsonrpc")) {
|
||||
return m_jsonrpc.process(in_buffer, length, callback);
|
||||
|
||||
} else {
|
||||
if (!m_use_jsonrpc) {
|
||||
const std::string response = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32601,\"message\":\"JSON-RPC not supported\"},\"id\":null}";
|
||||
return callback(response.c_str(), response.size());
|
||||
}
|
||||
break;
|
||||
|
||||
return m_jsonrpc.process(in_buffer, length, callback);
|
||||
|
||||
default:
|
||||
throw torrent::input_error("invalid parameters: unknown RPC type");
|
||||
@@ -172,32 +167,6 @@ RpcManager::cleanup() {
|
||||
m_jsonrpc.cleanup();
|
||||
}
|
||||
|
||||
bool
|
||||
RpcManager::is_type_enabled(RPCType type) const {
|
||||
switch (type) {
|
||||
case RPCType::XML:
|
||||
return m_is_xmlrpc_enabled;
|
||||
case RPCType::JSON:
|
||||
return m_is_jsonrpc_enabled;
|
||||
default:
|
||||
throw torrent::input_error("invalid parameters: unknown RPC type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RpcManager::set_type_enabled(RPCType type, bool enabled) {
|
||||
switch (type) {
|
||||
case RPCType::XML:
|
||||
m_is_xmlrpc_enabled = enabled;
|
||||
break;
|
||||
case RPCType::JSON:
|
||||
m_is_jsonrpc_enabled = enabled;
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("invalid parameters: unknown RPC type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RpcManager::insert_command(const char* name, const char* parm, const char* doc) {
|
||||
m_xmlrpc.insert_command(name, parm, doc);
|
||||
|
||||
+15
-6
@@ -67,8 +67,11 @@ public:
|
||||
int dialect() { return m_xmlrpc.dialect(); }
|
||||
void set_dialect(int dialect) { m_xmlrpc.set_dialect(dialect); }
|
||||
|
||||
bool is_type_enabled(RPCType type) const;
|
||||
void set_type_enabled(RPCType type, bool enabled);
|
||||
bool use_xmlrpc() const;
|
||||
void set_use_xmlrpc(bool v);
|
||||
|
||||
bool use_jsonrpc() const;
|
||||
void set_use_jsonrpc(bool v);
|
||||
|
||||
bool process(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback);
|
||||
bool process_untrusted(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback);
|
||||
@@ -102,11 +105,12 @@ private:
|
||||
JsonRpc m_jsonrpc;
|
||||
|
||||
bool m_handlers_initialized{};
|
||||
bool m_is_jsonrpc_enabled{true};
|
||||
bool m_is_xmlrpc_enabled{true};
|
||||
|
||||
std::atomic<bool> m_scgi_allow_compression{false};
|
||||
std::atomic<unsigned int> m_scgi_min_compress_size{0};
|
||||
bool m_use_jsonrpc{true};
|
||||
bool m_use_xmlrpc{true};
|
||||
|
||||
std::atomic<bool> m_scgi_allow_compression{true};
|
||||
std::atomic<unsigned int> m_scgi_min_compress_size{1000};
|
||||
|
||||
slot_download m_slot_find_download;
|
||||
slot_file m_slot_find_file;
|
||||
@@ -116,6 +120,11 @@ private:
|
||||
|
||||
extern RpcManager rpc;
|
||||
|
||||
inline bool RpcManager::use_xmlrpc() const { return m_use_xmlrpc; }
|
||||
inline void RpcManager::set_use_xmlrpc(bool v) { m_use_xmlrpc = v; }
|
||||
inline bool RpcManager::use_jsonrpc() const { return m_use_jsonrpc; }
|
||||
inline void RpcManager::set_use_jsonrpc(bool v) { m_use_jsonrpc = v; }
|
||||
|
||||
} // namespace rpc
|
||||
|
||||
#endif
|
||||
|
||||
+50
-58
@@ -5,12 +5,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/un.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/net/fd.h>
|
||||
#include <torrent/net/poll.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
#include <torrent/system/poll.h>
|
||||
#include <torrent/runtime/socket_manager.h>
|
||||
|
||||
#include "control.h"
|
||||
@@ -34,64 +33,60 @@ SCgi::~SCgi() {
|
||||
|
||||
void
|
||||
SCgi::open_port(sockaddr* sa, unsigned int length, bool dont_route) {
|
||||
torrent::runtime::socket_manager()->open_event_or_throw(this, [&]() {
|
||||
int fd = torrent::fd_open_family(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address,
|
||||
sa->sa_family);
|
||||
int fd = torrent::fd_open_family(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address,
|
||||
sa->sa_family);
|
||||
|
||||
if (fd == -1)
|
||||
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
|
||||
if (fd == -1)
|
||||
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
|
||||
|
||||
if (dont_route && !torrent::fd_set_dont_route(fd, true)) {
|
||||
torrent::fd_close(fd);
|
||||
throw torrent::resource_error("Could not set socket option IP_DONTROUTE: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
if (dont_route && !torrent::fd_set_dont_route(fd, true)) {
|
||||
torrent::fd_close(fd);
|
||||
throw torrent::resource_error("Could not set socket option IP_DONTROUTE: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
set_file_descriptor(fd);
|
||||
set_file_descriptor(fd);
|
||||
|
||||
open(reinterpret_cast<sockaddr*>(sa), length);
|
||||
});
|
||||
open(reinterpret_cast<sockaddr*>(sa), length);
|
||||
|
||||
torrent::connection_manager()->inc_socket_count();
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_rpc, []() {});
|
||||
}
|
||||
|
||||
void
|
||||
SCgi::open_named(const std::string& filename) {
|
||||
if (filename.empty() || filename.size() > 4096)
|
||||
if (filename.empty() || filename.size() >= sizeof(sockaddr_un::sun_path))
|
||||
throw torrent::resource_error("Invalid filename length.");
|
||||
|
||||
auto buffer = std::make_unique<char[]>(sizeof(sockaddr_un) + filename.size() + 1);
|
||||
|
||||
sockaddr_un* sa = reinterpret_cast<sockaddr_un*>(buffer.get());
|
||||
sa->sun_family = AF_LOCAL;
|
||||
|
||||
std::memcpy(sa->sun_path, filename.c_str(), filename.size() + 1);
|
||||
|
||||
torrent::runtime::socket_manager()->open_event_or_throw(this, [&]() {
|
||||
int fd = torrent::fd_open_local(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address);
|
||||
int fd = torrent::fd_open_local(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address);
|
||||
|
||||
if (fd == -1)
|
||||
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
|
||||
if (fd == -1)
|
||||
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
|
||||
|
||||
set_file_descriptor(fd);
|
||||
set_file_descriptor(fd);
|
||||
|
||||
open(reinterpret_cast<sockaddr*>(sa), offsetof(struct sockaddr_un, sun_path) + filename.size() + 1);
|
||||
});
|
||||
open(reinterpret_cast<sockaddr*>(sa), offsetof(struct sockaddr_un, sun_path) + filename.size() + 1);
|
||||
|
||||
torrent::connection_manager()->inc_socket_count();
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_rpc, []() {});
|
||||
|
||||
m_path = filename;
|
||||
}
|
||||
|
||||
void
|
||||
SCgi::open_fd(int fd) {
|
||||
torrent::runtime::socket_manager()->open_event_or_throw(this, [&]() {
|
||||
if (!torrent::fd_set_nonblock(fd))
|
||||
throw torrent::resource_error("Could not set non-blocking on systemd fd: " +
|
||||
std::string(std::strerror(errno)));
|
||||
set_file_descriptor(fd);
|
||||
// fd is already bound and listening; no bind()/listen() needed.
|
||||
});
|
||||
if (!torrent::fd_set_nonblock(fd))
|
||||
throw torrent::resource_error("Could not set non-blocking on systemd fd: " +
|
||||
std::string(std::strerror(errno)));
|
||||
set_file_descriptor(fd);
|
||||
|
||||
torrent::connection_manager()->inc_socket_count();
|
||||
// fd is already bound and listening; no bind()/listen() needed.
|
||||
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_rpc, []() {});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -116,7 +111,6 @@ SCgi::activate() {
|
||||
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
torrent::this_thread::poll()->insert_error(this);
|
||||
}
|
||||
|
||||
// TODO: This should close the fd to avoid reuse.
|
||||
@@ -132,15 +126,13 @@ SCgi::stop() {
|
||||
itr->close();
|
||||
}
|
||||
|
||||
torrent::runtime::socket_manager()->close_event_or_throw(this, [this]() {
|
||||
torrent::runtime::socket_manager()->unregister_event_or_throw(this, [this]() {
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
|
||||
torrent::fd_close(file_descriptor());
|
||||
set_file_descriptor(-1);
|
||||
});
|
||||
|
||||
torrent::connection_manager()->dec_socket_count();
|
||||
|
||||
if (!m_path.empty())
|
||||
::unlink(m_path.c_str());
|
||||
}
|
||||
@@ -159,38 +151,38 @@ SCgi::event_read() {
|
||||
if (m_current == m_tasks.end())
|
||||
m_current = std::find_if(m_tasks.begin(), prev, [](const auto& task) { return !task->is_open(); });
|
||||
|
||||
int fd = torrent::fd_accept(file_descriptor());
|
||||
|
||||
if (fd == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
||||
return;
|
||||
|
||||
// Force a new event_read() call just to be sure we don't enter an infinite loop.
|
||||
if (errno == ECONNABORTED)
|
||||
return;
|
||||
|
||||
throw torrent::resource_error("Listener port accept() failed: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
if (m_current == prev) {
|
||||
// TODO: Currently just close, although we should remove ourselves from read.
|
||||
int fd = torrent::fd_accept(file_descriptor());
|
||||
|
||||
if (fd != -1)
|
||||
torrent::fd_close(fd);
|
||||
|
||||
torrent::fd_close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto open_func = [this, task = m_current->get()]() {
|
||||
int fd = torrent::fd_accept(file_descriptor());
|
||||
|
||||
if (fd == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
||||
return;
|
||||
|
||||
// Force a new event_read() call just to be sure we don't enter an infinite loop.
|
||||
if (errno == ECONNABORTED)
|
||||
return;
|
||||
|
||||
throw torrent::resource_error("Listener port accept() failed: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
auto open_func = [this, fd, task = m_current->get()]() {
|
||||
task->open(this, fd);
|
||||
};
|
||||
|
||||
auto cleanup_func = [task = m_current->get()]() {
|
||||
auto cleanup_func = [fd, task = m_current->get()](bool opened) {
|
||||
if (!opened) {
|
||||
torrent::fd_close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
task->cancel_open();
|
||||
};
|
||||
|
||||
bool result = torrent::runtime::socket_manager()->open_event_or_cleanup(m_current->get(), open_func, cleanup_func);
|
||||
bool result = torrent::runtime::socket_manager()->open_event_or_cleanup(m_current->get(), torrent::runtime::category_rpc, open_func, cleanup_func);
|
||||
|
||||
if (!result)
|
||||
break;
|
||||
|
||||
+2
-2
@@ -3,13 +3,13 @@
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <torrent/event.h>
|
||||
#include <torrent/system/event.h>
|
||||
|
||||
#include "rpc/scgi_task.h"
|
||||
|
||||
namespace rpc {
|
||||
|
||||
class SCgi : public torrent::Event {
|
||||
class SCgi : public torrent::system::Event {
|
||||
public:
|
||||
static const int max_tasks = 100;
|
||||
|
||||
|
||||
+42
-26
@@ -11,10 +11,10 @@
|
||||
#include <sys/socket.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/net/fd.h>
|
||||
#include <torrent/net/poll.h>
|
||||
#include <torrent/runtime/socket_manager.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/system/poll.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/system/thread.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
@@ -24,6 +24,12 @@
|
||||
|
||||
namespace rpc {
|
||||
|
||||
SCgiTask::SCgiTask()
|
||||
: m_callback_id(torrent::system::make_callback_id()) {
|
||||
|
||||
reset_file_descriptor();
|
||||
}
|
||||
|
||||
void
|
||||
SCgiTask::open(SCgi* parent, int fd) {
|
||||
set_file_descriptor(fd);
|
||||
@@ -34,11 +40,15 @@ SCgiTask::open(SCgi* parent, int fd) {
|
||||
|
||||
m_content_length = 0;
|
||||
m_content_type = XML;
|
||||
m_content_type_set = false;
|
||||
m_accepts_compression = false;
|
||||
m_trusted = true; // SCgiTask is pooled and reused; reset trust to default
|
||||
// so a prior untrusted connection does not leak its
|
||||
// m_trusted=false into the next reuse, given that the
|
||||
// UNTRUSTED_CONNECTION=0 parse branch is a no-op.
|
||||
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
torrent::this_thread::poll()->insert_error(this);
|
||||
|
||||
auto lock = std::lock_guard<std::mutex>(m_result_mutex);
|
||||
|
||||
@@ -54,7 +64,7 @@ SCgiTask::cancel_open() {
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
|
||||
torrent::fd_close(file_descriptor());
|
||||
set_file_descriptor(-1);
|
||||
reset_file_descriptor();
|
||||
};
|
||||
|
||||
void
|
||||
@@ -62,14 +72,13 @@ SCgiTask::close() {
|
||||
if (!is_open())
|
||||
return;
|
||||
|
||||
torrent::main_thread::thread()->cancel_callback_and_wait(this);
|
||||
torrent::system::Thread::self()->cancel_callback(this);
|
||||
torrent::system::cancel_callback_and_wait(m_callback_id, scgi_thread::thread(), torrent::main_thread::thread());
|
||||
|
||||
torrent::runtime::socket_manager()->close_event_or_throw(this, [this]() {
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
|
||||
torrent::fd_close(file_descriptor());
|
||||
set_file_descriptor(-1);
|
||||
reset_file_descriptor();
|
||||
});
|
||||
|
||||
// The callbacks are guaranteed to be finished/canceled at this point.
|
||||
@@ -81,14 +90,14 @@ SCgiTask::close() {
|
||||
void
|
||||
SCgiTask::event_read() {
|
||||
int read_length = m_buffer.size() - m_position;
|
||||
|
||||
|
||||
if (m_content_length == 0)
|
||||
read_length--;
|
||||
|
||||
if (read_length <= 0)
|
||||
throw torrent::internal_error("SCgiTask::event_read() no space in buffer for event_read.");
|
||||
|
||||
int bytes = ::recv(m_fileDesc, m_buffer.data() + m_position, read_length, 0);
|
||||
|
||||
int bytes = ::recv(file_descriptor(), m_buffer.data() + m_position, read_length, 0);
|
||||
|
||||
if (bytes <= 0) {
|
||||
if (bytes == 0 || !(errno == EAGAIN || errno == EINTR))
|
||||
@@ -116,6 +125,9 @@ SCgiTask::event_read() {
|
||||
if (current == m_buffer.data())
|
||||
return;
|
||||
|
||||
if (current == m_buffer.data() + m_position)
|
||||
return;
|
||||
|
||||
if (*current != ':' || header_size < 17 || header_size > max_header_size)
|
||||
goto event_read_failed;
|
||||
|
||||
@@ -153,6 +165,11 @@ SCgiTask::event_read() {
|
||||
|
||||
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_buffer.data() + m_body, m_content_length, "scgi", "RPC read.", 0);
|
||||
|
||||
if (!m_content_type_set) {
|
||||
if (m_buffer[m_body] == '{' || m_buffer[m_body] == '[')
|
||||
m_content_type = ContentType::JSON;
|
||||
}
|
||||
|
||||
receive_call(m_buffer.data() + m_body, m_content_length);
|
||||
return;
|
||||
|
||||
@@ -163,10 +180,10 @@ event_read_failed:
|
||||
|
||||
void
|
||||
SCgiTask::event_write() {
|
||||
int bytes = ::send(m_fileDesc, m_buffer.data() + m_position, m_buffer.size() - m_position, 0);
|
||||
int bytes = ::send(file_descriptor(), m_buffer.data() + m_position, m_buffer.size() - m_position, 0);
|
||||
|
||||
if (bytes == -1) {
|
||||
if (!(errno == EAGAIN || errno == EINTR || errno == EPIPE))
|
||||
if (!(errno == EAGAIN || errno == EINTR))
|
||||
close();
|
||||
|
||||
return;
|
||||
@@ -231,7 +248,8 @@ SCgiTask::parse_headers(const char* current, unsigned int header_length) {
|
||||
if (std::strncmp(value, "1", 1+1) == 0)
|
||||
m_trusted = false;
|
||||
else if (std::strncmp(value, "0", 1+1) == 0)
|
||||
; // Default is trusted, so do nothing.
|
||||
m_trusted = true; // Explicit reset (open() also resets, but be defensive in case
|
||||
// future refactors stop pooling tasks or skip the open() reset).
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -285,19 +303,17 @@ scgi_match_content_type(const std::string& content_type, const char* type) {
|
||||
bool
|
||||
SCgiTask::detect_content_type(const std::string& content_type) {
|
||||
if (content_type.empty()) {
|
||||
// If no CONTENT_TYPE was supplied, peek at the body to check if it's JSON
|
||||
// { is a single request object, while [ is a batch array
|
||||
|
||||
if (m_buffer[m_body] == '{' || m_buffer[m_body] == '[')
|
||||
m_content_type = ContentType::JSON;
|
||||
else
|
||||
m_content_type = ContentType::XML;
|
||||
// Defer body-peek detection until the full body is received.
|
||||
// event_read() will auto-detect from the first body byte after
|
||||
// confirming m_position >= m_body + m_content_length.
|
||||
|
||||
} else if (scgi_match_content_type(content_type, "application/json")) {
|
||||
m_content_type = ContentType::JSON;
|
||||
m_content_type = ContentType::JSON;
|
||||
m_content_type_set = true;
|
||||
|
||||
} else if (scgi_match_content_type(content_type, "text/xml")) {
|
||||
m_content_type = ContentType::XML;
|
||||
m_content_type = ContentType::XML;
|
||||
m_content_type_set = true;
|
||||
|
||||
} else {
|
||||
// If the content type is not JSON or XML, we don't know how to handle it.
|
||||
@@ -309,7 +325,7 @@ SCgiTask::detect_content_type(const std::string& content_type) {
|
||||
|
||||
void
|
||||
SCgiTask::receive_call(const char* buffer, uint32_t length) {
|
||||
assert(torrent::system::Thread::self() == scgi_thread::thread());
|
||||
assert(torrent::this_thread::thread() == scgi_thread::thread());
|
||||
|
||||
RpcManager::RPCType rpc_type;
|
||||
|
||||
@@ -336,7 +352,7 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
|
||||
m_result_mutex.lock();
|
||||
m_result_mutex.unlock();
|
||||
|
||||
scgi_thread::thread()->callback_interrupt_polling(this, [this]() {
|
||||
scgi_thread::callback_interrupt(m_callback_id, [this]() {
|
||||
if (!is_open())
|
||||
return;
|
||||
|
||||
@@ -356,7 +372,7 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
|
||||
m_result_mutex.lock();
|
||||
m_result_mutex.unlock();
|
||||
|
||||
torrent::main_thread::thread()->callback_interrupt_polling(this, [this, rpc_type, buffer, length, result_callback]() {
|
||||
torrent::main_thread::callback_interrupt(m_callback_id, [this, rpc_type, buffer, length, result_callback]() {
|
||||
// Memory barrier for the input data.
|
||||
// std::atomic_thread_fence(std::memory_order_acquire);
|
||||
m_result_mutex.lock();
|
||||
@@ -371,7 +387,7 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
|
||||
|
||||
void
|
||||
SCgiTask::receive_write(const char* buffer, uint32_t length) {
|
||||
assert(torrent::system::Thread::self() == torrent::main_thread::thread());
|
||||
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
|
||||
|
||||
if (buffer == nullptr || length > (100 << 20))
|
||||
throw torrent::internal_error("SCgiTask::receive_write(...) received bad input.");
|
||||
|
||||
+8
-6
@@ -4,13 +4,13 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <torrent/event.h>
|
||||
#include <torrent/system/event.h>
|
||||
|
||||
namespace rpc {
|
||||
|
||||
class SCgi;
|
||||
|
||||
class SCgiTask : public torrent::Event {
|
||||
class SCgiTask : public torrent::system::Event {
|
||||
public:
|
||||
static constexpr int default_buffer_size = 8191;
|
||||
static constexpr int max_header_size = 2000;
|
||||
@@ -18,12 +18,12 @@ public:
|
||||
|
||||
enum ContentType { XML, JSON };
|
||||
|
||||
SCgiTask() { m_fileDesc = -1; }
|
||||
SCgiTask();
|
||||
|
||||
const char* type_name() const override { return "scgi-task"; }
|
||||
|
||||
bool is_open() const { return m_fileDesc != -1; }
|
||||
bool is_available() const { return m_fileDesc == -1; }
|
||||
bool is_open() const { return file_descriptor() != -1; }
|
||||
bool is_available() const { return file_descriptor() == -1; }
|
||||
|
||||
void open(SCgi* parent, int fd);
|
||||
void cancel_open();
|
||||
@@ -54,7 +54,8 @@ private:
|
||||
void plaintext_response(const char* buffer, uint32_t content_length);
|
||||
void gzip_response(const char* buffer, uint32_t content_length);
|
||||
|
||||
SCgi* m_parent{};
|
||||
SCgi* m_parent{};
|
||||
torrent::system::callback_id m_callback_id;
|
||||
|
||||
std::mutex m_result_mutex;
|
||||
|
||||
@@ -67,6 +68,7 @@ private:
|
||||
|
||||
bool m_accepts_compression{};
|
||||
bool m_trusted{true};
|
||||
bool m_content_type_set{false};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ distribution.
|
||||
#include "tinyxml2.h"
|
||||
|
||||
#include <new> // yes, this one new style header, is in the Android SDK.
|
||||
#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
|
||||
#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) || defined(__CC_ARM)
|
||||
# include <stddef.h>
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
@@ -239,13 +239,13 @@ char* StrPair::ParseName( char* p )
|
||||
if ( !p || !(*p) ) {
|
||||
return 0;
|
||||
}
|
||||
if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
|
||||
if ( !XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* const start = p;
|
||||
++p;
|
||||
while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) {
|
||||
while ( *p && XMLUtil::IsNameChar( static_cast<unsigned char>(*p) ) ) {
|
||||
++p;
|
||||
}
|
||||
|
||||
@@ -472,102 +472,94 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length
|
||||
}
|
||||
|
||||
|
||||
const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
|
||||
const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)
|
||||
{
|
||||
// Presume an entity, and pull it out.
|
||||
// Assume an entity, and pull it out.
|
||||
*length = 0;
|
||||
|
||||
if ( *(p+1) == '#' && *(p+2) ) {
|
||||
unsigned long ucs = 0;
|
||||
TIXMLASSERT( sizeof( ucs ) >= 4 );
|
||||
static const uint32_t MAX_CODE_POINT = 0x10FFFF;
|
||||
|
||||
if (*(p + 1) == '#' && *(p + 2)) {
|
||||
uint32_t ucs = 0;
|
||||
ptrdiff_t delta = 0;
|
||||
unsigned mult = 1;
|
||||
uint32_t mult = 1;
|
||||
static const char SEMICOLON = ';';
|
||||
|
||||
if ( *(p+2) == 'x' ) {
|
||||
bool hex = false;
|
||||
uint32_t radix = 10;
|
||||
const char* q = 0;
|
||||
char terminator = '#';
|
||||
|
||||
if (*(p + 2) == 'x') {
|
||||
// Hexadecimal.
|
||||
const char* q = p+3;
|
||||
if ( !(*q) ) {
|
||||
return 0;
|
||||
}
|
||||
hex = true;
|
||||
radix = 16;
|
||||
terminator = 'x';
|
||||
|
||||
q = strchr( q, SEMICOLON );
|
||||
|
||||
if ( !q ) {
|
||||
return 0;
|
||||
}
|
||||
TIXMLASSERT( *q == SEMICOLON );
|
||||
|
||||
delta = q-p;
|
||||
--q;
|
||||
|
||||
while ( *q != 'x' ) {
|
||||
unsigned int digit = 0;
|
||||
|
||||
if ( *q >= '0' && *q <= '9' ) {
|
||||
digit = *q - '0';
|
||||
}
|
||||
else if ( *q >= 'a' && *q <= 'f' ) {
|
||||
digit = *q - 'a' + 10;
|
||||
}
|
||||
else if ( *q >= 'A' && *q <= 'F' ) {
|
||||
digit = *q - 'A' + 10;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
TIXMLASSERT( digit < 16 );
|
||||
TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
|
||||
const unsigned int digitScaled = mult * digit;
|
||||
TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
|
||||
ucs += digitScaled;
|
||||
TIXMLASSERT( mult <= UINT_MAX / 16 );
|
||||
mult *= 16;
|
||||
--q;
|
||||
}
|
||||
q = p + 3;
|
||||
}
|
||||
else {
|
||||
// Decimal.
|
||||
const char* q = p+2;
|
||||
if ( !(*q) ) {
|
||||
q = p + 2;
|
||||
}
|
||||
if (!(*q)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
q = strchr(q, SEMICOLON);
|
||||
if (!q) {
|
||||
return 0;
|
||||
}
|
||||
TIXMLASSERT(*q == SEMICOLON);
|
||||
|
||||
delta = q - p;
|
||||
--q;
|
||||
|
||||
while (*q != terminator) {
|
||||
uint32_t digit = 0;
|
||||
|
||||
if (*q >= '0' && *q <= '9') {
|
||||
digit = *q - '0';
|
||||
}
|
||||
else if (hex && (*q >= 'a' && *q <= 'f')) {
|
||||
digit = *q - 'a' + 10;
|
||||
}
|
||||
else if (hex && (*q >= 'A' && *q <= 'F')) {
|
||||
digit = *q - 'A' + 10;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
TIXMLASSERT(digit < radix);
|
||||
|
||||
q = strchr( q, SEMICOLON );
|
||||
|
||||
if ( !q ) {
|
||||
return 0;
|
||||
const unsigned int digitScaled = mult * digit;
|
||||
ucs += digitScaled;
|
||||
mult *= radix;
|
||||
|
||||
// Security check: could a value exist that is out of range?
|
||||
// Easily; limit to the MAX_CODE_POINT, which also allows for a
|
||||
// bunch of leading zeroes.
|
||||
if (mult > MAX_CODE_POINT) {
|
||||
mult = MAX_CODE_POINT;
|
||||
}
|
||||
TIXMLASSERT( *q == SEMICOLON );
|
||||
|
||||
delta = q-p;
|
||||
--q;
|
||||
|
||||
while ( *q != '#' ) {
|
||||
if ( *q >= '0' && *q <= '9' ) {
|
||||
const unsigned int digit = *q - '0';
|
||||
TIXMLASSERT( digit < 10 );
|
||||
TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
|
||||
const unsigned int digitScaled = mult * digit;
|
||||
TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
|
||||
ucs += digitScaled;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
TIXMLASSERT( mult <= UINT_MAX / 10 );
|
||||
mult *= 10;
|
||||
--q;
|
||||
}
|
||||
}
|
||||
// Out of range:
|
||||
if (ucs > MAX_CODE_POINT) {
|
||||
return 0;
|
||||
}
|
||||
// convert the UCS to UTF-8
|
||||
ConvertUTF32ToUTF8( ucs, value, length );
|
||||
ConvertUTF32ToUTF8(ucs, value, length);
|
||||
if (length == 0) {
|
||||
// If length is 0, there was an error. (Security? Bad input?)
|
||||
// Fail safely.
|
||||
return 0;
|
||||
}
|
||||
return p + delta + 1;
|
||||
}
|
||||
return p+1;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
|
||||
void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
|
||||
{
|
||||
TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
|
||||
@@ -705,7 +697,7 @@ bool XMLUtil::ToInt64(const char* str, int64_t* value)
|
||||
bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
|
||||
unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
|
||||
if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) {
|
||||
*value = (uint64_t)v;
|
||||
*value = static_cast<uint64_t>(v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1982,7 +1974,7 @@ char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
|
||||
}
|
||||
|
||||
// attribute.
|
||||
if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
|
||||
if (XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
|
||||
XMLAttribute* attrib = CreateAttribute();
|
||||
TIXMLASSERT( attrib );
|
||||
attrib->_parseLineNum = _document->_parseCurLineNum;
|
||||
|
||||
@@ -98,11 +98,11 @@ distribution.
|
||||
/* Versioning, past 1.0.14:
|
||||
http://semver.org/
|
||||
*/
|
||||
static const int TIXML2_MAJOR_VERSION = 10;
|
||||
static const int TIXML2_MAJOR_VERSION = 11;
|
||||
static const int TIXML2_MINOR_VERSION = 0;
|
||||
static const int TIXML2_PATCH_VERSION = 0;
|
||||
|
||||
#define TINYXML2_MAJOR_VERSION 10
|
||||
#define TINYXML2_MAJOR_VERSION 11
|
||||
#define TINYXML2_MINOR_VERSION 0
|
||||
#define TINYXML2_PATCH_VERSION 0
|
||||
|
||||
|
||||
+8
-6
@@ -1,3 +1,4 @@
|
||||
#include <deque>
|
||||
#include "config.h"
|
||||
|
||||
#include "xmlrpc.h"
|
||||
@@ -9,20 +10,21 @@
|
||||
|
||||
namespace rpc {
|
||||
|
||||
std::vector<std::unique_ptr<const char>> XmlRpc::m_command_names;
|
||||
std::deque<std::string> XmlRpc::m_command_names;
|
||||
|
||||
const char*
|
||||
XmlRpc::store_command_name(const char* name) {
|
||||
if (::strnlen(name, 8192) == 8192)
|
||||
if (::strnlen(name, 1024 + 1) > 1024)
|
||||
throw torrent::input_error("XMLRPC command name too long, limit is 8192 characters.");
|
||||
|
||||
for (const auto& itr : m_command_names) {
|
||||
if (::strcmp(itr.get(), name) == 0)
|
||||
return itr.get();
|
||||
if (itr == name)
|
||||
return itr.c_str();
|
||||
}
|
||||
|
||||
m_command_names.push_back(std::unique_ptr<const char>(::strdup(name)));
|
||||
return m_command_names.back().get();
|
||||
m_command_names.push_back(name);
|
||||
|
||||
return m_command_names.back().c_str();
|
||||
}
|
||||
|
||||
#ifndef HAVE_XMLRPC_C
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#ifndef RTORRENT_RPC_XMLRPC_H
|
||||
#define RTORRENT_RPC_XMLRPC_H
|
||||
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/hash_string.h>
|
||||
@@ -61,7 +62,7 @@ public:
|
||||
private:
|
||||
static const char* store_command_name(const char* name);
|
||||
|
||||
static std::vector<std::unique_ptr<const char>> m_command_names;
|
||||
static std::deque<std::string> m_command_names;
|
||||
|
||||
slot_download m_slotFindDownload;
|
||||
slot_file m_slotFindFile;
|
||||
|
||||
+17
-2
@@ -272,12 +272,27 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
|
||||
#ifdef XMLRPC_HAVE_I8
|
||||
if (rpc.dialect() != XmlRpc::dialect_generic)
|
||||
return xmlrpc_i8_new(env, object.as_value());
|
||||
#else
|
||||
return xmlrpc_int_new(env, object.as_value());
|
||||
#endif
|
||||
|
||||
return xmlrpc_int_new(env, object.as_value());
|
||||
|
||||
case torrent::Object::TYPE_STRING:
|
||||
{
|
||||
if (object.flags() & torrent::Object::flag_as_binary) {
|
||||
|
||||
// This causes decode-and-reencode for base64, as XMLRPC-C doesn't allow us to pass base64 strings.
|
||||
if (object.flags() & torrent::Object::flag_base64) {
|
||||
auto binary_data = torrent::utils::transform_from_base64_unsafe(object.as_string());
|
||||
|
||||
if (!binary_data.has_value())
|
||||
throw torrent::input_error("invalid base64 string in base64-as-binary object");
|
||||
|
||||
return xmlrpc_base64_new(env, binary_data->size(), reinterpret_cast<const unsigned char*>(binary_data->data()));
|
||||
}
|
||||
|
||||
return xmlrpc_base64_new(env, object.as_string().size(), reinterpret_cast<const unsigned char*>(object.as_string().c_str()));
|
||||
}
|
||||
|
||||
#ifdef XMLRPC_HAVE_I8
|
||||
// The versions that support I8 do implicit utf-8 validation.
|
||||
xmlrpc_value* result = xmlrpc_string_new(env, object.as_string().c_str());
|
||||
|
||||
+59
-12
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
#include "parse_commands.h"
|
||||
#include "rpc/tinyxml2/tinyxml2.h"
|
||||
@@ -66,56 +67,85 @@ xml_value_to_object(const tinyxml2::XMLNode* elem) {
|
||||
if (elem == nullptr) {
|
||||
throw rpc_error(XMLRPC_INTERNAL_ERROR, "received null element to convert");
|
||||
}
|
||||
|
||||
if (std::strncmp(elem->Value(), "value", sizeof("value")) != 0) {
|
||||
throw rpc_error(XMLRPC_INTERNAL_ERROR, "received non-value element to convert");
|
||||
}
|
||||
|
||||
auto root_element = elem->FirstChild();
|
||||
|
||||
if (root_element == nullptr)
|
||||
throw rpc_error(XMLRPC_TYPE_ERROR, "empty value element");
|
||||
|
||||
auto root_type = root_element->Value();
|
||||
|
||||
if (std::strncmp(root_type, "string", sizeof("string")) == 0) {
|
||||
auto child_element = root_element->FirstChild();
|
||||
if (child_element == nullptr) {
|
||||
|
||||
if (child_element == nullptr)
|
||||
return torrent::Object("");
|
||||
}
|
||||
|
||||
return torrent::Object(child_element->ToText()->Value());
|
||||
|
||||
} else if (std::strncmp(root_type, "int", sizeof("int")) == 0 ||
|
||||
std::strncmp(root_type, "i4", sizeof("i4")) == 0 ||
|
||||
std::strncmp(root_type, "i8", sizeof("i8")) == 0) {
|
||||
return torrent::Object(element_to_int(root_element));
|
||||
|
||||
} else if (std::strncmp(root_type, "boolean", sizeof("boolean")) == 0) {
|
||||
auto boolean_text = std::string(root_element->FirstChild()->ToText()->Value());
|
||||
if (boolean_text == "1") {
|
||||
auto child_element = root_element->FirstChild();
|
||||
|
||||
if (child_element == nullptr)
|
||||
throw rpc_error(XMLRPC_TYPE_ERROR, "empty boolean element");
|
||||
|
||||
auto boolean_text = std::string(child_element->ToText()->Value());
|
||||
|
||||
if (boolean_text == "1")
|
||||
return torrent::Object((int64_t)1);
|
||||
} else if (boolean_text == "0") {
|
||||
else if (boolean_text == "0")
|
||||
return torrent::Object((int64_t)0);
|
||||
}
|
||||
|
||||
throw rpc_error(XMLRPC_TYPE_ERROR, "unknown boolean value: " + boolean_text);
|
||||
|
||||
} else if (std::strncmp(root_type, "array", sizeof("array")) == 0) {
|
||||
auto array_raw = torrent::Object::create_list();
|
||||
auto& array = array_raw.as_list();
|
||||
auto data_element = root_element->ToElement()->FirstChildElement("data");
|
||||
|
||||
if (data_element == nullptr)
|
||||
throw rpc_error(XMLRPC_PARSE_ERROR, "could not find expected data element in array");
|
||||
for (auto child = data_element->FirstChildElement("value"); child; child = child->NextSiblingElement("value")) {
|
||||
|
||||
for (auto child = data_element->FirstChildElement("value"); child; child = child->NextSiblingElement("value"))
|
||||
array.push_back(xml_value_to_object(child));
|
||||
}
|
||||
|
||||
return array_raw;
|
||||
} else if (std::strncmp(root_type, "struct", sizeof("struct")) == 0) {
|
||||
auto map_raw = torrent::Object::create_map();
|
||||
auto& map = map_raw.as_map();
|
||||
|
||||
for (auto child = root_element->FirstChildElement("member"); child; child = child->NextSiblingElement("member")) {
|
||||
auto key = child->FirstChildElement("name")->GetText();
|
||||
map[key] = std::move(xml_value_to_object(child->FirstChildElement("value")));
|
||||
auto name_element = child->FirstChildElement("name");
|
||||
|
||||
if (name_element == nullptr)
|
||||
throw rpc_error(XMLRPC_PARSE_ERROR, "struct member missing name element");
|
||||
|
||||
map[name_element->GetText()] = std::move(xml_value_to_object(child->FirstChildElement("value")));
|
||||
}
|
||||
|
||||
return map_raw;
|
||||
|
||||
} else if (std::strncmp(root_type, "base64", sizeof("base64")) == 0) {
|
||||
auto child_element = root_element->FirstChild();
|
||||
if (child_element == nullptr) {
|
||||
|
||||
if (child_element == nullptr)
|
||||
return torrent::Object("");
|
||||
}
|
||||
|
||||
return torrent::Object(utils::decode_base64(utils::remove_newlines(child_element->ToText()->Value())));
|
||||
|
||||
} else {
|
||||
throw rpc_error(XMLRPC_INTERNAL_ERROR, "received unsupported value type: " + std::string(root_type));
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
@@ -123,15 +153,32 @@ void
|
||||
print_object_xml(const torrent::Object& obj, tinyxml2::XMLPrinter* printer) {
|
||||
switch (obj.type()) {
|
||||
case torrent::Object::TYPE_STRING:
|
||||
if (obj.flags() & torrent::Object::flag_as_binary) {
|
||||
// It is optimal for tinyxml2 to pass base64 strings directly from torrent::string_utf8 sources.
|
||||
if (obj.flags() & torrent::Object::flag_base64) {
|
||||
printer->OpenElement("base64", true);
|
||||
printer->PushText(obj.as_string().c_str());
|
||||
printer->CloseElement(true);
|
||||
break;
|
||||
}
|
||||
|
||||
printer->OpenElement("base64", true);
|
||||
printer->PushText(torrent::utils::transform_to_base64(obj.as_string()).c_str());
|
||||
printer->CloseElement(true);
|
||||
break;
|
||||
}
|
||||
|
||||
printer->OpenElement("string", true);
|
||||
printer->PushText(obj.as_string().c_str());
|
||||
printer->CloseElement(true);
|
||||
break;
|
||||
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
printer->OpenElement("i8", true);
|
||||
printer->PushText(std::to_string(obj.as_value()).c_str());
|
||||
printer->CloseElement(true);
|
||||
break;
|
||||
|
||||
case torrent::Object::TYPE_LIST:
|
||||
printer->OpenElement("array", true);
|
||||
printer->OpenElement("data", true);
|
||||
|
||||
+8
-15
@@ -12,11 +12,6 @@
|
||||
|
||||
namespace scgi {
|
||||
|
||||
class ThreadScgiInternal {
|
||||
public:
|
||||
static ThreadScgi* thread_scgi() { return ThreadScgi::internal_thread_scgi(); }
|
||||
};
|
||||
|
||||
ThreadScgi* ThreadScgi::m_thread_scgi{};
|
||||
|
||||
void
|
||||
@@ -60,7 +55,7 @@ ThreadScgi::set_scgi(rpc::SCgi* scgi) {
|
||||
|
||||
change_rpc_log();
|
||||
|
||||
callback(nullptr, [this]() {
|
||||
callback([this]() {
|
||||
if (m_scgi == nullptr)
|
||||
throw torrent::internal_error("Tried to start SCGI but object was not present.");
|
||||
|
||||
@@ -72,7 +67,7 @@ ThreadScgi::set_scgi(rpc::SCgi* scgi) {
|
||||
|
||||
void
|
||||
ThreadScgi::set_rpc_log(const std::string& filename) {
|
||||
callback(nullptr, [this, filename]() {
|
||||
callback([this, filename]() {
|
||||
m_rpc_log_filename = filename;
|
||||
change_rpc_log();
|
||||
});
|
||||
@@ -127,15 +122,13 @@ ThreadScgi::next_timeout() {
|
||||
|
||||
namespace scgi_thread {
|
||||
|
||||
torrent::system::Thread* thread() { return scgi::ThreadScgiInternal::thread_scgi(); }
|
||||
std::thread::id thread_id() { return scgi::ThreadScgiInternal::thread_scgi()->thread_id(); }
|
||||
torrent::system::Thread* thread() { return scgi::ThreadScgi::thread_scgi(); }
|
||||
std::thread::id thread_id() { return scgi::ThreadScgi::thread_scgi()->thread_id(); }
|
||||
|
||||
void callback(void* target, std::function<void ()>&& fn) { scgi::ThreadScgiInternal::thread_scgi()->callback(target, std::move(fn)); }
|
||||
void cancel_callback(void* target) { scgi::ThreadScgiInternal::thread_scgi()->cancel_callback(target); }
|
||||
void cancel_callback_and_wait(void* target) { scgi::ThreadScgiInternal::thread_scgi()->cancel_callback_and_wait(target); }
|
||||
void callback_interrupt(torrent::system::callback_id& id, std::function<void ()>&& fn) { scgi::ThreadScgi::thread_scgi()->callback_interrupt(id, std::move(fn)); }
|
||||
|
||||
rpc::SCgi* scgi() { return scgi::ThreadScgiInternal::thread_scgi()->scgi(); }
|
||||
void set_scgi(rpc::SCgi* scgi) { scgi::ThreadScgiInternal::thread_scgi()->set_scgi(scgi); }
|
||||
void set_rpc_log(const std::string& filename) { scgi::ThreadScgiInternal::thread_scgi()->set_rpc_log(filename); }
|
||||
rpc::SCgi* scgi() { return scgi::ThreadScgi::thread_scgi()->scgi(); }
|
||||
void set_scgi(rpc::SCgi* scgi) { scgi::ThreadScgi::thread_scgi()->set_scgi(scgi); }
|
||||
void set_rpc_log(const std::string& filename) { scgi::ThreadScgi::thread_scgi()->set_rpc_log(filename); }
|
||||
|
||||
} // namespace scgi_thread
|
||||
|
||||
@@ -11,8 +11,6 @@ class SCgi;
|
||||
|
||||
namespace scgi {
|
||||
|
||||
class ThreadScgiInternal;
|
||||
|
||||
class ThreadScgi : public torrent::system::Thread {
|
||||
public:
|
||||
|
||||
@@ -28,8 +26,6 @@ public:
|
||||
void set_rpc_log(const std::string& filename);
|
||||
|
||||
protected:
|
||||
friend class ThreadScgiInternal;
|
||||
|
||||
ThreadScgi() = default;
|
||||
|
||||
static auto internal_thread_scgi() { return m_thread_scgi; }
|
||||
@@ -43,9 +39,9 @@ private:
|
||||
void task_touch_log();
|
||||
void change_rpc_log();
|
||||
|
||||
static ThreadScgi* m_thread_scgi;
|
||||
static ThreadScgi* m_thread_scgi;
|
||||
|
||||
std::atomic<rpc::SCgi*> m_scgi{nullptr};
|
||||
std::atomic<rpc::SCgi*> m_scgi{};
|
||||
std::string m_rpc_log_filename;
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
#include "globals.h"
|
||||
@@ -23,6 +24,7 @@ namespace session {
|
||||
|
||||
SessionManager::SessionManager(torrent::system::Thread* thread)
|
||||
: m_thread(thread),
|
||||
m_callback_id(torrent::system::make_callback_id()),
|
||||
m_lockfile(std::make_unique<utils::Lockfile>()) {
|
||||
}
|
||||
|
||||
@@ -221,8 +223,7 @@ SessionManager::cleanup() {
|
||||
|
||||
LT_LOG("session manager cleaned up", 0);
|
||||
|
||||
session_thread::cancel_callback(this);
|
||||
torrent::main_thread::cancel_callback(this);
|
||||
torrent::system::cancel_callback_and_wait(m_callback_id, session_thread::thread(), torrent::main_thread::thread());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -233,7 +234,9 @@ SessionManager::callback_pending_builds() {
|
||||
if (m_callback_scheduled_process_pending_builds.exchange(true))
|
||||
return;
|
||||
|
||||
torrent::main_thread::callback(this, [this]() { process_pending_builds(false); });
|
||||
torrent::main_thread::callback(m_callback_id, [this]() {
|
||||
process_pending_builds(false);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -247,7 +250,9 @@ SessionManager::callback_save_request() {
|
||||
if (m_callback_scheduled_process_saves_request.exchange(true))
|
||||
return;
|
||||
|
||||
session_thread::callback(this, [this]() { process_save_request(); });
|
||||
session_thread::callback(m_callback_id, [this]() {
|
||||
process_save_request();
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -255,7 +260,9 @@ SessionManager::callback_finished_saves() {
|
||||
if (m_callback_scheduled_process_finished_saves.exchange(true))
|
||||
return;
|
||||
|
||||
session_thread::callback(this, [this]() { process_finished_saves(); });
|
||||
session_thread::callback(m_callback_id, [this]() {
|
||||
process_finished_saves();
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -89,37 +89,39 @@ private:
|
||||
bool replace_save_request_unsafe(SaveRequest& download);
|
||||
bool remove_completely_unsafe(core::Download* download, std::unique_lock<std::mutex>& lock);
|
||||
|
||||
torrent::system::Thread* m_thread;
|
||||
using ProcessingSave = std::pair<std::future<void>, SaveRequest>;
|
||||
|
||||
bool m_freeze_info{};
|
||||
std::string m_path;
|
||||
bool m_use_fsyncdisk{true};
|
||||
bool m_use_lock{true};
|
||||
torrent::system::Thread* m_thread;
|
||||
torrent::system::callback_id m_callback_id;
|
||||
|
||||
std::mutex m_mutex;
|
||||
bool m_active{};
|
||||
bool m_freeze_info{};
|
||||
std::string m_path;
|
||||
bool m_use_fsyncdisk{true};
|
||||
bool m_use_lock{true};
|
||||
|
||||
typedef std::pair<std::future<void>, SaveRequest> ProcessingSave;
|
||||
align_cacheline std::mutex m_mutex;
|
||||
|
||||
std::deque<SaveRequest> m_save_requests;
|
||||
std::atomic<size_t> m_save_request_counter{};
|
||||
std::list<ProcessingSave> m_processing_saves;
|
||||
std::atomic<size_t> m_processing_save_counter{};
|
||||
std::condition_variable m_finished_condition;
|
||||
std::vector<ProcessingSave> m_finished_saves;
|
||||
bool m_active{};
|
||||
|
||||
std::atomic<bool> m_callback_scheduled_process_pending_builds{};
|
||||
std::atomic<bool> m_callback_scheduled_process_saves_request{};
|
||||
std::atomic<bool> m_callback_scheduled_process_finished_saves{};
|
||||
std::deque<SaveRequest> m_save_requests;
|
||||
std::atomic<size_t> m_save_request_counter{};
|
||||
std::list<ProcessingSave> m_processing_saves;
|
||||
std::atomic<size_t> m_processing_save_counter{};
|
||||
std::condition_variable m_finished_condition;
|
||||
std::vector<ProcessingSave> m_finished_saves;
|
||||
|
||||
std::atomic<bool> m_callback_scheduled_process_pending_builds{};
|
||||
std::atomic<bool> m_callback_scheduled_process_saves_request{};
|
||||
std::atomic<bool> m_callback_scheduled_process_finished_saves{};
|
||||
|
||||
std::unique_ptr<utils::Lockfile> m_lockfile;
|
||||
|
||||
std::chrono::microseconds m_last_storage_error_message{};
|
||||
unsigned int m_ignored_storage_error_count{};
|
||||
std::chrono::microseconds m_last_storage_error_message{};
|
||||
unsigned int m_ignored_storage_error_count{};
|
||||
|
||||
// Pending builds are only ever locked by main thread.
|
||||
std::mutex m_pending_builds_mutex;
|
||||
std::deque<core::Download*> m_pending_builds;
|
||||
std::mutex m_pending_builds_mutex;
|
||||
std::deque<core::Download*> m_pending_builds;
|
||||
};
|
||||
|
||||
inline bool SessionManager::is_used() const { return !m_path.empty(); }
|
||||
|
||||
@@ -4,15 +4,11 @@
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "session/session_manager.h"
|
||||
|
||||
namespace session {
|
||||
|
||||
class ThreadSessionInternal {
|
||||
public:
|
||||
static ThreadSession* thread_session() { return ThreadSession::internal_thread_session(); }
|
||||
};
|
||||
|
||||
ThreadSession* ThreadSession::m_thread_session{nullptr};
|
||||
|
||||
void
|
||||
@@ -74,14 +70,14 @@ ThreadSession::next_timeout() {
|
||||
|
||||
namespace session_thread {
|
||||
|
||||
torrent::system::Thread* thread() { return session::ThreadSessionInternal::thread_session(); }
|
||||
std::thread::id thread_id() { return session::ThreadSessionInternal::thread_session()->thread_id(); }
|
||||
torrent::system::Thread* thread() { return session::ThreadSession::thread_session(); }
|
||||
std::thread::id thread_id() { return thread()->thread_id(); }
|
||||
|
||||
void callback(void* target, std::function<void ()>&& fn) { session::ThreadSessionInternal::thread_session()->callback(target, std::move(fn)); }
|
||||
void cancel_callback(void* target) { session::ThreadSessionInternal::thread_session()->cancel_callback(target); }
|
||||
void cancel_callback_and_wait(void* target) { session::ThreadSessionInternal::thread_session()->cancel_callback_and_wait(target); }
|
||||
void callback(std::function<void()>&& fn) { thread()->callback(std::move(fn)); }
|
||||
void callback(torrent::system::callback_id& id, std::function<void()>&& fn) { thread()->callback(id, std::move(fn)); }
|
||||
void cancel_callback(torrent::system::callback_id& id) { thread()->cancel_callback(id); }
|
||||
|
||||
session::SessionManager* manager() { return session::ThreadSessionInternal::thread_session()->manager(); }
|
||||
std::string session_path() { return session::ThreadSessionInternal::thread_session()->manager()->path(); }
|
||||
session::SessionManager* manager() { return session::ThreadSession::thread_session()->manager(); }
|
||||
std::string session_path() { return manager()->path(); }
|
||||
|
||||
} // namespace session_thread
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ parse_main_options(int argc, char** argv) {
|
||||
optionParser.insert_option('b', [](auto& arg) { rpc::call_command_set_string("network.bind_address.set", arg); });
|
||||
optionParser.insert_option('d', [](auto& arg) { rpc::call_command_set_string("directory.default.set", arg); });
|
||||
optionParser.insert_option('i', [](auto& arg) { rpc::call_command_set_string("ip", arg); });
|
||||
optionParser.insert_option('p', [](auto& arg) { rpc::call_command_set_string("network.port_range.set", arg); });
|
||||
optionParser.insert_option('p', [](auto& arg) { rpc::call_command_set_string("network.listen.port.range.set", arg); });
|
||||
optionParser.insert_option('s', [](auto& arg) { rpc::call_command_set_string("session", arg); });
|
||||
|
||||
optionParser.insert_option('O', [](auto& arg) { rpc::parse_command_single_std(arg); });
|
||||
|
||||
@@ -42,6 +42,7 @@ SignalHandler::set_handler(unsigned int signum, slot_void slot) {
|
||||
throw std::logic_error("SignalHandler::set_handler(...) received an empty slot.");
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = &SignalHandler::caught;
|
||||
@@ -52,6 +53,46 @@ SignalHandler::set_handler(unsigned int signum, slot_void slot) {
|
||||
m_handlers[signum] = slot;
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_block(unsigned int signum) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::set_block(...) received invalid signal value.");
|
||||
|
||||
sigset_t mask;
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signum);
|
||||
|
||||
if (pthread_sigmask(SIG_BLOCK, &mask, NULL) == -1)
|
||||
throw std::logic_error("Could not block signal: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_unblock(unsigned int signum) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::set_unblock(...) received invalid signal value.");
|
||||
|
||||
sigset_t mask;
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signum);
|
||||
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL) == -1)
|
||||
throw std::logic_error("Could not unblock signal: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_sigchild_ignore() {
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sa.sa_flags = SA_NOCLDWAIT | SA_RESTART;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
if (sigaction(SIGCHLD, &sa, NULL) == -1)
|
||||
throw std::logic_error("Could not set sigaction (ignore) for SIGCHLD: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_sigaction_handler(unsigned int signum, handler_slot slot) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
|
||||
+5
-34
@@ -1,37 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_SIGNAL_HANDLER_H
|
||||
#define RTORRENT_SIGNAL_HANDLER_H
|
||||
|
||||
@@ -56,6 +22,11 @@ public:
|
||||
static void set_ignore(unsigned int signum);
|
||||
static void set_handler(unsigned int signum, slot_void slot);
|
||||
|
||||
static void set_block(unsigned int signum);
|
||||
static void set_unblock(unsigned int signum);
|
||||
|
||||
static void set_sigchild_ignore();
|
||||
|
||||
static void set_sigaction_handler(unsigned int signum, handler_slot slot);
|
||||
|
||||
static const char* as_string(unsigned int signum);
|
||||
|
||||
+5
-9
@@ -3,8 +3,6 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/chunk_manager.h>
|
||||
#include <torrent/connection_manager.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/data/file_list.h>
|
||||
@@ -32,10 +30,10 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
Download::Download(core::Download* d) :
|
||||
m_download(d) {
|
||||
Download::Download(core::Download* d)
|
||||
: m_download(d) {
|
||||
|
||||
m_windowDownloadStatus = new WDownloadStatus(d);
|
||||
m_windowDownloadStatus = std::make_unique<WDownloadStatus>(d);
|
||||
m_windowDownloadStatus->set_bottom(true);
|
||||
|
||||
m_uiArray[DISPLAY_MENU] = create_menu();
|
||||
@@ -61,8 +59,6 @@ Download::~Download() {
|
||||
assert(!is_active() && "ui::Download::~Download() called on an active object.");
|
||||
|
||||
std::for_each(m_uiArray, m_uiArray + DISPLAY_MAX_SIZE, [](ElementBase* eb) { delete eb; });
|
||||
|
||||
delete m_windowDownloadStatus;
|
||||
}
|
||||
|
||||
inline ElementBase*
|
||||
@@ -172,7 +168,7 @@ Download::activate(display::Frame* frame, [[maybe_unused]] bool focus) {
|
||||
m_frame = frame;
|
||||
m_frame->initialize_row(2);
|
||||
|
||||
m_frame->frame(1)->initialize_window(m_windowDownloadStatus);
|
||||
m_frame->frame(1)->initialize_window(m_windowDownloadStatus.get());
|
||||
m_windowDownloadStatus->set_active(true);
|
||||
|
||||
activate_display_menu(DISPLAY_PEER_LIST);
|
||||
@@ -250,7 +246,7 @@ Download::activate_display(Display displayType, bool focusDisplay) {
|
||||
// Set title.
|
||||
switch (displayType) {
|
||||
case DISPLAY_MAX_SIZE: break;
|
||||
default: control->ui()->window_title()->set_title(m_download->info()->name()); break;
|
||||
default: control->ui()->window_title()->set_title(m_download->info()->name().str()); break;
|
||||
}
|
||||
|
||||
control->display()->adjust_layout();
|
||||
|
||||
+1
-35
@@ -1,37 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_UI_DOWNLOAD_H
|
||||
#define RTORRENT_UI_DOWNLOAD_H
|
||||
|
||||
@@ -113,7 +79,7 @@ private:
|
||||
|
||||
bool m_focusDisplay{};
|
||||
|
||||
WDownloadStatus* m_windowDownloadStatus;
|
||||
std::unique_ptr<WDownloadStatus> m_windowDownloadStatus;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <sstream>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/utils/log.h>
|
||||
#include <torrent/utils/string_manip.h>
|
||||
|
||||
@@ -176,7 +177,7 @@ DownloadList::activate_display(Display displayType) {
|
||||
switch (displayType) {
|
||||
case DISPLAY_DOWNLOAD_LIST:
|
||||
control->ui()->window_title()->set_title("rTorrent " PACKAGE_VERSION "/" +
|
||||
std::string(torrent::version()) + " - " +
|
||||
std::string(torrent::runtime::version()) + " - " +
|
||||
rpc::call_command_string("session.name"));
|
||||
break;
|
||||
case DISPLAY_LOG:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/system/thread.h>
|
||||
|
||||
#include "display/frame.h"
|
||||
@@ -17,11 +18,16 @@ namespace ui {
|
||||
ElementLogComplete::ElementLogComplete(torrent::log_buffer* l) :
|
||||
m_log(l) {
|
||||
|
||||
unsigned int signal_index = torrent::main_thread::thread()->signal_bitfield()->add_signal(std::bind(&ElementLogComplete::received_update, this));
|
||||
m_log->lock_and_set_update_slot([this]() {
|
||||
if (m_log_updating.exchange(true) == true)
|
||||
return;
|
||||
|
||||
m_log->lock_and_set_update_slot([signal_index]() {
|
||||
torrent::main_thread::thread()->send_event_signal(signal_index, false);
|
||||
});
|
||||
torrent::main_thread::callback([this]() { received_update(); });
|
||||
});
|
||||
}
|
||||
|
||||
ElementLogComplete::~ElementLogComplete() {
|
||||
m_log->lock_and_set_update_slot(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -59,6 +65,8 @@ ElementLogComplete::window() {
|
||||
|
||||
void
|
||||
ElementLogComplete::received_update() {
|
||||
m_log_updating = false;
|
||||
|
||||
if (m_window != NULL)
|
||||
m_window->mark_dirty();
|
||||
}
|
||||
|
||||
@@ -15,12 +15,13 @@ namespace ui {
|
||||
|
||||
class ElementLogComplete : public ElementBase {
|
||||
public:
|
||||
typedef display::WindowLogComplete WLogComplete;
|
||||
using WLogComplete = display::WindowLogComplete;
|
||||
|
||||
ElementLogComplete(torrent::log_buffer* l);
|
||||
~ElementLogComplete() override;
|
||||
|
||||
void activate(display::Frame* frame, bool focus = true);
|
||||
void disable();
|
||||
void activate(display::Frame* frame, bool focus = true) override;
|
||||
void disable() override;
|
||||
|
||||
display::Window* window();
|
||||
|
||||
@@ -30,6 +31,10 @@ private:
|
||||
WLogComplete* m_window{};
|
||||
|
||||
torrent::log_buffer* m_log;
|
||||
|
||||
align_cacheline
|
||||
|
||||
std::atomic<bool> m_log_updating{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -70,4 +70,5 @@ decode_base64(const std::string& input) {
|
||||
}
|
||||
return decodedBytes;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
+3
-1
@@ -1,12 +1,14 @@
|
||||
#ifndef RTORRENT_UTILS_BASE64_H
|
||||
#define RTORRENT_UTILS_BASE64_H
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <vector>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
// TODO: Deprecate.
|
||||
std::string remove_newlines(const std::string& str);
|
||||
std::string decode_base64(const std::string& input);
|
||||
|
||||
|
||||
@@ -21,13 +21,16 @@ FileStatusCache::insert(const std::string& path) {
|
||||
|
||||
std::pair<iterator, bool> result = base_type::insert(value_type(path, file_status()));
|
||||
|
||||
// Return false if the file hasn't been modified since last time. We
|
||||
// use 'equal to' instead of 'greater than' since the file might
|
||||
// have been replaced by another file, and thus should be re-tried.
|
||||
if (!result.second && result.first->second.m_mtime == (uint32_t)fs.modified_time())
|
||||
// Return false if the file hasn't changed since last time. We use
|
||||
// 'equal to' instead of 'greater than' since the file might have
|
||||
// been replaced by another file, and thus should be re-tried.
|
||||
if (!result.second &&
|
||||
result.first->second.m_mtime == (uint32_t)fs.modified_time() &&
|
||||
result.first->second.m_size == (int64_t)fs.size())
|
||||
return false;
|
||||
|
||||
result.first->second.m_flags = 0;
|
||||
result.first->second.m_size = (int64_t)fs.size();
|
||||
result.first->second.m_mtime = fs.modified_time();
|
||||
|
||||
return true;
|
||||
@@ -41,7 +44,9 @@ FileStatusCache::prune() {
|
||||
torrent::utils::FileStat fs;
|
||||
iterator tmp = itr++;
|
||||
|
||||
if (!fs.update(expand_path(tmp->first)) || tmp->second.m_mtime != (uint32_t)fs.modified_time())
|
||||
if (!fs.update(expand_path(tmp->first)) ||
|
||||
tmp->second.m_mtime != (uint32_t)fs.modified_time() ||
|
||||
tmp->second.m_size != (int64_t)fs.size())
|
||||
base_type::erase(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace utils {
|
||||
|
||||
struct file_status {
|
||||
int m_flags;
|
||||
int64_t m_size;
|
||||
uint32_t m_mtime;
|
||||
};
|
||||
|
||||
@@ -32,14 +33,14 @@ public:
|
||||
|
||||
using base_type::erase;
|
||||
|
||||
// Insert and return true if the entry does not exist or the new
|
||||
// file's mtime is more recent.
|
||||
// Insert and return true if the entry does not exist or the file's
|
||||
// status has changed.
|
||||
bool insert(const std::string& path);
|
||||
|
||||
// Add a function for pruning a sorted list of paths.
|
||||
|
||||
// Function for pruning entries that no longer points to a file, or
|
||||
// has a different mtime.
|
||||
// has different status.
|
||||
void prune();
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "utils/waitpid_queue.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
WaitpidQueue::WaitpidQueue() {
|
||||
m_worker = std::async(std::launch::async, [this]() {
|
||||
auto wait_time = 50ms;
|
||||
|
||||
while (true) {
|
||||
if (!m_queue.empty()) {
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
|
||||
while (std::chrono::steady_clock::now() - start_time < wait_time) {
|
||||
if (m_should_shutdown.load(std::memory_order_acquire))
|
||||
return;
|
||||
|
||||
std::this_thread::sleep_for(50ms);
|
||||
|
||||
if (m_wakeup_worker.load(std::memory_order_acquire))
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
m_wakeup_worker.wait(false, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
// Adds a small delay to allow new processes to finish if they're quickly spawned and
|
||||
// terminated.
|
||||
std::this_thread::sleep_for(50ms);
|
||||
|
||||
std::set<pid_t> queue;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
|
||||
if (m_should_shutdown)
|
||||
return;
|
||||
|
||||
if (m_queue.empty())
|
||||
throw torrent::internal_error("WaitpidQueue worker thread woke up but queue is empty.");
|
||||
|
||||
queue = m_queue;
|
||||
|
||||
m_wakeup_worker.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
wait_time = std::min(10 * 1000ms, wait_time * 2);
|
||||
|
||||
for (auto pid : queue) {
|
||||
if (::waitpid(pid, nullptr, WNOHANG) == 0)
|
||||
continue;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
|
||||
if (m_queue.erase(pid) != 1)
|
||||
throw torrent::internal_error("WaitpidQueue worker thread could not find pid in queue.");
|
||||
}
|
||||
|
||||
wait_time = std::max(50ms, wait_time / 2);
|
||||
|
||||
m_remaining.fetch_sub(1, std::memory_order_release);
|
||||
m_remaining.notify_all();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// We don't wait for the worker thread to finish as waitpid isn't needed to be called on shutdown.
|
||||
WaitpidQueue::~WaitpidQueue() {
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
m_should_shutdown = true;
|
||||
}
|
||||
|
||||
m_wakeup_worker.store(true, std::memory_order_release);
|
||||
m_wakeup_worker.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
WaitpidQueue::close_pid(pid_t pid) {
|
||||
if (pid < 0)
|
||||
throw torrent::internal_error("WaitpidQueue::close_pid() called with invalid pid.");
|
||||
|
||||
m_remaining.fetch_add(1, std::memory_order_acquire);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
m_queue.insert(pid);
|
||||
}
|
||||
|
||||
m_wakeup_worker.store(true, std::memory_order_release);
|
||||
m_wakeup_worker.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
WaitpidQueue::wait_for(uint32_t max_remaining) {
|
||||
while (m_remaining.load(std::memory_order_acquire) > max_remaining)
|
||||
m_remaining.wait(max_remaining, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
} // namespace torrent::utils
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef RTORRENT_UTILS_WAITPID_QUEUE_H
|
||||
#define RTORRENT_UTILS_WAITPID_QUEUE_H
|
||||
|
||||
#include <future>
|
||||
#include <set>
|
||||
#include <torrent/system/common.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class WaitpidQueue {
|
||||
public:
|
||||
WaitpidQueue();
|
||||
~WaitpidQueue();
|
||||
|
||||
uint32_t size() const;
|
||||
|
||||
void close_pid(int pid);
|
||||
|
||||
void wait_for(uint32_t max_remaining);
|
||||
|
||||
private:
|
||||
WaitpidQueue(const WaitpidQueue&) = delete;
|
||||
WaitpidQueue& operator=(const WaitpidQueue&) = delete;
|
||||
|
||||
std::future<void> m_worker;
|
||||
|
||||
align_cacheline
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::set<pid_t> m_queue;
|
||||
|
||||
align_cacheline
|
||||
|
||||
std::atomic<bool> m_wakeup_worker{};
|
||||
std::atomic<bool> m_should_shutdown{};
|
||||
|
||||
std::atomic<uint32_t> m_remaining{};
|
||||
};
|
||||
|
||||
inline uint32_t WaitpidQueue::size() const { return m_remaining.load(std::memory_order_acquire); }
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "utils/watch_ready_queue.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <torrent/utils/file_stat.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "rpc/rpc_manager.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
namespace {
|
||||
|
||||
auto compare_next_time = [](const auto* lhs, const auto* rhs) {
|
||||
return lhs->next_time > rhs->next_time;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
WatchReadyQueue::WatchReadyQueue() {
|
||||
m_task_process.slot() = [this]() { process(); };
|
||||
}
|
||||
|
||||
WatchReadyQueue::~WatchReadyQueue() {
|
||||
torrent::this_thread::scheduler()->erase(&m_task_process);
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::push(const std::string& command, const std::string& path) {
|
||||
if (!m_active)
|
||||
return;
|
||||
|
||||
auto result = m_entries.emplace(path, Entry());
|
||||
auto& entry = result.first->second;
|
||||
|
||||
if (result.second) {
|
||||
entry.path = path;
|
||||
entry.first_seen = torrent::this_thread::cached_time();
|
||||
}
|
||||
|
||||
entry.command = command;
|
||||
entry.last_changed = torrent::this_thread::cached_time();
|
||||
update_status(&entry);
|
||||
|
||||
if (result.second) {
|
||||
update_next_time(&entry);
|
||||
push_entry(&entry);
|
||||
} else {
|
||||
update_entry(&entry);
|
||||
}
|
||||
|
||||
schedule();
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::shutdown() {
|
||||
m_active = false;
|
||||
m_entries.clear();
|
||||
m_entry_queue.clear();
|
||||
torrent::this_thread::scheduler()->erase(&m_task_process);
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::push_entry(Entry* entry) {
|
||||
m_entry_queue.push_back(entry);
|
||||
std::push_heap(m_entry_queue.begin(), m_entry_queue.end(), compare_next_time);
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::update_entry(Entry* entry) {
|
||||
update_next_time(entry);
|
||||
std::make_heap(m_entry_queue.begin(), m_entry_queue.end(), compare_next_time);
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::update_next_time(Entry* entry) {
|
||||
if (entry->regular && entry->size > 0) {
|
||||
entry->next_time = entry->last_changed + quiet_time;
|
||||
return;
|
||||
}
|
||||
|
||||
entry->next_time = std::min(torrent::this_thread::cached_time() + retry_time,
|
||||
entry->first_seen + stale_time);
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::update_status(Entry* entry) {
|
||||
torrent::utils::FileStat fs;
|
||||
bool regular = false;
|
||||
int64_t size = -1;
|
||||
time_t mtime = 0;
|
||||
|
||||
if (fs.update(expand_path(entry->path))) {
|
||||
regular = fs.is_regular();
|
||||
size = fs.size();
|
||||
mtime = fs.modified_time();
|
||||
}
|
||||
|
||||
if (entry->regular != regular || entry->size != size || entry->mtime != mtime) {
|
||||
entry->regular = regular;
|
||||
entry->size = size;
|
||||
entry->mtime = mtime;
|
||||
entry->last_changed = torrent::this_thread::cached_time();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::process() {
|
||||
ready_list ready;
|
||||
|
||||
while (!m_entry_queue.empty() && m_entry_queue.front()->next_time <= torrent::this_thread::cached_time()) {
|
||||
std::pop_heap(m_entry_queue.begin(), m_entry_queue.end(), compare_next_time);
|
||||
Entry* entry = m_entry_queue.back();
|
||||
m_entry_queue.pop_back();
|
||||
|
||||
update_status(entry);
|
||||
|
||||
bool unchanged_entry = torrent::this_thread::cached_time() - entry->last_changed >= quiet_time;
|
||||
bool stale_entry = torrent::this_thread::cached_time() - entry->first_seen >= stale_time;
|
||||
bool nonempty_regular = entry->regular && entry->size > 0;
|
||||
|
||||
if (nonempty_regular && unchanged_entry) {
|
||||
ready.emplace_back(entry->command, entry->path);
|
||||
std::string path = entry->path;
|
||||
m_entries.erase(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nonempty_regular && stale_entry) {
|
||||
std::string path = entry->path;
|
||||
lt_log_print(torrent::LOG_SYSTEM, "system: Dropped unready watch file after timeout: \"%s\"", path.c_str());
|
||||
m_entries.erase(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
update_next_time(entry);
|
||||
push_entry(entry);
|
||||
}
|
||||
|
||||
schedule();
|
||||
|
||||
for (const auto& item : ready)
|
||||
rpc::commands.call_catch(item.first.c_str(), rpc::make_target(), item.second);
|
||||
}
|
||||
|
||||
void
|
||||
WatchReadyQueue::schedule() {
|
||||
if (m_entry_queue.empty()) {
|
||||
torrent::this_thread::scheduler()->erase(&m_task_process);
|
||||
return;
|
||||
}
|
||||
|
||||
torrent::this_thread::scheduler()->update_wait_until(&m_task_process, m_entry_queue.front()->next_time);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef RTORRENT_UTILS_WATCH_READY_QUEUE_H
|
||||
#define RTORRENT_UTILS_WATCH_READY_QUEUE_H
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <torrent/system/scheduler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class WatchReadyQueue {
|
||||
public:
|
||||
WatchReadyQueue();
|
||||
~WatchReadyQueue();
|
||||
|
||||
void push(const std::string& command, const std::string& path);
|
||||
void shutdown();
|
||||
bool empty() const { return m_entries.empty(); }
|
||||
|
||||
private:
|
||||
using time_type = std::chrono::microseconds;
|
||||
|
||||
static constexpr auto quiet_time = std::chrono::milliseconds(500);
|
||||
static constexpr auto retry_time = std::chrono::milliseconds(250);
|
||||
static constexpr auto stale_time = std::chrono::seconds(10);
|
||||
|
||||
using ready_list = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
struct Entry {
|
||||
std::string command;
|
||||
std::string path;
|
||||
bool regular{};
|
||||
int64_t size{-1};
|
||||
time_t mtime{};
|
||||
time_type first_seen{};
|
||||
time_type last_changed{};
|
||||
time_type next_time{};
|
||||
};
|
||||
|
||||
void process();
|
||||
void push_entry(Entry* entry);
|
||||
void update_entry(Entry* entry);
|
||||
void update_next_time(Entry* entry);
|
||||
void update_status(Entry* entry);
|
||||
void schedule();
|
||||
|
||||
std::map<std::string, Entry> m_entries;
|
||||
std::vector<Entry*> m_entry_queue;
|
||||
|
||||
bool m_active{true};
|
||||
|
||||
torrent::system::SchedulerEntry m_task_process;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user