mailer/delay/delay.go

134 lines
2.8 KiB
Go
Raw Permalink Normal View History

2025-01-12 13:03:17 +00:00
package delay
import (
"errors"
"fmt"
"sync/atomic"
"time"
)
var GLOBAL_MAILCOUNT *mailqueue
type mailer struct {
subject string
to string
body string
}
// probably easier to do this as sqlite storage selections
type mailqueue struct {
dirty atomic.Bool
size int
instant chan mailer // priority zero
reminder chan mailer // priority one
maintenance chan mailer // priority two
marketing chan mailer // priority 3
errors int
maxerrors int
}
func init() {
var err error
GLOBAL_MAILCOUNT, err = NewMailqueue(100, 60, 90, 5)
if err != nil {
fmt.Println(err)
}
}
func NewMailqueue(size int, resetseconds int, sendseconds int, maxerrors int) (*mailqueue, error) {
m := mailqueue{
size: size,
instant: make(chan mailer, size),
reminder: make(chan mailer, size),
maintenance: make(chan mailer, size),
marketing: make(chan mailer, size),
maxerrors: maxerrors,
}
if resetseconds < 60 {
return nil, errors.New("too small of a value")
}
if sendseconds < 90 {
return nil, errors.New("too large of a value")
}
go m.BucketDrip(resetseconds)
go m.BackgroundMail(sendseconds)
return &m, nil
}
func (m *mailqueue) BucketDrip(resetseconds int) {
// every 60 seconds
for range time.Tick(time.Second * time.Duration(resetseconds)) {
m.dirty.Store(false)
}
}
func (m *mailqueue) BackgroundMail(sendseconds int) {
// every 90 seconds (.75*60*24, 1080)
for range time.Tick(time.Second * time.Duration(sendseconds)) {
if m.errors > m.maxerrors {
fmt.Println("too many errors, not sending.")
return
}
var err error
if m.dirty.Load() != true {
select {
case e := <-m.maintenance:
m.dirty.Store(true)
err = Send(e)
default:
select {
case e := <-m.maintenance:
m.dirty.Store(true)
err = Send(e)
case e := <-m.reminder:
m.dirty.Store(true)
err = Send(e)
default:
select {
case e := <-m.maintenance:
m.dirty.Store(true)
err = Send(e)
case e := <-m.reminder:
m.dirty.Store(true)
err = Send(e)
case e := <-m.marketing:
m.dirty.Store(true)
err = Send(e)
default:
fmt.Println("queue empty")
}
}
}
}
if err != nil {
// add to failed queue? store as failed?
m.errors += 1
}
err = nil
}
}
func (m *mailqueue) AddSend(mail mailer, queue string) error {
var target chan mailer
switch queue {
case "maintenance":
target = m.maintenance
case "reminder":
target = m.reminder
case "marketing":
target = m.marketing
default:
return errors.New("no valid queue")
}
if m.size-1 < len(target) {
return errors.New("mail queue full!")
}
select {
case target <- mail:
default:
return errors.New("mail queue full!")
}
return nil
}
func Send(m mailer) error {
fmt.Println(m.to, m.subject, m.body)
return nil
}