@@ -5,15 +5,19 @@ const similarity = require('../chat-utils/string-similarity');
5
5
// and then a simple formula to get the change in %
6
6
7
7
class ChatCache {
8
- constructor ( config ) {
8
+ constructor ( config , messageMatching ) {
9
+ this . messageMatching = messageMatching ;
9
10
this . messsagesToKeepPerUser = config . messsagesToKeepPerUser || 2 ;
10
11
this . maxMessagesInList = config . maxMessagesInList || 2000 ;
11
12
this . timeToLive = config . timeToLiveSeconds || 1800 ;
12
13
this . tombStoneInterval = config . tomeStoneIntervalMilliseconds || 120000 ;
13
14
this . rateLimitMaxMessages = config . rateLimitMaxMessages || 4 ;
14
15
this . rateLimitSecondsToRefresh = config . rateLimitSecondsToRefresh || 3 ;
15
16
this . viewerMessageMinimumLength = config . viewerMessageMinimumLength || 20 ;
17
+ this . messageUrlSpamSeconds = config . messageUrlSpamSeconds || 600 ;
18
+ this . messageUrlSpamUser = config . messageUrlSpamUser || null ;
16
19
this . viewerMap = { } ;
20
+ this . viewerUrlMap = { } ;
17
21
this . rateLimitMap = { } ;
18
22
this . runningMessageList = [ ] ;
19
23
this . tombStoneMap = { } ;
@@ -27,10 +31,18 @@ class ChatCache {
27
31
}
28
32
29
33
tombStoneCleanup ( ) {
30
- if ( _ . isEmpty ( this . tombStoneMap ) ) {
31
- return ;
32
- }
33
34
const now = moment ( ) . unix ( ) ;
35
+
36
+ _ . forIn ( this . viewerUrlMap , ( urls , user ) => {
37
+ const filteredOldUrls = urls . filter ( ( link ) => now - link . exp < this . messageUrlSpamSeconds ) ;
38
+ if ( filteredOldUrls . length === 0 ) {
39
+ delete this . viewerUrlMap [ user ] ;
40
+ } else {
41
+ this . viewerUrlMap [ user ] = filteredOldUrls ;
42
+ }
43
+ } ) ;
44
+
45
+ if ( _ . isEmpty ( this . tombStoneMap ) ) return ;
34
46
_ . forIn ( this . tombStoneMap , ( value , key ) => {
35
47
if ( now - value >= this . timeToLive ) {
36
48
delete this . tombStoneMap [ key ] ;
@@ -44,6 +56,7 @@ class ChatCache {
44
56
if ( message . length >= this . viewerMessageMinimumLength ) {
45
57
this . addMessageToViewerMap ( user , message ) ;
46
58
}
59
+ this . addMessageToViewerUrlMap ( user , message ) ;
47
60
this . addMessageToRunningList ( user , message ) ;
48
61
this . addMessageToRateLimitMap ( user ) ;
49
62
}
@@ -62,6 +75,31 @@ class ChatCache {
62
75
this . tombStoneMap [ user ] = moment ( ) . unix ( ) ;
63
76
}
64
77
78
+ addMessageToViewerUrlMap ( user , message ) {
79
+ if (
80
+ this . messageUrlSpamUser &&
81
+ ! this . messageMatching . mentionsUser ( message , this . messageUrlSpamUser )
82
+ ) {
83
+ return ;
84
+ }
85
+ this . messageMatching . getLinks ( message ) . forEach ( ( link ) => {
86
+ if ( ! _ . has ( this . viewerUrlMap , user ) ) this . viewerUrlMap [ user ] = [ ] ;
87
+ this . viewerUrlMap [ user ] . push ( {
88
+ url : link . hostname + link . pathname ,
89
+ exp : moment ( ) . unix ( ) ,
90
+ } ) ;
91
+ } ) ;
92
+ }
93
+
94
+ getViewerUrlList ( user ) {
95
+ if ( ! user || ! _ . has ( this . viewerUrlMap , user ) ) return [ ] ;
96
+ const now = moment ( ) . unix ( ) ;
97
+ const filteredOldUrls = this . viewerUrlMap [ user ]
98
+ . filter ( ( link ) => now - link . exp < this . messageUrlSpamSeconds )
99
+ . map ( ( link ) => link . url ) ;
100
+ return filteredOldUrls ;
101
+ }
102
+
65
103
isPastRateLimit ( user ) {
66
104
const lastMessages = this . rateLimitMap [ user ] ;
67
105
if ( lastMessages . length === this . rateLimitMaxMessages ) {
0 commit comments