// Callback is a callback handler. // It does HTTP request if it's needed. func Callback(ctx context.Context, cu *trim.CustomURL) error { req, err := cu.Callback() if err != nil { // empty callback if err == trim.ErrEmptyCallback { return nil } return err } req.Header = http.Header{"User-Agent": {httpUserAgent}} timeoutTLS, timeout := 5*time.Second, 7*time.Second tr := &http.Transport{ Proxy: http.ProxyFromEnvironment, Dial: (&net.Dialer{Timeout: timeout}).Dial, TLSHandshakeTimeout: timeoutTLS, // TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, } client := &http.Client{Transport: tr, Timeout: timeout} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() _, err = ioutil.ReadAll(resp.Body) return err }
// Tracker saves info about short URL activities. // GeoIP database can be loaded from // http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz func Tracker(ctx context.Context, cu *trim.CustomURL, addr string) error { c, err := conf.FromContext(ctx) if err != nil { return err } host, _, err := net.SplitHostPort(addr) if err != nil { return err } geo := GeoData{IP: host} record, err := c.GeoDB.City(net.ParseIP(host)) if err != nil { // not critical: skip GeoIP data filling c.L.Error.Println(err) } else { geo.Country = record.Country.Names["en"] geo.City = record.City.Names["en"] geo.Latitude = record.Location.Latitude geo.Longitude = record.Location.Longitude geo.Tz = record.Location.TimeZone } s, err := db.NewSession(c.Conn, true) if err != nil { return err } defer s.Close() coll, err := db.Coll(s, "tracks") if err != nil { return err } err = coll.Insert(bson.M{ "short": cu.String(), "url": cu.Original, "group": cu.Group, "tag": cu.Tag, "geo": geo, "ts": time.Now().UTC(), }) return err }