mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-21 23:15:06 +00:00
Reinstate url hitcount (#393)
This commit is contained in:
@@ -8,7 +8,9 @@
|
|||||||
"response": {
|
"response": {
|
||||||
"urlPairs": [{
|
"urlPairs": [{
|
||||||
"shortURL": "https://m3o.one/u/f8f3f83f3f83g",
|
"shortURL": "https://m3o.one/u/f8f3f83f3f83g",
|
||||||
"destinationURL": "https://mysite.com/this-is-a-rather-long-web-address"
|
"destinationURL": "https://mysite.com/this-is-a-rather-long-web-address",
|
||||||
|
"created": "2022-03-01T16:04:11.341277162Z",
|
||||||
|
"hit_count": "4"
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
|
|||||||
@@ -2,29 +2,33 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/micro/micro/v3/service"
|
||||||
|
"github.com/micro/micro/v3/service/client"
|
||||||
"github.com/micro/micro/v3/service/config"
|
"github.com/micro/micro/v3/service/config"
|
||||||
"github.com/micro/micro/v3/service/errors"
|
"github.com/micro/micro/v3/service/errors"
|
||||||
"github.com/micro/micro/v3/service/logger"
|
"github.com/micro/micro/v3/service/logger"
|
||||||
"github.com/micro/micro/v3/service/store"
|
"github.com/micro/micro/v3/service/store"
|
||||||
|
cachepb "github.com/micro/services/cache/proto"
|
||||||
pauth "github.com/micro/services/pkg/auth"
|
pauth "github.com/micro/services/pkg/auth"
|
||||||
adminpb "github.com/micro/services/pkg/service/proto"
|
adminpb "github.com/micro/services/pkg/service/proto"
|
||||||
"github.com/micro/services/pkg/tenant"
|
"github.com/micro/services/pkg/tenant"
|
||||||
url "github.com/micro/services/url/proto"
|
url "github.com/micro/services/url/proto"
|
||||||
cache "github.com/patrickmn/go-cache"
|
|
||||||
"github.com/teris-io/shortid"
|
"github.com/teris-io/shortid"
|
||||||
)
|
)
|
||||||
|
|
||||||
const hostPrefix = "https://m3o.one/u/"
|
const hostPrefix = "https://m3o.one/u/"
|
||||||
|
|
||||||
type Url struct {
|
type Url struct {
|
||||||
cache *cache.Cache
|
cache cachepb.CacheService
|
||||||
hostPrefix string
|
hostPrefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUrl() *Url {
|
func NewUrl(svc *service.Service) *Url {
|
||||||
var hp string
|
var hp string
|
||||||
|
|
||||||
cfg, err := config.Get("micro.url.host_prefix")
|
cfg, err := config.Get("micro.url.host_prefix")
|
||||||
@@ -37,7 +41,7 @@ func NewUrl() *Url {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Url{
|
return &Url{
|
||||||
cache: cache.New(cache.NoExpiration, cache.NoExpiration),
|
cache: cachepb.NewCacheService("cache", svc.Client()),
|
||||||
hostPrefix: hp,
|
hostPrefix: hp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,14 +85,17 @@ func (e *Url) Shorten(ctx context.Context, req *url.ShortenRequest, rsp *url.Sho
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Url) List(ctx context.Context, req *url.ListRequest, rsp *url.ListResponse) error {
|
func (e *Url) List(ctx context.Context, req *url.ListRequest, rsp *url.ListResponse) error {
|
||||||
|
method := "url.shorten"
|
||||||
|
errInternal := errors.InternalServerError(method, "Error listing URLs")
|
||||||
tenantId, ok := tenant.FromContext(ctx)
|
tenantId, ok := tenant.FromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Unauthorized("url.shorten", "not authorized")
|
return errors.Unauthorized(method, "not authorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
key := "urlOwner/" + tenantId + "/"
|
prefix := "urlOwner/" + tenantId + "/"
|
||||||
|
key := prefix
|
||||||
|
|
||||||
var opts []store.ReadOption
|
var opts []store.ReadOption
|
||||||
|
|
||||||
@@ -101,7 +108,8 @@ func (e *Url) List(ctx context.Context, req *url.ListRequest, rsp *url.ListRespo
|
|||||||
|
|
||||||
records, err := store.Read(key, opts...)
|
records, err := store.Read(key, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
logger.Errorf("Error reading record %s", err)
|
||||||
|
return errInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rec := range records {
|
for _, rec := range records {
|
||||||
@@ -110,8 +118,14 @@ func (e *Url) List(ctx context.Context, req *url.ListRequest, rsp *url.ListRespo
|
|||||||
if err := rec.Decode(uri); err != nil {
|
if err := rec.Decode(uri); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
crsp, err := e.cache.Get(ctx, &cachepb.GetRequest{Key: cacheKey(strings.TrimPrefix(rec.Key, prefix))}, client.WithAuthToken())
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Error reading cache %s", err)
|
||||||
|
return errInternal
|
||||||
|
}
|
||||||
|
uri.HitCount, _ = strconv.ParseInt(crsp.Value, 10, 64)
|
||||||
rsp.UrlPairs = append(rsp.UrlPairs, uri)
|
rsp.UrlPairs = append(rsp.UrlPairs, uri)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -135,10 +149,23 @@ func (e *Url) Proxy(ctx context.Context, req *url.ProxyRequest, rsp *url.ProxyRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
rsp.DestinationURL = uri.DestinationURL
|
rsp.DestinationURL = uri.DestinationURL
|
||||||
|
go func() {
|
||||||
|
_, err := e.cache.Increment(context.Background(), &cachepb.IncrementRequest{
|
||||||
|
Key: cacheKey(id),
|
||||||
|
Value: 1,
|
||||||
|
}, client.WithAuthToken())
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Error incrementing cache %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cacheKey(id string) string {
|
||||||
|
return fmt.Sprintf("url/HitCount/%s", id)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Url) DeleteData(ctx context.Context, request *adminpb.DeleteDataRequest, response *adminpb.DeleteDataResponse) error {
|
func (e *Url) DeleteData(ctx context.Context, request *adminpb.DeleteDataRequest, response *adminpb.DeleteDataResponse) error {
|
||||||
method := "admin.DeleteData"
|
method := "admin.DeleteData"
|
||||||
_, err := pauth.VerifyMicroAdmin(ctx, method)
|
_, err := pauth.VerifyMicroAdmin(ctx, method)
|
||||||
@@ -165,6 +192,7 @@ func (e *Url) DeleteData(ctx context.Context, request *adminpb.DeleteDataRequest
|
|||||||
if err := store.Delete(key); err != nil {
|
if err := store.Delete(key); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
e.cache.Delete(ctx, &cachepb.DeleteRequest{Key: cacheKey(id)}, client.WithAuthToken())
|
||||||
}
|
}
|
||||||
logger.Infof("Deleted %d objects from S3 for %s", len(keys), request.TenantId)
|
logger.Infof("Deleted %d objects from S3 for %s", len(keys), request.TenantId)
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func main() {
|
|||||||
service.Name("url"),
|
service.Name("url"),
|
||||||
service.Version("latest"),
|
service.Version("latest"),
|
||||||
)
|
)
|
||||||
h := handler.NewUrl()
|
h := handler.NewUrl(srv)
|
||||||
// Register handler
|
// Register handler
|
||||||
pb.RegisterUrlHandler(srv.Server(), h)
|
pb.RegisterUrlHandler(srv.Server(), h)
|
||||||
admin.RegisterAdminHandler(srv.Server(), h)
|
admin.RegisterAdminHandler(srv.Server(), h)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.27.1
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v3.15.6
|
// protoc v3.15.5
|
||||||
// source: proto/url.proto
|
// source: proto/url.proto
|
||||||
|
|
||||||
package url
|
package url
|
||||||
@@ -128,6 +128,8 @@ type URLPair struct {
|
|||||||
ShortURL string `protobuf:"bytes,2,opt,name=shortURL,proto3" json:"shortURL,omitempty"`
|
ShortURL string `protobuf:"bytes,2,opt,name=shortURL,proto3" json:"shortURL,omitempty"`
|
||||||
// time of creation
|
// time of creation
|
||||||
Created string `protobuf:"bytes,4,opt,name=created,proto3" json:"created,omitempty"`
|
Created string `protobuf:"bytes,4,opt,name=created,proto3" json:"created,omitempty"`
|
||||||
|
// The number of times the short URL has been resolved
|
||||||
|
HitCount int64 `protobuf:"varint,5,opt,name=hit_count,json=hitCount,proto3" json:"hit_count,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *URLPair) Reset() {
|
func (x *URLPair) Reset() {
|
||||||
@@ -183,6 +185,13 @@ func (x *URLPair) GetCreated() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *URLPair) GetHitCount() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.HitCount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// List all the shortened URLs
|
// List all the shortened URLs
|
||||||
type ListRequest struct {
|
type ListRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
@@ -387,37 +396,39 @@ var file_proto_url_proto_rawDesc = []byte{
|
|||||||
0x22, 0x2d, 0x0a, 0x0f, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x22, 0x2d, 0x0a, 0x0f, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x18,
|
0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x18,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x22,
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x22,
|
||||||
0x67, 0x0a, 0x07, 0x55, 0x52, 0x4c, 0x50, 0x61, 0x69, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x65,
|
0x84, 0x01, 0x0a, 0x07, 0x55, 0x52, 0x4c, 0x50, 0x61, 0x69, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x64,
|
||||||
0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01,
|
0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20,
|
||||||
0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55,
|
0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x18, 0x02,
|
0x55, 0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x18,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x12, 0x18,
|
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x12,
|
||||||
0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x29, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74,
|
0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x69, 0x74,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74,
|
0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x68, 0x69,
|
||||||
0x55, 0x52, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74,
|
0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x29, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
|
||||||
0x55, 0x52, 0x4c, 0x22, 0x38, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52,
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x08, 0x75, 0x72, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x73, 0x18,
|
0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52,
|
||||||
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x75, 0x72, 0x6c, 0x2e, 0x55, 0x52, 0x4c, 0x50,
|
0x4c, 0x22, 0x38, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x61, 0x69, 0x72, 0x52, 0x08, 0x75, 0x72, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x2a, 0x0a,
|
0x65, 0x12, 0x28, 0x0a, 0x08, 0x75, 0x72, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x73, 0x18, 0x01, 0x20,
|
||||||
0x0c, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
|
0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x75, 0x72, 0x6c, 0x2e, 0x55, 0x52, 0x4c, 0x50, 0x61, 0x69,
|
||||||
0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x72, 0x52, 0x08, 0x75, 0x72, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x2a, 0x0a, 0x0c, 0x50,
|
||||||
0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x22, 0x37, 0x0a, 0x0d, 0x50, 0x72, 0x6f,
|
0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73,
|
||||||
0x78, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x65,
|
0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73,
|
||||||
0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01,
|
0x68, 0x6f, 0x72, 0x74, 0x55, 0x52, 0x4c, 0x22, 0x37, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x78, 0x79,
|
||||||
0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55,
|
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x74,
|
||||||
0x52, 0x4c, 0x32, 0x9e, 0x01, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x12, 0x36, 0x0a, 0x07, 0x53, 0x68,
|
0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x6f, 0x72, 0x74, 0x65, 0x6e, 0x12, 0x13, 0x2e, 0x75, 0x72, 0x6c, 0x2e, 0x53, 0x68, 0x6f, 0x72,
|
0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x52, 0x4c,
|
||||||
0x74, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x72, 0x6c,
|
0x32, 0x9e, 0x01, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x12, 0x36, 0x0a, 0x07, 0x53, 0x68, 0x6f, 0x72,
|
||||||
0x2e, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x74, 0x65, 0x6e, 0x12, 0x13, 0x2e, 0x75, 0x72, 0x6c, 0x2e, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x65,
|
||||||
0x22, 0x00, 0x12, 0x2d, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x10, 0x2e, 0x75, 0x72, 0x6c,
|
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x72, 0x6c, 0x2e, 0x53,
|
||||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x75,
|
0x68, 0x6f, 0x72, 0x74, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||||
0x72, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
0x12, 0x2d, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x10, 0x2e, 0x75, 0x72, 0x6c, 0x2e, 0x4c,
|
||||||
0x00, 0x12, 0x30, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x11, 0x2e, 0x75, 0x72, 0x6c,
|
0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x75, 0x72, 0x6c,
|
||||||
0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e,
|
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
||||||
0x75, 0x72, 0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
0x30, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x11, 0x2e, 0x75, 0x72, 0x6c, 0x2e, 0x50,
|
||||||
0x65, 0x22, 0x00, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x75,
|
0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x75, 0x72,
|
||||||
0x72, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
|
0x00, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x75, 0x72, 0x6c,
|
||||||
|
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ message URLPair {
|
|||||||
string shortURL = 2;
|
string shortURL = 2;
|
||||||
// time of creation
|
// time of creation
|
||||||
string created = 4;
|
string created = 4;
|
||||||
|
// The number of times the short URL has been resolved
|
||||||
|
int64 hit_count = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all the shortened URLs
|
// List all the shortened URLs
|
||||||
|
|||||||
Reference in New Issue
Block a user