init
This commit is contained in:
@@ -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"]
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
Executable
+41
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNotInternal(t *testing.T) {
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user