summaryrefslogtreecommitdiff
path: root/reader/bunny.go
diff options
context:
space:
mode:
authoreltrac <hi@eltr.ac>2026-11-04 23:26:12 +0800
committereltrac <hi@eltr.ac>2026-11-04 23:26:12 +0800
commitaa8478f07217b5a44424b5c102220127f8585a1f (patch)
tree562d6be0551c2a9c8ff1b457c130c1f896bebd12 /reader/bunny.go
initial commit
project: go mod init data, reader: add types and roughly implement Bunny.net reader analytics: basic analyzer, experimental
Diffstat (limited to 'reader/bunny.go')
-rw-r--r--reader/bunny.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/reader/bunny.go b/reader/bunny.go
new file mode 100644
index 0000000..4a94913
--- /dev/null
+++ b/reader/bunny.go
@@ -0,0 +1,81 @@
+package reader
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/ohler55/ojg/oj"
+
+ "src.eltr.ac/eltrac/audidi/data"
+)
+
+type bunnyJSON struct {
+ Timestamp string `json:"timestamp"`
+ PullZoneID int `json:"pullZoneId"`
+ RequestID string `json:"requestId"`
+ CacheStatus string `json:"cacheStatus"`
+ StatusCode int `json:"statusCode"`
+ BytesSent int `json:"bytesSent"`
+ RemoteIP string `json:"remoteIp"`
+ CountryCode string `json:"countryCode"`
+ EdgeLocation string `json:"edgeLocation"`
+ Scheme string `json:"scheme"`
+ Host string `json:"host"`
+ Path string `json:"path"`
+ URL string `json:"url"`
+ UserAgent string `json:"userAgent"`
+ Referer string `json:"referer"`
+ JA4Fingerprint string `json:"ja4Fingerprint"`
+ ASN int `json:"asn"`
+ ASNOrganization string `json:"asnOrganization"`
+}
+
+type bunnyError struct {
+ Code string `json:"code"`
+ Message string `json:"message"`
+ Details []string `json:"details"`
+}
+
+type bunnyResponse struct {
+ Data []bunnyJSON `json:"data"`
+ Error *bunnyError `json:"error"`
+}
+
+// BunnyReader reads log entries from the Bunny.net Logging API v2.
+type BunnyReader struct{}
+
+// Read parses Bunny.net log records from input.
+func (r *BunnyReader) Read(input io.Reader) ([]data.LogEntry, error) {
+ b, err := io.ReadAll(input)
+ if err != nil {
+ return nil, fmt.Errorf("error reading from input")
+ }
+
+ var parser oj.Parser
+ var response bunnyResponse
+ parser.Unmarshal(b, &response)
+
+ if err := response.Error; err != nil {
+ return nil, fmt.Errorf("API response error %s: %s", err.Code, err.Message)
+ }
+
+ var result []data.LogEntry
+ if logdata := response.Data; len(logdata) > 0 {
+ for _, entry := range logdata {
+ result = append(result, data.LogEntry{
+ Host: entry.Host,
+ Path: entry.Path,
+ URL: entry.URL,
+ Status: entry.StatusCode,
+ CountryCode: entry.CountryCode,
+ IP: entry.RemoteIP,
+ ASN: entry.ASN,
+ UserAgent: entry.UserAgent,
+ JA4: entry.JA4Fingerprint,
+ JA3: "",
+ })
+ }
+ }
+
+ return result, nil
+}