Skip to content

Commit

Permalink
Cache in Redis
Browse files Browse the repository at this point in the history
- [x] Pipeline to update binary on server when changes are pushed
- [x] Added config option for Cache TTL in Seconds in `/etc/echoip/config.toml
- [x] Updated Readme for Cache Options
- [x] Added `Null` cache for optional no use of cache

- [x] Adding Redis Cache
- [x] Moving configuration to file config
- [x] Automatic Release for amd64 linux
- [x] Adding automatic deployment

- Added `LICENSE` file to the release file
  • Loading branch information
eknowlton committed Oct 7, 2023
1 parent 9971835 commit 79c8f54
Show file tree
Hide file tree
Showing 19 changed files with 585 additions and 368 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Release

on:
push:
tags:
- "*"

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: "1.18.x"

- name: Build EchoIP binary
run: go build -o ./echoip ./cmd/echoip/main.go

- name: Upload Release Artifact
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
zip -r echoip-linux-amd64-${{ github.ref_name }}.zip echoip html LICENSE
- name: Create Release
uses: ncipollo/release-action@v1
with:
artifacts: echoip-linux-amd64-${{ github.ref_name }}.zip
bodyFile: "CHANGELOG.md"
7 changes: 2 additions & 5 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Go
name: Test

on: [push]

Expand All @@ -13,10 +13,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: "1.13.x"

- name: Display Go version
run: go version
go-version: "1.18.x"

- name: Run tests
run: go test ./...
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog

## 1.0.0 (2023-10-06)


### Features

* Adding test to main.go ([a4d13ad](https://github.com/levelsoftware/echoip/commit/a4d13ad0edcc3c9dd591ad1aa26d2b50b8528168))
* Remove if inside loop from String() ([08fdacc](https://github.com/levelsoftware/echoip/commit/08fdacc08254a53169a19ff7f14cfad4c70655c1))
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ vet:
check-fmt:
bash -c "diff --line-format='%L' <(echo -n) <(gofmt -d -s .)"


lint: check-fmt vet

install:
install: install-config
go install ./...

install-config:
sudo install -D etc/echoip/config.toml /etc/echoip/config.toml

databases := GeoLite2-City GeoLite2-Country GeoLite2-ASN

$(databases):
Expand Down Expand Up @@ -63,7 +67,7 @@ docker-push: docker-test docker-login
docker-pushx: docker-multiarch-builder docker-test docker-login
$(DOCKER) buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t $(DOCKER_IMAGE) --push .

xinstall:
xinstall: install-config
env GOOS=$(XGOOS) GOARCH=$(XGOARCH) go install ./...

publish:
Expand Down
76 changes: 50 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,34 +84,58 @@ between IPv4 and IPv6 lookup.
- Port testing
- All endpoints (except `/port`) can return information about a custom IP address specified via `?ip=` query parameter
- Open source under the [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause)
- Supports IP Stack API or GeoIP

### Installation from Release

- Download release file.
- Install `./echoip` binary ( `sudo install echoip /usr/local/bin/echoip` )
- Install configuration file( `sudo install -D etc/echoip/config.toml /etc/echoip/config.toml` )
- Point `config.TemplateDir` to release `html/`

### Installation from Source

- Install Go 1.18
- `$ cd echoip/`
- `$ make install`

### Usage

```
$ echoip -h
Usage of echoip:
-C int
Size of response cache. Set to 0 to disable
-H value
Header to trust for remote IP, if present (e.g. X-Real-IP)
-P Enables profiling handlers
-S string
IP Stack API Key
-a string
Path to GeoIP ASN database
-c string
Path to GeoIP city database
-d string
Which database to use, 'ipstack' or 'geoip' (default "geoip")
-f string
Path to GeoIP country database
-h Use HTTPS for IP Stack ( only non-free accounts )
-l string
Listening address (default ":8080")
-p Enable port lookup
-r Perform reverse hostname lookups
-s Show sponsor logo
-t string
Path to template dir (default "html")
-x Enable security module for IP Stack ( must have security module, aka. non-free account. )
$ echoip
```

### Configuration

Configuration is managed in the `etc/echoip/config.toml` file. This file should be located in the `/etc` folder on your server ( /etc/echoip/config.toml ). If you have the project on your server, you can run `make install-config` to copy it the right location.

```toml
Listen = ":8080"
TemplateDir = "html" # The directory of the template files ( eg, index.html )
RedisUrl = "redis://localhost:6379" # Redis Connection URL, leave blank for no Cache
CacheTtl = 3600 # in seconds
ReverseLookup = true
PortLookup = true
ShowSponsor = true
Database = "ipstack" # use "IP Stack" or "GeoIP"
TrustedHeaders = [] # Which header to trust, eg, `["X-Real-IP"]`
Profile = false # enable debug / profiling

[IPStack]
ApiKey = ""
UseHttps = true
EnableSecurity = true

[GeoIP]
CountryFile = ""
CityFile = ""
AsnFile = ""
```

### Caching with Redis

You can connect EchoIP to a Redis client to cache each request per IP. You can configure the life of the key in `config.CacheTtl`.

### Running with `systemd`

There is a systemd service file you can install in `/etc/systemd`.
30 changes: 30 additions & 0 deletions cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cache

import (
"context"

parser "github.com/levelsoftware/echoip/iputil/paser"
)

type CachedResponse struct {
response *parser.Response
}

func (cr *CachedResponse) Build(response parser.Response) CachedResponse {
return CachedResponse{
response: &response,
}
}

func (cr *CachedResponse) Get() parser.Response {
return *cr.response
}

func (cr *CachedResponse) IsSet() bool {
return cr.response != nil
}

type Cache interface {
Get(ctx context.Context, ip string, cachedResponse *CachedResponse) error
Set(ctx context.Context, ip string, response CachedResponse, cacheTtl int) error
}
15 changes: 15 additions & 0 deletions cache/null.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cache

import (
"context"
)

type Null struct{}

func (nc *Null) Get(ctx context.Context, ip string, cachedResponse *CachedResponse) error {
return nil
}

func (nc *Null) Set(ctx context.Context, ip string, response CachedResponse, cacheTtl int) error {
return nil
}
41 changes: 41 additions & 0 deletions cache/redis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cache

import (
"context"
"time"

"github.com/go-redis/cache/v9"
"github.com/redis/go-redis/v9"
)

type Redis struct {
cache *cache.Cache
}

func RedisCache(url string) (Redis, error) {
opts, err := redis.ParseURL(url)
if err != nil {
return Redis{}, err
}
rdb := redis.NewClient(opts)
cache := cache.New(&cache.Options{
Redis: rdb,
LocalCache: cache.NewTinyLFU(1000, time.Minute),
})
return Redis{
cache: cache,
}, nil
}

func (r *Redis) Get(ctx context.Context, ip string, cachedResponse *CachedResponse) error {
return r.cache.Get(ctx, ip, cachedResponse)
}

func (r *Redis) Set(ctx context.Context, ip string, response CachedResponse, cacheTtl int) error {
return r.cache.Set(&cache.Item{
Ctx: ctx,
Key: ip,
Value: response,
TTL: time.Duration(cacheTtl * int(time.Second)),
})
}
Loading

0 comments on commit 79c8f54

Please sign in to comment.