Changeset 360 in code for trunk


Ignore:
Timestamp:
Jul 15, 2020, 3:47:57 PM (5 years ago)
Author:
contact
Message:

Implement CHATHISTORY AFTER

References: https://todo.sr.ht/~emersion/soju/12

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/downstream.go

    r354 r360  
    15991599                }
    16001600
     1601                batchRef := "history"
     1602                maxTries := 100
    16011603                switch subcommand {
    16021604                case "BEFORE":
    1603                         batchRef := "history"
    16041605                        dc.SendMessage(&irc.Message{
    16051606                                Prefix:  dc.srv.prefix(),
     
    16121613
    16131614                        tries := 0
    1614                         for remaining > 0 {
     1615                        for remaining > 0 && tries < maxTries {
    16151616                                buf, err := parseMessagesBefore(uc.network, entity, timestamp, remaining)
    16161617                                if err != nil {
     
    16201621                                if len(buf) == 0 {
    16211622                                        tries++
    1622                                         if tries >= 100 {
    1623                                                 break
    1624                                         }
    16251623                                } else {
    16261624                                        tries = 0
     
    16321630                        }
    16331631
    1634                         for _, m := range history[remaining:] {
    1635                                 m.Tags["batch"] = irc.TagValue(batchRef)
    1636                                 dc.SendMessage(dc.marshalMessage(m, uc.network))
     1632                        for _, msg := range history[remaining:] {
     1633                                msg.Tags["batch"] = irc.TagValue(batchRef)
     1634                                dc.SendMessage(dc.marshalMessage(msg, uc.network))
    16371635                        }
    16381636
     
    16421640                                Params:  []string{"-" + batchRef},
    16431641                        })
     1642                case "AFTER":
     1643                        dc.SendMessage(&irc.Message{
     1644                                Prefix:  dc.srv.prefix(),
     1645                                Command: "BATCH",
     1646                                Params:  []string{"+" + batchRef, "chathistory", target},
     1647                        })
     1648
     1649                        remaining := limit
     1650                        tries := 0
     1651                        now := time.Now()
     1652                        for remaining > 0 && tries < maxTries && timestamp.Before(now) {
     1653                                buf, err := parseMessagesAfter(uc.network, entity, timestamp, remaining)
     1654                                if err != nil {
     1655                                        dc.logger.Printf("failed parsing log messages for chathistory: %v", err)
     1656                                        return newChatHistoryError(subcommand, target)
     1657                                }
     1658                                if len(buf) == 0 {
     1659                                        tries++
     1660                                } else {
     1661                                        tries = 0
     1662                                }
     1663                                for _, msg := range buf {
     1664                                        msg.Tags["batch"] = irc.TagValue(batchRef)
     1665                                        dc.SendMessage(dc.marshalMessage(msg, uc.network))
     1666                                }
     1667                                remaining -= len(buf)
     1668                                year, month, day := timestamp.Date()
     1669                                timestamp = time.Date(year, month, day + 1, 0, 0, 0, 0, timestamp.Location())
     1670                        }
     1671
     1672                        dc.SendMessage(&irc.Message{
     1673                                Prefix:  dc.srv.prefix(),
     1674                                Command: "BATCH",
     1675                                Params:  []string{"-" + batchRef},
     1676                        })
    16441677                default:
    1645                         // TODO: support AFTER, LATEST, BETWEEN
     1678                        // TODO: support LATEST, BETWEEN
    16461679                        return ircError{&irc.Message{
    16471680                                Command: "FAIL",
  • trunk/logger.go

    r319 r360  
    135135}
    136136
    137 func parseMessagesBefore(network *network, entity string, timestamp time.Time, limit int) ([]*irc.Message, error) {
    138         year, month, day := timestamp.Date()
    139         path := logPath(network, entity, timestamp)
     137func parseMessage(line, entity string, ref time.Time) (*irc.Message, time.Time, error) {
     138        var hour, minute, second int
     139        _, err := fmt.Sscanf(line, "[%02d:%02d:%02d] ", &hour, &minute, &second)
     140        if err != nil {
     141                return nil, time.Time{}, err
     142        }
     143        line = line[11:]
     144
     145        // TODO: support NOTICE
     146        if !strings.HasPrefix(line, "<") {
     147                return nil, time.Time{}, nil
     148        }
     149        i := strings.Index(line, "> ")
     150        if i < 0 {
     151                return nil, time.Time{}, nil
     152        }
     153
     154        year, month, day := ref.Date()
     155        t := time.Date(year, month, day, hour, minute, second, 0, time.Local)
     156
     157        sender := line[1:i]
     158        text := line[i+2:]
     159        msg := &irc.Message{
     160                Tags: map[string]irc.TagValue{
     161                        "time": irc.TagValue(t.UTC().Format(serverTimeLayout)),
     162                },
     163                Prefix: &irc.Prefix{Name: sender},
     164                Command: "PRIVMSG",
     165                Params:  []string{entity, text},
     166        }
     167        return msg, t, nil
     168}
     169
     170func parseMessagesBefore(network *network, entity string, ref time.Time, limit int) ([]*irc.Message, error) {
     171        path := logPath(network, entity, ref)
    140172        f, err := os.Open(path)
    141173        if err != nil {
     
    152184        sc := bufio.NewScanner(f)
    153185        for sc.Scan() {
    154                 line := sc.Text()
    155                 var hour, minute, second int
    156                 _, err := fmt.Sscanf(line, "[%02d:%02d:%02d] ", &hour, &minute, &second)
     186                msg, t, err := parseMessage(sc.Text(), entity, ref)
    157187                if err != nil {
    158188                        return nil, err
    159                 }
    160                 message := line[11:]
    161                 // TODO: support NOTICE
    162                 if !strings.HasPrefix(message, "<") {
     189                } else if msg == nil {
    163190                        continue
    164                 }
    165                 i := strings.Index(message, "> ")
    166                 if i == -1 {
    167                         continue
    168                 }
    169                 t := time.Date(year, month, day, hour, minute, second, 0, time.Local)
    170                 if !t.Before(timestamp) {
     191                } else if !t.Before(ref) {
    171192                        break
    172193                }
    173194
    174                 sender := message[1:i]
    175                 text := message[i+2:]
    176                 historyRing[cur%limit] = &irc.Message{
    177                         Tags: map[string]irc.TagValue{
    178                                 "time": irc.TagValue(t.UTC().Format(serverTimeLayout)),
    179                         },
    180                         Prefix: &irc.Prefix{
    181                                 Name: sender,
    182                         },
    183                         Command: "PRIVMSG",
    184                         Params:  []string{entity, text},
    185                 }
     195                historyRing[cur%limit] = msg
    186196                cur++
    187197        }
     
    205215        }
    206216}
     217
     218func parseMessagesAfter(network *network, entity string, ref time.Time, limit int) ([]*irc.Message, error) {
     219        path := logPath(network, entity, ref)
     220        f, err := os.Open(path)
     221        if err != nil {
     222                if os.IsNotExist(err) {
     223                        return nil, nil
     224                }
     225                return nil, err
     226        }
     227        defer f.Close()
     228
     229        var history []*irc.Message
     230        sc := bufio.NewScanner(f)
     231        for sc.Scan() && len(history) < limit {
     232                msg, t, err := parseMessage(sc.Text(), entity, ref)
     233                if err != nil {
     234                        return nil, err
     235                } else if msg == nil || !t.After(ref) {
     236                        continue
     237                }
     238
     239                history = append(history, msg)
     240        }
     241        if sc.Err() != nil {
     242                return nil, sc.Err()
     243        }
     244
     245        return history, nil
     246}
Note: See TracChangeset for help on using the changeset viewer.