mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-03-06 04:32:12 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c010d336bb | ||
|
|
710411e112 |
@@ -22,7 +22,7 @@ func (e *DefaultEntryStreamerSocketConnector) SendEntry(socketId int, entry *tap
|
|||||||
if params.EnableFullEntries {
|
if params.EnableFullEntries {
|
||||||
message, _ = models.CreateFullEntryWebSocketMessage(entry)
|
message, _ = models.CreateFullEntryWebSocketMessage(entry)
|
||||||
} else {
|
} else {
|
||||||
protocol, ok := protocolsMap[entry.ProtocolId]
|
protocol, ok := protocolsMap[entry.Protocol.ToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("protocol not found, protocol: %v", protocol)
|
return fmt.Errorf("protocol not found, protocol: %v", protocol)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ func startReadingChannel(outputItems <-chan *tapApi.OutputChannelItem, extension
|
|||||||
serviceMapGenerator.NewTCPEntry(mizuEntry.Source, mizuEntry.Destination, &item.Protocol)
|
serviceMapGenerator.NewTCPEntry(mizuEntry.Source, mizuEntry.Destination, &item.Protocol)
|
||||||
|
|
||||||
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGeneratorSink)
|
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGeneratorSink)
|
||||||
oasGenerator.HandleEntry(mizuEntry, &item.Protocol)
|
oasGenerator.HandleEntry(mizuEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,11 +36,13 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var ProtocolHttp = &tapApi.Protocol{
|
var ProtocolHttp = &tapApi.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: tapApi.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "1.1",
|
||||||
|
Abbreviation: "HTTP",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
|
LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
|
||||||
Abbreviation: "HTTP",
|
|
||||||
Macro: "http",
|
Macro: "http",
|
||||||
Version: "1.1",
|
|
||||||
BackgroundColor: "#205cf5",
|
BackgroundColor: "#205cf5",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func (e *BasenineEntriesProvider) GetEntries(entriesRequest *models.EntriesReque
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol, ok := app.ProtocolsMap[entry.ProtocolId]
|
protocol, ok := app.ProtocolsMap[entry.Protocol.ToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
|
return nil, nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ func (e *BasenineEntriesProvider) GetEntry(singleEntryRequest *models.SingleEntr
|
|||||||
return nil, errors.New(string(bytes))
|
return nil, errors.New(string(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol, ok := app.ProtocolsMap[entry.ProtocolId]
|
protocol, ok := app.ProtocolsMap[entry.Protocol.ToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
|
return nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type OasGeneratorSink interface {
|
type OasGeneratorSink interface {
|
||||||
HandleEntry(mizuEntry *api.Entry, protocol *api.Protocol)
|
HandleEntry(mizuEntry *api.Entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
type OasGenerator interface {
|
type OasGenerator interface {
|
||||||
@@ -58,12 +58,12 @@ func (g *defaultOasGenerator) IsStarted() bool {
|
|||||||
return g.started
|
return g.started
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *defaultOasGenerator) HandleEntry(mizuEntry *api.Entry, protocol *api.Protocol) {
|
func (g *defaultOasGenerator) HandleEntry(mizuEntry *api.Entry) {
|
||||||
if !g.started {
|
if !g.started {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if protocol.Name == "http" {
|
if mizuEntry.Protocol.Name == "http" {
|
||||||
dest := mizuEntry.Destination.Name
|
dest := mizuEntry.Destination.Name
|
||||||
if dest == "" {
|
if dest == "" {
|
||||||
logger.Log.Debugf("OAS: Unresolved entry %d", mizuEntry.Id)
|
logger.Log.Debugf("OAS: Unresolved entry %d", mizuEntry.Id)
|
||||||
@@ -85,7 +85,7 @@ func (g *defaultOasGenerator) HandleEntry(mizuEntry *api.Entry, protocol *api.Pr
|
|||||||
|
|
||||||
g.handleHARWithSource(entryWSource)
|
g.handleHARWithSource(entryWSource)
|
||||||
} else {
|
} else {
|
||||||
logger.Log.Debugf("OAS: Unsupported protocol in entry %d: %s", mizuEntry.Id, protocol.Name)
|
logger.Log.Debugf("OAS: Unsupported protocol in entry %d: %s", mizuEntry.Id, mizuEntry.Protocol.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func TestEntryAddedCount(t *testing.T) {
|
|||||||
|
|
||||||
entryBucketKey := time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC)
|
entryBucketKey := time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC)
|
||||||
valueLessThanBucketThreshold := time.Second * 130
|
valueLessThanBucketThreshold := time.Second * 130
|
||||||
mockSummery := &api.BaseEntry{Protocol: api.Protocol{Name: "mock"}, Method: "mock-method", Timestamp: entryBucketKey.Add(valueLessThanBucketThreshold).UnixNano()}
|
mockSummery := &api.BaseEntry{Protocol: api.Protocol{ProtocolSummary: api.ProtocolSummary{Name: "mock"}}, Method: "mock-method", Timestamp: entryBucketKey.Add(valueLessThanBucketThreshold).UnixNano()}
|
||||||
for _, entriesCount := range tests {
|
for _, entriesCount := range tests {
|
||||||
t.Run(fmt.Sprintf("%d", entriesCount), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d", entriesCount), func(t *testing.T) {
|
||||||
for i := 0; i < entriesCount; i++ {
|
for i := 0; i < entriesCount; i++ {
|
||||||
@@ -61,7 +61,7 @@ func TestEntryAddedVolume(t *testing.T) {
|
|||||||
var expectedEntriesCount int
|
var expectedEntriesCount int
|
||||||
var expectedVolumeInGB float64
|
var expectedVolumeInGB float64
|
||||||
|
|
||||||
mockSummery := &api.BaseEntry{Protocol: api.Protocol{Name: "mock"}, Method: "mock-method", Timestamp: time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC).UnixNano()}
|
mockSummery := &api.BaseEntry{Protocol: api.Protocol{ProtocolSummary: api.ProtocolSummary{Name: "mock"}}, Method: "mock-method", Timestamp: time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC).UnixNano()}
|
||||||
|
|
||||||
for _, data := range tests {
|
for _, data := range tests {
|
||||||
t.Run(fmt.Sprintf("%d", len(data)), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d", len(data)), func(t *testing.T) {
|
||||||
|
|||||||
@@ -50,11 +50,13 @@ var (
|
|||||||
IP: fmt.Sprintf("%s.%s", Ip, UnresolvedNodeName),
|
IP: fmt.Sprintf("%s.%s", Ip, UnresolvedNodeName),
|
||||||
}
|
}
|
||||||
ProtocolHttp = &tapApi.Protocol{
|
ProtocolHttp = &tapApi.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: tapApi.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "1.1",
|
||||||
|
Abbreviation: "HTTP",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
|
LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
|
||||||
Abbreviation: "HTTP",
|
|
||||||
Macro: "http",
|
Macro: "http",
|
||||||
Version: "1.1",
|
|
||||||
BackgroundColor: "#205cf5",
|
BackgroundColor: "#205cf5",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
@@ -63,11 +65,13 @@ var (
|
|||||||
Priority: 0,
|
Priority: 0,
|
||||||
}
|
}
|
||||||
ProtocolRedis = &tapApi.Protocol{
|
ProtocolRedis = &tapApi.Protocol{
|
||||||
Name: "redis",
|
ProtocolSummary: tapApi.ProtocolSummary{
|
||||||
|
Name: "redis",
|
||||||
|
Version: "3.x",
|
||||||
|
Abbreviation: "REDIS",
|
||||||
|
},
|
||||||
LongName: "Redis Serialization Protocol",
|
LongName: "Redis Serialization Protocol",
|
||||||
Abbreviation: "REDIS",
|
|
||||||
Macro: "redis",
|
Macro: "redis",
|
||||||
Version: "3.x",
|
|
||||||
BackgroundColor: "#a41e11",
|
BackgroundColor: "#a41e11",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 11,
|
FontSize: 11,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -14,12 +15,20 @@ const UnknownNamespace = ""
|
|||||||
var UnknownIp = net.IP{0, 0, 0, 0}
|
var UnknownIp = net.IP{0, 0, 0, 0}
|
||||||
var UnknownPort uint16 = 0
|
var UnknownPort uint16 = 0
|
||||||
|
|
||||||
|
type ProtocolSummary struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Abbreviation string `json:"abbr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (protocol *ProtocolSummary) ToString() string {
|
||||||
|
return fmt.Sprintf("%s?%s?%s", protocol.Name, protocol.Version, protocol.Abbreviation)
|
||||||
|
}
|
||||||
|
|
||||||
type Protocol struct {
|
type Protocol struct {
|
||||||
Name string `json:"name"`
|
ProtocolSummary
|
||||||
LongName string `json:"longName"`
|
LongName string `json:"longName"`
|
||||||
Abbreviation string `json:"abbr"`
|
|
||||||
Macro string `json:"macro"`
|
Macro string `json:"macro"`
|
||||||
Version string `json:"version"`
|
|
||||||
BackgroundColor string `json:"backgroundColor"`
|
BackgroundColor string `json:"backgroundColor"`
|
||||||
ForegroundColor string `json:"foregroundColor"`
|
ForegroundColor string `json:"foregroundColor"`
|
||||||
FontSize int8 `json:"fontSize"`
|
FontSize int8 `json:"fontSize"`
|
||||||
@@ -151,7 +160,7 @@ func (e *Emitting) Emit(item *OutputChannelItem) {
|
|||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
ProtocolId string `json:"protocol"`
|
Protocol ProtocolSummary `json:"protocol"`
|
||||||
Capture Capture `json:"capture"`
|
Capture Capture `json:"capture"`
|
||||||
Source *TCP `json:"src"`
|
Source *TCP `json:"src"`
|
||||||
Destination *TCP `json:"dst"`
|
Destination *TCP `json:"dst"`
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect14/amqp/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect15/amqp/\* expect
|
||||||
|
|||||||
@@ -13,11 +13,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var protocol = api.Protocol{
|
var protocol = api.Protocol{
|
||||||
Name: "amqp",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "amqp",
|
||||||
|
Version: "0-9-1",
|
||||||
|
Abbreviation: "AMQP",
|
||||||
|
},
|
||||||
LongName: "Advanced Message Queuing Protocol 0-9-1",
|
LongName: "Advanced Message Queuing Protocol 0-9-1",
|
||||||
Abbreviation: "AMQP",
|
|
||||||
Macro: "amqp",
|
Macro: "amqp",
|
||||||
Version: "0-9-1",
|
|
||||||
BackgroundColor: "#ff6600",
|
BackgroundColor: "#ff6600",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
@@ -27,7 +29,7 @@ var protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var protocolsMap = map[string]*api.Protocol{
|
var protocolsMap = map[string]*api.Protocol{
|
||||||
fmt.Sprintf("%s/%s/%s", protocol.Name, protocol.Version, protocol.Abbreviation): &protocol,
|
protocol.ToString(): &protocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
type dissecting string
|
type dissecting string
|
||||||
@@ -222,8 +224,8 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
|
|
||||||
reqDetails["method"] = request["method"]
|
reqDetails["method"] = request["method"]
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
ProtocolId: fmt.Sprintf("%s/%s/%s", protocol.Name, protocol.Version, protocol.Abbreviation),
|
Protocol: protocol.ProtocolSummary,
|
||||||
Capture: item.Capture,
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -285,7 +287,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
|
|
||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: *protocolsMap[entry.ProtocolId],
|
Protocol: *protocolsMap[entry.Protocol.ToString()],
|
||||||
Capture: entry.Capture,
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
@@ -329,7 +331,7 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`amqp`: fmt.Sprintf(`protocol == "%s/%s/%s"`, protocol.Name, protocol.Version, protocol.Abbreviation),
|
`amqp`: fmt.Sprintf(`protocol.name == "%s"`, protocol.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func TestRegister(t *testing.T) {
|
|||||||
|
|
||||||
func TestMacros(t *testing.T) {
|
func TestMacros(t *testing.T) {
|
||||||
expectedMacros := map[string]string{
|
expectedMacros := map[string]string{
|
||||||
"amqp": `protocol == "amqp/0-9-1/AMQP"`,
|
"amqp": `protocol.name == "amqp"`,
|
||||||
}
|
}
|
||||||
dissector := NewDissector()
|
dissector := NewDissector()
|
||||||
macros := dissector.Macros()
|
macros := dissector.Macros()
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect14/http/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect15/http/\* expect
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var http10protocol = api.Protocol{
|
var http10protocol = api.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "1.0",
|
||||||
|
Abbreviation: "HTTP",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol -- HTTP/1.0",
|
LongName: "Hypertext Transfer Protocol -- HTTP/1.0",
|
||||||
Abbreviation: "HTTP",
|
|
||||||
Macro: "http",
|
Macro: "http",
|
||||||
Version: "1.0",
|
|
||||||
BackgroundColor: "#205cf5",
|
BackgroundColor: "#205cf5",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
@@ -29,11 +31,13 @@ var http10protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var http11protocol = api.Protocol{
|
var http11protocol = api.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "1.1",
|
||||||
|
Abbreviation: "HTTP",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
|
LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
|
||||||
Abbreviation: "HTTP",
|
|
||||||
Macro: "http",
|
Macro: "http",
|
||||||
Version: "1.1",
|
|
||||||
BackgroundColor: "#205cf5",
|
BackgroundColor: "#205cf5",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
@@ -43,11 +47,13 @@ var http11protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var http2Protocol = api.Protocol{
|
var http2Protocol = api.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "2.0",
|
||||||
|
Abbreviation: "HTTP/2",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2)",
|
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2)",
|
||||||
Abbreviation: "HTTP/2",
|
|
||||||
Macro: "http2",
|
Macro: "http2",
|
||||||
Version: "2.0",
|
|
||||||
BackgroundColor: "#244c5a",
|
BackgroundColor: "#244c5a",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 11,
|
FontSize: 11,
|
||||||
@@ -57,11 +63,13 @@ var http2Protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var grpcProtocol = api.Protocol{
|
var grpcProtocol = api.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "2.0",
|
||||||
|
Abbreviation: "gRPC",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ gRPC over HTTP/2 ]",
|
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ gRPC over HTTP/2 ]",
|
||||||
Abbreviation: "gRPC",
|
|
||||||
Macro: "grpc",
|
Macro: "grpc",
|
||||||
Version: "2.0",
|
|
||||||
BackgroundColor: "#244c5a",
|
BackgroundColor: "#244c5a",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 11,
|
FontSize: 11,
|
||||||
@@ -71,11 +79,13 @@ var grpcProtocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var graphQL1Protocol = api.Protocol{
|
var graphQL1Protocol = api.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "1.1",
|
||||||
|
Abbreviation: "GQL",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol -- HTTP/1.1 [ GraphQL over HTTP/1.1 ]",
|
LongName: "Hypertext Transfer Protocol -- HTTP/1.1 [ GraphQL over HTTP/1.1 ]",
|
||||||
Abbreviation: "GQL",
|
|
||||||
Macro: "gql",
|
Macro: "gql",
|
||||||
Version: "1.1",
|
|
||||||
BackgroundColor: "#e10098",
|
BackgroundColor: "#e10098",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
@@ -85,11 +95,13 @@ var graphQL1Protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var graphQL2Protocol = api.Protocol{
|
var graphQL2Protocol = api.Protocol{
|
||||||
Name: "http",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "http",
|
||||||
|
Version: "2.0",
|
||||||
|
Abbreviation: "GQL",
|
||||||
|
},
|
||||||
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ GraphQL over HTTP/2 ]",
|
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ GraphQL over HTTP/2 ]",
|
||||||
Abbreviation: "GQL",
|
|
||||||
Macro: "gql",
|
Macro: "gql",
|
||||||
Version: "2.0",
|
|
||||||
BackgroundColor: "#e10098",
|
BackgroundColor: "#e10098",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
@@ -99,12 +111,12 @@ var graphQL2Protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var protocolsMap = map[string]*api.Protocol{
|
var protocolsMap = map[string]*api.Protocol{
|
||||||
fmt.Sprintf("%s/%s/%s", http10protocol.Name, http10protocol.Version, http10protocol.Abbreviation): &http10protocol,
|
http10protocol.ToString(): &http10protocol,
|
||||||
fmt.Sprintf("%s/%s/%s", http11protocol.Name, http11protocol.Version, http11protocol.Abbreviation): &http11protocol,
|
http11protocol.ToString(): &http11protocol,
|
||||||
fmt.Sprintf("%s/%s/%s", http2Protocol.Name, http2Protocol.Version, http2Protocol.Abbreviation): &http2Protocol,
|
http2Protocol.ToString(): &http2Protocol,
|
||||||
fmt.Sprintf("%s/%s/%s", grpcProtocol.Name, grpcProtocol.Version, grpcProtocol.Abbreviation): &grpcProtocol,
|
grpcProtocol.ToString(): &grpcProtocol,
|
||||||
fmt.Sprintf("%s/%s/%s", graphQL1Protocol.Name, graphQL1Protocol.Version, graphQL1Protocol.Abbreviation): &graphQL1Protocol,
|
graphQL1Protocol.ToString(): &graphQL1Protocol,
|
||||||
fmt.Sprintf("%s/%s/%s", graphQL2Protocol.Name, graphQL2Protocol.Version, graphQL2Protocol.Abbreviation): &graphQL2Protocol,
|
graphQL2Protocol.ToString(): &graphQL2Protocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -294,8 +306,8 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
ProtocolId: fmt.Sprintf("%s/%s/%s", item.Protocol.Name, item.Protocol.Version, item.Protocol.Abbreviation),
|
Protocol: item.Protocol.ProtocolSummary,
|
||||||
Capture: item.Capture,
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -328,7 +340,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
|
|
||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: *protocolsMap[entry.ProtocolId],
|
Protocol: *protocolsMap[entry.Protocol.ToString()],
|
||||||
Capture: entry.Capture,
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
@@ -515,10 +527,10 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`http`: fmt.Sprintf(`protocol == "%s/%s/%s" or protocol == "%s/%s/%s"`, http10protocol.Name, http10protocol.Version, http10protocol.Abbreviation, http11protocol.Name, http11protocol.Version, http11protocol.Abbreviation),
|
`http`: fmt.Sprintf(`protocol.abbr == "%s"`, http11protocol.Abbreviation),
|
||||||
`http2`: fmt.Sprintf(`protocol == "%s/%s/%s"`, http2Protocol.Name, http2Protocol.Version, http2Protocol.Abbreviation),
|
`http2`: fmt.Sprintf(`protocol.abbr == "%s"`, http2Protocol.Abbreviation),
|
||||||
`grpc`: fmt.Sprintf(`protocol == "%s/%s/%s"`, grpcProtocol.Name, grpcProtocol.Version, grpcProtocol.Abbreviation),
|
`grpc`: fmt.Sprintf(`protocol.abbr == "%s"`, grpcProtocol.Abbreviation),
|
||||||
`gql`: fmt.Sprintf(`protocol == "%s/%s/%s" or protocol == "%s/%s/%s"`, graphQL1Protocol.Name, graphQL1Protocol.Version, graphQL1Protocol.Abbreviation, graphQL2Protocol.Name, graphQL2Protocol.Version, graphQL2Protocol.Abbreviation),
|
`gql`: fmt.Sprintf(`protocol.abbr == "%s"`, graphQL1Protocol.Abbreviation),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ func TestRegister(t *testing.T) {
|
|||||||
|
|
||||||
func TestMacros(t *testing.T) {
|
func TestMacros(t *testing.T) {
|
||||||
expectedMacros := map[string]string{
|
expectedMacros := map[string]string{
|
||||||
"http": `protocol == "http/1.0/HTTP" or protocol == "http/1.1/HTTP"`,
|
"http": `protocol.abbr == "HTTP"`,
|
||||||
"http2": `protocol == "http/2.0/HTTP/2"`,
|
"http2": `protocol.abbr == "HTTP/2"`,
|
||||||
"grpc": `protocol == "http/2.0/gRPC"`,
|
"grpc": `protocol.abbr == "gRPC"`,
|
||||||
"gql": `protocol == "http/1.1/GQL" or protocol == "http/2.0/GQL"`,
|
"gql": `protocol.abbr == "GQL"`,
|
||||||
}
|
}
|
||||||
dissector := NewDissector()
|
dissector := NewDissector()
|
||||||
macros := dissector.Macros()
|
macros := dissector.Macros()
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect14/kafka/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect15/kafka/\* expect
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var _protocol = api.Protocol{
|
var _protocol = api.Protocol{
|
||||||
Name: "kafka",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "kafka",
|
||||||
|
Version: "12",
|
||||||
|
Abbreviation: "KAFKA",
|
||||||
|
},
|
||||||
LongName: "Apache Kafka Protocol",
|
LongName: "Apache Kafka Protocol",
|
||||||
Abbreviation: "KAFKA",
|
|
||||||
Macro: "kafka",
|
Macro: "kafka",
|
||||||
Version: "12",
|
|
||||||
BackgroundColor: "#000000",
|
BackgroundColor: "#000000",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 11,
|
FontSize: 11,
|
||||||
@@ -25,7 +27,7 @@ var _protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var protocolsMap = map[string]*api.Protocol{
|
var protocolsMap = map[string]*api.Protocol{
|
||||||
fmt.Sprintf("%s/%s/%s", _protocol.Name, _protocol.Version, _protocol.Abbreviation): &_protocol,
|
_protocol.ToString(): &_protocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
type dissecting string
|
type dissecting string
|
||||||
@@ -70,8 +72,8 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
elapsedTime = 0
|
elapsedTime = 0
|
||||||
}
|
}
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
ProtocolId: fmt.Sprintf("%s/%s/%s", _protocol.Name, _protocol.Version, _protocol.Abbreviation),
|
Protocol: _protocol.ProtocolSummary,
|
||||||
Capture: item.Capture,
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -195,7 +197,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
|
|
||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: *protocolsMap[entry.ProtocolId],
|
Protocol: *protocolsMap[entry.Protocol.ToString()],
|
||||||
Capture: entry.Capture,
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
@@ -250,7 +252,7 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`kafka`: fmt.Sprintf(`protocol == "%s/%s/%s"`, _protocol.Name, _protocol.Version, _protocol.Abbreviation),
|
`kafka`: fmt.Sprintf(`protocol.name == "%s"`, _protocol.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func TestRegister(t *testing.T) {
|
|||||||
|
|
||||||
func TestMacros(t *testing.T) {
|
func TestMacros(t *testing.T) {
|
||||||
expectedMacros := map[string]string{
|
expectedMacros := map[string]string{
|
||||||
"kafka": `protocol == "kafka/12/KAFKA"`,
|
"kafka": `protocol.name == "kafka"`,
|
||||||
}
|
}
|
||||||
dissector := NewDissector()
|
dissector := NewDissector()
|
||||||
macros := dissector.Macros()
|
macros := dissector.Macros()
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect14/redis/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect15/redis/\* expect
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var protocol = api.Protocol{
|
var protocol = api.Protocol{
|
||||||
Name: "redis",
|
ProtocolSummary: api.ProtocolSummary{
|
||||||
|
Name: "redis",
|
||||||
|
Version: "3.x",
|
||||||
|
Abbreviation: "REDIS",
|
||||||
|
},
|
||||||
LongName: "Redis Serialization Protocol",
|
LongName: "Redis Serialization Protocol",
|
||||||
Abbreviation: "REDIS",
|
|
||||||
Macro: "redis",
|
Macro: "redis",
|
||||||
Version: "3.x",
|
|
||||||
BackgroundColor: "#a41e11",
|
BackgroundColor: "#a41e11",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 11,
|
FontSize: 11,
|
||||||
@@ -25,7 +27,7 @@ var protocol = api.Protocol{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var protocolsMap = map[string]*api.Protocol{
|
var protocolsMap = map[string]*api.Protocol{
|
||||||
fmt.Sprintf("%s/%s/%s", protocol.Name, protocol.Version, protocol.Abbreviation): &protocol,
|
protocol.ToString(): &protocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
type dissecting string
|
type dissecting string
|
||||||
@@ -78,8 +80,8 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
elapsedTime = 0
|
elapsedTime = 0
|
||||||
}
|
}
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
ProtocolId: fmt.Sprintf("%s/%s/%s", protocol.Name, protocol.Version, protocol.Abbreviation),
|
Protocol: protocol.ProtocolSummary,
|
||||||
Capture: item.Capture,
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -123,7 +125,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
|
|
||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: *protocolsMap[entry.ProtocolId],
|
Protocol: *protocolsMap[entry.Protocol.ToString()],
|
||||||
Capture: entry.Capture,
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
@@ -151,7 +153,7 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`redis`: fmt.Sprintf(`protocol == "%s/%s/%s"`, protocol.Name, protocol.Version, protocol.Abbreviation),
|
`redis`: fmt.Sprintf(`protocol.name == "%s"`, protocol.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func TestRegister(t *testing.T) {
|
|||||||
|
|
||||||
func TestMacros(t *testing.T) {
|
func TestMacros(t *testing.T) {
|
||||||
expectedMacros := map[string]string{
|
expectedMacros := map[string]string{
|
||||||
"redis": `protocol == "redis/3.x/REDIS"`,
|
"redis": `protocol.name == "redis"`,
|
||||||
}
|
}
|
||||||
dissector := NewDissector()
|
dissector := NewDissector()
|
||||||
macros := dissector.Macros()
|
macros := dissector.Macros()
|
||||||
|
|||||||
@@ -2,3 +2,7 @@
|
|||||||
width: 100%
|
width: 100%
|
||||||
display: flex
|
display: flex
|
||||||
justify-content: center
|
justify-content: center
|
||||||
|
|
||||||
|
.axisText
|
||||||
|
font-size: 12px
|
||||||
|
opacity: 0.9
|
||||||
|
|||||||
@@ -21,14 +21,14 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
|||||||
const [protocolsNamesAndColors, setProtocolsNamesAndColors] = useState([]);
|
const [protocolsNamesAndColors, setProtocolsNamesAndColors] = useState([]);
|
||||||
const [methodsStats, setMethodsStats] = useState(null);
|
const [methodsStats, setMethodsStats] = useState(null);
|
||||||
const [methodsNamesAndColors, setMethodsNamesAndColors] = useState(null);
|
const [methodsNamesAndColors, setMethodsNamesAndColors] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
const protocolsBarsData = [];
|
const protocolsBarsData = [];
|
||||||
const prtcNames = [];
|
const prtcNames = [];
|
||||||
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
||||||
let newProtocolObj: { [k: string]: any } = {};
|
let newProtocolObj: { [k: string]: any } = {};
|
||||||
newProtocolObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
newProtocolObj.timestamp = Utils.formatDate(protocolObj.timestamp);
|
||||||
protocolObj.protocols.forEach(protocol => {
|
protocolObj.protocols.forEach(protocol => {
|
||||||
newProtocolObj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]];
|
newProtocolObj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]];
|
||||||
prtcNames.push({ name: protocol.name, color: protocol.color });
|
prtcNames.push({ name: protocol.name, color: protocol.color });
|
||||||
@@ -50,10 +50,10 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
|||||||
const protocolsMethods = [];
|
const protocolsMethods = [];
|
||||||
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
||||||
let newMethodObj: { [k: string]: any } = {};
|
let newMethodObj: { [k: string]: any } = {};
|
||||||
newMethodObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
newMethodObj.timestamp = Utils.formatDate(protocolObj.timestamp);
|
||||||
protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(method => {
|
protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(method => {
|
||||||
newMethodObj[`${method.name}`] = method[StatsMode[timeLineBarChartMode]]
|
newMethodObj[`${method.name}`] = method[StatsMode[timeLineBarChartMode]]
|
||||||
protocolsMethodsNamesAndColors.push({name: method.name, color: method.color});
|
protocolsMethodsNamesAndColors.push({ name: method.name, color: method.color });
|
||||||
})
|
})
|
||||||
protocolsMethods.push(newMethodObj);
|
protocolsMethods.push(newMethodObj);
|
||||||
})
|
})
|
||||||
@@ -68,17 +68,13 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
|||||||
|
|
||||||
const renderTick = (tickProps) => {
|
const renderTick = (tickProps) => {
|
||||||
const { x, y, payload } = tickProps;
|
const { x, y, payload } = tickProps;
|
||||||
const { index, value } = payload;
|
const { offset, value } = payload;
|
||||||
|
const pathX = Math.floor(x - offset) + 0.5;
|
||||||
|
|
||||||
if (protocolStats.length > 5) {
|
return <React.Fragment>
|
||||||
if (index % 3 === 0) {
|
<text x={pathX} y={y + 10} textAnchor="middle" className={styles.axisText}>{`${value}`}</text>;
|
||||||
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
|
<path d={`M${pathX},${y - 4}v${-10}`} stroke="red" />;
|
||||||
}
|
</React.Fragment>
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -95,8 +91,8 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
|||||||
bottom: 5
|
bottom: 5
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<XAxis dataKey="timestamp" tick={renderTick} tickLine={false} interval="preserveStart" />
|
<XAxis dataKey="timestamp" tickLine={false} tick={renderTick} interval="preserveStart"/>
|
||||||
<YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} interval="preserveEnd"/>
|
<YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} interval="preserveEnd" />
|
||||||
<Tooltip formatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value + " Requests"} />
|
<Tooltip formatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value + " Requests"} />
|
||||||
{bars}
|
{bars}
|
||||||
</BarChart>}
|
</BarChart>}
|
||||||
|
|||||||
@@ -37,6 +37,20 @@ export class Utils {
|
|||||||
return hoursAndMinutes;
|
return hoursAndMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static formatDate = (date) => {
|
||||||
|
let d = new Date(date),
|
||||||
|
month = '' + (d.getMonth() + 1),
|
||||||
|
day = '' + d.getDate(),
|
||||||
|
year = d.getFullYear();
|
||||||
|
const hoursAndMinutes = Utils.getHoursAndMinutes(date);
|
||||||
|
if (month.length < 2)
|
||||||
|
month = '0' + month;
|
||||||
|
if (day.length < 2)
|
||||||
|
day = '0' + day;
|
||||||
|
const newDate = [year, month, day].join('-');
|
||||||
|
return [hoursAndMinutes, newDate].join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
static creatUniqueObjArrayByProp = (objArray, prop) => {
|
static creatUniqueObjArrayByProp = (objArray, prop) => {
|
||||||
const map = new Map(objArray.map((item) => [item[prop], item])).values()
|
const map = new Map(objArray.map((item) => [item[prop], item])).values()
|
||||||
return Array.from(map);
|
return Array.from(map);
|
||||||
|
|||||||
Reference in New Issue
Block a user