mirror of
https://github.com/binwiederhier/ntfy.git
synced 2025-06-01 11:09:30 +02:00
WIP: CLI, relates to #46
This commit is contained in:
parent
4346f55b29
commit
1e8421e8ce
10 changed files with 571 additions and 102 deletions
client
135
client/client.go
Normal file
135
client/client.go
Normal file
|
@ -0,0 +1,135 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultBaseURL = "https://ntfy.sh"
|
||||
)
|
||||
|
||||
const (
|
||||
MessageEvent = "message"
|
||||
KeepaliveEvent = "keepalive"
|
||||
OpenEvent = "open"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
BaseURL string
|
||||
Messages chan *Message
|
||||
subscriptions map[string]*subscription
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
ID string
|
||||
Event string
|
||||
Time int64
|
||||
Topic string
|
||||
Message string
|
||||
Title string
|
||||
Priority int
|
||||
Tags []string
|
||||
BaseURL string
|
||||
TopicURL string
|
||||
Raw string
|
||||
}
|
||||
|
||||
type subscription struct {
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
var DefaultClient = New()
|
||||
|
||||
func New() *Client {
|
||||
return &Client{
|
||||
Messages: make(chan *Message),
|
||||
subscriptions: make(map[string]*subscription),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Publish(topicURL, message string, options ...PublishOption) error {
|
||||
req, _ := http.NewRequest("POST", topicURL, strings.NewReader(message))
|
||||
for _, option := range options {
|
||||
if err := option(req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected response %d from server", resp.StatusCode)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) Subscribe(topicURL string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if _, ok := c.subscriptions[topicURL]; ok {
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
c.subscriptions[topicURL] = &subscription{cancel}
|
||||
go handleConnectionLoop(ctx, c.Messages, topicURL)
|
||||
}
|
||||
|
||||
func (c *Client) Unsubscribe(topicURL string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
sub, ok := c.subscriptions[topicURL]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
sub.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
func handleConnectionLoop(ctx context.Context, msgChan chan *Message, topicURL string) {
|
||||
for {
|
||||
if err := handleConnection(ctx, msgChan, topicURL); err != nil {
|
||||
log.Printf("connection to %s failed: %s", topicURL, err.Error())
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Printf("connection to %s exited", topicURL)
|
||||
return
|
||||
case <-time.After(5 * time.Second):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleConnection(ctx context.Context, msgChan chan *Message, topicURL string) error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/json", topicURL), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
for scanner.Scan() {
|
||||
var m *Message
|
||||
line := scanner.Text()
|
||||
if err := json.NewDecoder(strings.NewReader(line)).Decode(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
m.BaseURL = strings.TrimSuffix(topicURL, "/"+m.Topic) // FIXME hack!
|
||||
m.TopicURL = topicURL
|
||||
m.Raw = line
|
||||
msgChan <- m
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue