@@ -5,13 +5,9 @@ import (
55 "errors"
66 "fmt"
77 "io"
8- "maps"
98 "net/http"
109 "net/url"
1110 "regexp"
12- "slices"
13- "sort"
14- "strconv"
1511 "strings"
1612)
1713
@@ -37,12 +33,11 @@ func fetchDebURL(ctx context.Context, client *http.Client) (debURL string, err e
3733 return "" , fmt .Errorf ("reading response body: %w" , err )
3834 }
3935
40- debURLs , err := extractDebURLs (string (html ), url )
36+ debURL , err = extractDebURL (string (html ), url )
4137 if err != nil {
4238 return "" , fmt .Errorf ("extracting .deb URLs from download page: %w" , err )
4339 }
44-
45- return findBestDebURL (debURLs ), nil
40+ return debURL , nil
4641}
4742
4843func fetchURL (ctx context.Context , client * http.Client , rawURL string ) (content []byte , err error ) {
@@ -57,7 +52,7 @@ func fetchURL(ctx context.Context, client *http.Client, rawURL string) (content
5752 }
5853 defer response .Body .Close ()
5954
60- if response .StatusCode < http .StatusOK || response . StatusCode > 299 {
55+ if response .StatusCode != http .StatusOK {
6156 return nil , fmt .Errorf ("HTTP status code %d" , response .StatusCode )
6257 }
6358
@@ -73,16 +68,15 @@ var (
7368 hrefDebPattern = regexp .MustCompile (`href=["']([^"']+\.deb)["']` )
7469)
7570
76- func extractDebURLs (pageHTML , baseURL string ) (debURLs [] string , err error ) {
71+ func extractDebURL (pageHTML , baseURL string ) (debURL string , err error ) {
7772 baseParsed , err := url .Parse (baseURL )
7873 if err != nil {
79- return nil , fmt .Errorf ("parsing base url %q: %w" , baseURL , err )
74+ return "" , fmt .Errorf ("parsing base url %q: %w" , baseURL , err )
8075 }
8176
82- urlsSet := make (map [string ]struct {})
83-
84- for _ , match := range debURLPattern .FindAllString (pageHTML , - 1 ) {
85- urlsSet [match ] = struct {}{}
77+ debURL = debURLPattern .FindString (pageHTML )
78+ if debURL != "" {
79+ return debURL , nil
8680 }
8781
8882 for _ , groups := range hrefDebPattern .FindAllStringSubmatch (pageHTML , - 1 ) {
@@ -94,98 +88,9 @@ func extractDebURLs(pageHTML, baseURL string) (debURLs []string, err error) {
9488 if err != nil {
9589 continue
9690 }
97- resolved := baseParsed .ResolveReference (href ).String ()
98- urlsSet [resolved ] = struct {}{}
99- }
100-
101- if len (urlsSet ) == 0 {
102- return nil , errors .New ("no .deb URL found" )
103- }
104-
105- return slices .Collect (maps .Keys (urlsSet )), nil
106- }
107-
108- func findBestDebURL (debURLs []string ) (bestURL string ) {
109- type debCandidate struct {
110- url string
111- score int
112- major uint16
113- minor uint16
114- patch uint16
115- position uint
116- }
117- candidates := make ([]debCandidate , len (debURLs ))
118- for i , debURL := range debURLs {
119- score := scoreDebURL (debURL )
120- major , minor , patch := parseSemverFromURL (debURL )
121- candidates [i ] = debCandidate {
122- url : debURL ,
123- score : score ,
124- major : major ,
125- minor : minor ,
126- patch : patch ,
127- position : uint (i ), //nolint:gosec
128- }
129- }
130-
131- sort .Slice (candidates , func (i , j int ) bool {
132- left := candidates [i ]
133- right := candidates [j ]
134- if left .score != right .score {
135- return left .score > right .score
136- }
137- if left .major != right .major {
138- return left .major > right .major
139- }
140- if left .minor != right .minor {
141- return left .minor > right .minor
142- }
143- if left .patch != right .patch {
144- return left .patch > right .patch
145- }
146- if left .position != right .position {
147- return left .position < right .position
148- }
149- return left .url < right .url
150- })
151-
152- return candidates [0 ].url
153- }
154-
155- func scoreDebURL (debURL string ) (score int ) {
156- keywordToPoints := map [string ]int {
157- "purevpn" : 40 ,
158- "linux" : 30 ,
159- "gui" : 20 ,
160- "amd64" : 20 ,
161- "arm" : - 25 ,
162- "aarch" : - 25 ,
163- "i386" : - 25 ,
164- "x86" : - 25 ,
165- }
166-
167- debURL = strings .ToLower (debURL )
168- for keyword , points := range keywordToPoints {
169- if strings .Contains (debURL , keyword ) {
170- score += points
171- }
172- }
173-
174- return score
175- }
176-
177- var semverPattern = regexp .MustCompile (`(\d+)\.(\d+)\.(\d+)` )
178-
179- func parseSemverFromURL (rawURL string ) (major , minor , patch uint16 ) {
180- match := semverPattern .FindStringSubmatch (rawURL )
181- const expectedMatchesPlusOne = 4 // full match + 3 groups
182- if len (match ) != expectedMatchesPlusOne {
183- return 0 , 0 , 0
91+ debURL = baseParsed .ResolveReference (href ).String ()
92+ return debURL , nil
18493 }
18594
186- const base , bitSize = 10 , 16
187- majorUint64 , _ := strconv .ParseUint (match [1 ], base , bitSize )
188- minorUint64 , _ := strconv .ParseUint (match [2 ], base , bitSize )
189- patchUint64 , _ := strconv .ParseUint (match [3 ], base , bitSize )
190- return uint16 (majorUint64 ), uint16 (minorUint64 ), uint16 (patchUint64 )
95+ return "" , errors .New ("no .deb URL found" )
19196}
0 commit comments