Conditions (ee version) (#1858)
* feat(backend): moved conditions to ee folder * feat(backend): fixed typo
This commit is contained in:
parent
4711bf28f0
commit
354f071fb0
5 changed files with 180 additions and 148 deletions
11
backend/internal/http/router/conditions.go
Normal file
11
backend/internal/http/router/conditions.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (e *Router) getConditions(w http.ResponseWriter, r *http.Request) {
|
||||
ResponseWithError(w, http.StatusNotImplemented, errors.New("no support"), time.Now(), r.URL.Path, 0)
|
||||
}
|
||||
|
|
@ -645,32 +645,3 @@ func (e *Router) getTags(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
ResponseWithJSON(w, &UrlResponse{Tags: tags}, startTime, r.URL.Path, bodySize)
|
||||
}
|
||||
|
||||
func (e *Router) getConditions(w http.ResponseWriter, r *http.Request) {
|
||||
startTime := time.Now()
|
||||
bodySize := 0
|
||||
|
||||
// Check authorization
|
||||
_, err := e.services.Tokenizer.ParseFromHTTPRequest(r)
|
||||
if err != nil {
|
||||
ResponseWithError(w, http.StatusUnauthorized, err, startTime, r.URL.Path, bodySize)
|
||||
return
|
||||
}
|
||||
|
||||
// Get taskID
|
||||
vars := mux.Vars(r)
|
||||
projID := vars["project"]
|
||||
projectID, err := strconv.Atoi(projID)
|
||||
if err != nil {
|
||||
ResponseWithError(w, http.StatusBadRequest, err, startTime, r.URL.Path, bodySize)
|
||||
return
|
||||
}
|
||||
|
||||
// Get task info
|
||||
info, err := e.services.Conditions.Get(uint32(projectID))
|
||||
if err != nil {
|
||||
ResponseWithError(w, http.StatusInternalServerError, err, startTime, r.URL.Path, bodySize)
|
||||
return
|
||||
}
|
||||
ResponseWithJSON(w, info, startTime, r.URL.Path, bodySize)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,129 +1,13 @@
|
|||
package conditions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"openreplay/backend/pkg/db/postgres/pool"
|
||||
)
|
||||
|
||||
type Conditions interface {
|
||||
Get(projectID uint32) (*Response, error)
|
||||
GetRate(projectID uint32, condition string) (int, error)
|
||||
}
|
||||
type Conditions interface{}
|
||||
|
||||
type conditionsImpl struct {
|
||||
db pool.Pool
|
||||
cache map[uint32]map[string]int // projectID -> condition -> rate
|
||||
}
|
||||
type conditionsImpl struct{}
|
||||
|
||||
func New(db pool.Pool) Conditions {
|
||||
return &conditionsImpl{
|
||||
db: db,
|
||||
cache: make(map[uint32]map[string]int),
|
||||
}
|
||||
}
|
||||
|
||||
type ConditionType string
|
||||
|
||||
const (
|
||||
VisitedURL ConditionType = "visited_url"
|
||||
RequestURL ConditionType = "request_url"
|
||||
ClickLabel ConditionType = "click_label"
|
||||
ClickSelector ConditionType = "click_selector"
|
||||
CustomEvent ConditionType = "custom_event"
|
||||
Exception ConditionType = "exception"
|
||||
FeatureFlag ConditionType = "feature_flag"
|
||||
SessionDuration ConditionType = "session_duration"
|
||||
)
|
||||
|
||||
type ConditionOperator string
|
||||
|
||||
const (
|
||||
Is ConditionOperator = "is"
|
||||
IsNot ConditionOperator = "isNot"
|
||||
Contains ConditionOperator = "contains"
|
||||
NotContains ConditionOperator = "notContains"
|
||||
StartsWith ConditionOperator = "startsWith"
|
||||
EndsWith ConditionOperator = "endsWith"
|
||||
)
|
||||
|
||||
type Condition struct {
|
||||
Type ConditionType `json:"type"`
|
||||
Operator ConditionOperator `json:"operator"`
|
||||
Values []string `json:"value"`
|
||||
}
|
||||
|
||||
type ConditionSet struct {
|
||||
Name string `json:"name"`
|
||||
Filters interface{} `json:"filters"`
|
||||
Rate int `json:"capture_rate"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Conditions interface{} `json:"conditions"`
|
||||
}
|
||||
|
||||
func (c *conditionsImpl) getConditions(projectID uint32) ([]ConditionSet, error) {
|
||||
var conditions []ConditionSet
|
||||
rows, err := c.db.Query(`
|
||||
SELECT name, capture_rate, filters
|
||||
FROM projects_conditions
|
||||
WHERE project_id = $1
|
||||
`, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var name string
|
||||
var rate int
|
||||
var filters interface{}
|
||||
if err := rows.Scan(&name, &rate, &filters); err != nil {
|
||||
log.Printf("can't scan row: %s", err)
|
||||
continue
|
||||
}
|
||||
conditions = append(conditions, ConditionSet{
|
||||
Name: name,
|
||||
Filters: filters,
|
||||
Rate: rate,
|
||||
})
|
||||
}
|
||||
|
||||
// Save project's conditions to cache
|
||||
conditionSet := make(map[string]int)
|
||||
for _, condition := range conditions {
|
||||
conditionSet[condition.Name] = condition.Rate
|
||||
}
|
||||
c.cache[projectID] = conditionSet
|
||||
|
||||
if conditions == nil {
|
||||
return []ConditionSet{}, nil
|
||||
}
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
func (c *conditionsImpl) Get(projectID uint32) (*Response, error) {
|
||||
conditions, err := c.getConditions(projectID)
|
||||
return &Response{Conditions: conditions}, err
|
||||
}
|
||||
|
||||
func (c *conditionsImpl) GetRate(projectID uint32, condition string) (int, error) {
|
||||
proj, ok := c.cache[projectID]
|
||||
if ok {
|
||||
rate, ok := proj[condition]
|
||||
if ok {
|
||||
return rate, nil
|
||||
}
|
||||
}
|
||||
// Don't have project's conditions in cache or particular condition
|
||||
_, err := c.getConditions(projectID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rate, ok := c.cache[projectID][condition]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("condition %s not found", condition)
|
||||
}
|
||||
return rate, nil
|
||||
return &conditionsImpl{}
|
||||
}
|
||||
|
|
|
|||
37
ee/backend/internal/http/conditions.go
Normal file
37
ee/backend/internal/http/conditions.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (e *Router) getConditions(w http.ResponseWriter, r *http.Request) {
|
||||
startTime := time.Now()
|
||||
bodySize := 0
|
||||
|
||||
// Check authorization
|
||||
_, err := e.services.Tokenizer.ParseFromHTTPRequest(r)
|
||||
if err != nil {
|
||||
ResponseWithError(w, http.StatusUnauthorized, err, startTime, r.URL.Path, bodySize)
|
||||
return
|
||||
}
|
||||
|
||||
// Get taskID
|
||||
vars := mux.Vars(r)
|
||||
projID := vars["project"]
|
||||
projectID, err := strconv.Atoi(projID)
|
||||
if err != nil {
|
||||
ResponseWithError(w, http.StatusBadRequest, err, startTime, r.URL.Path, bodySize)
|
||||
return
|
||||
}
|
||||
|
||||
// Get task info
|
||||
info, err := e.services.Conditions.Get(uint32(projectID))
|
||||
if err != nil {
|
||||
ResponseWithError(w, http.StatusInternalServerError, err, startTime, r.URL.Path, bodySize)
|
||||
return
|
||||
}
|
||||
ResponseWithJSON(w, info, startTime, r.URL.Path, bodySize)
|
||||
}
|
||||
129
ee/backend/pkg/conditions/conditions.go
Normal file
129
ee/backend/pkg/conditions/conditions.go
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
package conditions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"openreplay/backend/pkg/db/postgres/pool"
|
||||
)
|
||||
|
||||
type Conditions interface {
|
||||
Get(projectID uint32) (*Response, error)
|
||||
GetRate(projectID uint32, condition string) (int, error)
|
||||
}
|
||||
|
||||
type conditionsImpl struct {
|
||||
db pool.Pool
|
||||
cache map[uint32]map[string]int // projectID -> condition -> rate
|
||||
}
|
||||
|
||||
func New(db pool.Pool) Conditions {
|
||||
return &conditionsImpl{
|
||||
db: db,
|
||||
cache: make(map[uint32]map[string]int),
|
||||
}
|
||||
}
|
||||
|
||||
type ConditionType string
|
||||
|
||||
const (
|
||||
VisitedURL ConditionType = "visited_url"
|
||||
RequestURL ConditionType = "request_url"
|
||||
ClickLabel ConditionType = "click_label"
|
||||
ClickSelector ConditionType = "click_selector"
|
||||
CustomEvent ConditionType = "custom_event"
|
||||
Exception ConditionType = "exception"
|
||||
FeatureFlag ConditionType = "feature_flag"
|
||||
SessionDuration ConditionType = "session_duration"
|
||||
)
|
||||
|
||||
type ConditionOperator string
|
||||
|
||||
const (
|
||||
Is ConditionOperator = "is"
|
||||
IsNot ConditionOperator = "isNot"
|
||||
Contains ConditionOperator = "contains"
|
||||
NotContains ConditionOperator = "notContains"
|
||||
StartsWith ConditionOperator = "startsWith"
|
||||
EndsWith ConditionOperator = "endsWith"
|
||||
)
|
||||
|
||||
type Condition struct {
|
||||
Type ConditionType `json:"type"`
|
||||
Operator ConditionOperator `json:"operator"`
|
||||
Values []string `json:"value"`
|
||||
}
|
||||
|
||||
type ConditionSet struct {
|
||||
Name string `json:"name"`
|
||||
Filters interface{} `json:"filters"`
|
||||
Rate int `json:"capture_rate"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Conditions interface{} `json:"conditions"`
|
||||
}
|
||||
|
||||
func (c *conditionsImpl) getConditions(projectID uint32) ([]ConditionSet, error) {
|
||||
var conditions []ConditionSet
|
||||
rows, err := c.db.Query(`
|
||||
SELECT name, capture_rate, filters
|
||||
FROM projects_conditions
|
||||
WHERE project_id = $1
|
||||
`, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var name string
|
||||
var rate int
|
||||
var filters interface{}
|
||||
if err := rows.Scan(&name, &rate, &filters); err != nil {
|
||||
log.Printf("can't scan row: %s", err)
|
||||
continue
|
||||
}
|
||||
conditions = append(conditions, ConditionSet{
|
||||
Name: name,
|
||||
Filters: filters,
|
||||
Rate: rate,
|
||||
})
|
||||
}
|
||||
|
||||
// Save project's conditions to cache
|
||||
conditionSet := make(map[string]int)
|
||||
for _, condition := range conditions {
|
||||
conditionSet[condition.Name] = condition.Rate
|
||||
}
|
||||
c.cache[projectID] = conditionSet
|
||||
|
||||
if conditions == nil {
|
||||
return []ConditionSet{}, nil
|
||||
}
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
func (c *conditionsImpl) Get(projectID uint32) (*Response, error) {
|
||||
conditions, err := c.getConditions(projectID)
|
||||
return &Response{Conditions: conditions}, err
|
||||
}
|
||||
|
||||
func (c *conditionsImpl) GetRate(projectID uint32, condition string) (int, error) {
|
||||
proj, ok := c.cache[projectID]
|
||||
if ok {
|
||||
rate, ok := proj[condition]
|
||||
if ok {
|
||||
return rate, nil
|
||||
}
|
||||
}
|
||||
// Don't have project's conditions in cache or particular condition
|
||||
_, err := c.getConditions(projectID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rate, ok := c.cache[projectID][condition]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("condition %s not found", condition)
|
||||
}
|
||||
return rate, nil
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue