forked from External/ergo
channel history modifications
This commit is contained in:
parent
f4c03b6765
commit
711af30aa8
5 changed files with 106 additions and 41 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue