push

package module
v0.0.0-...-122b339 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 12, 2014 License: BSD-2-Clause Imports: 3 Imported by: 0

README

PUSH

Features:

  • Push to APN and GCM through a single interface.
  • Streaming architecture.

Stream rows of device tokens from your database and send one by one until you are done. No need to buffer the whole list in advance or build your own bufferring solution. GCM payloads are collected into batches automatically.

INSTALL

go get github.com/chakrit/push

Internally, push use the following noteworthy packages:

More providers (or alternative implementation) can be added by implenmenting the Service interface (docs coming soon.)

CONFIGURE

Creates a client:

client = push.NewClient()

Adds APN push target:

client.Add(&push.APN{
  Gateway:         "gateway.sandbox.push.apple.com:2195",
  FeedbackGateway: "feedback.sandbox.push.apple.com:2196",
  KeyFile:         "your_apn_key_file.pem",
  CertFile:        "your_apn_cert_file.pem",
})

Adds GCM push target:

client.Add(&push.GCM{
  ApiKey:    "YOUR_GCM_API_KEY_HERE",
  BatchSize: 1000, // or your preferred batch processing size.
})

Refer to GCM docs for the maximum number of tokens that can be sent at once.

Starts all the services and feedback listeners.

e := client.Start()
if e != nil {
  // log
}

NOTE: You need to listen on the feedback channel, otherwise it will block the whole process. Refer to the feedback section below for more info / code samples.

SEND / STREAM

Starts a new session:

session := client.Send(&push.Payload{
  Title:       "Hello Mr. Nice Customer!"
  Description: "A new product awaits you."
  Data:        map[string]interface{}{"referenceId": 123}
})
defer session.Close()

Sends push.Device{} as you gets them from your database:

defer rows.Close()
for rows.Next() {

  // obtain one device (example is using sqlx).
  var device *DeviceInfo
  e := rows.StructScan(device)
  noError(e)

  // send to a single device
  switch device.Class {
  case "iphone":
    session.Devices <- &push.Device{device.Token, push.DeviceTypeIOS}
  case "android":
    session.Devices <- &push.Device{device.Token, push.DeviceTypeAndroid}
  }

}

FEEDBACK

You need to listen for Feedbacks for all push notifications. If you do not wish to handles feedback at the current point in time, simply spin an empty loop to empty the feedback queue. This is required to keep the engine going.

go func() {
  for result := range client.Feedbacks {
    if result.NewToken != "" {
      // GCM may return a new canonical device token.
      // You need to update your result.Token in yoru database to result.NewToken here.
      go MergeDeviceToken(result.Token, result.NewToken)
    }

    switch {
    case result.Error == nil: // success

    case result.Error == push.ErrInvalidDevice:
      // Bad device token as returned by both service providers.
      // You should remove the device association from your database here.
      go DeleteDeviceToken(result.Token)

    default:
      // Usually transfer general IO error.
    }
  }
}

There maybe any number of feedbacks received depending on the nature of each push providers. For example, GCM returns feedback for all devices sent to their endpoint but APN will only return ones where the delivery failed.

The presence (or absence) of Feedback does not directly translate to push notification success or failure as both service providers provides this on a "best effort" basis. Refers to each provider's documentation for more information.

LICENSE

BSD-2 (see LICENSE.md file)

SUPPORT / CONTRIBUTE

PRs infinitely welcome. Feel free to open a new GitHub issue if you find any problem, would like help, or just want to ask questions.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidDevice = fmt.Errorf("Device has been marked invalid by the service provider. It should be removed from the database.")

Functions

This section is empty.

Types

type APN

type APN struct {
	Gateway         string
	FeedbackGateway string
	KeyFile         string
	CertFile        string
}

func (*APN) Accepts

func (apn *APN) Accepts() []DeviceType

func (*APN) Start

func (apn *APN) Start(io *IO) error

type Client

type Client struct {
	Feedbacks chan *Feedback
	// contains filtered or unexported fields
}

func NewClient

func NewClient() *Client

func (*Client) Add

func (client *Client) Add(service Service)

func (*Client) Close

func (client *Client) Close()

func (*Client) Send

func (client *Client) Send(payload *Payload) *Session

func (*Client) Start

func (client *Client) Start() error

type Device

type Device struct {
	Token string
	Type  DeviceType
}

type DeviceType

type DeviceType string
const (
	DeviceTypeIOS     DeviceType = "ios"
	DeviceTypeAndroid DeviceType = "android"
)

type Feedback

type Feedback struct {
	*Device
	NewToken string
	Error    error
}

type GCM

type GCM struct {
	ApiKey    string
	BatchSize int
}

func (*GCM) Accepts

func (g *GCM) Accepts() []DeviceType

func (*GCM) Start

func (g *GCM) Start(io *IO) (e error)

type IO

type IO struct {
	Input  chan *Session
	Output chan *Feedback
}

func NewIO

func NewIO() *IO

func (*IO) Close

func (io *IO) Close()

type Payload

type Payload struct {
	Title       string
	Description string
	Data        map[string]interface{}
}

type Service

type Service interface {
	Accepts() []DeviceType
	Start(io *IO) error
}

type Session

type Session struct {
	*Payload
	Devices chan *Device
}

func NewSession

func NewSession(payload *Payload) *Session

func (*Session) Close

func (session *Session) Close()

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL