mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-07-26 19:22:19 +00:00
Enhance torrent server functionality and performance
This commit is contained in:
parent
eadcb945f7
commit
4adc34ffaf
12 changed files with 341 additions and 99 deletions
Binary file not shown.
32
go/go.mod
32
go/go.mod
|
|
@ -3,27 +3,27 @@ module server
|
|||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/anacrolix/torrent v1.58.1
|
||||
github.com/anacrolix/torrent v1.61.0
|
||||
github.com/rs/cors v1.11.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/RoaringBitmap/roaring v1.9.4 // indirect
|
||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect
|
||||
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
|
||||
github.com/anacrolix/chansync v0.6.0 // indirect
|
||||
github.com/anacrolix/dht/v2 v2.22.1 // indirect
|
||||
github.com/anacrolix/btree v0.0.0-20251201064447-d86c3fa41bd8 // indirect
|
||||
github.com/anacrolix/chansync v0.7.0 // indirect
|
||||
github.com/anacrolix/dht/v2 v2.23.0 // indirect
|
||||
github.com/anacrolix/envpprof v1.4.0 // indirect
|
||||
github.com/anacrolix/generics v0.0.3 // indirect
|
||||
github.com/anacrolix/generics v0.1.1-0.20251125230353-15d98d46693b // indirect
|
||||
github.com/anacrolix/go-libutp v1.3.2 // indirect
|
||||
github.com/anacrolix/log v0.16.0 // indirect
|
||||
github.com/anacrolix/log v0.17.1-0.20251118025802-918f1157b7bb // indirect
|
||||
github.com/anacrolix/missinggo v1.3.0 // indirect
|
||||
github.com/anacrolix/missinggo/perf v1.0.0 // indirect
|
||||
github.com/anacrolix/missinggo/v2 v2.8.0 // indirect
|
||||
github.com/anacrolix/missinggo/v2 v2.10.0 // indirect
|
||||
github.com/anacrolix/mmsg v1.1.1 // indirect
|
||||
github.com/anacrolix/multiless v0.4.0 // indirect
|
||||
github.com/anacrolix/stm v0.5.0 // indirect
|
||||
github.com/anacrolix/sync v0.5.4 // indirect
|
||||
github.com/anacrolix/sync v0.5.5-0.20251119100342-d78dd1f686f1 // indirect
|
||||
github.com/anacrolix/upnp v0.1.4 // indirect
|
||||
github.com/anacrolix/utp v0.2.0 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
|
|
@ -39,6 +39,7 @@ require (
|
|||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
|
|
@ -71,20 +72,21 @@ require (
|
|||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tidwall/btree v1.8.0 // indirect
|
||||
github.com/tidwall/btree v1.8.1 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
go.etcd.io/bbolt v1.4.2 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
golang.org/x/crypto v0.50.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
|
||||
golang.org/x/mobile v0.0.0-20260410095206-2cfb76559b7b // indirect
|
||||
golang.org/x/net v0.53.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/tools v0.44.0 // indirect
|
||||
lukechampine.com/blake3 v1.4.1 // indirect
|
||||
modernc.org/libc v1.66.3 // indirect
|
||||
|
|
|
|||
90
go/go.sum
90
go/go.sum
|
|
@ -14,8 +14,6 @@ github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv
|
|||
github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 h1:byYvvbfSo3+9efR4IeReh77gVs4PnNDR3AMOE9NJ7a0=
|
||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0/go.mod h1:q37NoqncT41qKc048STsifIt69LfUJ8SrWWcz/yam5k=
|
||||
github.com/alecthomas/assert/v2 v2.0.0-alpha3 h1:pcHeMvQ3OMstAWgaeaXIAL8uzB9xMm2zlxt+/4ml8lk=
|
||||
github.com/alecthomas/assert/v2 v2.0.0-alpha3/go.mod h1:+zD0lmDXTeQj7TgDgCt0ePWxb0hMC1G+PGTsTCv1B9o=
|
||||
github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8=
|
||||
|
|
@ -26,28 +24,31 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
|
|||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anacrolix/chansync v0.6.0 h1:/aQVvZ1yLRhmqEYrr9dC92JwzNBQ/SNnFi4uk+fTkQY=
|
||||
github.com/anacrolix/chansync v0.6.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
||||
github.com/anacrolix/dht/v2 v2.22.1 h1:mgsljPXyA/EWA7uUDSNjx7wf6gsfhppjVIp9auVeR6w=
|
||||
github.com/anacrolix/dht/v2 v2.22.1/go.mod h1:seXRz6HLw8zEnxlysf9ye2eQbrKUmch6PyOHpe/Nb/U=
|
||||
github.com/anacrolix/btree v0.0.0-20251201064447-d86c3fa41bd8 h1:c02PsmoaChabVqAFm7pqPI1UIkDdDAjUaWa6ZmfxybQ=
|
||||
github.com/anacrolix/btree v0.0.0-20251201064447-d86c3fa41bd8/go.mod h1:7stWJ39LeusmMI8mjJuhFNRqep//vx0AsaySRoK9or0=
|
||||
github.com/anacrolix/chansync v0.7.0 h1:wgwxbsJRmOqNjil4INpxHrDp4rlqQhECxR8/WBP4Et0=
|
||||
github.com/anacrolix/chansync v0.7.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
||||
github.com/anacrolix/dht/v2 v2.23.0 h1:EuD17ykTTEkAMPLjBsS5QjGOwuBgLTdQhds6zPAjeVY=
|
||||
github.com/anacrolix/dht/v2 v2.23.0/go.mod h1:seXRz6HLw8zEnxlysf9ye2eQbrKUmch6PyOHpe/Nb/U=
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
|
||||
github.com/anacrolix/envpprof v1.4.0 h1:QHeIcrgHcRChhnxR8l6rlaLlRQx9zd7Q2NII6Zbt83w=
|
||||
github.com/anacrolix/envpprof v1.4.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcertl6Yh0jCB0=
|
||||
github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
||||
github.com/anacrolix/generics v0.0.3 h1:wMkQgQzq0obSy1tMkxDu7Ife7PsegOBWHDRaSW31EnM=
|
||||
github.com/anacrolix/generics v0.0.3/go.mod h1:MN3ve08Z3zSV/rTuX/ouI4lNdlfTxgdafQJiLzyNRB8=
|
||||
github.com/anacrolix/generics v0.1.1-0.20251125230353-15d98d46693b h1:Kuvx/A/TTJuT9x8mn7DeGx2KW9tWn1LI8bira67xdT0=
|
||||
github.com/anacrolix/generics v0.1.1-0.20251125230353-15d98d46693b/go.mod h1:NGehhfeXJPBujPx0s6cstSj8B+TERsTY32Xckfx5ftc=
|
||||
github.com/anacrolix/go-libutp v1.3.2 h1:WswiaxTIogchbkzNgGHuHRfbrYLpv4o290mlvcx+++M=
|
||||
github.com/anacrolix/go-libutp v1.3.2/go.mod h1:fCUiEnXJSe3jsPG554A200Qv+45ZzIIyGEvE56SHmyA=
|
||||
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
||||
github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
||||
github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
|
||||
github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
||||
github.com/anacrolix/log v0.16.0 h1:DSuyb5kAJwl3Y0X1TRcStVrTS9ST9b0BHW+7neE4Xho=
|
||||
github.com/anacrolix/log v0.16.0/go.mod h1:m0poRtlr41mriZlXBQ9SOVZ8yZBkLjOkDhd5Li5pITA=
|
||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM=
|
||||
github.com/anacrolix/log v0.17.1-0.20251118025802-918f1157b7bb h1:nGNLCQbxFQZz7/9PXLGQ9GmavI/W+eX66pSwVeUwugU=
|
||||
github.com/anacrolix/log v0.17.1-0.20251118025802-918f1157b7bb/go.mod h1:YjBZbwe2v3RsU7WdoBlVSPVpfKuOAno9SRQ/8tIl+hk=
|
||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM=
|
||||
github.com/anacrolix/lsan v0.1.0 h1:TbgB8fdVXgBwrNsJGHtht9+9FepNFu5H7dU8ek6XYAY=
|
||||
github.com/anacrolix/lsan v0.1.0/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
|
||||
github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
||||
github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
||||
|
|
@ -58,8 +59,8 @@ github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy
|
|||
github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
|
||||
github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY=
|
||||
github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA=
|
||||
github.com/anacrolix/missinggo/v2 v2.8.0 h1:6pGnVOlR6TWL9JM5Msyezij8YHU3+oHO7r82Eql/kpA=
|
||||
github.com/anacrolix/missinggo/v2 v2.8.0/go.mod h1:vVO5FEziQm+NFmJesc7StpkquZk+WJFCaL0Wp//2sa0=
|
||||
github.com/anacrolix/missinggo/v2 v2.10.0 h1:pg0iO4Z/UhP2MAnmGcaMtp5ZP9kyWsusENWN9aolrkY=
|
||||
github.com/anacrolix/missinggo/v2 v2.10.0/go.mod h1:nCRMW6bRCMOVcw5z9BnSYKF+kDbtenx+hQuphf4bK8Y=
|
||||
github.com/anacrolix/mmsg v1.0.1/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc=
|
||||
github.com/anacrolix/mmsg v1.1.1 h1:4ce/3I5kM7qSF6T5A8MOmDCfac3UqYlk5Bzh5XsWebM=
|
||||
github.com/anacrolix/mmsg v1.1.1/go.mod h1:lPCXEN1eDDQtKktdKEzdw+roswx6wWPpeXAl/WpWVDU=
|
||||
|
|
@ -70,13 +71,13 @@ github.com/anacrolix/stm v0.5.0 h1:9df1KBpttF0TzLgDq51Z+TEabZKMythqgx89f1FQJt8=
|
|||
github.com/anacrolix/stm v0.5.0/go.mod h1:MOwrSy+jCm8Y7HYfMAwPj7qWVu7XoVvjOiYwJmpeB/M=
|
||||
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk=
|
||||
github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
||||
github.com/anacrolix/sync v0.5.4 h1:yXZLIjXh/G+Rh2mYGCAPmszmF/fvEPadDy7/pPChpKM=
|
||||
github.com/anacrolix/sync v0.5.4/go.mod h1:21cUWerw9eiu/3T3kyoChu37AVO+YFue1/H15qqubS0=
|
||||
github.com/anacrolix/sync v0.5.5-0.20251119100342-d78dd1f686f1 h1:oLCfNgEOR3/Z98mSwmwTM1pcqCDb/1zIjxCNn7dzVaE=
|
||||
github.com/anacrolix/sync v0.5.5-0.20251119100342-d78dd1f686f1/go.mod h1:21cUWerw9eiu/3T3kyoChu37AVO+YFue1/H15qqubS0=
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
||||
github.com/anacrolix/torrent v1.58.1 h1:6FP+KH57b1gyT2CpVL9fEqf9MGJEgh3xw1VA8rI0pW8=
|
||||
github.com/anacrolix/torrent v1.58.1/go.mod h1:/7ZdLuHNKgtCE1gjYJCfbtG9JodBcDaF5ip5EUWRtk8=
|
||||
github.com/anacrolix/torrent v1.61.0 h1:vxo+B4SwnoP5AQWbhvnTYIaTgPSX+llYUVuQVsN4Jg8=
|
||||
github.com/anacrolix/torrent v1.61.0/go.mod h1:yKUKuZSSDdyOsCbuH+rDOpswl/g546gICapdrU7aUmQ=
|
||||
github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U=
|
||||
github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
|
||||
github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI=
|
||||
|
|
@ -299,8 +300,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
|
|||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
|
||||
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8=
|
||||
|
|
@ -328,10 +329,10 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tidwall/btree v1.8.0 h1:kHHy8hSBauQUe0KPHMFLOt0olAj1nDnkHPJhr8+HFkM=
|
||||
github.com/tidwall/btree v1.8.0/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA=
|
||||
github.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
|
|
@ -346,27 +347,25 @@ go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
|
|||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc=
|
||||
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc=
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
|
@ -377,8 +376,8 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
|||
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -396,8 +395,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
|||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
|
@ -411,8 +408,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -436,8 +432,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
|
@ -453,11 +447,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
@ -468,8 +461,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
||||
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
|||
132
go/server.go
132
go/server.go
|
|
@ -33,14 +33,20 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
maxJSONBodyBytes int64 = 1 << 20
|
||||
maxTorrentUploadSize int64 = 100 << 20
|
||||
minStreamReadahead = 1 << 20
|
||||
baseStreamReadahead = 4 << 20
|
||||
maxStreamReadahead = 32 << 20
|
||||
seekBoostThreshold = 4 << 20
|
||||
seekBoostWindow = 32 << 20
|
||||
seekBoostReadahead = 16 << 20
|
||||
maxJSONBodyBytes int64 = 1 << 20
|
||||
maxTorrentUploadSize int64 = 100 << 20
|
||||
minStreamReadahead = 1 << 20
|
||||
baseStreamReadahead = 4 << 20
|
||||
maxStreamReadahead = 32 << 20
|
||||
seekBoostThreshold = 4 << 20
|
||||
seekBoostWindow = 32 << 20
|
||||
seekBoostReadahead = 16 << 20
|
||||
httpConnectTimeout = 5 * time.Second
|
||||
httpKeepAlive = 30 * time.Second
|
||||
httpIdleConnTimeout = 90 * time.Second
|
||||
httpTLSHandshakeTimeout = 5 * time.Second
|
||||
httpResponseHeaderTimeout = 15 * time.Second
|
||||
httpClientTimeout = 45 * time.Second
|
||||
)
|
||||
|
||||
// WorkerPool manages a pool of goroutines for concurrent tasks
|
||||
|
|
@ -140,6 +146,12 @@ func Start(config *Config) (int, error) {
|
|||
|
||||
torrentcliCfg = torrent.NewDefaultClientConfig()
|
||||
torrentcliCfg.DataDir = sanitizedConfig.Path
|
||||
torrentHTTPTransport := newTorrentHTTPTransport()
|
||||
torrentcliCfg.WebTransport = torrentHTTPTransport
|
||||
torrentcliCfg.MetainfoSourcesClient = &http.Client{
|
||||
Transport: torrentHTTPTransport,
|
||||
Timeout: httpClientTimeout,
|
||||
}
|
||||
|
||||
// Performance optimizations
|
||||
torrentcliCfg.DisableUTP = false
|
||||
|
|
@ -147,10 +159,13 @@ func Start(config *Config) (int, error) {
|
|||
torrentcliCfg.NoDefaultPortForwarding = false
|
||||
torrentcliCfg.DisablePEX = false
|
||||
torrentcliCfg.AcceptPeerConnections = true
|
||||
torrentcliCfg.DropDuplicatePeerIds = true
|
||||
torrentcliCfg.EstablishedConnsPerTorrent = 80
|
||||
torrentcliCfg.HalfOpenConnsPerTorrent = 25
|
||||
torrentcliCfg.TorrentPeersHighWater = 200
|
||||
torrentcliCfg.TorrentPeersLowWater = 50
|
||||
torrentcliCfg.HandshakesTimeout = 8 * time.Second
|
||||
torrentcliCfg.PieceHashersPerTorrent = pieceHashersPerTorrent()
|
||||
torrentcliCfg.Seed = false
|
||||
|
||||
log.Printf("[INFO] Download directory: %s", torrentcliCfg.DataDir)
|
||||
|
|
@ -230,6 +245,35 @@ func configureCORS() *cors.Cors {
|
|||
})
|
||||
}
|
||||
|
||||
func pieceHashersPerTorrent() int {
|
||||
workers := runtime.NumCPU() / 2
|
||||
if workers < 2 {
|
||||
workers = 2
|
||||
}
|
||||
if workers > 8 {
|
||||
workers = 8
|
||||
}
|
||||
return workers
|
||||
}
|
||||
|
||||
func newTorrentHTTPTransport() *http.Transport {
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: httpConnectTimeout,
|
||||
KeepAlive: httpKeepAlive,
|
||||
}).DialContext,
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 128,
|
||||
MaxIdleConnsPerHost: 32,
|
||||
MaxConnsPerHost: 64,
|
||||
IdleConnTimeout: httpIdleConnTimeout,
|
||||
TLSHandshakeTimeout: httpTLSHandshakeTimeout,
|
||||
ResponseHeaderTimeout: httpResponseHeaderTimeout,
|
||||
ExpectContinueTimeout: time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
func setupGracefulShutdown(server *http.Server) {
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
|
@ -573,7 +617,7 @@ func getInfoWithTimeout(t *torrent.Torrent, timeout time.Duration) error {
|
|||
}
|
||||
}
|
||||
|
||||
func initMagnet(w http.ResponseWriter, magnet string, alldn, alltr []string) *torrent.Torrent {
|
||||
func initMagnet(w http.ResponseWriter, magnet string, alldn, alltr, sources, webseeds []string) *torrent.Torrent {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(magnet)
|
||||
|
||||
|
|
@ -599,10 +643,70 @@ func initMagnet(w http.ResponseWriter, magnet string, alldn, alltr []string) *to
|
|||
|
||||
// Cache metadata
|
||||
cacheTorrentMetadata(t)
|
||||
applyTorrentFallbacks(t, sources, webseeds)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func normalizeHTTPURLs(values []string) []string {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
urls := make([]string, 0, len(values))
|
||||
seen := make(map[string]struct{}, len(values))
|
||||
for _, value := range values {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
parsedURL, err := url.Parse(value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
|
||||
continue
|
||||
}
|
||||
|
||||
normalizedURL := parsedURL.String()
|
||||
if _, exists := seen[normalizedURL]; exists {
|
||||
continue
|
||||
}
|
||||
seen[normalizedURL] = struct{}{}
|
||||
urls = append(urls, normalizedURL)
|
||||
}
|
||||
|
||||
return urls
|
||||
}
|
||||
|
||||
func applyTorrentFallbacks(t *torrent.Torrent, sources, webseeds []string) {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
|
||||
normalizedSources := normalizeHTTPURLs(sources)
|
||||
if len(normalizedSources) > 0 {
|
||||
t.AddSources(normalizedSources)
|
||||
}
|
||||
|
||||
normalizedWebseeds := normalizeHTTPURLs(webseeds)
|
||||
if len(normalizedWebseeds) > 0 {
|
||||
t.AddWebSeeds(normalizedWebseeds)
|
||||
}
|
||||
}
|
||||
|
||||
func collectTorrentFallbacks(values url.Values) ([]string, []string) {
|
||||
sources := append([]string{}, values["source"]...)
|
||||
sources = append(sources, values["xs"]...)
|
||||
sources = append(sources, values["as"]...)
|
||||
|
||||
webseeds := append([]string{}, values["webseed"]...)
|
||||
webseeds = append(webseeds, values["ws"]...)
|
||||
|
||||
return sources, webseeds
|
||||
}
|
||||
|
||||
func getTorrent(w http.ResponseWriter, infoHash string) *torrent.Torrent {
|
||||
if len(infoHash) != 40 {
|
||||
httpJSONError(w, "InfoHash not valid", http.StatusBadRequest)
|
||||
|
|
@ -750,7 +854,7 @@ func addMagnet(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
t := initMagnet(w, amBody.Magnet, []string{}, []string{})
|
||||
t := initMagnet(w, amBody.Magnet, []string{}, []string{}, amBody.Sources, amBody.Webseeds)
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -824,6 +928,7 @@ func streamTorrent(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
tFile.SetPriority(torrent.PiecePriorityHigh)
|
||||
fileReader := tFile.NewReader()
|
||||
fileReader.SetContext(r.Context())
|
||||
streamReader := configureStreamReader(fileReader, tFile.Length(), r.Header.Get("Range") != "")
|
||||
defer streamReader.Close()
|
||||
|
||||
|
|
@ -1176,6 +1281,7 @@ func AddTorrent(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// Cache metadata
|
||||
cacheTorrentMetadata(torrent)
|
||||
applyTorrentFallbacks(torrent, r.MultipartForm.Value["source"], r.MultipartForm.Value["webseed"])
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte(torrent.InfoHash().HexString()))
|
||||
|
|
@ -1191,6 +1297,7 @@ func playTorrent(w http.ResponseWriter, r *http.Request) {
|
|||
magnet, magOk := r.URL.Query()["magnet"]
|
||||
displayName := r.URL.Query()["dn"]
|
||||
trackers := r.URL.Query()["tr"]
|
||||
sources, webseeds := collectTorrentFallbacks(r.URL.Query())
|
||||
files, fOk := r.URL.Query()["file"]
|
||||
|
||||
if !magOk && !ihOk {
|
||||
|
|
@ -1200,11 +1307,12 @@ func playTorrent(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var t *torrent.Torrent
|
||||
if magOk && !ihOk {
|
||||
t = initMagnet(w, magnet[0], displayName, trackers)
|
||||
t = initMagnet(w, magnet[0], displayName, trackers, sources, webseeds)
|
||||
}
|
||||
|
||||
if ihOk && !magOk {
|
||||
t = getTorrent(w, infoHash[0])
|
||||
applyTorrentFallbacks(t, sources, webseeds)
|
||||
}
|
||||
|
||||
if t == nil {
|
||||
|
|
@ -1244,6 +1352,8 @@ type addMagnetBody struct {
|
|||
Magnet string
|
||||
AllFiles bool
|
||||
Files []string
|
||||
Sources []string
|
||||
Webseeds []string
|
||||
}
|
||||
|
||||
type addMagnetRes struct {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
"io"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
|
@ -15,6 +16,7 @@ type fakeTorrentReader struct {
|
|||
pos int64
|
||||
responsive bool
|
||||
readaheadFunc torrent.ReadaheadFunc
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (f *fakeTorrentReader) Read(p []byte) (int, error) {
|
||||
|
|
@ -38,6 +40,10 @@ func (f *fakeTorrentReader) ReadContext(_ context.Context, p []byte) (int, error
|
|||
return f.Read(p)
|
||||
}
|
||||
|
||||
func (f *fakeTorrentReader) SetContext(ctx context.Context) {
|
||||
f.ctx = ctx
|
||||
}
|
||||
|
||||
func (f *fakeTorrentReader) SetReadahead(_ int64) {}
|
||||
|
||||
func (f *fakeTorrentReader) SetReadaheadFunc(fn torrent.ReadaheadFunc) {
|
||||
|
|
@ -117,6 +123,43 @@ func TestIsAllowedOriginOnlyAcceptsLocalOrigins(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewTorrentHTTPTransportIsTunedForFallbacks(t *testing.T) {
|
||||
transport := newTorrentHTTPTransport()
|
||||
if transport == nil {
|
||||
t.Fatal("expected a transport instance")
|
||||
}
|
||||
if !transport.ForceAttemptHTTP2 {
|
||||
t.Fatal("expected HTTP/2 to be enabled")
|
||||
}
|
||||
if transport.MaxIdleConnsPerHost < 16 {
|
||||
t.Fatalf("expected connection pooling per host, got %d", transport.MaxIdleConnsPerHost)
|
||||
}
|
||||
if transport.ResponseHeaderTimeout != httpResponseHeaderTimeout {
|
||||
t.Fatalf("expected response header timeout %s, got %s", httpResponseHeaderTimeout, transport.ResponseHeaderTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectTorrentFallbacksIncludesLegacyMagnetParams(t *testing.T) {
|
||||
values, err := url.ParseQuery(
|
||||
"magnet=magnet%3A%3Fxt%3Durn%3Abtih%3Aabc123%26dn%3DExample&xs=https%3A%2F%2Fmeta.example%2Fmovie.torrent&as=https%3A%2F%2Fbackup.example%2Fmovie.torrent&ws=https%3A%2F%2Fcdn.example%2Fmovie.mkv&source=https%3A%2F%2Fexplicit.example%2Fmovie.torrent&webseed=https%3A%2F%2Fexplicit-cdn.example%2Fmovie.mkv",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseQuery failed: %v", err)
|
||||
}
|
||||
|
||||
sources, webseeds := collectTorrentFallbacks(values)
|
||||
|
||||
if len(sources) != 3 {
|
||||
t.Fatalf("expected 3 sources, got %d: %#v", len(sources), sources)
|
||||
}
|
||||
if len(webseeds) != 2 {
|
||||
t.Fatalf("expected 2 webseeds, got %d: %#v", len(webseeds), webseeds)
|
||||
}
|
||||
if values.Get("magnet") != "magnet:?xt=urn:btih:abc123&dn=Example" {
|
||||
t.Fatalf("expected magnet payload to stay intact, got %q", values.Get("magnet"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigureStreamReaderBoostsReadaheadAfterLargeSeek(t *testing.T) {
|
||||
fakeReader := &fakeTorrentReader{}
|
||||
streamReader := configureStreamReader(fakeReader, 1<<30, true)
|
||||
|
|
@ -128,6 +171,12 @@ func TestConfigureStreamReaderBoostsReadaheadAfterLargeSeek(t *testing.T) {
|
|||
t.Fatal("expected stream reader to install a readahead function")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
fakeReader.SetContext(ctx)
|
||||
if fakeReader.ctx != ctx {
|
||||
t.Fatal("expected reader context to be stored")
|
||||
}
|
||||
|
||||
baseReadahead := fakeReader.readaheadFunc(torrent.ReadaheadContext{})
|
||||
if _, err := streamReader.Seek(32<<20, io.SeekStart); err != nil {
|
||||
t.Fatalf("seek failed: %v", err)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,20 @@
|
|||
<dict>
|
||||
<key>AvailableLibraries</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>Libmtorrentserver.framework/Libmtorrentserver</string>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>ios-arm64</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>Libmtorrentserver.framework</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>ios</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>Libmtorrentserver.framework/Libmtorrentserver</string>
|
||||
|
|
@ -21,20 +35,6 @@
|
|||
<key>SupportedPlatformVariant</key>
|
||||
<string>simulator</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>Libmtorrentserver.framework/Libmtorrentserver</string>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>ios-arm64</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>Libmtorrentserver.framework</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>ios</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XFWK</string>
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
<key>MinimumOSVersion</key>
|
||||
<string>100.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.1776077599</string>
|
||||
<string>0.0.1776080429</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.0.1776077599</string>
|
||||
<string>0.0.1776080429</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
</dict>
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -9,9 +9,9 @@
|
|||
<key>MinimumOSVersion</key>
|
||||
<string>100.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.1776077599</string>
|
||||
<string>0.0.1776080429</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.0.1776077599</string>
|
||||
<string>0.0.1776080429</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
</dict>
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -11,6 +11,56 @@ import 'package:mangayomi/services/http/m_client.dart';
|
|||
import 'package:mangayomi/utils/extensions/string_extensions.dart';
|
||||
import 'package:mangayomi/ffi/torrent_server_ffi.dart' as libmtorrentserver_ffi;
|
||||
|
||||
String _buildQueryString(Map<String, List<String>> parameters) {
|
||||
final segments = <String>[];
|
||||
parameters.forEach((key, values) {
|
||||
for (final value in values) {
|
||||
segments.add(
|
||||
'${Uri.encodeQueryComponent(key)}=${Uri.encodeQueryComponent(value)}',
|
||||
);
|
||||
}
|
||||
});
|
||||
return segments.join('&');
|
||||
}
|
||||
|
||||
List<String> _normalizeHttpUrls(Iterable<String> values) {
|
||||
final normalized = <String>[];
|
||||
final seen = <String>{};
|
||||
for (final value in values) {
|
||||
final trimmed = value.trim();
|
||||
if (trimmed.isEmpty) continue;
|
||||
final uri = Uri.tryParse(trimmed);
|
||||
if (uri == null) continue;
|
||||
if (uri.scheme != 'http' && uri.scheme != 'https') continue;
|
||||
final normalizedValue = uri.toString();
|
||||
if (seen.add(normalizedValue)) {
|
||||
normalized.add(normalizedValue);
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
(List<String>, List<String>) _extractMagnetFallbacks(String magnetUrl) {
|
||||
final uri = Uri.tryParse(magnetUrl);
|
||||
if (uri == null || uri.scheme != 'magnet') {
|
||||
return (const [], const []);
|
||||
}
|
||||
|
||||
final sources = _normalizeHttpUrls([
|
||||
...uri.queryParametersAll['xs'] ?? const [],
|
||||
...uri.queryParametersAll['as'] ?? const [],
|
||||
]);
|
||||
final webseeds = _normalizeHttpUrls(uri.queryParametersAll['ws'] ?? const []);
|
||||
return (sources, webseeds);
|
||||
}
|
||||
|
||||
List<String> _mergeTorrentFallbacks(
|
||||
Iterable<String> base,
|
||||
Iterable<String> discovered,
|
||||
) {
|
||||
return _normalizeHttpUrls([...base, ...discovered]);
|
||||
}
|
||||
|
||||
class MTorrentServer {
|
||||
final http = MClient.init();
|
||||
Future<bool> removeTorrent(String? inforHash) async {
|
||||
|
|
@ -41,7 +91,12 @@ class MTorrentServer {
|
|||
}
|
||||
}
|
||||
|
||||
Future<String> getInfohash(String url, bool isFilePath) async {
|
||||
Future<String> getInfohash(
|
||||
String url,
|
||||
bool isFilePath, {
|
||||
List<String> sources = const [],
|
||||
List<String> webseeds = const [],
|
||||
}) async {
|
||||
try {
|
||||
final torrentByte = isFilePath
|
||||
? File(url).readAsBytesSync()
|
||||
|
|
@ -54,6 +109,10 @@ class MTorrentServer {
|
|||
request.files.add(
|
||||
MultipartFile.fromBytes('file', torrentByte, filename: 'file.torrent'),
|
||||
);
|
||||
request.fields.addAll({
|
||||
for (final source in sources) 'source': source,
|
||||
for (final webseed in webseeds) 'webseed': webseed,
|
||||
});
|
||||
final response = await http.send(request);
|
||||
return await response.stream.bytesToString();
|
||||
} catch (e) {
|
||||
|
|
@ -63,8 +122,10 @@ class MTorrentServer {
|
|||
|
||||
Future<(List<Video>, String?)> getTorrentPlaylist(
|
||||
String? url,
|
||||
String? archivePath,
|
||||
) async {
|
||||
String? archivePath, {
|
||||
List<String> sources = const [],
|
||||
List<String> webseeds = const [],
|
||||
}) async {
|
||||
try {
|
||||
final isFilePath = archivePath?.isNotEmpty ?? false;
|
||||
final isRunning = await check();
|
||||
|
|
@ -86,13 +147,41 @@ class MTorrentServer {
|
|||
}
|
||||
url = isFilePath ? archivePath! : url!;
|
||||
bool isMagnet = url.startsWith("magnet:?");
|
||||
final magnetFallbacks = _extractMagnetFallbacks(url);
|
||||
final mergedSources = _mergeTorrentFallbacks(sources, magnetFallbacks.$1);
|
||||
final mergedWebseeds = _mergeTorrentFallbacks(
|
||||
webseeds,
|
||||
magnetFallbacks.$2,
|
||||
);
|
||||
final remoteTorrentSources = !isMagnet && !isFilePath
|
||||
? _normalizeHttpUrls([url])
|
||||
: const <String>[];
|
||||
final effectiveSources = _mergeTorrentFallbacks(
|
||||
mergedSources,
|
||||
remoteTorrentSources,
|
||||
);
|
||||
String finalUrl = "";
|
||||
String? infohash;
|
||||
if (!isMagnet) {
|
||||
infohash = await getInfohash(url, isFilePath);
|
||||
finalUrl = "$_baseUrl/torrent/play?infohash=$infohash";
|
||||
infohash = await getInfohash(
|
||||
url,
|
||||
isFilePath,
|
||||
sources: effectiveSources,
|
||||
webseeds: mergedWebseeds,
|
||||
);
|
||||
finalUrl =
|
||||
'$_baseUrl/torrent/play?${_buildQueryString({
|
||||
'infohash': [infohash],
|
||||
if (effectiveSources.isNotEmpty) 'source': effectiveSources,
|
||||
if (mergedWebseeds.isNotEmpty) 'webseed': mergedWebseeds,
|
||||
})}';
|
||||
} else {
|
||||
finalUrl = "$_baseUrl/torrent/play?magnet=$url";
|
||||
finalUrl =
|
||||
'$_baseUrl/torrent/play?${_buildQueryString({
|
||||
'magnet': [url],
|
||||
if (effectiveSources.isNotEmpty) 'source': effectiveSources,
|
||||
if (mergedWebseeds.isNotEmpty) 'webseed': mergedWebseeds,
|
||||
})}';
|
||||
}
|
||||
|
||||
final masterPlaylist = (await http.get(Uri.parse(finalUrl))).body;
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in a new issue