pool.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright (C) 2015 Audrius Butkevicius and Contributors.
  2. package main
  3. import (
  4. "bytes"
  5. "crypto/tls"
  6. "encoding/json"
  7. "io"
  8. "log"
  9. "net/http"
  10. "net/url"
  11. "time"
  12. )
  13. const (
  14. httpStatusEnhanceYourCalm = 429
  15. )
  16. func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certificate) {
  17. if debug {
  18. log.Println("Joining", pool)
  19. }
  20. for {
  21. uriCopy := *uri
  22. uriCopy.Host = mapping.Address().String()
  23. var b bytes.Buffer
  24. json.NewEncoder(&b).Encode(struct {
  25. URL string `json:"url"`
  26. }{
  27. uriCopy.String(),
  28. })
  29. poolUrl, err := url.Parse(pool)
  30. if err != nil {
  31. log.Printf("Could not parse pool url '%s': %v", pool, err)
  32. }
  33. client := http.DefaultClient
  34. if poolUrl.Scheme == "https" {
  35. // Sent our certificate in join request
  36. client = &http.Client{
  37. Transport: &http.Transport{
  38. TLSClientConfig: &tls.Config{
  39. Certificates: []tls.Certificate{ownCert},
  40. },
  41. },
  42. }
  43. }
  44. resp, err := client.Post(pool, "application/json", &b)
  45. if err != nil {
  46. log.Printf("Error joining pool %v: HTTP request: %v", pool, err)
  47. time.Sleep(time.Minute)
  48. continue
  49. }
  50. bs, err := io.ReadAll(resp.Body)
  51. resp.Body.Close()
  52. if err != nil {
  53. log.Printf("Error joining pool %v: reading response: %v", pool, err)
  54. time.Sleep(time.Minute)
  55. continue
  56. }
  57. switch resp.StatusCode {
  58. case http.StatusOK:
  59. var x struct {
  60. EvictionIn time.Duration `json:"evictionIn"`
  61. }
  62. if err := json.Unmarshal(bs, &x); err == nil {
  63. rejoin := x.EvictionIn - (x.EvictionIn / 5)
  64. log.Printf("Joined pool %s, rejoining in %v", pool, rejoin)
  65. time.Sleep(rejoin)
  66. continue
  67. }
  68. log.Printf("Joined pool %s, failed to deserialize response: %v", pool, err)
  69. case http.StatusInternalServerError:
  70. log.Printf("Failed to join %v: server error", pool)
  71. log.Printf("Response data: %s", bs)
  72. time.Sleep(time.Minute)
  73. continue
  74. case http.StatusBadRequest:
  75. log.Printf("Failed to join %v: request or check error", pool)
  76. log.Printf("Response data: %s", bs)
  77. time.Sleep(time.Minute)
  78. continue
  79. case httpStatusEnhanceYourCalm:
  80. log.Printf("Failed to join %v: under load (rate limiting)", pool)
  81. time.Sleep(time.Minute)
  82. continue
  83. case http.StatusUnauthorized:
  84. log.Printf("Failed to join %v: IP address not matching external address", pool)
  85. log.Println("Aborting")
  86. return
  87. default:
  88. log.Printf("Failed to join %v: unexpected status code from server: %d", pool, resp.StatusCode)
  89. log.Printf("Response data: %s", bs)
  90. time.Sleep(time.Minute)
  91. continue
  92. }
  93. time.Sleep(time.Hour)
  94. }
  95. }