|
@ -9,14 +9,18 @@ import ( |
|
|
"git.aiterp.net/rpdata/api/models/channels" |
|
|
"git.aiterp.net/rpdata/api/models/channels" |
|
|
"git.aiterp.net/rpdata/api/repositories" |
|
|
"git.aiterp.net/rpdata/api/repositories" |
|
|
"git.aiterp.net/rpdata/api/services/parsers" |
|
|
"git.aiterp.net/rpdata/api/services/parsers" |
|
|
|
|
|
"golang.org/x/sync/errgroup" |
|
|
|
|
|
"log" |
|
|
|
|
|
"strings" |
|
|
"time" |
|
|
"time" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
type LogService struct { |
|
|
type LogService struct { |
|
|
logs repositories.LogRepository |
|
|
|
|
|
posts repositories.PostRepository |
|
|
|
|
|
changeService *ChangeService |
|
|
|
|
|
channelService *ChannelService |
|
|
|
|
|
|
|
|
logs repositories.LogRepository |
|
|
|
|
|
posts repositories.PostRepository |
|
|
|
|
|
changeService *ChangeService |
|
|
|
|
|
channelService *ChannelService |
|
|
|
|
|
characterService *CharacterService |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (s *LogService) Find(ctx context.Context, id string) (*models.Log, error) { |
|
|
func (s *LogService) Find(ctx context.Context, id string) (*models.Log, error) { |
|
@ -339,3 +343,123 @@ func (s *LogService) Delete(ctx context.Context, id string) (*models.Log, error) |
|
|
|
|
|
|
|
|
return log, nil |
|
|
return log, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *LogService) RefreshAllLogCharacters(ctx context.Context) error { |
|
|
|
|
|
start := time.Now() |
|
|
|
|
|
|
|
|
|
|
|
// Get all logs
|
|
|
|
|
|
logs, err := s.logs.List(ctx, models.LogFilter{}) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check all characters now instead of later.
|
|
|
|
|
|
characters, err := s.characterService.List(ctx, models.CharacterFilter{}) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
characterMap := s.makeCharacterMap(characters) |
|
|
|
|
|
|
|
|
|
|
|
eg := errgroup.Group{} |
|
|
|
|
|
for i := range logs { |
|
|
|
|
|
l := logs[i] |
|
|
|
|
|
|
|
|
|
|
|
eg.Go(func() error { |
|
|
|
|
|
return s.refreshLogCharacters(ctx, *l, characterMap) |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
err = eg.Wait() |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.Printf("Full log character refresh complete; nicks: %d, logs: %d, duration: %s", len(characterMap), len(logs), time.Since(start)) |
|
|
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *LogService) RefreshLogCharacters(ctx context.Context, log models.Log) error { |
|
|
|
|
|
return s.refreshLogCharacters(ctx, log, nil) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *LogService) refreshLogCharacters(ctx context.Context, log models.Log, characterMap map[string]*models.Character) error { |
|
|
|
|
|
posts, err := s.ListPosts(ctx, &models.PostFilter{LogID: &log.ShortID}) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return nil |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
counts := make(map[string]int) |
|
|
|
|
|
added := make(map[string]bool) |
|
|
|
|
|
removed := make(map[string]bool) |
|
|
|
|
|
for _, post := range posts { |
|
|
|
|
|
if post.Kind == "text" || post.Kind == "action" { |
|
|
|
|
|
if strings.HasPrefix(post.Text, "(") || strings.Contains(post.Nick, "(") || strings.Contains(post.Nick, "[E]") || strings.HasSuffix(post.Nick, "|") { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Clean up the nick (remove possessive suffix, comma, formatting stuff)
|
|
|
|
|
|
if strings.HasSuffix(post.Nick, "'s") || strings.HasSuffix(post.Nick, "`s") { |
|
|
|
|
|
post.Nick = post.Nick[:len(post.Nick)-2] |
|
|
|
|
|
} else if strings.HasSuffix(post.Nick, "'") || strings.HasSuffix(post.Nick, "`") || strings.HasSuffix(post.Nick, ",") || strings.HasSuffix(post.Nick, "\x0f") { |
|
|
|
|
|
post.Nick = post.Nick[:len(post.Nick)-1] |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
added[post.Nick] = true |
|
|
|
|
|
counts[post.Nick]++ |
|
|
|
|
|
} |
|
|
|
|
|
if post.Kind == "chars" { |
|
|
|
|
|
tokens := strings.Fields(post.Text) |
|
|
|
|
|
for _, token := range tokens { |
|
|
|
|
|
if strings.HasPrefix(token, "-") { |
|
|
|
|
|
removed[token[1:]] = true |
|
|
|
|
|
} else { |
|
|
|
|
|
added[strings.Replace(token, "+", "", 1)] = true |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
nicks := make([]string, 0, len(added)) |
|
|
|
|
|
for nick := range added { |
|
|
|
|
|
if added[nick] && !removed[nick] { |
|
|
|
|
|
nicks = append(nicks, nick) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if characterMap == nil { |
|
|
|
|
|
characters, err := s.characterService.List(ctx, models.CharacterFilter{Nicks: nicks}) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
characterMap = s.makeCharacterMap(characters) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.CharacterIDs = log.CharacterIDs[:0] |
|
|
|
|
|
for key := range added { |
|
|
|
|
|
delete(added, key) |
|
|
|
|
|
} |
|
|
|
|
|
for _, nick := range nicks { |
|
|
|
|
|
character := characterMap[nick] |
|
|
|
|
|
if character == nil || added[character.ID] { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
added[character.ID] = true |
|
|
|
|
|
|
|
|
|
|
|
log.CharacterIDs = append(log.CharacterIDs, character.ID) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_, err = s.logs.Update(ctx, log, models.LogUpdate{CharacterIDs: log.CharacterIDs}) |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *LogService) makeCharacterMap(characters []*models.Character) map[string]*models.Character { |
|
|
|
|
|
characterMap := make(map[string]*models.Character, len(characters)*3) |
|
|
|
|
|
for _, character := range characters { |
|
|
|
|
|
for _, nick := range character.Nicks { |
|
|
|
|
|
characterMap[nick] = character |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return characterMap |
|
|
|
|
|
} |