client.go 2.0 KB

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