diff --git a/cmd/root.go b/cmd/root.go index e2987bc..0380139 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -21,6 +21,7 @@ func init() { rootCmd.Flags().String("host", "api.modrinth.com", "Labrinth host") rootCmd.Flags().String("server-dir", "mc", "Server directory path") rootCmd.Flags().String("server-file", "", "Server jar file name") + rootCmd.Flags().String("proxy", "", "Use a proxy to download") } var rootCmd = &cobra.Command{ @@ -41,6 +42,17 @@ var rootCmd = &cobra.Command{ log.Fatalln(err) } + proxy, err := cmd.Flags().GetString("proxy") + if err != nil { + log.Fatalln(err) + } + if proxy != "" { + err := http.Instance.SetProxy(proxy) + if err != nil { + log.Fatalln(err) + } + } + input := args[0] version := "" if len(args) > 1 { diff --git a/http/client.go b/http/client.go index e5b5c83..01d35ff 100644 --- a/http/client.go +++ b/http/client.go @@ -10,7 +10,6 @@ import ( "os" "path" "regexp" - "runtime/debug" "strconv" ) @@ -18,25 +17,7 @@ type ErrorModel interface { String() string } -type Client struct { - UserAgent string - HTTPClient *http.Client -} - -// TODO: global lookup map host -> ratelimit hits left and sleep wait strategy - -var Instance *Client = nil - -func init() { - Instance = &Client{ - UserAgent: "mrpack-install", - HTTPClient: &http.Client{}, - } - info, ok := debug.ReadBuildInfo() - if ok && info.Main.Path != "" { - Instance.UserAgent = info.Main.Path + "/" + info.Main.Version - } -} +var Instance = NewHTTPClient() func (client *Client) GetJson(url string, respModel interface{}, errModel ErrorModel) error { request, err := http.NewRequest(http.MethodGet, url, nil) @@ -49,7 +30,7 @@ func (client *Client) GetJson(url string, respModel interface{}, errModel ErrorM request.Close = true - response, err := client.HTTPClient.Do(request) + response, err := client.Do(request) if err != nil { return err } @@ -86,7 +67,7 @@ func (client *Client) DownloadFile(url string, downloadDir string, fileName stri request.Header.Set("User-Agent", client.UserAgent) request.Close = true - response, err := client.HTTPClient.Do(request) + response, err := client.Do(request) if err != nil { return "", err } diff --git a/http/http_client.go b/http/http_client.go new file mode 100644 index 0000000..dd5d6ac --- /dev/null +++ b/http/http_client.go @@ -0,0 +1,115 @@ +package http + +import ( + "crypto/tls" + "net/http" + "net/http/cookiejar" + "net/url" + "runtime/debug" + "time" +) + +type Client struct { + http.Client + insecureSkipVerify bool + UserAgent string + transport *http.Transport +} + +// TODO: global lookup map host -> ratelimit hits left and sleep wait strategy + +func NewHTTPClient() *Client { + client := &Client{ + Client: http.Client{}, + UserAgent: "mrpack-install", + } + client.Client.Jar, _ = cookiejar.New(nil) + info, ok := debug.ReadBuildInfo() + if ok && info.Main.Path != "" { + client.UserAgent = info.Main.Path + "/" + info.Main.Version + } + return client +} + +func (client *Client) lazyInit() { + if client.transport == nil { + client.transport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, + }, + TLSHandshakeTimeout: 20 * time.Second, + DisableKeepAlives: false, + DisableCompression: false, // gzip + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + ResponseHeaderTimeout: 25 * time.Second, + ExpectContinueTimeout: 10 * time.Second, + } + client.Client.Transport = client.transport + } +} + +func (client *Client) SetUserAgent(ua string) { + client.UserAgent = ua +} + +func (client *Client) SetCookiejar(jar http.CookieJar) { + client.Client.Jar = jar +} + +func (client *Client) ResetCookiejar() { + client.Jar, _ = cookiejar.New(nil) +} + +func (client *Client) SetProxy(CustomProxy string) error { + client.lazyInit() + proxy, err := url.Parse(CustomProxy) + if err != nil { + return err + } + + client.transport.Proxy = http.ProxyURL(proxy) + + // Test proxy + httpUrl := "https://api.modrinth.com/" + response, err := client.Get(httpUrl) + if err != nil { + return err + } + if response.StatusCode != http.StatusOK { + return err + } + return nil +} + +func (client *Client) SetInsecureSkipVerify(b bool) { + client.lazyInit() + client.transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: b, + } +} + +func (client *Client) SetKeepAlive(b bool) { + client.lazyInit() + client.transport.DisableKeepAlives = !b +} + +func (client *Client) SetGzip(b bool) { + client.lazyInit() + client.transport.DisableCompression = !b +} + +func (client *Client) SetResponseHeaderTimeout(t time.Duration) { + client.lazyInit() + client.transport.ResponseHeaderTimeout = t +} + +func (client *Client) SetTLSHandshakeTimeout(t time.Duration) { + client.lazyInit() + client.transport.TLSHandshakeTimeout = t +} + +func (client *Client) SetTimeout(t time.Duration) { + client.Client.Timeout = t +}