Skip to content

Commit

Permalink
Merge pull request #7 from Savid/feat/frontend
Browse files Browse the repository at this point in the history
feat: frontend
  • Loading branch information
Savid committed Aug 31, 2022
2 parents 88bfcb3 + 7bc76b2 commit 3697c7b
Show file tree
Hide file tree
Showing 62 changed files with 27,863 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ jobs:
-
name: Set up Go
uses: actions/setup-go@v3
-
name: Set up NodeJS
uses: actions/setup-node@v3
with:
node-version: 18
-
name: Login to DockerHub
uses: docker/login-action@v1
Expand Down
1 change: 1 addition & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ before:
hooks:
- go mod tidy
- go generate ./...
- make build-web
builds:
- env:
- CGO_ENABLED=0
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/app .

FROM ubuntu:latest
FROM ubuntu:latest
RUN apt-get update && apt-get -y upgrade && apt-get install -y --no-install-recommends \
libssl-dev \
ca-certificates \
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ Download the latest release from the [Releases page](https://github.com/samcm/ch
./checkpointz --config your-config.yaml
```

### Frontend

A basic frontend is provided in this project in [`./web`](https://github.com/samcm/checkpointz/blob/master/example_config.yaml) directory which needs to be built before it can be served by the server, eg. `http://localhost:5555`.

The frontend can be built with the following command;
```bash
# install node modules and build
make build-web
```

Building frontend requires `npm` and `NodeJS` to be installed.

### Docker
Available as a docker image at [samcm/checkpointz](https://hub.docker.com/r/samcm/checkpointz/tags)
#### Images
Expand Down
12 changes: 10 additions & 2 deletions example_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@ checkpointz:
states:
max_items: 5
historical_epoch_count: 20
# set public url where checkpointz will be served from
# public_url: https://www.domain.com
frontend:
# if the frontend should served
enabled: false
# brand logo to display on the frontend (optional)
brand_image_url: https://www.cdn.com/logo.png
# brand to display on the frontend (optional)
brand_name: Brandname
# public url where frontend will be served from (optional)
public_url: https://www.domain.com


beacon:
upstreams:
Expand Down
3 changes: 3 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build-web:
@echo "Building web frontend..."
@npm --prefix ./web install && npm --prefix ./web run build
44 changes: 31 additions & 13 deletions pkg/api/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,24 @@ import (
type Handler struct {
log logrus.FieldLogger

eth *eth.Handler
checkpointz *checkpointz.Handler
publicURL string
eth *eth.Handler
checkpointz *checkpointz.Handler
publicURL string
brandName string
brandImageURL string

metrics Metrics
}

func NewHandler(log logrus.FieldLogger, beac beacon.FinalityProvider, publicURL string) *Handler {
func NewHandler(log logrus.FieldLogger, beac beacon.FinalityProvider, config *beacon.Config) *Handler {
return &Handler{
log: log.WithField("module", "api"),

eth: eth.NewHandler(log, beac, "checkpointz"),
checkpointz: checkpointz.NewHandler(log, beac),
publicURL: publicURL,
eth: eth.NewHandler(log, beac, "checkpointz"),
checkpointz: checkpointz.NewHandler(log, beac),
publicURL: config.Frontend.PublicURL,
brandName: config.Frontend.BrandName,
brandImageURL: config.Frontend.BrandImageURL,

metrics: NewMetrics("http"),
}
Expand Down Expand Up @@ -218,12 +222,18 @@ func (h *Handler) handleCheckpointzStatus(ctx context.Context, r *http.Request,
}

status.PublicURL = h.publicURL
status.BrandName = h.brandName
status.BrandImageURL = h.brandImageURL

return NewSuccessResponse(ContentTypeResolvers{
rsp := NewSuccessResponse(ContentTypeResolvers{
ContentTypeJSON: func() ([]byte, error) {
return json.Marshal(status)
},
}), nil
})

rsp.SetCacheControl("public, s-max-age=30")

return rsp, nil
}

func (h *Handler) handleCheckpointzBeaconSlots(ctx context.Context, r *http.Request, p httprouter.Params, contentType ContentType) (*HTTPResponse, error) {
Expand All @@ -236,11 +246,15 @@ func (h *Handler) handleCheckpointzBeaconSlots(ctx context.Context, r *http.Requ
return NewInternalServerErrorResponse(nil), err
}

return NewSuccessResponse(ContentTypeResolvers{
rsp := NewSuccessResponse(ContentTypeResolvers{
ContentTypeJSON: func() ([]byte, error) {
return json.Marshal(slots)
},
}), nil
})

rsp.SetCacheControl("public, s-max-age=30")

return rsp, nil
}

func (h *Handler) handleCheckpointzBeaconSlot(ctx context.Context, r *http.Request, p httprouter.Params, contentType ContentType) (*HTTPResponse, error) {
Expand All @@ -258,11 +272,15 @@ func (h *Handler) handleCheckpointzBeaconSlot(ctx context.Context, r *http.Reque
return NewInternalServerErrorResponse(nil), err
}

return NewSuccessResponse(ContentTypeResolvers{
rsp := NewSuccessResponse(ContentTypeResolvers{
ContentTypeJSON: func() ([]byte, error) {
return json.Marshal(slots)
},
}), nil
})

rsp.SetCacheControl("public, s-max-age=60")

return rsp, nil
}

func (h *Handler) handleEthV1BeaconStatesHeadFinalityCheckpoints(ctx context.Context, r *http.Request, p httprouter.Params, contentType ContentType) (*HTTPResponse, error) {
Expand Down
18 changes: 16 additions & 2 deletions pkg/beacon/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ type Config struct {
// HistoricalEpochCount determines how many historical epochs the provider will cache.
HistoricalEpochCount int `yaml:"historical_epoch_count"`

// PublicURL is the public URL where checkpointz will be served from
PublicURL string `yaml:"public_url"`
// Cache holds configuration for the caches.
Frontend FrontendConfig `yaml:"frontend"`
}

// Cache configuration holds configuration for the caches.
Expand All @@ -27,6 +27,20 @@ type CacheConfig struct {
States store.Config `yaml:"states"`
}

type FrontendConfig struct {
// Enabled flag enables the frontend assets to be served
Enabled bool `yaml:"enabled"`

// PublicURL is the public URL where checkpointz will be served from
PublicURL string `yaml:"public_url"`

// BrandName is the name of the brand to display in the frontend
BrandName string `yaml:"brand_name"`

// BrandImageURL is the URL of the brand image to be displayed on the frontend
BrandImageURL string `yaml:"brand_image_url"`
}

func (c *Config) Validate() error {
if c.HistoricalEpochCount < 1 {
return errors.New("historical_epoch_count must be at least 1")
Expand Down
4 changes: 2 additions & 2 deletions pkg/beacon/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
type Default struct {
log logrus.FieldLogger

config Config
config *Config
nodeConfigs []node.Config
nodes Nodes
broker *emission.Emitter
Expand All @@ -46,7 +46,7 @@ var (
topicFinalityHeadUpdated = "finality_head_updated"
)

func NewDefaultProvider(namespace string, log logrus.FieldLogger, nodes []node.Config, config Config) FinalityProvider {
func NewDefaultProvider(namespace string, log logrus.FieldLogger, nodes []node.Config, config *Config) FinalityProvider {
return &Default{
nodeConfigs: nodes,
log: log.WithField("module", "beacon/default"),
Expand Down
15 changes: 13 additions & 2 deletions pkg/checkpointz/checkpointz.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package checkpointz

import (
"context"
"io/fs"
"net/http"
"time"

"github.com/julienschmidt/httprouter"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/samcm/checkpointz/pkg/api"
"github.com/samcm/checkpointz/pkg/beacon"
static "github.com/samcm/checkpointz/web"
"github.com/sirupsen/logrus"
)

Expand All @@ -34,14 +36,14 @@ func NewServer(log *logrus.Logger, conf *Config) *Server {
namespace,
log,
conf.BeaconConfig.BeaconUpstreams,
conf.Checkpointz,
&conf.Checkpointz,
)

s := &Server{
Cfg: *conf,
log: log,

http: api.NewHandler(log, provider, conf.Checkpointz.PublicURL),
http: api.NewHandler(log, provider, &conf.Checkpointz),

provider: provider,
}
Expand All @@ -58,6 +60,15 @@ func (s *Server) Start(ctx context.Context) error {
return err
}

if s.Cfg.Checkpointz.Frontend.Enabled {
frontend, err := fs.Sub(static.FS, "build/frontend")
if err != nil {
return err
}

router.NotFound = http.FileServer(http.FS(frontend))
}

if err := s.ServeMetrics(ctx); err != nil {
return err
}
Expand Down
8 changes: 5 additions & 3 deletions pkg/service/checkpointz/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import (
)

type StatusResponse struct {
Upstreams map[string]*beacon.UpstreamStatus `json:"upstreams"`
Finality *v1.Finality `json:"finality"`
PublicURL string `json:"public_url,omitempty"`
Upstreams map[string]*beacon.UpstreamStatus `json:"upstreams"`
Finality *v1.Finality `json:"finality"`
PublicURL string `json:"public_url,omitempty"`
BrandName string `json:"brand_name,omitempty"`
BrandImageURL string `json:"brand_image_url,omitempty"`
}

type BeaconSlot struct {
Expand Down
23 changes: 23 additions & 0 deletions web/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build/frontend

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
Empty file added web/build/.gitkeep
Empty file.
Loading

0 comments on commit 3697c7b

Please sign in to comment.