Compare commits

..

6 Commits

Author SHA1 Message Date
RoyUP9
da846da334 api server support sync workspace (#340) 2021-10-11 13:09:23 +03:00
RoyUP9
ba6b5c868c added semver isvalid check in version update checker (#338) 2021-10-11 11:32:41 +03:00
RoyUP9
9d378ed75b refactor login (#339) 2021-10-11 11:31:12 +03:00
M. Mert Yıldıran
70982c2844 Fix the interface conversion errors in Redis (#334) 2021-10-10 08:34:47 +03:00
M. Mert Yıldıran
61f24320b8 Fix the issues in the Tabs React component (#335)
* Fix the issues in the `Tabs` React component

* Update the boolean expression as well
2021-10-09 13:16:08 +03:00
M. Mert Yıldıran
eb4a541376 Fix the interface conversion errors in Kafka (#333) 2021-10-08 07:35:20 +03:00
17 changed files with 234 additions and 156 deletions

View File

@@ -10,6 +10,7 @@ import (
"mizuserver/pkg/utils"
"mizuserver/pkg/validation"
"net/http"
"regexp"
"time"
"github.com/google/martian/har"
@@ -72,23 +73,46 @@ func SyncEntries(c *gin.Context) {
c.JSON(http.StatusBadRequest, err)
return
}
if err := validation.Validate(syncParams); err != nil {
c.JSON(http.StatusBadRequest, err)
return
}
if up9.GetAnalyzeInfo().IsAnalyzing {
c.String(http.StatusBadRequest, "Cannot analyze, mizu is already analyzing")
return
}
rlog.Infof("Sync entries - creating token. env %s\n", syncParams.Env)
token, err := up9.CreateAnonymousToken(syncParams.Env)
if err != nil {
c.String(http.StatusServiceUnavailable, "Cannot analyze, mizu is already analyzing")
var (
token, model string
guestMode bool
)
if syncParams.Token == "" {
rlog.Infof("Sync entries - creating token. env %s\n", syncParams.Env)
guestToken, err := up9.CreateAnonymousToken(syncParams.Env)
if err != nil {
c.String(http.StatusServiceUnavailable, "Failed creating anonymous token")
return
}
token = guestToken.Token
model = guestToken.Model
guestMode = true
} else {
token = fmt.Sprintf("bearer %s", syncParams.Token)
model = syncParams.Workspace
guestMode = false
}
modelRegex, _ := regexp.Compile("[A-Za-z0-9][-A-Za-z0-9_.]*[A-Za-z0-9]+$")
if len(model) > 63 || !modelRegex.MatchString(model) {
c.String(http.StatusBadRequest, "Invalid model name")
return
}
rlog.Infof("Sync entries - syncing. token: %s model: %s\n", token.Token, token.Model)
go up9.SyncEntriesImpl(token.Token, token.Model, syncParams.Env, syncParams.SleepIntervalSec)
rlog.Infof("Sync entries - syncing. token: %s, model: %s, guest mode: %v\n", token, model, guestMode)
go up9.SyncEntriesImpl(token, model, syncParams.Env, syncParams.UploadIntervalSec, guestMode)
c.String(http.StatusOK, "OK")
}

View File

@@ -23,8 +23,10 @@ type EntriesFilter struct {
}
type SyncEntriesRequestQuery struct {
Env string `form:"env"`
SleepIntervalSec int `form:"interval"`
Token string `form:"token"`
Env string `form:"env"`
Workspace string `form:"workspace"`
UploadIntervalSec int `form:"interval"`
}
type HarFetchRequestQuery struct {

View File

@@ -59,14 +59,16 @@ func GetRemoteUrl(analyzeDestination string, analyzeToken string) string {
return fmt.Sprintf("https://%s/share/%s", analyzeDestination, analyzeToken)
}
func CheckIfModelReady(analyzeDestination string, analyzeModel string, analyzeToken string) bool {
func CheckIfModelReady(analyzeDestination string, analyzeModel string, analyzeToken string, guestMode bool) bool {
statusUrl, _ := url.Parse(fmt.Sprintf("https://trcc.%s/models/%s/status", analyzeDestination, analyzeModel))
authHeader := getAuthHeader(guestMode)
req := &http.Request{
Method: http.MethodGet,
URL: statusUrl,
Header: map[string][]string{
"Content-Type": {"application/json"},
"Guest-Auth": {analyzeToken},
authHeader: {analyzeToken},
},
}
statusResp, err := http.DefaultClient.Do(req)
@@ -81,6 +83,14 @@ func CheckIfModelReady(analyzeDestination string, analyzeModel string, analyzeTo
return target.LastMajorGeneration > 0
}
func getAuthHeader(guestMode bool) string {
if guestMode {
return "Guest-Auth"
}
return "Authorization"
}
func GetTrafficDumpUrl(analyzeDestination string, analyzeModel string) *url.URL {
strUrl := fmt.Sprintf("https://traffic.%s/dumpTrafficBulk/%s", analyzeDestination, analyzeModel)
if strings.HasPrefix(analyzeDestination, "http") {
@@ -92,6 +102,7 @@ func GetTrafficDumpUrl(analyzeDestination string, analyzeModel string) *url.URL
type AnalyzeInformation struct {
IsAnalyzing bool
GuestMode bool
SentCount int
AnalyzedModel string
AnalyzeToken string
@@ -100,6 +111,7 @@ type AnalyzeInformation struct {
func (info *AnalyzeInformation) Reset() {
info.IsAnalyzing = false
info.GuestMode = true
info.AnalyzedModel = ""
info.AnalyzeToken = ""
info.AnalyzeDestination = ""
@@ -112,19 +124,20 @@ func GetAnalyzeInfo() *shared.AnalyzeStatus {
return &shared.AnalyzeStatus{
IsAnalyzing: analyzeInformation.IsAnalyzing,
RemoteUrl: GetRemoteUrl(analyzeInformation.AnalyzeDestination, analyzeInformation.AnalyzeToken),
IsRemoteReady: CheckIfModelReady(analyzeInformation.AnalyzeDestination, analyzeInformation.AnalyzedModel, analyzeInformation.AnalyzeToken),
IsRemoteReady: CheckIfModelReady(analyzeInformation.AnalyzeDestination, analyzeInformation.AnalyzedModel, analyzeInformation.AnalyzeToken, analyzeInformation.GuestMode),
SentCount: analyzeInformation.SentCount,
}
}
func SyncEntriesImpl(token string, model string, envPrefix string, sleepIntervalSec int) {
func SyncEntriesImpl(token string, model string, envPrefix string, uploadIntervalSec int, guestMode bool) {
analyzeInformation.IsAnalyzing = true
analyzeInformation.GuestMode = guestMode
analyzeInformation.AnalyzedModel = model
analyzeInformation.AnalyzeToken = token
analyzeInformation.AnalyzeDestination = envPrefix
analyzeInformation.SentCount = 0
sleepTime := time.Second * time.Duration(sleepIntervalSec)
sleepTime := time.Second * time.Duration(uploadIntervalSec)
var timestampFrom int64 = 0
@@ -170,13 +183,14 @@ func SyncEntriesImpl(token string, model string, envPrefix string, sleepInterval
_ = w.Close()
reqBody := ioutil.NopCloser(bytes.NewReader(in.Bytes()))
authHeader := getAuthHeader(guestMode)
req := &http.Request{
Method: http.MethodPost,
URL: GetTrafficDumpUrl(envPrefix, model),
Header: map[string][]string{
"Content-Encoding": {"deflate"},
"Content-Type": {"application/octet-stream"},
"Guest-Auth": {token},
authHeader: {token},
},
Body: reqBody,
}

View File

@@ -4,12 +4,17 @@ import (
"context"
"errors"
"fmt"
"github.com/creasty/defaults"
"github.com/golang-jwt/jwt/v4"
"github.com/google/uuid"
"github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/logger"
"github.com/up9inc/mizu/cli/uiUtils"
"golang.org/x/oauth2"
"net"
"net/http"
"os"
"time"
)
@@ -18,12 +23,60 @@ const loginTimeoutInMin = 2
// Ports are configured in keycloak "cli" client as valid redirect URIs. A change here must be reflected there as well.
var listenPorts = []int{3141, 4001, 5002, 6003, 7004, 8005, 9006, 10007}
func LoginInteractively(envName string) (*oauth2.Token, error) {
func IsTokenExpired(tokenString string) (bool, error) {
token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil {
return true, fmt.Errorf("failed to parse token, err: %v", err)
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return true, fmt.Errorf("can't convert token's claims to standard claims")
}
expiry := time.Unix(int64(claims["exp"].(float64)), 0)
return time.Now().After(expiry), nil
}
func Login() error {
token, err := loginInteractively()
if err != nil {
return fmt.Errorf("failed login interactively, err: %v", err)
}
authConfig := configStructs.AuthConfig{
EnvName: config.Config.Auth.EnvName,
Token: token.AccessToken,
}
configFile := config.ConfigStruct{}
if err := defaults.Set(&configFile); err != nil {
return fmt.Errorf("failed inserting default values to config, err: %v", err)
}
if err := config.LoadConfigFile(config.Config.ConfigFilePath, &configFile); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed getting config file, err: %v", err)
}
configFile.Auth = authConfig
if err := config.WriteConfig(&configFile); err != nil {
return fmt.Errorf("failed writing config with auth, err: %v", err)
}
config.Config.Auth = authConfig
logger.Log.Infof("Login successfully, token stored in config path: %s", fmt.Sprintf(uiUtils.Purple, config.Config.ConfigFilePath))
return nil
}
func loginInteractively() (*oauth2.Token, error) {
tokenChannel := make(chan *oauth2.Token)
errorChannel := make(chan error)
server := http.Server{}
go startLoginServer(tokenChannel, errorChannel, envName, &server)
go startLoginServer(tokenChannel, errorChannel, &server)
defer func() {
if err := server.Shutdown(context.Background()); err != nil {
@@ -41,14 +94,14 @@ func LoginInteractively(envName string) (*oauth2.Token, error) {
}
}
func startLoginServer(tokenChannel chan *oauth2.Token, errorChannel chan error, envName string, server *http.Server) {
func startLoginServer(tokenChannel chan *oauth2.Token, errorChannel chan error, server *http.Server) {
for _, port := range listenPorts {
var config = &oauth2.Config{
var authConfig = &oauth2.Config{
ClientID: "cli",
RedirectURL: fmt.Sprintf("http://localhost:%v/callback", port),
Endpoint: oauth2.Endpoint{
AuthURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/auth", envName),
TokenURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/token", envName),
AuthURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/auth", config.Config.Auth.EnvName),
TokenURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/token", config.Config.Auth.EnvName),
},
}
@@ -56,7 +109,7 @@ func startLoginServer(tokenChannel chan *oauth2.Token, errorChannel chan error,
mux := http.NewServeMux()
server.Handler = mux
mux.Handle("/callback", loginCallbackHandler(tokenChannel, errorChannel, config, envName, state))
mux.Handle("/callback", loginCallbackHandler(tokenChannel, errorChannel, authConfig, state))
listener, listenErr := net.Listen("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", port))
if listenErr != nil {
@@ -64,7 +117,7 @@ func startLoginServer(tokenChannel chan *oauth2.Token, errorChannel chan error,
continue
}
authorizationUrl := config.AuthCodeURL(state.String())
authorizationUrl := authConfig.AuthCodeURL(state.String())
uiUtils.OpenBrowser(authorizationUrl)
serveErr := server.Serve(listener)
@@ -83,7 +136,7 @@ func startLoginServer(tokenChannel chan *oauth2.Token, errorChannel chan error,
errorChannel <- fmt.Errorf("failed to start serving on all listen ports, ports: %v", listenPorts)
}
func loginCallbackHandler(tokenChannel chan *oauth2.Token, errorChannel chan error, config *oauth2.Config, envName string, state uuid.UUID) http.Handler {
func loginCallbackHandler(tokenChannel chan *oauth2.Token, errorChannel chan error, authConfig *oauth2.Config, state uuid.UUID) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
if err := request.ParseForm(); err != nil {
errorMsg := fmt.Sprintf("failed to parse form, err: %v", err)
@@ -108,7 +161,7 @@ func loginCallbackHandler(tokenChannel chan *oauth2.Token, errorChannel chan err
return
}
token, err := config.Exchange(context.Background(), code)
token, err := authConfig.Exchange(context.Background(), code)
if err != nil {
errorMsg := fmt.Sprintf("failed to create token, err: %v", err)
http.Error(writer, errorMsg, http.StatusInternalServerError)
@@ -118,6 +171,6 @@ func loginCallbackHandler(tokenChannel chan *oauth2.Token, errorChannel chan err
tokenChannel <- token
http.Redirect(writer, request, fmt.Sprintf("https://%s/CliLogin", envName), http.StatusFound)
http.Redirect(writer, request, fmt.Sprintf("https://%s/CliLogin", config.Config.Auth.EnvName), http.StatusFound)
})
}

View File

@@ -1,15 +0,0 @@
package cmd
import (
"github.com/spf13/cobra"
)
var authCmd = &cobra.Command{
Use: "auth",
Short: "Authenticate to up9 application",
}
func init() {
rootCmd.AddCommand(authCmd)
}

View File

@@ -1,44 +0,0 @@
package cmd
import (
"github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/auth"
"github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/logger"
"github.com/up9inc/mizu/cli/telemetry"
)
var authLoginCmd = &cobra.Command{
Use: "login",
Short: "Login to up9 application",
RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("authLogin", config.Config.Auth)
token, err := auth.LoginInteractively(config.Config.Auth.EnvName)
if err != nil {
logger.Log.Errorf("Failed login interactively, err: %v", err)
return nil
}
authConfig := configStructs.AuthConfig{
EnvName: config.Config.Auth.EnvName,
Token: token.AccessToken,
}
config.Config.Auth = authConfig
if err := config.WriteConfig(&config.Config); err != nil {
logger.Log.Errorf("Failed writing config with auth, err: %v", err)
return nil
}
logger.Log.Infof("Login successfully, token stored in config")
return nil
},
}
func init() {
authCmd.AddCommand(authLoginCmd)
}

View File

@@ -1,31 +0,0 @@
package cmd
import (
"github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/logger"
"github.com/up9inc/mizu/cli/telemetry"
)
var authLogoutCmd = &cobra.Command{
Use: "logout",
Short: "Logout from up9 application",
RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("authLogout", config.Config.Auth)
config.Config.Auth.Token = ""
if err := config.WriteConfig(&config.Config); err != nil {
logger.Log.Errorf("Failed writing config with default auth, err: %v", err)
return nil
}
logger.Log.Infof("Logout successfully, token removed from config")
return nil
},
}
func init() {
authCmd.AddCommand(authLogoutCmd)
}

View File

@@ -39,7 +39,7 @@ func InitConfig(cmd *cobra.Command) error {
configFilePathFlag := cmd.Flags().Lookup(ConfigFilePathCommandName)
configFilePath := configFilePathFlag.Value.String()
if err := mergeConfigFile(configFilePath); err != nil {
if err := LoadConfigFile(configFilePath, &Config); err != nil {
if configFilePathFlag.Changed || !os.IsNotExist(err) {
return fmt.Errorf("invalid config, %w\n"+
"you can regenerate the file by removing it (%v) and using `mizu config -r`", err, configFilePath)
@@ -80,7 +80,7 @@ func WriteConfig(config *ConfigStruct) error {
return nil
}
func mergeConfigFile(configFilePath string) error {
func LoadConfigFile(configFilePath string, config *ConfigStruct) error {
reader, openErr := os.Open(configFilePath)
if openErr != nil {
return openErr
@@ -91,10 +91,11 @@ func mergeConfigFile(configFilePath string) error {
return readErr
}
if err := yaml.Unmarshal(buf, &Config); err != nil {
if err := yaml.Unmarshal(buf, config); err != nil {
return err
}
logger.Log.Debugf("Found config file, merged to default options")
logger.Log.Debugf("Found config file, config path: %s", configFilePath)
return nil
}

View File

@@ -5,6 +5,7 @@ go 1.16
require (
github.com/creasty/defaults v1.5.1
github.com/denisbrodbeck/machineid v1.0.1
github.com/golang-jwt/jwt/v4 v4.1.0
github.com/google/go-github/v37 v37.0.0
github.com/google/uuid v1.1.2
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7

View File

@@ -175,6 +175,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=

View File

@@ -75,6 +75,12 @@ func CheckNewerVersion(versionChan chan string) {
gitHubVersionSemVer := semver.SemVersion(gitHubVersion)
currentSemVer := semver.SemVersion(mizu.SemVer)
if !gitHubVersionSemVer.IsValid() || !currentSemVer.IsValid() {
logger.Log.Debugf("[ERROR] Semver version is not valid, github version %v, current version %v", gitHubVersion, currentSemVer)
versionChan <- ""
return
}
logger.Log.Debugf("Finished version validation, github version %v, current version %v, took %v", gitHubVersion, currentSemVer, time.Since(start))
if gitHubVersionSemVer.GreaterThan(currentSemVer) {

View File

@@ -6,9 +6,17 @@ import (
type SemVersion string
func (v SemVersion) IsValid() bool {
re := regexp.MustCompile(`\d+`)
breakdown := re.FindAllString(string(v), 3)
return len(breakdown) == 3
}
func (v SemVersion) Breakdown() (string, string, string) {
re := regexp.MustCompile(`\d+`)
breakdown := re.FindAllString(string(v), 3)
return breakdown[0], breakdown[1], breakdown[2]
}

View File

@@ -130,8 +130,16 @@ func representMetadataResponse(data map[string]interface{}) []interface{} {
rep = representResponseHeader(data, rep)
payload := data["Payload"].(map[string]interface{})
topics, _ := json.Marshal(payload["Topics"].([]interface{}))
brokers, _ := json.Marshal(payload["Brokers"].([]interface{}))
topics := ""
if payload["Topics"] != nil {
_topics, _ := json.Marshal(payload["Topics"].([]interface{}))
topics = string(_topics)
}
brokers := ""
if payload["Brokers"] != nil {
_brokers, _ := json.Marshal(payload["Brokers"].([]interface{}))
brokers = string(_brokers)
}
controllerID := ""
clusterID := ""
throttleTimeMs := ""
@@ -155,7 +163,7 @@ func representMetadataResponse(data map[string]interface{}) []interface{} {
},
{
"name": "Brokers",
"value": string(brokers),
"value": brokers,
},
{
"name": "Cluster ID",
@@ -167,7 +175,7 @@ func representMetadataResponse(data map[string]interface{}) []interface{} {
},
{
"name": "Topics",
"value": string(topics),
"value": topics,
},
{
"name": "Cluster Authorized Operations",
@@ -303,7 +311,11 @@ func representProduceResponse(data map[string]interface{}) []interface{} {
rep = representResponseHeader(data, rep)
payload := data["Payload"].(map[string]interface{})
responses, _ := json.Marshal(payload["Responses"].([]interface{}))
responses := ""
if payload["Responses"] != nil {
_responses, _ := json.Marshal(payload["Responses"].([]interface{}))
responses = string(_responses)
}
throttleTimeMs := ""
if payload["ThrottleTimeMs"] != nil {
throttleTimeMs = fmt.Sprintf("%d", int(payload["ThrottleTimeMs"].(float64)))
@@ -333,7 +345,11 @@ func representFetchRequest(data map[string]interface{}) []interface{} {
rep = representRequestHeader(data, rep)
payload := data["Payload"].(map[string]interface{})
topics, _ := json.Marshal(payload["Topics"].([]interface{}))
topics := ""
if payload["Topics"] != nil {
_topics, _ := json.Marshal(payload["Topics"].([]interface{}))
topics = string(_topics)
}
replicaId := ""
if payload["ReplicaId"] != nil {
replicaId = fmt.Sprintf("%d", int(payload["ReplicaId"].(float64)))
@@ -361,7 +377,7 @@ func representFetchRequest(data map[string]interface{}) []interface{} {
}
rackId := ""
if payload["RackId"] != nil {
rackId = fmt.Sprintf("%d", int(payload["RackId"].(float64)))
rackId = payload["RackId"].(string)
}
repPayload, _ := json.Marshal([]map[string]string{
{
@@ -394,7 +410,7 @@ func representFetchRequest(data map[string]interface{}) []interface{} {
},
{
"name": "Topics",
"value": string(topics),
"value": topics,
},
{
"name": "Forgotten Topics Data",
@@ -420,7 +436,11 @@ func representFetchResponse(data map[string]interface{}) []interface{} {
rep = representResponseHeader(data, rep)
payload := data["Payload"].(map[string]interface{})
responses, _ := json.Marshal(payload["Responses"].([]interface{}))
responses := ""
if payload["Responses"] != nil {
_responses, _ := json.Marshal(payload["Responses"].([]interface{}))
responses = string(_responses)
}
throttleTimeMs := ""
if payload["ThrottleTimeMs"] != nil {
throttleTimeMs = fmt.Sprintf("%d", int(payload["ThrottleTimeMs"].(float64)))
@@ -448,7 +468,7 @@ func representFetchResponse(data map[string]interface{}) []interface{} {
},
{
"name": "Responses",
"value": string(responses),
"value": responses,
},
})
rep = append(rep, map[string]string{
@@ -466,7 +486,11 @@ func representListOffsetsRequest(data map[string]interface{}) []interface{} {
rep = representRequestHeader(data, rep)
payload := data["Payload"].(map[string]interface{})
topics, _ := json.Marshal(payload["Topics"].([]interface{}))
topics := ""
if payload["Topics"] != nil {
_topics, _ := json.Marshal(payload["Topics"].([]interface{}))
topics = string(_topics)
}
repPayload, _ := json.Marshal([]map[string]string{
{
"name": "Replica ID",
@@ -474,7 +498,7 @@ func representListOffsetsRequest(data map[string]interface{}) []interface{} {
},
{
"name": "Topics",
"value": string(topics),
"value": topics,
},
})
rep = append(rep, map[string]string{

View File

@@ -104,7 +104,11 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, entryId string, resolve
}
break
case Fetch:
topics := reqDetails["Payload"].(map[string]interface{})["Topics"].([]interface{})
_topics := reqDetails["Payload"].(map[string]interface{})["Topics"]
if _topics == nil {
break
}
topics := _topics.([]interface{})
for _, topic := range topics {
summary += fmt.Sprintf("%s, ", topic.(map[string]interface{})["Topic"].(string))
}
@@ -113,7 +117,11 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, entryId string, resolve
}
break
case ListOffsets:
topics := reqDetails["Payload"].(map[string]interface{})["Topics"].([]interface{})
_topics := reqDetails["Payload"].(map[string]interface{})["Topics"]
if _topics == nil {
break
}
topics := _topics.([]interface{})
for _, topic := range topics {
summary += fmt.Sprintf("%s, ", topic.(map[string]interface{})["Name"].(string))
}

View File

@@ -296,12 +296,28 @@ func (p *RedisProtocol) Read() (packet *RedisPacket, err error) {
switch x.(type) {
case []interface{}:
array := x.([]interface{})
packet.Command = RedisCommand(strings.ToUpper(string(array[0].([]uint8))))
if len(array) > 1 {
packet.Key = string(array[1].([]uint8))
}
if len(array) > 2 {
packet.Value = string(array[2].([]uint8))
switch array[0].(type) {
case []uint8:
packet.Command = RedisCommand(strings.ToUpper(string(array[0].([]uint8))))
if len(array) > 1 {
packet.Key = string(array[1].([]uint8))
}
if len(array) > 2 {
packet.Value = string(array[2].([]uint8))
}
if len(array) > 3 {
packet.Value = fmt.Sprintf("[%s", packet.Value)
for _, item := range array[3:] {
packet.Value = fmt.Sprintf("%s, %s", packet.Value, item.([]uint8))
}
packet.Value = strings.TrimSuffix(packet.Value, ", ")
packet.Value = fmt.Sprintf("%s]", packet.Value)
}
default:
msg := fmt.Sprintf("Unrecognized element in Redis array: %v\n", reflect.TypeOf(array[0]))
log.Printf(msg)
err = errors.New(msg)
return
}
case []uint8:
val := string(x.([]uint8))
@@ -316,6 +332,8 @@ func (p *RedisProtocol) Read() (packet *RedisPacket, err error) {
}
case string:
packet.Value = x.(string)
case int64:
packet.Value = fmt.Sprintf("%d", x.(int64))
default:
msg := fmt.Sprintf("Unrecognized Redis data type: %v\n", reflect.TypeOf(x))
log.Printf(msg)

View File

@@ -36,14 +36,8 @@ const SectionsRepresentation: React.FC<any> = ({data, color}) => {
const AutoRepresentation: React.FC<any> = ({representation, isRulesEnabled, rulesMatched, elapsedTime, color}) => {
var TABS = [
{
tab: 'request'
},
{
tab: 'response',
},
{
tab: 'Rules',
},
tab: 'Request'
}
];
const [currentTab, setCurrentTab] = useState(TABS[0].tab);
@@ -54,12 +48,25 @@ const AutoRepresentation: React.FC<any> = ({representation, isRulesEnabled, rule
const {request, response} = JSON.parse(representation);
if (!response) {
TABS[1]['hidden'] = true;
var responseTabIndex = 0;
var rulesTabIndex = 0;
if (response) {
TABS.push(
{
tab: 'Response',
}
);
responseTabIndex = TABS.length - 1;
}
if (!isRulesEnabled) {
TABS.pop()
if (isRulesEnabled) {
TABS.push(
{
tab: 'Rules',
}
);
rulesTabIndex = TABS.length - 1;
}
return <div className={styles.Entry}>
@@ -71,10 +78,10 @@ const AutoRepresentation: React.FC<any> = ({representation, isRulesEnabled, rule
{currentTab === TABS[0].tab && <React.Fragment>
<SectionsRepresentation data={request} color={color}/>
</React.Fragment>}
{response && currentTab === TABS[1].tab && <React.Fragment>
{response && currentTab === TABS[responseTabIndex].tab && <React.Fragment>
<SectionsRepresentation data={response} color={color}/>
</React.Fragment>}
{TABS.length > 2 && currentTab === TABS[2].tab && <React.Fragment>
{isRulesEnabled && currentTab === TABS[rulesTabIndex].tab && <React.Fragment>
<EntryTablePolicySection title={'Rule'} color={color} latency={elapsedTime} arrayToIterate={rulesMatched ? rulesMatched : []}/>
</React.Fragment>}
</div>}

View File

@@ -5,7 +5,6 @@ import variables from '../../variables.module.scss';
interface Tab {
tab: string,
hidden?: boolean,
disabled?: boolean,
disabledMessage?: string,
highlight?: boolean,
@@ -66,7 +65,8 @@ const useTabsStyles = makeStyles((theme) => ({
borderRight: "1px solid " + theme.palette.primary.dark,
height: 20,
verticalAlign: 'middle',
margin: '0 20px'
margin: '0 20px',
cursor: 'unset',
}
}));
@@ -75,7 +75,7 @@ const useTabsStyles = makeStyles((theme) => ({
const Tabs: React.FC<Props> = ({classes={}, tabs, currentTab, color, onChange, leftAligned, dark}) => {
const _classes = {...useTabsStyles(), ...classes};
return <div className={`${_classes.root} ${leftAligned ? _classes.tabsAlignLeft : ''}`}>
{tabs.filter((tab) => !tab.hidden).map(({tab, disabled, disabledMessage, highlight, badge}, index) => {
{tabs.map(({tab, disabled, disabledMessage, highlight, badge}, index) => {
const active = currentTab === tab;
const tabLink = <span
key={tab}