Initial support for iOS app

This commit is contained in:
Andrew Cope 2022-02-23 22:15:22 -05:00
parent 2eff8d6b47
commit 1b5be4fc6b
5 changed files with 61 additions and 1 deletions

View file

@ -25,6 +25,7 @@ help:
@echo " make build - Build"
@echo " make build-snapshot - Build snapshot"
@echo " make build-simple - Build (using go build, without goreleaser)"
@echo " make build-simple-darwin - Build (using go build, without goreleaser) on macOS systems"
@echo " make clean - Clean build folder"
@echo
@echo "Releasing (requires goreleaser):"
@ -114,6 +115,17 @@ build-simple: clean
-ldflags \
"-linkmode=external -extldflags=-static -s -w -X main.version=$(VERSION) -X main.commit=$(shell git rev-parse --short HEAD) -X main.date=$(shell date +%s)"
build-simple-darwin: clean
mkdir -p dist/ntfy_linux_amd64 server/docs
touch server/docs/dummy
export CGO_ENABLED=1
go build \
-o dist/ntfy_linux_amd64/ntfy \
-tags sqlite_omit_load_extension,osusergo,netgo \
-ldflags \
"-linkmode=external -s -w -X main.version=$(VERSION) -X main.commit=$(shell git rev-parse --short HEAD) -X main.date=$(shell date +%s)"
clean: .PHONY
rm -rf dist build server/docs

View file

@ -20,6 +20,7 @@ Build:
make build - Build
make build-snapshot - Build snapshot
make build-simple - Build (using go build, without goreleaser)
make build-simple-darwin - Build (using go build, without goreleaser) on macOS systems
make clean - Clean build folder
Releasing (requires goreleaser):

View file

@ -13,6 +13,7 @@ import (
const (
fcmMessageLimit = 4000
fcmApnsBodyMessageLimit = 100
)
// maybeTruncateFCMMessage performs best-effort truncation of FCM messages.
@ -34,6 +35,14 @@ func maybeTruncateFCMMessage(m *messaging.Message) *messaging.Message {
return m
}
func maybeTruncateAPNSBodyMessage(s string) string {
if len(s) >= fcmApnsBodyMessageLimit {
over := len(s) - fcmApnsBodyMessageLimit + 3 // len("...")
return s[:len(s)-over] + "..."
}
return s
}
func createFirebaseSubscriber(credentialsFile string, auther auth.Auther) (subscriber, error) {
fb, err := firebase.NewApp(context.Background(), nil, option.WithCredentialsFile(credentialsFile))
if err != nil {
@ -55,6 +64,7 @@ func createFirebaseSubscriber(credentialsFile string, auther auth.Auther) (subsc
func toFirebaseMessage(m *message, auther auth.Auther) (*messaging.Message, error) {
var data map[string]string // Mostly matches https://ntfy.sh/docs/subscribe/api/#json-message-format
var apnsConfig *messaging.APNSConfig
switch m.Event {
case keepaliveEvent, openEvent:
data = map[string]string{
@ -88,6 +98,17 @@ func toFirebaseMessage(m *message, auther auth.Auther) (*messaging.Message, erro
data["attachment_expires"] = fmt.Sprintf("%d", m.Attachment.Expires)
data["attachment_url"] = m.Attachment.URL
}
apnsConfig = &messaging.APNSConfig{
Payload: &messaging.APNSPayload{
Aps: &messaging.Aps{
MutableContent: true,
Alert: &messaging.ApsAlert{
Title: m.Title,
Body: maybeTruncateAPNSBodyMessage(m.Message),
},
},
},
}
} else {
// If anonymous read for a topic is not allowed, we cannot send the message along
// via Firebase. Instead, we send a "poll_request" message, asking the client to poll.
@ -109,5 +130,6 @@ func toFirebaseMessage(m *message, auther auth.Auther) (*messaging.Message, erro
Topic: m.Topic,
Data: data,
Android: androidConfig,
APNS: apnsConfig,
}), nil
}

View file

@ -32,6 +32,7 @@ func TestToFirebaseMessage_Keepalive(t *testing.T) {
require.Nil(t, err)
require.Equal(t, "mytopic", fbm.Topic)
require.Nil(t, fbm.Android)
require.Nil(t, fbm.APNS)
require.Equal(t, map[string]string{
"id": m.ID,
"time": fmt.Sprintf("%d", m.Time),
@ -46,6 +47,7 @@ func TestToFirebaseMessage_Open(t *testing.T) {
require.Nil(t, err)
require.Equal(t, "mytopic", fbm.Topic)
require.Nil(t, fbm.Android)
require.Nil(t, fbm.APNS)
require.Equal(t, map[string]string{
"id": m.ID,
"time": fmt.Sprintf("%d", m.Time),
@ -74,6 +76,17 @@ func TestToFirebaseMessage_Message_Normal_Allowed(t *testing.T) {
require.Equal(t, &messaging.AndroidConfig{
Priority: "high",
}, fbm.Android)
require.Equal(t, &messaging.APNSConfig{
Payload: &messaging.APNSPayload{
Aps: &messaging.Aps{
MutableContent: true,
Alert: &messaging.ApsAlert{
Title: "some title",
Body: "this is a message",
},
},
},
}, fbm.APNS)
require.Equal(t, map[string]string{
"id": m.ID,
"time": fmt.Sprintf("%d", m.Time),
@ -102,6 +115,7 @@ func TestToFirebaseMessage_Message_Normal_Not_Allowed(t *testing.T) {
require.Equal(t, &messaging.AndroidConfig{
Priority: "high",
}, fbm.Android)
require.Nil(t, fbm.APNS)
require.Equal(t, "", fbm.Data["message"])
require.Equal(t, "", fbm.Data["priority"])
require.Equal(t, map[string]string{
@ -129,6 +143,17 @@ func TestMaybeTruncateFCMMessage(t *testing.T) {
Android: &messaging.AndroidConfig{
Priority: "high",
},
APNS: &messaging.APNSConfig{
Payload: &messaging.APNSPayload{
Aps: &messaging.Aps{
MutableContent: true,
Alert: &messaging.ApsAlert{
Title: "some title",
Body: maybeTruncateAPNSBodyMessage(origMessage),
},
},
},
},
}
origMessageLength := len(origFCMMessage.Data["message"])
serializedOrigFCMMessage, _ := json.Marshal(origFCMMessage)

View file

@ -156,7 +156,7 @@ func TestServer_StaticSites(t *testing.T) {
require.Equal(t, 301, rr.Code)
rr = request(t, s, "GET", "/docs/", "", nil)
require.Equal(t, 200, rr.Code)
require.Equal(t, 200, rr.Code) // Test will fail if docs have not yet been built
require.Contains(t, rr.Body.String(), `Made with ❤️ by Philipp C. Heckel`)
require.Contains(t, rr.Body.String(), `<script src=static/js/extra.js></script>`)