commit
17b9dc6ae8
|
@ -28,6 +28,4 @@ key.pem
|
|||
config.yaml
|
||||
bin/*
|
||||
.DS_Store
|
||||
*.cert
|
||||
*.key
|
||||
coverage.out
|
||||
|
|
|
@ -11,7 +11,9 @@ go:
|
|||
|
||||
env:
|
||||
global:
|
||||
secure: ad5iOvyzCMdxp664YZD92Qse8EAB8R8jgoV8CspLBVbwfqPv2S+2IF2pHrxqd6o81y2sTgAr0VFOx9q9gVD3JZpT0vjpPIzscGNVYtup8bDBDFYIf3vwt6RVvJsSTYGQIQ6HulZ97CKB5W2pCI2q9pOrZqFzQG9lHA4J4m+XzAzH7eNx4PprboEwKKhESI4191ii47phWKcalcul00wo/oeM1u/Bmmg/rcGyQgzUHg3zFh+1avQp7z4yAMFmScRnJDJFABg9s9TVeQu8FQXUWTBv4tUQJrpPs60zRSxpt3ap9Yx67pkuVYpfZz9o9u6FLa8UC+zWVh+oHYXfYWrSmCcsyfLjy5Wg2Zt3Mx92Aqq8uiaGaLSxcn5pL9xeIK6X0uWixp2wzXMdjE9RkGRaPhTm/Ze4F810JyNR+i0AkM8py/gPEkVXkeIw+UGS/mo5bq4a5ntLKRbl1vePOIPUtpV8nlgBblNB6jqd3/wINRcCoNhNiKtr+uvUm1jKKK+hu4q9YncwG3gpB+u0DRR2KIPSgdUlzL3V43UMWIC12eEjVrS+xkMo7a2gfUXMzwmpMhQHZ2QMb0VMOgIde1X4nlOL0GHsrHJAp8AmjQF6xbv2gcxzs98zU9qKp/qm4QETGQvHaMXhvE8ogzx1EgXaJ0xn9SIAw11TBT6dpHLdcGI=
|
||||
- secure: ad5iOvyzCMdxp664YZD92Qse8EAB8R8jgoV8CspLBVbwfqPv2S+2IF2pHrxqd6o81y2sTgAr0VFOx9q9gVD3JZpT0vjpPIzscGNVYtup8bDBDFYIf3vwt6RVvJsSTYGQIQ6HulZ97CKB5W2pCI2q9pOrZqFzQG9lHA4J4m+XzAzH7eNx4PprboEwKKhESI4191ii47phWKcalcul00wo/oeM1u/Bmmg/rcGyQgzUHg3zFh+1avQp7z4yAMFmScRnJDJFABg9s9TVeQu8FQXUWTBv4tUQJrpPs60zRSxpt3ap9Yx67pkuVYpfZz9o9u6FLa8UC+zWVh+oHYXfYWrSmCcsyfLjy5Wg2Zt3Mx92Aqq8uiaGaLSxcn5pL9xeIK6X0uWixp2wzXMdjE9RkGRaPhTm/Ze4F810JyNR+i0AkM8py/gPEkVXkeIw+UGS/mo5bq4a5ntLKRbl1vePOIPUtpV8nlgBblNB6jqd3/wINRcCoNhNiKtr+uvUm1jKKK+hu4q9YncwG3gpB+u0DRR2KIPSgdUlzL3V43UMWIC12eEjVrS+xkMo7a2gfUXMzwmpMhQHZ2QMb0VMOgIde1X4nlOL0GHsrHJAp8AmjQF6xbv2gcxzs98zU9qKp/qm4QETGQvHaMXhvE8ogzx1EgXaJ0xn9SIAw11TBT6dpHLdcGI=
|
||||
- secure: nnOFadWZodcsJeRHwcPE7wjUk4xZ7oNjrJUPvs1yBDKGOCfga/KbmWpQ85PZiJmmxA7WO1PXpRV0lf+lHKDuAJKiXbQZNZOW8BoFSagRy7/lSicDqeQyJX2zJsjYbM11ZqOCH1uiTMBsNsbaGJTGtwHrbQ84zXJk2WXvDfrvNqlo85cXDHtxkdsqfETgY3S7Gis7VUKmoJKHuhF8ADvsLjaXpg/kgnrhEkTz9AD4oxscMUq3/vkf5wPN9a4uEXDJamKK6N2CKfwGZLwVPGMRIrIL+/gc1vyALGpl5xjC/rMuErESVfzKcUfLgENXL4JEv2IcqfInDqhVL56YG87xlYb4Wsxsm0u1IYDl+v8Frm35SPAz7C5Iha+/Kh1G1ip9AZKkpSS7IxpFOfRe6hmhvXIX00cNCo51ZMp7xBkahiktHveXj7UrqX72y949/+QXgbC0AvV2+4lYnEDydkphlkXH9MDeAVtkbYGUss06U0q19GuL0O8+iZPyBfajdAdS0V0nx7zIYYW42UVuJdRcndcEkaK7PQd0fZlwwZUSXQgqEg8zd+VzxC7tAgtS8LlOU2Ma3Vf4pZiScaZNqpJXPIyD/jPSqNSYQe6WJ6FKRPJw+1ZwN2kAeQMIt1th+08I+23dyolpbULPTkOFudsZoyFkSPhEcDBKNEQdrL7ggTw=
|
||||
- secure: MVVH7ilA3r3eLb1I9/KTn3hWaEWOhY8yeF1g2zO09r0oRwEr+NKba/Ey2TpBmkcbFt+CiKMrefzoG9dwHyHm9dFH/1OLBrRAXK3RLV6qyMNw708yOkc7NfH5xK7X7F2u0vWwagK3aVkhTxXGrIQvaEK5jJ2tK3K1uDO5TzUC4TM0hLsgGvyTah89LJBhM4k0OEcAIVmzPO58Ql+RZV3nw03LDtcLofVFNqApCAUJNPrArt9TP/UraPPg/R8WtAS/PMY6IsMRKWj3LjN/J089zfQgiHH6p2wPBQ0n2R2zgisnxjAz5wt6/Dkvo09UqkVWFGX4p6N4t7kxAZoqhRRt+t38qdDip5iloclHGO5eI3/dr30V88Y5ionLL81WsBRqFuMmWrEb86maSMsXWl5yM1qB76Rsh/sPMDRk99Wf9RqhHedJxek6reoUcTBZl9kgXJDlqpjEogyq6qgL0jCCqgl0N6FZAYE/5SvW82MCukZZmko2UXBS/GmU6fhBRGquzOczL43YvVqqV8olZ2qXIdeeX5KeO/SHMUvW3oUnENa6V49K6ZX1f7KG8p8jERTNuDfsdgvZdMSYR2EeDQ7RTU6fhoc3BX4cFyTrS1qImswoBvLCEr54awQXDhgWddZsIWQzCxw6TmD7u25G3YHTsM5Wvs2Gj4z0aJeXFlLSfSQ=
|
||||
|
||||
install:
|
||||
- go get -t -v ./...
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,59 @@
|
|||
Bag Attributes
|
||||
localKeyID: 8C 1A 9F 00 66 BD 24 42 B9 5D 1E EB FE 5E 8B CA 04 3D 73 83
|
||||
friendlyName: APNS/2 Private Key
|
||||
subject=/C=NZ/ST=Wellington/L=Wellington/O=Internet Widgits Pty Ltd/OU=9ZEH62KRVV/CN=APNS/2 Development IOS Push Services: com.sideshow.Apns2
|
||||
issuer=/C=NZ/ST=Wellington/L=Wellington/O=APNS/2 Inc./OU=APNS/2 Worldwide Developer Relations/CN=APNS/2 Worldwide Developer Relations Certification Authority
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID6zCCAtMCAQIwDQYJKoZIhvcNAQELBQAwgcMxCzAJBgNVBAYTAk5aMRMwEQYD
|
||||
VQQIEwpXZWxsaW5ndG9uMRMwEQYDVQQHEwpXZWxsaW5ndG9uMRQwEgYDVQQKEwtB
|
||||
UE5TLzIgSW5jLjEtMCsGA1UECxMkQVBOUy8yIFdvcmxkd2lkZSBEZXZlbG9wZXIg
|
||||
UmVsYXRpb25zMUUwQwYDVQQDEzxBUE5TLzIgV29ybGR3aWRlIERldmVsb3BlciBS
|
||||
ZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYwMTA4MDgzNDMw
|
||||
WhcNMjYwMTA1MDgzNDMwWjCBsjELMAkGA1UEBhMCTloxEzARBgNVBAgTCldlbGxp
|
||||
bmd0b24xEzARBgNVBAcTCldlbGxpbmd0b24xITAfBgNVBAoTGEludGVybmV0IFdp
|
||||
ZGdpdHMgUHR5IEx0ZDETMBEGA1UECxMKOVpFSDYyS1JWVjFBMD8GA1UEAxM4QVBO
|
||||
Uy8yIERldmVsb3BtZW50IElPUyBQdXNoIFNlcnZpY2VzOiBjb20uc2lkZXNob3cu
|
||||
QXBuczIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY0c1TKB5oZPwQ
|
||||
7t1CwMIrvqB6GIU3tPy6RhckZXTkOB8YeBWJ7UKfCz8HGHFVomBP0T5OUbeqQzqW
|
||||
YJbQzZ8a6ZMszbL0lO4X9++3Oi5/TtAwOUOK8rOFN25m2KfsayHQZ/4vWStK2Fwm
|
||||
5aJbGLlpH/b/7z1D4vhmMgoBuT1IuyhGiyFxlZ9EtTloFvsqM1E5fYZOSZACyXTa
|
||||
K4vdgbQMgUVsI714FAgLTlK0UeiRkmKm3pdbtfVbrthzI+IHXKItUIy+Fn20PRMh
|
||||
dSnaztSz7tgBWCIx22qvcYogHWiOgUYIM772zE2y8UVOr8DsiRlsOHSA7EI4MJcQ
|
||||
G2FUq2Z/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGyfyO2HMgcdeBcz3bt5BILX
|
||||
f7RA2/UmVIwcKR1qotTsF+PnBmcILeyOQgDe9tGU5cRc79kDt3JRmMYROFIMgFRf
|
||||
Wf22uOKtho7GQQaKvG+bkgMVdYFRlBHnF+KeqKH81qb9p+CT4Iw0GehIL1DijFLR
|
||||
VIAIBYpz4oBPCIE1ISVT+Fgaf3JAh59kbPbNw9AIDxaBtP8EuzSTNwfbxoGbCobS
|
||||
Wi1U8IsCwQFt8tM1m4ZXD1CcZIrGdryeAhVkvKIJRiU5QYWI2nqZN+JqQucm9ad0
|
||||
mYO5mJkIobUa4+ZJhCPKEdmgpFbRGk0wVuaDM9Cv6P2srsYAjaO4y3VP0GvNKRI=
|
||||
-----END CERTIFICATE-----
|
||||
Bag Attributes
|
||||
localKeyID: 8C 1A 9F 00 66 BD 24 42 B9 5D 1E EB FE 5E 8B CA 04 3D 73 83
|
||||
friendlyName: APNS/2 Private Key
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA2NHNUygeaGT8EO7dQsDCK76gehiFN7T8ukYXJGV05DgfGHgV
|
||||
ie1Cnws/BxhxVaJgT9E+TlG3qkM6lmCW0M2fGumTLM2y9JTuF/fvtzouf07QMDlD
|
||||
ivKzhTduZtin7Gsh0Gf+L1krSthcJuWiWxi5aR/2/+89Q+L4ZjIKAbk9SLsoRosh
|
||||
cZWfRLU5aBb7KjNROX2GTkmQAsl02iuL3YG0DIFFbCO9eBQIC05StFHokZJipt6X
|
||||
W7X1W67YcyPiB1yiLVCMvhZ9tD0TIXUp2s7Us+7YAVgiMdtqr3GKIB1ojoFGCDO+
|
||||
9sxNsvFFTq/A7IkZbDh0gOxCODCXEBthVKtmfwIDAQABAoIBAQCW8ZCI+OAae1tE
|
||||
ipZ9F2bWP3LHLXTo8FYVdCA+VWeITk3PoiIUkJmV0aWCUhDstgto5doDej5sCTur
|
||||
Xvj/ynaerMeqJFYWkewjwZcgLyAZvwuO1v7fp9E0x/9TGDfnjjnPNeaundxW0cNt
|
||||
zOY3l0HVHsy9Jpe3QDcAJovy4Tv5+hFY4kDxUBGsyjvhScVgKg5tLkJclm3sOu/L
|
||||
GyLqpwNI3OJAdMIuVD4N2BZ1aOEap6mp2y8Ie0/R4YWcaZ5A4Pw7xUPl6SXc9uua
|
||||
/78QTERtPC6ejyCBiE05a8m3Q3iud3Xtnlyws2KwhgBAfE6M4zR/f3OQB7ZIXMhy
|
||||
ZpmZZw5xAoGBAPYn84IrlIQetWQfvPdM7Kzgh6UDHCugnlCDghwYpRJGi8hMfuZV
|
||||
xNIrYAJzLYDQ01lFJRJgWXTcbqz9NBz1nhg+cNOz1/KY+38eudee6DNYmztP7jDP
|
||||
2jnaS+dtjC8hAXObnFqG+NilMDLLu6aRmrJaImbjSrfyLiE6mvJ7u81nAoGBAOF9
|
||||
g93wZ0mL1rk2s5WwHGTNU/HaOtmWS4z7kA7f4QaRub+MwppZmmDZPHpiZX7BPcZz
|
||||
iOPQh+xn7IqRGoQWBLykBVt8zZFoLZJoCR3n63lex5A4p/0Pp1gFZrR+xX8PYVos
|
||||
3yeeiWyPKsXXNc0s5QwHZcX6Wb8EHThTXGCBetcpAoGAMeQJC9IPaPPcae2w3CLA
|
||||
OY3MkFpgBEuqqsDsxwsLsfeQb0lp0v+BQ+O8suJrT5eDrq1ABUh3+SKQYAl13YS+
|
||||
xUUqkw35b9cn6iztF9HCWF3WIKBjs4r9PQqMpdxjNE4pQChC+Wov16ErcrAuWWVb
|
||||
iFiSbm4U/9FbHisFqq3/c3MCgYB+vzSuPgFw37+0oEDVtQZgyuGSop5NzCNvfb/9
|
||||
/G3aaXNFbnO8mv0hzzoleMWgODLnJ+4cUAz3H3tgcCu9bzr+Zhv0zvQl9a8YCo6F
|
||||
VuWPdW0rbg1PO8tOuMqATnno79ZC/9H3zS9l7BuY1V2SlNeyqT3VyOFFc6SREpps
|
||||
TJul8QKBgAxnQB8MA7zPULu1clyaJLdtEdRPkKWN7lKYptc0e/VHfSsKxseWkfqi
|
||||
zgXZ51kQTrT6Zb6HYRfwC1mMXHWRKRyYjAnCxVim6YQd+KVT49iRDDAiIFoMGA4i
|
||||
vvcIlneqOZZPDIoKJ60IjO/DZHWkw5mLjaIrT+qQ3XAGdJA13hcm
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC+zCCAeOgAwIBAgIJALbZEDvUQrFKMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
|
||||
BAMMCWxvY2FsaG9zdDAeFw0xNjAzMjgwMzMwNDFaFw0yNjAzMjYwMzMwNDFaMBQx
|
||||
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAMj1+xg4jVLzVnB5j7n1ul30WEE4BCzcNFxg5AOB5H5q+wje0YYiVFg6PQyv
|
||||
GCipqIRXVRdVQ1hHSeunYGKe8lq3Sb1X8PUJ12v9uRbpS9DK1Owqk8rsPDu6sVTL
|
||||
qKKgH1Z8yazzaS0AbXuA5e9gO/RzijbnpEP+quM4dueiMPVEJyLq+EoIQY+MM8MP
|
||||
8dZzL4XZl7wL4UsCN7rPcO6W3tlnT0iO3h9c/Ym2hFhz+KNJ9KRRCvtPGZESigtK
|
||||
bHsXH099WDo8v/Wp5/evBw/+JD0opxmCfHIBALHt9v53RvvsDZ1t33Rpu5C8znEY
|
||||
Y2Ay7NgxhqjqoWJqA48lJeA0clsCAwEAAaNQME4wHQYDVR0OBBYEFC0bTU1Xofeh
|
||||
NKIelashIsqKidDYMB8GA1UdIwQYMBaAFC0bTU1XofehNKIelashIsqKidDYMAwG
|
||||
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAiJL8IMTwNX9XqQWYDFgkG4
|
||||
AnrVwQhreAqC9rSxDCjqqnMHPHGzcCeDMLAMoh0kOy20nowUGNtCZ0uBvnX2q1bN
|
||||
g1jt+GBcLJDR3LL4CpNOlm3YhOycuNfWMxTA7BXkmnSrZD/7KhArsBEY8aulxwKJ
|
||||
HRgNlIwe1oFD1YdX1BS5pp4t25B6Vq4A3FMMUkVoWE688nE168hvQgwjrHkgHhwe
|
||||
eN8lGE2DhFraXnWmDMdwaHD3HRFGhyppIFN+f7BqbWX9gM+T2YRTfObIXLWbqJLD
|
||||
3Mk/NkxqVcg4eY54wJ1ufCUGAYAIaY6fQqiNUz8nhwK3t45NBVT9y/uJXqnTLyY=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAyPX7GDiNUvNWcHmPufW6XfRYQTgELNw0XGDkA4Hkfmr7CN7R
|
||||
hiJUWDo9DK8YKKmohFdVF1VDWEdJ66dgYp7yWrdJvVfw9QnXa/25FulL0MrU7CqT
|
||||
yuw8O7qxVMuooqAfVnzJrPNpLQBte4Dl72A79HOKNuekQ/6q4zh256Iw9UQnIur4
|
||||
SghBj4wzww/x1nMvhdmXvAvhSwI3us9w7pbe2WdPSI7eH1z9ibaEWHP4o0n0pFEK
|
||||
+08ZkRKKC0psexcfT31YOjy/9ann968HD/4kPSinGYJ8cgEAse32/ndG++wNnW3f
|
||||
dGm7kLzOcRhjYDLs2DGGqOqhYmoDjyUl4DRyWwIDAQABAoIBAGTKqsN9KbSfA42q
|
||||
CqI0UuLouJMNa1qsnz5uAi6YKWgWdA4A44mpEjCmFRSVhUJvxWuK+cyYIQzXxIWD
|
||||
D16nZdqF72AeCWZ9JySsvvZ00GfKM3y35iRy08sJWgOzmcLnGJCiSeyKsQe3HTJC
|
||||
dhDXbXqvsHTVPZg01LTeDxUiTffU8NMKqR2AecQ2sTDwXEhAnTyAtnzl/XaBgFzu
|
||||
U6G7FzGM5y9bxkfQVkvy+DEJkHGNOjzwcVfByyVl610ixmG1vmxVj9PbWmIPsUV8
|
||||
ySmjhvDQbOfoxW0h9vTlTqGtQcBw962osnDDMWFCdM7lzO0T7RRnPVGIRpCJOKhq
|
||||
keqHKwECgYEA8wwI/iZughoTXTNG9LnQQ/WAtsqO80EjMTUheo5I1kOzmUz09pyh
|
||||
iAsUDoN0/26tZ5WNjlnyZu7dvTc/x3dTZpmNnoo8gcVbQNECDRzqfuQ9PPXm1SN5
|
||||
6peBqAvBv78hjV05aXzPG/VBbeig7l299EarEA+a/oH3KrgDoqVqE0ECgYEA06vA
|
||||
YJmgg4fZRucAYoaYsLz9Z9rCFjTe1PBTmUJkbOR8vFIHHTTEWi/SuxXL0wDSeoE2
|
||||
7BQm86gCC7/KgRdrzoBqZ5qS9Mv2dsLgY635VSgjjfZkVLiH1VRRpSQObYnfoysg
|
||||
gatcHSKMExd4SLQByAuImXP+L5ayDBcEJfbqSpsCgYB78Is1b0uzNLDjOh7Y9Vhr
|
||||
D2qPzEORcIoNsdZctOoXuXaAmmngyIbm5R9ZN1gWWc47oFwLV3rxWqXgs6fmg8cX
|
||||
7v309vFcC9Q4/Vxaa4B5LNK9n3gTAIBPTOtlUnl+2my1tfBtBqRm0W6IKbTHWS5g
|
||||
vxjEm/CiEIyGUEgqTMgHAQKBgBKuXdQoutng63QufwIzDtbKVzMLQ4XiNKhmbXph
|
||||
OavCnp+gPbB+L7Yl8ltAmTSOJgVZ0hcT0DxA361Zx+2Mu58GBl4OblnchmwE1vj1
|
||||
KcQyPrEQxdoUTyiswGfqvrs8J9imvb+z9/U6T1KAB8Wi3WViXzPr4MsiaaRXg642
|
||||
FIdxAoGAZ7/735dkhJcyOfs+LKsLr68JSstoorXOYvdMu1+JGa9iLuhnHEcMVWC8
|
||||
IuihzPfloZtMbGYkZJn8l3BeGd8hmfFtgTgZGPoVRetft2LDFLnPxp2sEH5OFLsQ
|
||||
R+K/kAOul8eStWuMXOFA9pMzGkGEgIFJMJOyaJON3kedQI8deCM=
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,45 @@
|
|||
package gopush
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test file is missing
|
||||
func TestMissingFile(t *testing.T) {
|
||||
filename := "test"
|
||||
_, err := LoadConfYaml(filename)
|
||||
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
// Test wrong json format
|
||||
func TestWrongYAMLormat(t *testing.T) {
|
||||
content := []byte(`Wrong format`)
|
||||
|
||||
filename := "tempfile"
|
||||
|
||||
if err := ioutil.WriteFile(filename, content, 0644); err != nil {
|
||||
log.Fatalf("WriteFile %s: %v", filename, err)
|
||||
}
|
||||
|
||||
// clean up
|
||||
defer os.Remove(filename)
|
||||
|
||||
// parse JSON format error
|
||||
_, err := LoadConfYaml(filename)
|
||||
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
// Test config file.
|
||||
func TestReadConfig(t *testing.T) {
|
||||
config, err := LoadConfYaml("../config/config.yaml")
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "8088", config.Core.Port)
|
||||
assert.False(t, config.Android.Enabled)
|
||||
}
|
|
@ -13,7 +13,21 @@ type ExtendJSON struct {
|
|||
Value string `json:"val"`
|
||||
}
|
||||
|
||||
type alert struct {
|
||||
const (
|
||||
// PriorityLow will tell APNs to send the push message at a time that takes
|
||||
// into account power considerations for the device. Notifications with this
|
||||
// priority might be grouped and delivered in bursts. They are throttled, and
|
||||
// in some cases are not delivered.
|
||||
ApnsPriorityLow = 5
|
||||
|
||||
// PriorityHigh will tell APNs to send the push message immediately.
|
||||
// Notifications with this priority must trigger an alert, sound, or badge on
|
||||
// the target device. It is an error to use this priority for a push
|
||||
// notification that contains only the content-available key.
|
||||
ApnsPriorityHigh = 10
|
||||
)
|
||||
|
||||
type Alert struct {
|
||||
Action string `json:"action,omitempty"`
|
||||
ActionLocKey string `json:"action-loc-key,omitempty"`
|
||||
Body string `json:"body,omitempty"`
|
||||
|
@ -48,18 +62,16 @@ type RequestPushNotification struct {
|
|||
Topic string `json:"topic,omitempty"`
|
||||
Badge int `json:"badge,omitempty"`
|
||||
Sound string `json:"sound,omitempty"`
|
||||
Expiry int `json:"expiry,omitempty"`
|
||||
Retry int `json:"retry,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
URLArgs []string `json:"url-args,omitempty"`
|
||||
Extend []ExtendJSON `json:"extend,omitempty"`
|
||||
Alert alert `json:"alert,omitempty"`
|
||||
Alert Alert `json:"alert,omitempty"`
|
||||
|
||||
// meta
|
||||
IDs []uint64 `json:"seq_id,omitempty"`
|
||||
}
|
||||
|
||||
func InitAPNSClient() {
|
||||
func InitAPNSClient() error {
|
||||
if PushConf.Ios.Enabled {
|
||||
var err error
|
||||
|
||||
|
@ -68,7 +80,7 @@ func InitAPNSClient() {
|
|||
if err != nil {
|
||||
log.Println("Cert Error:", err)
|
||||
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if PushConf.Ios.Production {
|
||||
|
@ -77,6 +89,8 @@ func InitAPNSClient() {
|
|||
ApnsClient = apns.NewClient(CertificatePemIos).Development()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func pushNotification(notification RequestPushNotification) bool {
|
||||
|
@ -100,13 +114,10 @@ func pushNotification(notification RequestPushNotification) bool {
|
|||
return success
|
||||
}
|
||||
|
||||
func pushNotificationIos(req RequestPushNotification) bool {
|
||||
|
||||
// The Remote Notification Payload
|
||||
// https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html
|
||||
for _, token := range req.Tokens {
|
||||
// The iOS Notification Payload
|
||||
// ref: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html
|
||||
func GetIOSNotification(req RequestPushNotification) *apns.Notification {
|
||||
notification := &apns.Notification{}
|
||||
notification.DeviceToken = token
|
||||
|
||||
if len(req.ApnsID) > 0 {
|
||||
notification.ApnsID = req.ApnsID
|
||||
|
@ -150,8 +161,13 @@ func pushNotificationIos(req RequestPushNotification) bool {
|
|||
payload.AlertTitleLocKey(req.Alert.TitleLocKey)
|
||||
}
|
||||
|
||||
if len(req.Alert.LocArgs) > 0 {
|
||||
payload.AlertTitleLocArgs(req.Alert.LocArgs)
|
||||
// Need send PR to apns2 repo.
|
||||
// if len(req.Alert.LocArgs) > 0 {
|
||||
// payload.AlertLocArgs(req.Alert.LocArgs)
|
||||
// }
|
||||
|
||||
if len(req.Alert.TitleLocArgs) > 0 {
|
||||
payload.AlertTitleLocArgs(req.Alert.TitleLocArgs)
|
||||
}
|
||||
|
||||
if len(req.Alert.Body) > 0 {
|
||||
|
@ -186,6 +202,16 @@ func pushNotificationIos(req RequestPushNotification) bool {
|
|||
|
||||
notification.Payload = payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
func pushNotificationIos(req RequestPushNotification) bool {
|
||||
|
||||
notification := GetIOSNotification(req)
|
||||
|
||||
for _, token := range req.Tokens {
|
||||
notification.DeviceToken = token
|
||||
|
||||
// send ios notification
|
||||
res, err := ApnsClient.Push(notification)
|
||||
|
||||
|
@ -197,17 +223,15 @@ func pushNotificationIos(req RequestPushNotification) bool {
|
|||
|
||||
if res.Sent() {
|
||||
log.Println("APNs ID:", res.ApnsID)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func pushNotificationAndroid(req RequestPushNotification) bool {
|
||||
|
||||
// HTTP Connection Server Reference for Android
|
||||
// https://developers.google.com/cloud-messaging/http-server-ref
|
||||
// HTTP Connection Server Reference for Android
|
||||
// https://developers.google.com/cloud-messaging/http-server-ref
|
||||
func GetAndroidNotification(req RequestPushNotification) gcm.HttpMessage {
|
||||
notification := gcm.HttpMessage{}
|
||||
|
||||
notification.RegistrationIds = req.Tokens
|
||||
|
@ -255,21 +279,30 @@ func pushNotificationAndroid(req RequestPushNotification) bool {
|
|||
notification.Notification.Body = req.Message
|
||||
}
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
func pushNotificationAndroid(req RequestPushNotification) bool {
|
||||
|
||||
notification := GetAndroidNotification(req)
|
||||
|
||||
res, err := gcm.SendHttp(PushConf.Android.ApiKey, notification)
|
||||
|
||||
log.Printf("Success count: %d, Failure count: %d", res.Success, res.Failure)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("GCM Server Error Message: " + err.Error())
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if res.Error != "" {
|
||||
log.Println("GCM Error Message: " + res.Error)
|
||||
log.Println("GCM Http Error Message: " + res.Error)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if res.Success > 0 {
|
||||
log.Printf("Success count: %d, Failure count: %d", res.Success, res.Failure)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
package gopush
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/google/go-gcm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIOSNotificationStructure(t *testing.T) {
|
||||
var dat map[string]interface{}
|
||||
|
||||
test := "test"
|
||||
message := "Welcome notification Server"
|
||||
req := RequestPushNotification{
|
||||
ApnsID: test,
|
||||
Topic: test,
|
||||
Priority: "normal",
|
||||
Message: message,
|
||||
Badge: 1,
|
||||
Sound: test,
|
||||
ContentAvailable: true,
|
||||
Extend: []ExtendJSON{
|
||||
{
|
||||
Key: "key1",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Value: "2",
|
||||
},
|
||||
},
|
||||
Category: test,
|
||||
URLArgs: []string{"a", "b"},
|
||||
}
|
||||
|
||||
notification := GetIOSNotification(req)
|
||||
|
||||
dump, _ := json.Marshal(notification.Payload)
|
||||
data := []byte(string(dump))
|
||||
|
||||
if err := json.Unmarshal(data, &dat); err != nil {
|
||||
log.Println(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
alert, _ := jsonparser.GetString(data, "aps", "alert")
|
||||
badge, _ := jsonparser.GetInt(data, "aps", "badge")
|
||||
sound, _ := jsonparser.GetString(data, "aps", "sound")
|
||||
contentAvailable, _ := jsonparser.GetInt(data, "aps", "content-available")
|
||||
category, _ := jsonparser.GetString(data, "aps", "category")
|
||||
key1 := dat["key1"].(string)
|
||||
key2 := dat["key2"].(string)
|
||||
aps := dat["aps"].(map[string]interface{})
|
||||
urlArgs := aps["url-args"].([]interface{})
|
||||
|
||||
assert.Equal(t, test, notification.ApnsID)
|
||||
assert.Equal(t, test, notification.Topic)
|
||||
assert.Equal(t, ApnsPriorityLow, notification.Priority)
|
||||
assert.Equal(t, message, alert)
|
||||
assert.Equal(t, 1, int(badge))
|
||||
assert.Equal(t, test, sound)
|
||||
assert.Equal(t, 1, int(contentAvailable))
|
||||
assert.Equal(t, "1", key1)
|
||||
assert.Equal(t, "2", key2)
|
||||
assert.Equal(t, test, category)
|
||||
assert.Contains(t, urlArgs, "a")
|
||||
assert.Contains(t, urlArgs, "b")
|
||||
}
|
||||
|
||||
func TestIOSAlertNotificationStructure(t *testing.T) {
|
||||
var dat map[string]interface{}
|
||||
|
||||
test := "test"
|
||||
req := RequestPushNotification{
|
||||
Alert: Alert{
|
||||
Action: test,
|
||||
ActionLocKey: test,
|
||||
Body: test,
|
||||
LaunchImage: test,
|
||||
LocArgs: []string{"a", "b"},
|
||||
LocKey: test,
|
||||
Title: test,
|
||||
TitleLocArgs: []string{"a", "b"},
|
||||
TitleLocKey: test,
|
||||
},
|
||||
}
|
||||
|
||||
notification := GetIOSNotification(req)
|
||||
|
||||
dump, _ := json.Marshal(notification.Payload)
|
||||
data := []byte(string(dump))
|
||||
|
||||
if err := json.Unmarshal(data, &dat); err != nil {
|
||||
log.Println(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
action, _ := jsonparser.GetString(data, "aps", "alert", "action")
|
||||
actionLocKey, _ := jsonparser.GetString(data, "aps", "alert", "action-loc-key")
|
||||
body, _ := jsonparser.GetString(data, "aps", "alert", "body")
|
||||
launchImage, _ := jsonparser.GetString(data, "aps", "alert", "launch-image")
|
||||
locKey, _ := jsonparser.GetString(data, "aps", "alert", "loc-key")
|
||||
title, _ := jsonparser.GetString(data, "aps", "alert", "title")
|
||||
titleLocKey, _ := jsonparser.GetString(data, "aps", "alert", "title-loc-key")
|
||||
aps := dat["aps"].(map[string]interface{})
|
||||
alert := aps["alert"].(map[string]interface{})
|
||||
titleLocArgs := alert["title-loc-args"].([]interface{})
|
||||
|
||||
assert.Equal(t, test, action)
|
||||
assert.Equal(t, test, actionLocKey)
|
||||
assert.Equal(t, test, body)
|
||||
assert.Equal(t, test, launchImage)
|
||||
assert.Equal(t, test, locKey)
|
||||
assert.Equal(t, test, title)
|
||||
assert.Equal(t, test, titleLocKey)
|
||||
assert.Contains(t, titleLocArgs, "a")
|
||||
assert.Contains(t, titleLocArgs, "b")
|
||||
}
|
||||
|
||||
func TestAndroidNotificationStructure(t *testing.T) {
|
||||
|
||||
test := "test"
|
||||
req := RequestPushNotification{
|
||||
Tokens: []string{"a", "b"},
|
||||
Message: "Welcome",
|
||||
To: test,
|
||||
Priority: "high",
|
||||
CollapseKey: "1",
|
||||
ContentAvailable: true,
|
||||
DelayWhileIdle: true,
|
||||
TimeToLive: 100,
|
||||
RestrictedPackageName: test,
|
||||
DryRun: true,
|
||||
Data: map[string]interface{}{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
},
|
||||
Notification: gcm.Notification{
|
||||
Title: test,
|
||||
},
|
||||
}
|
||||
|
||||
notification := GetAndroidNotification(req)
|
||||
|
||||
assert.Equal(t, test, notification.To)
|
||||
assert.Equal(t, "high", notification.Priority)
|
||||
assert.Equal(t, "1", notification.CollapseKey)
|
||||
assert.True(t, notification.ContentAvailable)
|
||||
assert.True(t, notification.DelayWhileIdle)
|
||||
assert.Equal(t, 100, int(notification.TimeToLive))
|
||||
assert.Equal(t, test, notification.RestrictedPackageName)
|
||||
assert.True(t, notification.DryRun)
|
||||
assert.Equal(t, test, notification.Notification.Title)
|
||||
assert.Equal(t, "Welcome", notification.Notification.Body)
|
||||
}
|
|
@ -56,10 +56,13 @@ func GetMainEngine() *gin.Engine {
|
|||
return r
|
||||
}
|
||||
|
||||
func RunHTTPServer() {
|
||||
func RunHTTPServer() error {
|
||||
var err error
|
||||
if PushConf.Core.SSL && PushConf.Core.CertPath != "" && PushConf.Core.KeyPath != "" {
|
||||
GetMainEngine().RunTLS(":"+PushConf.Core.Port, PushConf.Core.CertPath, PushConf.Core.KeyPath)
|
||||
err = GetMainEngine().RunTLS(":"+PushConf.Core.Port, PushConf.Core.CertPath, PushConf.Core.KeyPath)
|
||||
} else {
|
||||
GetMainEngine().Run(":" + PushConf.Core.Port)
|
||||
err = GetMainEngine().Run(":" + PushConf.Core.Port)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -3,10 +3,14 @@ package gopush
|
|||
import (
|
||||
"github.com/appleboy/gofight"
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var go_version = runtime.Version()
|
||||
|
@ -16,6 +20,56 @@ func initTest() {
|
|||
PushConf.Core.Mode = "test"
|
||||
}
|
||||
|
||||
func testRequest(t *testing.T, url string) {
|
||||
resp, err := http.Get(url)
|
||||
defer resp.Body.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, ioerr := ioutil.ReadAll(resp.Body)
|
||||
assert.NoError(t, ioerr)
|
||||
assert.Equal(t, "200 OK", resp.Status, "should get a 200")
|
||||
}
|
||||
|
||||
func TestPrintGoPushVersion(t *testing.T) {
|
||||
PrintGoPushVersion()
|
||||
}
|
||||
|
||||
func TestRunNormalServer(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
router := gin.New()
|
||||
|
||||
go func() {
|
||||
assert.NoError(t, RunHTTPServer())
|
||||
}()
|
||||
// have to wait for the goroutine to start and run the server
|
||||
// otherwise the main thread will complete
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
assert.Error(t, router.Run(":8088"))
|
||||
testRequest(t, "http://localhost:8088/api/status")
|
||||
}
|
||||
|
||||
// func TestRunTLSServer(t *testing.T) {
|
||||
// initTest()
|
||||
|
||||
// PushConf.Core.SSL = true
|
||||
// PushConf.Core.Port = "8087"
|
||||
// PushConf.Core.CertPath = "../certificate/localhost.cert"
|
||||
// PushConf.Core.KeyPath = "../certificate/localhost.key"
|
||||
// router := gin.New()
|
||||
|
||||
// go func() {
|
||||
// assert.NoError(t, RunHTTPServer())
|
||||
// }()
|
||||
// // have to wait for the goroutine to start and run the server
|
||||
// // otherwise the main thread will complete
|
||||
// time.Sleep(5 * time.Millisecond)
|
||||
|
||||
// assert.Error(t, router.Run(":8087"))
|
||||
// testRequest(t, "https://localhost:8087/api/status")
|
||||
// }
|
||||
|
||||
func TestRootHandler(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
|
@ -48,7 +102,7 @@ func TestAPIStatusHandler(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestPushHandler(t *testing.T) {
|
||||
func TestMissingParameterPushHandler(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
r := gofight.New()
|
||||
|
@ -63,3 +117,157 @@ func TestPushHandler(t *testing.T) {
|
|||
assert.Equal(t, http.StatusBadRequest, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDisabledIosPushHandler(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Ios.Enabled = false
|
||||
InitAPNSClient()
|
||||
|
||||
r := gofight.New()
|
||||
|
||||
r.POST("/api/push").
|
||||
SetJSON(gofight.D{
|
||||
"tokens": []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
||||
"platform": 1,
|
||||
"message": "Welcome",
|
||||
}).
|
||||
Run(GetMainEngine(), func(r gofight.HttpResponse, rq gofight.HttpRequest) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMissingIosCertificate(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Ios.Enabled = true
|
||||
PushConf.Ios.PemKeyPath = "test"
|
||||
err := InitAPNSClient()
|
||||
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestIosPushDevelopment(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Ios.Enabled = true
|
||||
PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem"
|
||||
InitAPNSClient()
|
||||
|
||||
r := gofight.New()
|
||||
|
||||
r.POST("/api/push").
|
||||
SetJSON(gofight.D{
|
||||
"tokens": []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
||||
"platform": 1,
|
||||
"message": "Welcome",
|
||||
}).
|
||||
Run(GetMainEngine(), func(r gofight.HttpResponse, rq gofight.HttpRequest) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIosPushProduction(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Ios.Enabled = true
|
||||
PushConf.Ios.Production = true
|
||||
PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem"
|
||||
InitAPNSClient()
|
||||
|
||||
r := gofight.New()
|
||||
|
||||
r.POST("/api/push").
|
||||
SetJSON(gofight.D{
|
||||
"tokens": []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
|
||||
"platform": 1,
|
||||
"message": "Welcome",
|
||||
}).
|
||||
Run(GetMainEngine(), func(r gofight.HttpResponse, rq gofight.HttpRequest) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDisabledAndroidPushHandler(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Android.Enabled = false
|
||||
|
||||
r := gofight.New()
|
||||
|
||||
r.POST("/api/push").
|
||||
SetJSON(gofight.D{
|
||||
"tokens": []string{"aaaaaa", "bbbbb"},
|
||||
"platform": 2,
|
||||
"message": "Welcome",
|
||||
}).
|
||||
Run(GetMainEngine(), func(r gofight.HttpResponse, rq gofight.HttpRequest) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAndroidWrongAPIKey(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Android.Enabled = true
|
||||
PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY") + "a"
|
||||
|
||||
r := gofight.New()
|
||||
|
||||
r.POST("/api/push").
|
||||
SetJSON(gofight.D{
|
||||
"tokens": []string{"aaaaaa", "bbbbb"},
|
||||
"platform": 2,
|
||||
"message": "Welcome",
|
||||
}).
|
||||
Run(GetMainEngine(), func(r gofight.HttpResponse, rq gofight.HttpRequest) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAndroidWrongToken(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Android.Enabled = true
|
||||
PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY")
|
||||
|
||||
r := gofight.New()
|
||||
|
||||
r.POST("/api/push").
|
||||
SetJSON(gofight.D{
|
||||
"tokens": []string{"aaaaaa", "bbbbb"},
|
||||
"platform": 2,
|
||||
"message": "Welcome",
|
||||
}).
|
||||
Run(GetMainEngine(), func(r gofight.HttpResponse, rq gofight.HttpRequest) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAndroidRightToken(t *testing.T) {
|
||||
initTest()
|
||||
|
||||
PushConf.Android.Enabled = true
|
||||
PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY")
|
||||
|
||||
android_token := os.Getenv("ANDROID_TEST_TOKEN")
|
||||
|
||||
r := gofight.New()
|
||||
|
||||
r.POST("/api/push").
|
||||
SetJSON(gofight.D{
|
||||
"tokens": []string{android_token, "bbbbb"},
|
||||
"platform": 2,
|
||||
"message": "Welcome",
|
||||
}).
|
||||
Run(GetMainEngine(), func(r gofight.HttpResponse, rq gofight.HttpRequest) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue