mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-02-25 08:02:42 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e17ac5654 | ||
|
|
d274db2d87 | ||
|
|
0a2aacfb02 | ||
|
|
3c64c1c7ca | ||
|
|
005f000ef6 | ||
|
|
1ef3778051 | ||
|
|
9f1e311689 | ||
|
|
9aaf18842b | ||
|
|
880842c39f | ||
|
|
296e1bb667 | ||
|
|
2910611111 |
@@ -42,8 +42,8 @@ RUN go build -ldflags="-s -w \
|
||||
-X 'mizuserver/pkg/version.SemVer=${SEM_VER}'" -o mizuagent .
|
||||
|
||||
# Download Basenine executable, verify the sha1sum and move it to a directory in $PATH
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.13/basenine_linux_amd64 ./basenine_linux_amd64
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.13/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.17/basenine_linux_amd64 ./basenine_linux_amd64
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.17/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
||||
RUN shasum -a 256 -c basenine_linux_amd64.sha256
|
||||
RUN chmod +x ./basenine_linux_amd64
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ require (
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/up9inc/basenine/client/go v0.0.0-20211130202146-cf837626a065
|
||||
github.com/up9inc/basenine/client/go v0.0.0-20211207165834-2ced7577f9e6
|
||||
github.com/up9inc/mizu/shared v0.0.0
|
||||
github.com/up9inc/mizu/tap v0.0.0
|
||||
github.com/up9inc/mizu/tap/api v0.0.0
|
||||
|
||||
@@ -450,8 +450,8 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/up9inc/basenine/client/go v0.0.0-20211130202146-cf837626a065 h1:kfciLExAWkJMeMoKtnO5G5czqNv5/d0zjupG2nAeBmo=
|
||||
github.com/up9inc/basenine/client/go v0.0.0-20211130202146-cf837626a065/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
||||
github.com/up9inc/basenine/client/go v0.0.0-20211207165834-2ced7577f9e6 h1:8JOkoaZHhUPi4r7vSL/xo83foSz8BHPSabTDpxmtHFU=
|
||||
github.com/up9inc/basenine/client/go v0.0.0-20211207165834-2ced7577f9e6/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
|
||||
@@ -136,7 +136,7 @@ func startReadingChannel(outputItems <-chan *tapApi.OutputChannelItem, extension
|
||||
|
||||
harEntry, err := utils.NewEntry(mizuEntry.Request, mizuEntry.Response, mizuEntry.StartTime, mizuEntry.ElapsedTime)
|
||||
if err == nil {
|
||||
rules, _, _ := models.RunValidationRulesState(*harEntry, mizuEntry.Service)
|
||||
rules, _, _ := models.RunValidationRulesState(*harEntry, mizuEntry.Destination.Name)
|
||||
baseEntry.Rules = rules
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"mizuserver/pkg/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -95,8 +94,6 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
||||
startTimeBytes, _ := models.CreateWebsocketStartTimeMessage(startTime)
|
||||
SendToSocket(socketId, startTimeBytes)
|
||||
|
||||
queryRecieved := false
|
||||
|
||||
for {
|
||||
_, msg, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
@@ -104,75 +101,72 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
||||
break
|
||||
}
|
||||
|
||||
if !queryRecieved {
|
||||
if !isTapper && !isQuerySet {
|
||||
queryRecieved = true
|
||||
query := string(msg)
|
||||
err = basenine.Validate(shared.BasenineHost, shared.BaseninePort, query)
|
||||
if err != nil {
|
||||
toastBytes, _ := models.CreateWebsocketToastMessage(&models.ToastMessage{
|
||||
Type: "error",
|
||||
AutoClose: 5000,
|
||||
Text: fmt.Sprintf("Syntax error: %s", err.Error()),
|
||||
})
|
||||
SendToSocket(socketId, toastBytes)
|
||||
break
|
||||
}
|
||||
|
||||
isQuerySet = true
|
||||
|
||||
handleDataChannel := func(c *basenine.Connection, data chan []byte) {
|
||||
for {
|
||||
bytes := <-data
|
||||
|
||||
if string(bytes) == basenine.CloseChannel {
|
||||
return
|
||||
}
|
||||
|
||||
var dataMap map[string]interface{}
|
||||
err = json.Unmarshal(bytes, &dataMap)
|
||||
|
||||
base := dataMap["base"].(map[string]interface{})
|
||||
base["id"] = uint(dataMap["id"].(float64))
|
||||
|
||||
baseEntryBytes, _ := models.CreateBaseEntryWebSocketMessage(base)
|
||||
SendToSocket(socketId, baseEntryBytes)
|
||||
}
|
||||
}
|
||||
|
||||
handleMetaChannel := func(c *basenine.Connection, meta chan []byte) {
|
||||
for {
|
||||
bytes := <-meta
|
||||
|
||||
if string(bytes) == basenine.CloseChannel {
|
||||
return
|
||||
}
|
||||
|
||||
var metadata *basenine.Metadata
|
||||
err = json.Unmarshal(bytes, &metadata)
|
||||
if err != nil {
|
||||
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
||||
}
|
||||
|
||||
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
||||
SendToSocket(socketId, metadataBytes)
|
||||
}
|
||||
}
|
||||
|
||||
go handleDataChannel(connection, data)
|
||||
go handleMetaChannel(connection, meta)
|
||||
|
||||
connection.Query(query, data, meta)
|
||||
} else {
|
||||
eventHandlers.WebSocketMessage(socketId, msg)
|
||||
}
|
||||
} else {
|
||||
id, err := strconv.Atoi(string(msg))
|
||||
if !isTapper && !isQuerySet {
|
||||
query := string(msg)
|
||||
err = basenine.Validate(shared.BasenineHost, shared.BaseninePort, query)
|
||||
if err != nil {
|
||||
continue
|
||||
toastBytes, _ := models.CreateWebsocketToastMessage(&models.ToastMessage{
|
||||
Type: "error",
|
||||
AutoClose: 5000,
|
||||
Text: fmt.Sprintf("Syntax error: %s", err.Error()),
|
||||
})
|
||||
SendToSocket(socketId, toastBytes)
|
||||
break
|
||||
}
|
||||
focusEntryBytes, _ := models.CreateWebsocketFocusEntry(id)
|
||||
SendToSocket(socketId, focusEntryBytes)
|
||||
|
||||
isQuerySet = true
|
||||
|
||||
handleDataChannel := func(c *basenine.Connection, data chan []byte) {
|
||||
for {
|
||||
bytes := <-data
|
||||
|
||||
if string(bytes) == basenine.CloseChannel {
|
||||
return
|
||||
}
|
||||
|
||||
var dataMap map[string]interface{}
|
||||
err = json.Unmarshal(bytes, &dataMap)
|
||||
|
||||
var base map[string]interface{}
|
||||
switch dataMap["base"].(type) {
|
||||
case map[string]interface{}:
|
||||
base = dataMap["base"].(map[string]interface{})
|
||||
base["id"] = uint(dataMap["id"].(float64))
|
||||
default:
|
||||
logger.Log.Debugf("Base field has an unrecognized type: %+v", dataMap)
|
||||
continue
|
||||
}
|
||||
|
||||
baseEntryBytes, _ := models.CreateBaseEntryWebSocketMessage(base)
|
||||
SendToSocket(socketId, baseEntryBytes)
|
||||
}
|
||||
}
|
||||
|
||||
handleMetaChannel := func(c *basenine.Connection, meta chan []byte) {
|
||||
for {
|
||||
bytes := <-meta
|
||||
|
||||
if string(bytes) == basenine.CloseChannel {
|
||||
return
|
||||
}
|
||||
|
||||
var metadata *basenine.Metadata
|
||||
err = json.Unmarshal(bytes, &metadata)
|
||||
if err != nil {
|
||||
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
||||
}
|
||||
|
||||
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
||||
SendToSocket(socketId, metadataBytes)
|
||||
}
|
||||
}
|
||||
|
||||
go handleDataChannel(connection, data)
|
||||
go handleMetaChannel(connection, meta)
|
||||
|
||||
connection.Query(query, data, meta)
|
||||
} else {
|
||||
eventHandlers.WebSocketMessage(socketId, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ func GetEntry(c *gin.Context) {
|
||||
var isRulesEnabled bool
|
||||
if entry.Protocol.Name == "http" {
|
||||
harEntry, _ := utils.NewEntry(entry.Request, entry.Response, entry.StartTime, entry.ElapsedTime)
|
||||
_, rulesMatched, _isRulesEnabled := models.RunValidationRulesState(*harEntry, entry.Service)
|
||||
_, rulesMatched, _isRulesEnabled := models.RunValidationRulesState(*harEntry, entry.Destination.Name)
|
||||
isRulesEnabled = _isRulesEnabled
|
||||
inrec, _ := json.Marshal(rulesMatched)
|
||||
json.Unmarshal(inrec, &rules)
|
||||
|
||||
@@ -70,11 +70,6 @@ type WebSocketStartTimeMessage struct {
|
||||
Data int64 `json:"data"`
|
||||
}
|
||||
|
||||
type WebSocketFocusEntryMessage struct {
|
||||
*shared.WebSocketMessageMetadata
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
||||
func CreateBaseEntryWebSocketMessage(base map[string]interface{}) ([]byte, error) {
|
||||
message := &WebSocketEntryMessage{
|
||||
WebSocketMessageMetadata: &shared.WebSocketMessageMetadata{
|
||||
@@ -135,16 +130,6 @@ func CreateWebsocketStartTimeMessage(base int64) ([]byte, error) {
|
||||
return json.Marshal(message)
|
||||
}
|
||||
|
||||
func CreateWebsocketFocusEntry(id int) ([]byte, error) {
|
||||
message := &WebSocketFocusEntryMessage{
|
||||
WebSocketMessageMetadata: &shared.WebSocketMessageMetadata{
|
||||
MessageType: shared.WebSocketMessageFocusEntry,
|
||||
},
|
||||
Id: id,
|
||||
}
|
||||
return json.Marshal(message)
|
||||
}
|
||||
|
||||
// ExtendedHAR is the top level object of a HAR log.
|
||||
type ExtendedHAR struct {
|
||||
Log *ExtendedLog `json:"log"`
|
||||
|
||||
@@ -251,12 +251,12 @@ func syncEntriesImpl(token string, model string, envPrefix string, uploadInterva
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if entry.ResolvedSource != "" {
|
||||
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-source", Value: entry.ResolvedSource})
|
||||
if entry.Source.Name != "" {
|
||||
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-source", Value: entry.Source.Name})
|
||||
}
|
||||
if entry.ResolvedDestination != "" {
|
||||
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-destination", Value: entry.ResolvedDestination})
|
||||
harEntry.Request.URL = utils.SetHostname(harEntry.Request.URL, entry.ResolvedDestination)
|
||||
if entry.Destination.Name != "" {
|
||||
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-destination", Value: entry.Destination.Name})
|
||||
harEntry.Request.URL = utils.SetHostname(harEntry.Request.URL, entry.Destination.Name)
|
||||
}
|
||||
|
||||
// go's default marshal behavior is to encode []byte fields to base64, python's default unmarshal behavior is to not decode []byte fields from base64
|
||||
|
||||
@@ -18,8 +18,9 @@ build: ## Build mizu CLI binary (select platform via GOOS / GOARCH env variables
|
||||
go build -ldflags="-X 'github.com/up9inc/mizu/cli/mizu.GitCommitHash=$(COMMIT_HASH)' \
|
||||
-X 'github.com/up9inc/mizu/cli/mizu.Branch=$(GIT_BRANCH)' \
|
||||
-X 'github.com/up9inc/mizu/cli/mizu.BuildTimestamp=$(BUILD_TIMESTAMP)' \
|
||||
-X 'github.com/up9inc/mizu/cli/mizu.Platform=$(SUFFIX)' \
|
||||
-X 'github.com/up9inc/mizu/cli/mizu.SemVer=$(SEM_VER)'" \
|
||||
-o bin/mizu_$(SUFFIX) mizu.go
|
||||
-o bin/mizu_$(SUFFIX) mizu.go
|
||||
(cd bin && shasum -a 256 mizu_${SUFFIX} > mizu_${SUFFIX}.sha256)
|
||||
|
||||
build-all: ## Build for all supported platforms.
|
||||
|
||||
@@ -11,9 +11,12 @@ var (
|
||||
GitCommitHash = "" // this var is overridden using ldflags in makefile when building
|
||||
BuildTimestamp = "" // this var is overridden using ldflags in makefile when building
|
||||
RBACVersion = "v1"
|
||||
Platform = ""
|
||||
DaemonModePersistentVolumeSizeBufferBytes = int64(500 * 1000 * 1000) //500mb
|
||||
)
|
||||
|
||||
const DEVENVVAR = "MIZU_DISABLE_TELEMTRY"
|
||||
|
||||
func GetMizuFolderPath() string {
|
||||
home, homeDirErr := os.UserHomeDir()
|
||||
if homeDirErr != nil {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -39,6 +40,10 @@ func CheckVersionCompatibility(apiServerProvider *apiserver.Provider) (bool, err
|
||||
}
|
||||
|
||||
func CheckNewerVersion(versionChan chan string) {
|
||||
if _, present := os.LookupEnv(mizu.DEVENVVAR); present {
|
||||
versionChan <- ""
|
||||
return
|
||||
}
|
||||
logger.Log.Debugf("Checking for newer version...")
|
||||
start := time.Now()
|
||||
client := github.NewClient(nil)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
"github.com/up9inc/mizu/cli/apiserver"
|
||||
@@ -62,6 +63,9 @@ func ReportAPICalls(apiProvider *apiserver.Provider) {
|
||||
}
|
||||
|
||||
func shouldRunTelemetry() bool {
|
||||
if _, present := os.LookupEnv(mizu.DEVENVVAR); present {
|
||||
return false
|
||||
}
|
||||
if !config.Config.Telemetry {
|
||||
return false
|
||||
}
|
||||
@@ -79,6 +83,7 @@ func sendTelemetry(telemetryType string, argsMap map[string]interface{}) error {
|
||||
argsMap["buildTimestamp"] = mizu.BuildTimestamp
|
||||
argsMap["branch"] = mizu.Branch
|
||||
argsMap["version"] = mizu.SemVer
|
||||
argsMap["Platform"] = mizu.Platform
|
||||
|
||||
if machineId, err := machineid.ProtectedID("mizu"); err == nil {
|
||||
argsMap["machineId"] = machineId
|
||||
|
||||
@@ -37,8 +37,8 @@ COPY agent .
|
||||
RUN go build -gcflags="all=-N -l" -o mizuagent .
|
||||
|
||||
# Download Basenine executable, verify the sha1sum and move it to a directory in $PATH
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.13/basenine_linux_amd64 ./basenine_linux_amd64
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.13/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.17/basenine_linux_amd64 ./basenine_linux_amd64
|
||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.17/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
||||
RUN shasum -a 256 -c basenine_linux_amd64.sha256
|
||||
RUN chmod +x ./basenine_linux_amd64
|
||||
|
||||
|
||||
@@ -651,7 +651,17 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
|
||||
agentContainer.WithName(tapperPodName)
|
||||
agentContainer.WithImage(podImage)
|
||||
agentContainer.WithImagePullPolicy(imagePullPolicy)
|
||||
agentContainer.WithSecurityContext(applyconfcore.SecurityContext().WithPrivileged(true))
|
||||
|
||||
caps := applyconfcore.Capabilities().WithDrop("ALL").WithAdd("NET_RAW").WithAdd("NET_ADMIN")
|
||||
|
||||
if istio {
|
||||
caps = caps.WithAdd("SYS_ADMIN") // for reading /proc/PID/net/ns
|
||||
caps = caps.WithAdd("SYS_PTRACE") // for setting netns to other process
|
||||
caps = caps.WithAdd("DAC_OVERRIDE") // for reading /proc/PID/environ
|
||||
}
|
||||
|
||||
agentContainer.WithSecurityContext(applyconfcore.SecurityContext().WithCapabilities(caps))
|
||||
|
||||
agentContainer.WithCommand(mizuCmd...)
|
||||
agentContainer.WithEnv(
|
||||
applyconfcore.EnvVar().WithName(shared.LogLevelEnvVar).WithValue(logLevel.String()),
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/op/go-logging"
|
||||
"github.com/up9inc/mizu/shared/logger"
|
||||
"github.com/up9inc/mizu/tap/api"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -22,7 +21,6 @@ const (
|
||||
WebSocketMessageTypeToast WebSocketMessageType = "toast"
|
||||
WebSocketMessageTypeQueryMetadata WebSocketMessageType = "queryMetadata"
|
||||
WebSocketMessageTypeStartTime WebSocketMessageType = "startTime"
|
||||
WebSocketMessageFocusEntry WebSocketMessageType = "focusEntry"
|
||||
)
|
||||
|
||||
type Resources struct {
|
||||
|
||||
@@ -129,19 +129,10 @@ type MizuEntry struct {
|
||||
Response map[string]interface{} `json:"response"`
|
||||
Base *BaseEntryDetails `json:"base"`
|
||||
Summary string `json:"summary"`
|
||||
Url string `json:"url"`
|
||||
Method string `json:"method"`
|
||||
Status int `json:"status"`
|
||||
RequestSenderIp string `json:"requestSenderIp"`
|
||||
Service string `json:"service"`
|
||||
ElapsedTime int64 `json:"elapsedTime"`
|
||||
Path string `json:"path"`
|
||||
ResolvedSource string `json:"resolvedSource,omitempty"`
|
||||
ResolvedDestination string `json:"resolvedDestination,omitempty"`
|
||||
SourceIp string `json:"sourceIp,omitempty"`
|
||||
DestinationIp string `json:"destinationIp,omitempty"`
|
||||
SourcePort string `json:"sourcePort,omitempty"`
|
||||
DestinationPort string `json:"destinationPort,omitempty"`
|
||||
IsOutgoing bool `json:"isOutgoing,omitempty"`
|
||||
ContractStatus ContractStatus `json:"contractStatus,omitempty"`
|
||||
ContractRequestReason string `json:"contractRequestReason,omitempty"`
|
||||
@@ -160,24 +151,20 @@ type MizuEntryWrapper struct {
|
||||
}
|
||||
|
||||
type BaseEntryDetails struct {
|
||||
Id uint `json:"id"`
|
||||
Protocol Protocol `json:"protocol,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
RequestSenderIp string `json:"requestSenderIp,omitempty"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
Method string `json:"method,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
SourceIp string `json:"sourceIp,omitempty"`
|
||||
DestinationIp string `json:"destinationIp,omitempty"`
|
||||
SourcePort string `json:"sourcePort,omitempty"`
|
||||
DestinationPort string `json:"destinationPort,omitempty"`
|
||||
IsOutgoing bool `json:"isOutgoing,omitempty"`
|
||||
Latency int64 `json:"latency"`
|
||||
Rules ApplicableRules `json:"rules,omitempty"`
|
||||
ContractStatus ContractStatus `json:"contractStatus"`
|
||||
Id uint `json:"id"`
|
||||
Protocol Protocol `json:"protocol,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
Method string `json:"method,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
Source *TCP `json:"src"`
|
||||
Destination *TCP `json:"dst"`
|
||||
IsOutgoing bool `json:"isOutgoing,omitempty"`
|
||||
Latency int64 `json:"latency"`
|
||||
Rules ApplicableRules `json:"rules,omitempty"`
|
||||
ContractStatus ContractStatus `json:"contractStatus"`
|
||||
}
|
||||
|
||||
type ApplicableRules struct {
|
||||
@@ -202,18 +189,13 @@ type DataUnmarshaler interface {
|
||||
func (bed *BaseEntryDetails) UnmarshalData(entry *MizuEntry) error {
|
||||
bed.Protocol = entry.Protocol
|
||||
bed.Id = entry.Id
|
||||
bed.Url = entry.Url
|
||||
bed.RequestSenderIp = entry.RequestSenderIp
|
||||
bed.Service = entry.Service
|
||||
bed.Path = entry.Path
|
||||
bed.Summary = entry.Path
|
||||
bed.Summary = entry.Summary
|
||||
bed.StatusCode = entry.Status
|
||||
bed.Method = entry.Method
|
||||
bed.Timestamp = entry.Timestamp
|
||||
bed.SourceIp = entry.SourceIp
|
||||
bed.DestinationIp = entry.DestinationIp
|
||||
bed.SourcePort = entry.SourcePort
|
||||
bed.DestinationPort = entry.DestinationPort
|
||||
bed.Source = entry.Source
|
||||
bed.Destination = entry.Destination
|
||||
bed.IsOutgoing = entry.IsOutgoing
|
||||
bed.Latency = entry.ElapsedTime
|
||||
bed.ContractStatus = entry.ContractStatus
|
||||
@@ -271,7 +253,6 @@ func (h HTTPPayload) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
return json.Marshal(&HTTPWrapper{
|
||||
Method: harRequest.Method,
|
||||
Url: "",
|
||||
Details: harRequest,
|
||||
RawRequest: &HTTPRequestWrapper{Request: h.Data.(*http.Request)},
|
||||
})
|
||||
|
||||
@@ -226,12 +226,6 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
||||
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string) *api.MizuEntry {
|
||||
request := item.Pair.Request.Payload.(map[string]interface{})
|
||||
reqDetails := request["details"].(map[string]interface{})
|
||||
service := "amqp"
|
||||
if resolvedDestination != "" {
|
||||
service = resolvedDestination
|
||||
} else if resolvedSource != "" {
|
||||
service = resolvedSource
|
||||
}
|
||||
|
||||
summary := ""
|
||||
switch request["method"] {
|
||||
@@ -279,45 +273,31 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
||||
IP: item.ConnectionInfo.ServerIP,
|
||||
Port: item.ConnectionInfo.ServerPort,
|
||||
},
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Url: fmt.Sprintf("%s%s", service, summary),
|
||||
Method: request["method"].(string),
|
||||
Status: 0,
|
||||
RequestSenderIp: item.ConnectionInfo.ClientIP,
|
||||
Service: service,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: 0,
|
||||
Summary: summary,
|
||||
ResolvedSource: resolvedSource,
|
||||
ResolvedDestination: resolvedDestination,
|
||||
SourceIp: item.ConnectionInfo.ClientIP,
|
||||
DestinationIp: item.ConnectionInfo.ServerIP,
|
||||
SourcePort: item.ConnectionInfo.ClientPort,
|
||||
DestinationPort: item.ConnectionInfo.ServerPort,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Method: request["method"].(string),
|
||||
Status: 0,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: 0,
|
||||
Summary: summary,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
||||
return &api.BaseEntryDetails{
|
||||
Id: entry.Id,
|
||||
Protocol: protocol,
|
||||
Url: entry.Url,
|
||||
RequestSenderIp: entry.RequestSenderIp,
|
||||
Service: entry.Service,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
SourceIp: entry.SourceIp,
|
||||
DestinationIp: entry.DestinationIp,
|
||||
SourcePort: entry.SourcePort,
|
||||
DestinationPort: entry.DestinationPort,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Id: entry.Id,
|
||||
Protocol: protocol,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
Source: entry.Source,
|
||||
Destination: entry.Destination,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Rules: api.ApplicableRules{
|
||||
Latency: 0,
|
||||
Status: false,
|
||||
|
||||
@@ -158,7 +158,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
||||
}
|
||||
|
||||
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string) *api.MizuEntry {
|
||||
var host, authority, path, service string
|
||||
var host, authority, path string
|
||||
|
||||
request := item.Pair.Request.Payload.(map[string]interface{})
|
||||
response := item.Pair.Response.Payload.(map[string]interface{})
|
||||
@@ -191,9 +191,13 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
||||
}
|
||||
|
||||
if item.Protocol.Version == "2.0" && !isRequestUpgradedH2C {
|
||||
service = authority
|
||||
if resolvedDestination == "" {
|
||||
resolvedDestination = authority
|
||||
}
|
||||
if resolvedDestination == "" {
|
||||
resolvedDestination = host
|
||||
}
|
||||
} else {
|
||||
service = host
|
||||
u, err := url.Parse(reqDetails["url"].(string))
|
||||
if err != nil {
|
||||
path = reqDetails["url"].(string)
|
||||
@@ -221,12 +225,6 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
||||
reqDetails["_queryString"] = reqDetails["queryString"]
|
||||
reqDetails["queryString"] = mapSliceRebuildAsMap(reqDetails["_queryString"].([]interface{}))
|
||||
|
||||
if resolvedDestination != "" {
|
||||
service = resolvedDestination
|
||||
} else if resolvedSource != "" {
|
||||
service = resolvedSource
|
||||
}
|
||||
|
||||
method := reqDetails["method"].(string)
|
||||
statusCode := int(resDetails["status"].(float64))
|
||||
if item.Protocol.Abbreviation == "gRPC" {
|
||||
@@ -255,47 +253,33 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
||||
IP: item.ConnectionInfo.ServerIP,
|
||||
Port: item.ConnectionInfo.ServerPort,
|
||||
},
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Response: resDetails,
|
||||
Url: fmt.Sprintf("%s%s", service, path),
|
||||
Method: method,
|
||||
Status: statusCode,
|
||||
RequestSenderIp: item.ConnectionInfo.ClientIP,
|
||||
Service: service,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: elapsedTime,
|
||||
Summary: path,
|
||||
ResolvedSource: resolvedSource,
|
||||
ResolvedDestination: resolvedDestination,
|
||||
SourceIp: item.ConnectionInfo.ClientIP,
|
||||
DestinationIp: item.ConnectionInfo.ServerIP,
|
||||
SourcePort: item.ConnectionInfo.ClientPort,
|
||||
DestinationPort: item.ConnectionInfo.ServerPort,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
HTTPPair: string(httpPair),
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Response: resDetails,
|
||||
Method: method,
|
||||
Status: statusCode,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: elapsedTime,
|
||||
Summary: path,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
HTTPPair: string(httpPair),
|
||||
}
|
||||
}
|
||||
|
||||
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
||||
return &api.BaseEntryDetails{
|
||||
Id: entry.Id,
|
||||
Protocol: entry.Protocol,
|
||||
Url: entry.Url,
|
||||
RequestSenderIp: entry.RequestSenderIp,
|
||||
Service: entry.Service,
|
||||
Path: entry.Path,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
SourceIp: entry.SourceIp,
|
||||
DestinationIp: entry.DestinationIp,
|
||||
SourcePort: entry.SourcePort,
|
||||
DestinationPort: entry.DestinationPort,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Id: entry.Id,
|
||||
Protocol: entry.Protocol,
|
||||
Path: entry.Path,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
Source: entry.Source,
|
||||
Destination: entry.Destination,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Rules: api.ApplicableRules{
|
||||
Latency: 0,
|
||||
Status: false,
|
||||
|
||||
@@ -65,12 +65,6 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
||||
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string) *api.MizuEntry {
|
||||
request := item.Pair.Request.Payload.(map[string]interface{})
|
||||
reqDetails := request["details"].(map[string]interface{})
|
||||
service := "kafka"
|
||||
if resolvedDestination != "" {
|
||||
service = resolvedDestination
|
||||
} else if resolvedSource != "" {
|
||||
service = resolvedSource
|
||||
}
|
||||
apiKey := ApiKey(reqDetails["apiKey"].(float64))
|
||||
|
||||
summary := ""
|
||||
@@ -164,45 +158,31 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
||||
IP: item.ConnectionInfo.ServerIP,
|
||||
Port: item.ConnectionInfo.ServerPort,
|
||||
},
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Response: item.Pair.Response.Payload.(map[string]interface{})["details"].(map[string]interface{}),
|
||||
Url: fmt.Sprintf("%s%s", service, summary),
|
||||
Method: apiNames[apiKey],
|
||||
Status: 0,
|
||||
RequestSenderIp: item.ConnectionInfo.ClientIP,
|
||||
Service: service,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: elapsedTime,
|
||||
Summary: summary,
|
||||
ResolvedSource: resolvedSource,
|
||||
ResolvedDestination: resolvedDestination,
|
||||
SourceIp: item.ConnectionInfo.ClientIP,
|
||||
DestinationIp: item.ConnectionInfo.ServerIP,
|
||||
SourcePort: item.ConnectionInfo.ClientPort,
|
||||
DestinationPort: item.ConnectionInfo.ServerPort,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Response: item.Pair.Response.Payload.(map[string]interface{})["details"].(map[string]interface{}),
|
||||
Method: apiNames[apiKey],
|
||||
Status: 0,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: elapsedTime,
|
||||
Summary: summary,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
}
|
||||
}
|
||||
|
||||
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
||||
return &api.BaseEntryDetails{
|
||||
Id: entry.Id,
|
||||
Protocol: _protocol,
|
||||
Url: entry.Url,
|
||||
RequestSenderIp: entry.RequestSenderIp,
|
||||
Service: entry.Service,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
SourceIp: entry.SourceIp,
|
||||
DestinationIp: entry.DestinationIp,
|
||||
SourcePort: entry.SourcePort,
|
||||
DestinationPort: entry.DestinationPort,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Id: entry.Id,
|
||||
Protocol: _protocol,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
Source: entry.Source,
|
||||
Destination: entry.Destination,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Rules: api.ApplicableRules{
|
||||
Latency: 0,
|
||||
Status: false,
|
||||
|
||||
@@ -65,13 +65,6 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
||||
reqDetails := request["details"].(map[string]interface{})
|
||||
resDetails := response["details"].(map[string]interface{})
|
||||
|
||||
service := "redis"
|
||||
if resolvedDestination != "" {
|
||||
service = resolvedDestination
|
||||
} else if resolvedSource != "" {
|
||||
service = resolvedSource
|
||||
}
|
||||
|
||||
method := ""
|
||||
if reqDetails["command"] != nil {
|
||||
method = reqDetails["command"].(string)
|
||||
@@ -99,46 +92,32 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
||||
IP: item.ConnectionInfo.ServerIP,
|
||||
Port: item.ConnectionInfo.ServerPort,
|
||||
},
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Response: resDetails,
|
||||
Url: fmt.Sprintf("%s%s", service, summary),
|
||||
Method: method,
|
||||
Status: 0,
|
||||
RequestSenderIp: item.ConnectionInfo.ClientIP,
|
||||
Service: service,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: elapsedTime,
|
||||
Summary: summary,
|
||||
ResolvedSource: resolvedSource,
|
||||
ResolvedDestination: resolvedDestination,
|
||||
SourceIp: item.ConnectionInfo.ClientIP,
|
||||
DestinationIp: item.ConnectionInfo.ServerIP,
|
||||
SourcePort: item.ConnectionInfo.ClientPort,
|
||||
DestinationPort: item.ConnectionInfo.ServerPort,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||
Request: reqDetails,
|
||||
Response: resDetails,
|
||||
Method: method,
|
||||
Status: 0,
|
||||
Timestamp: item.Timestamp,
|
||||
StartTime: item.Pair.Request.CaptureTime,
|
||||
ElapsedTime: elapsedTime,
|
||||
Summary: summary,
|
||||
IsOutgoing: item.ConnectionInfo.IsOutgoing,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
||||
return &api.BaseEntryDetails{
|
||||
Id: entry.Id,
|
||||
Protocol: protocol,
|
||||
Url: entry.Url,
|
||||
RequestSenderIp: entry.RequestSenderIp,
|
||||
Service: entry.Service,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
SourceIp: entry.SourceIp,
|
||||
DestinationIp: entry.DestinationIp,
|
||||
SourcePort: entry.SourcePort,
|
||||
DestinationPort: entry.DestinationPort,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Id: entry.Id,
|
||||
Protocol: protocol,
|
||||
Summary: entry.Summary,
|
||||
StatusCode: entry.Status,
|
||||
Method: entry.Method,
|
||||
Timestamp: entry.Timestamp,
|
||||
Source: entry.Source,
|
||||
Destination: entry.Destination,
|
||||
IsOutgoing: entry.IsOutgoing,
|
||||
Latency: entry.ElapsedTime,
|
||||
Rules: api.ApplicableRules{
|
||||
Latency: 0,
|
||||
Status: false,
|
||||
|
||||
11
ui/package-lock.json
generated
11
ui/package-lock.json
generated
@@ -11080,6 +11080,11 @@
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@@ -13644,9 +13649,9 @@
|
||||
}
|
||||
},
|
||||
"react-scrollable-feed-virtualized": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/react-scrollable-feed-virtualized/-/react-scrollable-feed-virtualized-1.4.8.tgz",
|
||||
"integrity": "sha512-zsSO/9QB+4V6HEk39lxeMEUA6JFSZjfV4stw7RF17+vZdlVhyATsTBCzsj8hZywY4F29cBfH+3/GKrMhwmhAsw=="
|
||||
"version": "1.4.9",
|
||||
"resolved": "https://registry.npmjs.org/react-scrollable-feed-virtualized/-/react-scrollable-feed-virtualized-1.4.9.tgz",
|
||||
"integrity": "sha512-YkFkPjdIXDUsaCNYhZ+Blpp3LF+CsJWscwn/0fGSjF5QBKCtPURO9AEUA362Qnjr4S8LF2IjSAOCCFedIEnVNw=="
|
||||
},
|
||||
"react-syntax-highlighter": {
|
||||
"version": "15.4.3",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"@uiw/react-textarea-code-editor": "^1.4.12",
|
||||
"axios": "^0.21.1",
|
||||
"jsonpath": "^1.1.1",
|
||||
"moment": "^2.29.1",
|
||||
"node-sass": "^5.0.0",
|
||||
"numeral": "^2.0.6",
|
||||
"protobuf-decoder": "^0.1.0",
|
||||
@@ -23,7 +24,7 @@
|
||||
"react-copy-to-clipboard": "^5.0.3",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-scripts": "4.0.3",
|
||||
"react-scrollable-feed-virtualized": "^1.4.8",
|
||||
"react-scrollable-feed-virtualized": "^1.4.9",
|
||||
"react-syntax-highlighter": "^15.4.3",
|
||||
"react-toastify": "^8.0.3",
|
||||
"typescript": "^4.2.4",
|
||||
|
||||
@@ -1,33 +1,133 @@
|
||||
import React, {useRef} from "react";
|
||||
import React, {useCallback, useEffect, useMemo, useRef, useState} from "react";
|
||||
import styles from './style/EntriesList.module.sass';
|
||||
import ScrollableFeedVirtualized from "react-scrollable-feed-virtualized";
|
||||
import Moment from 'moment';
|
||||
import {EntryItem} from "./EntryListItem/EntryListItem";
|
||||
import down from "./assets/downImg.svg";
|
||||
import spinner from './assets/spinner.svg';
|
||||
import Api from "../helpers/api";
|
||||
|
||||
interface EntriesListProps {
|
||||
entries: any[];
|
||||
setEntries: any;
|
||||
query: string;
|
||||
listEntryREF: any;
|
||||
onSnapBrokenEvent: () => void;
|
||||
isSnappedToBottom: boolean;
|
||||
setIsSnappedToBottom: any;
|
||||
queriedCurrent: number;
|
||||
setQueriedCurrent: any;
|
||||
queriedTotal: number;
|
||||
startTime: number;
|
||||
noMoreDataTop: boolean;
|
||||
setNoMoreDataTop: (flag: boolean) => void;
|
||||
focusedEntryId: string;
|
||||
setFocusedEntryId: (id: string) => void;
|
||||
updateQuery: any;
|
||||
leftOffTop: number;
|
||||
setLeftOffTop: (leftOffTop: number) => void;
|
||||
reconnectWebSocket: any;
|
||||
isWebSocketConnectionClosed: boolean;
|
||||
closeWebSocket: any;
|
||||
}
|
||||
|
||||
export const EntriesList: React.FC<EntriesListProps> = ({entries, listEntryREF, onSnapBrokenEvent, isSnappedToBottom, setIsSnappedToBottom, queriedCurrent, queriedTotal, startTime}) => {
|
||||
const api = new Api();
|
||||
|
||||
export const EntriesList: React.FC<EntriesListProps> = ({entries, setEntries, query, listEntryREF, onSnapBrokenEvent, isSnappedToBottom, setIsSnappedToBottom, queriedCurrent, setQueriedCurrent, queriedTotal, startTime, noMoreDataTop, setNoMoreDataTop, focusedEntryId, setFocusedEntryId, updateQuery, leftOffTop, setLeftOffTop, reconnectWebSocket, isWebSocketConnectionClosed, closeWebSocket}) => {
|
||||
const [loadMoreTop, setLoadMoreTop] = useState(false);
|
||||
const [isLoadingTop, setIsLoadingTop] = useState(false);
|
||||
const scrollableRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const list = document.getElementById('list').firstElementChild;
|
||||
list.addEventListener('scroll', (e) => {
|
||||
const el: any = e.target;
|
||||
if(el.scrollTop === 0) {
|
||||
setLoadMoreTop(true);
|
||||
} else {
|
||||
setNoMoreDataTop(false);
|
||||
setLoadMoreTop(false);
|
||||
}
|
||||
});
|
||||
}, [setLoadMoreTop, setNoMoreDataTop]);
|
||||
|
||||
const memoizedEntries = useMemo(() => {
|
||||
return entries;
|
||||
},[entries]);
|
||||
|
||||
const getOldEntries = useCallback(async () => {
|
||||
setLoadMoreTop(false);
|
||||
if (leftOffTop === null || leftOffTop <= 0) {
|
||||
return;
|
||||
}
|
||||
setIsLoadingTop(true);
|
||||
const data = await api.fetchEntries(leftOffTop, -1, query, 100, 3000);
|
||||
if (!data || !data.meta) {
|
||||
setNoMoreDataTop(true);
|
||||
setIsLoadingTop(false);
|
||||
return;
|
||||
}
|
||||
setLeftOffTop(data.meta.leftOff);
|
||||
|
||||
let scrollTo: boolean;
|
||||
if (data.meta.leftOff === 0) {
|
||||
setNoMoreDataTop(true);
|
||||
scrollTo = false;
|
||||
} else {
|
||||
scrollTo = true;
|
||||
}
|
||||
setIsLoadingTop(false);
|
||||
|
||||
const newEntries = [...data.data.reverse(), ...entries];
|
||||
setEntries(newEntries);
|
||||
|
||||
setQueriedCurrent(queriedCurrent + data.meta.current);
|
||||
|
||||
if (scrollTo) {
|
||||
scrollableRef.current.scrollToIndex(data.data.length - 1);
|
||||
}
|
||||
},[setLoadMoreTop, setIsLoadingTop, entries, setEntries, query, setNoMoreDataTop, leftOffTop, setLeftOffTop, queriedCurrent, setQueriedCurrent]);
|
||||
|
||||
useEffect(() => {
|
||||
if(!isWebSocketConnectionClosed || !loadMoreTop || noMoreDataTop) return;
|
||||
getOldEntries();
|
||||
}, [loadMoreTop, noMoreDataTop, getOldEntries, isWebSocketConnectionClosed]);
|
||||
|
||||
const scrollbarVisible = scrollableRef.current?.childWrapperRef.current.clientHeight > scrollableRef.current?.wrapperRef.current.clientHeight;
|
||||
|
||||
return <>
|
||||
<div className={styles.list}>
|
||||
<div id="list" ref={listEntryREF} className={styles.list}>
|
||||
{isLoadingTop && <div className={styles.spinnerContainer}>
|
||||
<img alt="spinner" src={spinner} style={{height: 25}}/>
|
||||
</div>}
|
||||
{noMoreDataTop && <div id="noMoreDataTop" className={styles.noMoreDataAvailable}>No more data available</div>}
|
||||
<ScrollableFeedVirtualized ref={scrollableRef} itemHeight={48} marginTop={10} onSnapBroken={onSnapBrokenEvent}>
|
||||
{false /* TODO: why there is a need for something here (not necessarily false)? */}
|
||||
{entries}
|
||||
{false /* It's because the first child is ignored by ScrollableFeedVirtualized */}
|
||||
{memoizedEntries.map(entry => <EntryItem
|
||||
key={`entry-${entry.id}`}
|
||||
entry={entry}
|
||||
focusedEntryId={focusedEntryId}
|
||||
setFocusedEntryId={setFocusedEntryId}
|
||||
style={{}}
|
||||
updateQuery={updateQuery}
|
||||
headingMode={false}
|
||||
/>)}
|
||||
</ScrollableFeedVirtualized>
|
||||
<button type="button"
|
||||
className={`${styles.btnLive} ${isSnappedToBottom ? styles.hideButton : styles.showButton}`}
|
||||
title="Fetch old records"
|
||||
className={`${styles.btnOld} ${!scrollbarVisible && leftOffTop > 0 ? styles.showButton : styles.hideButton}`}
|
||||
onClick={(_) => {
|
||||
closeWebSocket();
|
||||
getOldEntries();
|
||||
}}>
|
||||
<img alt="down" src={down} />
|
||||
</button>
|
||||
<button type="button"
|
||||
title="Snap to bottom"
|
||||
className={`${styles.btnLive} ${isSnappedToBottom && !isWebSocketConnectionClosed ? styles.hideButton : styles.showButton}`}
|
||||
onClick={(_) => {
|
||||
reconnectWebSocket();
|
||||
scrollableRef.current.jumpToBottom();
|
||||
setIsSnappedToBottom(true);
|
||||
}}>
|
||||
@@ -36,8 +136,8 @@ export const EntriesList: React.FC<EntriesListProps> = ({entries, listEntryREF,
|
||||
</div>
|
||||
|
||||
<div className={styles.footer}>
|
||||
<div>Displaying <b>{entries?.length}</b> results (queried <b>{queriedCurrent}</b>/<b>{queriedTotal}</b>)</div>
|
||||
{startTime !== 0 && <div>Started listening at <span style={{marginRight: 5, fontWeight: 600, fontSize: 13}}>{new Date(startTime).toLocaleString()}</span></div>}
|
||||
<div>Displaying <b>{entries?.length}</b> results out of <b>{queriedTotal}</b> total</div>
|
||||
{startTime !== 0 && <div>Started listening at <span style={{marginRight: 5, fontWeight: 600, fontSize: 13}}>{Moment(startTime).utc().format('MM/DD/YYYY, h:mm:ss.SSS A')}</span></div>}
|
||||
</div>
|
||||
</div>
|
||||
</>;
|
||||
|
||||
@@ -73,7 +73,7 @@ const EntrySummary: React.FC<any> = ({data, updateQuery}) => {
|
||||
const entry = data.base;
|
||||
|
||||
return <EntryItem
|
||||
key={entry.id}
|
||||
key={`entry-${entry.id}`}
|
||||
entry={entry}
|
||||
focusedEntryId={null}
|
||||
setFocusedEntryId={null}
|
||||
|
||||
@@ -31,7 +31,7 @@ const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value, updateQuery,
|
||||
<Queryable
|
||||
query={query}
|
||||
updateQuery={updateQuery}
|
||||
style={{float: "right", height: "0px"}}
|
||||
style={{float: "right", height: "18px"}}
|
||||
iconStyle={{marginRight: "20px"}}
|
||||
flipped={true}
|
||||
displayIconOnMouseOver={true}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
.ruleNumberTextSuccess
|
||||
color: #219653
|
||||
|
||||
.service
|
||||
.resolvedName
|
||||
text-overflow: ellipsis
|
||||
overflow: hidden
|
||||
white-space: nowrap
|
||||
@@ -60,7 +60,7 @@
|
||||
color: $secondary-font-color
|
||||
padding-left: 12px
|
||||
flex-shrink: 0
|
||||
width: 145px
|
||||
width: 185px
|
||||
text-align: left
|
||||
|
||||
.endpointServiceContainer
|
||||
@@ -69,8 +69,6 @@
|
||||
overflow: hidden
|
||||
padding-right: 10px
|
||||
flex-grow: 1
|
||||
padding-top: 5px
|
||||
margin-left: -6px
|
||||
|
||||
.separatorRight
|
||||
display: flex
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React from "react";
|
||||
import Moment from 'moment';
|
||||
import SwapHorizIcon from '@material-ui/icons/SwapHoriz';
|
||||
import styles from './EntryListItem.module.sass';
|
||||
import StatusCode, {getClassification, StatusCodeClassification} from "../UI/StatusCode";
|
||||
import Protocol, {ProtocolInterface} from "../UI/Protocol"
|
||||
@@ -11,19 +13,21 @@ import outgoingIconSuccess from "../assets/outgoing-traffic-success.svg"
|
||||
import outgoingIconFailure from "../assets/outgoing-traffic-failure.svg"
|
||||
import outgoingIconNeutral from "../assets/outgoing-traffic-neutral.svg"
|
||||
|
||||
interface TCPInterface {
|
||||
ip: string
|
||||
port: string
|
||||
name: string
|
||||
}
|
||||
|
||||
interface Entry {
|
||||
protocol: ProtocolInterface,
|
||||
method?: string,
|
||||
summary: string,
|
||||
service: string,
|
||||
id: number,
|
||||
statusCode?: number;
|
||||
url?: string;
|
||||
timestamp: Date;
|
||||
sourceIp: string,
|
||||
sourcePort: string,
|
||||
destinationIp: string,
|
||||
destinationPort: string,
|
||||
src: TCPInterface,
|
||||
dst: TCPInterface,
|
||||
isOutgoing?: boolean;
|
||||
latency: number;
|
||||
rules: Rules;
|
||||
@@ -119,9 +123,13 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
break;
|
||||
}
|
||||
|
||||
const isStatusCodeEnabled = ((entry.protocol.name === "http" && "statusCode" in entry) || entry.statusCode !== 0);
|
||||
var endpointServiceContainer = "10px";
|
||||
if (!isStatusCodeEnabled) endpointServiceContainer = "20px";
|
||||
|
||||
return <>
|
||||
<div
|
||||
id={entry.id.toString()}
|
||||
id={`entry-${entry.id.toString()}`}
|
||||
className={`${styles.row}
|
||||
${isSelected && !rule && !contractEnabled ? styles.rowSelected : additionalRulesProperties}`}
|
||||
onClick={() => {
|
||||
@@ -141,22 +149,38 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
horizontal={false}
|
||||
updateQuery={updateQuery}
|
||||
/> : null}
|
||||
{((entry.protocol.name === "http" && "statusCode" in entry) || entry.statusCode !== 0) && <div>
|
||||
{isStatusCodeEnabled && <div>
|
||||
<StatusCode statusCode={entry.statusCode} updateQuery={updateQuery}/>
|
||||
</div>}
|
||||
<div className={styles.endpointServiceContainer}>
|
||||
<div className={styles.endpointServiceContainer} style={{paddingLeft: endpointServiceContainer}}>
|
||||
<Summary method={entry.method} summary={entry.summary} updateQuery={updateQuery}/>
|
||||
<div className={styles.service}>
|
||||
<div className={styles.resolvedName}>
|
||||
<Queryable
|
||||
query={`service == "${entry.service}"`}
|
||||
query={`src.name == "${entry.src.name}"`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={true}
|
||||
style={{marginTop: "-4px", overflow: "visible"}}
|
||||
iconStyle={{marginTop: "4px", left: "68px", position: "absolute"}}
|
||||
>
|
||||
<span
|
||||
title="Source Name"
|
||||
>
|
||||
{entry.src.name ? entry.src.name : "[Unresolved]"}
|
||||
</span>
|
||||
</Queryable>
|
||||
<SwapHorizIcon style={{color: entry.protocol.backgroundColor, marginTop: "-2px"}}></SwapHorizIcon>
|
||||
<Queryable
|
||||
query={`dst.name == "${entry.dst.name}"`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
style={{marginTop: "-4px"}}
|
||||
iconStyle={{marginTop: "4px", marginLeft: "-2px"}}
|
||||
>
|
||||
<span
|
||||
title="Service Name"
|
||||
title="Destination Name"
|
||||
>
|
||||
{entry.service}
|
||||
{entry.dst.name ? entry.dst.name : "[Unresolved]"}
|
||||
</span>
|
||||
</Queryable>
|
||||
</div>
|
||||
@@ -177,7 +201,7 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
}
|
||||
<div className={styles.separatorRight}>
|
||||
<Queryable
|
||||
query={`src.ip == "${entry.sourceIp}"`}
|
||||
query={`src.ip == "${entry.src.ip}"`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={true}
|
||||
@@ -187,12 +211,12 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
className={`${styles.tcpInfo} ${styles.ip}`}
|
||||
title="Source IP"
|
||||
>
|
||||
{entry.sourceIp}
|
||||
{entry.src.ip}
|
||||
</span>
|
||||
</Queryable>
|
||||
<span className={`${styles.tcpInfo}`} style={{marginTop: "18px"}}>:</span>
|
||||
<Queryable
|
||||
query={`src.port == "${entry.sourcePort}"`}
|
||||
query={`src.port == "${entry.src.port}"`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={true}
|
||||
@@ -202,7 +226,7 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
className={`${styles.tcpInfo} ${styles.port}`}
|
||||
title="Source Port"
|
||||
>
|
||||
{entry.sourcePort}
|
||||
{entry.src.port}
|
||||
</span>
|
||||
</Queryable>
|
||||
{entry.isOutgoing ?
|
||||
@@ -238,7 +262,7 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
</Queryable>
|
||||
}
|
||||
<Queryable
|
||||
query={`dst.ip == "${entry.destinationIp}"`}
|
||||
query={`dst.ip == "${entry.dst.ip}"`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={false}
|
||||
@@ -248,12 +272,12 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
className={`${styles.tcpInfo} ${styles.ip}`}
|
||||
title="Destination IP"
|
||||
>
|
||||
{entry.destinationIp}
|
||||
{entry.dst.ip}
|
||||
</span>
|
||||
</Queryable>
|
||||
<span className={`${styles.tcpInfo}`} style={{marginTop: "18px"}}>:</span>
|
||||
<Queryable
|
||||
query={`dst.port == "${entry.destinationPort}"`}
|
||||
query={`dst.port == "${entry.dst.port}"`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={false}
|
||||
@@ -262,13 +286,13 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
className={`${styles.tcpInfo} ${styles.port}`}
|
||||
title="Destination Port"
|
||||
>
|
||||
{entry.destinationPort}
|
||||
{entry.dst.port}
|
||||
</span>
|
||||
</Queryable>
|
||||
</div>
|
||||
<div className={styles.timestamp}>
|
||||
<Queryable
|
||||
query={`timestamp >= datetime("${new Date(+entry.timestamp)?.toLocaleString("en-US", {timeZone: 'UTC' })}")`}
|
||||
query={`timestamp >= datetime("${Moment(+entry.timestamp)?.utc().format('MM/DD/YYYY, h:mm:ss.SSS A')}")`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={false}
|
||||
@@ -276,7 +300,7 @@ export const EntryItem: React.FC<EntryProps> = ({entry, focusedEntryId, setFocus
|
||||
<span
|
||||
title="Timestamp"
|
||||
>
|
||||
{new Date(+entry.timestamp)?.toLocaleString("en-US")}
|
||||
{Moment(+entry.timestamp)?.utc().format('MM/DD/YYYY, h:mm:ss.SSS A')}
|
||||
</span>
|
||||
</Queryable>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ interface FiltersProps {
|
||||
setQuery: any
|
||||
backgroundColor: string
|
||||
ws: any
|
||||
openWebSocket: (query: string, resetEntriesBuffer: boolean) => void;
|
||||
openWebSocket: (query: string, resetEntries: boolean) => void;
|
||||
}
|
||||
|
||||
export const Filters: React.FC<FiltersProps> = ({query, setQuery, backgroundColor, ws, openWebSocket}) => {
|
||||
@@ -33,7 +33,7 @@ interface QueryFormProps {
|
||||
setQuery: any
|
||||
backgroundColor: string
|
||||
ws: any
|
||||
openWebSocket: (query: string, resetEntriesBuffer: boolean) => void;
|
||||
openWebSocket: (query: string, resetEntries: boolean) => void;
|
||||
}
|
||||
|
||||
const style = {
|
||||
@@ -64,7 +64,11 @@ export const QueryForm: React.FC<QueryFormProps> = ({query, setQuery, background
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
ws.close();
|
||||
openWebSocket(query, true);
|
||||
if (query) {
|
||||
openWebSocket(`(${query}) and leftOff(-1)`, true);
|
||||
} else {
|
||||
openWebSocket(`leftOff(-1)`, true);
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
@@ -210,7 +214,7 @@ export const QueryForm: React.FC<QueryFormProps> = ({query, setQuery, background
|
||||
<SyntaxHighlighter
|
||||
isWrapped={false}
|
||||
showLineNumbers={false}
|
||||
code={`timestamp < datetime("10/28/2021, 9:13:02 PM")`}
|
||||
code={`timestamp < datetime("10/28/2021, 9:13:02.905 PM")`}
|
||||
language="python"
|
||||
/>
|
||||
</Grid>
|
||||
@@ -240,7 +244,7 @@ export const QueryForm: React.FC<QueryFormProps> = ({query, setQuery, background
|
||||
<SyntaxHighlighter
|
||||
isWrapped={false}
|
||||
showLineNumbers={false}
|
||||
code={`and service == "carts.sock-shop"`}
|
||||
code={`and dst.name == "carts.sock-shop"`}
|
||||
language="python"
|
||||
/>
|
||||
<Typography id="modal-modal-description">
|
||||
@@ -301,7 +305,7 @@ export const QueryForm: React.FC<QueryFormProps> = ({query, setQuery, background
|
||||
<SyntaxHighlighter
|
||||
isWrapped={false}
|
||||
showLineNumbers={false}
|
||||
code={`timestamp >= datetime("10/19/2021, 6:29:02 PM")`}
|
||||
code={`timestamp >= datetime("10/19/2021, 6:29:02.593 PM")`}
|
||||
language="python"
|
||||
/>
|
||||
<Typography id="modal-modal-description">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, {useEffect, useRef, useState} from "react";
|
||||
import {Filters} from "./Filters";
|
||||
import {EntriesList} from "./EntriesList";
|
||||
import {EntryItem} from "./EntryListItem/EntryListItem";
|
||||
import {makeStyles} from "@material-ui/core";
|
||||
import "./style/TrafficPage.sass";
|
||||
import styles from './style/EntriesList.module.sass';
|
||||
@@ -51,11 +50,12 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
const classes = useLayoutStyles();
|
||||
|
||||
const [entries, setEntries] = useState([] as any);
|
||||
const [entriesBuffer, setEntriesBuffer] = useState([] as any);
|
||||
const [focusedEntryId, setFocusedEntryId] = useState(null);
|
||||
const [selectedEntryData, setSelectedEntryData] = useState(null);
|
||||
const [connection, setConnection] = useState(ConnectionStatus.Closed);
|
||||
|
||||
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
|
||||
|
||||
const [tappingStatus, setTappingStatus] = useState(null);
|
||||
|
||||
const [isSnappedToBottom, setIsSnappedToBottom] = useState(true);
|
||||
@@ -66,7 +66,8 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
|
||||
const [queriedCurrent, setQueriedCurrent] = useState(0);
|
||||
const [queriedTotal, setQueriedTotal] = useState(0);
|
||||
const [leftOff, setLeftOff] = useState(0);
|
||||
const [leftOffBottom, setLeftOffBottom] = useState(0);
|
||||
const [leftOffTop, setLeftOffTop] = useState(null);
|
||||
|
||||
const [startTime, setStartTime] = useState(0);
|
||||
|
||||
@@ -101,13 +102,13 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
|
||||
const listEntry = useRef(null);
|
||||
|
||||
const openWebSocket = (query: string, resetEntriesBuffer: boolean) => {
|
||||
if (resetEntriesBuffer) {
|
||||
const openWebSocket = (query: string, resetEntries: boolean) => {
|
||||
if (resetEntries) {
|
||||
setFocusedEntryId(null);
|
||||
setEntries([]);
|
||||
setEntriesBuffer([]);
|
||||
} else {
|
||||
setEntriesBuffer(entries);
|
||||
setQueriedCurrent(0);
|
||||
setLeftOffTop(null);
|
||||
setNoMoreDataTop(false);
|
||||
}
|
||||
ws.current = new WebSocket(MizuWebsocketURL);
|
||||
ws.current.onopen = () => {
|
||||
@@ -120,9 +121,9 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
ws.current.onerror = (event) => {
|
||||
console.error("WebSocket error:", event);
|
||||
if (query) {
|
||||
openWebSocket(`(${query}) and leftOff(${leftOff})`, false);
|
||||
openWebSocket(`(${query}) and leftOff(${leftOffBottom})`, false);
|
||||
} else {
|
||||
openWebSocket(`leftOff(${leftOff})`, false);
|
||||
openWebSocket(`leftOff(${leftOffBottom})`, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,23 +135,14 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
switch (message.messageType) {
|
||||
case "entry":
|
||||
const entry = message.data;
|
||||
var focusThis = false;
|
||||
if (!focusedEntryId) {
|
||||
focusThis = true;
|
||||
setFocusedEntryId(entry.id.toString());
|
||||
if (!focusedEntryId) setFocusedEntryId(entry.id.toString())
|
||||
const newEntries = [...entries, entry];
|
||||
if (newEntries.length === 10001) {
|
||||
setLeftOffTop(newEntries[0].entry.id);
|
||||
newEntries.shift();
|
||||
setNoMoreDataTop(false);
|
||||
}
|
||||
setEntriesBuffer([
|
||||
...entriesBuffer,
|
||||
<EntryItem
|
||||
key={entry.id}
|
||||
entry={entry}
|
||||
focusedEntryId={focusThis ? entry.id.toString() : focusedEntryId}
|
||||
setFocusedEntryId={setFocusedEntryId}
|
||||
style={{}}
|
||||
updateQuery={updateQuery}
|
||||
headingMode={false}
|
||||
/>
|
||||
]);
|
||||
setEntries(newEntries);
|
||||
break
|
||||
case "status":
|
||||
setTappingStatus(message.tappingStatus);
|
||||
@@ -174,24 +166,16 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
});
|
||||
break;
|
||||
case "queryMetadata":
|
||||
setQueriedCurrent(message.data.current);
|
||||
setQueriedCurrent(queriedCurrent + message.data.current);
|
||||
setQueriedTotal(message.data.total);
|
||||
setLeftOff(message.data.leftOff);
|
||||
setEntries(entriesBuffer);
|
||||
setLeftOffBottom(message.data.leftOff);
|
||||
if (leftOffTop === null) {
|
||||
setLeftOffTop(message.data.leftOff - 1);
|
||||
}
|
||||
break;
|
||||
case "startTime":
|
||||
setStartTime(message.data);
|
||||
break;
|
||||
case "focusEntry":
|
||||
// To achieve selecting only one entry, render all elements in the buffer
|
||||
// with the current `focusedEntryId` value.
|
||||
entriesBuffer.forEach((entry: any, i: number) => {
|
||||
entriesBuffer[i] = React.cloneElement(entry, {
|
||||
focusedEntryId: focusedEntryId
|
||||
});
|
||||
})
|
||||
setEntries(entriesBuffer);
|
||||
break;
|
||||
default:
|
||||
console.error(`unsupported websocket message type, Got: ${message.messageType}`)
|
||||
}
|
||||
@@ -217,11 +201,6 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
useEffect(() => {
|
||||
if (!focusedEntryId) return;
|
||||
setSelectedEntryData(null);
|
||||
|
||||
if (ws.current.readyState === WebSocket.OPEN) {
|
||||
ws.current.send(focusedEntryId);
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const entryData = await api.getEntry(focusedEntryId);
|
||||
@@ -241,18 +220,27 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
}
|
||||
console.error(error);
|
||||
}
|
||||
})()
|
||||
}, [focusedEntryId])
|
||||
})();
|
||||
// eslint-disable-next-line
|
||||
}, [focusedEntryId]);
|
||||
|
||||
const closeWebSocket = () => {
|
||||
ws.current.close();
|
||||
}
|
||||
|
||||
const reconnectWebSocket = () => {
|
||||
if (query) {
|
||||
openWebSocket(`(${query}) and leftOff(${leftOffBottom})`, false);
|
||||
} else {
|
||||
openWebSocket(`leftOff(${leftOffBottom})`, false);
|
||||
}
|
||||
}
|
||||
|
||||
const toggleConnection = () => {
|
||||
if (connection === ConnectionStatus.Connected) {
|
||||
ws.current.close();
|
||||
closeWebSocket();
|
||||
} else {
|
||||
if (query) {
|
||||
openWebSocket(`(${query}) and leftOff(${leftOff})`, false);
|
||||
} else {
|
||||
openWebSocket(`leftOff(${leftOff})`, false);
|
||||
}
|
||||
reconnectWebSocket();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +264,10 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
}
|
||||
|
||||
const onSnapBrokenEvent = () => {
|
||||
setIsSnappedToBottom(false)
|
||||
setIsSnappedToBottom(false);
|
||||
if (connection === ConnectionStatus.Connected) {
|
||||
closeWebSocket();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -305,13 +296,26 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
|
||||
<div className={styles.container}>
|
||||
<EntriesList
|
||||
entries={entries}
|
||||
setEntries={setEntries}
|
||||
query={query}
|
||||
listEntryREF={listEntry}
|
||||
onSnapBrokenEvent={onSnapBrokenEvent}
|
||||
isSnappedToBottom={isSnappedToBottom}
|
||||
setIsSnappedToBottom={setIsSnappedToBottom}
|
||||
queriedCurrent={queriedCurrent}
|
||||
setQueriedCurrent={setQueriedCurrent}
|
||||
queriedTotal={queriedTotal}
|
||||
startTime={startTime}
|
||||
noMoreDataTop={noMoreDataTop}
|
||||
setNoMoreDataTop={setNoMoreDataTop}
|
||||
focusedEntryId={focusedEntryId}
|
||||
setFocusedEntryId={setFocusedEntryId}
|
||||
updateQuery={updateQuery}
|
||||
leftOffTop={leftOffTop}
|
||||
setLeftOffTop={setLeftOffTop}
|
||||
reconnectWebSocket={reconnectWebSocket}
|
||||
isWebSocketConnectionClosed={connection === ConnectionStatus.Closed}
|
||||
closeWebSocket={closeWebSocket}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -48,7 +48,7 @@ const Protocol: React.FC<ProtocolProps> = ({protocol, horizontal, updateQuery})
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={false}
|
||||
iconStyle={{marginTop: "48px"}}
|
||||
iconStyle={{marginTop: "52px", marginRight: "10px", zIndex: 1000}}
|
||||
>
|
||||
<span
|
||||
className={`${styles.base} ${styles.vertical}`}
|
||||
@@ -56,6 +56,7 @@ const Protocol: React.FC<ProtocolProps> = ({protocol, horizontal, updateQuery})
|
||||
backgroundColor: protocol.backgroundColor,
|
||||
color: protocol.foregroundColor,
|
||||
fontSize: protocol.fontSize,
|
||||
marginRight: "-20px",
|
||||
}}
|
||||
title={protocol.longName}
|
||||
>
|
||||
|
||||
@@ -20,8 +20,9 @@ const StatusCode: React.FC<EntryProps> = ({statusCode, updateQuery}) => {
|
||||
return <Queryable
|
||||
query={`response.status == ${statusCode}`}
|
||||
updateQuery={updateQuery}
|
||||
style={{minWidth: "68px"}}
|
||||
displayIconOnMouseOver={true}
|
||||
flipped={true}
|
||||
iconStyle={{marginTop: "40px", paddingLeft: "10px"}}
|
||||
>
|
||||
<span
|
||||
title="Status Code"
|
||||
|
||||
@@ -17,6 +17,7 @@ export const Summary: React.FC<SummaryProps> = ({method, summary, updateQuery})
|
||||
className={`${miscStyles.protocol} ${miscStyles.method}`}
|
||||
updateQuery={updateQuery}
|
||||
displayIconOnMouseOver={true}
|
||||
style={{whiteSpace: "nowrap"}}
|
||||
>
|
||||
<span>
|
||||
{method}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 46 KiB |
@@ -38,6 +38,31 @@
|
||||
border: 1px solid #627ef7
|
||||
background-color: rgba(255, 255, 255, 0.06)
|
||||
|
||||
.spinnerContainer
|
||||
display: flex
|
||||
justify-content: center
|
||||
margin-bottom: 10px
|
||||
|
||||
.noMoreDataAvailable
|
||||
text-align: center
|
||||
font-weight: 600
|
||||
color: $secondary-font-color
|
||||
|
||||
.btnOld
|
||||
position: absolute
|
||||
top: 20px
|
||||
right: 10px
|
||||
background: #205CF5
|
||||
border-radius: 50%
|
||||
height: 35px
|
||||
width: 35px
|
||||
border: none
|
||||
cursor: pointer
|
||||
z-index: 1
|
||||
img
|
||||
height: 10px
|
||||
transform: scaleY(-1)
|
||||
|
||||
.btnLive
|
||||
position: absolute
|
||||
bottom: 10px
|
||||
|
||||
@@ -38,6 +38,14 @@ export default class Api {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
fetchEntries = async (leftOff, direction, query, limit, timeoutMs) => {
|
||||
const response = await this.client.get(`/entries/?leftOff=${leftOff}&direction=${direction}&query=${query}&limit=${limit}&timeoutMs=${timeoutMs}`).catch(function (thrown) {
|
||||
console.error(thrown.message);
|
||||
return {};
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
getRecentTLSLinks = async () => {
|
||||
const response = await this.client.get("/status/recentTLSLinks");
|
||||
return response.data;
|
||||
|
||||
Reference in New Issue
Block a user