Commit 9147792d authored by vicotor's avatar vicotor

add monitor

parent 4581f23b
......@@ -2,8 +2,10 @@ package acmanager
import (
"encoding/json"
"github.com/gofiber/fiber/v2/log"
"github.com/supabase-community/supabase-go"
"net/http"
"time"
)
type Account struct {
......@@ -17,81 +19,105 @@ type Account struct {
Available bool `json:"available"`
}
func (a Account) Stop() {
// todo: stop the account.
}
type Manager struct {
localUser map[string]Account
quit chan struct{}
client *supabase.Client
availableUser map[string]Account
userBlockedRecord map[string]time.Time
warningHistory []WarningRecord
}
func NewManager() *Manager {
return &Manager{
localUser: make(map[string]Account),
func NewManager(client *supabase.Client) *Manager {
m := &Manager{
quit: make(chan struct{}),
availableUser: make(map[string]Account),
warningHistory: make([]WarningRecord, 0),
client: client,
}
m.warningHistory = append(m.warningHistory, WarningRecord{
IsWarning: false,
Time: time.Now(),
})
return m
}
func (m *Manager) Init() error {
user, err := GetAllAccounts()
if err != nil {
return err
func (m *Manager) report(current int) {
if current < warningCount {
// check need to report.
last := m.warningHistory[len(m.warningHistory)-1]
// if last is not warning or last warning passed 5 minutes, send warning email.
if !last.IsWarning || (last.IsWarning && time.Now().After(last.Time.Add(time.Minute*5))) {
// send warning email.
if err := Warning(current); err != nil {
// log error.
log.Errorf("send warning email error: %s", err.Error())
} else {
m.warningHistory = append(m.warningHistory, WarningRecord{
IsWarning: true,
Time: time.Now(),
})
}
}
} else {
last := m.warningHistory[len(m.warningHistory)-1]
if last.IsWarning {
// send success email.
if err := Recovered(current); err != nil {
// log error.
log.Errorf("send success email error: %s", err.Error())
} else {
m.warningHistory = append(m.warningHistory, WarningRecord{
IsWarning: false,
Time: time.Now(),
})
}
}
}
for _, v := range user {
m.localUser[v.Username] = v
if len(m.warningHistory) > 10 {
old := m.warningHistory
m.warningHistory = make([]WarningRecord, 0)
m.warningHistory = append(m.warningHistory, old[len(old)-1])
}
return nil
}
func (m *Manager) AddUser(account Account) {
if account.Available {
m.addAvailable(account)
} else {
m.addInAvailable(account)
func (m *Manager) loop() {
// loop check available account count.
tc := time.NewTicker(time.Minute * 1)
defer tc.Stop()
for {
select {
case <-tc.C:
all, err := GetAllAccounts(m.client)
if err == nil {
available := make([]Account, 0)
unavailable := make([]Account, 0)
for _, v := range all {
if v.Available {
available = append(available, v)
} else {
unavailable = append(unavailable, v)
}
}
m.report(len(available))
}
tc.Reset(time.Minute * 3)
case <-m.quit:
return
}
}
}
func (m *Manager) addAvailable(account Account) {
// todo: add to available
func (m *Manager) Start() {
go m.loop()
}
func (m *Manager) addInAvailable(account Account) {
// todo: add to inavailable.
// do login to check if the account is available.
// if available, add to available.
//sc := twitterscraper.New()
func (m *Manager) Stop() {
close(m.quit)
}
func (m *Manager) UpdateUser() {
dbuser := make(map[string]Account)
accounts, err := GetAllAccounts()
if err != nil {
return
}
for _, v := range accounts {
dbuser[v.Username] = v
}
for k, v := range m.localUser {
if _, ok := dbuser[k]; !ok {
delete(m.localUser, k)
}
// delete the account, and stop the account.
v.Stop()
}
for k, v := range dbuser {
if _, ok := m.localUser[k]; !ok {
m.localUser[k] = v
}
}
}
func GetAllAccounts() ([]Account, error) {
// todo: get client from db.
var client *supabase.Client
func GetAllAccounts(client *supabase.Client) ([]Account, error) {
data, count, err := client.From("accounts").Select("*", "exact", false).Execute()
//data, count, err := client.From("accounts").Select("*", "exact", false).Eq("available", "true").Execute()
if err != nil {
return nil, err
}
......
package acmanager
import (
"fmt"
"gopkg.in/gomail.v2"
"os"
"strconv"
"strings"
"time"
)
const (
warningEmailTemplate = `
Hi there,
Current available account is %d, it is less than %d, please check it.
`
recoversEmailTemplate = `
Hi there,
Current available account is %d, warning cancelled.
`
warningCount = 5
ENV_ALERT_RECEIVERS = "TW_ALERT_RECEIVERS"
ENV_ALERT_EMAIL = "TW_ALERT_EMAIL"
ENV_EMAIL_SERVER = "TW_EMAIL_SERVER"
ENV_EMAIL_PORT = "TW_EMAIL_PORT"
ENV_EMAIL_USER = "TW_EMAIL_USER"
ENV_EMAIL_PASSWD = "TW_EMAIL_PASSWD"
)
type WarningRecord struct {
IsWarning bool
Time time.Time
}
type Environment struct {
AlertReceivers []string
AlertEmail string
EmailServer string
EmailPort int
EmailUser string
EmailPasswd string
}
func (e Environment) Available() bool {
if len(e.AlertReceivers) == 0 || e.AlertEmail == "" || e.EmailServer == "" || e.EmailPort == 0 || e.EmailUser == "" || e.EmailPasswd == "" {
return false
}
return true
}
func getEnv() Environment {
// get env from os.
env := Environment{}
if receiver, ok := os.LookupEnv(ENV_ALERT_RECEIVERS); ok {
rs := strings.Split(receiver, ",")
env.AlertReceivers = rs
}
if email, ok := os.LookupEnv(ENV_ALERT_EMAIL); ok {
env.AlertEmail = email
}
if server, ok := os.LookupEnv(ENV_EMAIL_SERVER); ok {
env.EmailServer = server
}
if port, ok := os.LookupEnv(ENV_EMAIL_PORT); ok {
env.EmailPort, _ = strconv.Atoi(port)
}
if user, ok := os.LookupEnv(ENV_EMAIL_USER); ok {
env.EmailUser = user
}
if passwd, ok := os.LookupEnv(ENV_EMAIL_PASSWD); ok {
env.EmailPasswd = passwd
}
return env
}
func Warning(count int) error {
// send email with warning template.
env := getEnv()
if env.Available() {
// send warning email.
msg := MsgInfo{
From: env.AlertEmail,
To: env.AlertReceivers,
Title: "New Warning",
Content: fmt.Sprintf(warningEmailTemplate, count, warningCount),
}
server := ServerInfo{
Server: env.EmailServer,
Port: env.EmailPort,
Username: env.EmailUser,
Passwd: env.EmailPasswd,
}
return sendMail(msg, server)
} else {
return fmt.Errorf("email env is not available")
}
}
func Recovered(count int) error {
// send email with warning template.
env := getEnv()
if env.Available() {
// send warning email.
msg := MsgInfo{
From: env.AlertEmail,
To: env.AlertReceivers,
Title: "Warning Cancelled",
Content: fmt.Sprintf(recoversEmailTemplate, count),
}
server := ServerInfo{
Server: env.EmailServer,
Port: env.EmailPort,
Username: env.EmailUser,
Passwd: env.EmailPasswd,
}
return sendMail(msg, server)
} else {
return fmt.Errorf("email env is not available")
}
}
type MsgInfo struct {
From string
To []string
Title string
Content string
}
type ServerInfo struct {
Server string
Port int
Username string
Passwd string
}
func sendMail(msg MsgInfo, server ServerInfo) error {
m := gomail.NewMessage()
m.SetHeader("From", msg.From)
m.SetHeader("To", msg.To...)
m.SetHeader("Subject", msg.Title)
m.SetBody("text/plain", msg.Content)
d := gomail.NewDialer(server.Server, server.Port, server.Username, server.Passwd)
return d.DialAndSend(m)
}
package acmanager
import "testing"
func TestWarning(t *testing.T) {
err := Warning(6)
if err != nil {
t.Fatal(err)
} else {
t.Log("TestWarning passed")
}
}
func TestRecovered(t *testing.T) {
err := Recovered(3)
if err != nil {
t.Fatal(err)
} else {
t.Log("TestRecovered passed")
}
}
......@@ -58,6 +58,8 @@ require (
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/tools v0.26.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
......
......@@ -261,11 +261,15 @@ golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
......
......@@ -15,6 +15,7 @@
package main
import (
"code.wuban.net.cn/odysseus/twitter_syncer/acmanager"
"fmt"
"github.com/gofiber/swagger"
"log/slog"
......@@ -49,6 +50,9 @@ func main() {
}
}()
manager := acmanager.NewManager(client)
manager.Start()
// taskIn = taskInStream
app := fiber.New()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment