aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Hanley <felix@userspace.com.au>2020-02-14 04:12:25 +0000
committerFelix Hanley <felix@userspace.com.au>2020-02-14 04:12:25 +0000
commit729c39874d906a6312b878046ca24458af4b6a8b (patch)
treef7f8d43d20859688eb15c90ac232d93232d220d5
parent91a6d4ab9ae45c64683eae764b0e0d3edf5e7c80 (diff)
downloadsws-729c39874d906a6312b878046ca24458af4b6a8b.tar.gz
sws-729c39874d906a6312b878046ca24458af4b6a8b.tar.bz2
Add user agent indexed by sha1
-rw-r--r--cmd/server/hits.go2
-rw-r--r--counter/sws.js2
-rw-r--r--hit.go25
-rw-r--r--sql/sqlite3/02_hits.sql13
-rw-r--r--store/sqlite3.go18
-rw-r--r--templates/example.tmpl7
-rw-r--r--user_agent.go33
7 files changed, 77 insertions, 23 deletions
diff --git a/cmd/server/hits.go b/cmd/server/hits.go
index 54574b1..64bab3b 100644
--- a/cmd/server/hits.go
+++ b/cmd/server/hits.go
@@ -26,7 +26,7 @@ func handleHitCounter(db sws.CounterStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
hit, err := sws.HitFromRequest(r)
if err != nil {
- log("failed to create hit", err)
+ log("failed to extract hit", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
diff --git a/counter/sws.js b/counter/sws.js
index 08c353a..9fabcf2 100644
--- a/counter/sws.js
+++ b/counter/sws.js
@@ -8,7 +8,7 @@ var me = document.currentScript
console.log('me:', me)
console.log('me.sws:', me.dataset.sws)
-_sws = _sws || {xhr:true}
+var _sws = w._sws || {xhr:true}
console.log('_sws:', _sws)
_sws.d = _sws.d || me.dataset.sws || 'http://sws.userspace.com.au/sws.gif'
console.log('using', _sws.d)
diff --git a/hit.go b/hit.go
index e9aefbe..5be6993 100644
--- a/hit.go
+++ b/hit.go
@@ -19,15 +19,16 @@ type Hit struct {
Query *string `json:"query,omitempty"`
Fragment *string `json:"fragment,omitempty"`
- Title *string `json:"title,omitempty"`
- Referrer *string `json:"referrer,omitempty"`
- UserAgent *string `json:"user_agent,omitempty"`
- ViewPort *string `json:"view_port,omitempty"`
+ Title *string `json:"title,omitempty"`
+ Referrer *string `json:"referrer,omitempty"`
+ UserAgentHash *string `json:"user_agent_hash,omitempty"`
+ ViewPort *string `json:"view_port,omitempty"`
//Features map[string]string `json:"features,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
// TODO
- Domain *Domain `json:"-"`
+ Domain *Domain `json:"-"`
+ UserAgent *UserAgent `json:"-"`
}
func (h Hit) String() string {
@@ -92,11 +93,15 @@ func HitFromRequest(r *http.Request) (*Hit, error) {
}
agent := q.Get("u")
- if agent != "" {
- out.UserAgent = &agent
- } else {
- s := r.UserAgent()
- out.UserAgent = &s
+ if agent == "" {
+ agent = r.UserAgent()
+ }
+ uaHash := UserAgentHash(agent)
+ out.UserAgentHash = &uaHash
+ out.UserAgent = &UserAgent{
+ Hash: uaHash,
+ Name: agent,
+ LastSeenAt: time.Now(),
}
if view := q.Get("v"); view != "" {
diff --git a/sql/sqlite3/02_hits.sql b/sql/sqlite3/02_hits.sql
index 2fd5539..ca76f0b 100644
--- a/sql/sqlite3/02_hits.sql
+++ b/sql/sqlite3/02_hits.sql
@@ -1,3 +1,11 @@
+pragma foreign_keys = on;
+
+create table user_agents (
+ hash varchar not null primary key,
+ name varchar not null,
+ last_seen_at timestamp not null
+);
+
create table hits (
id integer primary key autoincrement,
domain_id integer check(domain_id >0),
@@ -8,8 +16,9 @@ create table hits (
query varchar null,
title varchar null,
referrer varchar null,
- user_agent varchar null,
+ user_agent_hash varchar null,
view_port varchar null,
- created_at timestamp not null
+ created_at timestamp not null,
+ foreign key(user_agent_hash) references user_agents(hash)
);
create index "hits#domain_id#created" on hits(domain_id, created_at);
diff --git a/store/sqlite3.go b/store/sqlite3.go
index fce375a..499e8c5 100644
--- a/store/sqlite3.go
+++ b/store/sqlite3.go
@@ -74,6 +74,11 @@ func (s *Sqlite3) GetHits(d sws.Domain, start, end time.Time, f map[string]inter
}
func (s *Sqlite3) SaveHit(h *sws.Hit) error {
+ if h.UserAgent != nil {
+ if _, err := s.db.NamedExec(stmts["saveUserAgent"], *h.UserAgent); err != nil {
+ return err
+ }
+ }
if _, err := s.db.NamedExec(stmts["saveHit"], h); err != nil {
return err
}
@@ -91,12 +96,19 @@ created_at, updated_at from domains where id = $1 limit 1`,
name, description, aliases, enabled, created_at, updated_at) values (:name,
:description, :aliases, :enabled, :created_at, :updated_at)`,
+ "userAgentByHash": `select id, hash, name, last_seen_at from domains
+where hash = $1 limit 1`,
+
+ "saveUserAgent": `insert into user_agents (hash, name, last_seen_at)
+values (:hash, :name, :last_seen_at) on conflict(hash) do update set
+last_seen_at = :last_seen_at`,
+
"saveHit": `insert into hits (
-domain_id, addr, scheme, host, path, query, title, referrer, user_agent,
+domain_id, addr, scheme, host, path, query, title, referrer, user_agent_hash,
view_port, created_at) values (:domain_id, :addr, :scheme, :host, :path, :query,
-:title, :referrer, :user_agent, :view_port, :created_at)`,
+:title, :referrer, :user_agent_hash, :view_port, :created_at)`,
"filterHits": `select domain_id, addr, scheme, host, path, title,
-referrer, user_agent, view_port, created_at from hits where created_at > :start
+referrer, user_agent_hash, view_port, created_at from hits where created_at > :start
and created_at < :end`,
}
diff --git a/templates/example.tmpl b/templates/example.tmpl
index 75d28b6..13dd609 100644
--- a/templates/example.tmpl
+++ b/templates/example.tmpl
@@ -2,12 +2,7 @@
<html>
<head>
<meta charset="utf-8">
- <script>
- var _sws = {
- title: "test title"
- }
- </script>
- <script async src="http://localhost:5000/sws.js"></script>
+ <script async src="http://localhost:5000/sws.js" data-sws="http://localhost:5000/sws.gif"></script>
<title>This is the title</title>
<noscript>
<img src="http://localhost:5000/sws.gif" />
diff --git a/user_agent.go b/user_agent.go
new file mode 100644
index 0000000..cbb831b
--- /dev/null
+++ b/user_agent.go
@@ -0,0 +1,33 @@
+package sws
+
+import (
+ "crypto/sha1"
+ "fmt"
+ "net/http"
+ "time"
+)
+
+type UserAgent struct {
+ Hash string `json:"hash"`
+ Name string `json:"name"`
+ LastSeenAt time.Time `json:"last_seen_at"`
+}
+
+func UserAgentHash(s string) string {
+ return fmt.Sprintf("%x", sha1.Sum([]byte(s)))
+}
+
+func UserAgentFromRequest(r *http.Request) (*UserAgent, error) {
+ q := r.URL.Query()
+ agent := q.Get("u")
+ if agent == "" {
+ return nil, nil
+ }
+ ua := r.UserAgent()
+
+ return &UserAgent{
+ Name: ua,
+ LastSeenAt: time.Now(),
+ Hash: UserAgentHash(ua),
+ }, nil
+}