-
Notifications
You must be signed in to change notification settings - Fork 4
/
feedback.go
123 lines (99 loc) · 2.77 KB
/
feedback.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package apns
import (
"encoding/hex"
"encoding/binary"
"errors"
"bytes"
"time"
"log"
"io"
"bufio"
)
const APPLE_FEEDBACK string = "feedback.push.apple.com:2196"
const APPLE_FEEDBACK_SANDBOX string = "feedback.sandbox.push.apple.com:2196"
// NewFeedbackClient create a client for apple's Feedback system
//
func NewFeedbackClient(endpoint, certificate, key string) (*ApnsConn, error) {
return NewClient(endpoint, certificate, key)
}
type ApnsFeedbackMessage struct {
Time_t int32
DeviceToken string
}
func parseAppleFeedbackMessage(readb []byte) (*ApnsFeedbackMessage, error) {
var size int16
var err error
msg := &ApnsFeedbackMessage{}
if len(readb) < 6 {
return nil, errors.New("Not enough data in slice")
}
r := bytes.NewReader(readb)
err = binary.Read(r, binary.BigEndian, &msg.Time_t)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &size)
if err != nil {
return nil, err
}
if (6 + int(size)) > len(readb) {
return nil, errors.New("The Message size for the DeviceToken is bigger than the given buffer")
}
msg.DeviceToken = hex.EncodeToString(readb[6 : 6+int(size)])
return msg, nil
}
// StartListening listens on a apple Feedback connection and produces an ApnsFeedbackMessage
// each time a valid message is found
// If EOF is received the goroutine will try to re-connect 3 times waiting 5, 10 and 15 seconds
func (client *ApnsConn) StartListening() <-chan *ApnsFeedbackMessage {
outChan := make(chan *ApnsFeedbackMessage)
err := client.connect()
if err != nil {
close(outChan)
log.Printf("Could not Connect to feedback Service %v", err.Error())
return outChan
}
go func() {
readb := [4 + 2 + 32]byte{} // SSL default datapacket size
client.tlsconn.SetReadDeadline(time.Time{}) //Do not timeout
buff_reader := bufio.NewReader(client.tlsconn)
for {
n, err := buff_reader.Read(readb[:])
if err == io.EOF {
for count := 0; count < 3; count += 1 {
err = client.shutdown()
if err != nil {
log.Printf("Error closing the connection: %v", err)
}
log.Printf("Feedback: try reconnection in 30 sec")
time.Sleep(time.Second * 30)
err = client.connect()
if err != nil {
log.Print(err)
} else {
log.Printf("Feedback: reconnected")
client.tlsconn.SetReadDeadline(time.Time{}) //Do not timeout
buff_reader = bufio.NewReader(client.tlsconn)
break
}
if count == 3 {
panic("Failed reconnecting more than 3 times to the feedback service")
}
}
} else if err != nil {
close(outChan)
panic(err)
} else {
// parse all the messages
msg, err := parseAppleFeedbackMessage(readb[:n])
if err != nil {
close(outChan)
panic(err)
} else {
outChan <- msg
}
}
}
}()
return outChan
}