Skip to content

Commit

Permalink
Merge pull request #18 from pk910/live-frontpage
Browse files Browse the repository at this point in the history
Live frontpage
  • Loading branch information
pk910 authored Sep 8, 2023
2 parents f6b289f + 461aa26 commit 95e1586
Show file tree
Hide file tree
Showing 28 changed files with 603 additions and 127 deletions.
2 changes: 2 additions & 0 deletions cmd/explorer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ func startFrontend() {
router := mux.NewRouter()

router.HandleFunc("/", handlers.Index).Methods("GET")
router.HandleFunc("/index", handlers.Index).Methods("GET")
router.HandleFunc("/index/data", handlers.IndexData).Methods("GET")
router.HandleFunc("/clients", handlers.Clients).Methods("GET")
router.HandleFunc("/epochs", handlers.Epochs).Methods("GET")
router.HandleFunc("/epoch/{epoch}", handlers.Epoch).Methods("GET")
Expand Down
2 changes: 1 addition & 1 deletion handlers/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func getClientsPageData() *models.ClientsPageData {
}

func buildClientsPageData() (*models.ClientsPageData, time.Duration) {
logrus.Printf("clients page called")
logrus.Debugf("clients page called")
pageData := &models.ClientsPageData{
Clients: []*models.ClientsPageDataClient{},
}
Expand Down
2 changes: 1 addition & 1 deletion handlers/epoch.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func getEpochPageData(epoch uint64) *models.EpochPageData {
}

func buildEpochPageData(epoch uint64) (*models.EpochPageData, time.Duration) {
logrus.Printf("epoch page called: %v", epoch)
logrus.Debugf("epoch page called: %v", epoch)

now := time.Now()
currentSlot := utils.TimeToSlot(uint64(now.Unix()))
Expand Down
2 changes: 1 addition & 1 deletion handlers/epochs.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func getEpochsPageData(firstEpoch uint64, pageSize uint64) *models.EpochsPageDat
}

func buildEpochsPageData(firstEpoch uint64, pageSize uint64) (*models.EpochsPageData, time.Duration) {
logrus.Printf("epochs page called: %v:%v", firstEpoch, pageSize)
logrus.Debugf("epochs page called: %v:%v", firstEpoch, pageSize)
pageData := &models.EpochsPageData{}

now := time.Now()
Expand Down
22 changes: 18 additions & 4 deletions handlers/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package handlers

import (
"bytes"
"encoding/json"
"fmt"
"math"
"net/http"
"net/url"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -39,6 +42,16 @@ func Index(w http.ResponseWriter, r *http.Request) {
}
}

func IndexData(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
pageData := getIndexPageData()
err := json.NewEncoder(w).Encode(pageData)
if err != nil {
logrus.WithError(err).Error("error encoding index data")
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
}
}

func getIndexPageData() *models.IndexPageData {
pageData := &models.IndexPageData{}
pageCacheKey := "index"
Expand All @@ -51,7 +64,7 @@ func getIndexPageData() *models.IndexPageData {
}

func buildIndexPageData() (*models.IndexPageData, time.Duration) {
logrus.Printf("index page called")
logrus.Debugf("index page called")

recentEpochCount := 7
recentBlockCount := 7
Expand Down Expand Up @@ -81,10 +94,10 @@ func buildIndexPageData() (*models.IndexPageData, time.Duration) {
NetworkName: utils.Config.Chain.Name,
DepositContract: utils.Config.Chain.Config.DepositContractAddress,
ShowSyncingMessage: !isSynced,
SlotsPerEpoch: utils.Config.Chain.Config.SlotsPerEpoch,
CurrentEpoch: uint64(currentEpoch),
CurrentFinalizedEpoch: finalizedEpoch,
CurrentSlot: currentSlot,
CurrentSlotIndex: currentSlotIndex,
CurrentScheduledCount: utils.Config.Chain.Config.SlotsPerEpoch - currentSlotIndex,
CurrentEpochProgress: float64(100) * float64(currentSlotIndex) / float64(utils.Config.Chain.Config.SlotsPerEpoch),
}
Expand Down Expand Up @@ -191,8 +204,6 @@ func buildIndexPageRecentEpochsData(pageData *models.IndexPageData, currentEpoch
Finalized: finalizedEpoch >= int64(epochData.Epoch),
EligibleEther: epochData.Eligible,
TargetVoted: epochData.VotedTarget,
HeadVoted: epochData.VotedHead,
TotalVoted: epochData.VotedTotal,
VoteParticipation: voteParticipation,
})
}
Expand Down Expand Up @@ -223,6 +234,9 @@ func buildIndexPageRecentBlocksData(pageData *models.IndexPageData, currentSlot
if blockData.EthBlockNumber != nil {
blockModel.WithEthBlock = true
blockModel.EthBlock = *blockData.EthBlockNumber
if utils.Config.Frontend.EthExplorerLink != "" {
blockModel.EthBlockLink, _ = url.JoinPath(utils.Config.Frontend.EthExplorerLink, "block", strconv.FormatUint(blockModel.EthBlock, 10))
}
}
pageData.RecentBlocks = append(pageData.RecentBlocks, blockModel)
}
Expand Down
2 changes: 1 addition & 1 deletion handlers/slot.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func buildSlotPageData(blockSlot int64, blockRoot []byte, loadDuties bool) (*mod
} else {
return nil, -1
}
logrus.Printf("slot page called: %v", slot)
logrus.Debugf("slot page called: %v", slot)

pageData := &models.SlotPageData{
Slot: slot,
Expand Down
2 changes: 1 addition & 1 deletion handlers/slots.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func getSlotsPageData(firstSlot uint64, pageSize uint64) *models.SlotsPageData {
}

func buildSlotsPageData(firstSlot uint64, pageSize uint64) (*models.SlotsPageData, time.Duration) {
logrus.Printf("slots page called: %v:%v", firstSlot, pageSize)
logrus.Debugf("slots page called: %v:%v", firstSlot, pageSize)
pageData := &models.SlotsPageData{}

now := time.Now()
Expand Down
2 changes: 1 addition & 1 deletion handlers/slots_filtered.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func buildFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string
FilterWithOrphaned: withOrphaned,
FilterWithMissing: withMissing,
}
logrus.Printf("slots_filtered page called: %v:%v [%v]", pageIdx, pageSize, graffiti)
logrus.Debugf("slots_filtered page called: %v:%v [%v]", pageIdx, pageSize, graffiti)
if pageIdx == 0 {
pageData.IsDefaultPage = true
}
Expand Down
2 changes: 1 addition & 1 deletion handlers/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func getValidatorPageData(validatorIndex uint64) *models.ValidatorPageData {
}

func buildValidatorPageData(validatorIndex uint64) (*models.ValidatorPageData, time.Duration) {
logrus.Printf("validator page called: %v", validatorIndex)
logrus.Debugf("validator page called: %v", validatorIndex)

validatorSetRsp := services.GlobalBeaconService.GetCachedValidatorSet()
validator := validatorSetRsp.Data[validatorIndex]
Expand Down
2 changes: 1 addition & 1 deletion handlers/validator_slots.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func buildValidatorSlotsPageData(validator uint64, pageIdx uint64, pageSize uint
Index: validator,
Name: services.GlobalBeaconService.GetValidatorName(validator),
}
logrus.Printf("validator slots page called (%v): %v:%v", validator, pageIdx, pageSize)
logrus.Debugf("validator slots page called (%v): %v:%v", validator, pageIdx, pageSize)
if pageIdx == 0 {
pageData.IsDefaultPage = true
}
Expand Down
2 changes: 1 addition & 1 deletion handlers/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func getValidatorsPageData(firstValIdx uint64, pageSize uint64, sortOrder string
}

func buildValidatorsPageData(firstValIdx uint64, pageSize uint64, sortOrder string, filterPubKey string, filterIndex string, filterName string, filterStatus string) (*models.ValidatorsPageData, time.Duration) {
logrus.Printf("validators page called: %v:%v:%v:%v:%v:%v:%v", firstValIdx, pageSize, sortOrder, filterPubKey, filterIndex, filterName, filterStatus)
logrus.Debugf("validators page called: %v:%v:%v:%v:%v:%v:%v", firstValIdx, pageSize, sortOrder, filterPubKey, filterIndex, filterName, filterStatus)
pageData := &models.ValidatorsPageData{}
cacheTime := 10 * time.Minute

Expand Down
9 changes: 9 additions & 0 deletions indexer/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type indexerCache struct {
epochStatsMap map[uint64][]*EpochStats
lastValidatorsEpoch int64
lastValidatorsResp *rpctypes.StandardV1StateValidatorsResponse
genesisResp *rpctypes.StandardV1GenesisResponse
validatorLoadingLimiter chan int
}

Expand Down Expand Up @@ -79,6 +80,14 @@ func (cache *indexerCache) setFinalizedHead(epoch int64, root []byte) {
}
}

func (cache *indexerCache) setGenesis(genesis *rpctypes.StandardV1GenesisResponse) {
cache.cacheMutex.Lock()
defer cache.cacheMutex.Unlock()
if cache.genesisResp == nil {
cache.genesisResp = genesis
}
}

func (cache *indexerCache) getFinalizedHead() (int64, []byte) {
cache.cacheMutex.RLock()
defer cache.cacheMutex.RUnlock()
Expand Down
1 change: 1 addition & 0 deletions indexer/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ func (client *IndexerClient) checkIndexerClient() error {
if genesis.Data.GenesisForkVersion.String() != utils.Config.Chain.Config.GenesisForkVersion {
return fmt.Errorf("genesis fork version from RPC does not match the genesis fork version explorer configuration")
}
client.indexerCache.setGenesis(genesis)

// check syncronization state
syncStatus, err := client.rpcClient.GetNodeSyncing()
Expand Down
4 changes: 4 additions & 0 deletions indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ func (indexer *Indexer) GetRpcClient(archive bool, head []byte) *rpc.BeaconClien
return readyClient.rpcClient
}

func (indexer *Indexer) GetCachedGenesis() *rpctypes.StandardV1GenesisResponse {
return indexer.indexerCache.genesisResp
}

func (indexer *Indexer) GetFinalizedEpoch() (int64, []byte) {
return indexer.indexerCache.getFinalizedHead()
}
Expand Down
2 changes: 1 addition & 1 deletion services/beaconservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (bs *BeaconService) GetCachedEpochStats(epoch uint64) *indexer.EpochStats {
}

func (bs *BeaconService) GetGenesis() (*rpctypes.StandardV1GenesisResponse, error) {
return bs.indexer.GetRpcClient(false, nil).GetGenesis()
return bs.indexer.GetCachedGenesis(), nil
}

func (bs *BeaconService) GetSlotDetailsByBlockroot(blockroot []byte) (*rpctypes.CombinedBlockResponse, error) {
Expand Down
4 changes: 2 additions & 2 deletions services/frontendcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (fc *FrontendCacheService) ProcessCachedPage(pageKey string, caching bool,
processingPage := fc.processingDict[pageKey]
if processingPage != nil {
fc.processingMutex.Unlock()
logrus.Printf("page already processing: %v", pageKey)
logrus.Debugf("page already processing: %v", pageKey)

processingPage.modelMutex.RLock()
defer processingPage.modelMutex.RUnlock()
Expand Down Expand Up @@ -88,7 +88,7 @@ func (fc *FrontendCacheService) completePageLoad(pageKey string, processingPage
func (fc *FrontendCacheService) processCachedPageData(pageKey string, caching bool, pageData interface{}, buildFn func(pageCall *FrontendCacheProcessingPage) interface{}, pageCall *FrontendCacheProcessingPage) interface{} {
// check cache
if !utils.Config.Frontend.Debug && caching && fc.GetFrontendCache(pageKey, pageData) == nil {
logrus.Printf("page served from cache: %v", pageKey)
logrus.Debugf("page served from cache: %v", pageKey)
return pageData
}

Expand Down
4 changes: 4 additions & 0 deletions static/css/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ header nav .nav-item:focus-within .dropdown-menu {
white-space: nowrap;
}

.table .template-row {
display: none;
}

span.validator-label {
white-space: nowrap;
}
Expand Down
80 changes: 58 additions & 22 deletions static/js/explorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,75 @@
window.setInterval(updateTimers, 1000);
initHeaderSearch();
});
var tooltipDict = {};
var tooltipIdx = 1;
window.explorer = {
initControls: initControls,
renderRecentTime: renderRecentTime,
tooltipDict: tooltipDict,
};

function initControls() {
// init tooltips
var tooltipEls = document.querySelectorAll('[data-bs-toggle="tooltip"]');
Array.prototype.forEach.call(tooltipEls, function(tooltipEl) {
new bootstrap.Tooltip(tooltipEl)
});
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(initTooltip);
cleanupTooltips();

// init clipboard buttons
var clipboard = new ClipboardJS("[data-clipboard-text]");
clipboard.on("success", function (e) {
var title = e.trigger.getAttribute("data-bs-original-title");
var tooltip = bootstrap.Tooltip.getInstance(e.trigger);
tooltip.setContent({ '.tooltip-inner': 'Copied!' });
tooltip.show();
setTimeout(function () {
tooltip.setContent({ '.tooltip-inner': title });
}, 1000);
});
clipboard.on("error", function (e) {
var title = e.trigger.getAttribute("data-bs-original-title");
var tooltip = bootstrap.Tooltip.getInstance(e.trigger);
tooltip.setContent({ '.tooltip-inner': 'Failed to Copy!' });
tooltip.show();
setTimeout(function () {
tooltip.setContent({ '.tooltip-inner': title });
}, 1000);
document.querySelectorAll("[data-clipboard-text]").forEach(initCopyBtn);
}

function initTooltip(el) {
if($(el).data("tooltip-init"))
return;
//console.log("init tooltip", el);
var idx = tooltipIdx++;
$(el).data("tooltip-init", idx).attr("data-tooltip-idx", idx.toString());
$(el).tooltip();
var tooltip = bootstrap.Tooltip.getInstance(el);
tooltipDict[idx] = {
element: el,
tooltip: tooltip,
};
}

function cleanupTooltips() {
Object.keys(explorer.tooltipDict).forEach(function(idx) {
var ref = explorer.tooltipDict[idx];
if(document.body.contains(ref.element)) return;
ref.tooltip.dispose();
delete explorer.tooltipDict[idx];
});
}

function initCopyBtn(el) {
if($(el).data("clipboard-init"))
return;
$(el).data("clipboard-init", true);
var clipboard = new ClipboardJS(el);
clipboard.on("success", onClipboardSuccess);
clipboard.on("error", onClipboardError);
}

function onClipboardSuccess(e) {
var title = e.trigger.getAttribute("data-bs-original-title");
var tooltip = bootstrap.Tooltip.getInstance(e.trigger);
tooltip.setContent({ '.tooltip-inner': 'Copied!' });
tooltip.show();
setTimeout(function () {
tooltip.setContent({ '.tooltip-inner': title });
}, 1000);
}

function onClipboardError(e) {
var title = e.trigger.getAttribute("data-bs-original-title");
var tooltip = bootstrap.Tooltip.getInstance(e.trigger);
tooltip.setContent({ '.tooltip-inner': 'Failed to Copy!' });
tooltip.show();
setTimeout(function () {
tooltip.setContent({ '.tooltip-inner': title });
}, 1000);
}

function updateTimers() {
var timerEls = document.querySelectorAll("[data-timer]");
timerEls.forEach(function(timerEl) {
Expand Down
Loading

0 comments on commit 95e1586

Please sign in to comment.