add notification cleaning

This commit is contained in:
fade 2022-09-08 08:26:25 -04:00
parent 30b7fddf18
commit 8c6e023e51
9 changed files with 192 additions and 82 deletions

View File

@ -17,16 +17,18 @@ This is a bot which implements group functionality in Mastodon.
The bot is configured in a JSON file that looks like this: The bot is configured in a JSON file that looks like this:
``` ```
{ {
"Server": "https://example.com", "Server": "https://example.com",
"ClientID": "0000000000000000000000000000000000000000000", "ClientID": "0000000000000000000000000000000000000000000",
"ClientSecret": "0000000000000000000000000000000000000000000", "ClientSecret": "0000000000000000000000000000000000000000000",
"AccessToken": "0000000000000000000000000000000000000000000", "AccessToken": "0000000000000000000000000000000000000000000",
"WelcomeMessage": "We have a new member in our group. Please love and favor" "WelcomeMessage": "We have a new member in our group. Please love and favor",
"Max_toots": 2, "NotFollowedMessage": "you are not followed",
"Toots_interval": 12, "Max_toots": 2,
"Duplicate_buf": 10, "Toots_interval": 12,
"Order_limit": 1, "Duplicate_buf": 10,
"Admins": ["admin@example.com"] "Order_limit": 1,
"Del_notices_interval": 30,
"Admins": ["admin@example.com"]
} }
``` ```

63
bot.go
View File

@ -10,26 +10,25 @@ import (
"github.com/mattn/go-mastodon" "github.com/mattn/go-mastodon"
) )
func RunBot() { var (
logger_init() c = mastodon.NewClient(&mastodon.Config{
c := mastodon.NewClient(&mastodon.Config{
Server: Conf.Server, Server: Conf.Server,
ClientID: Conf.ClientID, ClientID: Conf.ClientID,
ClientSecret: Conf.ClientSecret, ClientSecret: Conf.ClientSecret,
AccessToken: Conf.AccessToken, AccessToken: Conf.AccessToken,
}) })
ctx := context.Background() ctx = context.Background()
my_account, _ = c.GetAccountCurrentUser(ctx)
)
func RunBot() {
events, err := c.StreamingUser(ctx) events, err := c.StreamingUser(ctx)
if err != nil { if err != nil {
ErrorLogger.Println("Streaming") ErrorLogger.Println("Streaming")
} }
my_account, err := c.GetAccountCurrentUser(ctx)
if err != nil {
ErrorLogger.Println("Fetch account info")
}
followers, err := c.GetAccountFollowers(ctx, my_account.ID, &mastodon.Pagination{Limit: 60}) followers, err := c.GetAccountFollowers(ctx, my_account.ID, &mastodon.Pagination{Limit: 60})
if err != nil { if err != nil {
ErrorLogger.Println("Fetch followers") ErrorLogger.Println("Fetch followers")
@ -43,28 +42,30 @@ func RunBot() {
} }
notif := notifEvent.Notification notif := notifEvent.Notification
ntype := notif.Type
acct := notif.Status.Account.Acct
content := notif.Status.Content
tooturl := notif.Status.URL
// Posting function /*postToot := func(toot string, vis string) (*mastodon.Status, error) {
postToot := func(toot string, vis string) error {
conToot := mastodon.Toot{ conToot := mastodon.Toot{
Status: toot, Status: toot,
Visibility: vis, Visibility: vis,
} }
_, err := c.PostStatus(ctx, &conToot) status, err := c.PostStatus(ctx, &conToot)
return err return status, err
} }*/
// New follower // New follower
if notif.Type == "follow" { if ntype == "follow" {
acct := notif.Account.Acct if !exist_in_database(acct) { // Add to db and post welcome message
if !followed(acct) { // Add to db and post welcome message
InfoLogger.Printf("%s followed", acct) InfoLogger.Printf("%s followed", acct)
add_to_db(acct) add_to_db(acct)
InfoLogger.Printf("%s added to database", acct) InfoLogger.Printf("%s added to database", acct)
message := fmt.Sprintf("%s @%s", Conf.WelcomeMessage, acct) message := fmt.Sprintf("%s @%s", Conf.WelcomeMessage, acct)
err := postToot(message, "public") _, err := postToot(message, "public")
if err != nil { if err != nil {
ErrorLogger.Println("Post welcome message") ErrorLogger.Println("Post welcome message")
} }
@ -73,11 +74,7 @@ func RunBot() {
} }
// Read message // Read message
if notif.Type == "mention" { if ntype == "mention" {
acct := notif.Status.Account.Acct
content := notif.Status.Content
tooturl := notif.Status.URL
for i := 0; i < len(followers); i++ { for i := 0; i < len(followers); i++ {
if acct == string(followers[i].Acct) { // Follow check if acct == string(followers[i].Acct) { // Follow check
if notif.Status.Visibility == "public" { // Reblog toot if notif.Status.Visibility == "public" { // Reblog toot
@ -96,7 +93,7 @@ func RunBot() {
} }
// Add to db if needed // Add to db if needed
if !followed(acct) { if !exist_in_database(acct) {
add_to_db(acct) add_to_db(acct)
InfoLogger.Printf("%s added to database", acct) InfoLogger.Printf("%s added to database", acct)
} }
@ -148,6 +145,24 @@ func RunBot() {
break break
} }
} }
if i == len(followers)-1 { // Notify user
if got_notice(acct) == 0 {
if !exist_in_database(acct) {
add_to_db(acct)
InfoLogger.Printf("%s added to database", acct)
}
message := fmt.Sprintf("@%s %s", acct, Conf.NotFollowedMessage)
_, err := postToot(message, "direct")
if err != nil {
ErrorLogger.Printf("Notify %s", acct)
}
InfoLogger.Printf("%s has been notified", acct)
mark_notice(acct)
InfoLogger.Printf("%s marked notification in database", acct)
}
}
} }
} }
} }

36
cleaning.go Normal file
View File

@ -0,0 +1,36 @@
package main
import (
"sync"
"time"
"github.com/mattn/go-mastodon"
)
var (
wg sync.WaitGroup
)
// Delete notices
func DeleteNotices() {
wg.Done()
for {
statuses, err := c.GetAccountStatuses(ctx, my_account.ID, &mastodon.Pagination{Limit: 60})
if err != nil {
ErrorLogger.Println("Get account statuses")
}
time.Sleep(time.Duration(Conf.Del_notices_interval) * time.Second)
for i := range statuses {
if statuses[i].Visibility == "direct" {
c.DeleteStatus(ctx, statuses[i].ID)
}
}
InfoLogger.Println("Cleaning notices")
reset_notice_counter()
InfoLogger.Println("Reset notice counter")
}
}

View File

@ -16,16 +16,18 @@ var (
) )
type Config struct { type Config struct {
Server string `json:"Server"` Server string `json:"Server"`
ClientID string `json:"ClientID"` ClientID string `json:"ClientID"`
ClientSecret string `json:"ClientSecret"` ClientSecret string `json:"ClientSecret"`
AccessToken string `json:"AccessToken"` AccessToken string `json:"AccessToken"`
WelcomeMessage string `json:"WelcomeMessage"` WelcomeMessage string `json:"WelcomeMessage"`
Max_toots uint16 `json:"Max_toots"` NotFollowedMessage string `json:"NotFollowedMessage"`
Toots_interval uint16 `json:"Toots_interval"` Max_toots uint `json:"Max_toots"`
Duplicate_buf uint16 `json:"Duplicate_buf"` Toots_interval uint `json:"Toots_interval"`
Order_limit uint16 `json:"Order_limit"` Duplicate_buf uint `json:"Duplicate_buf"`
Admins []string `json:"Admins"` Order_limit uint `json:"Order_limit"`
Del_notices_interval uint `json:"Del_notices_interval"`
Admins []string `json:"Admins"`
} }
func ReadConfig() Config { func ReadConfig() Config {

View File

@ -1,12 +1,14 @@
{ {
"Server": "https://example.com", "Server": "https://example.com",
"ClientID": "0000000000000000000000000000000000000000000", "ClientID": "0000000000000000000000000000000000000000000",
"ClientSecret": "0000000000000000000000000000000000000000000", "ClientSecret": "0000000000000000000000000000000000000000000",
"AccessToken": "0000000000000000000000000000000000000000000", "AccessToken": "0000000000000000000000000000000000000000000",
"WelcomeMessage": "We have a new member in our group. Please love and favor", "WelcomeMessage": "We have a new member in our group. Please love and favor",
"Max_toots": 2, "NotFollowedMessage": "you are not followed",
"Toots_interval": 12, "Max_toots": 2,
"Duplicate_buf": 10, "Toots_interval": 12,
"Order_limit": 1, "Duplicate_buf": 10,
"Admins": ["admin@example.com"] "Order_limit": 1,
"Del_notices_interval": 30,
"Admins": ["admin@example.com"]
} }

View File

@ -9,6 +9,10 @@ import (
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
var (
db = init_limit_db()
)
// Init database // Init database
func init_limit_db() *sql.DB { func init_limit_db() *sql.DB {
db, err := sql.Open("sqlite3", *DBPath) db, err := sql.Open("sqlite3", *DBPath)
@ -16,7 +20,7 @@ func init_limit_db() *sql.DB {
ErrorLogger.Println("Open database") ErrorLogger.Println("Open database")
} }
cmd1 := `CREATE TABLE IF NOT EXISTS Limits (id INTEGER PRIMARY KEY AUTOINCREMENT, acct TEXT, ticket INTEGER, order_msg INTEGER, time TEXT)` cmd1 := `CREATE TABLE IF NOT EXISTS Limits (id INTEGER PRIMARY KEY AUTOINCREMENT, acct TEXT, ticket INTEGER, order_msg INTEGER, got_notice INTEGER, posted TEXT)`
cmd2 := `CREATE TABLE IF NOT EXISTS MsgHashs (message_hash TEXT)` cmd2 := `CREATE TABLE IF NOT EXISTS MsgHashs (message_hash TEXT)`
stat1, err := db.Prepare(cmd1) stat1, err := db.Prepare(cmd1)
@ -36,18 +40,16 @@ func init_limit_db() *sql.DB {
// Add account to database // Add account to database
func add_to_db(acct string) { func add_to_db(acct string) {
db := init_limit_db() cmd := `INSERT INTO Limits (acct, ticket, order_msg, got_notice) VALUES (?, ?, ?, ?)`
cmd := `INSERT INTO Limits (acct, ticket, order_msg) VALUES (?, ?, ?)`
stat, err := db.Prepare(cmd) stat, err := db.Prepare(cmd)
if err != nil { if err != nil {
ErrorLogger.Println("Add account to databse") ErrorLogger.Println("Add account to database")
} }
stat.Exec(acct, Conf.Max_toots, 0) stat.Exec(acct, Conf.Max_toots, 0, 0)
} }
// Check followed once // Check followed once
func followed(acct string) bool { func exist_in_database(acct string) bool {
db := init_limit_db()
cmd := `SELECT acct FROM Limits WHERE acct = ?` cmd := `SELECT acct FROM Limits WHERE acct = ?`
err := db.QueryRow(cmd, acct).Scan(&acct) err := db.QueryRow(cmd, acct).Scan(&acct)
if err != nil { if err != nil {
@ -63,34 +65,32 @@ func followed(acct string) bool {
// Take ticket for tooting // Take ticket for tooting
func take_ticket(acct string) { func take_ticket(acct string) {
db := init_limit_db()
cmd1 := `SELECT ticket FROM Limits WHERE acct = ?` cmd1 := `SELECT ticket FROM Limits WHERE acct = ?`
cmd2 := `UPDATE Limits SET ticket = ?, time = ? WHERE acct = ?` cmd2 := `UPDATE Limits SET ticket = ?, posted = ? WHERE acct = ?`
var ticket uint16 var ticket uint
db.QueryRow(cmd1, acct).Scan(&ticket) db.QueryRow(cmd1, acct).Scan(&ticket)
if ticket > 0 { if ticket > 0 {
ticket = ticket - 1 ticket = ticket - 1
} }
now := time.Now()
last_toot_at := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Format("2006/01/02 15:04:05 MST")
stat, err := db.Prepare(cmd2) stat, err := db.Prepare(cmd2)
if err != nil { if err != nil {
ErrorLogger.Println("Take ticket") ErrorLogger.Println("Take ticket")
} }
now := time.Now()
last_toot_at := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Format("2006/01/02 15:04:05 MST")
stat.Exec(ticket, last_toot_at, acct) stat.Exec(ticket, last_toot_at, acct)
} }
// Check ticket availability // Check ticket availability
func check_ticket(acct string) uint16 { func check_ticket(acct string) uint {
db := init_limit_db()
cmd1 := `SELECT ticket FROM Limits WHERE acct = ?` cmd1 := `SELECT ticket FROM Limits WHERE acct = ?`
cmd2 := `SELECT time FROM Limits WHERE acct = ?` cmd2 := `SELECT posted FROM Limits WHERE acct = ?`
var tickets uint16 var tickets uint
var lastS string var lastS string
db.QueryRow(cmd1, acct).Scan(&tickets) db.QueryRow(cmd1, acct).Scan(&tickets)
@ -118,20 +118,18 @@ func check_ticket(acct string) uint16 {
// Save message hash // Save message hash
func save_msg_hash(hash string) { func save_msg_hash(hash string) {
db := init_limit_db()
cmd1 := `SELECT COUNT(*) FROM MsgHashs` cmd1 := `SELECT COUNT(*) FROM MsgHashs`
cmd2 := `DELETE FROM MsgHashs WHERE ROWID IN (SELECT ROWID FROM MsgHashs LIMIT 1)` cmd2 := `DELETE FROM MsgHashs WHERE ROWID IN (SELECT ROWID FROM MsgHashs LIMIT 1)`
cmd3 := `INSERT INTO MsgHashs (message_hash) VALUES (?)` cmd3 := `INSERT INTO MsgHashs (message_hash) VALUES (?)`
var rows uint16 var rows uint
db.QueryRow(cmd1).Scan(&rows) db.QueryRow(cmd1).Scan(&rows)
if rows >= Conf.Duplicate_buf { if rows >= Conf.Duplicate_buf {
superfluous := rows - Conf.Duplicate_buf superfluous := rows - Conf.Duplicate_buf
for i := uint16(0); i <= superfluous; i++ { for i := uint(0); i <= superfluous; i++ {
stat2, err := db.Prepare(cmd2) stat2, err := db.Prepare(cmd2)
if err != nil { if err != nil {
ErrorLogger.Println("Delete message hash from database") ErrorLogger.Println("Delete message hash from database")
@ -149,7 +147,6 @@ func save_msg_hash(hash string) {
// Check message hash // Check message hash
func check_msg_hash(hash string) bool { func check_msg_hash(hash string) bool {
db := init_limit_db()
cmd := `SELECT message_hash FROM MsgHashs WHERE message_hash = ?` cmd := `SELECT message_hash FROM MsgHashs WHERE message_hash = ?`
err := db.QueryRow(cmd, hash).Scan(&hash) err := db.QueryRow(cmd, hash).Scan(&hash)
if err != nil { if err != nil {
@ -165,7 +162,6 @@ func check_msg_hash(hash string) bool {
// Count order // Count order
func count_order(acct string) { func count_order(acct string) {
db := init_limit_db()
cmd1 := `UPDATE Limits SET order_msg = ? WHERE acct != ?` cmd1 := `UPDATE Limits SET order_msg = ? WHERE acct != ?`
cmd2 := `SELECT order_msg FROM Limits WHERE acct = ?` cmd2 := `SELECT order_msg FROM Limits WHERE acct = ?`
cmd3 := `UPDATE Limits SET order_msg = ? WHERE acct = ?` cmd3 := `UPDATE Limits SET order_msg = ? WHERE acct = ?`
@ -177,7 +173,7 @@ func count_order(acct string) {
stat1.Exec(0, acct) stat1.Exec(0, acct)
var order uint16 var order uint
db.QueryRow(cmd2, acct).Scan(&order) db.QueryRow(cmd2, acct).Scan(&order)
if order < Conf.Order_limit { if order < Conf.Order_limit {
order = order + 1 order = order + 1
@ -192,12 +188,51 @@ func count_order(acct string) {
} }
// Check order // Check order
func check_order(acct string) uint16 { func check_order(acct string) uint {
db := init_limit_db()
cmd := `SELECT order_msg FROM Limits WHERE acct = ?` cmd := `SELECT order_msg FROM Limits WHERE acct = ?`
var order uint16 var order uint
db.QueryRow(cmd, acct).Scan(&order) db.QueryRow(cmd, acct).Scan(&order)
return order return order
} }
// Mark notice
func mark_notice(acct string) {
cmd1 := `SELECT got_notice FROM Limits WHERE acct = ?`
cmd2 := `UPDATE Limits SET got_notice = ? WHERE acct = ?`
var notice uint
db.QueryRow(cmd1, acct).Scan(&notice)
if notice == 0 {
notice = notice + 1
}
stat, err := db.Prepare(cmd2)
if err != nil {
ErrorLogger.Println("Mark notice")
}
stat.Exec(notice, acct)
}
// Reset notice counter
func reset_notice_counter() {
cmd := `UPDATE Limits SET got_notice = ?`
stat, err := db.Prepare(cmd)
if err != nil {
ErrorLogger.Println("Reset notice counter")
}
stat.Exec(0)
}
// Check if got notification
func got_notice(acct string) uint {
cmd := `SELECT got_notice FROM Limits WHERE acct = ?`
var notice uint
db.QueryRow(cmd, acct).Scan(&notice)
return notice
}

View File

@ -11,7 +11,7 @@ var (
ErrorLogger *log.Logger ErrorLogger *log.Logger
) )
func logger_init() { func LoggerInit() {
file, err := os.OpenFile(*LogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) file, err := os.OpenFile(*LogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil { if err != nil {
log.Fatal("Failed to read log file") log.Fatal("Failed to read log file")

View File

@ -1,5 +1,10 @@
package main package main
func main() { func main() {
LoggerInit()
wg.Add(1)
go DeleteNotices()
RunBot() RunBot()
} }

13
utils.go Normal file
View File

@ -0,0 +1,13 @@
package main
import "github.com/mattn/go-mastodon"
// Posting function
func postToot(toot string, vis string) (*mastodon.Status, error) {
conToot := mastodon.Toot{
Status: toot,
Visibility: vis,
}
status, err := c.PostStatus(ctx, &conToot)
return status, err
}