Update On Thu Dec 12 11:41:03 CET 2024

This commit is contained in:
github-action[bot]
2024-12-12 11:41:03 +01:00
parent 82ec12ec72
commit 767320b3c9
407 changed files with 10588 additions and 10839 deletions
+1
View File
@@ -848,3 +848,4 @@ Update On Wed Dec 4 19:40:09 CET 2024
Update On Thu Dec 5 19:36:56 CET 2024
Update On Fri Dec 6 19:37:02 CET 2024
Update On Sat Dec 7 19:36:20 CET 2024
Update On Thu Dec 12 11:40:54 CET 2024
+8
View File
@@ -366,3 +366,11 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# debug log
debug_*.json
# dotnet run in `BBDown/` sub folder
/BBDown/*.mp4
/BBDown/*.xml
/BBDown/*.ass
+4 -1
View File
@@ -9,6 +9,7 @@ using static BBDown.Core.Util.SubUtil;
using static BBDown.Core.Logger;
using System.IO;
using BBDown.Core;
using System.Runtime.InteropServices;
namespace BBDown;
@@ -96,7 +97,7 @@ static partial class BBDownMuxer
return RunExe(MP4BOX, arguments, MP4BOX != "mp4box");
}
public static int MuxAV(bool useMp4box, string bvid, string videoPath, string audioPath, List<AudioMaterial> audioMaterial, string outPath, string desc = "", string title = "", string author = "", string episodeId = "", string pic = "", string lang = "", List<Subtitle>? subs = null, bool audioOnly = false, bool videoOnly = false, List<ViewPoint>? points = null, long pubTime = 0, bool simplyMux = false)
public static int MuxAV(bool useMp4box, string bvid, string videoPath, string audioPath, List<AudioMaterial> audioMaterial, string outPath, string desc = "", string title = "", string author = "", string episodeId = "", string pic = "", string lang = "", List<Subtitle>? subs = null, bool audioOnly = false, bool videoOnly = false, List<ViewPoint>? points = null, long pubTime = 0, bool simplyMux = false, bool isHevc = false)
{
if (audioOnly && audioPath != "")
videoPath = "";
@@ -191,6 +192,8 @@ static partial class BBDownMuxer
argsBuilder.Append("-c copy ");
if (audioOnly && audioPath == "") argsBuilder.Append("-vn ");
if (subs != null) argsBuilder.Append("-c:s mov_text ");
// fix macOS hev1, see https://discussions.apple.com/thread/253081863?sortBy=rank
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && isHevc) argsBuilder.Append("-tag:v:0 hvc1 ");
argsBuilder.Append($"-movflags faststart -strict unofficial -strict -2 -f mp4 -- \"{outPath}\"");
string arguments = argsBuilder.ToString();
+3 -1
View File
@@ -669,6 +669,8 @@ partial class Program
Log($"开始合并音视频{(subtitleInfo.Any() ? "" : "")}...");
if (myOption.AudioOnly)
savePath = savePath[..^4] + ".m4a";
var isHevc = selectedVideo?.codecs == "HEVC";
int code = BBDownMuxer.MuxAV(myOption.UseMP4box, p.bvid, videoPath, audioPath, audioMaterial, savePath,
desc,
title,
@@ -676,7 +678,7 @@ partial class Program
(pagesCount > 1 || (bangumi && !vInfo.IsBangumiEnd)) ? p.title : "",
File.Exists(coverPath) ? coverPath : "",
lang,
subtitleInfo, myOption.AudioOnly, myOption.VideoOnly, p.points, p.pubTime, myOption.SimplyMux);
subtitleInfo, myOption.AudioOnly, myOption.VideoOnly, p.points, p.pubTime, myOption.SimplyMux, isHevc);
if (code != 0 || !File.Exists(savePath) || new FileInfo(savePath).Length == 0)
{
LogError("合并失败"); return;
+1 -1
View File
@@ -53,7 +53,7 @@ func main() {
df := func() {}
app := cli.NewApp()
app.Name = "Brook"
app.Version = "20240606"
app.Version = "20250202"
app.Usage = "A cross-platform programmable network tool"
app.Authors = []*cli.Author{
{
+15 -13
View File
@@ -1,6 +1,8 @@
module github.com/txthinking/brook
go 1.21.5
go 1.22
toolchain go1.23.0
require (
github.com/gorilla/mux v1.8.1
@@ -9,8 +11,8 @@ require (
github.com/miekg/dns v1.1.57
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/phuslu/iploc v1.0.20240501
github.com/prometheus/client_golang v1.17.0
github.com/quic-go/quic-go v0.42.0
github.com/prometheus/client_golang v1.19.1
github.com/quic-go/quic-go v0.48.2
github.com/refraction-networking/utls v1.5.4
github.com/tdewolff/minify v2.3.6+incompatible
github.com/txthinking/runnergroup v0.0.0-20230325130830-408dc5853f86
@@ -18,8 +20,8 @@ require (
github.com/txthinking/x v0.0.0-20240301021728-6f68aba84c87
github.com/urfave/cli/v2 v2.25.7
github.com/urfave/negroni v1.0.0
golang.org/x/crypto v0.22.0
golang.org/x/net v0.24.0
golang.org/x/crypto v0.26.0
golang.org/x/net v0.28.0
)
require (
@@ -35,18 +37,18 @@ require (
github.com/klauspost/compress v1.16.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/tdewolff/parse v2.3.4+incompatible // indirect
github.com/tdewolff/test v1.0.10 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.13.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
+26
View File
@@ -57,14 +57,24 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/refraction-networking/utls v1.5.4 h1:9k6EO2b8TaOGsQ7Pl7p9w6PUhx18/ZCeT0WNTZ7Uw4o=
github.com/refraction-networking/utls v1.5.4/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
@@ -72,6 +82,7 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
@@ -100,12 +111,18 @@ golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -114,12 +131,15 @@ golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -131,6 +151,8 @@ golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -140,6 +162,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -148,6 +172,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+4 -4
View File
@@ -1,7 +1,7 @@
{
"version": "20240606",
"text": "brook-store: an open source store for some people",
"link": "https://github.com/TxThinkingInc/brook-store",
"text_zh": "YouTube: 为什么当我们谈到种族歧视时,普遍被歧视的是指黑色或黄色人种?",
"link_zh": "https://www.youtube.com/watch?v=7T_jwMGuZ_I"
"text": "Zhi - A Truely End-to-End Encrypted Instant Messaging App",
"link": "https://www.txthinking.com/zhi.html",
"text_zh": "纸,一个真正的端到端加密的聊天应用",
"link_zh": "https://www.txthinking.com/zhi.html"
}
@@ -0,0 +1,268 @@
package outbound
import (
"context"
"fmt"
"net"
"runtime"
"strconv"
"sync"
mieruclient "github.com/enfein/mieru/v3/apis/client"
mierumodel "github.com/enfein/mieru/v3/apis/model"
mierupb "github.com/enfein/mieru/v3/pkg/appctl/appctlpb"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"google.golang.org/protobuf/proto"
)
type Mieru struct {
*Base
option *MieruOption
client mieruclient.Client
mu sync.Mutex
}
type MieruOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port,omitempty"`
PortRange string `proxy:"port-range,omitempty"`
Transport string `proxy:"transport"`
UserName string `proxy:"username"`
Password string `proxy:"password"`
}
// DialContext implements C.ProxyAdapter
func (m *Mieru) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
if err := m.ensureClientIsRunning(opts...); err != nil {
return nil, err
}
addr := metadataToMieruNetAddrSpec(metadata)
c, err := m.client.DialContext(ctx, addr)
if err != nil {
return nil, fmt.Errorf("dial to %s failed: %w", addr, err)
}
return NewConn(c, m), nil
}
// ProxyInfo implements C.ProxyAdapter
func (m *Mieru) ProxyInfo() C.ProxyInfo {
info := m.Base.ProxyInfo()
info.DialerProxy = m.option.DialerProxy
return info
}
func (m *Mieru) ensureClientIsRunning(opts ...dialer.Option) error {
m.mu.Lock()
defer m.mu.Unlock()
if m.client.IsRunning() {
return nil
}
// Create a dialer and add it to the client config, before starting the client.
var dialer C.Dialer = dialer.NewDialer(m.Base.DialOptions(opts...)...)
var err error
if len(m.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(m.option.DialerProxy, dialer)
if err != nil {
return err
}
}
config, err := m.client.Load()
if err != nil {
return err
}
config.Dialer = dialer
if err := m.client.Store(config); err != nil {
return err
}
if err := m.client.Start(); err != nil {
return fmt.Errorf("failed to start mieru client: %w", err)
}
return nil
}
func NewMieru(option MieruOption) (*Mieru, error) {
config, err := buildMieruClientConfig(option)
if err != nil {
return nil, fmt.Errorf("failed to build mieru client config: %w", err)
}
c := mieruclient.NewClient()
if err := c.Store(config); err != nil {
return nil, fmt.Errorf("failed to store mieru client config: %w", err)
}
// Client is started lazily on the first use.
var addr string
if option.Port != 0 {
addr = net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
} else {
beginPort, _, _ := beginAndEndPortFromPortRange(option.PortRange)
addr = net.JoinHostPort(option.Server, strconv.Itoa(beginPort))
}
outbound := &Mieru{
Base: &Base{
name: option.Name,
addr: addr,
iface: option.Interface,
tp: C.Mieru,
udp: false,
xudp: false,
rmark: option.RoutingMark,
prefer: C.NewDNSPrefer(option.IPVersion),
},
option: &option,
client: c,
}
runtime.SetFinalizer(outbound, closeMieru)
return outbound, nil
}
func closeMieru(m *Mieru) {
m.mu.Lock()
defer m.mu.Unlock()
if m.client != nil && m.client.IsRunning() {
m.client.Stop()
}
}
func metadataToMieruNetAddrSpec(metadata *C.Metadata) mierumodel.NetAddrSpec {
if metadata.Host != "" {
return mierumodel.NetAddrSpec{
AddrSpec: mierumodel.AddrSpec{
FQDN: metadata.Host,
Port: int(metadata.DstPort),
},
Net: "tcp",
}
} else {
return mierumodel.NetAddrSpec{
AddrSpec: mierumodel.AddrSpec{
IP: metadata.DstIP.AsSlice(),
Port: int(metadata.DstPort),
},
Net: "tcp",
}
}
}
func buildMieruClientConfig(option MieruOption) (*mieruclient.ClientConfig, error) {
if err := validateMieruOption(option); err != nil {
return nil, fmt.Errorf("failed to validate mieru option: %w", err)
}
transportProtocol := mierupb.TransportProtocol_TCP.Enum()
var server *mierupb.ServerEndpoint
if net.ParseIP(option.Server) != nil {
// server is an IP address
if option.PortRange != "" {
server = &mierupb.ServerEndpoint{
IpAddress: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
PortRange: proto.String(option.PortRange),
Protocol: transportProtocol,
},
},
}
} else {
server = &mierupb.ServerEndpoint{
IpAddress: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
Port: proto.Int32(int32(option.Port)),
Protocol: transportProtocol,
},
},
}
}
} else {
// server is a domain name
if option.PortRange != "" {
server = &mierupb.ServerEndpoint{
DomainName: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
PortRange: proto.String(option.PortRange),
Protocol: transportProtocol,
},
},
}
} else {
server = &mierupb.ServerEndpoint{
DomainName: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
Port: proto.Int32(int32(option.Port)),
Protocol: transportProtocol,
},
},
}
}
}
return &mieruclient.ClientConfig{
Profile: &mierupb.ClientProfile{
ProfileName: proto.String(option.Name),
User: &mierupb.User{
Name: proto.String(option.UserName),
Password: proto.String(option.Password),
},
Servers: []*mierupb.ServerEndpoint{server},
},
}, nil
}
func validateMieruOption(option MieruOption) error {
if option.Name == "" {
return fmt.Errorf("name is empty")
}
if option.Server == "" {
return fmt.Errorf("server is empty")
}
if option.Port == 0 && option.PortRange == "" {
return fmt.Errorf("either port or port-range must be set")
}
if option.Port != 0 && option.PortRange != "" {
return fmt.Errorf("port and port-range cannot be set at the same time")
}
if option.Port != 0 && (option.Port < 1 || option.Port > 65535) {
return fmt.Errorf("port must be between 1 and 65535")
}
if option.PortRange != "" {
begin, end, err := beginAndEndPortFromPortRange(option.PortRange)
if err != nil {
return fmt.Errorf("invalid port-range format")
}
if begin < 1 || begin > 65535 {
return fmt.Errorf("begin port must be between 1 and 65535")
}
if end < 1 || end > 65535 {
return fmt.Errorf("end port must be between 1 and 65535")
}
if begin > end {
return fmt.Errorf("begin port must be less than or equal to end port")
}
}
if option.Transport != "TCP" {
return fmt.Errorf("transport must be TCP")
}
if option.UserName == "" {
return fmt.Errorf("username is empty")
}
if option.Password == "" {
return fmt.Errorf("password is empty")
}
return nil
}
func beginAndEndPortFromPortRange(portRange string) (int, int, error) {
var begin, end int
_, err := fmt.Sscanf(portRange, "%d-%d", &begin, &end)
return begin, end, err
}
@@ -0,0 +1,92 @@
package outbound
import "testing"
func TestNewMieru(t *testing.T) {
testCases := []struct {
option MieruOption
wantBaseAddr string
}{
{
option: MieruOption{
Name: "test",
Server: "1.2.3.4",
Port: 10000,
Transport: "TCP",
UserName: "test",
Password: "test",
},
wantBaseAddr: "1.2.3.4:10000",
},
{
option: MieruOption{
Name: "test",
Server: "2001:db8::1",
PortRange: "10001-10002",
Transport: "TCP",
UserName: "test",
Password: "test",
},
wantBaseAddr: "[2001:db8::1]:10001",
},
{
option: MieruOption{
Name: "test",
Server: "example.com",
Port: 10003,
Transport: "TCP",
UserName: "test",
Password: "test",
},
wantBaseAddr: "example.com:10003",
},
}
for _, testCase := range testCases {
mieru, err := NewMieru(testCase.option)
if err != nil {
t.Error(err)
}
if mieru.addr != testCase.wantBaseAddr {
t.Errorf("got addr %q, want %q", mieru.addr, testCase.wantBaseAddr)
}
}
}
func TestBeginAndEndPortFromPortRange(t *testing.T) {
testCases := []struct {
input string
begin int
end int
hasErr bool
}{
{"1-10", 1, 10, false},
{"1000-2000", 1000, 2000, false},
{"65535-65535", 65535, 65535, false},
{"1", 0, 0, true},
{"1-", 0, 0, true},
{"-10", 0, 0, true},
{"a-b", 0, 0, true},
{"1-b", 0, 0, true},
{"a-10", 0, 0, true},
}
for _, testCase := range testCases {
begin, end, err := beginAndEndPortFromPortRange(testCase.input)
if testCase.hasErr {
if err == nil {
t.Errorf("beginAndEndPortFromPortRange(%s) should return an error", testCase.input)
}
} else {
if err != nil {
t.Errorf("beginAndEndPortFromPortRange(%s) should not return an error, but got %v", testCase.input, err)
}
if begin != testCase.begin {
t.Errorf("beginAndEndPortFromPortRange(%s) begin port mismatch, got %d, want %d", testCase.input, begin, testCase.begin)
}
if end != testCase.end {
t.Errorf("beginAndEndPortFromPortRange(%s) end port mismatch, got %d, want %d", testCase.input, end, testCase.end)
}
}
}
}
@@ -141,6 +141,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
break
}
proxy, err = outbound.NewSsh(*sshOption)
case "mieru":
mieruOption := &outbound.MieruOption{}
err = decoder.Decode(mapping, mieruOption)
if err != nil {
break
}
proxy, err = outbound.NewMieru(*mieruOption)
default:
return nil, fmt.Errorf("unsupport proxy type: %s", proxyType)
}
@@ -42,6 +42,7 @@ const (
WireGuard
Tuic
Ssh
Mieru
)
const (
@@ -226,7 +227,8 @@ func (at AdapterType) String() string {
return "Tuic"
case Ssh:
return "Ssh"
case Mieru:
return "Mieru"
case Relay:
return "Relay"
case Selector:
@@ -846,6 +846,16 @@ proxies: # socks5
password: password
privateKey: path
# mieru
- name: mieru
type: mieru
server: 1.2.3.4
port: 2999
# port-range: 2090-2099 #(不可同时填写 port 和 port-range
transport: TCP # 只支持 TCP
username: user
password: password
# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理
- name: "dns-out"
type: dns
@@ -1202,4 +1212,4 @@ listeners:
# authentication-timeout: 1000
# alpn:
# - h3
# max-udp-relay-packet-size: 1500
# max-udp-relay-packet-size: 1500
@@ -7,6 +7,7 @@ require (
github.com/bahlo/generic-list-go v0.2.0
github.com/coreos/go-iptables v0.8.0
github.com/dlclark/regexp2 v1.11.4
github.com/enfein/mieru/v3 v3.8.3
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/render v1.0.3
github.com/gobwas/ws v1.4.0
@@ -114,6 +115,8 @@ require (
golang.org/x/text v0.20.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect
google.golang.org/grpc v1.64.1 // indirect
)
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20241121030428-33b6ebc52000
@@ -27,6 +27,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/enfein/mieru/v3 v3.8.3 h1:s4K0hMFDg6LHltokR8/nBTVCq15XnnxPsvc1LrHwpoo=
github.com/enfein/mieru/v3 v3.8.3/go.mod h1:YtU00qjAEt54mCBQu4WZPCey6cBdB1BUtXjvrHLEUNQ=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -59,7 +61,7 @@ github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakr
github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk=
github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -274,6 +276,10 @@ golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 h1:9Xyg6I9IWQZhRVfCWjKK+l6kI0jHcPesVlMnT//aHNo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -15,6 +15,7 @@ require (
github.com/cloudflare/circl v1.3.7 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/enfein/mieru/v3 v3.8.3 // indirect
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
@@ -106,6 +107,8 @@ require (
golang.org/x/text v0.20.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect
google.golang.org/grpc v1.64.1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
@@ -26,6 +26,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/enfein/mieru/v3 v3.8.3 h1:s4K0hMFDg6LHltokR8/nBTVCq15XnnxPsvc1LrHwpoo=
github.com/enfein/mieru/v3 v3.8.3/go.mod h1:YtU00qjAEt54mCBQu4WZPCey6cBdB1BUtXjvrHLEUNQ=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -58,7 +60,7 @@ github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakr
github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk=
github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -267,6 +269,10 @@ golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 h1:9Xyg6I9IWQZhRVfCWjKK+l6kI0jHcPesVlMnT//aHNo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
@@ -23,6 +23,7 @@ require (
github.com/buger/jsonparser v1.1.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/enfein/mieru/v3 v3.8.3 // indirect
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
@@ -112,6 +113,8 @@ require (
golang.org/x/text v0.20.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect
google.golang.org/grpc v1.64.1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
)
@@ -26,6 +26,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/enfein/mieru/v3 v3.8.3 h1:s4K0hMFDg6LHltokR8/nBTVCq15XnnxPsvc1LrHwpoo=
github.com/enfein/mieru/v3 v3.8.3/go.mod h1:YtU00qjAEt54mCBQu4WZPCey6cBdB1BUtXjvrHLEUNQ=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -58,7 +60,7 @@ github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakr
github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk=
github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -267,6 +269,10 @@ golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 h1:9Xyg6I9IWQZhRVfCWjKK+l6kI0jHcPesVlMnT//aHNo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+281
View File
@@ -0,0 +1,281 @@
package outbound
import (
"context"
"fmt"
"net"
"runtime"
"strconv"
"sync"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
mieruclient "github.com/enfein/mieru/v3/apis/client"
mierumodel "github.com/enfein/mieru/v3/apis/model"
mierupb "github.com/enfein/mieru/v3/pkg/appctl/appctlpb"
"google.golang.org/protobuf/proto"
)
type Mieru struct {
*Base
option *MieruOption
client mieruclient.Client
mu sync.Mutex
}
type MieruOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port,omitempty"`
PortRange string `proxy:"port-range,omitempty"`
Transport string `proxy:"transport"`
UserName string `proxy:"username"`
Password string `proxy:"password"`
Multiplexing string `proxy:"multiplexing,omitempty"`
}
// DialContext implements C.ProxyAdapter
func (m *Mieru) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
if err := m.ensureClientIsRunning(opts...); err != nil {
return nil, err
}
addr := metadataToMieruNetAddrSpec(metadata)
c, err := m.client.DialContext(ctx, addr)
if err != nil {
return nil, fmt.Errorf("dial to %s failed: %w", addr, err)
}
return NewConn(c, m), nil
}
// ProxyInfo implements C.ProxyAdapter
func (m *Mieru) ProxyInfo() C.ProxyInfo {
info := m.Base.ProxyInfo()
info.DialerProxy = m.option.DialerProxy
return info
}
func (m *Mieru) ensureClientIsRunning(opts ...dialer.Option) error {
m.mu.Lock()
defer m.mu.Unlock()
if m.client.IsRunning() {
return nil
}
// Create a dialer and add it to the client config, before starting the client.
var dialer C.Dialer = dialer.NewDialer(m.Base.DialOptions(opts...)...)
var err error
if len(m.option.DialerProxy) > 0 {
dialer, err = proxydialer.NewByName(m.option.DialerProxy, dialer)
if err != nil {
return err
}
}
config, err := m.client.Load()
if err != nil {
return err
}
config.Dialer = dialer
if err := m.client.Store(config); err != nil {
return err
}
if err := m.client.Start(); err != nil {
return fmt.Errorf("failed to start mieru client: %w", err)
}
return nil
}
func NewMieru(option MieruOption) (*Mieru, error) {
config, err := buildMieruClientConfig(option)
if err != nil {
return nil, fmt.Errorf("failed to build mieru client config: %w", err)
}
c := mieruclient.NewClient()
if err := c.Store(config); err != nil {
return nil, fmt.Errorf("failed to store mieru client config: %w", err)
}
// Client is started lazily on the first use.
var addr string
if option.Port != 0 {
addr = net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
} else {
beginPort, _, _ := beginAndEndPortFromPortRange(option.PortRange)
addr = net.JoinHostPort(option.Server, strconv.Itoa(beginPort))
}
outbound := &Mieru{
Base: &Base{
name: option.Name,
addr: addr,
iface: option.Interface,
tp: C.Mieru,
udp: false,
xudp: false,
rmark: option.RoutingMark,
prefer: C.NewDNSPrefer(option.IPVersion),
},
option: &option,
client: c,
}
runtime.SetFinalizer(outbound, closeMieru)
return outbound, nil
}
func closeMieru(m *Mieru) {
m.mu.Lock()
defer m.mu.Unlock()
if m.client != nil && m.client.IsRunning() {
m.client.Stop()
}
}
func metadataToMieruNetAddrSpec(metadata *C.Metadata) mierumodel.NetAddrSpec {
if metadata.Host != "" {
return mierumodel.NetAddrSpec{
AddrSpec: mierumodel.AddrSpec{
FQDN: metadata.Host,
Port: int(metadata.DstPort),
},
Net: "tcp",
}
} else {
return mierumodel.NetAddrSpec{
AddrSpec: mierumodel.AddrSpec{
IP: metadata.DstIP.AsSlice(),
Port: int(metadata.DstPort),
},
Net: "tcp",
}
}
}
func buildMieruClientConfig(option MieruOption) (*mieruclient.ClientConfig, error) {
if err := validateMieruOption(option); err != nil {
return nil, fmt.Errorf("failed to validate mieru option: %w", err)
}
transportProtocol := mierupb.TransportProtocol_TCP.Enum()
var server *mierupb.ServerEndpoint
if net.ParseIP(option.Server) != nil {
// server is an IP address
if option.PortRange != "" {
server = &mierupb.ServerEndpoint{
IpAddress: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
PortRange: proto.String(option.PortRange),
Protocol: transportProtocol,
},
},
}
} else {
server = &mierupb.ServerEndpoint{
IpAddress: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
Port: proto.Int32(int32(option.Port)),
Protocol: transportProtocol,
},
},
}
}
} else {
// server is a domain name
if option.PortRange != "" {
server = &mierupb.ServerEndpoint{
DomainName: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
PortRange: proto.String(option.PortRange),
Protocol: transportProtocol,
},
},
}
} else {
server = &mierupb.ServerEndpoint{
DomainName: proto.String(option.Server),
PortBindings: []*mierupb.PortBinding{
{
Port: proto.Int32(int32(option.Port)),
Protocol: transportProtocol,
},
},
}
}
}
config := &mieruclient.ClientConfig{
Profile: &mierupb.ClientProfile{
ProfileName: proto.String(option.Name),
User: &mierupb.User{
Name: proto.String(option.UserName),
Password: proto.String(option.Password),
},
Servers: []*mierupb.ServerEndpoint{server},
},
}
if multiplexing, ok := mierupb.MultiplexingLevel_value[option.Multiplexing]; ok {
config.Profile.Multiplexing = &mierupb.MultiplexingConfig{
Level: mierupb.MultiplexingLevel(multiplexing).Enum(),
}
}
return config, nil
}
func validateMieruOption(option MieruOption) error {
if option.Name == "" {
return fmt.Errorf("name is empty")
}
if option.Server == "" {
return fmt.Errorf("server is empty")
}
if option.Port == 0 && option.PortRange == "" {
return fmt.Errorf("either port or port-range must be set")
}
if option.Port != 0 && option.PortRange != "" {
return fmt.Errorf("port and port-range cannot be set at the same time")
}
if option.Port != 0 && (option.Port < 1 || option.Port > 65535) {
return fmt.Errorf("port must be between 1 and 65535")
}
if option.PortRange != "" {
begin, end, err := beginAndEndPortFromPortRange(option.PortRange)
if err != nil {
return fmt.Errorf("invalid port-range format")
}
if begin < 1 || begin > 65535 {
return fmt.Errorf("begin port must be between 1 and 65535")
}
if end < 1 || end > 65535 {
return fmt.Errorf("end port must be between 1 and 65535")
}
if begin > end {
return fmt.Errorf("begin port must be less than or equal to end port")
}
}
if option.Transport != "TCP" {
return fmt.Errorf("transport must be TCP")
}
if option.UserName == "" {
return fmt.Errorf("username is empty")
}
if option.Password == "" {
return fmt.Errorf("password is empty")
}
if option.Multiplexing != "" {
if _, ok := mierupb.MultiplexingLevel_value[option.Multiplexing]; !ok {
return fmt.Errorf("invalid multiplexing level: %s", option.Multiplexing)
}
}
return nil
}
func beginAndEndPortFromPortRange(portRange string) (int, int, error) {
var begin, end int
_, err := fmt.Sscanf(portRange, "%d-%d", &begin, &end)
return begin, end, err
}
+92
View File
@@ -0,0 +1,92 @@
package outbound
import "testing"
func TestNewMieru(t *testing.T) {
testCases := []struct {
option MieruOption
wantBaseAddr string
}{
{
option: MieruOption{
Name: "test",
Server: "1.2.3.4",
Port: 10000,
Transport: "TCP",
UserName: "test",
Password: "test",
},
wantBaseAddr: "1.2.3.4:10000",
},
{
option: MieruOption{
Name: "test",
Server: "2001:db8::1",
PortRange: "10001-10002",
Transport: "TCP",
UserName: "test",
Password: "test",
},
wantBaseAddr: "[2001:db8::1]:10001",
},
{
option: MieruOption{
Name: "test",
Server: "example.com",
Port: 10003,
Transport: "TCP",
UserName: "test",
Password: "test",
},
wantBaseAddr: "example.com:10003",
},
}
for _, testCase := range testCases {
mieru, err := NewMieru(testCase.option)
if err != nil {
t.Error(err)
}
if mieru.addr != testCase.wantBaseAddr {
t.Errorf("got addr %q, want %q", mieru.addr, testCase.wantBaseAddr)
}
}
}
func TestBeginAndEndPortFromPortRange(t *testing.T) {
testCases := []struct {
input string
begin int
end int
hasErr bool
}{
{"1-10", 1, 10, false},
{"1000-2000", 1000, 2000, false},
{"65535-65535", 65535, 65535, false},
{"1", 0, 0, true},
{"1-", 0, 0, true},
{"-10", 0, 0, true},
{"a-b", 0, 0, true},
{"1-b", 0, 0, true},
{"a-10", 0, 0, true},
}
for _, testCase := range testCases {
begin, end, err := beginAndEndPortFromPortRange(testCase.input)
if testCase.hasErr {
if err == nil {
t.Errorf("beginAndEndPortFromPortRange(%s) should return an error", testCase.input)
}
} else {
if err != nil {
t.Errorf("beginAndEndPortFromPortRange(%s) should not return an error, but got %v", testCase.input, err)
}
if begin != testCase.begin {
t.Errorf("beginAndEndPortFromPortRange(%s) begin port mismatch, got %d, want %d", testCase.input, begin, testCase.begin)
}
if end != testCase.end {
t.Errorf("beginAndEndPortFromPortRange(%s) end port mismatch, got %d, want %d", testCase.input, end, testCase.end)
}
}
}
}
+7
View File
@@ -141,6 +141,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
break
}
proxy, err = outbound.NewSsh(*sshOption)
case "mieru":
mieruOption := &outbound.MieruOption{}
err = decoder.Decode(mapping, mieruOption)
if err != nil {
break
}
proxy, err = outbound.NewMieru(*mieruOption)
default:
return nil, fmt.Errorf("unsupport proxy type: %s", proxyType)
}
+1 -1
View File
@@ -146,7 +146,7 @@ func (sd *Dispatcher) Enable() bool {
func (sd *Dispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metadata) (string, error) {
for s := range sd.sniffers {
if s.SupportNetwork() == C.TCP {
if s.SupportNetwork() == C.TCP && s.SupportPort(metadata.DstPort) {
_ = conn.SetReadDeadline(time.Now().Add(1 * time.Second))
_, err := conn.Peek(1)
_ = conn.SetReadDeadline(time.Time{})
+3 -1
View File
@@ -42,6 +42,7 @@ const (
WireGuard
Tuic
Ssh
Mieru
)
const (
@@ -226,7 +227,8 @@ func (at AdapterType) String() string {
return "Tuic"
case Ssh:
return "Ssh"
case Mieru:
return "Mieru"
case Relay:
return "Relay"
case Selector:
+13 -1
View File
@@ -846,6 +846,18 @@ proxies: # socks5
password: password
privateKey: path
# mieru
- name: mieru
type: mieru
server: 1.2.3.4
port: 2999
# port-range: 2090-2099 #(不可同时填写 port 和 port-range
transport: TCP # 只支持 TCP
username: user
password: password
# 可以使用的值包括 MULTIPLEXING_OFF, MULTIPLEXING_LOW, MULTIPLEXING_MIDDLE, MULTIPLEXING_HIGH。其中 MULTIPLEXING_OFF 会关闭多路复用功能。默认值为 MULTIPLEXING_LOW。
# multiplexing: MULTIPLEXING_LOW
# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理
- name: "dns-out"
type: dns
@@ -1202,4 +1214,4 @@ listeners:
# authentication-timeout: 1000
# alpn:
# - h3
# max-udp-relay-packet-size: 1500
# max-udp-relay-packet-size: 1500
+1
View File
@@ -7,6 +7,7 @@ require (
github.com/bahlo/generic-list-go v0.2.0
github.com/coreos/go-iptables v0.8.0
github.com/dlclark/regexp2 v1.11.4
github.com/enfein/mieru/v3 v3.8.4
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/render v1.0.3
github.com/gobwas/ws v1.4.0
+2
View File
@@ -27,6 +27,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/enfein/mieru/v3 v3.8.4 h1:PmBQykuEcl8yKcQ647pg8Qbjl433CRYgUbW6VLBgGn4=
github.com/enfein/mieru/v3 v3.8.4/go.mod h1:YtU00qjAEt54mCBQu4WZPCey6cBdB1BUtXjvrHLEUNQ=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
+8
View File
@@ -5,6 +5,7 @@ import (
"encoding/base64"
"flag"
"fmt"
"io"
"net"
"os"
"os/signal"
@@ -99,6 +100,13 @@ func main() {
log.Fatalln("Initial configuration error: %s", err.Error())
return
}
} else if configFile == "-" {
var err error
configBytes, err = io.ReadAll(os.Stdin)
if err != nil {
log.Fatalln("Initial configuration error: %s", err.Error())
return
}
} else {
if configFile != "" {
if !filepath.IsAbs(configFile) {
+23 -23
View File
@@ -683,7 +683,7 @@ version = "0.5.0"
source = "git+https://github.com/libnyanpasu/auto-launch.git#729d5429dd689067047489af4a0a32f7013854c8"
dependencies = [
"dirs 5.0.1",
"thiserror 2.0.4",
"thiserror 2.0.6",
"windows-registry 0.3.0",
"windows-result 0.2.0",
]
@@ -1397,9 +1397,9 @@ dependencies = [
[[package]]
name = "chrono"
version = "0.4.38"
version = "0.4.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -1573,7 +1573,7 @@ dependencies = [
"tauri-plugin-updater",
"tempfile",
"test-log",
"thiserror 2.0.4",
"thiserror 2.0.6",
"timeago",
"tokio",
"tracing",
@@ -6708,7 +6708,7 @@ dependencies = [
"rustc-hash 2.1.0",
"rustls",
"socket2",
"thiserror 2.0.4",
"thiserror 2.0.6",
"tokio",
"tracing",
]
@@ -6727,7 +6727,7 @@ dependencies = [
"rustls",
"rustls-pki-types",
"slab",
"thiserror 2.0.4",
"thiserror 2.0.6",
"tinyvec",
"tracing",
"web-time",
@@ -7522,9 +7522,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4"
[[package]]
name = "serde"
version = "1.0.215"
version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
dependencies = [
"serde_derive",
]
@@ -7552,9 +7552,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.215"
version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
dependencies = [
"proc-macro2",
"quote",
@@ -8425,7 +8425,7 @@ dependencies = [
"tauri-runtime",
"tauri-runtime-wry",
"tauri-utils",
"thiserror 2.0.4",
"thiserror 2.0.6",
"tokio",
"tray-icon",
"url",
@@ -8478,7 +8478,7 @@ dependencies = [
"sha2 0.10.8",
"syn 2.0.90",
"tauri-utils",
"thiserror 2.0.4",
"thiserror 2.0.6",
"time",
"url",
"uuid",
@@ -8560,7 +8560,7 @@ dependencies = [
"tauri",
"tauri-plugin",
"tauri-plugin-fs",
"thiserror 2.0.4",
"thiserror 2.0.6",
"url",
]
@@ -8581,7 +8581,7 @@ dependencies = [
"tauri",
"tauri-plugin",
"tauri-utils",
"thiserror 2.0.4",
"thiserror 2.0.6",
"toml 0.8.19",
"url",
"uuid",
@@ -8692,7 +8692,7 @@ dependencies = [
"tauri",
"tauri-plugin",
"tempfile",
"thiserror 2.0.4",
"thiserror 2.0.6",
"time",
"tokio",
"url",
@@ -8714,7 +8714,7 @@ dependencies = [
"serde",
"serde_json",
"tauri-utils",
"thiserror 2.0.4",
"thiserror 2.0.6",
"url",
"windows 0.58.0",
]
@@ -8774,7 +8774,7 @@ dependencies = [
"serde_json",
"serde_with",
"swift-rs",
"thiserror 2.0.4",
"thiserror 2.0.6",
"toml 0.8.19",
"url",
"urlpattern",
@@ -8946,11 +8946,11 @@ dependencies = [
[[package]]
name = "thiserror"
version = "2.0.4"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490"
checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
dependencies = [
"thiserror-impl 2.0.4",
"thiserror-impl 2.0.6",
]
[[package]]
@@ -8966,9 +8966,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
version = "2.0.4"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061"
checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
dependencies = [
"proc-macro2",
"quote",
@@ -11407,7 +11407,7 @@ dependencies = [
"pbkdf2",
"rand 0.8.5",
"sha1",
"thiserror 2.0.4",
"thiserror 2.0.6",
"time",
"zeroize",
"zopfli",
@@ -18,6 +18,6 @@
"swr": "2.2.5"
},
"devDependencies": {
"@types/react": "18.3.14"
"@types/react": "18.3.16"
}
}
+15 -15
View File
@@ -32,15 +32,15 @@
"i18next": "24.0.5",
"jotai": "2.10.3",
"json-schema": "0.4.0",
"material-react-table": "3.0.1",
"monaco-editor": "0.52.0",
"material-react-table": "3.0.2",
"monaco-editor": "0.52.2",
"mui-color-input": "5.0.1",
"react": "rc",
"react-dom": "rc",
"react-error-boundary": "4.1.2",
"react-fast-marquee": "1.6.5",
"react-hook-form-mui": "7.4.1",
"react-i18next": "15.1.3",
"react-i18next": "15.1.4",
"react-markdown": "9.0.1",
"react-split-grid": "1.0.4",
"react-use": "17.5.1",
@@ -52,21 +52,21 @@
"@csstools/normalize.css": "12.1.1",
"@emotion/babel-plugin": "11.13.5",
"@emotion/react": "11.13.5",
"@iconify/json": "2.2.280",
"@iconify/json": "2.2.281",
"@monaco-editor/react": "4.6.0",
"@tanstack/react-router": "1.86.1",
"@tanstack/router-devtools": "1.86.1",
"@tanstack/router-plugin": "1.86.0",
"@tauri-apps/plugin-clipboard-manager": "2.0.1",
"@tauri-apps/plugin-dialog": "2.0.1",
"@tauri-apps/plugin-fs": "2.0.3",
"@tauri-apps/plugin-notification": "2.0.0",
"@tauri-apps/plugin-os": "2.0.0",
"@tanstack/react-router": "1.87.9",
"@tanstack/router-devtools": "1.87.9",
"@tanstack/router-plugin": "1.87.7",
"@tauri-apps/plugin-clipboard-manager": "2.2.0",
"@tauri-apps/plugin-dialog": "2.2.0",
"@tauri-apps/plugin-fs": "2.2.0",
"@tauri-apps/plugin-notification": "2.2.0",
"@tauri-apps/plugin-os": "2.2.0",
"@tauri-apps/plugin-process": "2.0.0",
"@tauri-apps/plugin-shell": "2.0.1",
"@tauri-apps/plugin-updater": "2.0.0",
"@types/react": "18.3.14",
"@types/react-dom": "18.3.2",
"@types/react": "18.3.16",
"@types/react-dom": "18.3.5",
"@types/validator": "13.12.2",
"@vitejs/plugin-legacy": "6.0.0",
"@vitejs/plugin-react": "4.3.4",
@@ -79,7 +79,7 @@
"monaco-yaml": "5.2.3",
"nanoid": "5.0.9",
"sass": "1.82.0",
"shiki": "1.24.0",
"shiki": "1.24.2",
"tailwindcss-textshadow": "2.1.3",
"unplugin-auto-import": "0.18.6",
"unplugin-icons": "0.21.0",
@@ -1,183 +1,289 @@
{
"label_proxies": "прокси",
"label_profiles": "профили",
"label_connections": "связи",
"label_logs": "журналы",
"label_rules": "правила",
"label_settings": "настройки",
"label_providers": "поставщики",
"label_dashboard": "Панель управления",
"label_proxies": "Прокси",
"label_profiles": "Профили",
"label_connections": "Соединения",
"label_logs": "Журналы",
"label_rules": "Правила",
"label_settings": "Настройки",
"label_providers": "Поставщики",
"Connections": "Соединения",
"Logs": "Логи",
"Upload Traffic": "Отправка",
"Download Traffic": "Загрузка",
"Total": "Всего",
"Memory": "Память",
"Active Connections": "Активные соединения",
"Timeout": "Тайм-аут",
"Click to Refresh Now": "Нажмите для обновления",
"No Proxy": "Без прокси",
"Direct Mode": "Прямой режим",
"Rules": "Правила",
"No Rules": "Нет правил",
"Logs": "Журналы",
"No Logs": "Нет журналов",
"Clear": "Очистить",
"Proxies": "Прокси",
"Proxy Groups": "Группы прокси",
"rule": "правила",
"rule": "правило",
"global": "глобальный",
"direct": "прямой",
"script": "скриптовый",
"script": "скрипт",
"Dashboard": "Панель управления",
"Profiles": "Профили",
"Profile URL": "URL профиля",
"Import": "Импорт",
"Download": "Загрузить",
"Paste": "Вставить",
"Import": "Импортировать",
"New": "Новый",
"Edit Profile": "Редактировать профиль",
"Create Profile": "Создать профиль",
"New Profile": "Новый профиль",
"Choose File": "Выбрать файл",
"Close All": "Закрыть всё",
"Profile": "Профиль",
"Close All": "Закрыть все",
"Menu": "Меню",
"Select": "Выбрать",
"Edit Info": "Изменить информацию",
"Applying Profile": "Применение профиля...",
"Edit Info": "Редактировать информацию",
"Proxy Chains": "Цепочки прокси",
"Global Proxy Chains": "Глобальные цепочки прокси",
"New Chain": "Новая цепочка",
"New Script": "Новый скрипт",
"Edit Script": "Редактировать скрипт",
"Please fix the error before submitting": "Исправьте ошибку перед отправкой.",
"Open": "Открыть",
"Open File": "Открыть файл",
"Update": "Обновить",
"Update(Proxy)": "Обновить (прокси)",
"Update(Proxy)": "Обновитьрокси)",
"Delete": "Удалить",
"Enable": "Включить",
"Disable": "Отключить",
"Refresh": "Обновить",
"To Top": "Наверх",
"To End": "Вниз",
"To Top": "На верх",
"To End": "В конец",
"Update All Profiles": "Обновить все профили",
"View Runtime Config": росмотреть используемый конфиг",
"View Runtime Config": "Посмотреть конфигурацию времени выполнения",
"Reactivate Profiles": "Реактивировать профили",
"Location": "Местоположение",
"Delay check": "Проверка задержки",
"Sort by default": "Сортировать по умолчанию",
"Sort by delay": "Сортировать по задержке",
"Sort by name": "Сортировать по названию",
"Sort by name": "Сортировать по имени",
"Delay check URL": "URL проверки задержки",
"Proxy detail": "Подробности о прокси",
"Proxy detail": "Детали прокси",
"Filter": "Фильтр",
"Filter conditions": "Условия фильтрации",
"Refresh profiles": "Обновить профили",
"Connection Columns": "Колонки соединения",
"Actions": "Действия",
"Host": "Хост",
"Process": "Процесс",
"Downloaded": "Загружено",
"Uploaded": "Отправлено",
"DL Speed": "Скорость загрузки",
"UL Speed": "Скорость отправки",
"Chains": "Цепочки",
"Rule": "Правило",
"Time": "Время",
"Source": "Источник",
"Destination IP": "IP назначения",
"Destination ASN": "ASN назначения",
"Type": "Тип",
"Name": "Название",
"Connection Detail": "Детали соединения",
"Metadata": "Метаданные",
"Remote": "Удаленный",
"Local": "Локальный",
"Remote Profile": "Удаленный профиль",
"Local Profile": "Локальный профиль",
"Name": "Имя",
"Descriptions": "Описания",
"Subscription URL": "URL подписки",
"User Agent": "Пользовательский агент",
"Update Interval": "Интервал обновления",
"Tray Icons": "Значки в трее",
"Use System Proxy": "Использовать системный прокси",
"Use Clash Proxy": "Использовать прокси Clash",
"No Connections": "Нет соединений",
"Tray Icons": "Иконки в трее",
"Set": "Установить",
"Edit": "Редактировать",
"Reset": "Сбросить",
"Hotkeys": "Горячие клавиши",
"Feedback": "Обратная связь",
"Settings": "Настройки",
"Clash Setting": "Настройки Clash",
"System Setting": "Настройки системы",
"System Setting": "Системные настройки",
"Nyanpasu Setting": "Настройки Nyanpasu",
"Allow LAN": "Разрешить локальную сеть",
"Allow LAN": "Разрешить LAN",
"IPv6": "IPv6",
"TUN Stack": "Туннель куча",
"Log Level": "Уровень логов",
"Clash Port": "Clash порт",
"TUN Stack": "Стек TUN",
"Log Level": "Уровень логирования",
"Clash Port": "Порт Clash",
"Mixed Port": "Смешанный порт",
"Random Port": "Случайный порт",
"After restart to take effect": "Чтобы изменения вступили в силу, необходимо перезапустить приложение",
"After restart to take effect": "Вступит в силу после перезагрузки.",
"Clash External Controll": "Внешнее управление Clash",
"External Controller": "Внешний контроллер",
"Port Strategy": "Стратегия порта",
"Allow Fallback": "Разрешить откат",
"Fixed": "Фиксированный",
"Random": "Случайный",
"Core Secret": "Секрет ядра",
"Clash Core": "Ядро Clash",
"TUN Mode": "Режим туннеля",
"System Service": "Системная сервиса",
"Service Mode": "Режим сервиса",
"TUN Mode": "Режим TUN",
"System Service": "Системная служба",
"Service Mode": "Режим службы",
"Initiating Behavior": "Инициирующее поведение",
"Auto Start": "Автозапуск",
"Silent Start": "Тихий запуск",
"System Proxy": "Системный прокси",
"Open UWP Tool": "Открыть инструмент UWP",
"System Proxy Setting": "Настройка системного прокси",
"Proxy Guard": "Защита прокси",
"Guard Interval": "Период защиты",
"Proxy Bypass": "Игнорирование прокси",
"Proxy Guard": "Охрана прокси",
"Guard Interval": "Интервал охраны",
"The interval must be greater than 0 second": "Интервал должен быть больше 0 секунд.",
"Proxy Bypass": "Обход прокси",
"Apply": "Применить",
"Current System Proxy": "Текущий системный прокси",
"User Interface": "Пользовательский интерфейс",
"Theme Mode": "Режим темы",
"Open UWP Tool": "Открыть UWP инструмент",
"Theme Mode": "Тематический режим",
"Theme Blur": "Размытие темы",
"Theme Setting": "Настройка темы",
"Hotkey Setting": "Настройка клавиатурных сокращений",
"Icon Navigation Bar": "Панель навигации иконок",
"Layout Setting": "Настройка макета",
"Miscellaneous": "Разное",
"Hotkey Setting": "Настройка горячих клавиш",
"Traffic Graph": "График трафика",
"Page Transition Animation": "Анимация перехода страниц",
"Memory Usage": "Использование памяти",
"Page Transition Animation": "Анимация перехода страницы",
"Page Transition Animation Slide": "Слайд",
"Page Transition Animation Blur": "Размытие",
"Page Transition Animation Transparent": "Прозрачность",
"Page Transition Animation None": "Нет",
"Page Transition Animation None": "Без анимации",
"Language": "Язык",
"Open Config Dir": "Открыть папку конфигурации",
"Open Data Dir": "Открыть папку данных",
"Open Core Dir": "Открыть папку ядра",
"Open Logs Dir": "Открыть папку логов",
"Path Config": "Конфигурация пути",
"Migrate App Path": "Перенести путь приложения",
"Open Config Dir": "Открыть каталог конфигурации",
"Open Data Dir": "Открыть каталог данных",
"Open Core Dir": "Открыть каталог ядра",
"Open Logs Dir": "Открыть каталог журналов",
"Auto Check Updates": "Автоматическая проверка обновлений",
"Check for Updates": "Проверить обновления",
"Nyanpasu Version": "Версия Nyanpasu",
"theme.light": "Светлая",
"theme.dark": "Тёмная",
"theme.dark": "Темная",
"theme.system": "Системная",
"Clash Field": "Используемые настройки Clash",
"Runtime Config": "Используемый конфиг",
"ReadOnly": "Только для чтения",
"Clash Field": "Поле Clash",
"Original Config": "Исходная конфигурация",
"Runtime Config": "Конфигурация времени выполнения",
"Console": "Консоль",
"ReadOnly": "Только чтение",
"Check Updates": "Проверить обновления",
"Restart": "Перезапуск",
"Restart": "Перезапустить",
"Update Core": "Обновить ядро",
"Tasks": "Задачи",
"Auto Log Clean": "Автоочистка логов",
"Never Clean": "Никогда не чистить",
"Retain 3 Days": "Сохранять 3 дня",
"Retain 7 Days": "Сохранять 7 дней",
"Retain 30 Days": "Сохранять 30 дней",
"Retain 90 Days": "Сохранять 90 дней",
"Max Log Files": "Максимальное количество файлов логов",
"Collect Logs": "Собрать логи",
"Auto Log Clean": "Автоматическая очистка журналов",
"Never Clean": "Никогда не очищать",
"Retain 3 Days": "Хранить 3 дня",
"Retain 7 Days": "Хранить 7 дней",
"Retain 30 Days": "Хранить 30 дней",
"Retain 90 Days": "Хранить 90 дней",
"Max Log Files": "Максимум файлов журнала",
"Collect Logs": "Собрать журналы",
"Back": "Назад",
"Save": "Сохранить",
"Cancel": "Отмена",
"open_or_close_dashboard": "Открыть/закрыть панель управления",
"Default": "По умолчанию",
"Download Speed": "Скорость загрузки",
"Upload Speed": "Скорость отправки",
"open_or_close_dashboard": "Открыть/Закрыть панель управления",
"clash_mode_rule": "Режим правил",
"clash_mode_global": "Глобальный режим",
"clash_mode_direct": "Прямой режим",
"clash_mode_script": "Скриптовый режим",
"toggle_system_proxy": "Переключить режим системного прокси",
"clash_mode_script": "Режим скрипта",
"toggle_system_proxy": "Переключить системный прокси",
"enable_system_proxy": "Включить системный прокси",
"disable_system_proxy": "Отключить системный прокси",
"toggle_tun_mode": "Переключить режим туннеля",
"enable_tun_mode": "Включить режим туннеля",
"disable_tun_mode": "Отключить режим туннеля",
"toggle_tun_mode": "Переключить режим TUN",
"enable_tun_mode": "Включить режим TUN",
"disable_tun_mode": "Отключить режим TUN",
"App Log Level": "Уровень журнала приложения",
"Auto Close Connections": "Автоматическое закрытие соединений",
"Enable Clash Fields Filter": "Включить фильтр полей Clash",
"Enable Builtin Enhanced": "Включить встроенное улучшение",
"Proxy Layout Column": "Столбец макета прокси",
"Default Latency Test": "Тест задержки по умолчанию",
"Error": "Ошибка",
"Successful": "Успех",
"Providers": "Провайдеры",
"Rules Providers": ровайдеры правил",
"Update All Rules Providers": "Обновить все провайдеры правил",
"Rule Set rules": "{{rule}} правила",
"Last Update": "Последнее обновление {{fromNow}}",
"Successfully Updated Rules Providers": "Провайдеры правил успешно обновлены",
"Portable Update Error": "Обновление портативной версии не поддерживается",
"Tray Proxies Selector": "Выбор прокси в трее",
"Hidden": "Скрыть",
"Normal": "Обычный",
"Successful": "Успешно",
"Occupied": "Занято",
"Disabled": "Отключено",
"Providers": оставщики",
"Proxies Providers": "Поставщики прокси",
"Rules Providers": "Поставщики правил",
"Update All Rules Providers": "Обновить всех поставщиков правил",
"Rule Set rules": "{{rule}} правил",
"Last Update": "Последнее обновление: {{fromNow}}",
"Successfully Updated Rules Providers": "Успешно обновлены поставщики правил",
"Portable Update Error": "Портативное обновление не поддерживается. Пожалуйста, загрузите последнюю версию с официального сайта.",
"Tray Proxies Selector": "Селектор прокси в трее",
"Hidden": "Скрыто",
"Normal": "Нормальный",
"Submenu": "Подменю",
"Subscription": "подписка",
"FetchError": "Из-за проблем с сетью содержимое {{content}} невозможно получить. Пожалуйста, проверьте сетевое соединение или повторите попытку позже.",
"tun": "Туннель",
"normal": "Обычный",
"Proxy Set proxies": "{{rule}} прокси",
"Update All Proxies Providers": "Обновить всех поставщиков прокси",
"Lighten Up Animation Effects": "Осветлить анимационные эффекты",
"Subscription": "Подписка",
"FetchError": "Не удалось получить {{content}} из-за проблемы с сетью. Пожалуйста, проверьте ваше сетевое соединение и попробуйте снова позже.",
"tun": "Режим TUN",
"normal": "Нормальный",
"system_proxy": "Системный прокси",
"Subscription Expires In": "Подписка истекает через {{time}}",
"Subscription Updated At": "Подписка обновлена {{time}}",
"Proxy Takeover Status": "Статус захвата прокси",
"Subscription Expires In": "Истекает {{time}}",
"Subscription Updated At": "Обновлено в {{time}}",
"Choose file to import or leave it blank to create new one": "Выберите файл для импорта или оставьте пустым, чтобы создать новый.",
"updater": {
"title": "Доступно обновление",
"close": "Закрыть",
"update": "Обновить",
"title": "Доступна новая версия",
"close": "Игнорировать",
"update": "Обновить сейчас",
"go": "Посмотреть на GitHub"
},
"not_installed": "Не установлен",
"stopped": "Остановлен",
"running": "Запущен",
"stopped_reason": "Остановлен по причине: {{reason}}",
"not_installed": "Не установлено",
"stopped": "Остановлено",
"running": "Работает",
"stopped_reason": "Остановлено, Причина: {{reason}}",
"Current Status": "Текущее состояние: {{status}}",
"Information: To enable service mode, make sure the Clash Nyanpasu service is installed and started": "Информация: Чтобы включить режим службы, убедитесь, что служба Clash Nyanpasu установлена и запущена.",
"install": "установить",
"uninstall": "удалить",
"start": "запустить",
"stop": "остановить",
"Failed to install": "Не удалось установить",
"Failed to uninstall": "Не удалось удалить",
"service_shortcuts": {
"title": "Службы",
"title": "Ярлыки службы",
"core_status": "Статус ядра: ",
"service_status": "Статус службы: ",
"core_started_by": "Ядро запущено: ",
"core_started_by": "Запущено {{by}}",
"last_status_changed_since": "Последнее изменение статуса: {{time}}"
}
},
"service": "Служба",
"UI": "Пользовательский интерфейс",
"Service Manual Tips": "Руководство по обслуживанию",
"Unable to operation the service automatically": "Не удается автоматически {{operation}} службу. Пожалуйста, перейдите в каталог ядра, запустите PowerShell как администратор на Windows или эмулятор терминала на macOS/Linux и выполните следующие команды:",
"Successfully switched to the clash core": "Успешно переключено на ядро {{core}}.",
"Failed to switch. You could see the details in the log": "Не удалось переключить. Вы можете увидеть детали в журнале. \nОшибка: {{error}}",
"Successfully restarted the core": "Ядро успешно перезапущено.",
"Failed to restart. You could see the details in the log": "Не удалось перезапустить. Вы можете увидеть детали в журнале.\n\nОшибка:",
"Failed to fetch. Please check your network connection": "Не удалось получить. Пожалуйста, проверьте ваше сетевое соединение.",
"Successfully updated the core": "Ядро успешно обновлено {{core}}.",
"Failed to update": "Не удалось обновить. {{error}}",
"Multiple directories are not supported": "Несколько каталогов не поддерживаются.",
"Successfully changed the app directory": "Каталог приложения успешно изменен.",
"Failed to migrate": "Не удалось мигрировать. {{error}}",
"Web UI": "Веб-интерфейс",
"New Item": "Новый элемент",
"Edit Item": "Редактировать элемент",
"Input": "Ввод",
"Support %host %port, and %secret": "Поддерживает %host, %port и %secret",
"Replace host, port, and secret with": "Замените хост, порт и секрет на:",
"Result": "Результат"
}
+2 -2
View File
@@ -24,7 +24,7 @@
"@radix-ui/react-scroll-area": "1.2.1",
"@tauri-apps/api": "2.1.1",
"@types/d3": "7.4.3",
"@types/react": "18.3.14",
"@types/react": "18.3.16",
"@vitejs/plugin-react": "4.3.4",
"ahooks": "3.8.4",
"d3": "7.9.0",
@@ -32,7 +32,7 @@
"react": "rc",
"react-dom": "rc",
"react-error-boundary": "4.1.2",
"react-i18next": "15.1.3",
"react-i18next": "15.1.4",
"react-use": "17.5.1",
"vite": "6.0.3",
"vite-tsconfig-paths": "5.1.4"
+46
View File
@@ -0,0 +1,46 @@
{
"_version": 1,
"tray": {
"copy_env": {
"cmd": "Копировать Env (CMD)",
"ps": "Копировать Env (PS)",
"sh": "Копировать Env (sh)"
},
"select_proxies": "Выбрать прокси",
"dashboard": "Панель управления",
"direct_mode": "Прямой режим",
"global_mode": "Глобальный режим",
"more": {
"menu": "Еще",
"restart_app": "Перезапустить приложение",
"restart_clash": "Перезапустить Clash"
},
"open_dir": {
"menu": "Открыть папку",
"app_config_dir": "Папка конфигурации",
"app_data_dir": "Папка данных",
"core_dir": "Папка ядра",
"log_dir": "Папка журналов"
},
"proxy_action": {
"on": "Включить",
"off": "Выключить"
},
"quit": "Выйти",
"rule_mode": "Режим правил",
"script_mode": "Режим скриптов",
"system_proxy": "Системный прокси",
"tun_mode": "Режим TUN"
},
"dialog": {
"panic": "Пожалуйста, сообщите об этой проблеме в трекере проблем Github.",
"migrate": "Обнаружен файл конфигурации старой версии\nМигрировать на новую версию или нет?\n ВНИМАНИЕ: Это перезапишет вашу текущую конфигурацию, если она существует",
"custom_app_dir_migrate": "Вы установите пользовательскую папку приложения в %{path}\nПереместить ли текущую папку приложения в новую?",
"warning": {
"enable_tun_with_no_permission": "Режим TUN требует прав администратора или режима службы, ни один из которых не включен, режим TUN не будет работать должным образом."
},
"info": {
"grant_core_permission": "Ядру Clash необходимы права администратора для корректной работы режима TUN, предоставить их?\n\nОбратите внимание: Эта операция требует ввода пароля."
}
}
}
+3 -3
View File
@@ -1,8 +1,8 @@
{
"manifest_version": 1,
"latest": {
"mihomo": "v1.18.10",
"mihomo_alpha": "alpha-d6b496d",
"mihomo": "v1.19.0",
"mihomo_alpha": "alpha-5d9d8f4",
"clash_rs": "v0.7.3",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.7.3-alpha+sha.e711fd9"
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2024-12-04T22:21:03.586Z"
"updated_at": "2024-12-10T22:20:57.885Z"
}
+2 -2
View File
@@ -63,7 +63,7 @@
"@tauri-apps/cli": "2.1.0",
"@types/fs-extra": "11.0.4",
"@types/lodash-es": "4.17.12",
"@types/node": "22.10.1",
"@types/node": "22.10.2",
"@typescript-eslint/eslint-plugin": "8.17.0",
"@typescript-eslint/parser": "8.17.0",
"autoprefixer": "10.4.20",
@@ -82,7 +82,7 @@
"eslint-plugin-react": "7.37.2",
"eslint-plugin-react-compiler": "0.0.0-experimental-fcabbc1-20241106",
"eslint-plugin-react-hooks": "4.6.2",
"knip": "5.39.2",
"knip": "5.39.4",
"lint-staged": "15.2.10",
"npm-run-all2": "7.0.1",
"postcss": "8.4.49",
+326 -263
View File
File diff suppressed because it is too large Load Diff
+23 -8
View File
@@ -3,20 +3,25 @@ name: main
on:
push:
branches:
- 'master'
- "master"
tags:
- 'v*'
- "v*"
pull_request:
jobs:
# linters
# linters
lint-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: "22.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- run: make lint-frontend
lint-backend:
runs-on: ubuntu-latest
@@ -32,14 +37,19 @@ jobs:
steps:
- run: echo "done"
# tests
# tests
test-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: "22.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- run: make test-frontend
test-backend:
runs-on: ubuntu-latest
@@ -55,7 +65,7 @@ jobs:
steps:
- run: echo "done"
# release
# release
release:
runs-on: ubuntu-latest
needs: [lint, test]
@@ -67,9 +77,14 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version: 1.23.0
- uses: pnpm/action-setup@v4
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: "22.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
+4 -3
View File
@@ -10,7 +10,7 @@ build: | build-frontend build-backend ## Build binary
.PHONY: build-frontend
build-frontend: ## Build frontend
$Q cd frontend && npm ci && npm run build
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run build
.PHONY: build-backend
build-backend: ## Build backend
@@ -21,6 +21,7 @@ test: | test-frontend test-backend ## Run all tests
.PHONY: test-frontend
test-frontend: ## Run frontend tests
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run typecheck
.PHONY: test-backend
test-backend: ## Run backend tests
@@ -31,7 +32,7 @@ lint: lint-frontend lint-backend ## Run all linters
.PHONY: lint-frontend
lint-frontend: ## Run frontend linters
$Q cd frontend && npm ci && npm run lint
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run lint
.PHONY: lint-backend
lint-backend: | $(golangci-lint) ## Run backend linters
@@ -65,4 +66,4 @@ help: ## Show this help
@awk 'BEGIN {FS = ":.*?## "} { \
if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \
else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \
}' $(MAKEFILE_LIST)
}' $(MAKEFILE_LIST)
-27
View File
@@ -1,27 +0,0 @@
{
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript",
"@vue/eslint-config-prettier"
],
"rules": {
"vue/multi-word-component-names": "off",
"vue/no-mutating-props": [
"error",
{
"shallowOnly": true
}
]
// no-undef is already included in
// @vue/eslint-config-typescript
},
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
}
}
+39
View File
@@ -0,0 +1,39 @@
import pluginVue from "eslint-plugin-vue";
import vueTsEslintConfig from "@vue/eslint-config-typescript";
import prettierConfig from "@vue/eslint-config-prettier";
export default [
{
name: "app/files-to-lint",
files: ["**/*.{ts,mts,tsx,vue}"],
},
{
name: "app/files-to-ignore",
ignores: ["**/dist/**", "**/dist-ssr/**", "**/coverage/**"],
},
...pluginVue.configs["flat/essential"],
...vueTsEslintConfig(),
prettierConfig,
{
rules: {
"no-var": "warn",
"prefer-const": "warn",
// Note: you must disable the base rule as it can report incorrect errors
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/ban-ts-comment": "warn",
"vue/block-lang": "warn",
"vue/multi-word-component-names": "off",
"vue/no-mutating-props": [
"error",
{
shallowOnly: true,
},
],
},
},
];
-10
View File
@@ -1,10 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
File diff suppressed because it is too large Load Diff
+30 -21
View File
@@ -4,32 +4,33 @@
"private": true,
"type": "module",
"engines": {
"npm": ">=7.0.0",
"node": ">=18.0.0"
"node": ">=22.0.0",
"pnpm": ">=9.0.0"
},
"scripts": {
"dev": "vite dev",
"build": "npm run typecheck && vite build",
"build": "pnpm run typecheck && vite build",
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
"typecheck": "vue-tsc -p ./tsconfig.json --noEmit",
"lint": "npm run typecheck && eslint --ext .vue,.ts src/",
"lint:fix": "eslint --ext .vue,.ts --fix src/",
"typecheck": "vue-tsc -p ./tsconfig.tsc.json --noEmit",
"lint": "eslint src/",
"lint:fix": "eslint --fix src/",
"format": "prettier --write .",
"test": "playwright test"
},
"dependencies": {
"@chenfengyuan/vue-number-input": "^2.0.1",
"@vueuse/core": "^10.9.0",
"@vueuse/integrations": "^10.9.0",
"@vueuse/core": "^12.0.0",
"@vueuse/integrations": "^12.0.0",
"ace-builds": "^1.32.9",
"core-js": "^3.36.1",
"dayjs": "^1.11.10",
"epubjs": "^0.3.93",
"filesize": "^10.1.1",
"js-base64": "^3.7.7",
"jwt-decode": "^4.0.0",
"lodash-es": "^4.17.21",
"marked": "^15.0.3",
"material-icons": "^1.13.12",
"marked": "^14.1.0",
"normalize.css": "^8.0.1",
"pinia": "^2.1.7",
"pretty-bytes": "^6.1.1",
@@ -41,33 +42,41 @@
"videojs-mobile-ui": "^1.1.1",
"vue": "^3.4.21",
"vue-final-modal": "^4.5.4",
"vue-i18n": "^9.14.2",
"vue-i18n": "^10.0.5",
"vue-lazyload": "^3.0.0",
"vue-reader": "^1.2.14",
"vue-router": "^4.3.0",
"vue-toastification": "^2.0.0-rc.5"
},
"devDependencies": {
"@intlify/unplugin-vue-i18n": "^4.0.0",
"@intlify/unplugin-vue-i18n": "^6.0.0",
"@playwright/test": "^1.42.1",
"@tsconfig/node22": "^22.0.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.12.2",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@vitejs/plugin-legacy": "^5.3.2",
"@types/node": "^22.10.1",
"@typescript-eslint/eslint-plugin": "^8.17.0",
"@vitejs/plugin-legacy": "^6.0.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/eslint-config-prettier": "^10.1.0",
"@vue/eslint-config-typescript": "^14.1.4",
"@vue/tsconfig": "^0.7.0",
"autoprefixer": "^10.4.19",
"concurrently": "^8.2.2",
"eslint": "^8.57.0",
"concurrently": "^9.1.0",
"eslint": "^9.16.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.24.0",
"jsdom": "^24.0.0",
"jsdom": "^25.0.1",
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"terser": "^5.30.0",
"vite": "^5.4.6",
"vite": "^6.0.2",
"vite-plugin-compression2": "^1.0.0",
"vue-tsc": "^2.0.7"
}
},
"pnpm": {
"overrides": {
"typescript": "~5.6.3"
}
},
"packageManager": "pnpm@9.14.4+sha512.c8180b3fbe4e4bca02c94234717896b5529740a6cbadf19fa78254270403ea2f27d4e1d46a08a0f56c89b63dc8ebfd3ee53326da720273794e6200fcf0d184ab"
}
+5386
View File
File diff suppressed because it is too large Load Diff
@@ -50,7 +50,7 @@ import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout";
import { commands } from "@/api";
import { throttle } from "lodash";
import { throttle } from "lodash-es";
import { theme } from "@/utils/constants";
export default {
@@ -14,15 +14,15 @@
</div>
</template>
<script setup lang="ts">
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import UTIF from "utif";
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
interface IProps {
src: string;
moveDisabledTime: number;
classList: any[];
zoomStep: number;
moveDisabledTime?: number;
classList?: any[];
zoomStep?: number;
}
const props = withDefaults(defineProps<IProps>(), {
@@ -120,7 +120,7 @@ const subLabel = (subUrl: string) => {
let url: URL;
try {
url = new URL(subUrl);
} catch (_) {
} catch {
// treat it as a relative url
// we only need this for filename
url = new URL(subUrl, window.location.origin);
@@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { SelectHTMLAttributes } from "vue";
import type { SelectHTMLAttributes } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
+1 -1
View File
@@ -4,7 +4,7 @@ import VueNumberInput from "@chenfengyuan/vue-number-input";
import VueLazyload from "vue-lazyload";
import { createVfm } from "vue-final-modal";
import Toast, { POSITION, useToast } from "vue-toastification";
import {
import type {
ToastOptions,
PluginOptions,
} from "vue-toastification/dist/types/types";
+2 -1
View File
@@ -1,4 +1,5 @@
import { RouteLocation, createRouter, createWebHistory } from "vue-router";
import type { RouteLocation } from "vue-router";
import { createRouter, createWebHistory } from "vue-router";
import Login from "@/views/Login.vue";
import Layout from "@/views/Layout.vue";
import Files from "@/views/Files.vue";
+1 -1
View File
@@ -1,6 +1,6 @@
import { createPinia as _createPinia } from "pinia";
import { markRaw } from "vue";
import { Router } from "vue-router";
import type { Router } from "vue-router";
export default function createPinia(router: Router) {
const pinia = _createPinia();
+1 -1
View File
@@ -1,7 +1,7 @@
import { defineStore } from "pinia";
import { useFileStore } from "./file";
import { files as api } from "@/api";
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import buttons from "@/utils/buttons";
// TODO: make this into a user setting
+2 -1
View File
@@ -1,6 +1,7 @@
import { useAuthStore } from "@/stores/auth";
import router from "@/router";
import { JwtPayload, jwtDecode } from "jwt-decode";
import type { JwtPayload } from "jwt-decode";
import { jwtDecode } from "jwt-decode";
import { baseURL, noAuth } from "./constants";
import { StatusError } from "@/api/utils";
@@ -285,7 +285,7 @@ import { users, files as api } from "@/api";
import { enableExec } from "@/utils/constants";
import * as upload from "@/utils/upload";
import css from "@/utils/css";
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import { Base64 } from "js-base64";
import HeaderBar from "@/components/header/HeaderBar.vue";
@@ -168,7 +168,7 @@ import { files as api } from "@/api";
import { createURL } from "@/api/utils";
import { resizePreview } from "@/utils/constants";
import url from "@/utils/url";
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import HeaderBar from "@/components/header/HeaderBar.vue";
import Action from "@/components/header/Action.vue";
import ExtendedImage from "@/components/files/ExtendedImage.vue";
+13
View File
@@ -0,0 +1,13 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"types": ["vite/client", "@intlify/unplugin-vue-i18n/messages"],
"paths": {
"@/*": ["./src/*"]
}
}
}
+8 -21
View File
@@ -1,24 +1,11 @@
{
"compilerOptions": {
"baseUrl": ".",
"allowJs": true,
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node10",
"strict": true,
"sourceMap": true,
"noImplicitReturns": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"types": ["vite/client", "@intlify/unplugin-vue-i18n/messages"],
"paths": {
"@/*": ["./src/*"]
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
},
"include": ["src/**/*.ts", "src/**/*.vue"],
"exclude": ["node_modules", "dist"]
]
}
+18
View File
@@ -0,0 +1,18 @@
{
"extends": "@tsconfig/node22/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}
+14
View File
@@ -0,0 +1,14 @@
{
"extends": "./tsconfig.app.json",
// vue-tsc wont shut up about error TS9005
// in non-TS vue files so exclude them
"exclude": [
"src/components/Shell.vue",
"src/components/prompts/Copy.vue",
"src/components/prompts/Delete.vue",
"src/components/prompts/FileList.vue",
"src/components/prompts/Rename.vue",
"src/components/prompts/Share.vue",
"src/components/prompts/UploadFiles.vue"
]
}
+10 -10
View File
@@ -2,19 +2,19 @@ module github.com/Loyalsoldier/geoip
go 1.23
toolchain go1.23.2
toolchain go1.23.4
require (
github.com/klauspost/compress v1.17.11
github.com/maxmind/mmdbwriter v1.0.0
github.com/oschwald/geoip2-golang v1.11.0
github.com/oschwald/maxminddb-golang v1.13.1
github.com/sagernet/sing-box v1.10.1
github.com/sagernet/sing-box v1.10.3
github.com/spf13/cobra v1.8.1
github.com/tailscale/hujson v0.0.0-20241010212012-29efb4a0184b
github.com/tidwall/gjson v1.18.0
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
google.golang.org/protobuf v1.35.1
google.golang.org/protobuf v1.35.2
gopkg.in/yaml.v2 v2.4.0
)
@@ -22,14 +22,14 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/sagernet/sing v0.5.0-rc.2 // indirect
github.com/sagernet/sing-dns v0.3.0-rc.2 // indirect
github.com/sagernet/sing v0.5.1 // indirect
github.com/sagernet/sing-dns v0.3.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/tools v0.23.0 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+24 -24
View File
@@ -33,14 +33,14 @@ github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU=
github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q=
github.com/sagernet/sing v0.5.0-rc.2 h1:tIrs6pRbjJWvI0ITRSg47P1wosY+iSuHpw9t5/hBx+Q=
github.com/sagernet/sing v0.5.0-rc.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.10.1 h1:J3H0TzF0LGC4uOR62TpSuAhhHkv3Bx5M5F5kK5JB+WA=
github.com/sagernet/sing-box v1.10.1/go.mod h1:Nk9Ww0M1ulUsbfd5d4dfMBfJ0Audmm6m5+YYdvdpcZQ=
github.com/sagernet/sing-dns v0.3.0-rc.2 h1:z1yROBxd/6wik5h53Sz5df1DSmbPTaOu/Z0wAmyXGoQ=
github.com/sagernet/sing-dns v0.3.0-rc.2/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
github.com/sagernet/quic-go v0.48.2-beta.1 h1:W0plrLWa1XtOWDTdX3CJwxmQuxkya12nN5BRGZ87kEg=
github.com/sagernet/quic-go v0.48.2-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/+or9YMLaG5VeTk4k=
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.10.3 h1:Ptknjvcm6IfKnezuJZWQsQGxh6ZV1pAi/GIbfRNKELQ=
github.com/sagernet/sing-box v1.10.3/go.mod h1:u67UniOxg+rs31hx4tLwabkai0H2vL+psjAGBPz4Osc=
github.com/sagernet/sing-dns v0.3.0 h1:uHCIlbCwBxALJwXcEK1d75d7t3vzCSVEQsPfZR1cxQE=
github.com/sagernet/sing-dns v0.3.0/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -57,24 +57,24 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+1 -1
View File
@@ -238,7 +238,7 @@ func (s *SRSIn) generateEntries(name string, reader io.Reader, entries map[strin
return err
}
for _, rule := range plainRuleSet.Rules {
for _, rule := range plainRuleSet.Options.Rules {
for _, cidrStr := range rule.DefaultOptions.IPCIDR {
if err := entry.AddPrefix(cidrStr); err != nil {
return err
+1 -1
View File
@@ -194,7 +194,7 @@ func (s *SRSOut) writeFile(filename string, ruleset *option.PlainRuleSet) error
}
defer f.Close()
err = srs.Write(f, *ruleset, false)
err = srs.Write(f, *ruleset, constant.RuleSetVersion1)
if err != nil {
return err
}
+12 -9
View File
@@ -204,6 +204,7 @@ type serverConfigOutboundDirect struct {
BindIPv4 string `mapstructure:"bindIPv4"`
BindIPv6 string `mapstructure:"bindIPv6"`
BindDevice string `mapstructure:"bindDevice"`
FastOpen bool `mapstructure:"fastOpen"`
}
type serverConfigOutboundSOCKS5 struct {
@@ -518,18 +519,18 @@ func (c *serverConfig) fillQUICConfig(hyConfig *server.Config) error {
}
func serverConfigOutboundDirectToOutbound(c serverConfigOutboundDirect) (outbounds.PluggableOutbound, error) {
var mode outbounds.DirectOutboundMode
opts := outbounds.DirectOutboundOptions{}
switch strings.ToLower(c.Mode) {
case "", "auto":
mode = outbounds.DirectOutboundModeAuto
opts.Mode = outbounds.DirectOutboundModeAuto
case "64":
mode = outbounds.DirectOutboundMode64
opts.Mode = outbounds.DirectOutboundMode64
case "46":
mode = outbounds.DirectOutboundMode46
opts.Mode = outbounds.DirectOutboundMode46
case "6":
mode = outbounds.DirectOutboundMode6
opts.Mode = outbounds.DirectOutboundMode6
case "4":
mode = outbounds.DirectOutboundMode4
opts.Mode = outbounds.DirectOutboundMode4
default:
return nil, configError{Field: "outbounds.direct.mode", Err: errors.New("unsupported mode")}
}
@@ -546,12 +547,14 @@ func serverConfigOutboundDirectToOutbound(c serverConfigOutboundDirect) (outboun
if len(c.BindIPv6) > 0 && ip6 == nil {
return nil, configError{Field: "outbounds.direct.bindIPv6", Err: errors.New("invalid IPv6 address")}
}
return outbounds.NewDirectOutboundBindToIPs(mode, ip4, ip6)
opts.BindIP4 = ip4
opts.BindIP6 = ip6
}
if bindDevice {
return outbounds.NewDirectOutboundBindToDevice(mode, c.BindDevice)
opts.DeviceName = c.BindDevice
}
return outbounds.NewDirectOutboundSimple(mode), nil
opts.FastOpen = c.FastOpen
return outbounds.NewDirectOutboundWithOptions(opts)
}
func serverConfigOutboundSOCKS5ToOutbound(c serverConfigOutboundSOCKS5) (outbounds.PluggableOutbound, error) {
+1
View File
@@ -138,6 +138,7 @@ func TestServerConfig(t *testing.T) {
BindIPv4: "2.4.6.8",
BindIPv6: "0:0:0:0:0:ffff:0204:0608",
BindDevice: "eth233",
FastOpen: true,
},
},
{
+1
View File
@@ -108,6 +108,7 @@ outbounds:
bindIPv4: 2.4.6.8
bindIPv6: 0:0:0:0:0:ffff:0204:0608
bindDevice: eth233
fastOpen: true
- name: badstuff
type: socks5
socks5:
+3 -1
View File
@@ -25,7 +25,7 @@ require (
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301
go.uber.org/zap v1.24.0
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
golang.org/x/sys v0.23.0
golang.org/x/sys v0.25.0
)
require (
@@ -33,6 +33,8 @@ require (
github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 // indirect
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect
github.com/cloudflare/circl v1.3.9 // indirect
github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect
github.com/database64128/tfo-go/v2 v2.2.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
+6 -2
View File
@@ -63,6 +63,10 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a h1:t4SDi0pmNkryzKdM4QF3o5vqSP4GRjeZD/6j3nyxNP0=
github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a/go.mod h1:7K2NQKbabB5mBl41vF6YayYl5g7YpDwc4dQ5iMpP3Lg=
github.com/database64128/tfo-go/v2 v2.2.2 h1:BxynF4qGF5ct3DpPLEG62uyJZ3LQhqaf0Ken+kyy7PM=
github.com/database64128/tfo-go/v2 v2.2.2/go.mod h1:2IW8jppdBwdVMjA08uEyMNnqiAHKUlqAA+J8NrsfktY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -463,8 +467,8 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+1 -1
View File
@@ -27,7 +27,7 @@ require (
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/protobuf v1.34.1 // indirect
+1 -2
View File
@@ -58,8 +58,7 @@ golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+3 -1
View File
@@ -8,6 +8,7 @@ require (
github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000
github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6
github.com/database64128/tfo-go/v2 v2.2.2
github.com/hashicorp/golang-lru/v2 v2.0.5
github.com/miekg/dns v1.1.59
github.com/refraction-networking/utls v1.6.6
@@ -21,6 +22,7 @@ require (
require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/cloudflare/circl v1.3.9 // indirect
github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
@@ -36,7 +38,7 @@ require (
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+6 -2
View File
@@ -10,6 +10,10 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a h1:t4SDi0pmNkryzKdM4QF3o5vqSP4GRjeZD/6j3nyxNP0=
github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a/go.mod h1:7K2NQKbabB5mBl41vF6YayYl5g7YpDwc4dQ5iMpP3Lg=
github.com/database64128/tfo-go/v2 v2.2.2 h1:BxynF4qGF5ct3DpPLEG62uyJZ3LQhqaf0Ken+kyy7PM=
github.com/database64128/tfo-go/v2 v2.2.2/go.mod h1:2IW8jppdBwdVMjA08uEyMNnqiAHKUlqAA+J8NrsfktY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -92,8 +96,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+229
View File
@@ -0,0 +1,229 @@
package outbounds
import (
"net"
"sync"
"time"
"github.com/database64128/tfo-go/v2"
)
type fastOpenDialer struct {
dialer *tfo.Dialer
}
func newFastOpenDialer(netDialer *net.Dialer) *fastOpenDialer {
return &fastOpenDialer{
dialer: &tfo.Dialer{
Dialer: *netDialer,
},
}
}
// Dial returns immediately without actually establishing a connection.
// The connection will be established by the first Write() call.
func (d *fastOpenDialer) Dial(network, address string) (net.Conn, error) {
return &fastOpenConn{
dialer: d.dialer,
network: network,
address: address,
readyChan: make(chan struct{}),
}, nil
}
type fastOpenConn struct {
dialer *tfo.Dialer
network string
address string
conn net.Conn
connLock sync.RWMutex
readyChan chan struct{}
// States before connection ready
deadline *time.Time
readDeadline *time.Time
writeDeadline *time.Time
}
func (c *fastOpenConn) Read(b []byte) (n int, err error) {
c.connLock.RLock()
conn := c.conn
c.connLock.RUnlock()
if conn != nil {
return conn.Read(b)
}
// Wait until the connection is ready or closed
<-c.readyChan
if c.conn == nil {
// This is equivalent to isClosedBeforeReady() == true
return 0, net.ErrClosed
}
return c.conn.Read(b)
}
func (c *fastOpenConn) Write(b []byte) (n int, err error) {
c.connLock.RLock()
conn := c.conn
c.connLock.RUnlock()
if conn != nil {
return conn.Write(b)
}
c.connLock.RLock()
closed := c.isClosedBeforeReady()
c.connLock.RUnlock()
if closed {
return 0, net.ErrClosed
}
c.connLock.Lock()
defer c.connLock.Unlock()
if c.isClosedBeforeReady() {
// Closed by other goroutine
return 0, net.ErrClosed
}
conn = c.conn
if conn != nil {
// Established by other goroutine
return conn.Write(b)
}
conn, err = c.dialer.Dial(c.network, c.address, b)
if err != nil {
close(c.readyChan)
return 0, err
}
// Apply pre-set states
if c.deadline != nil {
_ = conn.SetDeadline(*c.deadline)
}
if c.readDeadline != nil {
_ = conn.SetReadDeadline(*c.readDeadline)
}
if c.writeDeadline != nil {
_ = conn.SetWriteDeadline(*c.writeDeadline)
}
c.conn = conn
close(c.readyChan)
return len(b), nil
}
func (c *fastOpenConn) Close() error {
c.connLock.RLock()
defer c.connLock.RUnlock()
if c.isClosedBeforeReady() {
return net.ErrClosed
}
if c.conn != nil {
return c.conn.Close()
}
close(c.readyChan)
return nil
}
// isClosedBeforeReady returns true if the connection is closed before the real connection is established.
// This function should be called with connLock.RLock().
func (c *fastOpenConn) isClosedBeforeReady() bool {
select {
case <-c.readyChan:
if c.conn == nil {
return true
}
default:
}
return false
}
func (c *fastOpenConn) LocalAddr() net.Addr {
c.connLock.RLock()
defer c.connLock.RUnlock()
if c.conn != nil {
return c.conn.LocalAddr()
}
return nil
}
func (c *fastOpenConn) RemoteAddr() net.Addr {
c.connLock.RLock()
conn := c.conn
c.connLock.RUnlock()
if conn != nil {
return conn.RemoteAddr()
}
addr, err := net.ResolveTCPAddr(c.network, c.address)
if err != nil {
return nil
}
return addr
}
func (c *fastOpenConn) SetDeadline(t time.Time) error {
c.connLock.RLock()
defer c.connLock.RUnlock()
c.deadline = &t
if c.conn != nil {
return c.conn.SetDeadline(t)
}
if c.isClosedBeforeReady() {
return net.ErrClosed
}
return nil
}
func (c *fastOpenConn) SetReadDeadline(t time.Time) error {
c.connLock.RLock()
defer c.connLock.RUnlock()
c.readDeadline = &t
if c.conn != nil {
return c.conn.SetReadDeadline(t)
}
if c.isClosedBeforeReady() {
return net.ErrClosed
}
return nil
}
func (c *fastOpenConn) SetWriteDeadline(t time.Time) error {
c.connLock.RLock()
defer c.connLock.RUnlock()
c.writeDeadline = &t
if c.conn != nil {
return c.conn.SetWriteDeadline(t)
}
if c.isClosedBeforeReady() {
return net.ErrClosed
}
return nil
}
var _ net.Conn = (*fastOpenConn)(nil)
+80 -33
View File
@@ -35,8 +35,8 @@ type directOutbound struct {
Mode DirectOutboundMode
// Dialer4 and Dialer6 are used for IPv4 and IPv6 TCP connections respectively.
Dialer4 *net.Dialer
Dialer6 *net.Dialer
DialFunc4 func(network, address string) (net.Conn, error)
DialFunc6 func(network, address string) (net.Conn, error)
// DeviceName & BindIPs are for UDP connections. They don't use dialers, so we
// need to bind them when creating the connection.
@@ -45,6 +45,16 @@ type directOutbound struct {
BindIP6 net.IP
}
type DirectOutboundOptions struct {
Mode DirectOutboundMode
DeviceName string
BindIP4 net.IP
BindIP6 net.IP
FastOpen bool
}
type noAddressError struct {
IPv4 bool
IPv6 bool
@@ -84,6 +94,57 @@ func (e resolveError) Unwrap() error {
return e.Err
}
func NewDirectOutboundWithOptions(opts DirectOutboundOptions) (PluggableOutbound, error) {
dialer4 := &net.Dialer{
Timeout: defaultDialerTimeout,
}
if opts.BindIP4 != nil {
if opts.BindIP4.To4() == nil {
return nil, errors.New("BindIP4 must be an IPv4 address")
}
dialer4.LocalAddr = &net.TCPAddr{
IP: opts.BindIP4,
}
}
dialer6 := &net.Dialer{
Timeout: defaultDialerTimeout,
}
if opts.BindIP6 != nil {
if opts.BindIP6.To4() != nil {
return nil, errors.New("BindIP6 must be an IPv6 address")
}
dialer6.LocalAddr = &net.TCPAddr{
IP: opts.BindIP6,
}
}
if opts.DeviceName != "" {
err := dialerBindToDevice(dialer4, opts.DeviceName)
if err != nil {
return nil, err
}
err = dialerBindToDevice(dialer6, opts.DeviceName)
if err != nil {
return nil, err
}
}
dialFunc4 := dialer4.Dial
dialFunc6 := dialer6.Dial
if opts.FastOpen {
dialFunc4 = newFastOpenDialer(dialer4).Dial
dialFunc6 = newFastOpenDialer(dialer6).Dial
}
return &directOutbound{
Mode: opts.Mode,
DialFunc4: dialFunc4,
DialFunc6: dialFunc6,
DeviceName: opts.DeviceName,
BindIP4: opts.BindIP4,
BindIP6: opts.BindIP6,
}, nil
}
// NewDirectOutboundSimple creates a new directOutbound with the given mode,
// without binding to a specific device. Works on all platforms.
func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound {
@@ -91,9 +152,9 @@ func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound {
Timeout: defaultDialerTimeout,
}
return &directOutbound{
Mode: mode,
Dialer4: d,
Dialer6: d,
Mode: mode,
DialFunc4: d.Dial,
DialFunc6: d.Dial,
}
}
@@ -102,34 +163,20 @@ func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound {
// can be nil, in which case the directOutbound will not bind to a specific address
// for that family.
func NewDirectOutboundBindToIPs(mode DirectOutboundMode, bindIP4, bindIP6 net.IP) (PluggableOutbound, error) {
if bindIP4 != nil && bindIP4.To4() == nil {
return nil, errors.New("bindIP4 must be an IPv4 address")
}
if bindIP6 != nil && bindIP6.To4() != nil {
return nil, errors.New("bindIP6 must be an IPv6 address")
}
ob := &directOutbound{
Mode: mode,
Dialer4: &net.Dialer{
Timeout: defaultDialerTimeout,
},
Dialer6: &net.Dialer{
Timeout: defaultDialerTimeout,
},
return NewDirectOutboundWithOptions(DirectOutboundOptions{
Mode: mode,
BindIP4: bindIP4,
BindIP6: bindIP6,
}
if bindIP4 != nil {
ob.Dialer4.LocalAddr = &net.TCPAddr{
IP: bindIP4,
}
}
if bindIP6 != nil {
ob.Dialer6.LocalAddr = &net.TCPAddr{
IP: bindIP6,
}
}
return ob, nil
})
}
// NewDirectOutboundBindToDevice creates a new directOutbound with the given mode,
// and binds to the given device. Only works on Linux.
func NewDirectOutboundBindToDevice(mode DirectOutboundMode, deviceName string) (PluggableOutbound, error) {
return NewDirectOutboundWithOptions(DirectOutboundOptions{
Mode: mode,
DeviceName: deviceName,
})
}
// resolve is our built-in DNS resolver for handling the case when
@@ -201,9 +248,9 @@ func (d *directOutbound) TCP(reqAddr *AddrEx) (net.Conn, error) {
func (d *directOutbound) dialTCP(ip net.IP, port uint16) (net.Conn, error) {
if ip.To4() != nil {
return d.Dialer4.Dial("tcp4", net.JoinHostPort(ip.String(), strconv.Itoa(int(port))))
return d.DialFunc4("tcp4", net.JoinHostPort(ip.String(), strconv.Itoa(int(port))))
} else {
return d.Dialer6.Dial("tcp6", net.JoinHostPort(ip.String(), strconv.Itoa(int(port))))
return d.DialFunc6("tcp6", net.JoinHostPort(ip.String(), strconv.Itoa(int(port))))
}
}
+19 -19
View File
@@ -6,31 +6,31 @@ import (
"syscall"
)
// NewDirectOutboundBindToDevice creates a new directOutbound with the given mode,
// and binds to the given device. Only works on Linux.
func NewDirectOutboundBindToDevice(mode DirectOutboundMode, deviceName string) (PluggableOutbound, error) {
func dialerBindToDevice(dialer *net.Dialer, deviceName string) error {
if err := verifyDeviceName(deviceName); err != nil {
return nil, err
return err
}
d := &net.Dialer{
Timeout: defaultDialerTimeout,
Control: func(network, address string, c syscall.RawConn) error {
var errBind error
err := c.Control(func(fd uintptr) {
errBind = syscall.BindToDevice(int(fd), deviceName)
})
originControl := dialer.Control
dialer.Control = func(network, address string, c syscall.RawConn) error {
if originControl != nil {
// Chaining other control function
err := originControl(network, address, c)
if err != nil {
return err
}
return errBind
},
}
var errBind error
err := c.Control(func(fd uintptr) {
errBind = syscall.BindToDevice(int(fd), deviceName)
})
if err != nil {
return err
}
return errBind
}
return &directOutbound{
Mode: mode,
Dialer4: d,
Dialer6: d,
DeviceName: deviceName,
}, nil
return nil
}
func verifyDeviceName(deviceName string) error {
@@ -7,11 +7,8 @@ import (
"net"
)
// NewDirectOutboundBindToDevice creates a new directOutbound with the given mode,
// and binds to the given device. This doesn't work on non-Linux platforms, so this
// is just a stub function that always returns an error.
func NewDirectOutboundBindToDevice(mode DirectOutboundMode, deviceName string) (PluggableOutbound, error) {
return nil, errors.New("binding to device is not supported on this platform")
func dialerBindToDevice(dialer *net.Dialer, deviceName string) error {
return errors.New("binding to device is not supported on this platform")
}
func udpConnBindToDevice(conn *net.UDPConn, deviceName string) error {
+2 -2
View File
@@ -1,2 +1,2 @@
LINUX_VERSION-6.1 = .118
LINUX_KERNEL_HASH-6.1.118 = 010784bd7161c32c4cd68a423d4dcb14e4587677d238b2825a31fe012869224c
LINUX_VERSION-6.1 = .119
LINUX_KERNEL_HASH-6.1.119 = aecdaf39d0a844a81ce4c67d9daff8979e938bb690df4f679fbbb494fe423278
+2 -2
View File
@@ -1,2 +1,2 @@
LINUX_VERSION-6.6 = .63
LINUX_KERNEL_HASH-6.6.63 = d1054ab4803413efe2850f50f1a84349c091631ec50a1cf9e891d1b1f9061835
LINUX_VERSION-6.6 = .64
LINUX_KERNEL_HASH-6.6.64 = 065fd93fa6cb422f650fb563f15d3e0107c85009f766405993d795fd39796ab1
@@ -1,10 +1,11 @@
do_sysinfo_generic() {
[ -d /proc/device-tree ] || return
mkdir -p /tmp/sysinfo
[ -d /proc/device-tree ] || return
[ -e /tmp/sysinfo/board_name ] || \
echo "$(strings /proc/device-tree/compatible | head -1)" > /tmp/sysinfo/board_name
[ ! -e /tmp/sysinfo/model -a -e /proc/device-tree/model ] && \
echo "$(cat /proc/device-tree/model)" > /tmp/sysinfo/model
[ -z "$(fw_printenv model_name)" ] || fw_printenv model_name > /tmp/sysinfo/model
}
boot_hook_add preinit_main do_sysinfo_generic
@@ -16,7 +16,8 @@ alfa-network,ac1200rm|\
alfa-network,awusfree1|\
alfa-network,quad-e4g|\
alfa-network,r36m-e4g|\
alfa-network,tube-e4g)
alfa-network,tube-e4g|\
huasifei,mt7621dtu)
ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x1000"
;;
allnet,all0256n-4m|\
@@ -0,0 +1,22 @@
--- a/common/edid.c
+++ b/common/edid.c
@@ -3579,7 +3579,7 @@ int add_cea_modes(struct hdmi_edid_data
{
const u8 *cea = drm_find_cea_extension(edid);
const u8 *db, *hdmi = NULL, *video = NULL;
- u8 dbl, hdmi_len, video_len = 0;
+ u8 dbl, hdmi_len = 0, video_len = 0;
int modes = 0;
if (cea && cea_revision(cea) >= 3) {
--- a/include/command.h
+++ b/include/command.h
@@ -139,7 +139,7 @@ enum command_ret_t {
* number of ticks the command took to complete.
* @return 0 if the command succeeded, 1 if it failed
*/
-int cmd_process(int flag, int argc, char * const argv[],
+enum command_ret_t cmd_process(int flag, int argc, char * const argv[],
int *repeatable, unsigned long *ticks);
void fixup_cmdtable(cmd_tbl_t *cmdtp, int size);
@@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=intel-microcode
PKG_VERSION:=20240531
PKG_VERSION:=20241112
PKG_RELEASE:=1
PKG_SOURCE:=intel-microcode_3.$(PKG_VERSION).1.tar.xz
PKG_SOURCE_URL:=@DEBIAN/pool/non-free-firmware/i/intel-microcode/
PKG_HASH:=808cbb57a790dab7060b59b31e70e54ac47d3798d75e9784ed57a65b9f951fc4
PKG_HASH:=aeee844da5136ad8d9cd94661b8d6398a775780bf719f3ef28e9d9c9ee9fe819
PKG_BUILD_DIR:=$(BUILD_DIR)/intel-microcode-3.$(PKG_VERSION).1
PKG_CPE_ID:=cpe:/a:intel:microcode
@@ -220,7 +220,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
struct vc4_hang_state *hang_state;
@@ -963,6 +967,9 @@ extern struct platform_driver vc4_dsi_dr
@@ -964,6 +968,9 @@ extern struct platform_driver vc4_dsi_dr
/* vc4_fence.c */
extern const struct dma_fence_ops vc4_fence_ops;
@@ -83,7 +83,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
struct drm_device;
struct drm_gem_object;
@@ -494,6 +495,17 @@ struct drm_encoder *vc4_find_encoder_by_
@@ -495,6 +496,17 @@ struct drm_encoder *vc4_find_encoder_by_
return NULL;
}
@@ -101,7 +101,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
struct vc4_crtc_data {
const char *name;
@@ -538,9 +550,19 @@ struct vc4_crtc {
@@ -539,9 +551,19 @@ struct vc4_crtc {
/* Timestamp at start of vblank irq - unaffected by lock delays. */
ktime_t t_vblank;
@@ -126,7 +126,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -243,7 +243,8 @@ static void vc4_hvs_lut_load(struct vc4_
@@ -248,7 +248,8 @@ static void vc4_hvs_lut_load(struct vc4_
static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs,
struct vc4_crtc *vc4_crtc)
{
@@ -136,7 +136,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
struct drm_color_lut *lut = crtc_state->gamma_lut->data;
u32 length = drm_color_lut_size(crtc_state->gamma_lut);
u32 i;
@@ -257,6 +258,81 @@ static void vc4_hvs_update_gamma_lut(str
@@ -262,6 +263,81 @@ static void vc4_hvs_update_gamma_lut(str
vc4_hvs_lut_load(hvs, vc4_crtc);
}
@@ -218,7 +218,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo)
{
struct drm_device *drm = &hvs->vc4->base;
@@ -400,7 +476,10 @@ static int vc4_hvs_init_channel(struct v
@@ -405,7 +481,10 @@ static int vc4_hvs_init_channel(struct v
/* Reload the LUT, since the SRAMs would have been disabled if
* all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
*/
@@ -230,7 +230,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
drm_dev_exit(idx);
@@ -646,7 +725,11 @@ void vc4_hvs_atomic_flush(struct drm_crt
@@ -649,7 +728,11 @@ void vc4_hvs_atomic_flush(struct drm_crt
u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(channel));
if (crtc->state->gamma_lut) {
@@ -17,7 +17,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -143,6 +143,85 @@ static int vc4_hvs_debugfs_dlist(struct
@@ -145,6 +145,85 @@ static int vc4_hvs_debugfs_dlist(struct
return 0;
}
@@ -103,7 +103,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
/* The filter kernel is composed of dwords each containing 3 9-bit
* signed integers packed next to each other.
*/
@@ -850,11 +929,15 @@ int vc4_hvs_debugfs_init(struct drm_mino
@@ -854,11 +933,15 @@ int vc4_hvs_debugfs_init(struct drm_mino
if (!vc4->hvs)
return -ENODEV;
@@ -45,7 +45,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -613,6 +613,9 @@ vc4_crtc_to_vc4_pv_data(const struct vc4
@@ -614,6 +614,9 @@ vc4_crtc_to_vc4_pv_data(const struct vc4
return container_of_const(data, struct vc4_pv_data, base);
}
@@ -57,7 +57,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -596,6 +596,36 @@ out:
@@ -599,6 +599,36 @@ out:
drm_dev_exit(idx);
}
@@ -94,7 +94,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
@@ -626,7 +656,7 @@ int vc4_hvs_atomic_check(struct drm_crtc
@@ -629,7 +659,7 @@ int vc4_hvs_atomic_check(struct drm_crtc
if (ret)
return ret;
@@ -20,7 +20,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -548,8 +548,11 @@ static int vc4_hvs_init_channel(struct v
@@ -553,8 +553,11 @@ static int vc4_hvs_init_channel(struct v
dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
@@ -33,7 +33,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
(interlace ? SCALER_DISPBKGND_INTERLACE : 0));
/* Reload the LUT, since the SRAMs would have been disabled if
@@ -834,18 +837,25 @@ void vc4_hvs_atomic_flush(struct drm_crt
@@ -837,18 +840,25 @@ void vc4_hvs_atomic_flush(struct drm_crt
u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(channel));
if (crtc->state->gamma_lut) {
@@ -13,7 +13,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -614,6 +614,16 @@ static int vc4_hvs_gamma_check(struct dr
@@ -617,6 +617,16 @@ static int vc4_hvs_gamma_check(struct dr
if (!crtc_state->color_mgmt_changed)
return 0;
@@ -12,7 +12,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -408,7 +408,7 @@ struct vc4_plane_state {
@@ -409,7 +409,7 @@ struct vc4_plane_state {
/* Clipped coordinates of the plane on the display. */
int crtc_x, crtc_y, crtc_w, crtc_h;
@@ -42,7 +42,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -626,12 +626,7 @@ struct vc4_crtc_state {
@@ -627,12 +627,7 @@ struct vc4_crtc_state {
bool txp_armed;
unsigned int assigned_channel;
@@ -13,7 +13,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -976,6 +976,9 @@ int vc4_hvs_debugfs_init(struct drm_mino
@@ -980,6 +980,9 @@ int vc4_hvs_debugfs_init(struct drm_mino
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_hvs *hvs = vc4->hvs;
@@ -45,7 +45,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
static const char * const output_format_str[] = {
[VC4_HDMI_OUTPUT_RGB] = "RGB",
[VC4_HDMI_OUTPUT_YUV420] = "YUV 4:2:0",
@@ -478,7 +484,9 @@ static int vc4_hdmi_connector_detect_ctx
@@ -482,7 +488,9 @@ static int vc4_hdmi_connector_detect_ctx
return connector_status_unknown;
}
@@ -30,7 +30,7 @@ Signed-off-by: Dom Cobley <popcornmix@gmail.com>
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -2400,7 +2400,7 @@ static int vc4_hdmi_audio_startup(struct
@@ -2404,7 +2404,7 @@ static int vc4_hdmi_audio_startup(struct
}
if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
@@ -98,7 +98,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
}
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -332,6 +332,9 @@ struct vc4_hvs {
@@ -333,6 +333,9 @@ struct vc4_hvs {
struct drm_mm lbm_mm;
spinlock_t mm_lock;
@@ -108,7 +108,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
struct drm_mm_node mitchell_netravali_filter;
struct debugfs_regset32 regset;
@@ -619,10 +622,16 @@ struct drm_connector *vc4_get_crtc_conne
@@ -620,10 +623,16 @@ struct drm_connector *vc4_get_crtc_conne
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
struct drm_crtc_state *state);
@@ -127,7 +127,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
bool txp_armed;
unsigned int assigned_channel;
@@ -1032,6 +1041,8 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
@@ -1033,6 +1042,8 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output);
int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output);
u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo);
@@ -138,7 +138,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state);
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -412,6 +412,152 @@ static void vc5_hvs_update_gamma_lut(str
@@ -417,6 +417,152 @@ static void vc5_hvs_update_gamma_lut(str
vc5_hvs_lut_load(hvs, vc4_crtc);
}
@@ -291,7 +291,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo)
{
struct drm_device *drm = &hvs->vc4->base;
@@ -643,13 +789,12 @@ int vc4_hvs_atomic_check(struct drm_crtc
@@ -646,13 +792,12 @@ int vc4_hvs_atomic_check(struct drm_crtc
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
@@ -306,7 +306,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
/* The pixelvalve can only feed one encoder (and encoders are
* 1:1 with connectors.)
@@ -662,12 +807,11 @@ int vc4_hvs_atomic_check(struct drm_crtc
@@ -665,12 +810,11 @@ int vc4_hvs_atomic_check(struct drm_crtc
dlist_count++; /* Account for SCALER_CTL0_END. */
@@ -324,7 +324,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
return vc4_hvs_gamma_check(crtc, state);
}
@@ -683,8 +827,9 @@ static void vc4_hvs_install_dlist(struct
@@ -686,8 +830,9 @@ static void vc4_hvs_install_dlist(struct
if (!drm_dev_enter(dev, &idx))
return;
@@ -335,7 +335,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
drm_dev_exit(idx);
}
@@ -711,8 +856,10 @@ static void vc4_hvs_update_dlist(struct
@@ -714,8 +859,10 @@ static void vc4_hvs_update_dlist(struct
spin_unlock_irqrestore(&dev->event_lock, flags);
}
@@ -347,7 +347,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags);
}
@@ -769,8 +916,7 @@ void vc4_hvs_atomic_flush(struct drm_crt
@@ -772,8 +919,7 @@ void vc4_hvs_atomic_flush(struct drm_crt
struct vc4_plane_state *vc4_plane_state;
bool debug_dump_regs = false;
bool enable_bg_fill = false;
@@ -357,7 +357,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
unsigned int zpos = 0;
bool found = false;
int idx;
@@ -788,6 +934,9 @@ void vc4_hvs_atomic_flush(struct drm_crt
@@ -791,6 +937,9 @@ void vc4_hvs_atomic_flush(struct drm_crt
vc4_hvs_dump_state(hvs);
}
@@ -367,7 +367,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
/* Copy all the active planes' dlist contents to the hardware dlist. */
do {
found = false;
@@ -821,7 +970,8 @@ void vc4_hvs_atomic_flush(struct drm_crt
@@ -824,7 +973,8 @@ void vc4_hvs_atomic_flush(struct drm_crt
writel(SCALER_CTL0_END, dlist_next);
dlist_next++;
@@ -377,7 +377,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
if (enable_bg_fill)
/* This sets a black background color fill, as is the case
@@ -960,6 +1110,11 @@ static irqreturn_t vc4_hvs_irq_handler(i
@@ -964,6 +1114,11 @@ static irqreturn_t vc4_hvs_irq_handler(i
irqret = IRQ_HANDLED;
}
@@ -389,7 +389,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
}
/* Clear every per-channel interrupt flag. */
@@ -1014,6 +1169,9 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
@@ -1018,6 +1173,9 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
spin_lock_init(&hvs->mm_lock);
@@ -19,7 +19,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -452,6 +452,8 @@ vc4_hvs_alloc_dlist_entry(struct vc4_hvs
@@ -457,6 +457,8 @@ vc4_hvs_alloc_dlist_entry(struct vc4_hvs
if (!alloc)
return ERR_PTR(-ENOMEM);
@@ -14,7 +14,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -466,6 +466,18 @@ vc4_hvs_alloc_dlist_entry(struct vc4_hvs
@@ -471,6 +471,18 @@ vc4_hvs_alloc_dlist_entry(struct vc4_hvs
return alloc;
}
@@ -33,7 +33,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
void vc4_hvs_mark_dlist_entry_stale(struct vc4_hvs *hvs,
struct vc4_hvs_dlist_allocation *alloc)
{
@@ -553,9 +565,7 @@ static void vc4_hvs_dlist_free_work(stru
@@ -558,9 +570,7 @@ static void vc4_hvs_dlist_free_work(stru
if (!vc4_hvs_frcnt_lte(cur->target_frame_count, frcnt))
continue;
@@ -27,7 +27,7 @@ Signed-off-by: Maxime Ripard <maxime@cerno.tech>
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -490,6 +490,18 @@ void vc4_hvs_mark_dlist_entry_stale(stru
@@ -495,6 +495,18 @@ void vc4_hvs_mark_dlist_entry_stale(stru
if (!drm_mm_node_allocated(&alloc->mm_node))
return;
@@ -18,7 +18,7 @@ Signed-off-by: Matthias Reichl <hias@horus.com>
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -2132,7 +2132,7 @@ vc4_hdmi_encoder_compute_config(const st
@@ -2136,7 +2136,7 @@ vc4_hdmi_encoder_compute_config(const st
{
struct drm_device *dev = vc4_hdmi->connector.dev;
struct drm_connector_state *conn_state = &vc4_state->base;

Some files were not shown because too many files have changed in this diff Show More