package server import ( "be-vpn/internal/dto" "be-vpn/internal/model" "be-vpn/internal/storage" "github.com/gin-gonic/gin" "log" "math/rand" "net/http" "strconv" "sync" "time" ) var nodes = make([]*model.Node, 0) var locker = sync.RWMutex{} var totalFreeDuration = uint64((time.Hour * 1).Milliseconds() / 1000) func Config(c *gin.Context) { deviceId := c.Query("deviceId") usedDuration, err := storage.GetUsedDuration(deviceId) if err != nil { dto.Error(c, err) return } c.JSON(http.StatusOK, dto.ConfigResponse{ Response: dto.NewOkResponse(), Data: dto.ConfigResult{ FreeTrialDuration: totalFreeDuration - usedDuration, Timestamp: time.Now().Unix(), Node: convert2DtoNode(healthNodes()[0]), }, }) } func AddUsedDuration(c *gin.Context) { deviceId := c.Query("deviceId") usedDurationStr := c.Query("usedDuration") log.Printf("deviceId: %s, usedDuration: %s", deviceId, usedDurationStr) usedDuration, err := strconv.ParseUint(usedDurationStr, 10, 64) if err != nil { dto.Error(c, err) return } if existed, err := storage.AddUsedDuration(deviceId, usedDuration); err != nil { dto.Error(c, err) return } else { freeTrialDuration := totalFreeDuration - existed if freeTrialDuration > totalFreeDuration || freeTrialDuration < 0 { freeTrialDuration = 0 } c.JSON(http.StatusOK, dto.ConfigResponse{ Response: dto.NewOkResponse(), Data: dto.ConfigResult{ FreeTrialDuration: freeTrialDuration, Timestamp: time.Now().Unix(), Node: convert2DtoNode(healthNodes()[0]), }, }) } } func Register(c *gin.Context) { locker.Lock() defer locker.Unlock() var request dto.RegisterRequest if err := c.ShouldBindJSON(&request); err != nil { dto.BadRequest(c, err) return } for _, node := range nodes { if node.Ip == request.Ip { node.Ip = request.Ip node.Secret = request.Secret node.CountryCode = request.CountryCode node.CountryName = request.CountryName node.LastUpdateTime = time.Now() c.JSON(http.StatusOK, dto.RegisterResponse{ Response: dto.NewOkResponse(), Data: dto.RegisterResult{ Success: true, }, }) return } } node := &model.Node{ Ip: request.Ip, Secret: request.Secret, LastUpdateTime: time.Now(), } nodes = append(nodes, node) log.Printf("update nodes: %+v", nodes) } func List(c *gin.Context) { locker.RLock() defer locker.RUnlock() dtoNodes := make([]dto.Node, 0) for _, node := range healthNodes() { dtoNodes = append(dtoNodes, convert2DtoNode(node)) } c.JSON(http.StatusOK, dto.ListResponse{ Response: dto.NewOkResponse(), Data: dtoNodes, }) } func SecretRandom(c *gin.Context) { locker.RLock() defer locker.RUnlock() random := rand.Intn(len(nodes)) for i, node := range nodes { if i == random { c.Header("Content-Disposition", "attachment; filename=client.ovpn") c.Data(http.StatusOK, "plain/text", []byte(node.Secret)) return } } c.JSON(http.StatusNotFound, gin.H{ "message": "not found", }) } func Secret(c *gin.Context) { locker.RLock() defer locker.RUnlock() var request dto.DetailRequest if err := c.ShouldBindQuery(&request); err != nil { dto.BadRequest(c, err) return } for _, node := range nodes { if node.Ip == request.Ip { //secret, err := util.AesEncrypt([]byte(node.Secret)) //if err != nil { // dto.Error(c, err) // return //} c.Header("Content-Disposition", "attachment; filename=client.ovpn") c.Data(http.StatusOK, "plain/text", []byte(node.Secret)) return } } c.JSON(http.StatusNotFound, gin.H{ "message": "not found ip", }) } func Health(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "up"}) } func healthNodes() []*model.Node { healthNodes := make([]*model.Node, 0) for _, node := range nodes { if node.LastUpdateTime.Add(10 * time.Second).After(time.Now()) { healthNodes = append(healthNodes, node) } } return healthNodes } func convert2DtoNode(node *model.Node) dto.Node { icon := "" if node.CountryCode == "BR" { icon = "http://v.starttransfernow.com/static/BR.jpg" } else if node.CountryCode == "DE" { icon = "http://v.starttransfernow.com/static/DE.jpg" } else if node.CountryCode == "HK" { icon = "http://v.starttransfernow.com/static/HK.jpg" } else if node.CountryCode == "JA" { icon = "http://v.starttransfernow.com/static/JA.jpg" } else if node.CountryCode == "US" { icon = "http://v.starttransfernow.com/static/US.jpg" } return dto.Node{ Ip: node.Ip, CountryCode: node.CountryCode, CountryName: node.CountryName, Icon: icon, //Icon: "https://img.zcool.cn/community/010a5a57dbc2140000018c1b0a9b5f.png", } }