ソースを参照

fix #833

tags/v2.0.0-rc1
Shivaram Lingamneni 4年前
コミット
d967129446
4個のファイルの変更69行の追加75行の削除
  1. 7
    4
      irc/client.go
  2. 3
    5
      irc/handlers.go
  3. 42
    49
      irc/mysql/history.go
  4. 17
    17
      irc/server.go

+ 7
- 4
irc/client.go ファイルの表示

1563
 	}
1563
 	}
1564
 
1564
 
1565
 	client.stateMutex.RLock()
1565
 	client.stateMutex.RLock()
1566
-	loggedIn := client.account != ""
1566
+	target = client.account
1567
 	historyStatus := client.accountSettings.DMHistory
1567
 	historyStatus := client.accountSettings.DMHistory
1568
-	target = client.nickCasefolded
1569
 	client.stateMutex.RUnlock()
1568
 	client.stateMutex.RUnlock()
1570
 
1569
 
1571
-	if !loggedIn {
1570
+	if target == "" {
1572
 		return HistoryEphemeral, ""
1571
 		return HistoryEphemeral, ""
1573
 	}
1572
 	}
1574
-	return historyEnabled(config.History.Persistent.DirectMessages, historyStatus), target
1573
+	status = historyEnabled(config.History.Persistent.DirectMessages, historyStatus)
1574
+	if status != HistoryPersistent {
1575
+		target = ""
1576
+	}
1577
+	return
1575
 }
1578
 }
1576
 
1579
 
1577
 // these are bit flags indicating what part of the client status is "dirty"
1580
 // these are bit flags indicating what part of the client status is "dirty"

+ 3
- 5
irc/handlers.go ファイルの表示

2011
 			item.CfCorrespondent = details.nickCasefolded
2011
 			item.CfCorrespondent = details.nickCasefolded
2012
 			user.history.Add(item)
2012
 			user.history.Add(item)
2013
 		}
2013
 		}
2014
-		cPersistent := cStatus == HistoryPersistent
2015
-		tPersistent := tStatus == HistoryPersistent
2016
-		if cPersistent || tPersistent {
2017
-			item.CfCorrespondent = ""
2018
-			server.historyDB.AddDirectMessage(details.nickCasefolded, user.NickCasefolded(), cPersistent, tPersistent, targetedItem)
2014
+		if cStatus == HistoryPersistent || tStatus == HistoryPersistent {
2015
+			targetedItem.CfCorrespondent = ""
2016
+			server.historyDB.AddDirectMessage(details.nickCasefolded, details.account, tDetails.nickCasefolded, tDetails.account, targetedItem)
2019
 		}
2017
 		}
2020
 	}
2018
 	}
2021
 }
2019
 }

+ 42
- 49
irc/mysql/history.go ファイルの表示

25
 	MaxTargetLength = 64
25
 	MaxTargetLength = 64
26
 
26
 
27
 	// latest schema of the db
27
 	// latest schema of the db
28
-	latestDbSchema   = "1"
28
+	latestDbSchema   = "2"
29
 	keySchemaVersion = "db.version"
29
 	keySchemaVersion = "db.version"
30
 	cleanupRowLimit  = 50
30
 	cleanupRowLimit  = 50
31
 	cleanupPauseTime = 10 * time.Minute
31
 	cleanupPauseTime = 10 * time.Minute
144
 
144
 
145
 	_, err = mysql.db.Exec(fmt.Sprintf(`CREATE TABLE conversations (
145
 	_, err = mysql.db.Exec(fmt.Sprintf(`CREATE TABLE conversations (
146
 		id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
146
 		id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
147
-		lower_target VARBINARY(%[1]d) NOT NULL,
148
-		upper_target VARBINARY(%[1]d) NOT NULL,
147
+		target VARBINARY(%[1]d) NOT NULL,
148
+		correspondent VARBINARY(%[1]d) NOT NULL,
149
 		nanotime BIGINT UNSIGNED NOT NULL,
149
 		nanotime BIGINT UNSIGNED NOT NULL,
150
 		history_id BIGINT NOT NULL,
150
 		history_id BIGINT NOT NULL,
151
-		KEY (lower_target, upper_target, nanotime),
151
+		KEY (target, correspondent, nanotime),
152
 		KEY (history_id)
152
 		KEY (history_id)
153
 	) CHARSET=ascii COLLATE=ascii_bin;`, MaxTargetLength))
153
 	) CHARSET=ascii COLLATE=ascii_bin;`, MaxTargetLength))
154
 	if err != nil {
154
 	if err != nil {
278
 		return
278
 		return
279
 	}
279
 	}
280
 	mysql.insertConversation, err = mysql.db.Prepare(`INSERT INTO conversations
280
 	mysql.insertConversation, err = mysql.db.Prepare(`INSERT INTO conversations
281
-		(lower_target, upper_target, nanotime, history_id) VALUES (?, ?, ?, ?);`)
281
+		(target, correspondent, nanotime, history_id) VALUES (?, ?, ?, ?);`)
282
 	if err != nil {
282
 	if err != nil {
283
 		return
283
 		return
284
 	}
284
 	}
315
 		return
315
 		return
316
 	}
316
 	}
317
 
317
 
318
-	err = mysql.insertSequenceEntry(ctx, target, item.Message.Time, id)
318
+	err = mysql.insertSequenceEntry(ctx, target, item.Message.Time.UnixNano(), id)
319
 	return
319
 	return
320
 }
320
 }
321
 
321
 
322
-func (mysql *MySQL) insertSequenceEntry(ctx context.Context, target string, messageTime time.Time, id int64) (err error) {
323
-	_, err = mysql.insertSequence.ExecContext(ctx, target, messageTime.UnixNano(), id)
322
+func (mysql *MySQL) insertSequenceEntry(ctx context.Context, target string, messageTime int64, id int64) (err error) {
323
+	_, err = mysql.insertSequence.ExecContext(ctx, target, messageTime, id)
324
 	mysql.logError("could not insert sequence entry", err)
324
 	mysql.logError("could not insert sequence entry", err)
325
 	return
325
 	return
326
 }
326
 }
327
 
327
 
328
-func (mysql *MySQL) insertConversationEntry(ctx context.Context, sender, recipient string, messageTime time.Time, id int64) (err error) {
329
-	lower, higher := stringMinMax(sender, recipient)
330
-	_, err = mysql.insertConversation.ExecContext(ctx, lower, higher, messageTime.UnixNano(), id)
328
+func (mysql *MySQL) insertConversationEntry(ctx context.Context, target, correspondent string, messageTime int64, id int64) (err error) {
329
+	_, err = mysql.insertConversation.ExecContext(ctx, target, correspondent, messageTime, id)
331
 	mysql.logError("could not insert conversations entry", err)
330
 	mysql.logError("could not insert conversations entry", err)
332
 	return
331
 	return
333
 }
332
 }
355
 	return
354
 	return
356
 }
355
 }
357
 
356
 
358
-func stringMinMax(first, second string) (min, max string) {
359
-	if first < second {
360
-		return first, second
361
-	} else {
362
-		return second, first
363
-	}
364
-}
365
-
366
-func (mysql *MySQL) AddDirectMessage(sender, recipient string, senderPersistent, recipientPersistent bool, item history.Item) (err error) {
357
+func (mysql *MySQL) AddDirectMessage(sender, senderAccount, recipient, recipientAccount string, item history.Item) (err error) {
367
 	if mysql.db == nil {
358
 	if mysql.db == nil {
368
 		return
359
 		return
369
 	}
360
 	}
370
 
361
 
371
-	if !(senderPersistent || recipientPersistent) {
362
+	if senderAccount == "" && recipientAccount == "" {
372
 		return
363
 		return
373
 	}
364
 	}
374
 
365
 
384
 		return
375
 		return
385
 	}
376
 	}
386
 
377
 
387
-	if senderPersistent {
388
-		mysql.insertSequenceEntry(ctx, sender, item.Message.Time, id)
378
+	nanotime := item.Message.Time.UnixNano()
379
+
380
+	if senderAccount != "" {
381
+		err = mysql.insertSequenceEntry(ctx, senderAccount, nanotime, id)
382
+		if err != nil {
383
+			return
384
+		}
385
+		err = mysql.insertConversationEntry(ctx, senderAccount, recipient, nanotime, id)
389
 		if err != nil {
386
 		if err != nil {
390
 			return
387
 			return
391
 		}
388
 		}
392
 	}
389
 	}
393
 
390
 
394
-	if recipientPersistent && sender != recipient {
395
-		err = mysql.insertSequenceEntry(ctx, recipient, item.Message.Time, id)
391
+	if recipientAccount != "" && sender != recipient {
392
+		err = mysql.insertSequenceEntry(ctx, recipientAccount, nanotime, id)
393
+		if err != nil {
394
+			return
395
+		}
396
+		err = mysql.insertConversationEntry(ctx, recipientAccount, sender, nanotime, id)
396
 		if err != nil {
397
 		if err != nil {
397
 			return
398
 			return
398
 		}
399
 		}
399
 	}
400
 	}
400
 
401
 
401
-	err = mysql.insertConversationEntry(ctx, sender, recipient, item.Message.Time, id)
402
-
403
 	return
402
 	return
404
 }
403
 }
405
 
404
 
453
 	return
452
 	return
454
 }
453
 }
455
 
454
 
456
-func (mysql *MySQL) betweenTimestamps(ctx context.Context, sender, recipient string, after, before, cutoff time.Time, limit int) (results []history.Item, err error) {
457
-	useSequence := true
458
-	var lowerTarget, upperTarget string
459
-	if sender != "" {
460
-		lowerTarget, upperTarget = stringMinMax(sender, recipient)
461
-		useSequence = false
462
-	}
463
-
455
+func (mysql *MySQL) betweenTimestamps(ctx context.Context, target, correspondent string, after, before, cutoff time.Time, limit int) (results []history.Item, err error) {
456
+	useSequence := correspondent == ""
464
 	table := "sequence"
457
 	table := "sequence"
465
 	if !useSequence {
458
 	if !useSequence {
466
 		table = "conversations"
459
 		table = "conversations"
479
 		"SELECT history.data from history INNER JOIN %[1]s ON history.id = %[1]s.history_id WHERE", table)
472
 		"SELECT history.data from history INNER JOIN %[1]s ON history.id = %[1]s.history_id WHERE", table)
480
 	if useSequence {
473
 	if useSequence {
481
 		fmt.Fprintf(&queryBuf, " sequence.target = ?")
474
 		fmt.Fprintf(&queryBuf, " sequence.target = ?")
482
-		args = append(args, recipient)
475
+		args = append(args, target)
483
 	} else {
476
 	} else {
484
-		fmt.Fprintf(&queryBuf, " conversations.lower_target = ? AND conversations.upper_target = ?")
485
-		args = append(args, lowerTarget)
486
-		args = append(args, upperTarget)
477
+		fmt.Fprintf(&queryBuf, " conversations.target = ? AND conversations.correspondent = ?")
478
+		args = append(args, target)
479
+		args = append(args, correspondent)
487
 	}
480
 	}
488
 	if !after.IsZero() {
481
 	if !after.IsZero() {
489
 		fmt.Fprintf(&queryBuf, " AND %s.nanotime > ?", table)
482
 		fmt.Fprintf(&queryBuf, " AND %s.nanotime > ?", table)
514
 // implements history.Sequence, emulating a single history buffer (for a channel,
507
 // implements history.Sequence, emulating a single history buffer (for a channel,
515
 // a single user's DMs, or a DM conversation)
508
 // a single user's DMs, or a DM conversation)
516
 type mySQLHistorySequence struct {
509
 type mySQLHistorySequence struct {
517
-	mysql     *MySQL
518
-	sender    string
519
-	recipient string
520
-	cutoff    time.Time
510
+	mysql         *MySQL
511
+	target        string
512
+	correspondent string
513
+	cutoff        time.Time
521
 }
514
 }
522
 
515
 
523
 func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (results []history.Item, complete bool, err error) {
516
 func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (results []history.Item, complete bool, err error) {
539
 		}
532
 		}
540
 	}
533
 	}
541
 
534
 
542
-	results, err = s.mysql.betweenTimestamps(ctx, s.sender, s.recipient, startTime, endTime, s.cutoff, limit)
535
+	results, err = s.mysql.betweenTimestamps(ctx, s.target, s.correspondent, startTime, endTime, s.cutoff, limit)
543
 	return results, (err == nil), err
536
 	return results, (err == nil), err
544
 }
537
 }
545
 
538
 
547
 	return history.GenericAround(s, start, limit)
540
 	return history.GenericAround(s, start, limit)
548
 }
541
 }
549
 
542
 
550
-func (mysql *MySQL) MakeSequence(sender, recipient string, cutoff time.Time) history.Sequence {
543
+func (mysql *MySQL) MakeSequence(target, correspondent string, cutoff time.Time) history.Sequence {
551
 	return &mySQLHistorySequence{
544
 	return &mySQLHistorySequence{
552
-		sender:    sender,
553
-		recipient: recipient,
554
-		mysql:     mysql,
555
-		cutoff:    cutoff,
545
+		target:        target,
546
+		correspondent: correspondent,
547
+		mysql:         mysql,
548
+		cutoff:        cutoff,
556
 	}
549
 	}
557
 }
550
 }

+ 17
- 17
irc/server.go ファイルの表示

862
 
862
 
863
 // Gets the abstract sequence from which we're going to query history;
863
 // Gets the abstract sequence from which we're going to query history;
864
 // we may already know the channel we're querying, or we may have
864
 // we may already know the channel we're querying, or we may have
865
-// to look it up via a string target. This function is responsible for
865
+// to look it up via a string query. This function is responsible for
866
 // privilege checking.
866
 // privilege checking.
867
-func (server *Server) GetHistorySequence(providedChannel *Channel, client *Client, target string) (channel *Channel, sequence history.Sequence, err error) {
867
+func (server *Server) GetHistorySequence(providedChannel *Channel, client *Client, query string) (channel *Channel, sequence history.Sequence, err error) {
868
 	config := server.Config()
868
 	config := server.Config()
869
 	// 4 cases: {persistent, ephemeral} x {normal, conversation}
869
 	// 4 cases: {persistent, ephemeral} x {normal, conversation}
870
-	// with ephemeral history, recipient is implicit in the choice of `hist`,
871
-	// and sender is "" if we're retrieving a channel or *, and the correspondent's name
870
+	// with ephemeral history, target is implicit in the choice of `hist`,
871
+	// and correspondent is "" if we're retrieving a channel or *, and the correspondent's name
872
 	// if we're retrieving a DM conversation ("query buffer"). with persistent history,
872
 	// if we're retrieving a DM conversation ("query buffer"). with persistent history,
873
-	// recipient is always nonempty, and sender is either empty or nonempty as before.
873
+	// target is always nonempty, and correspondent is either empty or nonempty as before.
874
 	var status HistoryStatus
874
 	var status HistoryStatus
875
-	var sender, recipient string
875
+	var target, correspondent string
876
 	var hist *history.Buffer
876
 	var hist *history.Buffer
877
 	channel = providedChannel
877
 	channel = providedChannel
878
 	if channel == nil {
878
 	if channel == nil {
879
-		if strings.HasPrefix(target, "#") {
880
-			channel = server.channels.Get(target)
879
+		if strings.HasPrefix(query, "#") {
880
+			channel = server.channels.Get(query)
881
 			if channel == nil {
881
 			if channel == nil {
882
 				return
882
 				return
883
 			}
883
 			}
888
 			err = errInsufficientPrivs
888
 			err = errInsufficientPrivs
889
 			return
889
 			return
890
 		}
890
 		}
891
-		status, recipient = channel.historyStatus(config)
891
+		status, target = channel.historyStatus(config)
892
 		switch status {
892
 		switch status {
893
 		case HistoryEphemeral:
893
 		case HistoryEphemeral:
894
 			hist = &channel.history
894
 			hist = &channel.history
895
 		case HistoryPersistent:
895
 		case HistoryPersistent:
896
-			// already set `recipient`
896
+			// already set `target`
897
 		default:
897
 		default:
898
 			return
898
 			return
899
 		}
899
 		}
900
 	} else {
900
 	} else {
901
-		status, recipient = client.historyStatus(config)
902
-		if target != "*" {
903
-			sender, err = CasefoldName(target)
901
+		status, target = client.historyStatus(config)
902
+		if query != "*" {
903
+			correspondent, err = CasefoldName(query)
904
 			if err != nil {
904
 			if err != nil {
905
 				return
905
 				return
906
 			}
906
 			}
909
 		case HistoryEphemeral:
909
 		case HistoryEphemeral:
910
 			hist = &client.history
910
 			hist = &client.history
911
 		case HistoryPersistent:
911
 		case HistoryPersistent:
912
-			// already set `recipient`, and `sender` if necessary
912
+			// already set `target`, and `correspondent` if necessary
913
 		default:
913
 		default:
914
 			return
914
 			return
915
 		}
915
 		}
931
 	}
931
 	}
932
 
932
 
933
 	if hist != nil {
933
 	if hist != nil {
934
-		sequence = hist.MakeSequence(sender, cutoff)
935
-	} else if recipient != "" {
936
-		sequence = server.historyDB.MakeSequence(sender, recipient, cutoff)
934
+		sequence = hist.MakeSequence(correspondent, cutoff)
935
+	} else if target != "" {
936
+		sequence = server.historyDB.MakeSequence(target, correspondent, cutoff)
937
 	}
937
 	}
938
 	return
938
 	return
939
 }
939
 }

読み込み中…
キャンセル
保存