Skip to content

Commit

Permalink
use db for shared links
Browse files Browse the repository at this point in the history
  • Loading branch information
poundifdef committed Mar 18, 2024
1 parent 41181bd commit ff95d8f
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 33 deletions.
43 changes: 13 additions & 30 deletions pkg/api/share.go
Expand Up @@ -34,52 +34,35 @@ func (a *ScratchDataAPIStruct) CreateQuery(w http.ResponseWriter, r *http.Reques
return
}

cachedQueryData := CachedQueryData{
Query: requestBody.Query,
DatabaseID: a.AuthGetDatabaseID(r.Context()),
}
cachedQueryDataBytes, err := json.Marshal(cachedQueryData)

destId := a.AuthGetDatabaseID(r.Context())
expires := time.Duration(requestBody.Duration) * time.Second
sharedQueryId, err := a.storageServices.Database.CreateShareQuery(destId, requestBody.Query, expires)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Failed to marshal data"))
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}

// Generate a new UUID
queryUUID := uuid.New()

// Store the query and its expiration time
queryExpiration := time.Duration(requestBody.Duration)
a.storageServices.Cache.Set(queryUUID.String(), cachedQueryDataBytes, &queryExpiration)

// Return the UUID representing the query
render.JSON(w, r, render.M{"id": queryUUID.String()})
render.JSON(w, r, render.M{"id": sharedQueryId.String()})
}

func (a *ScratchDataAPIStruct) ShareData(w http.ResponseWriter, r *http.Request) {
queryUUID := chi.URLParam(r, "uuid")
format := chi.URLParam(r, "format")

// Retrieve query from cache using UUID
cachedQueryDataBytes, found := a.storageServices.Cache.Get(queryUUID)
if !found {
http.Error(w, "Query not found", http.StatusNotFound)
id, err := uuid.Parse(queryUUID)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

var cachedQueryData CachedQueryData
if err := json.Unmarshal(cachedQueryDataBytes, &cachedQueryData); err != nil {
http.Error(w, "Failed to unmarshal data", http.StatusInternalServerError)
cachedQuery, found := a.storageServices.Database.GetShareQuery(id)
if !found {
http.Error(w, "Query not found", http.StatusNotFound)
return
}

// Convert query to string
queryStr := cachedQueryData.Query

// Execute query and stream data
databaseID := cachedQueryData.DatabaseID
if err := a.executeQueryAndStreamData(w, queryStr, databaseID, format); err != nil {
if err := a.executeQueryAndStreamData(w, cachedQuery.Query, cachedQuery.DestinationID, format); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
13 changes: 10 additions & 3 deletions pkg/storage/database/database.go
@@ -1,19 +1,26 @@
package database

import (
"time"

"github.com/google/uuid"
"github.com/scratchdata/scratchdata/config"
"github.com/scratchdata/scratchdata/pkg/storage/database/memory"
"github.com/scratchdata/scratchdata/pkg/storage/database/models"
)

type Database interface {
VerifyAdminAPIKey(hashedAPIKey string) bool
GetAPIKeyDetails(hashedAPIKey string) (models.APIKey, error)

GetDestinationCredentials(dbID int64) (config.Destination, error)
GetDestinations() []config.Destination
CreateDestination(destType string, settings map[string]any) (config.Destination, error)
GetDestinationCredentials(dbID int64) (config.Destination, error)

AddAPIKey(destId int64, hashedAPIKey string) error
GetDestinations() []config.Destination
GetAPIKeyDetails(hashedAPIKey string) (models.APIKey, error)

CreateShareQuery(destId int64, query string, expires time.Duration) (queryId uuid.UUID, err error)
GetShareQuery(queryId uuid.UUID) (models.SharedQuery, bool)

Hash(s string) string
}
Expand Down
43 changes: 43 additions & 0 deletions pkg/storage/database/memory/memory.go
Expand Up @@ -2,7 +2,9 @@ package memory

import (
"errors"
"time"

"github.com/google/uuid"
"github.com/rs/zerolog/log"
"github.com/scratchdata/scratchdata/config"
"github.com/scratchdata/scratchdata/pkg/storage/database/models"
Expand Down Expand Up @@ -45,6 +47,47 @@ func (db *MemoryDatabase) VerifyAdminAPIKey(apiKey string) bool {
return false
}

func (db *MemoryDatabase) CreateShareQuery(destId int64, query string, expires time.Duration) (queryId uuid.UUID, err error) {
id := uuid.New()
link := ShareLink{
UUID: id.String(),
DestinationID: destId,
Query: query,
ExpiresAt: time.Now().Add(expires),
}

log.Print(link)
log.Print(time.Now())

res := db.sqlite.Create(&link)
if res.Error != nil {
return uuid.Nil, res.Error
}

return id, nil
}

func (db *MemoryDatabase) GetShareQuery(queryId uuid.UUID) (models.SharedQuery, bool) {
var link ShareLink
res := db.sqlite.First(&link, "uuid = ? AND expires_at > ?", queryId.String(), time.Now())
if res.Error != nil {
if !errors.Is(res.Error, gorm.ErrRecordNotFound) {
log.Error().Err(res.Error).Str("query_id", queryId.String()).Msg("Unable to find shared query")
}

return models.SharedQuery{}, false
}

rc := models.SharedQuery{
ID: link.UUID,
Query: link.Query,
ExpiresAt: link.ExpiresAt,
DestinationID: link.DestinationID,
}

return rc, true
}

func NewMemoryDatabase(conf config.Database, destinations []config.Destination, apiKeys []config.APIKey) *MemoryDatabase {
rc := MemoryDatabase{
conf: conf,
Expand Down
1 change: 1 addition & 0 deletions pkg/storage/database/memory/sqlite.go
Expand Up @@ -8,6 +8,7 @@ import (

type ShareLink struct {
gorm.Model
UUID string `gorm:"index:idx_uuid,unique"`
DestinationID int64
Query string
ExpiresAt time.Time
Expand Down
11 changes: 11 additions & 0 deletions pkg/storage/database/models/models.go
@@ -1,6 +1,17 @@
package models

import (
"time"
)

type APIKey struct {
ID string `toml:"id"`
DestinationID int64 `toml:"destination_id"`
}

type SharedQuery struct {
ID string
Query string
DestinationID int64
ExpiresAt time.Time
}

0 comments on commit ff95d8f

Please sign in to comment.