Changeset 549 in code
- Timestamp:
- Jun 2, 2021, 6:32:11 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/downstream.go
r547 r549 2031 2031 return err 2032 2032 } 2033 case "TARGETS": 2034 if err := parseMessageParams(msg, nil, &boundsStr[0], &boundsStr[1], &limitStr); err != nil { 2035 return err 2036 } 2033 2037 default: 2034 2038 // TODO: support LATEST, AROUND … … 2093 2097 history, err = store.LoadBeforeTime(uc.network, entity, bounds[0], bounds[1], limit) 2094 2098 } 2099 case "TARGETS": 2100 // TODO: support TARGETS in multi-upstream mode 2101 targets, err := store.ListTargets(uc.network, bounds[0], bounds[1], limit) 2102 if err != nil { 2103 dc.logger.Printf("failed fetching targets for chathistory: %v", target, err) 2104 return ircError{&irc.Message{ 2105 Command: "FAIL", 2106 Params: []string{"CHATHISTORY", "MESSAGE_ERROR", subcommand, "Failed to retrieve targets"}, 2107 }} 2108 } 2109 2110 batchRef := "history-targets" 2111 dc.SendMessage(&irc.Message{ 2112 Prefix: dc.srv.prefix(), 2113 Command: "BATCH", 2114 Params: []string{"+" + batchRef, "draft/chathistory-targets"}, 2115 }) 2116 2117 for _, target := range targets { 2118 dc.SendMessage(&irc.Message{ 2119 Tags: irc.Tags{"batch": irc.TagValue(batchRef)}, 2120 Prefix: dc.srv.prefix(), 2121 Command: "CHATHISTORY", 2122 Params: []string{"TARGETS", target.Name, target.LatestMessage.UTC().Format(serverTimeLayout)}, 2123 }) 2124 } 2125 2126 dc.SendMessage(&irc.Message{ 2127 Prefix: dc.srv.prefix(), 2128 Command: "BATCH", 2129 Params: []string{"-" + batchRef}, 2130 }) 2131 2132 return nil 2095 2133 } 2096 2134 if err != nil { -
trunk/msgstore.go
r516 r549 22 22 } 23 23 24 type chatHistoryTarget struct { 25 Name string 26 LatestMessage time.Time 27 } 28 24 29 // chatHistoryMessageStore is a message store that supports chat history 25 30 // operations. … … 27 32 messageStore 28 33 34 // ListTargets lists channels and nicknames by time of the latest message. 35 // It returns up to limit targets, starting from start and ending on end, 36 // both excluded. end may be before or after start. 37 ListTargets(network *network, start, end time.Time, limit int) ([]chatHistoryTarget, error) 29 38 // LoadBeforeTime loads up to limit messages before start down to end. The 30 39 // returned messages must be between and excluding the provided bounds. -
trunk/msgstore_fs.go
r517 r549 7 7 "os" 8 8 "path/filepath" 9 "sort" 9 10 "strings" 10 11 "time" … … 394 395 } 395 396 396 func truncateDay(t time.Time) time.Time {397 year, month, day := t.Date()398 return time.Date(year, month, day, 0, 0, 0, 0, t.Location())399 }400 401 397 func (ms *fsMessageStore) LoadLatestID(network *network, entity, id string, limit int) ([]*irc.Message, error) { 402 398 var afterTime time.Time … … 442 438 return history[remaining:], nil 443 439 } 440 441 func (ms *fsMessageStore) ListTargets(network *network, start, end time.Time, limit int) ([]chatHistoryTarget, error) { 442 rootPath := filepath.Join(ms.root, escapeFilename.Replace(network.GetName())) 443 root, err := os.Open(rootPath) 444 if err != nil { 445 return nil, err 446 } 447 448 // The returned targets are escaped, and there is no way to un-escape 449 // TODO: switch to ReadDir (Go 1.16+) 450 targetNames, err := root.Readdirnames(0) 451 root.Close() 452 if err != nil { 453 return nil, err 454 } 455 456 var targets []chatHistoryTarget 457 for _, target := range targetNames { 458 // target is already escaped here 459 targetPath := filepath.Join(rootPath, target) 460 targetDir, err := os.Open(targetPath) 461 if err != nil { 462 return nil, err 463 } 464 465 entries, err := targetDir.Readdir(0) 466 targetDir.Close() 467 if err != nil { 468 return nil, err 469 } 470 471 // We use mtime here, which may give imprecise or incorrect results 472 var t time.Time 473 for _, entry := range entries { 474 if entry.ModTime().After(t) { 475 t = entry.ModTime() 476 } 477 } 478 479 // The timestamps we get from logs have second granularity 480 t = truncateSecond(t) 481 482 // Filter out targets that don't fullfil the time bounds 483 if !isTimeBetween(t, start, end) { 484 continue 485 } 486 487 targets = append(targets, chatHistoryTarget{ 488 Name: target, 489 LatestMessage: t, 490 }) 491 } 492 493 // Sort targets by latest message time, backwards or forwards depending on 494 // the order of the time bounds 495 sort.Slice(targets, func(i, j int) bool { 496 t1, t2 := targets[i].LatestMessage, targets[j].LatestMessage 497 if start.Before(end) { 498 return t1.Before(t2) 499 } else { 500 return !t1.Before(t2) 501 } 502 }) 503 504 // Truncate the result if necessary 505 if len(targets) > limit { 506 targets = targets[:limit] 507 } 508 509 return targets, nil 510 } 511 512 func truncateDay(t time.Time) time.Time { 513 year, month, day := t.Date() 514 return time.Date(year, month, day, 0, 0, 0, 0, t.Location()) 515 } 516 517 func truncateSecond(t time.Time) time.Time { 518 year, month, day := t.Date() 519 return time.Date(year, month, day, t.Hour(), t.Minute(), t.Second(), 0, t.Location()) 520 } 521 522 func isTimeBetween(t, start, end time.Time) bool { 523 if end.Before(start) { 524 end, start = start, end 525 } 526 return start.Before(t) && t.Before(end) 527 }
Note:
See TracChangeset
for help on using the changeset viewer.