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

feat(explorer/graphql): reading from db #190

Merged
merged 8 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
12 changes: 12 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ builds:
goos: [ linux, darwin ]
goarch: [ amd64, arm64 ]

- id: explorer-graphql
main: ./explorer/graphql
binary: /explorer/graphql
env: [ CGO_ENABLED=0 ]
goos: [ linux, darwin ]
goarch: [ amd64, arm64 ]

- id: explorer-indexer
main: ./explorer/indexer
binary: explorer/indexer
Expand All @@ -47,6 +54,11 @@ dockers:
image_templates:
- omniops/explorer-api:latest

- ids: [explorer-graphql]
dockerfile: ./explorer/graphql/Dockerfile
image_templates:
- omniops/explorer-graphql:latest

- ids: [explorer-indexer]
dockerfile: ./explorer/indexer/Dockerfile
image_templates:
Expand Down
18 changes: 18 additions & 0 deletions explorer/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,21 @@ gen-api: ## generates our openapi.yaml bindings for the api and ui

gen-db: ## generates our ent orm schemas
make -C ./db gen

open-dev: ## opens all of the local host endpoints
python -m webbrowser "http://localhost:3000"
python -m webbrowser "http://localhost:8080"
python -m webbrowser "http://localhost:8081/hello"

build: ## builds our docker images
make -C ../ build-docker

run: ## runs our docker compose up
docker-compose up

stop: ## stops our docker compose
docker-compose down

run-clean: ## docker build and run
make -C ./ build
make -C ./ run
22 changes: 17 additions & 5 deletions explorer/db/ent_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@ type EntServerClient interface {

type ClientImpl struct {
EntServerClient
port int
}

func NewClient(port int) *ClientImpl {
client := ClientImpl{
port: port,
}
func NewClient() *ClientImpl {
client := ClientImpl{}

return &client
}
Expand All @@ -44,6 +41,21 @@ func (ClientImpl) CreateNewEntClient(ctx context.Context, databaseURL string) (*

client := ent.NewClient(ent.Driver(drv))

return client, nil
}

func (ClientImpl) CreateNewEntClientWithSchema(ctx context.Context, databaseURL string) (*ent.Client, error) {
db, err := sql.Open("pgx", databaseURL)
if err != nil {
log.Error(ctx, "Failed to connect to postgres database: %v", err)
return nil, errors.Wrap(err, "failed to open postgres connection")
}

// Create an ent.Driver from `db`.
drv := entsql.OpenDB(dialect.Postgres, db)

client := ent.NewClient(ent.Driver(drv))

if err := client.Schema.Create(ctx); err != nil {
log.Error(ctx, "Failed creating schema resources: %v", err)
return nil, errors.Wrap(err, "failed to do schema creation for postgresql db")
Expand Down
50 changes: 37 additions & 13 deletions explorer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,56 @@ version: '3.9'
services:
db:
image: postgres:14-alpine
ports:
- 5432:5432
volumes:
- ~/apps/postgres:/var/lib/postgresql/data
container_name: omni-db
environment:
- POSTGRES_PASSWORD=omni_secret
- POSTGRES_USER=omni_user
- POSTGRES_DB=omni_db
POSTGRES_DB: omni_db
POSTGRES_USER: omni
POSTGRES_PASSWORD: password
ports: 5432:5432
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U omni -d omni_db" ]
interval: 3s
timeout: 5s
retries: 5
restart: unless-stopped

ui:
build:
context: ./ui
dockerfile: Dockerfile
ports:
expose:
- 3000
ports:
- 3000:3000
depends_on:
- db
db:
condition: service_healthy

api:
image: omniops/explorer-api
ports:
# api:
# image: omniops/explorer-api
# ports:
# - 8000
# depends_on:
# - db

graphql:
image: omniops/explorer-graphql
expose:
- 8080
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
links:
- db

indexer:
image: omniops/explorer-indexer
expose:
- 8081
ports:
- 8081:8081
depends_on:
- db
db:
condition: service_healthy
9 changes: 9 additions & 0 deletions explorer/graphql/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM scratch

COPY explorer/graphql /app

EXPOSE 8080

ENTRYPOINT ["/app"]

CMD ["run"]
2 changes: 2 additions & 0 deletions explorer/graphql/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
help: ## Display this help message.
@egrep -h '\s##\s' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m %-30s\033[0m %s\n", $$1, $$2}'
96 changes: 96 additions & 0 deletions explorer/graphql/app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package app

import (
"context"
"fmt"
"net/http"
"time"

"github.com/omni-network/omni/explorer/db"
"github.com/omni-network/omni/explorer/graphql/data"
"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/log"
)

func Run(ctx context.Context, conf ExplorerGralQLConfig) error {
log.Info(ctx, "Config: %v", conf)
ctx, cancel := context.WithCancel(ctx)

go func() {
// create ent client
entClient := db.NewClient()
client, err := entClient.CreateNewEntClient(ctx, conf.DBUrl)

if err != nil {
log.Error(ctx, "Failed to open ent client", err)
return
}

provider := data.Provider{
EntClient: client,
}

mux := http.NewServeMux()

mux.HandleFunc("/", home)
mux.Handle("/query", GraphQL(provider))

httpServer := &http.Server{
Addr: fmt.Sprintf(":%v", conf.Port),
ReadHeaderTimeout: 30 * time.Second,
IdleTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
Handler: mux,
}

log.Info(ctx, "Starting to serve GraphQL - API on port: %v", httpServer.Addr)

err = httpServer.ListenAndServe()
if errors.Is(err, http.ErrServerClosed) {
log.Info(ctx, "Closed http server @%v", httpServer.Addr)
} else {
log.Error(ctx, "Error listening for %v:", err, conf.Port)
}
cancel()
}()

<-ctx.Done()

return nil
}

func Debug(ctx context.Context, conf ExplorerGralQLConfig) error {
DanFlannel marked this conversation as resolved.
Show resolved Hide resolved
log.Info(ctx, "Config: %v", conf)
ctx, cancel := context.WithCancel(ctx)

go func() {
provider := data.Provider{}

mux := http.NewServeMux()

mux.HandleFunc("/", home)
mux.Handle("/query", GraphQL(provider))

httpServer := &http.Server{
Addr: fmt.Sprintf(":%v", conf.Port),
ReadHeaderTimeout: 30 * time.Second,
IdleTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
Handler: mux,
}

log.Info(ctx, "Starting to serve GraphQL - API on port: %v", httpServer.Addr)

err := httpServer.ListenAndServe()
if errors.Is(err, http.ErrServerClosed) {
log.Info(ctx, "Closed http server @%v", httpServer.Addr)
} else {
log.Error(ctx, "Error listening for %v:", err, conf.Port)
}
cancel()
}()

<-ctx.Done()

return nil
}
18 changes: 18 additions & 0 deletions explorer/graphql/app/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package app

const (
port = 8080
dbURL = "postgres://omni:password@db:5432/omni_db"
)

type ExplorerGralQLConfig struct {
Port int
DBUrl string
}

func DefaultExplorerAPIConfig() ExplorerGralQLConfig {
return ExplorerGralQLConfig{
Port: port,
DBUrl: dbURL,
}
}
43 changes: 43 additions & 0 deletions explorer/graphql/app/graphql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package app

import (
"net/http"

"github.com/omni-network/omni/explorer/graphql/data"
"github.com/omni-network/omni/explorer/graphql/resolvers"
"github.com/omni-network/omni/lib/log"

graphql "github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"

_ "embed"
)

//go:embed graphql.schema
var schema string

//go:embed index.html
var graphiql []byte

func GraphQL(provider data.Provider) http.Handler {
// dummy hard-coded data
br := resolvers.BlocksResolver{
BlocksProvider: provider,
}

opts := []graphql.SchemaOpt{
graphql.UseFieldResolvers(),
graphql.UseStringDescriptions(),
}
s := graphql.MustParseSchema(schema, &resolvers.Query{BlocksResolver: br}, opts...)

return &relay.Handler{Schema: s}
}

func home(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/html; charset=utf-8")
_, err := w.Write(graphiql)
if err != nil {
log.Error(r.Context(), "graphql home err", err)
}
}
65 changes: 65 additions & 0 deletions explorer/graphql/app/graphql.schema
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Msg is a cross-chain message.
"""
type Msg {

"Monotonically incremented offset of Msg in the Steam"
StreamOffset: BigInt!

"Sender on source chain, set to msg.Sender"
SourceMessageSender: String!

"Target/To address to 'call' on destination chain"
DestAddress: String!

"Gas limit to use for 'call' on destination chain"
DestGasLimit: BigInt!

"Source chain ID as per https://chainlist.org/"
SourceChainID: BigInt!

"Destination chain ID as per https://chainlist.org/"
DestChainID: BigInt!

"Hash of the source chain transaction that emitted the message"
TxHash: String!
}

"""
Block represents a cross-chain block.
"""
type Block {

"UUID of our block"
UUID: String!

"Source chain ID as per https://chainlist.org"
SourceChainID: BigInt!

"Height of the source chain block"
BlockHeight: BigInt!

"Hash of the source chain block"
BlockHash: String!

"All cross-chain messages sent/emittted in the block"
Messages: [Msg!]!

# "Receipts of all submitted cross-chain messages applied in the block"
# Receipts [Receipt!]!

"Timestamp of the source chain block"
Timestamp: Time!
}

"""
Some browsers do not work nicely with numbers higher than max Int32.
Therefore BigInt passes these numbers enclosed in string quotes.
"""
scalar BigInt
scalar Time

type Query {
hello(name: String!): String!
block(sourceChainID: BigInt!, height: BigInt!): Block
}
Loading
Loading