func (c Client) fetchEvents(since int64, lastID string) (*pollResponse, error) {
	u := c.options.SubscribeUrl
	if c.options.LoggingEnabled {
		log.Printf("INFO - golongpoll.Client.fetchEvents - Polling Events. %s\n", c.getCommonLogFields(since, lastID))
	}
	query := u.Query()
	query.Set("category", c.options.Category)
	query.Set("since_time", fmt.Sprintf("%d", since))
	if len(lastID) > 0 {
		query.Set("last_id", lastID)
	}
	query.Set("timeout", fmt.Sprintf("%d", c.options.PollTimeoutSeconds))
	u.RawQuery = query.Encode()
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("HTTP request error: %v", err)
	}
	if len(c.options.BasicAuthUsername) > 0 && len(c.options.BasicAuthPassword) > 0 {
		req.SetBasicAuth(c.options.BasicAuthUsername, c.options.BasicAuthPassword)
	}
	for _, kvpair := range c.options.ExtraHeaders {
		req.Header.Add(kvpair.Key, kvpair.Value)
	}
	resp, err := c.options.HttpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Error connecting to %v, error: %s", u, err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP response code: %d", resp.StatusCode)
	}
	decoder := json.NewDecoder(resp.Body)
	var pollResp pollResponse
	err = decoder.Decode(&pollResp)
	if err != nil {
		return nil, fmt.Errorf("Error decoding poll response: %v", err)
	}
	if len(pollResp.ErrorMessage) > 0 {
		return nil, fmt.Errorf("Longpoll API error message: %s", pollResp.ErrorMessage)
	}
	return &pollResp, nil
}
Call the longpoll server to get the events since a specific timestamp
package client
import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"sync/atomic"
	"time"
	"github.com/jcuga/golongpoll"
)
type ClientOptions struct {
	SubscribeUrl url.URL
	Category string
	PublishUrl url.URL
	PollTimeoutSeconds uint
	ReattemptWaitSeconds uint
	SuccessWaitSeconds uint
	HttpClient *http.Client
	BasicAuthUsername string
	BasicAuthPassword string
	LoggingEnabled bool
	OnFailure func(err error) bool
	ExtraHeaders []HeaderKeyValue
}
type HeaderKeyValue struct {
	Key   string
	Value string
}
type Client struct {
	runID uint64
	options ClientOptions
	events chan *golongpoll.Event
	started bool
	stopped bool
}
func NewClient(opts ClientOptions) (*Client, error) {
	if len(opts.Category) == 0 {
		return nil, fmt.Errorf("opts.Category cannot be empty")
	}
	if (len(opts.BasicAuthUsername) > 0 && len(opts.BasicAuthPassword) == 0) ||
		(len(opts.BasicAuthPassword) > 0 && len(opts.BasicAuthUsername) == 0) {
		return nil, fmt.Errorf("missing opts.BasicAuthUsername or opts.BasicAuthPassword value. Must have both or neither.")
	}
	if opts.PollTimeoutSeconds == 0 {
		opts.PollTimeoutSeconds = 45
	}
	if opts.ReattemptWaitSeconds == 0 {
		opts.ReattemptWaitSeconds = 30
	}
	if opts.HttpClient == nil {
		opts.HttpClient = &http.Client{}
	}
	if len(opts.SubscribeUrl.String()) == 0 && len(opts.PublishUrl.String()) == 0 {
		return nil, fmt.Errorf("At least one of opts.SubscribeUrl and opts.PublishUrl must be non-empty.")
	}
	client := &Client{
		options: opts,
		events:  make(chan *golongpoll.Event, 100),
	}
	return client, nil
}
func (c *Client) Start(pollSince time.Time) <-chan *golongpoll.Event {
	if c.stopped {
		panic("golongpoll Client cannot be started after already stopped.")
	}
	if c.started {
		panic("golongpoll Client cannot be started more than once.")
	}
	if len(c.options.SubscribeUrl.String()) == 0 {
		log.Printf("ERROR - golongpoll.Client.Publish - Cannot call Start when client options.SubscribeUrl is empty.")
		val := make(chan *golongpoll.Event)
		close(val)
		return val
	}
	c.started = true
	u := c.options.SubscribeUrl
	atomic.AddUint64(&(c.runID), 1)
	currentRunID := atomic.LoadUint64(&(c.runID))
	go func(runID uint64, u url.URL, pollSince time.Time) {
		since := pollSince.Unix() * 1000  
		lastID := ""                      
		if c.options.LoggingEnabled {
			log.Printf("INFO - golongpoll.Client.Start - Start polling for events, %s\n", c.getCommonLogFields(since, lastID))
		}
		for {
			if c.doQuit(runID) {
				return
			}
			pollResp, err := c.fetchEvents(since, lastID)
			if err != nil {
				if c.options.LoggingEnabled {
					log.Printf("ERROR - golongpoll.Client.run - fetchEvents error: %v, %s\n", err, c.getCommonLogFields(since, lastID))
				}
				if c.options.OnFailure != nil {
					if !c.options.OnFailure(err) {
						if c.options.LoggingEnabled {
							log.Printf("WARN - golongpoll.Client.run - Stopping due to OnFailure callback, %s\n", c.getCommonLogFields(since, lastID))
						}
						close(c.events)
						return
					}
				}
				if c.doQuit(runID) {
					return
				}
				if c.options.LoggingEnabled {
					log.Printf("INFO - golongpoll.Client.run - Reattempting in %d seconds, %s\n", c.options.ReattemptWaitSeconds,
						c.getCommonLogFields(since, lastID))
				}
				time.Sleep(time.Duration(c.options.ReattemptWaitSeconds) * time.Second)
				continue
			}
			if c.doQuit(runID) {
				return
			}
			eventsLen := len(pollResp.Events)
			if eventsLen > 0 {
				if c.options.LoggingEnabled {
					log.Printf("INFO - golongpoll.Client.run - Got %d event(s), %s\n", eventsLen, c.getCommonLogFields(since, lastID))
				}
				doQuitCheck := eventsLen >= cap(c.events)-len(c.events)
				for _, event := range pollResp.Events {
					since = event.Timestamp
					lastID = event.ID.String()
					if doQuitCheck && c.doQuit(runID) {
						return
					}
					c.events <- event
				}
				if c.options.SuccessWaitSeconds > 0 {
					time.Sleep(time.Duration(c.options.SuccessWaitSeconds) * time.Second)
				}
			} else {
				if pollResp.Timestamp > since {
					since = pollResp.Timestamp
				} else if pollResp.Timestamp == 0 {
					if c.options.LoggingEnabled {
						log.Printf("WARN - golongpoll.Client.run - got response without events, timeout, or error. %s\n",
							c.getCommonLogFields(since, lastID))
					}
				}
			}
		}
	}(currentRunID, u, pollSince)
	return c.events
}
func (c *Client) Stop() {
	if c.stopped {
		panic("golongpoll Client cannot be stopped more than once.")
	}
	if !c.started {
		panic("golongpoll Client cannot be stopped, never started.")
	}
	c.stopped = true
	if c.options.LoggingEnabled {
		log.Printf("INFO - golongpoll.Client.Stop - Sending stop signal. url: %s, category: \"%v\", timeout: %v,\n",
			c.options.SubscribeUrl.String(), c.options.Category, c.options.PollTimeoutSeconds)
	}
	atomic.AddUint64(&(c.runID), 1)
}
func (c *Client) doQuit(runID uint64) bool {
	newRunID := atomic.LoadUint64(&(c.runID))
	if newRunID != runID {
		if c.options.LoggingEnabled {
			log.Printf("INFO - golongpoll.Client.run - received stop signal, stopping. url: %s, category: \"%v\", timeout: %v,\n",
				c.options.SubscribeUrl.String(), c.options.Category, c.options.PollTimeoutSeconds)
		}
		close(c.events)
		return true
	}
	return false
}
func (c *Client) getCommonLogFields(since int64, lastID string) string {
	return fmt.Sprintf("subscribe_url: %s, category: \"%v\", timeout: %v, since_time: %v, last_id: %v",
		c.options.SubscribeUrl.String(), c.options.Category, c.options.PollTimeoutSeconds, since, lastID)
}
type pollResponse struct {
	Events []*golongpoll.Event `json:"events"`
	Timestamp int64 `json:"timestamp"`
	ErrorMessage string `json:"error"`
}