117 lines
3.5 KiB
Go
117 lines
3.5 KiB
Go
package services
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"git.solsynth.dev/hypernet/interactive/pkg/internal/database"
|
|
"git.solsynth.dev/hypernet/interactive/pkg/internal/models"
|
|
"git.solsynth.dev/hypernet/interactive/pkg/internal/services/mastodon"
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/samber/lo"
|
|
"github.com/spf13/viper"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
type FromFediversePost interface {
|
|
ToFediversePost() models.FediversePost
|
|
}
|
|
|
|
type FediverseFriendConfig struct {
|
|
ID string `json:"id"`
|
|
URL string `json:"url"`
|
|
Type string `json:"type"`
|
|
Trending bool `json:"trending"`
|
|
}
|
|
|
|
var fediverseFriends []FediverseFriendConfig
|
|
|
|
func ReadFriendConfig() {
|
|
if err := viper.UnmarshalKey("fediverse.friends", &fediverseFriends); err != nil {
|
|
log.Error().Err(err).Msg("Failed to loading fediverse friend config...")
|
|
}
|
|
log.Info().Int("count", len(fediverseFriends)).Msg("Loaded fediverse friend config!")
|
|
}
|
|
|
|
func FetchFediversePost(cfg FediverseFriendConfig) ([]models.FediversePost, error) {
|
|
switch cfg.Type {
|
|
case "mastodon":
|
|
data, err := mastodon.FetchTimeline(cfg.URL, 50, cfg.Trending)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
posts := lo.Map(data, func(item mastodon.MastodonPost, _ int) models.FediversePost {
|
|
return item.ToFediversePost()
|
|
})
|
|
return posts, nil
|
|
default:
|
|
// TODO Other platform fetching is still under development
|
|
// DO NOT USE THEM
|
|
return nil, fmt.Errorf("unsupported fediverse service: %s", cfg.Type)
|
|
}
|
|
}
|
|
|
|
func FetchFediverseTimedTask() {
|
|
if len(fediverseFriends) == 0 {
|
|
return
|
|
}
|
|
|
|
log.Debug().Msg("Starting fetching fediverse friends timeline...")
|
|
|
|
var totalPosts []models.FediversePost
|
|
var totalUsers []models.FediverseUser
|
|
userMap := make(map[string]models.FediverseUser)
|
|
|
|
for _, friend := range fediverseFriends {
|
|
log.Info().Str("id", friend.ID).Str("url", friend.URL).Msg("Fetching fediverse friend timeline...")
|
|
posts, err := FetchFediversePost(friend)
|
|
if err != nil {
|
|
log.Error().Err(err).Str("id", friend.ID).Str("url", friend.URL).Msg("Failed to fetch fediverse friend timeline...")
|
|
continue
|
|
}
|
|
|
|
log.Info().Str("id", friend.ID).Str("url", friend.URL).Int("count", len(posts)).Msg("Fetched fediverse friend timeline...")
|
|
|
|
for _, post := range posts {
|
|
if _, exists := userMap[post.User.Identifier]; !exists {
|
|
userMap[post.User.Identifier] = post.User
|
|
}
|
|
}
|
|
|
|
totalPosts = append(totalPosts, posts...)
|
|
}
|
|
|
|
for _, user := range userMap {
|
|
totalUsers = append(totalUsers, user)
|
|
}
|
|
|
|
if len(totalUsers) > 0 {
|
|
if err := database.C.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "identifier"}},
|
|
DoUpdates: clause.AssignmentColumns([]string{"name", "nick", "avatar"}),
|
|
}).Create(&totalUsers).Error; err != nil {
|
|
log.Error().Err(err).Msg("Failed to save fediverse users...")
|
|
}
|
|
|
|
for _, user := range totalUsers {
|
|
userMap[user.Identifier] = user
|
|
}
|
|
}
|
|
|
|
for i := range totalPosts {
|
|
if user, exists := userMap[totalPosts[i].User.Identifier]; exists {
|
|
totalPosts[i].UserID = user.ID
|
|
totalPosts[i].User = user
|
|
} else {
|
|
log.Warn().Str("user_identifier", totalPosts[i].User.Identifier).Msg("User ID not found for post, skipping")
|
|
totalPosts = append(totalPosts[:i], totalPosts[i+1:]...) // Remove invalid post
|
|
i-- // Adjust index after removal
|
|
}
|
|
}
|
|
|
|
if len(totalPosts) > 0 {
|
|
if err := database.C.Clauses(clause.OnConflict{DoNothing: true}).Create(&totalPosts).Error; err != nil {
|
|
log.Error().Err(err).Msg("Failed to save timeline posts...")
|
|
}
|
|
}
|
|
}
|