1
0
Fork 0
forked from External/ergo

channel history modifications

This commit is contained in:
CEF Server 2024-11-18 19:38:49 +00:00
parent f4c03b6765
commit 711af30aa8
5 changed files with 106 additions and 41 deletions

View file

@ -971,7 +971,7 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
}
}
if 0 < numItems {
channel.replayHistoryItems(rb, items, false)
channel.replayHistoryItems(rb, items, false, "", "", numItems)
rb.Flush(true)
}
}
@ -1062,7 +1062,7 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname))
}
func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, chathistoryCommand bool) {
func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, chathistoryCommand bool, identifier string, preposition string, limit int) {
// send an empty batch if necessary, as per the CHATHISTORY spec
chname := channel.Name()
client := rb.target
@ -1082,7 +1082,7 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
}
}
batchID := rb.StartNestedBatch("chathistory", chname)
batchID := rb.StartNestedBatch("chathistory", chname, identifier, preposition, strconv.Itoa(limit))
defer rb.EndNestedBatch(batchID)
for _, item := range items {

View file

@ -35,8 +35,8 @@ import (
)
const (
// maximum IRC line length, not including tags
DefaultMaxLineLen = 512
// Set to 4096 because CEF doesn't care about compatibility
DefaultMaxLineLen = 4096
// IdentTimeout is how long before our ident (username) check times out.
IdentTimeout = time.Second + 500*time.Millisecond
@ -649,6 +649,17 @@ func (client *Client) run(session *Session) {
firstLine := !isReattach
correspondents, _ := client.server.historyDB.GetPMs(client.NickCasefolded())
// For safety, let's keep this within the 4096 character barrier
var lineBuilder utils.TokenLineBuilder
lineBuilder.Initialize(MaxLineLen, ",")
for username, timestamp := range correspondents {
lineBuilder.Add(fmt.Sprintf("%s %d", client.server.getCurrentNick(username), timestamp))
}
for _, message := range lineBuilder.Lines() {
session.Send(nil, client.server.name, "PMS", message)
}
for {
var invalidUtf8 bool
line, err := session.socket.Read()
@ -862,14 +873,14 @@ func (session *Session) Ping() {
session.Send(nil, "", "PING", session.client.Nick())
}
func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string, chathistoryCommand bool) {
func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string, chathistoryCommand bool, identifier string, preposition string, limit int) {
var batchID string
details := client.Details()
nick := details.nick
if target == "" {
target = nick
}
batchID = rb.StartNestedBatch("chathistory", target)
batchID = rb.StartNestedBatch("chathistory", target, identifier, preposition, strconv.Itoa(limit))
isSelfMessage := func(item *history.Item) bool {
// XXX: Params[0] is the message target. if the source of this message is an in-memory

View file

@ -712,6 +712,14 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
var err error
var listTargets bool
var targets []history.TargetListing
var _, batchIdentifier = msg.GetTag("identifier")
var assuredPreposition = "error"
var limit int
if len(batchIdentifier) == 0 {
batchIdentifier = "UNIDENTIFIED"
}
defer func() {
// errors are sent either without a batch, or in a draft/labeled-response batch as usual
if err == utils.ErrInvalidParams {
@ -731,9 +739,9 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
target.Time.Format(IRCv3TimestampFormat))
}
} else if channel != nil {
channel.replayHistoryItems(rb, items, true)
channel.replayHistoryItems(rb, items, true, batchIdentifier, assuredPreposition, limit)
} else {
client.replayPrivmsgHistory(rb, items, target, true)
client.replayPrivmsgHistory(rb, items, target, true, batchIdentifier, assuredPreposition, limit)
}
}
}()
@ -786,7 +794,6 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
paramPos := 2
var start, end history.Selector
var limit int
switch preposition {
case "targets":
// use the same selector parsing as BETWEEN,
@ -841,6 +848,7 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
err = utils.ErrInvalidParams
return
}
assuredPreposition = preposition
if listTargets {
targets, err = client.listTargets(start, end, limit)
@ -1227,29 +1235,34 @@ Get an explanation of <argument>, or "index" for a list of help topics.`), rb)
// HISTORY alice 15
// HISTORY #darwin 1h
func historyHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
config := server.Config()
if !config.History.Enabled {
rb.Notice(client.t("This command has been disabled by the server administrators"))
return false
}
items, channel, err := easySelectHistory(server, client, msg.Params)
if err == errNoSuchChannel {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(msg.Params[0]), client.t("No such channel"))
return false
} else if err != nil {
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), msg.Command, client.t("Could not retrieve history"))
return false
}
if len(items) != 0 {
if channel != nil {
channel.replayHistoryItems(rb, items, true)
} else {
client.replayPrivmsgHistory(rb, items, "", true)
rb.Notice(client.t("This command is currently disabled. Please use CHATHISTORY"))
/*
config := server.Config()
if !config.History.Enabled {
rb.Notice(client.t("This command has been disabled by the server administrators"))
return false
}
}
items, channel, err := easySelectHistory(server, client, msg.Params)
if err == errNoSuchChannel {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(msg.Params[0]), client.t("No such channel"))
return false
} else if err != nil {
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), msg.Command, client.t("Could not retrieve history"))
return false
}
var _, batchIdentifier = msg.GetTag("identifier")
if len(items) != 0 {
if channel != nil {
channel.replayHistoryItems(rb, items, true, batchIdentifier)
} else {
client.replayPrivmsgHistory(rb, items, "", true, batchIdentifier)
}
}
*/
return false
}

View file

@ -623,6 +623,9 @@ func (mysql *MySQL) AddChannelItem(target string, item history.Item, account str
func (mysql *MySQL) insertSequenceEntry(ctx context.Context, target string, messageTime int64, id int64) (err error) {
_, err = mysql.insertSequence.ExecContext(ctx, target, messageTime, id)
if err != nil {
println(target, messageTime, id, ctx)
}
mysql.logError("could not insert sequence entry", err)
return
}
@ -640,17 +643,17 @@ func (mysql *MySQL) insertCorrespondentsEntry(ctx context.Context, target, corre
}
func (mysql *MySQL) insertBase(ctx context.Context, item history.Item) (id int64, err error) {
value, err := marshalItem(&item)
_, err := marshalItem(&item)
if mysql.logError("could not marshal item", err) {
return
}
msgidBytes, err := decodeMsgid(item.Message.Msgid)
if mysql.logError("could not decode msgid", err) {
//msgidBytes, err := decodeMsgid(item.Message.Msgid)
/*if mysql.logError("could not decode msgid", err) {
return
}
}*/
result, err := mysql.insertHistory.ExecContext(ctx, value, msgidBytes)
result, err := mysql.insertHistory.ExecContext(ctx, value, item.Message.Msgid)
if mysql.logError("could not insert item", err) {
return
}
@ -812,7 +815,6 @@ func (mysql *MySQL) Export(account string, writer io.Writer) {
}
func (mysql *MySQL) lookupMsgid(ctx context.Context, msgid string, includeData bool) (result time.Time, id uint64, data []byte, err error) {
decoded, err := decodeMsgid(msgid)
if err != nil {
return
}
@ -820,11 +822,14 @@ func (mysql *MySQL) lookupMsgid(ctx context.Context, msgid string, includeData b
if includeData {
cols = `sequence.nanotime, conversations.nanotime, history.id, history.data`
}
// Since CEF uses snowflakes and vanilla ergo uses blobs, we cast as int to make it function.
// May have to adjust it some day
row := mysql.db.QueryRowContext(ctx, fmt.Sprintf(`
SELECT %s FROM history
LEFT JOIN sequence ON history.id = sequence.history_id
LEFT JOIN conversations ON history.id = conversations.history_id
WHERE history.msgid = ? LIMIT 1;`, cols), decoded)
WHERE history.msgid = CAST(? AS INT) LIMIT 1;`, cols), msgid)
var nanoSeq, nanoConv sql.NullInt64
if !includeData {
err = row.Scan(&nanoSeq, &nanoConv)
@ -1042,6 +1047,7 @@ func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (
defer cancel()
startTime := start.Time
if start.Msgid != "" {
startTime, _, _, err = s.mysql.lookupMsgid(ctx, start.Msgid, false)
if err != nil {
@ -1055,6 +1061,7 @@ func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (
endTime := end.Time
if end.Msgid != "" {
endTime, _, _, err = s.mysql.lookupMsgid(ctx, end.Msgid, false)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
@ -1101,3 +1108,37 @@ func (mysql *MySQL) MakeSequence(target, correspondent string, cutoff time.Time)
cutoff: cutoff,
}
}
func (mysql *MySQL) GetPMs(casefoldedUser string) (results map[string]int64, err error) {
if mysql.db == nil {
return
}
results = make(map[string]int64)
ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout())
defer cancel()
var queryBuf strings.Builder
args := make([]interface{}, 0)
queryBuf.WriteString(`SELECT max(nanotime), correspondent FROM conversations WHERE target = ? GROUP BY correspondent;`)
args = append(args, casefoldedUser)
rows, err := mysql.db.QueryContext(ctx, queryBuf.String(), args...)
if mysql.logError("could not get pms", err) {
return
}
defer rows.Close()
var last int64
var correspondent string
for rows.Next() {
err = rows.Scan(&last, &correspondent)
if mysql.logError("could not get pms", err) {
return
}
// We really don't need nanosecond precision
results[correspondent] = last / 1000000
}
return
}

View file

@ -203,7 +203,7 @@ func zncPlayPrivmsgsFrom(client *Client, rb *ResponseBuffer, target string, star
zncMax := client.server.Config().History.ZNCMax
items, err := sequence.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax)
if err == nil && len(items) != 0 {
client.replayPrivmsgHistory(rb, items, target, false)
client.replayPrivmsgHistory(rb, items, target, false, "", "", 0)
}
}
@ -211,7 +211,7 @@ func zncPlayPrivmsgsFromAll(client *Client, rb *ResponseBuffer, start, end time.
zncMax := client.server.Config().History.ZNCMax
items, err := client.privmsgsBetween(start, end, maxDMTargetsForAutoplay, zncMax)
if err == nil && len(items) != 0 {
client.replayPrivmsgHistory(rb, items, "", false)
client.replayPrivmsgHistory(rb, items, "", false, "", "", 0)
}
}