-
Notifications
You must be signed in to change notification settings - Fork 133
/
db.go
145 lines (125 loc) · 3.86 KB
/
db.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
package rotateproxy
import (
"fmt"
"os"
"strings"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
type ProxyURL struct {
gorm.Model
URL string `gorm:"uniqueIndex;column:url"`
Retry int `gorm:"column:retry"`
Available bool `gorm:"column:available"`
CanBypassGFW bool `gorm:"column:can_bypass_gfw"`
Timeout int64 `gorm:"column:timeout;default:0"`
}
func (ProxyURL) TableName() string {
return "proxy_urls"
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
func init() {
var err error
// 启动前删除缓存数据库
files := []string{
"db.db",
"db.db-shm",
"db.db-wal",
}
for _, f := range files {
if err = os.Remove(f); err != nil {
if !os.IsNotExist(err) {
panic(err)
}
}
}
// https://github.com/glebarez/sqlite/issues/52#issuecomment-1214160902
DB, err = gorm.Open(sqlite.Open("file:db.db?cache=shared&_pragma=journal_mode(WAL)&_pragma=busy_timeout(10000)"), &gorm.Config{
Logger: logger.Discard,
})
checkErr(err)
DB.AutoMigrate(&ProxyURL{})
}
func CreateProxyURL(url string) error {
tx := DB.Create(&ProxyURL{
URL: url,
Retry: 0,
Available: false,
})
return tx.Error
}
func QueryAvailProxyURL() (proxyURLs []ProxyURL, err error) {
tx := DB.Where("available = ?", true).Find(&proxyURLs)
err = tx.Error
return
}
func QueryProxyURL() (proxyURLs []ProxyURL, err error) {
tx := DB.Find(&proxyURLs)
err = tx.Error
return
}
func SetProxyURLAvail(url string, timeout int64, canBypassGFW bool) error {
tx := DB.Model(&ProxyURL{}).Where("url = ?", url).Updates(ProxyURL{
Retry: 0,
Available: true,
CanBypassGFW: canBypassGFW,
Timeout: timeout,
})
return tx.Error
}
func SetProxyURLUnavail(url string) error {
if !strings.HasPrefix(url, "socks5://") {
url = "socks5://" + url
}
// 这个语句似乎并没有将代理设置成不可用。。。
// tx := DB.Model(&ProxyURL{}).Where("url = ?", url).Updates(ProxyURL{Retry: 1, Available: 0})
tx := DB.Model(&ProxyURL{}).Where("url = ?", url).Update("available", false)
ErrorLog(Warn("Mark %v Unavailble!", url))
return tx.Error
}
func AddProxyURLRetry(url string) error {
tx := DB.Model(&ProxyURL{}).Where("url = ?", url).Update("retry", gorm.Expr("retry + 1"))
return tx.Error
}
func RandomProxyURL(regionFlag int, strategyFlag int) (pu string, err error) {
var proxyURL ProxyURL
var tx *gorm.DB
if strategyFlag == 0 {
switch regionFlag {
case 1:
tx = DB.Raw(fmt.Sprintf("SELECT * FROM %s WHERE available = ? AND can_bypass_gfw = ? ORDER BY RANDOM() LIMIT 1;", proxyURL.TableName()), true, false).Scan(&proxyURL)
case 2:
tx = DB.Raw(fmt.Sprintf("SELECT * FROM %s WHERE available = ? AND can_bypass_gfw = ? ORDER BY RANDOM() LIMIT 1;", proxyURL.TableName()), true, true).Scan(&proxyURL)
default:
tx = DB.Raw(fmt.Sprintf("SELECT * FROM %s WHERE available = 1 ORDER BY RANDOM() LIMIT 1;", proxyURL.TableName())).Scan(&proxyURL)
}
} else {
switch regionFlag {
case 1:
tx = DB.Raw(fmt.Sprintf("SELECT * FROM (SELECT * FROM %s WHERE available = 1 AND can_bypass_gfw = ? AND timeout <> 0 ORDER BY timeout LIMIT ?) TA ORDER BY RANDOM() LIMIT 1;", proxyURL.TableName()), false, strategyFlag).Scan(&proxyURL)
case 2:
tx = DB.Raw(fmt.Sprintf("SELECT * FROM (SELECT * FROM %s WHERE available = 1 AND can_bypass_gfw = ? AND timeout <> 0 ORDER BY timeout LIMIT ?) TA ORDER BY RANDOM() LIMIT 1;", proxyURL.TableName()), true, strategyFlag).Scan(&proxyURL)
default:
tx = DB.Raw(fmt.Sprintf("SELECT * FROM (SELECT * FROM %s WHERE available = 1 AND timeout <> 0 ORDER BY timeout LIMIT ?) TA ORDER BY RANDOM() LIMIT 1;", proxyURL.TableName()), strategyFlag).Scan(&proxyURL)
}
}
pu = proxyURL.URL
err = tx.Error
return pu, err
}
func CloseDB() error {
if DB == nil {
return fmt.Errorf("DB is nil")
}
db, err := DB.DB()
if err != nil {
return err
}
return db.Close()
}