Преглед изворни кода

Allow using a standard HTTP proxy in reddit widget

Svilen Markov пре 6 месеци
родитељ
комит
108c83588c
3 измењених фајлова са 105 додато и 16 уклоњено
  1. 25 1
      docs/configuration.md
  2. 50 0
      internal/glance/config-fields.go
  3. 30 15
      internal/glance/widget-reddit.go

+ 25 - 1
docs/configuration.md

@@ -746,6 +746,7 @@ Example:
 | collapse-after | integer | no | 5 |
 | comments-url-template | string | no | https://www.reddit.com/{POST-PATH} |
 | request-url-template | string | no |  |
+| proxy | string or multiple parameters | no |  |
 | sort-by | string | no | hot |
 | top-period | string | no | day |
 | search | string | no | |
@@ -807,7 +808,7 @@ r/selfhosted/comments/bsp01i/welcome_to_rselfhosted_please_read_this_first/
 `{SUBREDDIT}` - the subreddit name
 
 ##### `request-url-template`
-A custom request url that will be used to fetch the data instead. This is useful when you're hosting Glance on a VPS and Reddit is blocking the requests, and you want to route it through an HTTP proxy.
+A custom request URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to route them through a proxy that accepts the URL as either a part of the path or a query parameter.
 
 Placeholders:
 
@@ -818,6 +819,29 @@ https://proxy/{REQUEST-URL}
 https://your.proxy/?url={REQUEST-URL}
 ```
 
+##### `proxy`
+A custom HTTP/HTTPS proxy URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to bypass the restriction by routing the requests through a proxy. Example:
+
+```
+proxy: http://user:pass@proxy.com:8080
+proxy: https://user:pass@proxy.com:443
+```
+
+Alternatively, you can specify the proxy URL as well as additional options by using multiple parameters:
+
+```yaml
+proxy:
+  url: http://proxy.com:8080
+  allow-insecure: true
+  timeout: 10s
+```
+
+###### `allow-insecure`
+When set to `true`, allows the use of insecure connections such as when the proxy has a self-signed certificate.
+
+###### `timeout`
+The maximum time to wait for a response from the proxy. The value is a string and must be a number followed by one of s, m, h, d. Example: `10s` for 10 seconds, `1m` for 1 minute, etc
+
 ##### `sort-by`
 Can be used to specify the order in which the posts should get returned. Possible values are `hot`, `new`, `top` and `rising`.
 

+ 50 - 0
internal/glance/config-fields.go

@@ -1,7 +1,10 @@
 package glance
 
 import (
+	"crypto/tls"
 	"fmt"
+	"net/http"
+	"net/url"
 	"regexp"
 	"strconv"
 	"strings"
@@ -169,3 +172,50 @@ func (i *customIconField) UnmarshalYAML(node *yaml.Node) error {
 	*i = newCustomIconField(value)
 	return nil
 }
+
+type proxyOptionsField struct {
+	URL           string        `yaml:"url"`
+	AllowInsecure bool          `yaml:"allow-insecure"`
+	Timeout       durationField `yaml:"timeout"`
+	client        *http.Client  `yaml:"-"`
+}
+
+func (p *proxyOptionsField) UnmarshalYAML(node *yaml.Node) error {
+	type proxyOptionsFieldAlias proxyOptionsField
+	alias := (*proxyOptionsFieldAlias)(p)
+	var proxyURL string
+
+	if err := node.Decode(&proxyURL); err != nil {
+		if err := node.Decode(alias); err != nil {
+			return err
+		}
+	}
+
+	if proxyURL == "" && p.URL == "" {
+		return nil
+	}
+
+	if p.URL != "" {
+		proxyURL = p.URL
+	}
+
+	parsedUrl, err := url.Parse(proxyURL)
+	if err != nil {
+		return fmt.Errorf("parsing proxy URL: %v", err)
+	}
+
+	var timeout = defaultClientTimeout
+	if p.Timeout > 0 {
+		timeout = time.Duration(p.Timeout)
+	}
+
+	p.client = &http.Client{
+		Timeout: timeout,
+		Transport: &http.Transport{
+			Proxy:           http.ProxyURL(parsedUrl),
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: p.AllowInsecure},
+		},
+	}
+
+	return nil
+}

+ 30 - 15
internal/glance/widget-reddit.go

@@ -19,19 +19,20 @@ var (
 
 type redditWidget struct {
 	widgetBase          `yaml:",inline"`
-	Posts               forumPostList `yaml:"-"`
-	Subreddit           string        `yaml:"subreddit"`
-	Style               string        `yaml:"style"`
-	ShowThumbnails      bool          `yaml:"show-thumbnails"`
-	ShowFlairs          bool          `yaml:"show-flairs"`
-	SortBy              string        `yaml:"sort-by"`
-	TopPeriod           string        `yaml:"top-period"`
-	Search              string        `yaml:"search"`
-	ExtraSortBy         string        `yaml:"extra-sort-by"`
-	CommentsUrlTemplate string        `yaml:"comments-url-template"`
-	Limit               int           `yaml:"limit"`
-	CollapseAfter       int           `yaml:"collapse-after"`
-	RequestUrlTemplate  string        `yaml:"request-url-template"`
+	Posts               forumPostList     `yaml:"-"`
+	Subreddit           string            `yaml:"subreddit"`
+	Proxy               proxyOptionsField `yaml:"proxy"`
+	Style               string            `yaml:"style"`
+	ShowThumbnails      bool              `yaml:"show-thumbnails"`
+	ShowFlairs          bool              `yaml:"show-flairs"`
+	SortBy              string            `yaml:"sort-by"`
+	TopPeriod           string            `yaml:"top-period"`
+	Search              string            `yaml:"search"`
+	ExtraSortBy         string            `yaml:"extra-sort-by"`
+	CommentsUrlTemplate string            `yaml:"comments-url-template"`
+	Limit               int               `yaml:"limit"`
+	CollapseAfter       int               `yaml:"collapse-after"`
+	RequestUrlTemplate  string            `yaml:"request-url-template"`
 }
 
 func (widget *redditWidget) initialize() error {
@@ -94,6 +95,7 @@ func (widget *redditWidget) update(ctx context.Context) {
 		widget.Search,
 		widget.CommentsUrlTemplate,
 		widget.RequestUrlTemplate,
+		widget.Proxy.client,
 		widget.ShowFlairs,
 	)
 
@@ -161,7 +163,16 @@ func templateRedditCommentsURL(template, subreddit, postId, postPath string) str
 	return template
 }
 
-func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate, requestUrlTemplate string, showFlairs bool) (forumPostList, error) {
+func fetchSubredditPosts(
+	subreddit,
+	sort,
+	topPeriod,
+	search,
+	commentsUrlTemplate,
+	requestUrlTemplate string,
+	proxyClient *http.Client,
+	showFlairs bool,
+) (forumPostList, error) {
 	query := url.Values{}
 	var requestUrl string
 
@@ -180,8 +191,12 @@ func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate
 		requestUrl = fmt.Sprintf("https://www.reddit.com/r/%s/%s.json?%s", subreddit, sort, query.Encode())
 	}
 
+	var client requestDoer = defaultHTTPClient
+
 	if requestUrlTemplate != "" {
 		requestUrl = strings.ReplaceAll(requestUrlTemplate, "{REQUEST-URL}", requestUrl)
+	} else if proxyClient != nil {
+		client = proxyClient
 	}
 
 	request, err := http.NewRequest("GET", requestUrl, nil)
@@ -191,7 +206,7 @@ func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate
 
 	// Required to increase rate limit, otherwise Reddit randomly returns 429 even after just 2 requests
 	setBrowserUserAgentHeader(request)
-	responseJson, err := decodeJsonFromRequest[subredditResponseJson](defaultHTTPClient, request)
+	responseJson, err := decodeJsonFromRequest[subredditResponseJson](client, request)
 	if err != nil {
 		return nil, err
 	}