|
@@ -1,231 +0,0 @@
|
|
|
-package server
|
|
|
-
|
|
|
-import (
|
|
|
- "be-vpn/internal/dto"
|
|
|
- "be-vpn/internal/model"
|
|
|
- "be-vpn/internal/storage"
|
|
|
- "fmt"
|
|
|
- "github.com/gin-gonic/gin"
|
|
|
- "log"
|
|
|
- "math/rand"
|
|
|
- "net/http"
|
|
|
- "sort"
|
|
|
- "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
|
|
|
- }
|
|
|
- var node *model.Node
|
|
|
- if len(healthNodes()) > 0 {
|
|
|
- node = healthNodes()[0]
|
|
|
- }
|
|
|
- freeTrialDuration := uint64(0)
|
|
|
- if usedDuration <= totalFreeDuration {
|
|
|
- freeTrialDuration = totalFreeDuration - usedDuration
|
|
|
- }
|
|
|
-
|
|
|
- c.JSON(http.StatusOK, dto.ConfigResponse{
|
|
|
- Response: dto.NewOkResponse(),
|
|
|
- Data: dto.ConfigResult{
|
|
|
- FreeTrialDuration: freeTrialDuration,
|
|
|
- Timestamp: time.Now().Unix(),
|
|
|
- Node: convert2DtoNode(node, 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], 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.City = request.City
|
|
|
- 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()
|
|
|
-
|
|
|
- nodes := healthNodes()
|
|
|
- sort.SliceStable(nodes, func(i, j int) bool {
|
|
|
- return nodes[i].CountryCode > nodes[j].CountryCode
|
|
|
- })
|
|
|
-
|
|
|
- countryLabelSeqs := make(map[string]int)
|
|
|
- dtoNodes := make([]*dto.Node, 0)
|
|
|
- for _, node := range nodes {
|
|
|
- seq, ok := countryLabelSeqs[node.CountryCode]
|
|
|
- if !ok {
|
|
|
- countryLabelSeqs[node.CountryCode] = 0
|
|
|
- } else {
|
|
|
- countryLabelSeqs[node.CountryCode] = seq + 1
|
|
|
- }
|
|
|
- dtoNodes = append(dtoNodes, convert2DtoNode(node, countryLabelSeqs[node.CountryCode]))
|
|
|
- }
|
|
|
-
|
|
|
- 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, seq int) *dto.Node {
|
|
|
- if node == nil {
|
|
|
- return nil
|
|
|
- }
|
|
|
- icons := map[string]string{
|
|
|
- "BR": "http://v.starttransfernow.com/static/BR.jpg",
|
|
|
- "DE": "http://v.starttransfernow.com/static/DE.jpg",
|
|
|
- "HK": "http://v.starttransfernow.com/static/HK.jpg",
|
|
|
- "JP": "http://v.starttransfernow.com/static/JP.jpg",
|
|
|
- "US": "http://v.starttransfernow.com/static/US.jpg",
|
|
|
- "UK": "http://v.starttransfernow.com/static/UK.jpg",
|
|
|
- "GB": "http://v.starttransfernow.com/static/UK.jpg",
|
|
|
- }
|
|
|
- countryLabels := map[string]string{
|
|
|
- "BR": "Brazil",
|
|
|
- "DE": "Germany",
|
|
|
- "HK": "Hong Kong",
|
|
|
- "JP": "Japan",
|
|
|
- "US": "United States",
|
|
|
- "UK": "United Kingdom",
|
|
|
- "GB": "United Kingdom",
|
|
|
- }
|
|
|
-
|
|
|
- return &dto.Node{
|
|
|
- Ip: node.Ip,
|
|
|
- CountryCode: node.CountryCode,
|
|
|
- CountryName: node.CountryName,
|
|
|
- City: node.City,
|
|
|
- CountryLabel: fmt.Sprintf("%s - %d", countryLabels[node.CountryCode], seq+1),
|
|
|
- Icon: icons[node.CountryCode],
|
|
|
- SecretUrl: fmt.Sprintf("http://v.starttransfernow.com/secret?ip=%s", node.Ip),
|
|
|
- }
|
|
|
-}
|