133 lines
2.8 KiB
Go
133 lines
2.8 KiB
Go
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
|
|
}
|