From 736a60cd1b65fc7e57f4465d708014f21ae48cca Mon Sep 17 00:00:00 2001 From: Mickael Remond Date: Sat, 8 Jun 2019 18:52:19 +0200 Subject: [PATCH] Use StreamClient interface in StreamManager --- _examples/go.mod | 8 +++++++- _examples/go.sum | 7 ++----- client.go | 2 +- config.go | 2 +- stream_manager.go | 52 ++++++++++++++++++++++++++--------------------- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/_examples/go.mod b/_examples/go.mod index 352eef6..84f9745 100644 --- a/_examples/go.mod +++ b/_examples/go.mod @@ -2,4 +2,10 @@ module gosrc.io/xmpp/_examples go 1.12 -require gosrc.io/xmpp v0.0.0-20190608091551-b7461ae97fed +require ( + github.com/processone/mpg123 v1.0.0 + github.com/processone/soundcloud v1.0.0 + gosrc.io/xmpp v0.0.0-20190608160922-63a29d5c218a +) + +replace gosrc.io/xmpp => gosrc.io/xmpp v0.0.0-20190608160922-63a29d5c218a diff --git a/_examples/go.sum b/_examples/go.sum index 943df1c..123436d 100644 --- a/_examples/go.sum +++ b/_examples/go.sum @@ -1,11 +1,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/processone/mpg123 v1.0.0 h1:o2WOyGZRM255or1Zc/LtF/jARn51B+9aQl72Qace0GA= github.com/processone/mpg123 v1.0.0/go.mod h1:X/FeL+h8vD1bYsG9tIWV3M2c4qNTZOficyvPVBP08go= -github.com/processone/soundcloud v1.0.0 h1:/+i6+Yveb7Y6IFGDSkesYI+HddblzcRTQClazzVHxoE= github.com/processone/soundcloud v1.0.0/go.mod h1:kDLeWpkRtN3C8kIReQdxoiRi92P9xR6yW6qLOJnNWfY= -golang.org/x/net v0.0.0-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM= golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522 h1:bhOzK9QyoD0ogCnFro1m2mz41+Ib0oOhfJnBp5MR4K4= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gosrc.io/xmpp v0.0.0-20190608091551-b7461ae97fed h1:uLrripMKk85UZ0Kd9V2S7qQy2CM4kveMZkCBqBEOqmY= -gosrc.io/xmpp v0.0.0-20190608091551-b7461ae97fed/go.mod h1:it3z4S42Sy7eHWFqwmdFJbygg7lCmbrhKeqK7HQSqSU= +gosrc.io/xmpp v0.0.0-20190608160922-63a29d5c218a h1:TKUhPFlQkBLpoSTNgh4rX64T1FmObGcggIYl7d2q4vM= +gosrc.io/xmpp v0.0.0-20190608160922-63a29d5c218a/go.mod h1:6NJG4vRCxQJMGLxIdroPLPd++FPLOmDqJdJEt2mu4kQ= diff --git a/client.go b/client.go index f9d572a..4bc2a9b 100644 --- a/client.go +++ b/client.go @@ -143,7 +143,7 @@ func (c *Client) Connect() error { } c.updateState(StateConnected) - // Connection is ok, we now open XMPP session + // Client is ok, we now open XMPP session if c.conn, c.Session, err = NewSession(c.conn, c.config); err != nil { return err } diff --git a/config.go b/config.go index 79770b1..92748ac 100644 --- a/config.go +++ b/config.go @@ -12,7 +12,7 @@ type Config struct { Password string PacketLogger *os.File // Used for debugging Lang string // TODO: should default to 'en' - ConnectTimeout int // Connection timeout in seconds. Default to 15 + ConnectTimeout int // Client timeout in seconds. Default to 15 // Insecure can be set to true to allow to open a session without TLS. If TLS // is supported on the server, we will still try to use it. Insecure bool diff --git a/stream_manager.go b/stream_manager.go index fd73ef2..b353c2b 100644 --- a/stream_manager.go +++ b/stream_manager.go @@ -1,6 +1,7 @@ package xmpp // import "gosrc.io/xmpp" import ( + "errors" "time" "golang.org/x/xerrors" @@ -11,13 +12,13 @@ import ( // stream events and doing the right operations. // // It can handle: -// - Connection +// - Client // - Stream establishment workflow // - Reconnection strategies, with exponential backoff. It also takes into account // permanent errors to avoid useless reconnection loops. // - Metrics processing -type StreamSession interface { +type StreamClient interface { Connect() error Disconnect() SetHandler(handler EventHandler) @@ -26,66 +27,71 @@ type StreamSession interface { // StreamManager supervises an XMPP client connection. Its role is to handle connection events and // apply reconnection strategy. type StreamManager struct { - Client *Client - Session *Session + client StreamClient PostConnect PostConnect // Store low level metrics Metrics *Metrics } -type PostConnect func(c *Client) +type PostConnect func(c StreamClient) // NewStreamManager creates a new StreamManager structure, intended to support // handling XMPP client state event changes and auto-trigger reconnection // based on StreamManager configuration. -func NewStreamManager(client *Client, pc PostConnect) *StreamManager { +// TODO: Move parameters to Start and remove factory method +func NewStreamManager(client StreamClient, pc PostConnect) *StreamManager { return &StreamManager{ - Client: client, + client: client, PostConnect: pc, } } // Start launch the connection loop -func (cm *StreamManager) Start() error { - cm.Client.Handler = func(e Event) { +func (sm *StreamManager) Start() error { + if sm.client == nil { + return errors.New("missing stream client") + } + + handler := func(e Event) { switch e.State { case StateConnected: - cm.Metrics.setConnectTime() + sm.Metrics.setConnectTime() case StateSessionEstablished: - cm.Metrics.setLoginTime() + sm.Metrics.setLoginTime() case StateDisconnected: // Reconnect on disconnection - cm.connect() + sm.connect() case StateStreamError: - cm.Client.Disconnect() + sm.client.Disconnect() // Only try reconnecting if we have not been kicked by another session to avoid connection loop. if e.StreamError != "conflict" { - cm.connect() + sm.connect() } } } + sm.client.SetHandler(handler) - return cm.connect() + return sm.connect() } // Stop cancels pending operations and terminates existing XMPP client. -func (cm *StreamManager) Stop() { +func (sm *StreamManager) Stop() { // Remove on disconnect handler to avoid triggering reconnect - cm.Client.Handler = nil - cm.Client.Disconnect() + sm.client.SetHandler(nil) + sm.client.Disconnect() } // connect manages the reconnection loop and apply the define backoff to avoid overloading the server. -func (cm *StreamManager) connect() error { +func (sm *StreamManager) connect() error { var backoff Backoff // TODO: Group backoff calculation features with connection manager? for { var err error // TODO: Make it possible to define logger to log disconnect and reconnection attempts - cm.Metrics = initMetrics() + sm.Metrics = initMetrics() - if err = cm.Client.Connect(); err != nil { + if err = sm.client.Connect(); err != nil { var actualErr ConnError if xerrors.As(err, &actualErr) { if actualErr.Permanent { @@ -98,8 +104,8 @@ func (cm *StreamManager) connect() error { } } - if cm.PostConnect != nil { - cm.PostConnect(cm.Client) + if sm.PostConnect != nil { + sm.PostConnect(sm.client) } return nil }