herald.go/server/server.go

233 lines
6.2 KiB
Go
Raw Normal View History

2021-04-19 21:25:34 +02:00
package server
2021-03-18 22:14:56 +01:00
import (
2021-09-18 19:21:32 +02:00
"context"
2021-10-01 19:54:03 +02:00
"crypto/sha256"
2021-09-18 19:21:32 +02:00
"fmt"
2021-10-01 19:54:03 +02:00
"hash"
2021-06-18 06:01:47 +02:00
"log"
2021-10-01 19:54:03 +02:00
"net/http"
"os"
2021-06-18 06:01:47 +02:00
"regexp"
"sync"
2021-09-21 20:02:09 +02:00
"time"
2021-10-01 19:54:03 +02:00
"github.com/ReneKroon/ttlcache/v2"
"github.com/lbryio/hub/internal/metrics"
2021-09-24 22:24:22 +02:00
"github.com/lbryio/hub/meta"
2021-03-18 22:14:56 +01:00
pb "github.com/lbryio/hub/protobuf/go"
2021-06-04 07:56:50 +02:00
"github.com/olivere/elastic/v7"
"github.com/prometheus/client_golang/prometheus"
2021-07-06 02:20:38 +02:00
"github.com/prometheus/client_golang/prometheus/promhttp"
"google.golang.org/grpc"
2021-03-18 22:14:56 +01:00
)
2021-04-19 21:25:34 +02:00
type Server struct {
2021-10-03 04:49:49 +02:00
GrpcServer *grpc.Server
Args *Args
MultiSpaceRe *regexp.Regexp
WeirdCharsRe *regexp.Regexp
EsClient *elastic.Client
Servers map[string]*FederatedServer
2021-10-03 04:49:49 +02:00
QueryCache *ttlcache.Cache
S256 *hash.Hash
LastRefreshCheck time.Time
RefreshDelta time.Duration
NumESRefreshes int64
PeerSubs sync.Map
peerChannel chan *peerAddMsg
2021-03-18 22:14:56 +01:00
pb.UnimplementedHubServer
}
2021-09-24 22:24:22 +02:00
func getVersion() string {
return meta.Version
2021-07-06 02:20:38 +02:00
}
2021-03-18 22:14:56 +01:00
/*
'blockchain.block.get_chunk'
'blockchain.block.get_header'
'blockchain.estimatefee'
'blockchain.relayfee'
'blockchain.scripthash.get_balance'
'blockchain.scripthash.get_history'
'blockchain.scripthash.get_mempool'
'blockchain.scripthash.listunspent'
'blockchain.scripthash.subscribe'
'blockchain.transaction.broadcast'
'blockchain.transaction.get'
'blockchain.transaction.get_batch'
'blockchain.transaction.info'
'blockchain.transaction.get_merkle'
'server.add_peer'
'server.banner'
'server.payment_address'
'server.donation_address'
'server.features'
'server.peers.subscribe'
'server.version'
'blockchain.transaction.get_height'
'blockchain.claimtrie.search'
'blockchain.claimtrie.resolve'
'blockchain.claimtrie.getclaimsbyids'
'blockchain.block.get_server_height'
'mempool.get_fee_histogram'
'blockchain.block.headers'
'server.ping'
'blockchain.headers.subscribe'
'blockchain.address.get_balance'
'blockchain.address.get_history'
'blockchain.address.get_mempool'
'blockchain.address.listunspent'
'blockchain.address.subscribe'
'blockchain.address.unsubscribe'
*/
// MakeHubServer takes the arguments given to a hub when it's started and
// initializes everything. It loads information about previously known peers,
// creates needed internal data structures, and initializes goroutines.
func MakeHubServer(ctx context.Context, args *Args) *Server {
2021-07-06 02:20:38 +02:00
grpcServer := grpc.NewServer(grpc.NumStreamWorkers(10))
2021-06-01 04:19:10 +02:00
peerChannel := make(chan *peerAddMsg)
2021-08-24 10:45:30 +02:00
multiSpaceRe, err := regexp.Compile(`\s{2,}`)
2021-06-01 04:19:10 +02:00
if err != nil {
log.Fatal(err)
}
weirdCharsRe, err := regexp.Compile("[#!~]")
if err != nil {
log.Fatal(err)
}
servers := loadPeers(args)
var client *elastic.Client
if !args.DisableEs {
esUrl := args.EsHost + ":" + args.EsPort
opts := []elastic.ClientOptionFunc{
elastic.SetSniff(true),
elastic.SetSnifferTimeoutStartup(time.Second * 60),
elastic.SetSnifferTimeout(time.Second * 60),
elastic.SetURL(esUrl),
}
if args.Debug {
opts = append(opts, elastic.SetTraceLog(log.New(os.Stderr, "[[ELASTIC]]", 0)))
}
client, err = elastic.NewClient(opts...)
if err != nil {
log.Fatal(err)
}
} else {
client = nil
}
2021-10-01 19:54:03 +02:00
cache := ttlcache.NewCache()
err = cache.SetTTL(time.Duration(args.CacheTTL) * time.Minute)
2021-10-01 19:54:03 +02:00
if err != nil {
log.Fatal(err)
}
s256 := sha256.New()
var refreshDelta = time.Second * time.Duration(args.RefreshDelta)
2021-10-03 04:49:49 +02:00
if args.Debug {
refreshDelta = time.Second * 0
}
2021-08-11 05:39:37 +02:00
s := &Server{
2021-10-03 04:49:49 +02:00
GrpcServer: grpcServer,
Args: args,
MultiSpaceRe: multiSpaceRe,
WeirdCharsRe: weirdCharsRe,
EsClient: client,
QueryCache: cache,
S256: &s256,
LastRefreshCheck: time.Now(),
RefreshDelta: refreshDelta,
NumESRefreshes: 0,
Servers: servers,
PeerSubs: sync.Map{},
peerChannel: peerChannel,
}
// Start up our background services
if args.StartPeerAdder {
go s.peerAdder(ctx)
}
if args.StartPrometheus {
go s.prometheusEndpoint(s.Args.PrometheusPort, "metrics")
}
if args.StartUDP {
go func() {
err := UDPServer(args)
if err != nil {
log.Println("UDP Server failed!", err)
}
}()
2021-06-01 04:19:10 +02:00
}
return s
2021-07-06 02:20:38 +02:00
}
// prometheusEndpoint is a goroutine which start up a prometheus endpoint
// for this hub to allow for metric tracking.
func (s *Server) prometheusEndpoint(port string, endpoint string) {
2021-09-21 20:02:09 +02:00
http.Handle("/"+endpoint, promhttp.Handler())
2021-07-06 02:20:38 +02:00
log.Println(fmt.Sprintf("listening on :%s /%s", port, endpoint))
2021-09-21 20:02:09 +02:00
err := http.ListenAndServe(":"+port, nil)
log.Fatalln("Shouldn't happen??!?!", err)
}
// Hello is a grpc endpoint to allow another hub to tell us about itself.
// The passed message includes information about the other hub, and all
// of its peers which are added to the knowledge of this hub.
func (s *Server) Hello(ctx context.Context, args *pb.HelloMessage) (*pb.HelloMessage, error) {
port := args.Port
host := args.Host
server := &FederatedServer{
Address: host,
Port: port,
Ts: time.Now(),
}
log.Println(server)
s.addPeer(&pb.ServerMessage{Address: host, Port: port}, false)
s.mergeFederatedServers(args.Servers)
s.writePeers()
s.notifyPeerSubs(server)
return s.makeHelloMessage(), nil
}
// PeerSubscribe adds a peer hub to the list of subscribers to update about
// new peers.
func (s *Server) PeerSubscribe(ctx context.Context, in *pb.ServerMessage) (*pb.StringValue, error) {
peer := &FederatedServer{
Address: in.Address,
Port: in.Port,
Ts: time.Now(),
2021-07-06 02:20:38 +02:00
}
s.PeerSubs.Store(peerKey(in), peer)
return &pb.StringValue{Value: "Success"}, nil
2021-07-06 02:20:38 +02:00
}
// AddPeer is a grpc endpoint to tell this hub about another hub in the network.
func (s *Server) AddPeer(ctx context.Context, args *pb.ServerMessage) (*pb.StringValue, error) {
s.addPeer(args, true)
return &pb.StringValue{Value: "Success!"}, nil
2021-07-06 02:20:38 +02:00
}
// Ping is a grpc endpoint that returns a short message.
func (s *Server) Ping(ctx context.Context, args *pb.EmptyMessage) (*pb.StringValue, error) {
metrics.RequestsCount.With(prometheus.Labels{"method": "ping"}).Inc()
2021-09-18 19:21:32 +02:00
return &pb.StringValue{Value: "Hello, world!"}, nil
2021-07-06 02:20:38 +02:00
}
// Version is a grpc endpoint to get this hub's version.
func (s *Server) Version(ctx context.Context, args *pb.EmptyMessage) (*pb.StringValue, error) {
metrics.RequestsCount.With(prometheus.Labels{"method": "version"}).Inc()
2021-09-24 22:24:22 +02:00
return &pb.StringValue{Value: getVersion()}, nil
2021-09-18 19:21:32 +02:00
}