pullaway

package module
v0.0.0-...-cc4fff1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 1, 2024 License: MIT Imports: 12 Imported by: 0

README

Pullaway

CI

Pullaway is a lightweight Go Pushover client cli and library. It allows you to receive messages from Pushover in real-time via WebSocket. You can use it as a command-line tool or as a library in your Go projects.

Note: Pullaway is a Pushover client for receiving messages from Pushover. It is not a library for sending messages via Pushover.

[!IMPORTANT] This tool requires a Pushover account and a Pushover Desktop license. You can purchase a license at https://pushover.net/clients/desktop.

Features

  • Login and Device Registration: Securely log in to your Pushover account and register your device.
  • Message Retrieval: Download and delete messages from your Pushover account.
  • Real-Time Listening: Listen for incoming messages via WebSocket with automatic reconnection.
  • Secure Credential Storage: Uses keyring to securely store your Pushover credentials.
  • Library Support: Use Pullaway as a Go library in your own projects.

Installation

As a Command-Line Tool

Install pullaway using go install:

go install github.com/donatj/pullaway/cmd/pullaway@latest

This will download and install the pullaway command-line tool to your $GOPATH/bin directory.

As a Library

To use pullaway as a library in your Go project, get it using go get:

go get github.com/donatj/pullaway

Then import it in your code:

import "github.com/donatj/pullaway"

Usage

Prerequisites
Command-Line Tool
Initialization

On first setup, you will need to run pullaway init to authorize your account and register the client as a Pushover device.

This only needs to be done once.

pullaway init

You will be prompted to enter:

  • Email: Your Pushover account email.
  • Password: Your Pushover account password.
  • Two-Factor Authentication: If enabled, provide your 2FA code.
  • Device ShortName: A name for your device (up to 25 characters).

Your credentials and device information will be securely stored using keyring.

Listening for Messages

After initialization, start listening for incoming messages:

pullaway listen

Pullaway will connect to Pushover's WebSocket server to receive messages in real-time. It automatically handles reconnections in case of network interruptions.

Library Usage

You can use pullaway as a library in your Go projects to interact with Pushover. Below is a basic example:

package main

import (
    "log"

    "github.com/donatj/pullaway"
)

func main() {
    // Initialize a new Pushover client
    pc := &pullaway.PushoverClient{}

    // Log in to Pushover
    loginResp, err := pc.Login("your-email@example.com", "your-password", "your-2fa-code")
    if err != nil {
        log.Fatalf("Login failed: %v", err)
    }

    // Register the device
    regResp, err := pc.Register(loginResp.Secret, "your-device-name")
    if err != nil {
        log.Fatalf("Registration failed: %v", err)
    }

    // Create an authorized client
    ac := pullaway.NewAuthorizedClient(loginResp.Secret, regResp.ID)

    // Download messages
    messages, err := ac.DownloadMessages()
    if err != nil {
        log.Fatalf("Failed to download messages: %v", err)
    }

    // Process messages
    for _, msg := range messages.Messages {
        log.Printf("Received message: %s", msg.Message)
    }
}
Listening for Messages with Reconnection
package main

import (
    "log"

    "github.com/donatj/pullaway"
    "log/slog"
    "os"
)

func main() {
    // Assuming you have the user secret and device ID stored securely
    userSecret := "your-user-secret"
    deviceID := "your-device-id"

    // Create an authorized client
    ac := pullaway.NewAuthorizedClient(userSecret, deviceID)

    // Get an authorized listener with a logger
    listener := ac.GetAuthorizedListener(slog.New(slog.NewTextHandler(os.Stdout, nil)))

    // Define your message callback
    messageCallback := func() error {
        // Download and process messages
        messages, _, err := ac.DownloadAndDeleteMessages()
        if err != nil {
            return err
        }

        for _, msg := range messages.Messages {
            log.Printf("Received message: %s", msg.Message)
        }

        return nil
    }

    // Start listening with automatic reconnection
    err := listener.ListenWithReconnect(messageCallback)
    if err != nil {
        log.Fatalf("Error listening: %v", err)
    }
}

Configuration

Pullaway securely stores your Pushover secret and device ID using the keyring library. This ensures that your sensitive information remains protected across sessions.

Logging

By default, pullaway logs informational messages to the console. You can customize logging behavior by implementing your own LeveledLogger interface if needed.

Important Note

Pullaway is intended solely for receiving messages from Pushover. It does not support sending messages. If you are looking for a library to send messages via Pushover, please refer to other available libraries.

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests for enhancements or bug fixes.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrWebsocketConnectFail = fmt.Errorf("error connecting to WebSocket")
	ErrWebsocketLoginFail   = fmt.Errorf("error logging in to WebSocket")
	ErrWebsocketReadFail    = fmt.Errorf("error reading from WebSocket")

	ErrNeedReconnect  = fmt.Errorf("need to reconnect")
	ErrPermanentIssue = fmt.Errorf("permanent error")
	ErrSessionIssue   = fmt.Errorf("session issue")
)
View Source
var DefaultListener = &Listener{
	Log: slog.New(slog.NewTextHandler(io.Discard, nil)),
}

Functions

func Listen

func Listen(deviceID string, secret string, ml MessageCallback) error

func ListenWithReconnect

func ListenWithReconnect(deviceID string, secret string, ml MessageCallback) error

Types

type AuthorizedClient

type AuthorizedClient struct {
	UserSecret string
	DeviceID   string

	*PushoverClient
}

func NewAuthorizedClient

func NewAuthorizedClient(userSecret, deviceID string) *AuthorizedClient

func (*AuthorizedClient) DeleteMessages

func (ac *AuthorizedClient) DeleteMessages(id int64) (*DeleteResponse, error)

func (*AuthorizedClient) DownloadAndDeleteMessages

func (ac *AuthorizedClient) DownloadAndDeleteMessages() (*DownloadResponse, *DeleteResponse, error)

func (*AuthorizedClient) DownloadMessages

func (ac *AuthorizedClient) DownloadMessages() (*DownloadResponse, error)

func (*AuthorizedClient) GetAuthorizedListener

func (ac *AuthorizedClient) GetAuthorizedListener(l LeveledLogger) *AuthorizedListener

type AuthorizedListener

type AuthorizedListener struct {
	*AuthorizedClient
	*Listener
}

func NewAuthorizedListener

func NewAuthorizedListener(ac *AuthorizedClient, l LeveledLogger) *AuthorizedListener

func (*AuthorizedListener) Listen

func (al *AuthorizedListener) Listen(ml MessageCallback) error

func (*AuthorizedListener) ListenWithReconnect

func (al *AuthorizedListener) ListenWithReconnect(ml MessageCallback) error

type DeleteResponse

type DeleteResponse struct {
	PushoverClientResponse
}

func DeleteMessages

func DeleteMessages(api url.URL, secret, deviceID string, id int64) (*DeleteResponse, error)

type Device

type Device struct {
	Name                              string `json:"name"`
	EncryptionEnabled                 bool   `json:"encryption_enabled"`
	DefaultSound                      string `json:"default_sound"`
	AlwaysUseDefaultSound             bool   `json:"always_use_default_sound"`
	DefaultHighPrioritySound          string `json:"default_high_priority_sound"`
	AlwaysUseDefaultHighPrioritySound bool   `json:"always_use_default_high_priority_sound"`
	DismissalSyncEnabled              bool   `json:"dismissal_sync_enabled"`
}

type DownloadResponse

type DownloadResponse struct {
	Messages []Messages `json:"messages"`
	User     User       `json:"user"`
	Device   Device     `json:"device"`

	PushoverClientResponse
}

func DownloadMessages

func DownloadMessages(api url.URL, secret, deviceID string) (*DownloadResponse, error)

func (*DownloadResponse) MaxID

func (r *DownloadResponse) MaxID() int64

type Errors

type Errors struct {
	Name []string `json:"name"`
}

type LeveledLogger

type LeveledLogger interface {
	Error(string, ...interface{})
	Info(string, ...interface{})
	Debug(string, ...interface{})
	Warn(string, ...interface{})
}

LeveledLogger is an interface for loggers or logger wrappers that support leveled logging. The methods take a message string and optional variadic key-value pairs.

type Listener

type Listener struct {
	Log LeveledLogger
}

func NewListener

func NewListener(l LeveledLogger) *Listener

func (*Listener) Listen

func (l *Listener) Listen(deviceID string, secret string, ml MessageCallback) error

func (*Listener) ListenWithReconnect

func (l *Listener) ListenWithReconnect(deviceID string, secret string, ml MessageCallback) error

type LoginResponse

type LoginResponse struct {
	ID     string `json:"id"`
	Secret string `json:"secret"`

	PushoverClientResponse
}

func Login

func Login(api url.URL, username, password, twofa string) (*LoginResponse, error)

type MessageCallback

type MessageCallback func() error

type Messages

type Messages struct {
	ID             int64  `json:"id"`
	IDStr          string `json:"id_str"`
	Message        string `json:"message"`
	App            string `json:"app"`
	Aid            int    `json:"aid"`
	AidStr         string `json:"aid_str"`
	Icon           string `json:"icon"`
	Date           int    `json:"date"`
	Priority       int    `json:"priority"`
	Acked          int    `json:"acked"`
	Umid           int64  `json:"umid"`
	UmidStr        string `json:"umid_str"`
	Title          string `json:"title"`
	DispatchedDate int    `json:"dispatched_date"`
	URL            string `json:"url,omitempty"`
	QueuedDate     int    `json:"queued_date,omitempty"`
}

type PushoverClient

type PushoverClient struct {
	APIURL string
}

func (*PushoverClient) DownloadAndDeleteMessages

func (pc *PushoverClient) DownloadAndDeleteMessages(secret, deviceID string) (*DownloadResponse, *DeleteResponse, error)

func (*PushoverClient) GetApiURL

func (pc *PushoverClient) GetApiURL() (url.URL, error)

func (*PushoverClient) Login

func (pc *PushoverClient) Login(username, password, twofa string) (*LoginResponse, error)

func (*PushoverClient) Register

func (pc *PushoverClient) Register(secret, name string) (*RegistrationResponse, error)

type PushoverClientResponse

type PushoverClientResponse struct {
	Status  int    `json:"status"`
	Request string `json:"request"`
	Errors  Errors `json:"errors,omitempty"`
}

func (*PushoverClientResponse) Error

func (r *PushoverClientResponse) Error() string

func (*PushoverClientResponse) IsValid

func (r *PushoverClientResponse) IsValid() bool

type RegistrationResponse

type RegistrationResponse struct {
	ID string `json:"id"`

	PushoverClientResponse
}

func Register

func Register(api url.URL, secret, name string) (*RegistrationResponse, error)

type User

type User struct {
	QuietHours        bool   `json:"quiet_hours"`
	IsAndroidLicensed bool   `json:"is_android_licensed"`
	IsIosLicensed     bool   `json:"is_ios_licensed"`
	IsDesktopLicensed bool   `json:"is_desktop_licensed"`
	Email             string `json:"email"`
	CreatedAt         int    `json:"created_at"`
	FirstEmailAlias   string `json:"first_email_alias"`
	ShowTipjar        string `json:"show_tipjar"`
	ShowTeamAd        string `json:"show_team_ad"`
}

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL