poster

package
v0.0.31 Latest Latest
Warning

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

Go to latest
Published: Jul 4, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrPosterClosed is returned when attempting to post after the poster has been closed
	ErrPosterClosed = errors.New("poster is closed")
)

Functions

This section is empty.

Types

type DeferredCheckError added in v0.0.29

type DeferredCheckError struct {
	FailedArticles []FailedArticleInfo
	TotalArticles  int
}

DeferredCheckError is a non-fatal error indicating some articles need deferred verification. The upload itself succeeded, but article verification (STAT check) failed after all immediate retries.

func (*DeferredCheckError) Error added in v0.0.29

func (e *DeferredCheckError) Error() string

type Engine added in v0.0.30

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the process-wide upload resource owner. It bounds the number of articles posted concurrently (worker slots) and the total memory reserved for in-flight article buffers (buffer budget), independent of how many queue jobs are active. One Engine is shared by every job through the transfer runtime.

All methods are safe for concurrent use and safe to call on a nil *Engine, in which case they are no-ops (preserving standalone behaviour when no engine is injected).

func NewEngine added in v0.0.30

func NewEngine(articleSize uint64, bufferLimit int64, connCapacity int) *Engine

NewEngine builds an Engine sized for the given article size, explicit buffer limit (0 = auto), and total upload connection capacity.

func (*Engine) AcquireWorker added in v0.0.30

func (e *Engine) AcquireWorker(ctx context.Context) error

AcquireWorker blocks until an upload worker slot is free (or ctx is cancelled). Returns ctx.Err() if cancelled while waiting. A nil engine is a no-op.

func (*Engine) Budget added in v0.0.30

func (e *Engine) Budget() EngineBudget

Budget returns the resolved limits.

func (*Engine) Metrics added in v0.0.30

func (e *Engine) Metrics() Metrics

Metrics returns a snapshot of current engine activity. Safe on a nil engine.

func (*Engine) PerArticleBytes added in v0.0.30

func (e *Engine) PerArticleBytes() int64

PerArticleBytes is the reservation size for a single in-flight article, or 0 when no engine is configured.

func (*Engine) ReleaseBuffer added in v0.0.30

func (e *Engine) ReleaseBuffer(n int64)

ReleaseBuffer returns n bytes of buffer budget. Must be paired with a prior successful ReserveBuffer of the same size. A nil engine or non-positive n is a no-op.

func (*Engine) ReleaseWorker added in v0.0.30

func (e *Engine) ReleaseWorker()

ReleaseWorker frees a worker slot acquired by AcquireWorker. A nil engine is a no-op.

func (*Engine) ReserveBuffer added in v0.0.30

func (e *Engine) ReserveBuffer(ctx context.Context, n int64) error

ReserveBuffer blocks until n bytes of buffer budget are available (or ctx is cancelled), then records the reservation. Returns ctx.Err() if cancelled while waiting. A nil engine or non-positive n is a no-op.

type EngineBudget added in v0.0.30

type EngineBudget struct {
	// PerArticleBytes is the memory reserved for a single in-flight article
	// (raw body + estimated encoded size + fixed overhead).
	PerArticleBytes int64
	// BudgetBytes is the total buffer memory the engine may reserve at once.
	BudgetBytes int64
	// WorkerCount is the maximum number of articles posted concurrently.
	WorkerCount int64
}

EngineBudget is the resolved set of process-wide upload limits.

func ComputeEngineBudget added in v0.0.30

func ComputeEngineBudget(articleSize uint64, bufferLimit int64, connCapacity int) EngineBudget

ComputeEngineBudget resolves the process-wide upload-buffer budget and worker count from the configured article size, an explicit buffer limit (0 = auto), and the total connection capacity (sum of max_connections * effective inflight across upload providers).

per_article          = article_size + estimated_yenc_size + 256 KiB
auto_budget          = clamp(per_article * min(conn_capacity, 32), 64MiB, 512MiB)
worker_count         = min(conn_capacity, floor(budget / per_article))

The result guarantees BudgetBytes >= PerArticleBytes and WorkerCount >= 1 so callers can always make forward progress.

type FailedArticleInfo added in v0.0.29

type FailedArticleInfo struct {
	MessageID string
	Groups    []string
}

FailedArticleInfo contains information about an article that failed verification and should be deferred for later checking.

type ManifestSink added in v0.0.30

type ManifestSink interface {
	RecordFile(ctx context.Context, filePath string, articles []*article.Article) error
	// ExistingArticles returns a previously recorded manifest's article records
	// for filePath (ok=false if none), used for crash recovery to reuse the
	// exact Message-IDs rather than regenerating them.
	ExistingArticles(ctx context.Context, filePath string) ([]manifest.ArticleRecord, bool, error)
}

ManifestSink records a durable manifest for a file's articles before they are posted. It is implemented outside the poster (by the transfer runtime) and injected per job; a nil sink disables manifest recording (standalone mode).

type Metrics added in v0.0.30

type Metrics struct {
	ActiveWorkers  int64
	QueuedWorkers  int64
	WorkerCount    int64
	ReservedBytes  int64
	BudgetBytes    int64
	PerArticleByte int64
}

Metrics is a point-in-time snapshot of engine activity for observability.

type Post

type Post struct {
	FilePath string
	Articles []*article.Article
	Status   PostStatus
	Error    error
	Retries  int
	// contains filtered or unexported fields
}

Post represents a file to be posted

type PostStatus

type PostStatus int

PostStatus represents the status of a post

const (
	PostStatusPending PostStatus = iota
	PostStatusPosted
	PostStatusVerified
	PostStatusFailed
	PostStatusCancelled
	PostStatusPosting
)

type Poster

type Poster interface {
	// Post posts files from a directory to Usenet
	Post(ctx context.Context, files []string, rootDir string, nzbGen nzb.NZBGenerator) error
	// PostWithRelativePaths posts files with custom display names (relative paths) for subjects
	// relativePaths maps absolute file path to the display name to use in the subject
	PostWithRelativePaths(ctx context.Context, files []string, rootDir string, nzbGen nzb.NZBGenerator, relativePaths map[string]string) error
	// Stats returns posting statistics
	Stats() Stats
	// Close closes the poster
	Close()
}

Poster defines the interface for posting articles to Usenet

func New

func New(ctx context.Context, cfg config.Config, poolManager pool.PoolManager, jobProgress progress.JobProgress) (Poster, error)

New creates a new poster using dependency injection for the connection pool manager

func NewWithEngine added in v0.0.30

func NewWithEngine(ctx context.Context, cfg config.Config, poolManager pool.PoolManager, jobProgress progress.JobProgress, engine *Engine, manifestSink ManifestSink) (Poster, error)

NewWithEngine creates a poster that routes upload work through the supplied process-wide Engine, so effective concurrency and in-flight buffer memory are bounded across all jobs. A nil engine preserves standalone behaviour. The optional manifestSink records a durable manifest per file before posting; a nil sink disables manifest recording.

type Reposter added in v0.0.30

type Reposter struct {
	// contains filtered or unexported fields
}

Reposter re-posts individual articles during durable verification, reading each body from its original source file and posting through the shared upload pool and engine. It is process-wide (owned by the transfer runtime), distinct from the per-job poster, and implements verification.Reposter.

func NewReposter added in v0.0.30

func NewReposter(uploadPool pool.NNTPClient, engine *Engine, throttleRate int64) *Reposter

NewReposter creates a Reposter using the shared upload pool and engine. If throttleRate > 0 the same byte/sec throttle as normal uploads is applied.

func (*Reposter) Repost added in v0.0.30

func (r *Reposter) Repost(ctx context.Context, rec manifest.ArticleRecord) error

Repost re-posts a single article from its manifest record. The body is read from rec.SourcePath at rec.Offset, and the post reuses rec's Message-ID and headers so the NZB remains correct. It acquires an engine worker slot and buffer reservation so re-posts share the process-wide resource limits.

func (*Reposter) Stats added in v0.0.30

func (r *Reposter) Stats() Stats

Stats returns a snapshot of re-post statistics.

type Stats

type Stats struct {
	ArticlesPosted  int64
	ArticlesChecked int64
	BytesPosted     int64
	ArticleErrors   int64
	StartTime       time.Time
	// contains filtered or unexported fields
}

Stats tracks posting statistics

type Throttle

type Throttle struct {
	// contains filtered or unexported fields
}

Throttle handles rate limiting using a token-bucket algorithm. Token-bucket state is protected by a mutex: the previous lock-free implementation allowed concurrent consumers to overdraw the bucket past zero, silently bypassing the configured rate under contention.

func NewThrottle added in v0.0.6

func NewThrottle(rate int64, interval time.Duration) *Throttle

NewThrottle creates a new throttle with the given rate and interval

func (*Throttle) Wait

func (t *Throttle) Wait(bytes int64)

Wait waits until enough tokens are available for the given bytes. The mutex serialises bucket math so concurrent callers cannot both pass the availability check and double-spend the same tokens.

Jump to

Keyboard shortcuts

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