Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First implementation of React UI #25

Merged
merged 53 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
4ab80fc
React UI test implementation
dvovk Aug 31, 2023
b1fac46
added http as rest.port
mh0lt Aug 31, 2023
edbbc1d
added rest.port (http)
mh0lt Aug 31, 2023
15650c3
add _bin to gitignore
mh0lt Aug 31, 2023
99139d6
_bin as dir
mh0lt Aug 31, 2023
2ee0915
mrg
dvovk Aug 31, 2023
b99949a
added simple serving react app
dvovk Sep 3, 2023
45108e1
added browser open on start
dvovk Sep 4, 2023
b57a906
fixed build issue
dvovk Sep 4, 2023
8f90898
updated routing to be node and rest based
mh0lt Sep 6, 2023
f33ae1c
merging
dvovk Sep 7, 2023
df37b96
merged
dvovk Sep 7, 2023
0fac916
merging
dvovk Sep 7, 2023
4742cfe
updated FE build
dvovk Sep 7, 2023
18b0f59
removed log file
dvovk Sep 7, 2023
71b601f
added cmdline and flags supports
mh0lt Sep 7, 2023
235f393
Merge branch 'test_react_ui' of https://github.com/ledgerwatch/diagno…
mh0lt Sep 7, 2023
d69b060
fix merge type changes
mh0lt Sep 7, 2023
dc0b0da
added log processing updates
mh0lt Sep 10, 2023
eacc804
Added lock to request inc
mh0lt Sep 11, 2023
7b9f2fa
updated FE
dvovk Sep 11, 2023
1a469f2
added logs displaying
dvovk Sep 11, 2023
cbb5374
add lock
mh0lt Sep 11, 2023
5b18978
fixed json unmarshal breaks
mh0lt Sep 11, 2023
6bad72e
updated FE
dvovk Sep 12, 2023
bcda174
added db and sync stages support
mh0lt Sep 12, 2023
b5d2d94
Merge branch 'test_react_ui' of https://github.com/ledgerwatch/diagno…
mh0lt Sep 12, 2023
bf75366
move base64 decode to unmarshal
mh0lt Sep 13, 2023
abec8fd
updated UI
dvovk Sep 13, 2023
f29979c
updated FE
dvovk Sep 14, 2023
0329bc7
updated endpoints
mh0lt Sep 15, 2023
b02722b
Merge branch 'test_react_ui' of https://github.com/ledgerwatch/diagno…
mh0lt Sep 15, 2023
e333c14
fixed query sync stages param to be base64url encoded
dvovk Sep 16, 2023
96bfa30
updated build and documentation
dvovk Sep 18, 2023
1ce9185
added find reorgs to REST API
dvovk Sep 24, 2023
f460a9a
added fetching active peers
dvovk Sep 26, 2023
e4c3659
added bootnodes query
dvovk Oct 2, 2023
e2d7eab
added diagnostics connection diagram
dvovk Oct 7, 2023
0fab1d0
updated documentation: updated, images, added network tab descrription
dvovk Oct 8, 2023
121c99a
changed peer data structure
dvovk Oct 13, 2023
1abd447
updated UI, updated peer diagnostics data structure
dvovk Oct 24, 2023
8e4f46d
updated UII
dvovk Oct 26, 2023
0ae9989
updated UI
dvovk Oct 29, 2023
b14cfd1
updated UI
dvovk Oct 29, 2023
ed6fe62
updated readme
dvovk Oct 29, 2023
d7b0302
updated UI
dvovk Oct 29, 2023
909acca
added handling subpaths for FE
dvovk Oct 29, 2023
b97da35
fix tests
dvovk Oct 31, 2023
b70b3de
fixed lint errors
dvovk Oct 31, 2023
12dbdc9
commented unused funcs
dvovk Nov 1, 2023
2392c21
fixed lint errors
dvovk Nov 1, 2023
d8660cd
commented tests
dvovk Nov 2, 2023
f258bd9
removed redundant tests
dvovk Nov 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,21 @@


# IDE configuration
.idea
.idea

# misc
.DS_Store
.vscode

*.log

_bin/

go.work*

# temp testing
hive/

*__debug_bin*
yarn.lock
node_modules
212 changes: 145 additions & 67 deletions README.md

Large diffs are not rendered by default.

Binary file removed _images/cmd_line.png
Binary file not shown.
Binary file modified _images/create_new_session.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/create_session_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/create_session_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/create_session_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/dbs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/diagnostics-connection-anim.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed _images/flags.png
Binary file not shown.
Binary file modified _images/logs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/peer_details.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/peers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/process/cmd_line.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/process/find_reorgs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/process/flags.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/process/node_info.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/process/sync_stages.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/statusbar/nodes_popup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/statusbar/sessions_popup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/statusbar/status_bar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/statusbar/status_bar_nodes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _images/statusbar/status_bar_sessions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed _images/sync_stages.png
Binary file not shown.
Binary file removed _images/versions.png
Binary file not shown.
202 changes: 114 additions & 88 deletions api/bridge_handler.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package api

import (
"bytes"
"context"
"encoding/binary"
"encoding/json"
"fmt"
"log"
"net/http"
"sync"

"github.com/go-chi/chi/v5"
"github.com/ledgerwatch/diagnostics"
"github.com/ledgerwatch/diagnostics/api/internal"
"github.com/ledgerwatch/diagnostics/internal/erigon_node"
"github.com/ledgerwatch/diagnostics/internal/sessions"
"github.com/pkg/errors"
"io"
"log"
"net/http"
)

var _ http.Handler = &UIHandler{}
Expand All @@ -23,112 +24,137 @@ type BridgeHandler struct {
}

func (h BridgeHandler) Bridge(w http.ResponseWriter, r *http.Request) {
pin, err := retrievePinFromURL(r)
if err != nil {
http.Error(w, "Error parsing session PIN", http.StatusBadRequest)
}

nodeSession, ok := h.cache.FindNodeSession(pin)
if !ok {
log.Printf("Session with specified PIN %d not found\n", pin)
internal.EncodeError(w, r, diagnostics.AsBadRequestErr(errors.Errorf("Session with specified PIN %d not found", pin)))
return
}

//Sends a success Message to the Node client, to receive more information
flusher, _ := w.(http.Flusher)
fmt.Fprintf(w, "SUCCESS\n")
ctx, cancel := context.WithCancel(r.Context())
defer cancel()
defer r.Body.Close()

nodeSession.Connect(r.RemoteAddr)
defer nodeSession.Disconnect()

// Update the request context with the connection context.
// If the connection is closed by the server, it will also notify everything that waits on the request context.
*r = *r.WithContext(ctx)

w.WriteHeader(http.StatusOK)
flusher.Flush()

var versionBytes [8]byte
if _, err := io.ReadFull(r.Body, versionBytes[:]); err != nil {
log.Printf("Error reading version bytes: %v\n", err)
internal.EncodeError(w, r, diagnostics.AsBadRequestErr(errors.Errorf("Error reading version bytes: %v", err)))
connectionInfo := struct {
Version uint64 `json:"version"`
Sessions []string `json:"sessions"`
Nodes []*sessions.NodeInfo `json:"nodes"`
}{}

err := json.NewDecoder(r.Body).Decode(&connectionInfo)

if err != nil {
log.Printf("Error reading connection info: %v\n", err)
internal.EncodeError(w, r, diagnostics.AsBadRequestErr(errors.Errorf("Error reading connection info: %v", err)))
return
}

nodeSession.SupportVersion = binary.BigEndian.Uint64(versionBytes[:])

// Read data from the request body
var writeBuf bytes.Buffer
for request := range nodeSession.RequestCh {
request.Lock.Lock()
url := request.Url
request.Lock.Unlock()
log.Printf("Sending request %s\n", url)
writeBuf.Reset()
fmt.Fprint(&writeBuf, url)
if _, err := w.Write(writeBuf.Bytes()); err != nil {
log.Printf("Writing metrics request: %v\n", err)
request.Lock.Lock()
request.Served = true
request.Response = nil
request.Err = fmt.Sprintf("writing metrics request: %v", err)
request.Retries++
if request.Retries < 15 {
select {
case nodeSession.RequestCh <- request:
default:
}
requestMap := map[string]*erigon_node.NodeRequest{}
requestMutex := sync.Mutex{}

for _, node := range connectionInfo.Nodes {
nodeSession, ok := h.cache.FindNodeSession(node.Id)

if !ok {
nodeSession, err = h.cache.CreateNodeSession(node)

if err != nil {
log.Printf("Error creating node session: %v\n", err)
internal.EncodeError(w, r, diagnostics.AsBadRequestErr(fmt.Errorf("error creating node session: %w", err)))
return

}
request.Lock.Unlock()
return
}
flusher.Flush()
// Read the response
var sizeBuf [4]byte
if _, err := io.ReadFull(r.Body, sizeBuf[:]); err != nil {
log.Printf("Reading size of metrics response: %v\n", err)
request.Lock.Lock()
request.Served = true
request.Response = nil
request.Err = fmt.Sprintf("reading size of metrics response: %v", err)
request.Retries++
if request.Retries < 15 {
select {
case nodeSession.RequestCh <- request:
default:

nodeSession.AttachSessions(connectionInfo.Sessions)

nodeSession.Connect(r.RemoteAddr)

go func() {
defer nodeSession.Disconnect()

for request := range nodeSession.RequestCh {
rpcRequest := request.Request

bytes, err := json.Marshal(rpcRequest)

if err != nil {
request.Responses <- &erigon_node.Response{
Last: true,
Error: &erigon_node.Error{
Message: fmt.Errorf("failed to marshal request: %w", err).Error(),
},
}
continue
}
}
request.Lock.Unlock()
return
}
metricsBuf := make([]byte, binary.BigEndian.Uint32(sizeBuf[:]))
if _, err := io.ReadFull(r.Body, metricsBuf); err != nil {
log.Printf("Reading metrics response: %v\n", err)
request.Lock.Lock()
request.Served = true
request.Response = nil
request.Err = fmt.Sprintf("reading metrics response: %v", err)
request.Retries++
if request.Retries < 15 {
select {
case nodeSession.RequestCh <- request:
default:

//fmt.Printf("Sending request %s\n", string(bytes))

requestMutex.Lock()
requestMap[rpcRequest.Id] = request
requestMutex.Unlock()

if _, err := w.Write(bytes); err != nil {
requestMutex.Lock()
delete(requestMap, rpcRequest.Id)
requestMutex.Unlock()

fmt.Println(request.Retries, err)
request.Retries++
if request.Retries < 15 {
select {
case nodeSession.RequestCh <- request:
default:
}
} else {
request.Responses <- &erigon_node.Response{
Last: true,
Error: &erigon_node.Error{
Message: fmt.Errorf("failed to write metrics request: %w", err).Error(),
},
}
}
continue
}

flusher.Flush()
}
request.Lock.Unlock()
return
}
request.Lock.Lock()
request.Served = true
request.Response = metricsBuf
request.Err = ""
request.Lock.Unlock()
}()
}

decoder := json.NewDecoder(r.Body)

for {
var response erigon_node.Response

if err = decoder.Decode(&response); err != nil {
fmt.Printf("can't read response: %v\n", err)
continue
}

requestMutex.Lock()
request, ok := requestMap[response.Id]
requestMutex.Unlock()

if !ok {
continue
}

if response.Error != nil {
response.Last = true
}

request.Responses <- &response

if response.Last {
requestMutex.Lock()
delete(requestMap, response.Id)
requestMutex.Unlock()
}
}
}

func NewBridgeHandler(cacheSvc sessions.CacheService) BridgeHandler {
Expand All @@ -137,7 +163,7 @@ func NewBridgeHandler(cacheSvc sessions.CacheService) BridgeHandler {
cache: cacheSvc,
}

r.Post("/{pin}", r.Bridge)
r.Post("/", r.Bridge)

return *r
}
38 changes: 16 additions & 22 deletions api/helpers.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
package api

import (
"fmt"
"log"
"net/http"
"net/url"
"path"
"strconv"
)

func retrievePinFromURL(r *http.Request) (uint64, error) {
parsedURL, err := url.Parse(r.URL.Path)
if err != nil {
log.Println("Error parsing URL:", err)
return 0, fmt.Errorf("Error parsing URL: %w", err)
/*func retrievePinFromURL(r *http.Request) (pins []uint64, err error) {

for _, session := range strings.Split(r.URL.Query().Get("sessions"), ",") {
pin, err := strconv.ParseUint(session, 10, 64)

if err != nil {
log.Printf("Error parsing session pin %s: %v\n", session, err)
return pins, fmt.Errorf("error parsing session pin %s: %w", session, err)
}

pins = append(pins, pin)
}

lastPathItem := path.Base(parsedURL.Path)
pin, err := strconv.ParseUint(lastPathItem, 10, 64)
if err != nil {
log.Printf("Error parsing session pin %s: %v\n", lastPathItem, err)
return 0, fmt.Errorf("Error parsing session pin %s: %w", lastPathItem, err)
if len(pins) == 0 {
err = fmt.Errorf("no sessions")
}

return pin, nil
return pins, err
}

func retrieveSizeStrFrom(r *http.Request) (uint64, error) {
sizeStr := r.Form.Get("size")
size, err := strconv.ParseUint(sizeStr, 10, 64)
if err != nil {
return 0, fmt.Errorf("Parsing size %s: %w", sizeStr, err)
return 0, fmt.Errorf("parsing size %s: %w", sizeStr, err)
}

var offset uint64
Expand All @@ -39,4 +33,4 @@ func retrieveSizeStrFrom(r *http.Request) (uint64, error) {
}

return offset, nil
}
}*/
4 changes: 1 addition & 3 deletions api/internal/end_points.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@ package internal

const (
HealthCheckEndPoint = "/healthcheck"
UIEndPoint = "/ui"
ScriptEndPoint = "/script"
SupportEndPoint = "/support"
BridgeEndPoint = "/bridge"
)
5 changes: 3 additions & 2 deletions api/internal/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package internal

import (
"encoding/json"
"github.com/ledgerwatch/diagnostics"
"net/http"

"github.com/ledgerwatch/diagnostics"
)

type Error struct {
Expand All @@ -24,7 +25,7 @@ func marshalError(r *http.Request, err error) Error {

} else {
code = http.StatusInternalServerError
message = "internal server error"
message = err.Error()
}

return Error{
Expand Down
Loading