client.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Copyright (C) 2015 Audrius Butkevicius and Contributors (see the CONTRIBUTORS file).
  2. package client
  3. import (
  4. "context"
  5. "crypto/tls"
  6. "fmt"
  7. "net/url"
  8. "time"
  9. "github.com/syncthing/syncthing/lib/relay/protocol"
  10. "github.com/syncthing/syncthing/lib/sync"
  11. "github.com/syncthing/syncthing/lib/util"
  12. "github.com/thejerf/suture/v4"
  13. )
  14. type relayClientFactory func(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) RelayClient
  15. var (
  16. supportedSchemes = map[string]relayClientFactory{
  17. "relay": newStaticClient,
  18. "dynamic+http": newDynamicClient,
  19. "dynamic+https": newDynamicClient,
  20. }
  21. )
  22. type RelayClient interface {
  23. suture.Service
  24. Error() error
  25. Latency() time.Duration
  26. String() string
  27. Invitations() chan protocol.SessionInvitation
  28. URI() *url.URL
  29. }
  30. func NewClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) (RelayClient, error) {
  31. factory, ok := supportedSchemes[uri.Scheme]
  32. if !ok {
  33. return nil, fmt.Errorf("unsupported scheme: %s", uri.Scheme)
  34. }
  35. return factory(uri, certs, invitations, timeout), nil
  36. }
  37. type commonClient struct {
  38. util.ServiceWithError
  39. invitations chan protocol.SessionInvitation
  40. closeInvitationsOnFinish bool
  41. mut sync.RWMutex
  42. }
  43. func newCommonClient(invitations chan protocol.SessionInvitation, serve func(context.Context) error, creator string) commonClient {
  44. c := commonClient{
  45. invitations: invitations,
  46. mut: sync.NewRWMutex(),
  47. }
  48. newServe := func(ctx context.Context) error {
  49. defer c.cleanup()
  50. return serve(ctx)
  51. }
  52. c.ServiceWithError = util.AsService(newServe, creator)
  53. if c.invitations == nil {
  54. c.closeInvitationsOnFinish = true
  55. c.invitations = make(chan protocol.SessionInvitation)
  56. }
  57. return c
  58. }
  59. func (c *commonClient) cleanup() {
  60. c.mut.Lock()
  61. if c.closeInvitationsOnFinish {
  62. close(c.invitations)
  63. }
  64. c.mut.Unlock()
  65. }
  66. func (c *commonClient) Invitations() chan protocol.SessionInvitation {
  67. c.mut.RLock()
  68. defer c.mut.RUnlock()
  69. return c.invitations
  70. }