1
0
mirror of https://github.com/nikoksr/notify.git synced 2025-02-09 13:13:44 +02:00

refactor(service): normalize and clean-up bark service

This commit is contained in:
Niko Köser 2022-04-23 16:12:57 +02:00
parent 8fdd3c24dc
commit db2e5884c2
No known key found for this signature in database
GPG Key ID: F3F28C118DAA6375
3 changed files with 186 additions and 74 deletions

View File

@ -5,18 +5,24 @@
## Usage
```go
// Create a bark service. `device key` is generated when you install the application
barkService := bark.New("your bark device key", bark.DefaultServer)
// Create a bark service. `device key` is generated when you install the application. You can use the
// `bark.NewWithServers()` function to create a service with a custom server.
barkService := bark.NewWithServers("your bark device key", bark.DefaultServerURL)
// Tell our notifier to use the bark service. You can repeat the above process
// for as many services as you like and just tell the notifier to use them.
// Or use `bark.New()` to create a service with the default server.
barkService = bark.New("your bark device key")
// Add more servers
barkService.AddReceivers("https://your-bark-server.com")
// Tell our notifier to use the bark service.
notify.UseServices(barkService)
// Send a test message.
_ = notify.Send(
context.Background(),
"Subject/Title",
"The actual message - Hello, you awesome gophers! :)",
context.Background(),
"Subject/Title",
"The actual message - Hello, you awesome gophers! :)",
)
```

View File

@ -7,6 +7,8 @@ import (
"fmt"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
"time"
"github.com/pkg/errors"
@ -14,80 +16,150 @@ import (
// Service allow you to configure Bark service.
type Service struct {
Server string
DeviceKey string
url string
deviceKey string
client *http.Client
serverURLs []string
}
// DefaultServer is the default server to use for the bark service.
const DefaultServer = "api.day.app"
func defaultHTTPClient() *http.Client {
return &http.Client{
Timeout: 5 * time.Second,
}
}
// New returns a new instance of Bark service.
func New(deviceKey, server string) *Service {
p := &Service{
Server: server,
DeviceKey: deviceKey,
// DefaultServerURL is the default server to use for the bark service.
const DefaultServerURL = "https://api.day.app/"
// normalizeServerURL normalizes the server URL. It prefixes it with https:// if it's not already and appends a slash
// if it's not already there. If the serverURL is empty, the DefaultServerURL is used. We're not validating the url here
// on purpose, we leave that to the http client.
func normalizeServerURL(serverURL string) string {
if serverURL == "" {
return DefaultServerURL
}
if server != "" {
p.url = fmt.Sprintf("https://%s/push", server)
} else {
p.url = fmt.Sprintf("https://%s/push", "api.day.app")
// Normalize the url
if !strings.HasPrefix(serverURL, "http") {
serverURL = "https://" + serverURL
}
return p
if !strings.HasSuffix(serverURL, "/") {
serverURL = serverURL + "/"
}
return serverURL
}
// AddReceivers adds server URLs to the list of servers to use for sending messages. We call it Receivers and not
// servers because strictly speaking, the server is still receiving the message, and additionally we're following the
// naming convention of the other services.
func (s *Service) AddReceivers(serverURLs ...string) {
for _, serverURL := range serverURLs {
serverURL = normalizeServerURL(serverURL)
s.serverURLs = append(s.serverURLs, serverURL)
}
}
// NewWithServers returns a new instance of Bark service. You can use this service to send messages to bark. You can
// specify the servers to send the messages to. By default, the service will use the default server
// (https://api.day.app/) if you don't specify any servers.
func NewWithServers(deviceKey string, serverURLs ...string) *Service {
s := &Service{
deviceKey: deviceKey,
client: defaultHTTPClient(),
}
if len(serverURLs) > 0 {
serverURLs = append(serverURLs, DefaultServerURL)
}
// Calling service.AddReceivers() instead of directly setting the serverURLs because we want to normalize the URLs.
s.AddReceivers(serverURLs...)
return s
}
// New returns a new instance of Bark service. You can use this service to send messages to bark. By default, the
// service will use the default server (https://api.day.app/).
func New(deviceKey string) *Service {
return NewWithServers(deviceKey)
}
// postData is the data to send to the bark server.
type postData struct {
DeviceKey string `json:"device_key"`
Title string `json:"title"`
Body string `json:"body,omitempty"`
Badge int `json:"badge,omitempty"`
Sound string `json:"sound,omitempty"`
Icon string `json:"icon,omitempty"`
Group string `json:"group,omitempty"`
URL string `json:"pushURL,omitempty"`
}
func (s *Service) send(ctx context.Context, serverURL, subject, content string) (err error) {
if serverURL == "" {
return errors.New("server url is empty")
}
// Marshal the message to post
message := &postData{
DeviceKey: s.deviceKey,
Title: subject,
Body: content,
Sound: "alarm.caf",
}
messageJSON, err := json.Marshal(message)
if err != nil {
return errors.Wrap(err, "marshal message")
}
// Create new request
pushURL := filepath.Join(serverURL, "push")
req, err := http.NewRequestWithContext(ctx, http.MethodPost, pushURL, bytes.NewBuffer(messageJSON))
if err != nil {
return errors.Wrap(err, "create request")
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
// Send request
resp, err := s.client.Do(req)
if err != nil {
return errors.Wrap(err, "send request")
}
defer func() { _ = resp.Body.Close() }()
// Read response and verify success
result, err := ioutil.ReadAll(resp.Body)
if err != nil {
return errors.Wrap(err, "read response")
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("bark returned status code %d: %s", resp.StatusCode, string(result))
}
return nil
}
// Send takes a message subject and a message content and sends them to bark application.
func (p *Service) Send(ctx context.Context, subject, content string) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
type postData struct {
DeviceKey string `json:"device_key"`
Title string `json:"title"`
Body string `json:"body,omitempty"`
Badge int `json:"badge,omitempty"`
Sound string `json:"sound,omitempty"`
Icon string `json:"icon,omitempty"`
Group string `json:"group,omitempty"`
URL string `json:"url,omitempty"`
}
pd := &postData{
DeviceKey: p.DeviceKey,
Title: subject,
Body: content,
Sound: "alarm.caf",
}
data, err := json.Marshal(pd)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, "POST", p.url, bytes.NewBuffer(data))
if err != nil {
return errors.Wrap(err, "failed to create bark request")
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
httpClient := &http.Client{
Timeout: time.Second * 5,
}
resp, err := httpClient.Do(req)
if err != nil {
return errors.Wrap(err, "send bark request failed")
}
defer resp.Body.Close()
result, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("statusCode: %d, body: %v", resp.StatusCode, string(result))
return errors.Wrap(err, "send bark message failed")
}
if err != nil {
return errors.Wrapf(err, "failed to send message")
}
return nil
func (s *Service) Send(ctx context.Context, subject, content string) error {
if s.client == nil {
return errors.New("client is nil")
}
for _, serverURL := range s.serverURLs {
select {
case <-ctx.Done():
return ctx.Err()
default:
err := s.send(ctx, serverURL, subject, content)
if err != nil {
return errors.Wrapf(err, "failed to send message to bark server %q", serverURL)
}
}
}
return nil
}

34
service/bark/doc.go Normal file
View File

@ -0,0 +1,34 @@
/*
Package bark provides a service for sending messages to bark.
Usage:
package main
import (
"context"
"log"
"github.com/nikoksr/notify"
"github.com/nikoksr/notify/service/bark"
)
func main() {
// Create a bark service. `device key` is generated when you install the application. You can use the
// `bark.NewWithServers` function to create a service with a custom server.
barkService := bark.NewWithServers("your bark device key", bark.DefaultServerURL)
// Or use `bark.New` to create a service with the default server.
barkService = bark.New("your bark device key")
// Tell our notifier to use the bark service.
notify.UseServices(barkService)
// Send a test message.
_ = notify.Send(
context.Background(),
"Subject/Title",
"The actual message - Hello, you awesome gophers! :)",
)
}
*/
package bark