Compare commits
33 Commits
Author | SHA1 | Date |
---|---|---|
Avril | 3267151615 | 2 years ago |
Avril | bfaff6067a | 4 years ago |
Avril | 5c784482f6 | 4 years ago |
Avril | bdf61340db | 4 years ago |
Avril | 7635ff9d52 | 4 years ago |
Avril | acf2ac605e | 4 years ago |
Avril | d1251a592c | 4 years ago |
Avril | 75730cbe0f | 4 years ago |
Avril | 5dc10547d5 | 4 years ago |
Avril | 6453392758 | 4 years ago |
Avril | a6fc26a053 | 4 years ago |
Avril | 3b4dc663fa | 4 years ago |
Avril | d8404f65ed | 4 years ago |
Avril | 5280c622c9 | 4 years ago |
Avril | 1c509031d6 | 4 years ago |
Avril | 107b34bcbd | 4 years ago |
Avril | 684a6f6aa0 | 4 years ago |
Avril | 8996b0bb7b | 4 years ago |
Avril | 633b4351c2 | 4 years ago |
Avril | bcaac2b2e3 | 4 years ago |
Avril | 59dcecded3 | 4 years ago |
Avril | 4e1e38a0fd | 4 years ago |
Avril | 5ba673e64f | 4 years ago |
Avril | cb163a14e9 | 4 years ago |
Avril | 34a62da8ba | 4 years ago |
Avril | 460d2b0081 | 4 years ago |
Avril | 5f2e3a5b5b | 4 years ago |
Avril | 7c67a4decc | 4 years ago |
Avril | 4227a12521 | 4 years ago |
Avril | 9e25c7cfa3 | 4 years ago |
Avril | b488194fd3 | 4 years ago |
Avril | a6b6ee9a42 | 4 years ago |
Avril | 13dbe37d2b | 4 years ago |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
||||
Disallow exact same map input buffers by keeping hashes of input buffers.
|
@ -0,0 +1,26 @@
|
||||
|
||||
extern crate rustc_version;
|
||||
use rustc_version::{version, version_meta, Channel};
|
||||
|
||||
fn main() {
|
||||
// Assert we haven't travelled back in time
|
||||
assert!(version().unwrap().major >= 1);
|
||||
|
||||
// Set cfg flags depending on release channel
|
||||
match version_meta().unwrap().channel {
|
||||
Channel::Stable => {
|
||||
println!("cargo:rustc-cfg=stable");
|
||||
}
|
||||
Channel::Beta => {
|
||||
println!("cargo:rustc-cfg=beta");
|
||||
}
|
||||
Channel::Nightly => {
|
||||
println!("cargo:rustc-cfg=nightly");
|
||||
}
|
||||
Channel::Dev => {
|
||||
println!("cargo:rustc-cfg=dev");
|
||||
}
|
||||
}
|
||||
|
||||
//println!("cargo:rustc-link-lib=static=bz2"); // TODO: Make this conditional for `compress-chain`
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
# Copyright 2017-2020 Gentoo Authors
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
|
||||
# Auto-Generated by cargo-ebuild 0.3.1
|
||||
|
||||
EAPI=7
|
||||
|
||||
CRATES="
|
||||
aho-corasick-0.7.13
|
||||
arc-swap-0.4.7
|
||||
async-compression-0.3.5
|
||||
atty-0.2.14
|
||||
autocfg-0.1.7
|
||||
autocfg-1.0.1
|
||||
base64-0.12.3
|
||||
bitflags-1.2.1
|
||||
block-buffer-0.7.3
|
||||
block-buffer-0.9.0
|
||||
block-padding-0.1.5
|
||||
buf_redux-0.8.4
|
||||
byte-tools-0.3.1
|
||||
byteorder-1.3.4
|
||||
bytes-0.5.6
|
||||
bzip2-0.3.3
|
||||
bzip2-sys-0.1.9+1.0.8
|
||||
cc-1.0.60
|
||||
cfg-if-0.1.10
|
||||
cfg-if-1.0.0
|
||||
cloudabi-0.0.3
|
||||
cpuid-bool-0.1.2
|
||||
digest-0.8.1
|
||||
digest-0.9.0
|
||||
dtoa-0.4.6
|
||||
either-1.6.1
|
||||
env_logger-0.7.1
|
||||
fake-simd-0.1.2
|
||||
fixedbitset-0.2.0
|
||||
fnv-1.0.7
|
||||
fuchsia-cprng-0.1.1
|
||||
fuchsia-zircon-0.3.3
|
||||
fuchsia-zircon-sys-0.3.3
|
||||
futures-0.3.6
|
||||
futures-channel-0.3.6
|
||||
futures-core-0.3.6
|
||||
futures-executor-0.3.6
|
||||
futures-io-0.3.6
|
||||
futures-macro-0.3.6
|
||||
futures-sink-0.3.6
|
||||
futures-task-0.3.6
|
||||
futures-util-0.3.6
|
||||
generic-array-0.12.3
|
||||
generic-array-0.14.4
|
||||
getopts-0.2.21
|
||||
getrandom-0.1.15
|
||||
h2-0.2.6
|
||||
half-1.6.0
|
||||
hashbrown-0.9.1
|
||||
headers-0.3.2
|
||||
headers-core-0.2.0
|
||||
hermit-abi-0.1.17
|
||||
http-0.2.1
|
||||
http-body-0.3.1
|
||||
httparse-1.3.4
|
||||
httpdate-0.3.2
|
||||
humantime-1.3.0
|
||||
hyper-0.13.8
|
||||
idna-0.2.0
|
||||
indexmap-1.6.0
|
||||
input_buffer-0.3.1
|
||||
iovec-0.1.4
|
||||
itertools-0.9.0
|
||||
itoa-0.4.6
|
||||
kernel32-sys-0.2.2
|
||||
lazy_static-1.4.0
|
||||
libc-0.2.79
|
||||
linked-hash-map-0.5.3
|
||||
log-0.4.11
|
||||
markov-1.1.0
|
||||
matches-0.1.8
|
||||
memchr-2.3.3
|
||||
mime-0.3.16
|
||||
mime_guess-2.0.3
|
||||
mio-0.6.22
|
||||
mio-named-pipes-0.1.7
|
||||
mio-uds-0.6.8
|
||||
miow-0.2.1
|
||||
miow-0.3.5
|
||||
multipart-0.17.0
|
||||
net2-0.2.35
|
||||
num_cpus-1.13.0
|
||||
once_cell-1.4.1
|
||||
opaque-debug-0.2.3
|
||||
opaque-debug-0.3.0
|
||||
percent-encoding-2.1.0
|
||||
petgraph-0.5.1
|
||||
pin-project-0.4.26
|
||||
pin-project-internal-0.4.26
|
||||
pin-project-lite-0.1.10
|
||||
pin-utils-0.1.0
|
||||
pkg-config-0.3.18
|
||||
ppv-lite86-0.2.9
|
||||
pretty_env_logger-0.4.0
|
||||
proc-macro-hack-0.5.18
|
||||
proc-macro-nested-0.1.6
|
||||
proc-macro2-1.0.24
|
||||
quick-error-1.2.3
|
||||
quote-1.0.7
|
||||
rand-0.6.5
|
||||
rand-0.7.3
|
||||
rand_chacha-0.1.1
|
||||
rand_chacha-0.2.2
|
||||
rand_core-0.3.1
|
||||
rand_core-0.4.2
|
||||
rand_core-0.5.1
|
||||
rand_hc-0.1.0
|
||||
rand_hc-0.2.0
|
||||
rand_isaac-0.1.1
|
||||
rand_jitter-0.1.4
|
||||
rand_os-0.1.3
|
||||
rand_pcg-0.1.2
|
||||
rand_xorshift-0.1.1
|
||||
rdrand-0.4.0
|
||||
redox_syscall-0.1.57
|
||||
regex-1.3.9
|
||||
regex-syntax-0.6.18
|
||||
remove_dir_all-0.5.3
|
||||
rustc_version-0.2.3
|
||||
ryu-1.0.5
|
||||
safemem-0.3.3
|
||||
scoped-tls-1.0.0
|
||||
semver-0.9.0
|
||||
semver-parser-0.7.0
|
||||
serde-1.0.116
|
||||
serde_cbor-0.11.1
|
||||
serde_derive-1.0.116
|
||||
serde_json-1.0.58
|
||||
serde_urlencoded-0.6.1
|
||||
serde_yaml-0.8.13
|
||||
sha-1-0.8.2
|
||||
sha-1-0.9.1
|
||||
signal-hook-registry-1.2.1
|
||||
slab-0.4.2
|
||||
smallmap-1.1.5
|
||||
socket2-0.3.15
|
||||
syn-1.0.42
|
||||
tempfile-3.1.0
|
||||
termcolor-1.1.0
|
||||
thread_local-1.0.1
|
||||
time-0.1.44
|
||||
tinyvec-0.3.4
|
||||
tokio-0.2.22
|
||||
tokio-macros-0.2.5
|
||||
tokio-tungstenite-0.11.0
|
||||
tokio-util-0.3.1
|
||||
toml-0.5.6
|
||||
tower-service-0.3.0
|
||||
tracing-0.1.21
|
||||
tracing-core-0.1.17
|
||||
tracing-futures-0.2.4
|
||||
try-lock-0.2.3
|
||||
tungstenite-0.11.1
|
||||
twoway-0.1.8
|
||||
typenum-1.12.0
|
||||
unicase-2.6.0
|
||||
unicode-bidi-0.3.4
|
||||
unicode-normalization-0.1.13
|
||||
unicode-width-0.1.8
|
||||
unicode-xid-0.2.1
|
||||
url-2.1.1
|
||||
urlencoding-1.1.1
|
||||
utf-8-0.7.5
|
||||
version_check-0.9.2
|
||||
want-0.3.0
|
||||
warp-0.2.5
|
||||
wasi-0.10.0+wasi-snapshot-preview1
|
||||
wasi-0.9.0+wasi-snapshot-preview1
|
||||
winapi-0.2.8
|
||||
winapi-0.3.9
|
||||
winapi-build-0.1.1
|
||||
winapi-i686-pc-windows-gnu-0.4.0
|
||||
winapi-util-0.1.5
|
||||
winapi-x86_64-pc-windows-gnu-0.4.0
|
||||
ws2_32-sys-0.2.1
|
||||
yaml-rust-0.4.4
|
||||
"
|
||||
|
||||
inherit cargo
|
||||
|
||||
DESCRIPTION="Generate string of text from Markov chain fed by stdin"
|
||||
# Double check the homepage as the cargo_metadata crate
|
||||
# does not provide this value so instead repository is used
|
||||
HOMEPAGE="https://flanchan.moe/markov/"
|
||||
SRC_URI="$(cargo_crate_uris ${CRATES}) https://git.flanchan.moe/attachments/cf0b9095-2403-465b-b3aa-61b121134c84 -> markov-0.7.1.crate"
|
||||
RESTRICT="mirror"
|
||||
# License set may be more restrictive as OR is not respected
|
||||
# use cargo-license for a more accurate license picture
|
||||
LICENSE="GPL-3+"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64"
|
||||
IUSE="+compress-chain +split-newlines +api split-sentance always-aggregate hog-buffer"
|
||||
|
||||
DEPEND="compress-chain? ( app-arch/bzip2 )"
|
||||
RDEPEND=""
|
||||
|
||||
src_configure() {
|
||||
local myfeatures=(
|
||||
$(usev compress-chain)
|
||||
$(usev split-newlines)
|
||||
$(usev api)
|
||||
$(usev split-sentance)
|
||||
$(usev always-aggregate)
|
||||
$(usev hog-buffer)
|
||||
)
|
||||
#TODO: This hack slows compilation down I think, but without it ld fails so... We should add cargo buildscript to do this instead
|
||||
use compress-chain && export RUSTFLAGS="${RUSTFLAGS} -ldylib=bz2"
|
||||
cargo_src_configure --no-default-features
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
# Copyright 2017-2020 Gentoo Authors
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
|
||||
# Auto-Generated by cargo-ebuild 0.3.1
|
||||
|
||||
EAPI=7
|
||||
CRATES="
|
||||
aho-corasick-0.7.13
|
||||
arc-swap-0.4.7
|
||||
async-compression-0.3.5
|
||||
atty-0.2.14
|
||||
autocfg-0.1.7
|
||||
autocfg-1.0.1
|
||||
base64-0.12.3
|
||||
bitflags-1.2.1
|
||||
block-buffer-0.7.3
|
||||
block-buffer-0.9.0
|
||||
block-padding-0.1.5
|
||||
buf_redux-0.8.4
|
||||
byte-tools-0.3.1
|
||||
byteorder-1.3.4
|
||||
bytes-0.5.6
|
||||
bzip2-0.3.3
|
||||
bzip2-sys-0.1.9+1.0.8
|
||||
cc-1.0.60
|
||||
cfg-if-0.1.10
|
||||
cfg-if-1.0.0
|
||||
cloudabi-0.0.3
|
||||
cpuid-bool-0.1.2
|
||||
digest-0.8.1
|
||||
digest-0.9.0
|
||||
dtoa-0.4.6
|
||||
either-1.6.1
|
||||
env_logger-0.7.1
|
||||
fake-simd-0.1.2
|
||||
fixedbitset-0.2.0
|
||||
fnv-1.0.7
|
||||
fuchsia-cprng-0.1.1
|
||||
fuchsia-zircon-0.3.3
|
||||
fuchsia-zircon-sys-0.3.3
|
||||
futures-0.3.6
|
||||
futures-channel-0.3.6
|
||||
futures-core-0.3.6
|
||||
futures-executor-0.3.6
|
||||
futures-io-0.3.6
|
||||
futures-macro-0.3.6
|
||||
futures-sink-0.3.6
|
||||
futures-task-0.3.6
|
||||
futures-util-0.3.6
|
||||
generic-array-0.12.3
|
||||
generic-array-0.14.4
|
||||
getopts-0.2.21
|
||||
getrandom-0.1.15
|
||||
h2-0.2.6
|
||||
half-1.6.0
|
||||
hashbrown-0.9.1
|
||||
headers-0.3.2
|
||||
headers-core-0.2.0
|
||||
hermit-abi-0.1.17
|
||||
http-0.2.1
|
||||
http-body-0.3.1
|
||||
httparse-1.3.4
|
||||
httpdate-0.3.2
|
||||
humantime-1.3.0
|
||||
hyper-0.13.8
|
||||
idna-0.2.0
|
||||
indexmap-1.6.0
|
||||
input_buffer-0.3.1
|
||||
iovec-0.1.4
|
||||
itertools-0.9.0
|
||||
itoa-0.4.6
|
||||
kernel32-sys-0.2.2
|
||||
lazy_static-1.4.0
|
||||
libc-0.2.79
|
||||
linked-hash-map-0.5.3
|
||||
log-0.4.11
|
||||
markov-1.1.0
|
||||
matches-0.1.8
|
||||
memchr-2.3.3
|
||||
mime-0.3.16
|
||||
mime_guess-2.0.3
|
||||
mio-0.6.22
|
||||
mio-named-pipes-0.1.7
|
||||
mio-uds-0.6.8
|
||||
miow-0.2.1
|
||||
miow-0.3.5
|
||||
multipart-0.17.0
|
||||
net2-0.2.35
|
||||
num_cpus-1.13.0
|
||||
once_cell-1.4.1
|
||||
opaque-debug-0.2.3
|
||||
opaque-debug-0.3.0
|
||||
percent-encoding-2.1.0
|
||||
petgraph-0.5.1
|
||||
pin-project-0.4.26
|
||||
pin-project-internal-0.4.26
|
||||
pin-project-lite-0.1.10
|
||||
pin-utils-0.1.0
|
||||
pkg-config-0.3.18
|
||||
ppv-lite86-0.2.9
|
||||
pretty_env_logger-0.4.0
|
||||
proc-macro-hack-0.5.18
|
||||
proc-macro-nested-0.1.6
|
||||
proc-macro2-1.0.24
|
||||
quick-error-1.2.3
|
||||
quote-1.0.7
|
||||
rand-0.6.5
|
||||
rand-0.7.3
|
||||
rand_chacha-0.1.1
|
||||
rand_chacha-0.2.2
|
||||
rand_core-0.3.1
|
||||
rand_core-0.4.2
|
||||
rand_core-0.5.1
|
||||
rand_hc-0.1.0
|
||||
rand_hc-0.2.0
|
||||
rand_isaac-0.1.1
|
||||
rand_jitter-0.1.4
|
||||
rand_os-0.1.3
|
||||
rand_pcg-0.1.2
|
||||
rand_xorshift-0.1.1
|
||||
rdrand-0.4.0
|
||||
redox_syscall-0.1.57
|
||||
regex-1.3.9
|
||||
regex-syntax-0.6.18
|
||||
remove_dir_all-0.5.3
|
||||
rustc_version-0.2.3
|
||||
ryu-1.0.5
|
||||
safemem-0.3.3
|
||||
scoped-tls-1.0.0
|
||||
semver-0.9.0
|
||||
semver-parser-0.7.0
|
||||
serde-1.0.116
|
||||
serde_cbor-0.11.1
|
||||
serde_derive-1.0.116
|
||||
serde_json-1.0.58
|
||||
serde_urlencoded-0.6.1
|
||||
serde_yaml-0.8.13
|
||||
sha-1-0.8.2
|
||||
sha-1-0.9.1
|
||||
signal-hook-registry-1.2.1
|
||||
slab-0.4.2
|
||||
smallmap-1.1.5
|
||||
socket2-0.3.15
|
||||
syn-1.0.42
|
||||
tempfile-3.1.0
|
||||
termcolor-1.1.0
|
||||
thread_local-1.0.1
|
||||
time-0.1.44
|
||||
tinyvec-0.3.4
|
||||
tokio-0.2.22
|
||||
tokio-macros-0.2.5
|
||||
tokio-tungstenite-0.11.0
|
||||
tokio-util-0.3.1
|
||||
toml-0.5.6
|
||||
tower-service-0.3.0
|
||||
tracing-0.1.21
|
||||
tracing-core-0.1.17
|
||||
tracing-futures-0.2.4
|
||||
try-lock-0.2.3
|
||||
tungstenite-0.11.1
|
||||
twoway-0.1.8
|
||||
typenum-1.12.0
|
||||
unicase-2.6.0
|
||||
unicode-bidi-0.3.4
|
||||
unicode-normalization-0.1.13
|
||||
unicode-width-0.1.8
|
||||
unicode-xid-0.2.1
|
||||
url-2.1.1
|
||||
urlencoding-1.1.1
|
||||
utf-8-0.7.5
|
||||
version_check-0.9.2
|
||||
want-0.3.0
|
||||
warp-0.2.5
|
||||
wasi-0.10.0+wasi-snapshot-preview1
|
||||
wasi-0.9.0+wasi-snapshot-preview1
|
||||
winapi-0.2.8
|
||||
winapi-0.3.9
|
||||
winapi-build-0.1.1
|
||||
winapi-i686-pc-windows-gnu-0.4.0
|
||||
winapi-util-0.1.5
|
||||
winapi-x86_64-pc-windows-gnu-0.4.0
|
||||
ws2_32-sys-0.2.1
|
||||
yaml-rust-0.4.4
|
||||
"
|
||||
|
||||
inherit cargo
|
||||
|
||||
DESCRIPTION="Generate string of text from Markov chain fed by stdin"
|
||||
# Double check the homepage as the cargo_metadata crate
|
||||
# does not provide this value so instead repository is used
|
||||
HOMEPAGE="https://flanchan.moe/markov/"
|
||||
SRC_URI="$(cargo_crate_uris ${CRATES}) https://git.flanchan.moe/attachments/c6f37bfc-afd8-462f-807f-ab9f95197680 -> markov-0.8.1.crate"
|
||||
RESTRICT="mirror"
|
||||
# License set may be more restrictive as OR is not respected
|
||||
# use cargo-license for a more accurate license picture
|
||||
LICENSE="GPL-3+"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64"
|
||||
IUSE="+compress-chain +split-newlines +api split-sentance feed-sentance always-aggregate hog-buffer"
|
||||
|
||||
DEPEND="compress-chain? ( app-arch/bzip2 )"
|
||||
RDEPEND=""
|
||||
|
||||
src_configure() {
|
||||
local myfeatures=(
|
||||
$(usev compress-chain)
|
||||
$(usev split-newlines)
|
||||
$(usev api)
|
||||
$(usev split-sentance)
|
||||
$(usev feed-sentance)
|
||||
$(usev always-aggregate)
|
||||
$(usev hog-buffer)
|
||||
)
|
||||
#TODO: This hack slows compilation down I think, but without it ld fails so... We should add cargo buildscript to do this instead
|
||||
use compress-chain && export RUSTFLAGS="${RUSTFLAGS} -ldylib=bz2"
|
||||
cargo_src_configure --no-default-features
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
|
||||
<pkgmetadata>
|
||||
<maintainer type="person">
|
||||
<email>flanchan@cumallover.me</email>
|
||||
</maintainer>
|
||||
<use>
|
||||
<flag name="compress-chain">Compress chain when saving/loading</flag>
|
||||
<flag name="split-newlines">Treat each new line as a new set to feed</flag>
|
||||
<flag name="api">Enable /api route</flag>
|
||||
<flag name="feed-sentance">Further split buffers by sentance, feeding a new one for each.</flag>
|
||||
<flag name="split-sentance">Split by sentance as well as word boundaries</flag>
|
||||
<flag name="always-aggregate">Always operate on aggregated request body (can speed up writes at the cost of memory)</flag>
|
||||
<flag name="hog-buffer">Acquire chain mutex write lock while streaming body (can speed up writes, but can also allow for DoS)</flag></use>
|
||||
</pkgmetadata>
|
@ -0,0 +1,203 @@
|
||||
# Copyright 2017-2020 Gentoo Authors
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
|
||||
# Auto-Generated by cargo-ebuild 0.3.1
|
||||
|
||||
EAPI=7
|
||||
|
||||
CRATES="
|
||||
aho-corasick-0.7.13
|
||||
arc-swap-0.4.7
|
||||
async-compression-0.3.5
|
||||
atty-0.2.14
|
||||
autocfg-0.1.7
|
||||
autocfg-1.0.1
|
||||
base64-0.12.3
|
||||
bitflags-1.2.1
|
||||
block-buffer-0.7.3
|
||||
block-buffer-0.9.0
|
||||
block-padding-0.1.5
|
||||
buf_redux-0.8.4
|
||||
byte-tools-0.3.1
|
||||
byteorder-1.3.4
|
||||
bytes-0.5.6
|
||||
bzip2-0.3.3
|
||||
bzip2-sys-0.1.9+1.0.8
|
||||
cc-1.0.60
|
||||
cfg-if-0.1.10
|
||||
cfg-if-1.0.0
|
||||
cloudabi-0.0.3
|
||||
cpuid-bool-0.1.2
|
||||
digest-0.8.1
|
||||
digest-0.9.0
|
||||
dtoa-0.4.6
|
||||
either-1.6.1
|
||||
env_logger-0.7.1
|
||||
fake-simd-0.1.2
|
||||
fixedbitset-0.2.0
|
||||
fnv-1.0.7
|
||||
fuchsia-cprng-0.1.1
|
||||
fuchsia-zircon-0.3.3
|
||||
fuchsia-zircon-sys-0.3.3
|
||||
futures-0.3.6
|
||||
futures-channel-0.3.6
|
||||
futures-core-0.3.6
|
||||
futures-executor-0.3.6
|
||||
futures-io-0.3.6
|
||||
futures-macro-0.3.6
|
||||
futures-sink-0.3.6
|
||||
futures-task-0.3.6
|
||||
futures-util-0.3.6
|
||||
generic-array-0.12.3
|
||||
generic-array-0.14.4
|
||||
getopts-0.2.21
|
||||
getrandom-0.1.15
|
||||
h2-0.2.6
|
||||
half-1.6.0
|
||||
hashbrown-0.9.1
|
||||
headers-0.3.2
|
||||
headers-core-0.2.0
|
||||
hermit-abi-0.1.17
|
||||
http-0.2.1
|
||||
http-body-0.3.1
|
||||
httparse-1.3.4
|
||||
httpdate-0.3.2
|
||||
humantime-1.3.0
|
||||
hyper-0.13.8
|
||||
idna-0.2.0
|
||||
indexmap-1.6.0
|
||||
input_buffer-0.3.1
|
||||
iovec-0.1.4
|
||||
itertools-0.9.0
|
||||
itoa-0.4.6
|
||||
kernel32-sys-0.2.2
|
||||
lazy_static-1.4.0
|
||||
libc-0.2.79
|
||||
linked-hash-map-0.5.3
|
||||
log-0.4.11
|
||||
markov-1.1.0
|
||||
matches-0.1.8
|
||||
memchr-2.3.3
|
||||
mime-0.3.16
|
||||
mime_guess-2.0.3
|
||||
mio-0.6.22
|
||||
mio-named-pipes-0.1.7
|
||||
mio-uds-0.6.8
|
||||
miow-0.2.1
|
||||
miow-0.3.5
|
||||
multipart-0.17.0
|
||||
net2-0.2.35
|
||||
num_cpus-1.13.0
|
||||
once_cell-1.4.1
|
||||
opaque-debug-0.2.3
|
||||
opaque-debug-0.3.0
|
||||
percent-encoding-2.1.0
|
||||
petgraph-0.5.1
|
||||
pin-project-0.4.26
|
||||
pin-project-internal-0.4.26
|
||||
pin-project-lite-0.1.10
|
||||
pin-utils-0.1.0
|
||||
pkg-config-0.3.18
|
||||
ppv-lite86-0.2.9
|
||||
pretty_env_logger-0.4.0
|
||||
proc-macro-hack-0.5.18
|
||||
proc-macro-nested-0.1.6
|
||||
proc-macro2-1.0.24
|
||||
quick-error-1.2.3
|
||||
quote-1.0.7
|
||||
rand-0.6.5
|
||||
rand-0.7.3
|
||||
rand_chacha-0.1.1
|
||||
rand_chacha-0.2.2
|
||||
rand_core-0.3.1
|
||||
rand_core-0.4.2
|
||||
rand_core-0.5.1
|
||||
rand_hc-0.1.0
|
||||
rand_hc-0.2.0
|
||||
rand_isaac-0.1.1
|
||||
rand_jitter-0.1.4
|
||||
rand_os-0.1.3
|
||||
rand_pcg-0.1.2
|
||||
rand_xorshift-0.1.1
|
||||
rdrand-0.4.0
|
||||
redox_syscall-0.1.57
|
||||
regex-1.3.9
|
||||
regex-syntax-0.6.18
|
||||
remove_dir_all-0.5.3
|
||||
rustc_version-0.2.3
|
||||
ryu-1.0.5
|
||||
safemem-0.3.3
|
||||
scoped-tls-1.0.0
|
||||
semver-0.9.0
|
||||
semver-parser-0.7.0
|
||||
serde-1.0.116
|
||||
serde_cbor-0.11.1
|
||||
serde_derive-1.0.116
|
||||
serde_json-1.0.58
|
||||
serde_urlencoded-0.6.1
|
||||
serde_yaml-0.8.13
|
||||
sha-1-0.8.2
|
||||
sha-1-0.9.1
|
||||
signal-hook-registry-1.2.1
|
||||
slab-0.4.2
|
||||
smallmap-1.1.5
|
||||
socket2-0.3.15
|
||||
syn-1.0.42
|
||||
tempfile-3.1.0
|
||||
termcolor-1.1.0
|
||||
thread_local-1.0.1
|
||||
time-0.1.44
|
||||
tinyvec-0.3.4
|
||||
tokio-0.2.22
|
||||
tokio-macros-0.2.5
|
||||
tokio-tungstenite-0.11.0
|
||||
tokio-util-0.3.1
|
||||
toml-0.5.6
|
||||
tower-service-0.3.0
|
||||
tracing-0.1.21
|
||||
tracing-core-0.1.17
|
||||
tracing-futures-0.2.4
|
||||
try-lock-0.2.3
|
||||
tungstenite-0.11.1
|
||||
twoway-0.1.8
|
||||
typenum-1.12.0
|
||||
unicase-2.6.0
|
||||
unicode-bidi-0.3.4
|
||||
unicode-normalization-0.1.13
|
||||
unicode-width-0.1.8
|
||||
unicode-xid-0.2.1
|
||||
url-2.1.1
|
||||
urlencoding-1.1.1
|
||||
utf-8-0.7.5
|
||||
version_check-0.9.2
|
||||
want-0.3.0
|
||||
warp-0.2.5
|
||||
wasi-0.10.0+wasi-snapshot-preview1
|
||||
wasi-0.9.0+wasi-snapshot-preview1
|
||||
winapi-0.2.8
|
||||
winapi-0.3.9
|
||||
winapi-build-0.1.1
|
||||
winapi-i686-pc-windows-gnu-0.4.0
|
||||
winapi-util-0.1.5
|
||||
winapi-x86_64-pc-windows-gnu-0.4.0
|
||||
ws2_32-sys-0.2.1
|
||||
yaml-rust-0.4.4
|
||||
"
|
||||
|
||||
inherit cargo
|
||||
|
||||
DESCRIPTION="Generate string of text from Markov chain fed by stdin"
|
||||
# Double check the homepage as the cargo_metadata crate
|
||||
# does not provide this value so instead repository is used
|
||||
HOMEPAGE="homepage field in Cargo.toml inaccessible to cargo metadata"
|
||||
SRC_URI="$(cargo_crate_uris ${CRATES})"
|
||||
RESTRICT="mirror"
|
||||
# License set may be more restrictive as OR is not respected
|
||||
# use cargo-license for a more accurate license picture
|
||||
LICENSE="Apache-2.0 Apache-2.0 WITH LLVM-exception BSD-2-Clause BSD-3-Clause BSL-1.0 CC0-1.0 ISC MIT Unlicense Zlib gpl-3.0-or-later"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64"
|
||||
IUSE=""
|
||||
|
||||
DEPEND=""
|
||||
RDEPEND=""
|
@ -1,34 +1,46 @@
|
||||
//! Generating the strings
|
||||
use super::*;
|
||||
use tokio::sync::mpsc::error::SendError;
|
||||
use futures::StreamExt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GenBodyError(pub String);
|
||||
#[derive(Debug, Default)]
|
||||
pub struct GenBodyError(Option<String>);
|
||||
|
||||
impl error::Error for GenBodyError{}
|
||||
impl fmt::Display for GenBodyError
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "failed to write {:?} to body", self.0)
|
||||
if let Some(z) = &self.0 {
|
||||
write!(f, "failed to write read string {:?} to body", z)
|
||||
} else {
|
||||
write!(f, "failed to read string from chain. it might be empty.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn body(state: State, num: Option<usize>, mut output: mpsc::Sender<String>) -> Result<(), GenBodyError>
|
||||
{
|
||||
let chain = state.chain().read().await;
|
||||
if !chain.is_empty() {
|
||||
let filter = state.outbound_filter();
|
||||
match num {
|
||||
Some(num) if num < state.config().max_gen_size => {
|
||||
//This could DoS `full_body` and writes, potentially.
|
||||
for string in chain.str_iter_for(num) {
|
||||
output.send(filter.filter_owned(string)).await.map_err(|e| GenBodyError(e.0))?;
|
||||
}
|
||||
},
|
||||
_ => output.send(filter.filter_owned(chain.generate_str())).await.map_err(|e| GenBodyError(e.0))?,
|
||||
}
|
||||
let mut chain = state.chain_read();
|
||||
let filter = state.outbound_filter();
|
||||
match num {
|
||||
Some(num) if num < state.config().max_gen_size => {
|
||||
let mut chain = chain.take(num);
|
||||
while let Some(string) = chain.next().await {
|
||||
output.send(filter.filter_owned(string)).await?;
|
||||
}
|
||||
},
|
||||
_ => output.send(filter.filter_owned(chain.next().await.ok_or_else(GenBodyError::default)?)).await?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
impl From<SendError<String>> for GenBodyError
|
||||
{
|
||||
#[inline] fn from(from: SendError<String>) -> Self
|
||||
{
|
||||
Self(Some(from.0))
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,392 @@
|
||||
//! Chain handler.
|
||||
use super::*;
|
||||
use std::{
|
||||
marker::Send,
|
||||
sync::Weak,
|
||||
num::NonZeroUsize,
|
||||
task::{Poll, Context,},
|
||||
pin::Pin,
|
||||
};
|
||||
use tokio::{
|
||||
sync::{
|
||||
RwLock,
|
||||
RwLockReadGuard,
|
||||
mpsc::{
|
||||
self,
|
||||
error::SendError,
|
||||
},
|
||||
watch,
|
||||
Notify,
|
||||
},
|
||||
task::JoinHandle,
|
||||
time::{
|
||||
self,
|
||||
Duration,
|
||||
},
|
||||
};
|
||||
use futures::StreamExt;
|
||||
|
||||
pub const DEFAULT_TIMEOUT: Duration= Duration::from_secs(5);
|
||||
|
||||
/// Settings for chain handler
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Settings
|
||||
{
|
||||
pub backlog: usize,
|
||||
pub internal_backlog: usize,
|
||||
pub capacity: usize,
|
||||
pub timeout: Duration,
|
||||
pub throttle: Option<Duration>,
|
||||
pub bounds: range::DynRange<usize>,
|
||||
}
|
||||
|
||||
impl Settings
|
||||
{
|
||||
/// Should we keep this string.
|
||||
#[inline] fn matches(&self, _s: &str) -> bool
|
||||
{
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Settings
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Self
|
||||
{
|
||||
Self {
|
||||
backlog: 32,
|
||||
internal_backlog: 8,
|
||||
capacity: 4,
|
||||
timeout: Duration::from_secs(5),
|
||||
throttle: Some(Duration::from_millis(200)),
|
||||
bounds: feed::DEFAULT_FEED_BOUNDS.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct HostInner<T>
|
||||
{
|
||||
input: mpsc::Receiver<Vec<T>>,
|
||||
shutdown: watch::Receiver<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Handle<T: Send+ chain::Chainable>
|
||||
{
|
||||
chain: RwLock<chain::Chain<T>>,
|
||||
input: mpsc::Sender<Vec<T>>,
|
||||
opt: Settings,
|
||||
notify_write: Arc<Notify>,
|
||||
push_now: Arc<Notify>,
|
||||
shutdown: watch::Sender<bool>,
|
||||
|
||||
/// Data used only for the worker task.
|
||||
host: msg::Once<HostInner<T>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ChainHandle<T: Send + chain::Chainable>(Arc<Box<Handle<T>>>);
|
||||
|
||||
impl<T: Send+ chain::Chainable + 'static> ChainHandle<T>
|
||||
{
|
||||
pub fn with_settings(chain: chain::Chain<T>, opt: Settings) -> Self
|
||||
{
|
||||
let (shutdown_tx, shutdown) = watch::channel(false);
|
||||
let (itx, irx) = mpsc::channel(opt.backlog);
|
||||
Self(Arc::new(Box::new(Handle{
|
||||
chain: RwLock::new(chain),
|
||||
input: itx,
|
||||
opt,
|
||||
push_now: Arc::new(Notify::new()),
|
||||
notify_write: Arc::new(Notify::new()),
|
||||
shutdown: shutdown_tx,
|
||||
|
||||
host: msg::Once::new(HostInner{
|
||||
input: irx,
|
||||
shutdown,
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
/// Acquire the chain read lock
|
||||
async fn chain(&self) -> RwLockReadGuard<'_, chain::Chain<T>>
|
||||
{
|
||||
self.0.chain.read().await
|
||||
}
|
||||
|
||||
/// A reference to the chain
|
||||
pub fn chain_ref(&self) -> &RwLock<chain::Chain<T>>
|
||||
{
|
||||
&self.0.chain
|
||||
}
|
||||
|
||||
/// Create a stream that reads generated values forever.
|
||||
pub fn read(&self) -> ChainStream<T>
|
||||
{
|
||||
ChainStream{
|
||||
chain: Arc::downgrade(&self.0),
|
||||
buffer: Vec::with_capacity(self.0.opt.backlog),
|
||||
}
|
||||
}
|
||||
|
||||
/// Send this buffer to the chain
|
||||
pub fn write(&self, buf: Vec<T>) -> impl futures::Future<Output = Result<(), SendError<Vec<T>>>> + 'static
|
||||
{
|
||||
let mut write = self.0.input.clone();
|
||||
async move {
|
||||
write.send(buf).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Send this stream buffer to the chain
|
||||
pub fn write_stream<'a, I: Stream<Item=T>>(&self, buf: I) -> impl futures::Future<Output = Result<(), SendError<Vec<T>>>> + 'a
|
||||
where I: 'a
|
||||
{
|
||||
let mut write = self.0.input.clone();
|
||||
async move {
|
||||
write.send(buf.collect().await).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Send this buffer to the chain
|
||||
pub async fn write_in_place(&self, buf: Vec<T>) -> Result<(), SendError<Vec<T>>>
|
||||
{
|
||||
self.0.input.clone().send(buf).await
|
||||
}
|
||||
|
||||
/// A referencer for the notifier
|
||||
pub fn notify_when(&self) -> &Arc<Notify>
|
||||
{
|
||||
&self.0.notify_write
|
||||
}
|
||||
|
||||
/// Force the pending buffers to be written to the chain now
|
||||
pub fn push_now(&self)
|
||||
{
|
||||
self.0.push_now.notify();
|
||||
}
|
||||
|
||||
/// Hang the worker thread, preventing it from taking any more inputs and also flushing it.
|
||||
///
|
||||
/// # Panics
|
||||
/// If there was no worker thread.
|
||||
pub fn hang(&self)
|
||||
{
|
||||
trace!("Communicating hang request");
|
||||
self.0.shutdown.broadcast(true).expect("Failed to communicate hang");
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainHandle<String>
|
||||
{
|
||||
#[deprecated = "use read() pls"]
|
||||
pub async fn generate_body(&self, state: &state::State, num: Option<usize>, mut output: mpsc::Sender<String>) -> Result<(), SendError<String>>
|
||||
{
|
||||
let chain = self.chain().await;
|
||||
if !chain.is_empty() {
|
||||
let filter = state.outbound_filter();
|
||||
match num {
|
||||
Some(num) if num < state.config().max_gen_size => {
|
||||
//This could DoS writes, potentially.
|
||||
for string in chain.str_iter_for(num) {
|
||||
output.send(filter.filter_owned(string)).await?;
|
||||
}
|
||||
},
|
||||
_ => output.send(filter.filter_owned(chain.generate_str())).await?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Host this handle on the current task.
|
||||
///
|
||||
/// # Panics
|
||||
/// If `from` has already been hosted.
|
||||
pub async fn host(from: ChainHandle<String>)
|
||||
{
|
||||
let opt = from.0.opt.clone();
|
||||
let mut data = from.0.host.unwrap().await;
|
||||
|
||||
let (mut tx, mut child) = {
|
||||
// The `real` input channel.
|
||||
let from = from.clone();
|
||||
let opt = opt.clone();
|
||||
let (tx, rx) = mpsc::channel::<Vec<Vec<_>>>(opt.internal_backlog);
|
||||
(tx, tokio::spawn(async move {
|
||||
let mut rx = if let Some(thr) = opt.throttle {
|
||||
time::throttle(thr, rx).boxed()
|
||||
} else {
|
||||
rx.boxed()
|
||||
};
|
||||
trace!("child: Begin waiting on parent");
|
||||
while let Some(item) = rx.next().await {
|
||||
if item.len() > 0 {
|
||||
info!("Write lock acq");
|
||||
let mut lock = from.0.chain.write().await;
|
||||
for item in item.into_iter()
|
||||
{
|
||||
use std::ops::DerefMut;
|
||||
for item in item.into_iter() {
|
||||
feed::feed(lock.deref_mut(), item, &from.0.opt.bounds);
|
||||
}
|
||||
}
|
||||
trace!("Signalling write");
|
||||
from.0.notify_write.notify();
|
||||
}
|
||||
}
|
||||
trace!("child: exiting");
|
||||
}))
|
||||
};
|
||||
|
||||
trace!("Begin polling on child");
|
||||
tokio::select!{
|
||||
v = &mut child => {
|
||||
match v {
|
||||
/*#[cold]*/ Ok(_) => {warn!("Child exited before we have? This should probably never happen.")},//Should never happen.
|
||||
Err(e) => {error!("Child exited abnormally. Aborting: {}", e)}, //Child panic or cancel.
|
||||
}
|
||||
},
|
||||
_ = async move {
|
||||
let mut rx = data.input.chunk(opt.capacity); //we don't even need this tbh, oh well.
|
||||
|
||||
if !data.shutdown.recv().await.unwrap_or(true) { //first shutdown we get for free
|
||||
while Arc::strong_count(&from.0) > 2 {
|
||||
if *data.shutdown.borrow() {
|
||||
break;
|
||||
}
|
||||
|
||||
tokio::select!{
|
||||
Some(true) = data.shutdown.recv() => {
|
||||
debug!("Got shutdown (hang) request. Sending now then breaking");
|
||||
|
||||
let mut rest = {
|
||||
let irx = rx.get_mut();
|
||||
irx.close(); //accept no more inputs
|
||||
let mut output = Vec::with_capacity(opt.capacity);
|
||||
while let Ok(item) = irx.try_recv() {
|
||||
output.push(item);
|
||||
}
|
||||
output
|
||||
};
|
||||
rest.extend(rx.take_now());
|
||||
if rest.len() > 0 {
|
||||
if let Err(err) = tx.send(rest).await {
|
||||
error!("Failed to force send buffer, exiting now: {}", err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ = time::delay_for(opt.timeout) => {
|
||||
trace!("Setting push now");
|
||||
rx.push_now();
|
||||
}
|
||||
_ = from.0.push_now.notified() => {
|
||||
debug!("Got force push signal");
|
||||
let take =rx.take_now();
|
||||
rx.push_now();
|
||||
if take.len() > 0 {
|
||||
if let Err(err) = tx.send(take).await {
|
||||
error!("Failed to force send buffer: {}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(buffer) = rx.next() => {
|
||||
debug!("Sending {} (cap {})", buffer.len(), buffer.capacity());
|
||||
if let Err(err) = tx.send(buffer).await {
|
||||
// Receive closed?
|
||||
//
|
||||
// This probably shouldn't happen, as we `select!` for it up there and child never calls `close()` on `rx`.
|
||||
// In any case, it means we should abort.
|
||||
/*#[cold]*/ error!("Failed to send buffer: {}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let last = rx.into_buffer();
|
||||
if last.len() > 0 {
|
||||
if let Err(err) = tx.send(last).await {
|
||||
error!("Failed to force send last part of buffer: {}", err);
|
||||
} else {
|
||||
trace!("Sent rest of buffer");
|
||||
}
|
||||
}
|
||||
} => {
|
||||
// Normal exit
|
||||
trace!("Normal exit")
|
||||
},
|
||||
}
|
||||
trace!("Waiting on child");
|
||||
// No more handles except child, no more possible inputs.
|
||||
child.await.expect("Child panic");
|
||||
trace!("Returning");
|
||||
}
|
||||
|
||||
/// Spawn a new chain handler for this chain.
|
||||
pub fn spawn(from: chain::Chain<String>, opt: Settings) -> (JoinHandle<()>, ChainHandle<String>)
|
||||
{
|
||||
debug!("Spawning with opt: {:?}", opt);
|
||||
let handle = ChainHandle::with_settings(from, opt);
|
||||
(tokio::spawn(host(handle.clone())), handle)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChainStream<T: Send + chain::Chainable>
|
||||
{
|
||||
chain: Weak<Box<Handle<T>>>,
|
||||
buffer: Vec<T>,
|
||||
}
|
||||
|
||||
impl ChainStream<String>
|
||||
{
|
||||
async fn try_pull(&mut self, n: usize) -> Option<NonZeroUsize>
|
||||
{
|
||||
if n == 0 {
|
||||
return None;
|
||||
}
|
||||
if let Some(read) = self.chain.upgrade() {
|
||||
let chain = read.chain.read().await;
|
||||
if chain.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let n = if n == 1 {
|
||||
self.buffer.push(chain.generate_str());
|
||||
1
|
||||
} else {
|
||||
self.buffer.extend(chain.str_iter_for(n));
|
||||
n //for now
|
||||
};
|
||||
Some(unsafe{NonZeroUsize::new_unchecked(n)})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for ChainStream<String>
|
||||
{
|
||||
type Item = String;
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
use futures::Future;
|
||||
let this = self.get_mut();
|
||||
|
||||
if this.buffer.len() == 0 {
|
||||
let pull = this.try_pull(this.buffer.capacity());
|
||||
tokio::pin!(pull);
|
||||
match pull.poll(cx) {
|
||||
Poll::Ready(Some(_)) => {},
|
||||
Poll::Pending => return Poll::Pending,
|
||||
_ => return Poll::Ready(None),
|
||||
};
|
||||
}
|
||||
debug_assert!(this.buffer.len()>0);
|
||||
Poll::Ready(Some(this.buffer.remove(0)))
|
||||
}
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
//! Filter accepts and denies based on cidr masks.
|
||||
use super::*;
|
||||
use cidr::{
|
||||
Cidr,
|
||||
IpCidr,
|
||||
};
|
||||
use std::{
|
||||
net::{
|
||||
IpAddr,
|
||||
},
|
||||
error,
|
||||
fmt,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IpFilterDeniedError(IpAddr, Option<IpCidr>);
|
||||
|
||||
impl warp::reject::Reject for IpFilterDeniedError{}
|
||||
impl error::Error for IpFilterDeniedError{}
|
||||
impl fmt::Display for IpFilterDeniedError
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "Denied {} due to ", self.0)?;
|
||||
match &self.1 {
|
||||
Some(cidr) => write!(f, "matching rule {}", cidr),
|
||||
None => write!(f, "non-matching accept rule"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum Rule
|
||||
{
|
||||
Accept,
|
||||
Deny,
|
||||
}
|
||||
|
||||
impl Default for Rule
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Self
|
||||
{
|
||||
Self::Deny
|
||||
}
|
||||
}
|
||||
|
||||
impl Rule
|
||||
{
|
||||
fn into_result<'a>(self, net: Option<&'a IpCidr>) -> Result<Option<&'a IpCidr>, Option<IpCidr>>
|
||||
{
|
||||
if let Self::Accept = self {
|
||||
Ok(net)
|
||||
} else {
|
||||
Err(net.cloned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct IpFilter
|
||||
{
|
||||
/// The default fallback rule
|
||||
pub default: Rule,
|
||||
|
||||
#[serde(default)]
|
||||
accept: Vec<IpCidr>,
|
||||
#[serde(default)]
|
||||
deny: Vec<IpCidr>,
|
||||
}
|
||||
|
||||
#[inline] fn find_in<'a>(needle: &IpAddr, haystack: &'a [IpCidr]) -> Option<&'a IpCidr>
|
||||
{
|
||||
for x in haystack.iter()
|
||||
{
|
||||
if x.contains(needle) {
|
||||
return Some(x);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl Default for IpFilter
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Self
|
||||
{
|
||||
Self {
|
||||
default: Rule::Deny,
|
||||
accept: vec![cidr::Cidr::new_host([127,0,0,1].into())],
|
||||
deny: Vec::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IpFilter
|
||||
{
|
||||
/// Create a new CIDR filter with thie default rule.
|
||||
///
|
||||
/// Use `default()` to use with default rule.
|
||||
pub fn new(fallback: Rule) -> Self
|
||||
{
|
||||
Self {
|
||||
default: fallback,
|
||||
accept: Vec::new(),
|
||||
deny: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the rule for this IP, returns a result if it should accept or not.
|
||||
///
|
||||
/// If acceptance rule is met, return the CIDR match that caused the acceptance if applicable
|
||||
///
|
||||
/// If acceptance rule is not met, return in the error which CIDR match cause the deny if applicable
|
||||
pub fn check(&self, ip: &IpAddr) -> Result<Option<&'_ IpCidr>, IpFilterDeniedError>
|
||||
{
|
||||
let accept = find_in(ip, &self.accept[..]);
|
||||
let deny = find_in(ip, &self.deny[..]);
|
||||
|
||||
let (rule, cidr) = match (accept, deny) {
|
||||
(None, Some(net)) => (Rule::Deny, Some(net)),
|
||||
(Some(net), None) => (Rule::Accept, Some(net)),
|
||||
(Some(ac), Some(den)) if ac != den => {
|
||||
if ac.network_length() > den.network_length() {
|
||||
(Rule::Accept, Some(ac))
|
||||
} else {
|
||||
(Rule::Deny, Some(den))
|
||||
}
|
||||
},
|
||||
_ => (self.default, None)
|
||||
};
|
||||
rule.into_result(cidr)
|
||||
.map_err(|cidr| IpFilterDeniedError(*ip, cidr))
|
||||
}
|
||||
|
||||
pub fn accept_mask(&self) -> &[IpCidr]
|
||||
{
|
||||
&self.accept[..]
|
||||
}
|
||||
pub fn deny_mask(&self) -> &[IpCidr]
|
||||
{
|
||||
&self.deny[..]
|
||||
}
|
||||
pub fn accept_range(&mut self, items: impl IntoIterator<Item = IpCidr>)
|
||||
{
|
||||
self.accept.extend(items)
|
||||
}
|
||||
pub fn deny_range(&mut self, items: impl IntoIterator<Item = IpCidr>)
|
||||
{
|
||||
self.deny.extend(items)
|
||||
}
|
||||
|
||||
pub fn accept_one(&mut self, item: IpCidr)
|
||||
{
|
||||
self.accept.push(item)
|
||||
}
|
||||
pub fn deny_one(&mut self, items: IpCidr)
|
||||
{
|
||||
self.deny.push(items)
|
||||
}
|
||||
|
||||
/// Can any connection ever be accepted?
|
||||
pub fn possible(&self) -> bool
|
||||
{
|
||||
//TODO: Test this
|
||||
!(self.default == Rule::Deny && self.accept.len() == 0) &&
|
||||
!(self.deny.iter().find(|x| x.network_length() == 0).is_some() && self.accept.len() == 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn recover(err: warp::Rejection) -> Result<impl warp::Reply, warp::Rejection>
|
||||
{
|
||||
if let Some(t) = err.find::<IpFilterDeniedError>() {
|
||||
error!("Denying access to {} because of {:?} (403)", t.0, t.1);
|
||||
Ok(warp::http::Response::builder()
|
||||
.status(status!(403))
|
||||
.body(format!("Access denied: {}", t)))
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
//! Message passing things
|
||||
use super::*;
|
||||
use tokio::{
|
||||
sync::{
|
||||
watch,
|
||||
Mutex,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
task::{Poll, Context},
|
||||
pin::Pin,
|
||||
fmt,
|
||||
error,
|
||||
};
|
||||
use futures::{
|
||||
future::{
|
||||
Future,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InitError;
|
||||
#[derive(Debug)]
|
||||
pub struct InitWaitError;
|
||||
|
||||
impl error::Error for InitError{}
|
||||
impl fmt::Display for InitError
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "failed to set init value")
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for InitWaitError{}
|
||||
impl fmt::Display for InitWaitError
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "failed to receive init value")
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides a method of waiting on and setting a single initialisation.
|
||||
///
|
||||
/// In general, it should only be set once, as multiple sets do nothing but hog `Arc`s.
|
||||
/// Dropping the `Initialiser` after waiting or setting should generally be done immediately.
|
||||
/// Choose the `into_wait()` and `set()` varients over the non-consuming ones.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Initialiser
|
||||
{
|
||||
tx: Arc<watch::Sender<bool>>,
|
||||
rx: watch::Receiver<bool>
|
||||
}
|
||||
|
||||
impl Initialiser
|
||||
{
|
||||
/// Create a new, unset initialiser
|
||||
pub fn new() -> Self
|
||||
{
|
||||
let (tx, rx) = watch::channel(false);
|
||||
Self {
|
||||
tx: Arc::new(tx),
|
||||
rx,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a pre-set initialiser. Calls to `wait()` will immediately resolve.
|
||||
pub fn new_set() -> Self
|
||||
{
|
||||
let (tx, rx) = watch::channel(true);
|
||||
Self {
|
||||
tx: Arc::new(tx),
|
||||
rx,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume into a future that completes when init is set.
|
||||
pub fn into_wait(self) -> impl Future<Output=Result<(), InitWaitError>> + 'static
|
||||
{
|
||||
let mut rx = self.rx;
|
||||
async move {
|
||||
if !*rx.borrow() {
|
||||
while !rx.recv().await.ok_or_else(|| InitWaitError)? {
|
||||
//tokio::task::yield_now().await;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clone into a future that completes when init is set.
|
||||
///
|
||||
/// This method does not clone any `Arc`s and is prefered to `self.clone().into_wait()`.
|
||||
/// Use this when the `Initialiser` you want to wait on is behind a shared reference.
|
||||
pub fn clone_into_wait(&self) -> impl Future<Output=Result<(), InitWaitError>> + 'static
|
||||
{
|
||||
let mut rx = self.rx.clone();
|
||||
async move {
|
||||
if !*rx.borrow() {
|
||||
while !rx.recv().await.ok_or_else(|| InitWaitError)? {
|
||||
//tokio::task::yield_now().await;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Completes when init is set
|
||||
pub async fn wait(&mut self) -> Result<(), InitWaitError>
|
||||
{
|
||||
if !*self.rx.borrow() {
|
||||
while !self.rx.recv().await.ok_or_else(|| InitWaitError)? {
|
||||
//tokio::task::yield_now().await;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Is init set?
|
||||
pub fn is_set(&self) -> bool
|
||||
{
|
||||
*self.rx.borrow()
|
||||
}
|
||||
|
||||
/// Consume and set init if it's not already set
|
||||
pub fn set(self) -> Result<(), InitError>
|
||||
{
|
||||
if !*self.rx.borrow() {
|
||||
self.tx.broadcast(true).map_err(|_| InitError)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Set init without consuming.
|
||||
///
|
||||
/// # Note
|
||||
/// It is prefered to use `set()`, as this method may make `Arc`s hang around longer than they need to.
|
||||
/// Calling this multiple times is useless.
|
||||
pub fn set_in_place(&self) -> Result<(), InitError>
|
||||
{
|
||||
if !*self.rx.borrow() {
|
||||
self.tx.broadcast(true).map_err(|_| InitError)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for Initialiser
|
||||
{
|
||||
type Output = Result<(), InitWaitError>;
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let uhh = self.wait();
|
||||
tokio::pin!(uhh);
|
||||
uhh.poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// A value that can be consumed once.
|
||||
#[derive(Debug)]
|
||||
pub struct Once<T>(Mutex<Option<T>>);
|
||||
|
||||
impl<T> Once<T>
|
||||
{
|
||||
/// Create a new instance
|
||||
pub fn new(from: T) -> Self
|
||||
{
|
||||
Self(Mutex::new(Some(from)))
|
||||
}
|
||||
/// Consume into the instance from behind a potentially shared reference.
|
||||
pub async fn consume_shared(self: Arc<Self>) -> Option<T>
|
||||
{
|
||||
match Arc::try_unwrap(self) {
|
||||
Ok(x) => x.0.into_inner(),
|
||||
Err(x) => x.0.lock().await.take(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume from a shared reference and panic if the value has already been consumed.
|
||||
pub async fn unwrap_shared(self: Arc<Self>) -> T
|
||||
{
|
||||
self.consume_shared().await.unwrap()
|
||||
}
|
||||
|
||||
/// Consume into the instance.
|
||||
pub async fn consume(&self) -> Option<T>
|
||||
{
|
||||
self.0.lock().await.take()
|
||||
}
|
||||
|
||||
/// Consume and panic if the value has already been consumed.
|
||||
pub async fn unwrap(&self) -> T
|
||||
{
|
||||
self.consume().await.unwrap()
|
||||
}
|
||||
|
||||
/// Consume into the inner value
|
||||
pub fn into_inner(self) -> Option<T>
|
||||
{
|
||||
self.0.into_inner()
|
||||
}
|
||||
}
|
@ -0,0 +1,296 @@
|
||||
//! Workarounds for ridiculously janky `std::ops::Range*` polymorphism
|
||||
use super::*;
|
||||
use std::{
|
||||
ops::{
|
||||
Range,
|
||||
RangeFrom,
|
||||
RangeInclusive,
|
||||
RangeTo,
|
||||
RangeToInclusive,
|
||||
RangeFull,
|
||||
|
||||
Bound,
|
||||
RangeBounds,
|
||||
},
|
||||
str::{
|
||||
FromStr,
|
||||
},
|
||||
fmt,
|
||||
error,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum DynRange<T>
|
||||
{
|
||||
Range(Range<T>),
|
||||
From(RangeFrom<T>),
|
||||
Inclusive(RangeInclusive<T>),
|
||||
To(RangeTo<T>),
|
||||
ToInclusive(RangeToInclusive<T>),
|
||||
Full(RangeFull),
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! impl_from {
|
||||
(Full, RangeFull) => {
|
||||
impl<T> From<RangeFull> for DynRange<T>
|
||||
{
|
||||
#[inline] fn from(from: RangeFull) -> Self
|
||||
{
|
||||
Self::Full(from)
|
||||
}
|
||||
}
|
||||
};
|
||||
($name:ident, $range:tt) => {
|
||||
|
||||
impl<T> From<$range <T>> for DynRange<T>
|
||||
{
|
||||
#[inline] fn from(from: $range<T>) -> Self
|
||||
{
|
||||
Self::$name(from)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from!(Range, Range);
|
||||
impl_from!(From, RangeFrom);
|
||||
impl_from!(Inclusive, RangeInclusive);
|
||||
impl_from!(To, RangeTo);
|
||||
impl_from!(ToInclusive, RangeToInclusive);
|
||||
impl_from!(Full, RangeFull);
|
||||
|
||||
macro_rules! bounds {
|
||||
($self:ident, $bound:ident) => {
|
||||
match $self {
|
||||
DynRange::Range(from) => from.$bound(),
|
||||
DynRange::From(from) => from.$bound(),
|
||||
DynRange::Inclusive(i) => i.$bound(),
|
||||
DynRange::To(i) => i.$bound(),
|
||||
DynRange::ToInclusive(i) => i.$bound(),
|
||||
DynRange::Full(_) => (..).$bound(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<T> RangeBounds<T> for DynRange<T>
|
||||
{
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
bounds!(self, start_bound)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
bounds!(self, end_bound)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RangeBounds<T> for &'a DynRange<T>
|
||||
{
|
||||
fn start_bound(&self) -> Bound<&T> {
|
||||
bounds!(self, start_bound)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&T> {
|
||||
bounds!(self, end_bound)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for DynRange<T>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
match self {
|
||||
Self::Range(from) => write!(f, "{}..{}", from.start, from.end),
|
||||
Self::From(from) => write!(f, "{}..", from.start),
|
||||
Self::Inclusive(from) => write!(f, "{}..={}", from.start(), from.end()),
|
||||
Self::To(from) => write!(f, "..{}", from.end),
|
||||
Self::ToInclusive(from) => write!(f, "..={}", from.end),
|
||||
Self::Full(_) => write!(f, ".."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use std::any::{
|
||||
Any,
|
||||
};
|
||||
|
||||
impl<T: 'static> DynRange<T>
|
||||
{
|
||||
#[inline]
|
||||
pub fn into_boxed(self) -> Box<dyn Any /*TODO: + Send + Sync */+ 'static>
|
||||
{
|
||||
self.into_inner()
|
||||
}
|
||||
fn into_inner(self) -> Box<dyn Any + 'static>
|
||||
{
|
||||
match self {
|
||||
Self::Range(from) => Box::new(from),
|
||||
Self::From(from) => Box::new(from),
|
||||
Self::Inclusive(from) => Box::new(from),
|
||||
Self::To(from) => Box::new(from),
|
||||
Self::ToInclusive(from) => Box::new(from),
|
||||
Self::Full(_) => Box::new(..),
|
||||
}
|
||||
}
|
||||
fn inner_mut(&mut self) -> &mut dyn Any
|
||||
{
|
||||
match self {
|
||||
Self::Range(from) => from,
|
||||
Self::From(from) => from,
|
||||
Self::Inclusive(from) => from,
|
||||
Self::To(from) => from,
|
||||
Self::ToInclusive(from) => from,
|
||||
Self::Full(f) => f,
|
||||
}
|
||||
}
|
||||
fn inner_ref(&self) -> &dyn Any
|
||||
{
|
||||
match self {
|
||||
Self::Range(from) => from,
|
||||
Self::From(from) => from,
|
||||
Self::Inclusive(from) => from,
|
||||
Self::To(from) => from,
|
||||
Self::ToInclusive(from) => from,
|
||||
Self::Full(_) => &(..),
|
||||
}
|
||||
}
|
||||
pub fn downcast_ref<R: RangeBounds<T> + 'static>(&self) -> Option<&R>
|
||||
{
|
||||
self.inner_ref().downcast_ref()
|
||||
}
|
||||
pub fn downcast_mut<R: RangeBounds<T> + 'static>(&mut self) -> Option<&mut R>
|
||||
{
|
||||
self.inner_mut().downcast_mut()
|
||||
}
|
||||
pub fn downcast<R: RangeBounds<T> + 'static>(self) -> Result<R, Self>
|
||||
{
|
||||
self.into_inner().downcast::<R>()
|
||||
.map(|x| *x)
|
||||
.map_err(|b| {
|
||||
todo!("make this bullshit properly unboxable ehh...")
|
||||
})
|
||||
//Box::<(dyn std::any::Any + 'static)>::downcast(Box::new(self)).map_ok(|ok| *ok)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseError(DynRange<()>, Option<Box<dyn error::Error+'static>>);
|
||||
|
||||
impl ParseError
|
||||
{
|
||||
fn new<R: Into<DynRange<()>>>(which: R, err: impl error::Error + 'static) -> Self
|
||||
{
|
||||
Self(which.into(), Some(Box::new(err)))
|
||||
}
|
||||
fn none(which: impl Into<DynRange<()>>) -> Self
|
||||
{
|
||||
Self(which.into(), None)
|
||||
}
|
||||
fn map<T: Into<DynRange<()>>>(self, to: T) -> Self
|
||||
{
|
||||
Self (to.into(), self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ParseError
|
||||
{
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
if let Some(this) = self.1.as_ref() {
|
||||
Some(this.as_ref())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseError
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "failed to parse range in format `{:?}`", self.0)?;
|
||||
if let Some(this) = self.1.as_ref() {
|
||||
write!(f, ": {}", this)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: FromStr> FromStr for DynRange<T>
|
||||
where T::Err: error::Error + 'static
|
||||
{
|
||||
type Err = ParseError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s== ".." {
|
||||
Ok(Self::Full(..))
|
||||
} else if s.starts_with("..=") {
|
||||
Ok(Self::ToInclusive(..=T::from_str(&s[3..]).map_err(|x| ParseError::new(..=(), x))?))
|
||||
} else if s.starts_with("..") {
|
||||
Ok(Self::To(..(T::from_str(&s[2..])).map_err(|x| ParseError::new(..(), x))?))
|
||||
} else if s.ends_with("..") {
|
||||
Ok(Self::From(T::from_str(&s[..s.len()-2]).map_err(|x| ParseError::new(().., x))?..))
|
||||
} else {
|
||||
fn try_next_incl<'a, T: FromStr>(m: &mut impl Iterator<Item=&'a str>) -> Result<RangeInclusive<T>, ParseError>
|
||||
where T::Err: error::Error + 'static
|
||||
{
|
||||
let (first, second) = if let Some(first) = m.next() {
|
||||
if let Some(seocond) = m.next() {
|
||||
(first,seocond)
|
||||
} else {
|
||||
return Err(ParseError::none(()..=()));
|
||||
}
|
||||
} else {
|
||||
return Err(ParseError::none(()..=()));
|
||||
};
|
||||
|
||||
let first: T = first.parse().map_err(|x| ParseError::new(()..=(), x))?;
|
||||
let second: T = second.parse().map_err(|x| ParseError::new(()..=(), x))?;
|
||||
|
||||
Ok(first..=second)
|
||||
}
|
||||
|
||||
fn try_next<'a, T: FromStr>(m: &mut impl Iterator<Item=&'a str>) -> Result<Range<T>, ParseError>
|
||||
where T::Err: error::Error + 'static
|
||||
{
|
||||
let (first, second) = if let Some(first) = m.next() {
|
||||
if let Some(seocond) = m.next() {
|
||||
(first,seocond)
|
||||
} else {
|
||||
return Err(ParseError::none(()..()));
|
||||
}
|
||||
} else {
|
||||
return Err(ParseError::none(()..()));
|
||||
};
|
||||
|
||||
let first: T = first.parse().map_err(|x| ParseError::new(()..(), x))?;
|
||||
let second: T = second.parse().map_err(|x| ParseError::new(()..(), x))?;
|
||||
|
||||
Ok(first..second)
|
||||
}
|
||||
|
||||
|
||||
let mut split = s.split("..=").fuse();
|
||||
|
||||
let mut last_err = ParseError::none(()..());
|
||||
match loop {
|
||||
match try_next_incl(&mut split) {
|
||||
Err(ParseError(_, None)) => break Err(last_err), // iter empty
|
||||
Err(other) => last_err = other,
|
||||
Ok(value) => break Ok(Self::Inclusive(value)),
|
||||
}
|
||||
} {
|
||||
Ok(v) => return Ok(v),
|
||||
Err(e) => last_err = e,
|
||||
};
|
||||
|
||||
let mut split = s.split("..").fuse();
|
||||
match loop {
|
||||
match try_next(&mut split) {
|
||||
Err(ParseError(_, None)) => break Err(last_err), // iter empty
|
||||
Err(other) => last_err = other,
|
||||
Ok(value) => break Ok(Self::Range(value)),
|
||||
}
|
||||
} {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue