mirror of
https://github.com/binwiederhier/ntfy.git
synced 2024-11-21 19:03:26 +01:00
Do not print ugly WS error; tests
This commit is contained in:
parent
846ee0fb2d
commit
707c58a120
9 changed files with 204 additions and 65 deletions
|
@ -36,14 +36,16 @@ type Client struct {
|
||||||
|
|
||||||
// Message is a struct that represents a ntfy message
|
// Message is a struct that represents a ntfy message
|
||||||
type Message struct { // TODO combine with server.message
|
type Message struct { // TODO combine with server.message
|
||||||
ID string
|
ID string
|
||||||
Event string
|
Event string
|
||||||
Time int64
|
Time int64
|
||||||
Topic string
|
Topic string
|
||||||
Message string
|
Message string
|
||||||
Title string
|
Title string
|
||||||
Priority int
|
Priority int
|
||||||
Tags []string
|
Tags []string
|
||||||
|
Click string
|
||||||
|
Attachment *Attachment
|
||||||
|
|
||||||
// Additional fields
|
// Additional fields
|
||||||
TopicURL string
|
TopicURL string
|
||||||
|
@ -51,6 +53,15 @@ type Message struct { // TODO combine with server.message
|
||||||
Raw string
|
Raw string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Attachment struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Size int64 `json:"size,omitempty"`
|
||||||
|
Expires int64 `json:"expires,omitempty"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Owner string `json:"-"` // IP address of uploader, used for rate limiting
|
||||||
|
}
|
||||||
|
|
||||||
type subscription struct {
|
type subscription struct {
|
||||||
ID string
|
ID string
|
||||||
topicURL string
|
topicURL string
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"heckel.io/ntfy/client"
|
"heckel.io/ntfy/client"
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -15,7 +13,7 @@ import (
|
||||||
// This only contains helpers so far
|
// This only contains helpers so far
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
log.SetOutput(io.Discard)
|
// log.SetOutput(io.Discard)
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,3 +34,39 @@ func TestCLI_Publish_Subscribe_Poll(t *testing.T) {
|
||||||
m = toMessage(t, stdout.String())
|
m = toMessage(t, stdout.String())
|
||||||
require.Equal(t, "some message", m.Message)
|
require.Equal(t, "some message", m.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCLI_Publish_All_The_Things(t *testing.T) {
|
||||||
|
s, port := test.StartServer(t)
|
||||||
|
defer test.StopServer(t, s, port)
|
||||||
|
topic := fmt.Sprintf("http://127.0.0.1:%d/mytopic", port)
|
||||||
|
|
||||||
|
app, _, stdout, _ := newTestApp()
|
||||||
|
require.Nil(t, app.Run([]string{
|
||||||
|
"ntfy", "publish",
|
||||||
|
"--title", "this is a title",
|
||||||
|
"--priority", "high",
|
||||||
|
"--tags", "tag1,tag2",
|
||||||
|
// No --delay, --email
|
||||||
|
"--click", "https://ntfy.sh",
|
||||||
|
"--attach", "https://f-droid.org/F-Droid.apk",
|
||||||
|
"--filename", "fdroid.apk",
|
||||||
|
"--no-cache",
|
||||||
|
"--no-firebase",
|
||||||
|
topic,
|
||||||
|
"some message",
|
||||||
|
}))
|
||||||
|
m := toMessage(t, stdout.String())
|
||||||
|
require.Equal(t, "message", m.Event)
|
||||||
|
require.Equal(t, "mytopic", m.Topic)
|
||||||
|
require.Equal(t, "some message", m.Message)
|
||||||
|
require.Equal(t, "this is a title", m.Title)
|
||||||
|
require.Equal(t, 4, m.Priority)
|
||||||
|
require.Equal(t, []string{"tag1", "tag2"}, m.Tags)
|
||||||
|
require.Equal(t, "https://ntfy.sh", m.Click)
|
||||||
|
require.Equal(t, "https://f-droid.org/F-Droid.apk", m.Attachment.URL)
|
||||||
|
require.Equal(t, "fdroid.apk", m.Attachment.Name)
|
||||||
|
require.Equal(t, int64(0), m.Attachment.Size)
|
||||||
|
require.Equal(t, "", m.Attachment.Owner)
|
||||||
|
require.Equal(t, int64(0), m.Attachment.Expires)
|
||||||
|
require.Equal(t, "", m.Attachment.Type)
|
||||||
|
}
|
||||||
|
|
68
cmd/serve_test.go
Normal file
68
cmd/serve_test.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"heckel.io/ntfy/client"
|
||||||
|
"heckel.io/ntfy/test"
|
||||||
|
"heckel.io/ntfy/util"
|
||||||
|
"math/rand"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().UnixMilli())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCLI_Serve_Unix_Curl(t *testing.T) {
|
||||||
|
sockFile := filepath.Join(t.TempDir(), "ntfy.sock")
|
||||||
|
go func() {
|
||||||
|
app, _, _, _ := newTestApp()
|
||||||
|
err := app.Run([]string{"ntfy", "serve", "--listen-http=-", "--listen-unix=" + sockFile})
|
||||||
|
require.Nil(t, err)
|
||||||
|
}()
|
||||||
|
for i := 0; i < 40 && !util.FileExists(sockFile); i++ {
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
}
|
||||||
|
require.True(t, util.FileExists(sockFile))
|
||||||
|
|
||||||
|
cmd := exec.Command("curl", "-s", "--unix-socket", sockFile, "-d", "this is a message", "localhost/mytopic")
|
||||||
|
out, err := cmd.Output()
|
||||||
|
require.Nil(t, err)
|
||||||
|
m := toMessage(t, string(out))
|
||||||
|
require.Equal(t, "this is a message", m.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCLI_Serve_WebSocket(t *testing.T) {
|
||||||
|
port := 10000 + rand.Intn(20000)
|
||||||
|
go func() {
|
||||||
|
app, _, _, _ := newTestApp()
|
||||||
|
err := app.Run([]string{"ntfy", "serve", fmt.Sprintf("--listen-http=:%d", port)})
|
||||||
|
require.Nil(t, err)
|
||||||
|
}()
|
||||||
|
test.WaitForPortUp(t, port)
|
||||||
|
|
||||||
|
ws, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf("ws://127.0.0.1:%d/mytopic/ws", port), nil)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
messageType, data, err := ws.ReadMessage()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, websocket.TextMessage, messageType)
|
||||||
|
require.Equal(t, "open", toMessage(t, string(data)).Event)
|
||||||
|
|
||||||
|
c := client.New(client.NewConfig())
|
||||||
|
_, err = c.Publish(fmt.Sprintf("http://127.0.0.1:%d/mytopic", port), "my message")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
messageType, data, err = ws.ReadMessage()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, websocket.TextMessage, messageType)
|
||||||
|
|
||||||
|
m := toMessage(t, string(data))
|
||||||
|
require.Equal(t, "my message", m.Message)
|
||||||
|
require.Equal(t, "mytopic", m.Topic)
|
||||||
|
}
|
|
@ -184,6 +184,9 @@ format. Keepalive messages are sent as empty lines.
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Subscribe via WebSockets
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
## Advanced features
|
## Advanced features
|
||||||
|
|
||||||
### Poll for messages
|
### Poll for messages
|
||||||
|
|
49
server/errors.go
Normal file
49
server/errors.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errHTTP is a generic HTTP error for any non-200 HTTP error
|
||||||
|
type errHTTP struct {
|
||||||
|
Code int `json:"code,omitempty"`
|
||||||
|
HTTPCode int `json:"http"`
|
||||||
|
Message string `json:"error"`
|
||||||
|
Link string `json:"link,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e errHTTP) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e errHTTP) JSON() string {
|
||||||
|
b, _ := json.Marshal(&e)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errHTTPBadRequestEmailDisabled = &errHTTP{40001, http.StatusBadRequest, "e-mail notifications are not enabled", "https://ntfy.sh/docs/config/#e-mail-notifications"}
|
||||||
|
errHTTPBadRequestDelayNoCache = &errHTTP{40002, http.StatusBadRequest, "cannot disable cache for delayed message", ""}
|
||||||
|
errHTTPBadRequestDelayNoEmail = &errHTTP{40003, http.StatusBadRequest, "delayed e-mail notifications are not supported", ""}
|
||||||
|
errHTTPBadRequestDelayCannotParse = &errHTTP{40004, http.StatusBadRequest, "invalid delay parameter: unable to parse delay", "https://ntfy.sh/docs/publish/#scheduled-delivery"}
|
||||||
|
errHTTPBadRequestDelayTooSmall = &errHTTP{40005, http.StatusBadRequest, "invalid delay parameter: too small, please refer to the docs", "https://ntfy.sh/docs/publish/#scheduled-delivery"}
|
||||||
|
errHTTPBadRequestDelayTooLarge = &errHTTP{40006, http.StatusBadRequest, "invalid delay parameter: too large, please refer to the docs", "https://ntfy.sh/docs/publish/#scheduled-delivery"}
|
||||||
|
errHTTPBadRequestPriorityInvalid = &errHTTP{40007, http.StatusBadRequest, "invalid priority parameter", "https://ntfy.sh/docs/publish/#message-priority"}
|
||||||
|
errHTTPBadRequestSinceInvalid = &errHTTP{40008, http.StatusBadRequest, "invalid since parameter", "https://ntfy.sh/docs/subscribe/api/#fetch-cached-messages"}
|
||||||
|
errHTTPBadRequestTopicInvalid = &errHTTP{40009, http.StatusBadRequest, "invalid topic: path invalid", ""}
|
||||||
|
errHTTPBadRequestTopicDisallowed = &errHTTP{40010, http.StatusBadRequest, "invalid topic: topic name is disallowed", ""}
|
||||||
|
errHTTPBadRequestMessageNotUTF8 = &errHTTP{40011, http.StatusBadRequest, "invalid message: message must be UTF-8 encoded", ""}
|
||||||
|
errHTTPBadRequestAttachmentTooLarge = &errHTTP{40012, http.StatusBadRequest, "invalid request: attachment too large, or bandwidth limit reached", ""}
|
||||||
|
errHTTPBadRequestAttachmentURLInvalid = &errHTTP{40013, http.StatusBadRequest, "invalid request: attachment URL is invalid", ""}
|
||||||
|
errHTTPBadRequestAttachmentsDisallowed = &errHTTP{40014, http.StatusBadRequest, "invalid request: attachments not allowed", ""}
|
||||||
|
errHTTPBadRequestAttachmentsExpiryBeforeDelivery = &errHTTP{40015, http.StatusBadRequest, "invalid request: attachment expiry before delayed delivery date", ""}
|
||||||
|
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", ""}
|
||||||
|
errHTTPTooManyRequestsLimitRequests = &errHTTP{42901, http.StatusTooManyRequests, "limit reached: too many requests, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
|
||||||
|
errHTTPTooManyRequestsLimitEmails = &errHTTP{42902, http.StatusTooManyRequests, "limit reached: too many emails, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
|
||||||
|
errHTTPTooManyRequestsLimitSubscriptions = &errHTTP{42903, http.StatusTooManyRequests, "limit reached: too many active subscriptions, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
|
||||||
|
errHTTPTooManyRequestsLimitTotalTopics = &errHTTP{42904, http.StatusTooManyRequests, "limit reached: the total number of topics on the server has been reached, please contact the admin", "https://ntfy.sh/docs/publish/#limitations"}
|
||||||
|
errHTTPTooManyRequestsAttachmentBandwidthLimit = &errHTTP{42905, http.StatusTooManyRequests, "too many requests: daily bandwidth limit reached", "https://ntfy.sh/docs/publish/#limitations"}
|
||||||
|
errHTTPInternalError = &errHTTP{50001, http.StatusInternalServerError, "internal server error", ""}
|
||||||
|
errHTTPInternalErrorInvalidFilePath = &errHTTP{50002, http.StatusInternalServerError, "internal server error: invalid file path", ""}
|
||||||
|
)
|
|
@ -54,23 +54,6 @@ type Server struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// errHTTP is a generic HTTP error for any non-200 HTTP error
|
|
||||||
type errHTTP struct {
|
|
||||||
Code int `json:"code,omitempty"`
|
|
||||||
HTTPCode int `json:"http"`
|
|
||||||
Message string `json:"error"`
|
|
||||||
Link string `json:"link,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e errHTTP) Error() string {
|
|
||||||
return e.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e errHTTP) JSON() string {
|
|
||||||
b, _ := json.Marshal(&e)
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
type indexPage struct {
|
type indexPage struct {
|
||||||
Topic string
|
Topic string
|
||||||
CacheDuration time.Duration
|
CacheDuration time.Duration
|
||||||
|
@ -128,30 +111,6 @@ var (
|
||||||
//go:embed docs
|
//go:embed docs
|
||||||
docsStaticFs embed.FS
|
docsStaticFs embed.FS
|
||||||
docsStaticCached = &util.CachingEmbedFS{ModTime: time.Now(), FS: docsStaticFs}
|
docsStaticCached = &util.CachingEmbedFS{ModTime: time.Now(), FS: docsStaticFs}
|
||||||
|
|
||||||
errHTTPBadRequestEmailDisabled = &errHTTP{40001, http.StatusBadRequest, "e-mail notifications are not enabled", "https://ntfy.sh/docs/config/#e-mail-notifications"}
|
|
||||||
errHTTPBadRequestDelayNoCache = &errHTTP{40002, http.StatusBadRequest, "cannot disable cache for delayed message", ""}
|
|
||||||
errHTTPBadRequestDelayNoEmail = &errHTTP{40003, http.StatusBadRequest, "delayed e-mail notifications are not supported", ""}
|
|
||||||
errHTTPBadRequestDelayCannotParse = &errHTTP{40004, http.StatusBadRequest, "invalid delay parameter: unable to parse delay", "https://ntfy.sh/docs/publish/#scheduled-delivery"}
|
|
||||||
errHTTPBadRequestDelayTooSmall = &errHTTP{40005, http.StatusBadRequest, "invalid delay parameter: too small, please refer to the docs", "https://ntfy.sh/docs/publish/#scheduled-delivery"}
|
|
||||||
errHTTPBadRequestDelayTooLarge = &errHTTP{40006, http.StatusBadRequest, "invalid delay parameter: too large, please refer to the docs", "https://ntfy.sh/docs/publish/#scheduled-delivery"}
|
|
||||||
errHTTPBadRequestPriorityInvalid = &errHTTP{40007, http.StatusBadRequest, "invalid priority parameter", "https://ntfy.sh/docs/publish/#message-priority"}
|
|
||||||
errHTTPBadRequestSinceInvalid = &errHTTP{40008, http.StatusBadRequest, "invalid since parameter", "https://ntfy.sh/docs/subscribe/api/#fetch-cached-messages"}
|
|
||||||
errHTTPBadRequestTopicInvalid = &errHTTP{40009, http.StatusBadRequest, "invalid topic: path invalid", ""}
|
|
||||||
errHTTPBadRequestTopicDisallowed = &errHTTP{40010, http.StatusBadRequest, "invalid topic: topic name is disallowed", ""}
|
|
||||||
errHTTPBadRequestMessageNotUTF8 = &errHTTP{40011, http.StatusBadRequest, "invalid message: message must be UTF-8 encoded", ""}
|
|
||||||
errHTTPBadRequestAttachmentTooLarge = &errHTTP{40012, http.StatusBadRequest, "invalid request: attachment too large, or bandwidth limit reached", ""}
|
|
||||||
errHTTPBadRequestAttachmentURLInvalid = &errHTTP{40013, http.StatusBadRequest, "invalid request: attachment URL is invalid", ""}
|
|
||||||
errHTTPBadRequestAttachmentsDisallowed = &errHTTP{40014, http.StatusBadRequest, "invalid request: attachments not allowed", ""}
|
|
||||||
errHTTPBadRequestAttachmentsExpiryBeforeDelivery = &errHTTP{40015, http.StatusBadRequest, "invalid request: attachment expiry before delayed delivery date", ""}
|
|
||||||
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", ""}
|
|
||||||
errHTTPTooManyRequestsLimitRequests = &errHTTP{42901, http.StatusTooManyRequests, "limit reached: too many requests, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
|
|
||||||
errHTTPTooManyRequestsLimitEmails = &errHTTP{42902, http.StatusTooManyRequests, "limit reached: too many emails, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
|
|
||||||
errHTTPTooManyRequestsLimitSubscriptions = &errHTTP{42903, http.StatusTooManyRequests, "limit reached: too many active subscriptions, please be nice", "https://ntfy.sh/docs/publish/#limitations"}
|
|
||||||
errHTTPTooManyRequestsLimitTotalTopics = &errHTTP{42904, http.StatusTooManyRequests, "limit reached: the total number of topics on the server has been reached, please contact the admin", "https://ntfy.sh/docs/publish/#limitations"}
|
|
||||||
errHTTPTooManyRequestsAttachmentBandwidthLimit = &errHTTP{42905, http.StatusTooManyRequests, "too many requests: daily bandwidth limit reached", "https://ntfy.sh/docs/publish/#limitations"}
|
|
||||||
errHTTPInternalError = &errHTTP{50001, http.StatusInternalServerError, "internal server error", ""}
|
|
||||||
errHTTPInternalErrorInvalidFilePath = &errHTTP{50002, http.StatusInternalServerError, "internal server error: invalid file path", ""}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -159,10 +118,14 @@ const (
|
||||||
emptyMessageBody = "triggered" // Used if message body is empty
|
emptyMessageBody = "triggered" // Used if message body is empty
|
||||||
defaultAttachmentMessage = "You received a file: %s" // Used if message body is empty, and there is an attachment
|
defaultAttachmentMessage = "You received a file: %s" // Used if message body is empty, and there is an attachment
|
||||||
fcmMessageLimit = 4000 // see maybeTruncateFCMMessage for details
|
fcmMessageLimit = 4000 // see maybeTruncateFCMMessage for details
|
||||||
wsWriteWait = 2 * time.Second
|
)
|
||||||
wsBufferSize = 1024
|
|
||||||
wsReadLimit = 64 // We only ever receive PINGs
|
// WebSocket constants
|
||||||
wsPongWait = 15 * time.Second
|
const (
|
||||||
|
wsWriteWait = 2 * time.Second
|
||||||
|
wsBufferSize = 1024
|
||||||
|
wsReadLimit = 64 // We only ever receive PINGs
|
||||||
|
wsPongWait = 15 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// New instantiates a new Server. It creates the cache and adds a Firebase
|
// New instantiates a new Server. It creates the cache and adds a Firebase
|
||||||
|
@ -371,16 +334,19 @@ func (s *Server) Stop() {
|
||||||
|
|
||||||
func (s *Server) handle(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handle(w http.ResponseWriter, r *http.Request) {
|
||||||
if err := s.handleInternal(w, r); err != nil {
|
if err := s.handleInternal(w, r); err != nil {
|
||||||
var e *errHTTP
|
if websocket.IsWebSocketUpgrade(r) {
|
||||||
var ok bool
|
log.Printf("[%s] WS %s %s - %s", r.RemoteAddr, r.Method, r.URL.Path, err.Error())
|
||||||
if e, ok = err.(*errHTTP); !ok {
|
return // Do not attempt to write to upgraded connection
|
||||||
e = errHTTPInternalError
|
|
||||||
}
|
}
|
||||||
log.Printf("[%s] %s - %d - %d - %s", r.RemoteAddr, r.Method, e.HTTPCode, e.Code, err.Error())
|
httpErr, ok := err.(*errHTTP)
|
||||||
|
if !ok {
|
||||||
|
httpErr = errHTTPInternalError
|
||||||
|
}
|
||||||
|
log.Printf("[%s] HTTP %s %s - %d - %d - %s", r.RemoteAddr, r.Method, r.URL.Path, httpErr.HTTPCode, httpErr.Code, err.Error())
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*") // CORS, allow cross-origin requests
|
w.Header().Set("Access-Control-Allow-Origin", "*") // CORS, allow cross-origin requests
|
||||||
w.WriteHeader(e.HTTPCode)
|
w.WriteHeader(httpErr.HTTPCode)
|
||||||
io.WriteString(w, e.JSON()+"\n")
|
io.WriteString(w, httpErr.JSON()+"\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,7 +877,11 @@ func (s *Server) handleSubscribeWS(w http.ResponseWriter, r *http.Request, v *vi
|
||||||
if err := s.sendOldMessages(topics, since, scheduled, sub); err != nil {
|
if err := s.sendOldMessages(topics, since, scheduled, sub); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return g.Wait()
|
err = g.Wait()
|
||||||
|
if err != nil && websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
|
||||||
|
return nil // Normal closures are not errors
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseQueryFilters(r *http.Request) (messageFilter string, titleFilter string, priorityFilter []int, tagsFilter []string, err error) {
|
func parseQueryFilters(r *http.Request) (messageFilter string, titleFilter string, priorityFilter []int, tagsFilter []string, err error) {
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
# base-url:
|
# base-url:
|
||||||
|
|
||||||
# Listen address for the HTTP & HTTPS web server. If "listen-https" is set, you must also
|
# Listen address for the HTTP & HTTPS web server. If "listen-https" is set, you must also
|
||||||
# set "key-file" and "cert-file". Format: <hostname>:<port>
|
# set "key-file" and "cert-file". Format: [<ip>]:<port>, e.g. "1.2.3.4:8080".
|
||||||
#
|
#
|
||||||
|
# To listen on all interfaces, you may omit the IP address, e.g. ":443".
|
||||||
# To disable HTTP, set "listen-http" to "-".
|
# To disable HTTP, set "listen-http" to "-".
|
||||||
#
|
#
|
||||||
# listen-http: ":80"
|
# listen-http: ":80"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"heckel.io/ntfy/server"
|
"heckel.io/ntfy/server"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -22,6 +23,8 @@ func StartServer(t *testing.T) (*server.Server, int) {
|
||||||
func StartServerWithConfig(t *testing.T, conf *server.Config) (*server.Server, int) {
|
func StartServerWithConfig(t *testing.T, conf *server.Config) (*server.Server, int) {
|
||||||
port := 10000 + rand.Intn(20000)
|
port := 10000 + rand.Intn(20000)
|
||||||
conf.ListenHTTP = fmt.Sprintf(":%d", port)
|
conf.ListenHTTP = fmt.Sprintf(":%d", port)
|
||||||
|
conf.AttachmentCacheDir = t.TempDir()
|
||||||
|
conf.CacheFile = filepath.Join(t.TempDir(), "cache.db")
|
||||||
s, err := server.New(conf)
|
s, err := server.New(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
Loading…
Reference in a new issue