This repository has been archived by the owner on Jul 15, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tempbanmanager.go
167 lines (133 loc) · 3.48 KB
/
tempbanmanager.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
package tempban
import (
"encoding/gob"
"errors"
"io"
"github.com/icedream/vpnbot/debug/sync"
"github.com/fluffle/goirc/logging"
)
var currentExportVersion = uint64(0x0)
type TemporaryBanExport struct {
Bans []TemporaryBan
}
type TemporaryBanManager struct {
data *TemporaryBanExport
dataSync *sync.RWMutex
banRemovalTrigger map[TemporaryBan]chan interface{}
BanExpiredFunc func(TemporaryBan)
DisableExpiry bool
}
func (tbmgr *TemporaryBanManager) onBanExpired(ban TemporaryBan) {
f := tbmgr.BanExpiredFunc
if f != nil {
f(ban)
}
}
func (tbmgr *TemporaryBanManager) GetAll() []TemporaryBan {
tbmgr.dataSync.RLock()
defer tbmgr.dataSync.RUnlock()
return tbmgr.data.Bans
}
func (tbmgr *TemporaryBanManager) Get(hostmask string) (TemporaryBan, bool) {
tbmgr.dataSync.RLock()
defer tbmgr.dataSync.RUnlock()
return tbmgr.getNoLock(hostmask)
}
func (tbmgr *TemporaryBanManager) getNoLock(hostmask string) (foundBan TemporaryBan, ok bool) {
for _, ban := range tbmgr.data.Bans {
if ban.Hostmask == hostmask {
foundBan = ban
ok = true
return
}
}
return
}
func (tbmgr *TemporaryBanManager) Add(ban TemporaryBan) error {
tbmgr.dataSync.Lock()
defer tbmgr.dataSync.Unlock()
if _, ok := tbmgr.getNoLock(ban.Hostmask); ok {
return ErrHostmaskAlreadyBanned
}
tbmgr.data.Bans = append(tbmgr.data.Bans, ban)
if !tbmgr.DisableExpiry {
tbmgr.handleBan(&ban)
}
return nil
}
func (tbmgr *TemporaryBanManager) handleBan(banPtr *TemporaryBan) {
ban := *banPtr
banRemovalTriggerChan := make(chan interface{})
tbmgr.banRemovalTrigger[ban] = banRemovalTriggerChan
go func() {
select {
case <-ban.WaitUntilExpired(): // expired
ban, _ := tbmgr.Remove(ban.Hostmask)
tbmgr.onBanExpired(ban)
case _, _ = <-banRemovalTriggerChan: // manually removed
}
delete(tbmgr.banRemovalTrigger, ban)
}()
}
func (tbmgr *TemporaryBanManager) Remove(hostmask string) (foundBan TemporaryBan, deleted bool) {
tbmgr.dataSync.Lock()
defer tbmgr.dataSync.Unlock()
for index, ban := range tbmgr.data.Bans {
if ban.Hostmask == hostmask {
close(tbmgr.banRemovalTrigger[ban])
tbmgr.data.Bans = append(tbmgr.data.Bans[0:index], tbmgr.data.Bans[index+1:]...)
foundBan = ban
deleted = true
return
}
}
return
}
func NewTemporaryBanManager() *TemporaryBanManager {
return &TemporaryBanManager{
data: new(TemporaryBanExport),
dataSync: &sync.RWMutex{},
banRemovalTrigger: make(map[TemporaryBan]chan interface{}),
}
}
func (tbmgr *TemporaryBanManager) Import(r io.Reader) error {
tbmgr.dataSync.Lock()
defer tbmgr.dataSync.Unlock()
decoder := gob.NewDecoder(r)
var exportVersion uint64
if err := decoder.Decode(&exportVersion); err != nil {
return err
}
switch exportVersion {
case 0x0:
// Structure:
// - Bans = []*TemporaryBan
if err := decoder.Decode(tbmgr.data); err != nil {
return err
}
default:
return errors.New("Invalid version found in input data")
}
// Run background handler for each temporary ban
if !tbmgr.DisableExpiry {
for _, ban := range tbmgr.data.Bans {
tbmgr.handleBan(&ban)
}
}
logging.Info("Imported %v bans.", len(tbmgr.data.Bans))
return nil
}
func (tbmgr *TemporaryBanManager) Export(w io.Writer) error {
tbmgr.dataSync.RLock()
defer tbmgr.dataSync.RUnlock()
encoder := gob.NewEncoder(w)
if err := encoder.Encode(currentExportVersion); err != nil {
return err
}
// Structure:
// - Bans = []*TemporaryBan
if err := encoder.Encode(tbmgr.data); err != nil {
return err
}
return nil
}