Documentation
¶
Index ¶
- Variables
- type BrokerWithStatus
- type Job
- func (j *Job) Cancel()
- func (j *Job) Complete()
- func (j *Job) Context() context.Context
- func (j *Job) GetStatus() JobStatus
- func (j *Job) IsCancelled() bool
- func (j *Job) Pause(daySent int, errorMsg string)
- func (j *Job) RecordAuthFailure() bool
- func (j *Job) ResetAuthFailures()
- func (j *Job) SetDailyLimit(limit int)
- func (j *Job) StopWithError(errorType, errorMsg string)
- func (j *Job) ToJSON() map[string]interface{}
- func (j *Job) Update(sent, failed int, currentBroker, currentBrokerID string)
- type JobManager
- type JobPersistence
- type JobStatus
- type PersistentJobState
- type PipelineStats
- type RateLimiter
- type Server
- type Session
- type SessionStore
- type Stats
Constants ¶
This section is empty.
Variables ¶
var Version = "dev"
Version is the build version shown in the web UI footer. main sets it from its own -ldflags-injected version at startup; it stays "dev" otherwise.
Functions ¶
This section is empty.
Types ¶
type BrokerWithStatus ¶
type BrokerWithStatus struct {
broker.Broker
Status string // "never", "sent", "failed"
LastSent string // formatted date or empty
TotalSent int
Excluded bool // true if excluded via config.Options.ExcludedBrokers/ExcludedCategories
ManualMode bool // config.Options.send_mode == "manual" - row shows "Email" + "Mark sent" instead of "Send"
}
BrokerWithStatus combines broker info with history status
type Job ¶
type Job struct {
ID string `json:"id"`
ProfileID string `json:"profile_id"`
Status JobStatus `json:"status"`
Progress int `json:"progress"`
Sent int `json:"sent"`
Failed int `json:"failed"`
Total int `json:"total"`
CurrentBroker string `json:"current_broker"`
CurrentBrokerID string `json:"current_broker_id"`
StartedAt time.Time `json:"started_at"`
CompletedAt time.Time `json:"completed_at,omitempty"`
Error string `json:"error,omitempty"`
ErrorType string `json:"error_type,omitempty"` // "auth", "rate_limit", etc.
DailyLimit int `json:"daily_limit,omitempty"` // Max emails per day
DaySent int `json:"day_sent,omitempty"` // Emails sent today
// contains filtered or unexported fields
}
Job represents a background email sending job
func (*Job) GetStatus ¶
GetStatus returns the job's current status. Status is mutated under j.mu by Update/Complete/Cancel/StopWithError, so reading the field directly (as GetActive and Cleanup used to) is a data race - go through this.
func (*Job) IsCancelled ¶
IsCancelled returns true if the job was cancelled
func (*Job) Pause ¶
Pause marks the job paused (daily send limit reached) with the given day-sent count and message, all under one lock - processSendJob used to set these three fields directly, racing with any concurrent read (e.g. ToJSON on a status-polling request).
func (*Job) RecordAuthFailure ¶
RecordAuthFailure records an auth failure and returns true if job should stop
func (*Job) ResetAuthFailures ¶
func (j *Job) ResetAuthFailures()
ResetAuthFailures resets the consecutive auth failure counter
func (*Job) SetDailyLimit ¶
SetDailyLimit sets the job's daily send limit under lock.
func (*Job) StopWithError ¶
StopWithError stops the job due to an error
type JobManager ¶
type JobManager struct {
// contains filtered or unexported fields
}
JobManager manages background jobs
func NewJobManager ¶
func NewJobManager() *JobManager
NewJobManager creates a new job manager and starts its background cleanup loop, which evicts completed jobs older than jobRetention.
func (*JobManager) Cleanup ¶
func (jm *JobManager) Cleanup(maxAge time.Duration)
Cleanup removes completed jobs older than the specified duration
func (*JobManager) Create ¶
func (jm *JobManager) Create(total int, profileID string) *Job
Create creates a new job with the given total count, scoped to profileID
func (*JobManager) Get ¶
func (jm *JobManager) Get(id string) *Job
Get returns a job by ID, or nil if not found
func (*JobManager) GetActive ¶
func (jm *JobManager) GetActive(profileID string) *Job
GetActive returns the currently running job for the given profile, or nil if none. Scoped per-profile so switching profiles in the web UI doesn't report a false "job already running" - two profiles can send concurrently, each against its own daily limit and history.
type JobPersistence ¶
type JobPersistence struct {
// contains filtered or unexported fields
}
JobPersistence handles saving/loading job state
func NewJobPersistence ¶
func NewJobPersistence(dataDir string) *JobPersistence
NewJobPersistence creates a new job persistence handler
func (*JobPersistence) Clear ¶
func (jp *JobPersistence) Clear() error
Clear removes the saved job state
func (*JobPersistence) Load ¶
func (jp *JobPersistence) Load() (*PersistentJobState, error)
Load loads a pending job state from disk, returns nil if none exists
func (*JobPersistence) Save ¶
func (jp *JobPersistence) Save(state *PersistentJobState) error
Save saves the job state to disk
type PersistentJobState ¶
type PersistentJobState struct {
ID string `json:"id"`
ProfileID string `json:"profile_id"`
Status JobStatus `json:"status"`
Sent int `json:"sent"`
Failed int `json:"failed"`
Total int `json:"total"`
StartedAt time.Time `json:"started_at"`
RemainingBrokers []string `json:"remaining_brokers"` // Broker IDs still to process
Search string `json:"search"` // Original filter params
Category string `json:"category"`
Region string `json:"region"`
StatusFilter string `json:"status_filter"`
}
PersistentJobState represents a job that can be saved/loaded from disk
type PipelineStats ¶
type PipelineStats struct {
EmailSent int
AwaitingResponse int
FormRequired int
FormFilled int
AwaitingCaptcha int
CaptchaSolved int
AwaitingConfirmation int
Confirmed int
Rejected int
Failed int
PendingTasks int
NeedsReview int
}
PipelineStats holds stats for the pipeline dashboard
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
func NewRateLimiter ¶
func NewRateLimiter(limit int, window time.Duration) *RateLimiter
func (*RateLimiter) Allow ¶
func (rl *RateLimiter) Allow(key string) bool
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
type Session ¶
type Session struct {
ID string
Step string
Profile config.Profile
Email config.Email
ManualSend bool // user chose to send removal emails by hand - no SMTP
CreatedAt time.Time
ExpiresAt time.Time
}
Session holds wizard state securely on the server
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore manages secure server-side sessions Credentials are never sent to the client - only an opaque session ID
func NewSessionStore ¶
func NewSessionStore(ttl time.Duration) *SessionStore
NewSessionStore creates a new session store with automatic cleanup
func (*SessionStore) Create ¶
func (s *SessionStore) Create() (string, error)
Create creates a new session and returns its ID
func (*SessionStore) Get ¶
func (s *SessionStore) Get(id string) *Session
Get retrieves a session by ID, returns nil if not found or expired