-
Notifications
You must be signed in to change notification settings - Fork 1
/
seamlink.go
148 lines (123 loc) · 3.68 KB
/
seamlink.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package seamlink
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/gofiber/fiber/v2"
)
// PageVisit tracks initial page visits
type PageVisit struct {
URL string `json:"url"`
Referrer string `json:"referrer"`
UserAgent string `json:"userAgent"`
Timestamp time.Time `json:"timestamp"`
}
func New(config ...SeamlinkConfig) fiber.Handler {
fmt.Println("Seamlink middleware initialized")
cfg := DefaultConfig()
if len(config) > 0 {
cfg = config[0]
}
trackingScript := `
<script>
console.log('Seamlink tracking script loaded');
// Track page visit when loaded
fetch('/api/seamlink/pageview', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: window.location.href,
referrer: document.referrer || 'direct',
userAgent: navigator.userAgent,
timestamp: new Date().toISOString()
})
});
// Track outbound clicks
const seamlinkTrack = function(e) {
e.preventDefault();
const link = e.currentTarget;
const url = link.getAttribute('href');
fetch('/api/seamlink/track', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: url,
referrer: window.location.href,
userAgent: navigator.userAgent,
timestamp: new Date().toISOString()
})
}).then(() => {
window.open(url, '_blank');
}).catch(error => {
console.error('Tracking error:', error);
window.open(url, '_blank');
});
};
// Add tracking to links when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
const links = document.querySelectorAll('a[href^="http"]');
links.forEach(link => {
link.addEventListener('click', seamlinkTrack);
console.log('Added tracking to:', link.href);
});
console.log('Seamlink initialized on', links.length, 'links');
});
</script>`
return func(c *fiber.Ctx) error {
fmt.Println("Middleware called for path:", c.Path())
// Handle page visit tracking
if c.Path() == "/api/seamlink/pageview" {
fmt.Println("Received pageview request")
var visit PageVisit
if err := json.Unmarshal(c.Body(), &visit); err != nil {
fmt.Printf("Error parsing pageview data: %v\n", err)
return c.Status(400).SendString("Invalid pageview data")
}
fmt.Printf("Processing pageview: %+v\n", visit)
if err := cfg.StorePageVisit(visit); err != nil {
fmt.Printf("Error storing pageview: %v\n", err)
return c.Status(500).SendString("Failed to store pageview data")
}
fmt.Println("Successfully processed pageview")
return c.SendStatus(200)
}
// Handle click tracking
if c.Path() == "/api/seamlink/track" {
fmt.Println("Received click tracking request")
var click SeamlinkClick
if err := json.Unmarshal(c.Body(), &click); err != nil {
fmt.Printf("Error parsing click data: %v\n", err)
return c.Status(400).SendString("Invalid click data")
}
fmt.Printf("Processing click: %+v\n", click)
if err := cfg.StoreLinkClick(click); err != nil {
fmt.Printf("Error storing click: %v\n", err)
return c.Status(500).SendString("Failed to store click data")
}
fmt.Println("Successfully processed click")
return c.SendStatus(200)
}
// Process the response
if err := c.Next(); err != nil {
return err
}
// Only proceed for HTML responses
contentType := string(c.Response().Header.ContentType())
if !strings.Contains(contentType, "text/html") {
return nil
}
// Inject tracking script
body := string(c.Response().Body())
if strings.Contains(body, "</body>") {
fmt.Println("Injecting tracking script")
modified := strings.Replace(body, "</body>", trackingScript+"</body>", 1)
c.Response().SetBody([]byte(modified))
}
return nil
}
}