This repository has been archived by the owner on Sep 21, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
store.go
132 lines (106 loc) · 2.99 KB
/
store.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
package store
import (
"context"
"fmt"
"strings"
"cloud.google.com/go/datastore"
"github.com/majordomusio/commons/pkg/env"
"github.com/majordomusio/commons/pkg/util"
"github.com/lnkk-ai/url-shortener/internal/types"
"github.com/lnkk-ai/url-shortener/pkg/api"
"github.com/lnkk-ai/url-shortener/pkg/errorreporting"
)
var dsClient *datastore.Client
func init() {
ctx := context.Background()
c, err := datastore.NewClient(ctx, env.Getenv("PROJECT_ID", ""))
if err != nil {
errorreporting.Report(err)
}
dsClient = c
}
// Close does the clean-up
func Close() {
dsClient.Close()
}
// AssetKey creates the datastore key for an asset
func AssetKey(uri string) *datastore.Key {
return datastore.NameKey(api.DatastoreAssets, uri, nil)
}
// GeoLocationKey creates the datastore key for a geolocation
func GeoLocationKey(ip string) *datastore.Key {
return datastore.NameKey(api.DatastoreGeoLocation, ip, nil)
}
// CreateAsset stores an asset in the Datastore
func CreateAsset(ctx context.Context, as *api.Asset) (string, error) {
uri, _ := util.ShortUUID()
secret, _ := util.ShortUUID()
asset := types.AssetDS{
URI: uri,
URL: as.URL,
Owner: "anonymous",
SecretID: secret,
Source: as.Source,
Cohort: as.Cohort,
Affiliate: as.Affiliate,
Tags: as.Tags,
Created: util.Timestamp(),
}
k := AssetKey(uri)
if _, err := dsClient.Put(ctx, k, &asset); err != nil {
errorreporting.Report(err)
return "", err
}
return uri, nil
}
// GetAsset retrieves the asset
func GetAsset(ctx context.Context, uri string) (*api.Asset, error) {
var as types.AssetDS
k := AssetKey(uri)
if err := dsClient.Get(ctx, k, &as); err != nil {
return nil, err
}
return as.AsExternal(), nil
}
// CreateMeasurement records a link activation
func CreateMeasurement(ctx context.Context, m *types.MeasurementDS) error {
// anonimize the IP to be GDPR compliant
m.IP = anonimizeIP(m.IP)
// TODO: use a queue here, go routine will not work !
CreateGeoLocation(ctx, m.IP)
k := datastore.IncompleteKey(api.DatastoreMeasurement, nil)
if _, err := dsClient.Put(ctx, k, m); err != nil {
errorreporting.Report(err)
return err
}
return nil
}
// CreateGeoLocation looks up the IP's geolocation if it is unknown
func CreateGeoLocation(ctx context.Context, ip string) error {
var loc types.GeoLocationDS
k := GeoLocationKey(ip)
if err := dsClient.Get(ctx, k, &loc); err != nil {
// assuming the location is unknown
l, err := lookupGeoLocation(ip)
if err != nil {
errorreporting.Report(err)
return err
}
if _, err := dsClient.Put(ctx, k, l.AsInternal()); err != nil {
errorreporting.Report(err)
return err
}
}
return nil
}
// Anonimize the IP to be GDPR compliant
func anonimizeIP(ip string) string {
if strings.ContainsRune(ip, 58) {
// IPv6
parts := strings.Split(ip, ":")
return fmt.Sprintf("%s:%s:%s:0000:0000:0000:0000:0000", parts[0], parts[1], parts[2])
}
// IPv4
parts := strings.Split(ip, ".")
return fmt.Sprintf("%s.%s.%s.0", parts[0], parts[1], parts[2])
}