This commit is contained in:
arraykeys
2019-08-08 17:13:34 +08:00
parent e8e5966a8c
commit f0bf2d5fec
2885 changed files with 1195993 additions and 12 deletions
+148
View File
@@ -0,0 +1,148 @@
package main
import (
"log"
"time"
"github.com/astaxie/beego"
)
//定时锁定流量用完的用户
func InitUserTrafficLocker() {
go func() {
log.Printf("user traffic monitor is running")
sleep := beego.AppConfig.DefaultInt("user.scan.round.sleep.seconds", 60)
lastID := "0"
pagesize := beego.AppConfig.DefaultInt("user.scan.pagesize", 100)
for {
sql := db.AR().Select("user_id").From("user").Where(map[string]interface{}{
"user_id >": lastID,
"is_active": 1,
"is_forbidden": 0,
}).Limit(pagesize).OrderBy("user_id", "asc")
rs, err := db.Query(sql)
if err != nil {
log.Printf("query user ERR:%s", err)
time.Sleep(time.Second * 30)
continue
}
for _, userID := range rs.Values("user_id") {
if userIsNoTraffic(userID) {
killUser(userID, false, "")
}
lastID = userID
}
if rs.Len() == 0 {
lastID = "0"
time.Sleep(time.Second * time.Duration(sleep))
}
}
}()
}
//定时清理无效的conn信息
func InitConnCleaner() {
go func() {
log.Printf("conn cleaner is running")
for {
db.Exec(db.AR().Delete("conn", map[string]interface{}{
"update_time <": time.Now().Unix() - 300,
}))
time.Sleep(time.Second * time.Duration(beego.AppConfig.DefaultInt("conn.scan.round.sleep.seconds", 300)))
}
}()
}
//定时清理异常的隧道
func InitTunnelCleaner() {
go func() {
log.Printf("tunnel cleaner is running")
sleep := beego.AppConfig.DefaultInt("tunnel.scan.round.sleep.seconds", 300)
lastID := "0"
pagesize := beego.AppConfig.DefaultInt("tunnel.scan.pagesize", 300)
for {
updateData := []map[string]interface{}{}
sql := db.AR().Select("server_id,client_id,cluster_id,tunnel_id").From("tunnel").Where(map[string]interface{}{
"tunnel_id >": lastID,
"is_open": 1,
"is_delete": 0,
}).Limit(pagesize).OrderBy("tunnel_id", "asc")
rs, err := db.Query(sql)
if err != nil {
log.Printf("query tunnel ERR:%s", err)
time.Sleep(time.Second * 30)
continue
}
if rs.Len() == 0 {
lastID = "0"
time.Sleep(time.Second * time.Duration(sleep))
}
for _, row := range rs.Rows() {
if !csIsOnline(row["server_id"], "server") || !csIsOnline(row["client_id"], "client") {
err := killTunnel(row["tunnel_id"], row["cluster_id"])
if err == nil {
updateData = append(updateData, map[string]interface{}{
"tunnel_id": row["tunnel_id"],
"is_open": 0,
"status": 0,
})
}
}
if len(updateData) > 0 {
sql := db.AR().UpdateBatch("tunnel", updateData, []string{"tunnel_id"})
rs, err = db.Exec(sql)
if err != nil {
log.Printf("update tunnel ERR:%s", err)
time.Sleep(time.Second * 30)
continue
}
}
lastID = row["tunnel_id"]
}
}
}()
}
//定时清理异常的online
func InitOnlineCleaner() {
go func() {
log.Printf("online cleaner is running")
sleep := beego.AppConfig.DefaultInt("online.scan.round.sleep.seconds", 300)
lastID := "0"
pagesize := beego.AppConfig.DefaultInt("online.scan.pagesize", 300)
for {
deleteData := []string{}
sql := db.AR().Select("cluster_id,cs_id,cs_type,online_id").From("online").Where(map[string]interface{}{
"online_id >": lastID,
}).Limit(pagesize).OrderBy("online_id", "asc")
rs, err := db.Query(sql)
if err != nil {
log.Printf("query online ERR:%s", err)
time.Sleep(time.Second * 30)
continue
}
if rs.Len() == 0 {
lastID = "0"
time.Sleep(time.Second * time.Duration(sleep))
}
for _, row := range rs.Rows() {
if !csIsOnCluster(row["cluster_id"], row["cs_id"], row["cs_type"]) {
deleteData = append(deleteData, row["online_id"])
}
if len(deleteData) > 0 {
sql := db.AR().Delete("online", map[string]interface{}{
"online_id": deleteData,
})
rs, err = db.Exec(sql)
if err != nil {
log.Printf("delete online ERR:%s", err)
time.Sleep(time.Second * 30)
continue
}
log.Printf("clean online %v", deleteData)
}
lastID = row["online_id"]
}
}
}()
}
+41
View File
@@ -0,0 +1,41 @@
runmode = "${UMSMODE||dev}"
cluster.api.port=37080
db_port="3306"
db_conn_max_idle=30
db_conn_max_connection=50
user.scan.round.sleep.seconds=120
user.scan.pagesize=100
tunnel.scan.round.sleep.seconds=80
tunnel.scan.pagesize=100
online.scan.round.sleep.seconds=100
online.scan.pagesize=100
conn.scan.round.sleep.seconds=60
#database system
db_name="anytunnel_system"
db_table_prefix="system_"
#database base
db.base.name="anytunnel_base"
db.base.table_prefix="at_"
[dev]
db_host="10.69.213.221"
db_user="admin_user"
db_pass="a9BAECadminD3056D83"
[mac]
db_host="127.0.0.1"
db_user="root"
db_pass="root"
[prod]
db_host="10.69.213.221"
db_user="admin_user"
db_pass="a9BAECadminD3056D83"
+225
View File
@@ -0,0 +1,225 @@
package main
import (
utils "anytunnel/at-common"
"encoding/json"
"fmt"
"log"
"strconv"
"time"
"github.com/astaxie/beego"
)
func userIsNoTraffic(userID string) bool {
now := time.Now().Unix()
rs, err := db.Query(db.AR().Select("user_id").From("package").Where(map[string]interface{}{
"user_id": userID,
"start_time <": now,
"end_time >": now,
"bytes_left >": 0,
}).Limit(1))
if err != nil {
log.Printf("query user package ERR:%s", err)
return false
}
return rs.Len() == 0
}
func killUser(userID string, forbidden bool, reason string) {
//log.Printf("kill user : %s", userID)
//1.kill all user's online server
rs, err := db.Query(db.AR().Select("cs_id,cluster_id").From("online").Where(map[string]interface{}{
"user_id": userID,
"cs_type": "server",
}))
if err != nil {
return
}
allOnlineServerIDs := rs.Rows()
for _, online := range allOnlineServerIDs {
killCS(online["cluster_id"], online["cs_id"], true)
}
//2.kill all user's online client
rs, err = db.Query(db.AR().Select("cs_id,cluster_id").From("online").Where(map[string]interface{}{
"user_id": userID,
"cs_type": "client",
}))
if err != nil {
return
}
allOnlineClientIDs := rs.Rows()
for _, online := range allOnlineClientIDs {
killCS(online["cluster_id"], online["cs_id"], false)
}
//3.kill all user's online tunnel
killUserTunnel(userID)
//4.if user forbidden or not
if forbidden {
_, err := db.Exec(db.AR().Update("user", map[string]interface{}{"is_forbidden": 1, "forbidden_reason": reason}, map[string]interface{}{"user_id": userID}))
if err != nil {
return
}
}
}
func killCS(clusterID, csID string, isServer bool) (err error) {
typ := "server"
if !isServer {
typ = "client"
}
log.Printf("kill %s : %s", typ, csID)
rs, err := db.Query(db.AR().From("cluster").Where(map[string]interface{}{"is_delete": 0}))
if err != nil {
return
}
if rs.Len() == 0 {
err = fmt.Errorf("empty cluster for cluster_id:%s", clusterID)
return
}
cluster := rs.Row()
rs, err = db.Query(db.AR().From(typ).Where(map[string]interface{}{
typ + "_id": csID,
"is_delete": 0,
}))
if err != nil {
return
}
if rs.Len() == 0 {
err = fmt.Errorf("empty %s for %s_id:%s", typ, typ, csID)
return
}
item := rs.Row()
url := fmt.Sprintf("https://%s:%s/%s/offline/%s", cluster["ip"], beego.AppConfig.String("cluster.api.port"), typ, item["token"])
body, code, err := utils.HttpGet(url)
if err != nil {
log.Printf("kill server fail,code: %d,body: %s ,ERR: %s ", code, string(body), err)
}
return
}
func killUserTunnel(userID string) {
rs, err := db.Query(db.AR().From("conn").Where(map[string]interface{}{"user_id": userID}))
if err != nil {
return
}
if rs.Len() == 0 {
//err = fmt.Errorf("killUserTunnel , empty tunnel for user_id:%s", userID)
return
}
for _, conn := range rs.Rows() {
log.Printf("kill tunnel:%s , userID: %s", conn["tunnel_id"], userID)
rs, err = db.Query(db.AR().From("cluster").Where(map[string]interface{}{
"cluster_id": conn["cluster_id"],
"is_delete": 0,
}))
if err != nil {
return
}
if rs.Len() == 0 {
//err = fmt.Errorf("killUserTunnel , empty cluster for cluster_id:%s", conn["cluster_id"])
return
}
cluster := rs.Row()
url := fmt.Sprintf("https://%s:%s/port/close/%s", cluster["ip"], beego.AppConfig.String("cluster.api.port"), conn["tunnel_id"])
body, code, err := utils.HttpGet(url)
if err != nil {
log.Printf("kill tunnel fail,code: %d,body: %s ,ERR: %s ", code, string(body), err)
return
}
}
db.Exec(db.AR().Delete("conn", map[string]interface{}{
"user_id": userID,
}))
}
func csIsOnline(csID, csType string) bool {
rs, err := db.Query(db.AR().From("online").Where(map[string]interface{}{
"cs_id": csID,
"cs_type": csType,
}))
if err != nil {
return false
}
return rs.Len() == 1
}
func killTunnel(tunnelID, clusterID string) (err error) {
rs, err := db.Query(db.AR().From("cluster").Where(map[string]interface{}{
"cluster_id": clusterID,
"is_delete": 0,
}))
if err != nil {
log.Printf("kill tunnel fail,ERR:%s", err)
return
}
if rs.Len() == 0 {
return
}
cluster := rs.Row()
url := fmt.Sprintf("https://%s:%s/port/close/%s", cluster["ip"], beego.AppConfig.String("cluster.api.port"), tunnelID)
body, code, err := utils.HttpGet(url)
if err != nil {
log.Printf("kill tunnel fail,code: %d,body: %s ,ERR: %s ", code, string(body), err)
return
}
return
}
func GetCS(csID, csType string) (row map[string]string, err error) {
rs, err := db.Query(db.AR().From(csType).Where(map[string]interface{}{
csType + "_id": csID,
"is_delete": 0,
}))
if err != nil {
log.Printf("query %s fail,ERR:%s", csType, err)
return
}
if rs.Len() == 0 {
err = fmt.Errorf("%s not exists", csType)
return
}
row = rs.Row()
return
}
func GetCluster(clusterID string) (row map[string]string, err error) {
rs, err := db.Query(db.AR().From("cluster").Where(map[string]interface{}{
"cluster_id": clusterID,
"is_delete": 0,
}))
if err != nil {
log.Printf("query clusterfail,ERR:%s", err)
return
}
if rs.Len() == 0 {
err = fmt.Errorf("cluster not exists ,clusterID:%s", clusterID)
return
}
row = rs.Row()
return
}
func csIsOnCluster(clusterID, csID, csType string) (exists bool) {
cluster, err := GetCluster(clusterID)
if err != nil {
return
}
cs, err := GetCS(csID, csType)
if err != nil {
return
}
url := fmt.Sprintf("https://%s:%s/%s/status/%s", cluster["ip"], beego.AppConfig.String("cluster.api.port"), csType, cs["token"])
body, code, err := utils.HttpGet(url)
if err != nil {
log.Printf("get %s status fail,code: %d,body: %s ,ERR: %s ", csType, code, string(body), err)
return
}
res := map[string]interface{}{}
err = json.Unmarshal(body, &res)
if err != nil {
log.Printf("parse csIsOnCluster result ERR:%s,body:%s", err, string(body))
}
respCode, err := strconv.ParseUint(fmt.Sprintf("%.0f", res["code"]), 10, 64)
if err != nil {
return
}
return respCode == 1
}
+19
View File
@@ -0,0 +1,19 @@
package main
import (
"anytunnel/at-admin/app/models"
)
var db = models.G.DB("base")
func main() {
//定时清理无效的conn信息
InitConnCleaner()
//定时关闭异常的隧道
InitTunnelCleaner()
//定时清理异常的online
InitOnlineCleaner()
//定时锁定流量用完的用户
InitUserTrafficLocker()
select {}
}
+12
View File
@@ -0,0 +1,12 @@
package main
import (
"log"
"os"
"testing"
)
func TestNotInternal(t *testing.T) {
log.SetOutput(os.Stdout)
}