forked from timehop/apns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
notification.go
141 lines (113 loc) · 3.44 KB
/
notification.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package apns
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"time"
)
const (
PriorityImmediate = 10
PriorityPowerConserve = 5
)
const (
commandID = 2
// Items IDs
deviceTokenItemID = 1
payloadItemID = 2
notificationIdentifierItemID = 3
expirationDateItemID = 4
priorityItemID = 5
// Item lengths
deviceTokenItemLength = 32
notificationIdentifierItemLength = 4
expirationDateItemLength = 4
priorityItemLength = 1
)
type NotificationResult struct {
Notif Notification
Err Error
}
type Alert struct {
Body string `json:"body,omitempty"`
LocKey string `json:"loc-key,omitempty"`
LocArgs []string `json:"loc-args,omitempty"`
ActionLocKey string `json:"action-loc-key,omitempty"`
LaunchImage string `json:"launch-image,omitempty"`
}
type APS struct {
Alert Alert `json:"alert,omitempty"`
Badge int `json:"badge,omitempty"`
Sound string `json:"sound,omitempty"`
ContentAvailable int `json:"content-available,omitempty"`
Category string `json:"category,omitempty"`
}
type Payload struct {
APS APS
customValues map[string]interface{}
}
type Notification struct {
ID string
DeviceToken string
Identifier uint32
Expiration *time.Time
Priority int
Payload *Payload
}
func NewNotification() Notification {
return Notification{Payload: NewPayload()}
}
func NewPayload() *Payload {
return &Payload{customValues: map[string]interface{}{}}
}
func (p *Payload) SetCustomValue(key string, value interface{}) error {
if key == "aps" {
return errors.New("cannot assign a custom APS value in payload")
}
p.customValues[key] = value
return nil
}
func (p *Payload) MarshalJSON() ([]byte, error) {
p.customValues["aps"] = p.APS
return json.Marshal(p.customValues)
}
func (n Notification) ToBinary() ([]byte, error) {
b := []byte{}
binTok, err := hex.DecodeString(n.DeviceToken)
if err != nil {
return b, fmt.Errorf("convert token to hex error: %s", err)
}
j, _ := json.Marshal(n.Payload)
buf := bytes.NewBuffer(b)
// Token
binary.Write(buf, binary.BigEndian, uint8(deviceTokenItemID))
binary.Write(buf, binary.BigEndian, uint16(deviceTokenItemLength))
binary.Write(buf, binary.BigEndian, binTok)
// Payload
binary.Write(buf, binary.BigEndian, uint8(payloadItemID))
binary.Write(buf, binary.BigEndian, uint16(len(j)))
binary.Write(buf, binary.BigEndian, j)
// Identifier
binary.Write(buf, binary.BigEndian, uint8(notificationIdentifierItemID))
binary.Write(buf, binary.BigEndian, uint16(notificationIdentifierItemLength))
binary.Write(buf, binary.BigEndian, uint32(n.Identifier))
// Expiry
binary.Write(buf, binary.BigEndian, uint8(expirationDateItemID))
binary.Write(buf, binary.BigEndian, uint16(expirationDateItemLength))
if n.Expiration == nil {
binary.Write(buf, binary.BigEndian, uint32(0))
} else {
binary.Write(buf, binary.BigEndian, uint32(n.Expiration.Unix()))
}
// Priority
binary.Write(buf, binary.BigEndian, uint8(priorityItemID))
binary.Write(buf, binary.BigEndian, uint16(priorityItemLength))
binary.Write(buf, binary.BigEndian, uint8(n.Priority))
framebuf := bytes.NewBuffer([]byte{})
binary.Write(framebuf, binary.BigEndian, uint8(commandID))
binary.Write(framebuf, binary.BigEndian, uint32(buf.Len()))
binary.Write(framebuf, binary.BigEndian, buf.Bytes())
return framebuf.Bytes(), nil
}