Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# data
data/analytics.db
data

# debug
__debug_*

# bench
# build out
tinyauth-analytics

# benchmarks
bench
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"mode": "auto",
"program": "${fileDirname}",
"env": {
"DB_PATH": "./data/analytics.db",
"DATABASE_PATH": "./data/analytics.db",
"PORT": "8080",
"ADDRESS": "0.0.0.0",
"TRUSTED_PROXIES": "0.0.0.0",
Expand Down
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ COPY go.sum ./

RUN go mod download

COPY ./cache.go ./
COPY ./health_handler.go ./
COPY ./instances_handler.go ./
COPY ./main.go ./
COPY ./internal ./internal
COPY ./rate_limiter.go ./
COPY ./database ./database

RUN CGO_ENABLED=0 go build -ldflags "-s -w -X main.version=${VERSION}"

Expand Down
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A simple server to transparently collect version information from Tinyauth insta

## How does it work

Every Tinyauth instance runs a goroutine (unless you choose to opt-out) that does a "heartbeat" every 12 hours indicating the instance is still alive. The heartbeat contains the UUID generated by Tinyauth on start up and the version information. The server stores them in the SQLite database alongside with the last seen date. When you request all the instances, the server responds with an array containing the versions, UUIDs and last seen dates. In order to increase transparency, if the `LOG_LEVEL` is configured to `debug` or `trace`, the server will return a warning both in the instances and heartbeat endpoint in order to inform the user that sensitive information like IP addresses may be logged.
Every Tinyauth instance runs a goroutine (unless you choose to opt-out) that does a "heartbeat" every 12 hours indicating the instance is still alive. The heartbeat contains the UUID generated by Tinyauth on start up and the version information. The server stores them in the SQLite database alongside with the last seen date. When you request all the instances, the server responds with an array containing the versions, UUIDs and last seen dates.
Comment thread
steveiliop56 marked this conversation as resolved.

## Running

Expand All @@ -18,15 +18,14 @@ docker compose up -d

The server is configured using environment variables, the following options are supported:

| Name | Type | Description | Default |
| ---------------------- | ------------ | ---------------------------------------------------------- | -------------------- |
| `DB_PATH` | string | Path to the SQLite database file. | `/data/analytics.db` |
| `PORT` | number | The port to run the server on. | `8080` |
| `ADDRESS` | string | The address to bind the server to. | `0.0.0.0` |
| `RATE_LIMIT_COUNT` | number | Maximum number of requests per minute per IP. | `3` |
| `CORS_ALLOWED_ORIGINS` | string/array | Comma-separated list of allowed CORS origins. | `*` |
| `TRUSTED_PROXIES` | string/array | Comma-separated list of trusted proxy IPs. | `""` (empty) |
| `LOG_LEVEL` | string | Log level (trace, debug, info, warn, error, fatal, panic). | `info` |
| Name | Type | Description | Default |
| ---------------------- | ------------ | --------------------------------------------- | -------------------- |
| `DATABASE_PATH` | string | Path to the SQLite database file. | `/data/analytics.db` |
| `PORT` | number | The port to run the server on. | `8080` |
| `ADDRESS` | string | The address to bind the server to. | `0.0.0.0` |
| `RATE_LIMIT_COUNT` | number | Maximum number of requests per minute per IP. | `3` |
| `CORS_ALLOWED_ORIGINS` | string/array | Comma-separated list of allowed CORS origins. | `*` |
| `TRUSTED_PROXIES` | string/array | Comma-separated list of trusted proxy IPs. | `` |

## Contributing

Expand Down
85 changes: 85 additions & 0 deletions cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package main

import (
"sync"
"time"
)

type cacheField struct {
value any
expire int64
}

type Cache struct {
cache map[string]cacheField
mutex sync.RWMutex
}

func NewCache() *Cache {
cache := &Cache{
cache: make(map[string]cacheField),
}
cache.cleanup()
return cache
}

func (c *Cache) Set(key string, value any, ttl int64) {
c.mutex.Lock()
defer c.mutex.Unlock()

expire := time.Now().Add(time.Duration(ttl) * time.Second).Unix()

c.cache[key] = cacheField{
value: value,
expire: expire,
}
}

func (c *Cache) Get(key string) (any, bool) {
c.mutex.RLock()

field, ok := c.cache[key]

if !ok {
c.mutex.RUnlock()
return nil, false
}

if time.Now().Unix() > field.expire {
c.mutex.RUnlock()
c.Delete(key)
return nil, false
}

c.mutex.RUnlock()
return field.value, true
}

func (c *Cache) Delete(key string) {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(c.cache, key)
}

func (c *Cache) Flush() {
c.mutex.Lock()
defer c.mutex.Unlock()
c.cache = make(map[string]cacheField, 0)
}

func (c *Cache) cleanup() {
go func() {
ticker := time.NewTicker(24 * time.Hour)
defer ticker.Stop()

for range ticker.C {
c.mutex.Lock()
for key, field := range c.cache {
if time.Now().Unix() > field.expire {
delete(c.cache, key)
}
}
c.mutex.Unlock()
}
}()
}
Comment thread
steveiliop56 marked this conversation as resolved.
Empty file removed data/.gitkeep
Empty file.
31 changes: 31 additions & 0 deletions database/queries/db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions database/queries/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

123 changes: 123 additions & 0 deletions database/queries/query.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 17 additions & 18 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,26 @@ services:
- RATE_LIMIT_COUNT=15
- CORS_ALLOWED_ORIGINS=*
- TRUSTED_PROXIES=0.0.0.0
- LOG_LEVEL=debug
volumes:
- ./data:/data
ports:
- 8080:8080
restart: unless-stopped

analytics-dashboard:
build:
context: ./dashboard
dockerfile: Dockerfile
args:
- VERSION=development
environment:
- PORT=8090
- ADDRESS=0.0.0.0
- API_SERVER=http://tinyauth-analytics:8080
- PAGE_SIZE=10
- REFRESH_INTERVAL=1
ports:
- 8090:8090
restart: unless-stopped
depends_on:
- tinyauth-analytics
# analytics-dashboard:
# build:
# context: ./dashboard
# dockerfile: Dockerfile
# args:
# - VERSION=development
# environment:
# - PORT=8090
# - ADDRESS=0.0.0.0
# - API_SERVER=http://tinyauth-analytics:8080
# - PAGE_SIZE=10
# - REFRESH_INTERVAL=1
# ports:
# - 8090:8090
# restart: unless-stopped
# depends_on:
# - tinyauth-analytics
Loading