-
Notifications
You must be signed in to change notification settings - Fork 0
/
penalize.go
187 lines (163 loc) · 5 KB
/
penalize.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package main
import (
"database/sql"
"github.com/captainzidgel/rgl"
"log"
"time"
)
/*
Bans and penalties (penalties are a subset of bans)
A ban prevents a user from que-ing.
A penalty prevents a user from que-ing in reaction to a bait or ragequit. It falls off over shorter periods of time.
A ban that is not a penalty is a reaction to an RGL ban for cheating or harassment or something of the sort. Most likely permanent.
*/
var SelectBan *sql.Stmt
var UpdateBan *sql.Stmt
const dayDur = time.Hour * 24
const weekDur = dayDur * 7
type ban struct {
steamid string
expires time.Time
banLevel int //should be -1 if you're banned for being a cheater and >= 0 for being a baiter
lastOffence *time.Time
}
//Get a ban from the database and return a pointer to it
func getBan(steamid string) *ban {
player, err := getRGLSummary(steamid)
if err != nil {
log.Printf("Err GETting RGL summary: %v\n", err)
return nil
}
if player != (rgl.Player{}) {
rban := getRGLBan(player)
if rban != nil { //RGL bans 'supercede' leveled bans, don't search for one
rban.commitBan()
return rban
}
}
b, err := selectBanMethod(steamid)
if err != nil {
if err != sql.ErrNoRows {
log.Printf("Err selecting ban: %v\n", err)
return nil
} else { //Received No Rows in sql, not banned
return nil
}
}
return b
}
func getRGLBan(player rgl.Player) *ban {
if player.Ban == nil {
return nil
} else {
return &ban{
steamid: player.SteamId,
expires: rgl.ToGoTime(player.Ban.Ends),
banLevel: -1,
lastOffence: nil,
}
}
}
//This variable can be overwritten in a test to replace time.Now() with whatever time we want
var now = time.Now
//Create a new ban struct with a level of -1 or 0 and apply the penalty if 0.
func createBan(steamid string, leveled bool) *ban {
b := &ban{steamid: steamid}
if leveled {
t := now()
b.lastOffence = &t
b.expires = b.lastOffence.Add(expireLadder[0])
} else {
b.banLevel = -1
}
b.commitBan()
return b
}
var expireLadder = [7]time.Duration{30 * time.Minute, 1 * time.Hour, 4 * time.Hour, 1 * dayDur, 2 * dayDur, 3 * dayDur, 1 * weekDur}
func (ban *ban) isActive() bool {
return now().Before(ban.expires)
}
//Take a ban, calculate weeks since last offence, add a new penalty at the appropriate level.
func (ban *ban) newPenalty() {
if ban.banLevel == -1 {
return
}
d := now().Sub(*ban.lastOffence) //the amount of time elapsed since last offence
weeksSince := int(d.Hours() / 24 / 7) //Convert d to an exact (float) value of weeks, then floor it by casting to int.
if weeksSince == 0 { //Penalized within a week of last offence
ban.banLevel = ban.banLevel + 1 //Go to next tier
} else { //Congrats sailor, you went at least a week without offending
ban.banLevel = clamp(ban.banLevel-weeksSince, 0, 7) //If you're at tier x and it's been y weeks since last offence, your new offence will be at tier x-y.
}
t := now()
ban.lastOffence = &t
ban.expires = ban.lastOffence.Add(expireLadder[ban.banLevel])
ban.commitBan() //write to database
}
func (b *ban) commitBan() {
expire_epoch := b.expires.Unix()
var lastoff_epoch int64
if b.banLevel > -1 {
lastoff_epoch = b.lastOffence.Unix()
} else {
lastoff_epoch = 0
}
err := updateBanMethod(b.steamid, expire_epoch, b.banLevel, lastoff_epoch)
if err != nil {
log.Fatalf("Error updating ban %v", err)
}
bruh := b.expires.Sub(now())
log.Println("Sanity check", b.steamid, b.expires.Sub(now()))
ok := banCache.SetWithTTL("ban"+b.steamid, *b, 1, bruh)
if !ok {
log.Println("Warning: Couldn't set cache at ban commit")
}
}
func punishDelinquents(steam64s []string) {
for _, id := range steam64s {
b := checkBanCache(id)
if b == nil {
b = createBan(id, true)
} else {
b.newPenalty()
}
log.Printf("Banning user %s until %v (%f hours) for baiting/quitting\n", id, b.expires, b.expires.Sub(now()).Hours())
}
}
var selectBanMethod func(steamid string) (*ban, error)
var updateBanMethod func(steamid string, exp_epoch int64, blvl int, lastoff int64) error
var testBanSlice = make([]*ban, 0)
func updateBanSql(steamid string, exp_epoch int64, blvl int, lastoff int64) error {
_, err := UpdateBan.Exec(steamid, exp_epoch, blvl, lastoff)
return err
}
func updateBanMock(steamid string, exp_epoch int64, blvl int, lastoff int64) error {
ti := time.Unix(lastoff, 0)
testBanSlice = append(testBanSlice, &ban{steamid: steamid, expires: time.Unix(exp_epoch, 0), banLevel: blvl, lastOffence: &ti})
return nil
}
func selectBanSql(steamid string) (*ban, error) {
var expire_epoch int64
var lastOffence_epoch int64
var level int
err := SelectBan.QueryRow(steamid).Scan(&expire_epoch, &level, &lastOffence_epoch)
if err != nil {
return nil, err
}
lo := time.Unix(lastOffence_epoch, 0)
b := &ban{
steamid: steamid,
expires: time.Unix(expire_epoch, 0),
banLevel: level,
lastOffence: &lo,
}
return b, nil
}
func selectBanMock(steamid string) (*ban, error) {
for _, b := range testBanSlice {
if b.steamid == steamid {
return b, nil
}
}
return nil, sql.ErrNoRows
}