reprogl

Форк
0
/
tracking.go 
141 строка · 3.2 Кб
1
package tracking
2

3
import (
4
	"errors"
5
	"fmt"
6
	"net"
7
	"net/http"
8
	"regexp"
9
	"strings"
10
	"time"
11

12
	"github.com/xelbot/yetacache"
13
	"xelbot.com/reprogl/container"
14
	"xelbot.com/reprogl/models"
15
	"xelbot.com/reprogl/models/repositories"
16
	trackmodels "xelbot.com/reprogl/utils/tracking/models"
17
)
18

19
var (
20
	regexpArticle = regexp.MustCompile(`^\/article\/(?P<slug>[^/?#]+)`)
21
	slugIndex     = regexpArticle.SubexpIndex("slug")
22
	trackingCache *yetacache.Cache[string, int8]
23
)
24

25
func init() {
26
	trackingCache = yetacache.New[string, int8](container.TrackExpiration, container.CleanUpInterval)
27
}
28

29
func CreateActivity(req *http.Request) *trackmodels.Activity {
30
	ip := net.ParseIP(container.RealRemoteAddress(req))
31
	if ip == nil {
32
		return nil
33
	}
34

35
	activity := &trackmodels.Activity{
36
		Time:         time.Now(),
37
		IsCDN:        container.IsCDN(req),
38
		Addr:         ip,
39
		UserAgent:    req.UserAgent(),
40
		RequestedURI: req.URL.RequestURI(),
41
		Method:       req.Method,
42
	}
43

44
	setupBrowserPassiveFingerprint(req, activity)
45

46
	return activity
47
}
48

49
func SaveActivity(activity *trackmodels.Activity, app *container.Application) {
50
	var (
51
		userAgentId, articleId int
52
	)
53

54
	if strings.HasPrefix(activity.RequestedURI, "/_fragment/") && activity.Status == http.StatusOK {
55
		return
56
	}
57

58
	repo := repositories.TrackingRepository{DB: app.DB}
59
	agent, err := repo.GetAgentByHash(container.MD5(activity.UserAgent))
60
	if err != nil {
61
		if errors.Is(err, models.RecordNotFound) {
62
			userAgentId, err = repo.SaveTrackingAgent(activity)
63
			if err != nil {
64
				app.LogError(err)
65
				return
66
			}
67
		} else {
68
			app.LogError(err)
69
			return
70
		}
71
	} else {
72
		userAgentId = agent.ID
73
	}
74

75
	location, err := findLocationByIP(activity.Addr, app)
76
	if err == nil {
77
		activity.LocationID = location.ID
78
	}
79

80
	matches := regexpArticle.FindStringSubmatch(activity.RequestedURI)
81
	if matches != nil {
82
		articleRepo := repositories.ArticleRepository{DB: app.DB}
83
		articleId = articleRepo.GetIdBySlug(matches[slugIndex])
84
	}
85

86
	if !trackingCache.Has(activity.FingerPrint) ||
87
		activity.Status != http.StatusOK ||
88
		activity.Method != "GET" {
89
		err = repo.SaveTracking(activity, userAgentId, articleId)
90
		if err != nil {
91
			app.LogError(err)
92

93
			ipKey := ipAddrKey(activity.Addr)
94
			cache := app.GetIntCache()
95
			cache.Delete(ipKey)
96

97
			return
98
		}
99

100
		trackingCache.Set(activity.FingerPrint, 1, yetacache.DefaultTTL)
101
	}
102
}
103

104
func findLocationByIP(ip net.IP, app *container.Application) (*models.Geolocation, error) {
105
	ipKey := ipAddrKey(ip)
106

107
	cache := app.GetIntCache()
108
	if locationID, found := cache.Get(ipKey); found {
109
		app.InfoLog.Printf("[CACHE] IP %s HIT\n", ip.String())
110

111
		return &models.Geolocation{IpAddr: ip.String(), ID: locationID}, nil
112
	} else {
113
		app.InfoLog.Printf("[CACHE] IP %s MISS\n", ip.String())
114
	}
115

116
	geolocationRepo := repositories.GeolocationRepository{DB: app.DB}
117
	location, err := geolocationRepo.FindByIP(ip)
118
	if err != nil {
119
		return nil, err
120
	}
121

122
	cache.Set(ipKey, location.ID, 168*time.Hour)
123

124
	return location, nil
125
}
126

127
func setupBrowserPassiveFingerprint(req *http.Request, a *trackmodels.Activity) {
128
	a.FingerPrint = container.MD5(
129
		fmt.Sprintf(
130
			"%s:%s:%s:%d",
131
			a.UserAgent,
132
			a.Addr.String(),
133
			req.URL.RequestURI(),
134
			a.Status,
135
		),
136
	)
137
}
138

139
func ipAddrKey(ip net.IP) string {
140
	return "IP_" + ip.String()
141
}
142

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.