| -rw-r--r-- | config/config.local.yaml | 3 | ||||
| -rw-r--r-- | config/config.prod.yaml | 2 | ||||
| -rw-r--r-- | config/config.stage.yaml | 2 | ||||
| -rw-r--r-- | internal/blogtrigger/blogtrigger.go | 4 | ||||
| -rw-r--r-- | internal/mailer/mailer.go | 53 | ||||
| -rw-r--r-- | internal/router/client-cache.go | 12 | ||||
| -rw-r--r-- | internal/router/lang-user-unsubscribe.go | 4 | ||||
| -rw-r--r-- | main.go | 3 |
8 files changed, 67 insertions, 16 deletions
diff --git a/config/config.local.yaml b/config/config.local.yaml index d40e8e9..e23c808 100644 --- a/config/config.local.yaml +++ b/config/config.local.yaml @@ -32,7 +32,8 @@ auth: db: type: sqlite3 config: - dsn: 'file:/tmp/auth.db?cache=shared&mode=rwc' + # dsn: 'file:/tmp/auth.db?cache=shared&mode=rwc&_journal_mode=WAL' + dsn: 'file:/tmp/auth.db?cache=private&mode=rwc&_locking_mode=EXCLUSIVE&_mutex=no&_auto_vacuum=2&_journal_mode=WAL' salt: '123' mail: clientHost: '127.0.0.1:3000' diff --git a/config/config.prod.yaml b/config/config.prod.yaml index 7a9e5ae..0bee79d 100644 --- a/config/config.prod.yaml +++ b/config/config.prod.yaml @@ -32,7 +32,7 @@ auth: db: type: sqlite3 config: - dsn: 'file:/data/auth.db?cache=private&mode=rwc&_locking_mode=EXCLUSIVE&_mutex=no&_auto_vacuum=2' + dsn: 'file:/data/auth.db?cache=private&mode=rwc&_locking_mode=EXCLUSIVE&_mutex=no&_auto_vacuum=2&_journal_mode=WAL' salt: '${AUTH_SALT}' mail: clientHost: '${FQDN}' diff --git a/config/config.stage.yaml b/config/config.stage.yaml index 8a5fde1..1c15dae 100644 --- a/config/config.stage.yaml +++ b/config/config.stage.yaml @@ -32,7 +32,7 @@ auth: db: type: sqlite3 config: - dsn: 'file:/data/auth.db?cache=private&mode=rwc&_locking_mode=EXCLUSIVE&_mutex=no&_auto_vacuum=2' + dsn: 'file:/data/auth.db?cache=private&mode=rwc&_locking_mode=EXCLUSIVE&_mutex=no&_auto_vacuum=2&_journal_mode=WAL' salt: '${AUTH_SALT}' mail: clientHost: '${FQDN}' diff --git a/internal/blogtrigger/blogtrigger.go b/internal/blogtrigger/blogtrigger.go index 9b016e8..c5b3097 100644 --- a/internal/blogtrigger/blogtrigger.go +++ b/internal/blogtrigger/blogtrigger.go @@ -49,6 +49,10 @@ func NewBlogTriggerScheduler(b2Client *b2.B2Client, availableLanguages []config. return bts, nil } +func (bts *BlogTriggerScheduler) Close() error { + return bts.s.Shutdown() +} + func (bts *BlogTriggerScheduler) scan() (newPages []*b2.BlogPage, err error) { newPages = make([]*b2.BlogPage, 0) for lang := range bts.knownBlogPages { diff --git a/internal/mailer/mailer.go b/internal/mailer/mailer.go index eb86d56..d6dbd17 100644 --- a/internal/mailer/mailer.go +++ b/internal/mailer/mailer.go @@ -151,15 +151,19 @@ func (m *Mailer) MailIsTaken(email string) (bool, error) { if err != nil { return false, fmt.Errorf("failed to initialize transaction with db: %s", err) } + + slog.Debug("began db transaction", slog.String("method", "MailIsTaken")) defer func(tx *sql.Tx) { if err = tx.Commit(); err != nil { tx.Rollback() } + slog.Debug("ended db transaction", slog.String("method", "MailIsTaken")) }(tx) var rows *sql.Rows if rows, err = tx.Query(`SELECT email FROM user_email_table WHERE email=? LIMIT 1;`, email); err != nil { tx.Rollback() + return false, fmt.Errorf("failed to query user-email settings in db: %s", err) } defer rows.Close() @@ -173,10 +177,13 @@ func (m *Mailer) GetInfo(userIdHash []byte) (email string, lang string, err erro if err != nil { return "", "", fmt.Errorf("failed to initialize transaction with db: %s", err) } + + slog.Debug("began db transaction", slog.String("method", "GetInfo")) defer func(tx *sql.Tx) { if err = tx.Commit(); err != nil { tx.Rollback() } + slog.Debug("ended db transaction", slog.String("method", "GetInfo")) }(tx) var rows *sql.Rows @@ -310,18 +317,22 @@ func (m *Mailer) Verify(verificationCodeEncoded string, lang string) error { return fmt.Errorf("failed to initialize transaction with db: %s", err) } + slog.Debug("began db transaction", slog.String("method", "Verify")) if _, err = tx.Exec(`INSERT INTO user_email_table(user_id, email, lang) VALUES(?, ?, ?) ON CONFLICT(user_id) DO UPDATE SET email=excluded.email, lang=excluded.lang;`, m.GetHash(string(userId)), address, lang); err != nil { tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "Verify")) return fmt.Errorf("failed to configure user-email settings in db: %s", err) } if err = tx.Commit(); err != nil { tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "Verify")) return fmt.Errorf("failed to commit transaction to db: %s", err) } + slog.Debug("ended db transaction", slog.String("method", "Verify")) m.verificationCodes.Del(verificationCode) delete(m.lostMailMap, verificationSegments[0]) @@ -333,10 +344,13 @@ func (m *Mailer) GetSubscriptions(userId string) (subscriptionType SubscriptionT if err != nil { return None, nil, fmt.Errorf("failed to initialize transaction with db: %s", err) } + + slog.Debug("began db transaction", slog.String("method", "GetSubscriptions")) defer func(tx *sql.Tx) { if err = tx.Commit(); err != nil { tx.Rollback() } + slog.Debug("ended db transaction", slog.String("method", "GetSubscriptions")) }(tx) hash := m.GetHash(userId) @@ -373,6 +387,8 @@ func (m *Mailer) Subscribe(userIdHash []byte, subscriptionType SubscriptionType, return fmt.Errorf("failed to initialize transaction with db: %s", err) } + slog.Debug("began db transaction", slog.String("method", "Subscribe")) + slices.Sort(tags) tagsOutput := "" switch subscriptionType { @@ -388,13 +404,16 @@ func (m *Mailer) Subscribe(userIdHash []byte, subscriptionType SubscriptionType, ON CONFLICT(user_id) DO UPDATE SET tags=excluded.tags;`, userIdHash, tagsOutput); err != nil { tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "Subscribe")) return fmt.Errorf("failed to configure user-to-tags table in db for the user: %s", err) } if err = tx.Commit(); err != nil { tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "Subscribe")) return fmt.Errorf("failed to commit transaction to db: %s", err) } + slog.Debug("ended db transaction", slog.String("method", "Subscribe")) return nil } @@ -405,9 +424,11 @@ func (m *Mailer) NewPost(post *b2.BlogPage) error { return fmt.Errorf("failed to initialize transaction with db: %s", err) } + slog.Debug("began db transaction", slog.String("method", "NewPost")) var rows *sql.Rows if rows, err = tx.Query(`SELECT user_id, tags FROM subscription_user_to_tags_table;`); err != nil { tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "NewPost")) return fmt.Errorf("failed to query user-to-tags table in db: %s", err) } @@ -431,21 +452,11 @@ rowLoop: continue } - email, lang, err := m.GetInfo(userId) - if err != nil { - slog.Warn("failed to get info about the user", slog.String("error", err.Error()), slog.Int("index", i), slog.String("user_id", base64.RawStdEncoding.EncodeToString(userId))) - continue - } - - if lang != post.Lang { - continue - } - if tagsString == "_all" { usersToSend = append(usersToSend, struct { userId []byte email string - }{userId, email}) + }{userId, ""}) continue } @@ -455,7 +466,7 @@ rowLoop: usersToSend = append(usersToSend, struct { userId []byte email string - }{userId, email}) + }{userId, ""}) continue rowLoop } } @@ -463,9 +474,27 @@ rowLoop: tx.Commit() rows.Close() + slog.Debug("ended db transaction", slog.String("method", "NewPost")) + + for i := range usersToSend { + email, lang, err := m.GetInfo(usersToSend[i].userId) + if err != nil { + slog.Warn("failed to get info about the user", slog.String("error", err.Error()), slog.Int("index", i), slog.String("user_id", base64.RawStdEncoding.EncodeToString(userId))) + continue + } + + if lang != post.Lang { + continue + } + + usersToSend[i].email = email + } messages := make([]*mail.Msg, 0, len(usersToSend)) for _, user := range usersToSend { + if user.email == "" { + continue + } unsubscribeCodeBytes := make([]byte, 8) rand.Read(unsubscribeCodeBytes) unsubscribeCode := binary.LittleEndian.Uint64(unsubscribeCodeBytes) diff --git a/internal/router/client-cache.go b/internal/router/client-cache.go index 26557d0..e7cda30 100644 --- a/internal/router/client-cache.go +++ b/internal/router/client-cache.go @@ -31,10 +31,12 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) { if err != nil { return nil, fmt.Errorf("fail to init transaction with db to fill cache: %w", err) } + slog.Debug("began db transaction", slog.String("method", "NewClientCache")) rows, err := tx.Query("select * from blog_likes;") if err != nil { tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "NewClientCache")) return nil, fmt.Errorf("fail to query db for blog_likes to fill cache: %w", err) } @@ -62,6 +64,7 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) { rows, err = tx.Query("select * from blog_views;") if err != nil { tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "NewClientCache")) return nil, fmt.Errorf("fail to query db for blog_views to fill cache: %w", err) } @@ -81,8 +84,11 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) { } if err = tx.Commit(); err != nil { + tx.Rollback() + slog.Debug("ended db transaction", slog.String("method", "NewClientCache")) return nil, fmt.Errorf("fail to commit transaction in db: %w", err) } + slog.Debug("ended db transaction", slog.String("method", "NewClientCache")) return &ClientCache{ hashMap: make(map[string]string), @@ -99,21 +105,27 @@ func (c *ClientCache) Close() error { if err != nil { return fmt.Errorf("fail to init transaction with db to dump cache: %w", err) } + slog.Debug("began db transaction in ClientCache.Close") if err = batchSave(tx, "blog_likes", c.likePageMap); err != nil { tx.Rollback() + slog.Debug("ended db transaction in ClientCache.Close") return fmt.Errorf("fail to save blog_likes: %s", err) } if err = batchSave(tx, "blog_views", c.viewPageMap); err != nil { tx.Rollback() + slog.Debug("ended db transaction in ClientCache.Close") return fmt.Errorf("fail to save blog_views: %s", err) } if err = tx.Commit(); err != nil { tx.Rollback() + slog.Debug("ended db transaction in ClientCache.Close") return fmt.Errorf("fail to commit all the changes related to cache: %s", err) } + + slog.Debug("ended db transaction in ClientCache.Close") return nil } diff --git a/internal/router/lang-user-unsubscribe.go b/internal/router/lang-user-unsubscribe.go index a6ca89f..c39f5e7 100644 --- a/internal/router/lang-user-unsubscribe.go +++ b/internal/router/lang-user-unsubscribe.go @@ -35,17 +35,19 @@ func Lang_User_Unsubscribe(l map[string]*locale.LocaleConfig, langs []config.Ava statusText = l[lang].UnsubscribePage.UnsetCode status = fiber.ErrBadRequest.Code } else if clientError, serverError := Mailer.Unsubscribe(unsubscribeCode); clientError != nil { + slog.Info("got a client error when unsubscribing", slog.String("error", clientError.Error())) statusColor = "255, 0, 0" statusEmoji = "(͠≖~≖ ͡ )" statusText = l[lang].UnsubscribePage.InvalidCode status = fiber.ErrBadRequest.Code } else if serverError != nil { + slog.Error("got a server error when unsubscribing", slog.String("error", serverError.Error())) statusColor = "255, 128, 0" statusEmoji = "( ˶°ㅁ°) !!" statusText = l[lang].UnsubscribePage.OnServerError status = fiber.ErrInternalServerError.Code } else { - statusColor = "0, 255, 0," + statusColor = "0, 255, 0" statusEmoji = "♡⸜(˶˃ ᵕ ˂˶)⸝♡" statusText = l[lang].UnsubscribePage.Success status = fiber.StatusOK @@ -202,6 +202,9 @@ func main() { <-sigChan slog.Info("gracefully shutting down...") + if err = router.BlogTrigger.Close(); err != nil { + slog.Error("fail to shutdown blog trigger scheduler", slog.String("error", err.Error())) + } if err = app.Shutdown(); err != nil { slog.Error("fail to shutdown fiber server", slog.String("error", err.Error())) } |