223 lines
5.3 KiB
Go
223 lines
5.3 KiB
Go
package ironnotify
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// Transport handles HTTP communication with the IronNotify API.
|
|
type Transport struct {
|
|
baseURL string
|
|
apiKey string
|
|
debug bool
|
|
httpClient *http.Client
|
|
}
|
|
|
|
// NewTransport creates a new Transport.
|
|
func NewTransport(baseURL, apiKey string, timeout time.Duration, debug bool) *Transport {
|
|
return &Transport{
|
|
baseURL: baseURL,
|
|
apiKey: apiKey,
|
|
debug: debug,
|
|
httpClient: &http.Client{
|
|
Timeout: timeout,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Send sends a notification payload to the server.
|
|
func (t *Transport) Send(ctx context.Context, payload *NotificationPayload) SendResult {
|
|
data, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return SendResult{Success: false, Error: err.Error()}
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "POST", t.baseURL+"/api/v1/notify", bytes.NewReader(data))
|
|
if err != nil {
|
|
return SendResult{Success: false, Error: err.Error()}
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+t.apiKey)
|
|
|
|
if t.debug {
|
|
fmt.Printf("[IronNotify] Sending notification: %s\n", payload.EventType)
|
|
}
|
|
|
|
resp, err := t.httpClient.Do(req)
|
|
if err != nil {
|
|
return SendResult{Success: false, Error: err.Error()}
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
|
var result struct {
|
|
NotificationID string `json:"notificationId"`
|
|
}
|
|
if err := json.Unmarshal(body, &result); err == nil {
|
|
return SendResult{Success: true, NotificationID: result.NotificationID}
|
|
}
|
|
return SendResult{Success: true}
|
|
}
|
|
|
|
var errorResp struct {
|
|
Error string `json:"error"`
|
|
}
|
|
if err := json.Unmarshal(body, &errorResp); err == nil && errorResp.Error != "" {
|
|
return SendResult{Success: false, Error: errorResp.Error}
|
|
}
|
|
|
|
return SendResult{Success: false, Error: fmt.Sprintf("HTTP %d: %s", resp.StatusCode, string(body))}
|
|
}
|
|
|
|
// GetNotifications retrieves notifications from the server.
|
|
func (t *Transport) GetNotifications(ctx context.Context, limit, offset int, unreadOnly bool) ([]Notification, error) {
|
|
u, err := url.Parse(t.baseURL + "/api/v1/notifications")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
q := u.Query()
|
|
if limit > 0 {
|
|
q.Set("limit", strconv.Itoa(limit))
|
|
}
|
|
if offset > 0 {
|
|
q.Set("offset", strconv.Itoa(offset))
|
|
}
|
|
if unreadOnly {
|
|
q.Set("unread_only", "true")
|
|
}
|
|
u.RawQuery = q.Encode()
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+t.apiKey)
|
|
|
|
resp, err := t.httpClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
var notifications []Notification
|
|
if err := json.NewDecoder(resp.Body).Decode(¬ifications); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return notifications, nil
|
|
}
|
|
|
|
// GetUnreadCount retrieves the unread notification count.
|
|
func (t *Transport) GetUnreadCount(ctx context.Context) (int, error) {
|
|
req, err := http.NewRequestWithContext(ctx, "GET", t.baseURL+"/api/v1/notifications/unread-count", nil)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+t.apiKey)
|
|
|
|
resp, err := t.httpClient.Do(req)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return 0, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
var result struct {
|
|
Count int `json:"count"`
|
|
}
|
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return result.Count, nil
|
|
}
|
|
|
|
// MarkAsRead marks a notification as read.
|
|
func (t *Transport) MarkAsRead(ctx context.Context, notificationID string) error {
|
|
req, err := http.NewRequestWithContext(ctx, "POST", t.baseURL+"/api/v1/notifications/"+notificationID+"/read", nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+t.apiKey)
|
|
|
|
resp, err := t.httpClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
|
return nil
|
|
}
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
// MarkAllAsRead marks all notifications as read.
|
|
func (t *Transport) MarkAllAsRead(ctx context.Context) error {
|
|
req, err := http.NewRequestWithContext(ctx, "POST", t.baseURL+"/api/v1/notifications/read-all", nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+t.apiKey)
|
|
|
|
resp, err := t.httpClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
|
return nil
|
|
}
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
|
|
// IsOnline checks if the API is reachable.
|
|
func (t *Transport) IsOnline(ctx context.Context) bool {
|
|
req, err := http.NewRequestWithContext(ctx, "GET", t.baseURL+"/health", nil)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
resp, err := t.httpClient.Do(req)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode == http.StatusOK
|
|
}
|
|
|
|
// Close closes the transport.
|
|
func (t *Transport) Close() {
|
|
t.httpClient.CloseIdleConnections()
|
|
}
|