|
|
|
package main
|
|
|
|
|
|
|
|
import "time"
|
|
|
|
|
|
|
|
// clearEmails removes stored emails for users which no longer exist.
|
|
|
|
// meant to be called with other such housekeeping functions, so assumes
|
|
|
|
// the user cache is fresh.
|
|
|
|
func (app *appContext) clearEmails() {
|
|
|
|
app.debug.Println("Housekeeping: removing unused email addresses")
|
|
|
|
users, status, err := app.jf.GetUsers(false)
|
|
|
|
if status != 200 || err != nil || len(users) == 0 {
|
|
|
|
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Rebuild email storage to from existing users to reduce time complexity
|
|
|
|
emails := emailStore{}
|
|
|
|
app.storage.emailsLock.Lock()
|
|
|
|
for _, user := range users {
|
|
|
|
if email, ok := app.storage.GetEmailsKey(user.ID); ok {
|
|
|
|
emails[user.ID] = email
|
|
|
|
}
|
|
|
|
}
|
|
|
|
app.storage.emails = emails
|
|
|
|
app.storage.storeEmails()
|
|
|
|
app.storage.emailsLock.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// clearDiscord does the same as clearEmails, but for Discord Users.
|
|
|
|
func (app *appContext) clearDiscord() {
|
|
|
|
app.debug.Println("Housekeeping: removing unused Discord IDs")
|
|
|
|
users, status, err := app.jf.GetUsers(false)
|
|
|
|
if status != 200 || err != nil || len(users) == 0 {
|
|
|
|
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Rebuild discord storage to from existing users to reduce time complexity
|
|
|
|
dcUsers := discordStore{}
|
|
|
|
app.storage.discordLock.Lock()
|
|
|
|
for _, user := range users {
|
|
|
|
if dcUser, ok := app.storage.GetDiscordKey(user.ID); ok {
|
|
|
|
dcUsers[user.ID] = dcUser
|
|
|
|
}
|
|
|
|
}
|
|
|
|
app.storage.discord = dcUsers
|
|
|
|
app.storage.storeDiscordUsers()
|
|
|
|
app.storage.discordLock.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// clearMatrix does the same as clearEmails, but for Matrix Users.
|
|
|
|
func (app *appContext) clearMatrix() {
|
|
|
|
app.debug.Println("Housekeeping: removing unused Matrix IDs")
|
|
|
|
users, status, err := app.jf.GetUsers(false)
|
|
|
|
if status != 200 || err != nil || len(users) == 0 {
|
|
|
|
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Rebuild matrix storage to from existing users to reduce time complexity
|
|
|
|
mxUsers := matrixStore{}
|
|
|
|
app.storage.matrixLock.Lock()
|
|
|
|
for _, user := range users {
|
|
|
|
if mxUser, ok := app.storage.GetMatrixKey(user.ID); ok {
|
|
|
|
mxUsers[user.ID] = mxUser
|
|
|
|
}
|
|
|
|
}
|
|
|
|
app.storage.matrix = mxUsers
|
|
|
|
app.storage.storeMatrixUsers()
|
|
|
|
app.storage.matrixLock.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// clearTelegram does the same as clearEmails, but for Telegram Users.
|
|
|
|
func (app *appContext) clearTelegram() {
|
|
|
|
app.debug.Println("Housekeeping: removing unused Telegram IDs")
|
|
|
|
users, status, err := app.jf.GetUsers(false)
|
|
|
|
if status != 200 || err != nil || len(users) == 0 {
|
|
|
|
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Rebuild telegram storage to from existing users to reduce time complexity
|
|
|
|
tgUsers := telegramStore{}
|
|
|
|
app.storage.telegramLock.Lock()
|
|
|
|
for _, user := range users {
|
|
|
|
if tgUser, ok := app.storage.GetTelegramKey(user.ID); ok {
|
|
|
|
tgUsers[user.ID] = tgUser
|
|
|
|
}
|
|
|
|
}
|
|
|
|
app.storage.telegram = tgUsers
|
|
|
|
app.storage.storeTelegramUsers()
|
|
|
|
app.storage.telegramLock.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://bbengfort.github.io/snippets/2016/06/26/background-work-goroutines-timer.html THANKS
|
|
|
|
|
|
|
|
type housekeepingDaemon struct {
|
|
|
|
Stopped bool
|
|
|
|
ShutdownChannel chan string
|
|
|
|
Interval time.Duration
|
|
|
|
period time.Duration
|
|
|
|
jobs []func(app *appContext)
|
|
|
|
app *appContext
|
|
|
|
}
|
|
|
|
|
|
|
|
func newInviteDaemon(interval time.Duration, app *appContext) *housekeepingDaemon {
|
|
|
|
daemon := housekeepingDaemon{
|
|
|
|
Stopped: false,
|
|
|
|
ShutdownChannel: make(chan string),
|
|
|
|
Interval: interval,
|
|
|
|
period: interval,
|
|
|
|
app: app,
|
|
|
|
}
|
|
|
|
daemon.jobs = []func(app *appContext){func(app *appContext) {
|
|
|
|
app.debug.Println("Housekeeping: Checking for expired invites")
|
|
|
|
app.checkInvites()
|
|
|
|
}}
|
|
|
|
|
|
|
|
clearEmail := app.config.Section("email").Key("require_unique").MustBool(false)
|
|
|
|
clearDiscord := app.config.Section("discord").Key("require_unique").MustBool(false)
|
|
|
|
clearTelegram := app.config.Section("telegram").Key("require_unique").MustBool(false)
|
|
|
|
clearMatrix := app.config.Section("matrix").Key("require_unique").MustBool(false)
|
|
|
|
|
|
|
|
if clearEmail || clearDiscord || clearTelegram || clearMatrix {
|
|
|
|
daemon.jobs = append(daemon.jobs, func(app *appContext) { app.jf.CacheExpiry = time.Now() })
|
|
|
|
}
|
|
|
|
|
|
|
|
if clearEmail {
|
|
|
|
daemon.jobs = append(daemon.jobs, func(app *appContext) { app.clearEmails() })
|
|
|
|
}
|
|
|
|
if clearDiscord {
|
|
|
|
daemon.jobs = append(daemon.jobs, func(app *appContext) { app.clearDiscord() })
|
|
|
|
}
|
|
|
|
if clearTelegram {
|
|
|
|
daemon.jobs = append(daemon.jobs, func(app *appContext) { app.clearTelegram() })
|
|
|
|
}
|
|
|
|
if clearMatrix {
|
|
|
|
daemon.jobs = append(daemon.jobs, func(app *appContext) { app.clearMatrix() })
|
|
|
|
}
|
|
|
|
|
|
|
|
return &daemon
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rt *housekeepingDaemon) run() {
|
|
|
|
rt.app.info.Println("Invite daemon started")
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-rt.ShutdownChannel:
|
|
|
|
rt.ShutdownChannel <- "Down"
|
|
|
|
return
|
|
|
|
case <-time.After(rt.period):
|
|
|
|
break
|
|
|
|
}
|
|
|
|
started := time.Now()
|
|
|
|
rt.app.storage.loadInvites()
|
|
|
|
|
|
|
|
for _, job := range rt.jobs {
|
|
|
|
job(rt.app)
|
|
|
|
}
|
|
|
|
|
|
|
|
finished := time.Now()
|
|
|
|
duration := finished.Sub(started)
|
|
|
|
rt.period = rt.Interval - duration
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rt *housekeepingDaemon) Shutdown() {
|
|
|
|
rt.Stopped = true
|
|
|
|
rt.ShutdownChannel <- "Down"
|
|
|
|
<-rt.ShutdownChannel
|
|
|
|
close(rt.ShutdownChannel)
|
|
|
|
}
|