app

package
v0.31.3 Latest Latest
Warning

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

Go to latest
Published: May 17, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrTooManyActiveCodes = errors.New("too many active bind codes for this admin")
	ErrCodeUsedOrExpired  = errors.New("bind code is invalid, expired, or already used")
	ErrInvalidReplyLang   = errors.New("invalid reply_lang; only 'zh' or 'en' allowed")
)
View Source
var (
	ErrTorrentNotFound    = errors.New("torrent not found")
	ErrDownloaderNotFound = errors.New("downloader not found")
)
View Source
var ErrConfNotFound = errors.New("notification conf not found")

ErrConfNotFound 当 conf id 不存在时返回。

View Source
var ErrJobNotWired = errors.New("task service start/stop not yet wired (pending T32)")

ErrJobNotWired 表示 StartJob/StopJob 尚未在 T32(DI 接线)阶段完成。 接口契约稳定,方便上层(chatops 命令、web API)先编程对接。

View Source
var ErrSiteNotFound = errors.New("site not found")

ErrSiteNotFound 表示请求的站点未在 registry / ConfigStore 中找到。

View Source
var ErrUserInfoUnavailable = errors.New("site user info not available")

ErrUserInfoUnavailable 表示站点尚未抓取到用户信息,或 driver 不支持。

Functions

This section is empty.

Types

type AuditDTO

type AuditDTO struct {
	ID            uint      `json:"id"`
	CreatedAt     time.Time `json:"created_at"`
	ChannelType   string    `json:"channel_type"`
	ChannelUserID string    `json:"channel_user_id"`
	Command       string    `json:"command"`
	ArgsJSON      string    `json:"args_json"`
	Result        string    `json:"result"`
	LatencyMs     int64     `json:"latency_ms"`
}

type AuditEntry

type AuditEntry struct {
	NotificationConfID uint
	ChannelType        string
	ChannelUserID      string
	Command            string
	Args               map[string]any
	Result             string
	LatencyMs          int64
}

type AuditQuery

type AuditQuery struct {
	Since         time.Time
	Until         time.Time
	ChannelUserID string
	Command       string
	Result        string
	Page          int
	PageSize      int
}

type AuditService

type AuditService interface {
	Record(ctx context.Context, e AuditEntry) error
	Query(ctx context.Context, q AuditQuery) (items []AuditDTO, total int, err error)
	Stats(ctx context.Context) (AuditStatsDTO, error)
	Prune(ctx context.Context) (deleted int64, err error)
}

func NewAuditService

func NewAuditService(db *gorm.DB) AuditService

func NewAuditServiceWithCap

func NewAuditServiceWithCap(db *gorm.DB, rowCap int64, retention time.Duration) AuditService

NewAuditServiceWithCap 暴露 rowCap / retention 供测试注入小阈值;生产请用 NewAuditService。

type AuditStatsDTO

type AuditStatsDTO struct {
	TodayCount   int64   `json:"today_count"`
	TotalCount   int64   `json:"total_count"`
	SuccessRate  float64 `json:"success_rate"`
	MaxLatencyMs int64   `json:"max_latency_ms"`
	AvgLatencyMs float64 `json:"avg_latency_ms"`
}

AuditStatsDTO 聚合指标,用于 ChatOps 审计页顶部的 stat chip。 SuccessRate 单位为百分比 (0..100),已四舍五入到 2 位小数。

type BindCodeDTO

type BindCodeDTO struct {
	Code      string     `json:"code"`
	ConfID    uint       `json:"conf_id"`
	Label     string     `json:"label"`
	ExpiresAt *time.Time `json:"expires_at,omitempty"`
	CreatedAt time.Time  `json:"created_at"`
}

type BindingDTO

type BindingDTO struct {
	ID            uint      `json:"id"`
	ConfID        uint      `json:"conf_id"`
	ChannelType   string    `json:"channel_type"`
	ChannelUserID string    `json:"channel_user_id"`
	Label         string    `json:"label"`
	ReplyLang     string    `json:"reply_lang"`
	PtAdmin       bool      `json:"admin"`
	Allowed       bool      `json:"allowed"`
	CreatedAt     time.Time `json:"created_at"`
	LastActiveAt  time.Time `json:"last_active"`
}

type BindingService

type BindingService interface {
	IssueCode(ctx context.Context, confID uint, label string, ttl time.Duration) (BindCodeDTO, error)
	ListPendingCodes(ctx context.Context) ([]BindCodeDTO, error)
	ConsumeCode(ctx context.Context, code, channelType, channelUserID string) (BindingDTO, error)
	ListBindings(ctx context.Context) ([]BindingDTO, error)
	Revoke(ctx context.Context, bindingID uint) error
	SetReplyLang(ctx context.Context, bindingID uint, lang string) error
}

func NewBindingService

func NewBindingService(db *gorm.DB, createdBy string) BindingService

type CreateConfReq

type CreateConfReq struct {
	ChannelType string
	Name        string
	ConfigJSON  json.RawMessage
	Enabled     bool
}

CreateConfReq 创建通知通道的请求;ConfigJSON 为通道原始配置,进入 service 后会被 AES-GCM 加密落库。

type JobLister

type JobLister interface {
	ListJobs() []scheduler.JobStatus
}

JobLister 是 scheduler.Manager 的最小读视图,便于单元测试 mock。 *scheduler.Manager 自动满足该接口(ListJobs 已在 T8 公开)。

type JobStatusDTO

type JobStatusDTO struct {
	SiteName  string    `json:"site_name"`
	RSSName   string    `json:"rss_name"`
	Running   bool      `json:"running"`
	StartedAt time.Time `json:"started_at"`
}

JobStatusDTO 是 RSS 订阅任务的运行时快照,供 chatops `/tasks`、`/jobs` 等命令使用。

type Notification

type Notification struct {
	Title        string            `json:"title"`
	Text         string            `json:"text"`
	SourceConfID uint              `json:"source_conf_id,omitempty"`
	UserID       string            `json:"user_id,omitempty"`
	Targets      map[string]string `json:"targets,omitempty"`
	Buttons      [][]notify.Button `json:"buttons,omitempty"`
}

Notification 是 NotificationService 与 NotifyManager 之间传递的最小消息载荷。 TODO(T15): 替换为 internal/notify 包内的 notify.Notification 完整结构。

type NotificationConfDTO

type NotificationConfDTO struct {
	ID              uint            `json:"id"`
	ChannelType     string          `json:"channel_type"`
	Name            string          `json:"name"`
	Enabled         bool            `json:"enabled"`
	QuietHoursStart string          `json:"quiet_hours_start,omitempty"`
	QuietHoursEnd   string          `json:"quiet_hours_end,omitempty"`
	ConfigJSON      json.RawMessage `json:"config_json,omitempty"`
	CreatedAt       time.Time       `json:"created_at"`
	UpdatedAt       time.Time       `json:"updated_at"`
}

NotificationConfDTO 是对 models.NotificationConf 的对外只读视图,不含密文字段。

type NotificationService

type NotificationService interface {
	ListConfs(ctx context.Context) ([]NotificationConfDTO, error)
	GetConf(ctx context.Context, id uint) (NotificationConfDTO, error)
	CreateConf(ctx context.Context, req CreateConfReq) (NotificationConfDTO, error)
	UpdateConf(ctx context.Context, id uint, req UpdateConfReq) error
	DeleteConf(ctx context.Context, id uint) error
	TestConf(ctx context.Context, id uint) error
	Push(ctx context.Context, n Notification) error
	PushSync(ctx context.Context, n Notification) error
	Enqueue(ctx context.Context, n Notification, confID uint) error
}

NotificationService 管理通知通道配置与消息投递。

func NewNotificationService

func NewNotificationService(db *gorm.DB, manager NotifyManager, pushTimeout time.Duration) NotificationService

NewNotificationService 构造一个 NotificationService。pushTimeout 为同步投递的最长等待时间, 超时后会落到 notification_outbox 表由后台 worker 异步重试。

type NotificationServiceForRSS

type NotificationServiceForRSS interface {
	Push(ctx context.Context, n Notification) error
}

type NotifyManager

type NotifyManager interface {
	Send(ctx context.Context, confID uint, n Notification) error
}

NotifyManager 抽象底层投递。 TODO(T15): 替换为 internal/notify.Manager 接口的真实实现。

type QuietLookupFunc

type QuietLookupFunc func(confID uint) (start, end string, err error)

QuietLookupFunc 返回指定 NotificationConf 的 quiet_hours_start / quiet_hours_end。 用于在 tryDispatch 中按通道判断是否处于静默窗口。

type RSSCallbackActions

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

RSSCallbackActions resolves Telegram inline-button callbacks (dl/ig) against the rss_notification_log row referenced by the button payload.

func NewRSSCallbackActions

func NewRSSCallbackActions(db *gorm.DB, fetcher TorrentDataFetcher) *RSSCallbackActions

NewRSSCallbackActions wires the dependencies needed by Telegram's CallbackActionHandler. fetcher may be nil; OnRSSDownload will then short-circuit with an explanatory error so callers see the wiring gap.

func (*RSSCallbackActions) OnRSSDownload

func (a *RSSCallbackActions) OnRSSDownload(ctx context.Context, logID uint, userID int64) error

OnRSSDownload looks up the torrent referenced by logID and pushes it via the existing internal.PushTorrentToDownloader path. The downloader is resolved from RSSSubscription.DownloaderID; when nil, the default downloader is used. last_error is cleared on success and populated on failure so the row in /chatops/rss-notifications reflects reality.

func (*RSSCallbackActions) OnRSSIgnore

func (a *RSSCallbackActions) OnRSSIgnore(ctx context.Context, logID uint, userID int64) error

OnRSSIgnore marks the underlying log row as suppressed. It is idempotent and safe to call against a row that is already in any terminal state.

type RSSFilteredEvent

type RSSFilteredEvent struct {
	RSS       *models.RSSConfig
	Torrent   *v2.TorrentItem
	Rule      *models.FilterRule
	SiteName  string
	TorrentID string
}

type RSSItemEvent

type RSSItemEvent struct {
	RSS       *models.RSSConfig
	FeedItem  *gofeed.Item
	SiteName  string
	TorrentID string
}

type RSSNotifier

type RSSNotifier interface {
	NotifyNewItem(ctx context.Context, ev RSSItemEvent) error
	NotifyFilteredItem(ctx context.Context, ev RSSFilteredEvent) error
}

func NewRSSNotifier

func NewRSSNotifier(db *gorm.DB, notifySvc NotificationServiceForRSS) RSSNotifier

type RSSRetryWorker

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

RSSRetryWorker 周期性扫描 rss_notification_log 中 result='pending' 且 next_retry_at <= now 的行,复用 payload_json 重新尝试投递;连续失败超过 rssRetryMaxAttempts 后标记 'failed'。

func NewRSSRetryWorker

func NewRSSRetryWorker(db *gorm.DB, notifySvc NotificationServiceForRSS) *RSSRetryWorker

func (*RSSRetryWorker) Run

func (w *RSSRetryWorker) Run(ctx context.Context)

Run 阻塞直到 ctx 取消,应作为 goroutine 启动。

type SiteLister

type SiteLister interface {
	ListSites() (map[models.SiteGroup]models.SiteConfig, error)
}

SiteLister 是 ConfigStore 的最小读视图(便于测试 mock)。*core.ConfigStore 自动满足。

type SiteService

type SiteService interface {
	ListSites(ctx context.Context) ([]SiteSummaryDTO, error)
	GetSiteUserInfo(ctx context.Context, siteName string) (UserInfoDTO, error)
}

SiteService 为 chatops `/sites` `/userinfo` 等命令提供站点元数据与用户统计。

func NewSiteService

func NewSiteService(store *core.ConfigStore, users UserInfoSource) SiteService

NewSiteService 注入 *core.ConfigStore 与 v2.UserInfoRepo(典型为 *v2.DBUserInfoRepo)。 users 可为 nil,此时 GetSiteUserInfo 永远返回 ErrUserInfoUnavailable。

type SiteSummaryDTO

type SiteSummaryDTO struct {
	Name          string    `json:"name"`
	Enabled       bool      `json:"enabled"`
	LastScrapedAt time.Time `json:"last_scraped_at"`
	Status        string    `json:"status"`
}

SiteSummaryDTO 用于 chatops `/sites` 命令展示已配置的站点列表概览。

type TaskService

type TaskService interface {
	ListJobs(ctx context.Context) ([]JobStatusDTO, error)
	StartJob(ctx context.Context, siteName, rssName string) error
	StopJob(ctx context.Context, siteName, rssName string) error
}

TaskService 封装 scheduler.Manager 的 RSS 任务生命周期,剥离上层对底层 manager 的直接依赖。

func NewTaskService

func NewTaskService(mgr *scheduler.Manager) TaskService

NewTaskService 构造 TaskService,注入 *scheduler.Manager。

type TorrentDTO

type TorrentDTO struct {
	ID       string    `json:"id"`
	Name     string    `json:"name"`
	SiteName string    `json:"site_name"`
	State    string    `json:"state"`
	Size     int64     `json:"size"`
	Progress float64   `json:"progress"`
	Ratio    float64   `json:"ratio"`
	ETA      int64     `json:"eta"`
	AddedAt  time.Time `json:"added_at"`
}

type TorrentDataFetcher

type TorrentDataFetcher func(ctx context.Context, siteName, torrentID string) ([]byte, error)

TorrentDataFetcher fetches the raw .torrent payload for a (siteName, torrentID) pair. Callers wire in a closure backed by the v2 site registry so this package stays free of web / site/v2 imports.

type TorrentService

type TorrentService interface {
	ListByDownloader(ctx context.Context, downloaderName string, page, pageSize int) (items []TorrentDTO, total int, err error)
	Get(ctx context.Context, downloaderName, torrentID string) (TorrentDTO, error)
	Pause(ctx context.Context, downloaderName, torrentID string) error
	Resume(ctx context.Context, downloaderName, torrentID string) error
	Delete(ctx context.Context, downloaderName, torrentID string, removeData bool) error
}

func NewTorrentService

func NewTorrentService(mgr *downloader.DownloaderManager) TorrentService

type UpdateConfReq

type UpdateConfReq struct {
	ChannelType     *string
	Name            *string
	ConfigJSON      json.RawMessage
	Enabled         *bool
	QuietHoursStart *string
	QuietHoursEnd   *string
}

UpdateConfReq 更新请求,ConfigJSON 为空时不更新对应字段。

type UserInfoDTO

type UserInfoDTO struct {
	SiteName   string `json:"site_name"`
	Username   string `json:"username"`
	Uploaded   string `json:"uploaded"`
	Downloaded string `json:"downloaded"`
	Ratio      string `json:"ratio"`
	Bonus      string `json:"bonus"`
	Class      string `json:"class"`
}

UserInfoDTO 是站点用户信息的 chatops 友好快照(字段全部转字符串便于格式化展示)。

type UserInfoSource

type UserInfoSource interface {
	Get(ctx context.Context, site string) (v2.UserInfo, error)
}

UserInfoSource 抽象 site/v2 的 UserInfoRepo(实测使用 *v2.DBUserInfoRepo)。 仅暴露 chatops 必需的最小读取面,避免上层依赖 v2 全部 API。

Jump to

Keyboard shortcuts

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