From 47e6163aedf31db01de70ac7217f13e0d557bdac Mon Sep 17 00:00:00 2001 From: Matt Bonnell Date: Thu, 21 May 2020 23:18:09 -0400 Subject: [PATCH 1/2] interaction debouncing window implemented and working --- Makefile | 4 ++-- proximity/config/config.go | 3 +++ proximity/pkg/handlers/api_handlers.go | 19 ++++++++++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 9942810..49a41b4 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ clean-scoring: rm -f ./scoring/$(BUILD_DIR)/${BINARY_NAME} clean: clean-circle clean-proximity clean-scoring token: - ./auth/cmd/tokengen/tokengen.out -u $(uid) + ./auth/cmd/tokengen/tokengen.out -u $(uid) | pbcopy run: ./$(PACKAGE)$(BUILD_DIR)/$(EXEC) $(ARGS) push-deps: @@ -54,4 +54,4 @@ build: build-deps stop: docker-compose down ${service} - @echo Services torn down \ No newline at end of file + @echo Services torn down diff --git a/proximity/config/config.go b/proximity/config/config.go index 15230a6..3f40804 100644 --- a/proximity/config/config.go +++ b/proximity/config/config.go @@ -18,3 +18,6 @@ var Middleware = []mux.MiddlewareFunc{ // ProductionTopic is the Kafka topic this service produces to const ProductionTopic = "interaction_added" + +// InteractionDebouncingPeriod is the number of seconds after receiving an interaction between two users for which subsequent interactions should be ignored +const InteractionDebouncingPeriod = 60 diff --git a/proximity/pkg/handlers/api_handlers.go b/proximity/pkg/handlers/api_handlers.go index aae5511..a9de21b 100644 --- a/proximity/pkg/handlers/api_handlers.go +++ b/proximity/pkg/handlers/api_handlers.go @@ -2,12 +2,15 @@ package handlers import ( "encoding/json" + "errors" "fmt" "log" "net/http" + "time" "github.com/safe-distance/socium-infra/auth" "github.com/safe-distance/socium-infra/common" + "github.com/safe-distance/socium-infra/proximity/config" "github.com/safe-distance/socium-infra/proximity/pkg/models" ) @@ -38,6 +41,20 @@ func AddInteraction(s *common.Service) http.Handler { json.NewEncoder(w).Encode(response) return } + // Check if we've already registered an interaction for these users in the debouncing window + startOfDebouncingPeriod := interaction.Timestamp.Add(-config.InteractionDebouncingPeriod * time.Second) + fmt.Printf("start of debouncing period: %v\n", startOfDebouncingPeriod) + var mostRecentInteraction models.Interaction + if err := s.DB.Where(models.Interaction{UID: user.ID, OtherUID: otherUserUID}).Or(models.Interaction{UID: otherUserUID, OtherUID: user.ID}).First(&mostRecentInteraction).Error; err != nil { + common.ThrowError(w, fmt.Errorf("error retrieving most recent interaction between %v and %v: %v", user.ID, otherUserUID, err), http.StatusAlreadyReported) + return + } + if mostRecentInteraction.Timestamp.After(startOfDebouncingPeriod) { + msg := fmt.Sprintf("error: interaction between these two users recorded at %v", mostRecentInteraction.Timestamp) + common.ThrowError(w, errors.New(msg), http.StatusAlreadyReported) + return + } + // Add the user's UID from the auth token to the interaction interaction.UID = user.ID interaction.OtherUID = otherUserUID @@ -45,7 +62,7 @@ func AddInteraction(s *common.Service) http.Handler { json.NewEncoder(w).Encode(&interaction) fmt.Printf("created interaction: %+v\n", interaction) - // Log a new interaction (send msg to kafka) + // Publish a new interaction (send msg to kafka) common.LogObject(s.Producer, string(interaction.ID), interaction, s.ProductionTopic) }) From ff74d2423e539451a96ddb0d4815839100c6b3cf Mon Sep 17 00:00:00 2001 From: Matt Bonnell Date: Thu, 21 May 2020 23:58:27 -0400 Subject: [PATCH 2/2] extracted debouncing period to env var --- docker-compose.yml | 1 + proximity/config/config.go | 15 ++++++++++++++- proximity/pkg/handlers/api_handlers.go | 8 +++++--- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ec3190d..6643171 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -91,6 +91,7 @@ services: PORT: $PORT KAFKA_PEERS: kafka:9092 GOOGLE_APPLICATION_CREDENTIALS: /run/secrets/google_application_credentials + INTERACTION_DEBOUNCING_PERIOD_SECONDS: $INTERACTION_DEBOUNCING_PERIOD_SECONDS expose: - $PORT secrets: diff --git a/proximity/config/config.go b/proximity/config/config.go index 3f40804..c055013 100644 --- a/proximity/config/config.go +++ b/proximity/config/config.go @@ -1,6 +1,9 @@ package config import ( + "os" + "strconv" + "github.com/gorilla/mux" "github.com/safe-distance/socium-infra/auth" ) @@ -19,5 +22,15 @@ var Middleware = []mux.MiddlewareFunc{ // ProductionTopic is the Kafka topic this service produces to const ProductionTopic = "interaction_added" +const debouncingPeriodEnvVariableName = "INTERACTION_DEBOUNCING_PERIOD_SECONDS" + // InteractionDebouncingPeriod is the number of seconds after receiving an interaction between two users for which subsequent interactions should be ignored -const InteractionDebouncingPeriod = 60 +func InteractionDebouncingPeriod() int { + period, err := strconv.Atoi(os.Getenv(debouncingPeriodEnvVariableName)) + if err != nil { + return defaultInteractionDebouncingPeriod + } + return period +} + +const defaultInteractionDebouncingPeriod = 60 diff --git a/proximity/pkg/handlers/api_handlers.go b/proximity/pkg/handlers/api_handlers.go index a9de21b..72cdfef 100644 --- a/proximity/pkg/handlers/api_handlers.go +++ b/proximity/pkg/handlers/api_handlers.go @@ -42,14 +42,16 @@ func AddInteraction(s *common.Service) http.Handler { return } // Check if we've already registered an interaction for these users in the debouncing window - startOfDebouncingPeriod := interaction.Timestamp.Add(-config.InteractionDebouncingPeriod * time.Second) + startOfDebouncingPeriod := interaction.Timestamp.Add(-1 * time.Duration(config.InteractionDebouncingPeriod()) * time.Second) fmt.Printf("start of debouncing period: %v\n", startOfDebouncingPeriod) var mostRecentInteraction models.Interaction - if err := s.DB.Where(models.Interaction{UID: user.ID, OtherUID: otherUserUID}).Or(models.Interaction{UID: otherUserUID, OtherUID: user.ID}).First(&mostRecentInteraction).Error; err != nil { + query := s.DB.Where(models.Interaction{UID: user.ID, OtherUID: otherUserUID}).Or(models.Interaction{UID: otherUserUID, OtherUID: user.ID}).Order("timestamp desc") + query = query.Attrs(models.Interaction{UID: "not_found"}).FirstOrInit(&mostRecentInteraction) + if query.Error != nil { common.ThrowError(w, fmt.Errorf("error retrieving most recent interaction between %v and %v: %v", user.ID, otherUserUID, err), http.StatusAlreadyReported) return } - if mostRecentInteraction.Timestamp.After(startOfDebouncingPeriod) { + if mostRecentInteraction.UID != "not_found" && mostRecentInteraction.Timestamp.After(startOfDebouncingPeriod) { msg := fmt.Sprintf("error: interaction between these two users recorded at %v", mostRecentInteraction.Timestamp) common.ThrowError(w, errors.New(msg), http.StatusAlreadyReported) return