diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go b/Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go new file mode 100644 index 000000000..32e7f0f15 --- /dev/null +++ b/Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go @@ -0,0 +1,102 @@ +package apns + +import ( + "bytes" + "crypto/tls" + "encoding/binary" + "encoding/hex" + "errors" + "net" + "strings" + "time" +) + +// Wait at most this many seconds for feedback data from Apple. +const FeedbackTimeoutSeconds = 5 + +// FeedbackChannel will receive individual responses from Apple. +var FeedbackChannel = make(chan (*FeedbackResponse)) + +// If there's nothing to read, ShutdownChannel gets a true. +var ShutdownChannel = make(chan bool) + +// FeedbackResponse represents a device token that Apple has +// indicated should not be sent to in the future. +type FeedbackResponse struct { + Timestamp uint32 + DeviceToken string +} + +// NewFeedbackResponse creates and returns a FeedbackResponse structure. +func NewFeedbackResponse() (resp *FeedbackResponse) { + resp = new(FeedbackResponse) + return +} + +// ListenForFeedback connects to the Apple Feedback Service +// and checks for device tokens. +// +// Feedback consists of device tokens that should +// not be sent to in the future; Apple *does* monitor that +// you respect this so you should be checking it ;) +func (client *Client) ListenForFeedback() (err error) { + var cert tls.Certificate + + if len(client.CertificateBase64) == 0 && len(client.KeyBase64) == 0 { + // The user did not specify raw block contents, so check the filesystem. + cert, err = tls.LoadX509KeyPair(client.CertificateFile, client.KeyFile) + } else { + // The user provided the raw block contents, so use that. + cert, err = tls.X509KeyPair([]byte(client.CertificateBase64), []byte(client.KeyBase64)) + } + + if err != nil { + return err + } + + gatewayParts := strings.Split(client.Gateway, ":") + conf := &tls.Config{ + Certificates: []tls.Certificate{cert}, + ServerName: gatewayParts[0], + } + + conn, err := net.Dial("tcp", client.Gateway) + if err != nil { + return err + } + defer conn.Close() + conn.SetReadDeadline(time.Now().Add(FeedbackTimeoutSeconds * time.Second)) + + tlsConn := tls.Client(conn, conf) + err = tlsConn.Handshake() + if err != nil { + return err + } + + var tokenLength uint16 + buffer := make([]byte, 38, 38) + deviceToken := make([]byte, 32, 32) + + for { + _, err := tlsConn.Read(buffer) + if err != nil { + ShutdownChannel <- true + break + } + + resp := NewFeedbackResponse() + + r := bytes.NewReader(buffer) + binary.Read(r, binary.BigEndian, &resp.Timestamp) + binary.Read(r, binary.BigEndian, &tokenLength) + binary.Read(r, binary.BigEndian, &deviceToken) + if tokenLength != 32 { + return errors.New("token length should be equal to 32, but isn't") + } + resp.DeviceToken = hex.EncodeToString(deviceToken) + + FeedbackChannel <- resp + } + + return nil +} |