Merge pull request #99 from Roasbeef/pricesrpc-full-req

multi: extend the pricesrpc interface to pass in the full HTTP request context
This commit is contained in:
Olaoluwa Osuntokun
2023-06-14 19:44:47 -05:00
committed by GitHub
18 changed files with 856 additions and 235 deletions

View File

@@ -27,6 +27,16 @@ env:
GO_VERSION: 1.19.2
jobs:
rpc-check:
name: RPC check
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v3
- name: Generate RPC stubs and check REST annotations
run: make rpc-check
########################
# lint code
########################

View File

@@ -111,6 +111,19 @@ list:
grep -v Makefile | \
sort
rpc:
@$(call print, "Compiling protos.")
cd ./pricesrpc; ./gen_protos_docker.sh
rpc-format:
@$(call print, "Formatting protos.")
cd ./pricesrpc; find . -name "*.proto" | xargs clang-format --style=file -i
rpc-check: rpc
@$(call print, "Verifying protos.")
cd ./pricesrpc; ../scripts/check-rest-annotations.sh
if test -n "$$(git status --porcelain)"; then echo "Protos not properly formatted or not compiled with correct version"; git status; git diff; exit 1; fi
clean:
@$(call print, "Cleaning source.$(NC)")
$(RM) ./aperture

View File

@@ -1,6 +1,9 @@
package pricer
import "context"
import (
"context"
"net/http"
)
// DefaultPricer provides the same price for any service path. It implements
// the Pricer interface.
@@ -16,8 +19,8 @@ func NewDefaultPricer(price int64) *DefaultPricer {
// GetPrice returns the price charged for all resources of a service.
// It is part of the Pricer interface.
func (d *DefaultPricer) GetPrice(_ context.Context, _ string) (int64,
error) {
func (d *DefaultPricer) GetPrice(_ context.Context,
_ *http.Request) (int64, error) {
return d.Price, nil
}

View File

@@ -1,8 +1,10 @@
package pricer
import (
"bytes"
"context"
"fmt"
"net/http"
"github.com/lightninglabs/aperture/pricesrpc"
"google.golang.org/grpc"
@@ -68,15 +70,23 @@ func NewGRPCPricer(cfg *Config) (*GRPCPricer, error) {
// GetPrice queries the server for the price of a resource path and returns the
// price. GetPrice is part of the Pricer interface.
func (c GRPCPricer) GetPrice(ctx context.Context, path string) (int64, error) {
func (c GRPCPricer) GetPrice(ctx context.Context,
r *http.Request) (int64, error) {
var b bytes.Buffer
if err := r.Write(&b); err != nil {
return 0, nil
}
resp, err := c.rpcClient.GetPrice(ctx, &pricesrpc.GetPriceRequest{
Path: path,
Path: r.URL.Path,
HttpRequestText: b.String(),
})
if err != nil {
return 0, err
}
return resp.Price, nil
return resp.PriceSats, nil
}
// Close closes the gRPC connection. It is part of the Pricer interface.

View File

@@ -1,12 +1,15 @@
package pricer
import "context"
import (
"context"
"net/http"
)
// Pricer is an interface used to query price data from a price provider.
type Pricer interface {
// GetPrice should return the price in satoshis for the given
// resource path.
GetPrice(ctx context.Context, path string) (int64, error)
GetPrice(ctx context.Context, req *http.Request) (int64, error)
// Close should clean up the Pricer implementation if needed.
Close() error

32
pricesrpc/Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
FROM golang:1.20.4-buster
RUN apt-get update && apt-get install -y \
git \
protobuf-compiler='3.6.1*' \
clang-format='1:7.0*'
# We don't want any default values for these variables to make sure they're
# explicitly provided by parsing the go.mod file. Otherwise we might forget to
# update them here if we bump the versions.
ARG PROTOBUF_VERSION
ARG GRPC_GATEWAY_VERSION
ENV PROTOC_GEN_GO_GRPC_VERSION="v1.1.0"
ENV FALAFEL_VERSION="v0.9.1"
ENV GOCACHE=/tmp/build/.cache
ENV GOMODCACHE=/tmp/build/.modcache
RUN cd /tmp \
&& mkdir -p /tmp/build/.cache \
&& mkdir -p /tmp/build/.modcache \
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@${PROTOBUF_VERSION} \
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@${PROTOC_GEN_GO_GRPC_VERSION} \
&& go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@${GRPC_GATEWAY_VERSION} \
&& go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@${GRPC_GATEWAY_VERSION} \
&& go install github.com/lightninglabs/falafel@${FALAFEL_VERSION} \
&& go install golang.org/x/tools/cmd/goimports@v0.1.7 \
&& chmod -R 777 /tmp/build/
WORKDIR /build
CMD ["/bin/bash", "/build/pricesrpc/gen_protos.sh"]

80
pricesrpc/gen_protos.sh Executable file
View File

@@ -0,0 +1,80 @@
#!/bin/bash
set -e
# generate compiles the *.pb.go stubs from the *.proto files.
function generate() {
echo "Generating root gRPC server protos"
PROTOS="prices.proto"
# For each of the sub-servers, we then generate their protos, but a restricted
# set as they don't yet require REST proxies, or swagger docs.
for file in $PROTOS; do
DIRECTORY=$(dirname "${file}")
echo "Generating protos from ${file}, into ${DIRECTORY}"
# Generate the protos.
protoc -I/usr/local/include -I. \
--go_out . --go_opt paths=source_relative \
--go-grpc_out . --go-grpc_opt paths=source_relative \
"${file}"
# Generate the REST reverse proxy.
annotationsFile=${file//proto/yaml}
protoc -I/usr/local/include -I. \
--grpc-gateway_out . \
--grpc-gateway_opt logtostderr=true \
--grpc-gateway_opt paths=source_relative \
--grpc-gateway_opt grpc_api_configuration=${annotationsFile} \
"${file}"
# Generate the swagger file which describes the REST API in detail.
protoc -I/usr/local/include -I. \
--openapiv2_out . \
--openapiv2_opt logtostderr=true \
--openapiv2_opt grpc_api_configuration=${annotationsFile} \
--openapiv2_opt json_names_for_fields=false \
"${file}"
done
# Generate the JSON/WASM client stubs.
falafel=$(which falafel)
pkg="pricesrpc"
opts="package_name=$pkg,js_stubs=1,build_tags=// +build js"
protoc -I/usr/local/include -I. -I.. \
--plugin=protoc-gen-custom=$falafel\
--custom_out=. \
--custom_opt="$opts" \
prices.proto
PACKAGES=""
for package in $PACKAGES; do
opts="package_name=$package,manual_import=$manual_import,js_stubs=1,build_tags=// +build js"
pushd $package
protoc -I/usr/local/include -I. -I.. \
--plugin=protoc-gen-custom=$falafel\
--custom_out=. \
--custom_opt="$opts" \
"$(find . -name '*.proto')"
popd
done
}
# format formats the *.proto files with the clang-format utility.
function format() {
find . -name "*.proto" -print0 | xargs -0 clang-format --style=file -i
}
# Compile and format the pricesrpc package.
pushd pricesrpc
format
generate
popd
if [[ "$COMPILE_MOBILE" == "1" ]]; then
pushd mobile
./gen_bindings.sh $FALAFEL_VERSION
popd
fi

25
pricesrpc/gen_protos_docker.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
set -e
# Directory of the script file, independent of where it's called from.
DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)"
PROTOBUF_VERSION=$(go list -f '{{.Version}}' -m google.golang.org/protobuf)
GRPC_GATEWAY_VERSION=$(go list -f '{{.Version}}' -m github.com/grpc-ecosystem/grpc-gateway/v2)
echo "Building protobuf compiler docker image..."
docker build -t aperture-protobuf-builder \
--build-arg PROTOBUF_VERSION="$PROTOBUF_VERSION" \
--build-arg GRPC_GATEWAY_VERSION="$GRPC_GATEWAY_VERSION" \
.
echo "Compiling and formatting *.proto files..."
docker run \
--rm \
--user "$UID:$(id -g)" \
-e UID=$UID \
-e COMPILE_MOBILE \
-e SUBSERVER_PREFIX \
-v "$DIR/../:/build" \
aperture-protobuf-builder

225
pricesrpc/prices.pb.go Normal file
View File

@@ -0,0 +1,225 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.6.1
// source: prices.proto
package pricesrpc
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GetPriceRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
HttpRequestText string `protobuf:"bytes,2,opt,name=http_request_text,json=httpRequestText,proto3" json:"http_request_text,omitempty"`
}
func (x *GetPriceRequest) Reset() {
*x = GetPriceRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_prices_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetPriceRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPriceRequest) ProtoMessage() {}
func (x *GetPriceRequest) ProtoReflect() protoreflect.Message {
mi := &file_prices_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetPriceRequest.ProtoReflect.Descriptor instead.
func (*GetPriceRequest) Descriptor() ([]byte, []int) {
return file_prices_proto_rawDescGZIP(), []int{0}
}
func (x *GetPriceRequest) GetPath() string {
if x != nil {
return x.Path
}
return ""
}
func (x *GetPriceRequest) GetHttpRequestText() string {
if x != nil {
return x.HttpRequestText
}
return ""
}
type GetPriceResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PriceSats int64 `protobuf:"varint,1,opt,name=price_sats,json=priceSats,proto3" json:"price_sats,omitempty"`
}
func (x *GetPriceResponse) Reset() {
*x = GetPriceResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_prices_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetPriceResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPriceResponse) ProtoMessage() {}
func (x *GetPriceResponse) ProtoReflect() protoreflect.Message {
mi := &file_prices_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetPriceResponse.ProtoReflect.Descriptor instead.
func (*GetPriceResponse) Descriptor() ([]byte, []int) {
return file_prices_proto_rawDescGZIP(), []int{1}
}
func (x *GetPriceResponse) GetPriceSats() int64 {
if x != nil {
return x.PriceSats
}
return 0
}
var File_prices_proto protoreflect.FileDescriptor
var file_prices_proto_rawDesc = []byte{
0x0a, 0x0c, 0x70, 0x72, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09,
0x70, 0x72, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x22, 0x51, 0x0a, 0x0f, 0x47, 0x65, 0x74,
0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68,
0x12, 0x2a, 0x0a, 0x11, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x74, 0x74,
0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x65, 0x78, 0x74, 0x22, 0x31, 0x0a, 0x10,
0x47, 0x65, 0x74, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x69, 0x63, 0x65, 0x53, 0x61, 0x74, 0x73, 0x32,
0x4d, 0x0a, 0x06, 0x50, 0x72, 0x69, 0x63, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x08, 0x47, 0x65, 0x74,
0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70,
0x63, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65,
0x74, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2d,
0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67,
0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x61, 0x70, 0x65, 0x72, 0x74,
0x75, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x73, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_prices_proto_rawDescOnce sync.Once
file_prices_proto_rawDescData = file_prices_proto_rawDesc
)
func file_prices_proto_rawDescGZIP() []byte {
file_prices_proto_rawDescOnce.Do(func() {
file_prices_proto_rawDescData = protoimpl.X.CompressGZIP(file_prices_proto_rawDescData)
})
return file_prices_proto_rawDescData
}
var file_prices_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_prices_proto_goTypes = []interface{}{
(*GetPriceRequest)(nil), // 0: pricesrpc.GetPriceRequest
(*GetPriceResponse)(nil), // 1: pricesrpc.GetPriceResponse
}
var file_prices_proto_depIdxs = []int32{
0, // 0: pricesrpc.Prices.GetPrice:input_type -> pricesrpc.GetPriceRequest
1, // 1: pricesrpc.Prices.GetPrice:output_type -> pricesrpc.GetPriceResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_prices_proto_init() }
func file_prices_proto_init() {
if File_prices_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_prices_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetPriceRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_prices_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetPriceResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_prices_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_prices_proto_goTypes,
DependencyIndexes: file_prices_proto_depIdxs,
MessageInfos: file_prices_proto_msgTypes,
}.Build()
File_prices_proto = out.File
file_prices_proto_rawDesc = nil
file_prices_proto_goTypes = nil
file_prices_proto_depIdxs = nil
}

167
pricesrpc/prices.pb.gw.go Normal file
View File

@@ -0,0 +1,167 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: prices.proto
/*
Package pricesrpc is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package pricesrpc
import (
"context"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
func request_Prices_GetPrice_0(ctx context.Context, marshaler runtime.Marshaler, client PricesClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetPriceRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetPrice(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Prices_GetPrice_0(ctx context.Context, marshaler runtime.Marshaler, server PricesServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetPriceRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetPrice(ctx, &protoReq)
return msg, metadata, err
}
// RegisterPricesHandlerServer registers the http handlers for service Prices to "mux".
// UnaryRPC :call PricesServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterPricesHandlerFromEndpoint instead.
func RegisterPricesHandlerServer(ctx context.Context, mux *runtime.ServeMux, server PricesServer) error {
mux.Handle("POST", pattern_Prices_GetPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/pricesrpc.Prices/GetPrice", runtime.WithHTTPPathPattern("/v1/aperture/price"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Prices_GetPrice_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Prices_GetPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterPricesHandlerFromEndpoint is same as RegisterPricesHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterPricesHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterPricesHandler(ctx, mux, conn)
}
// RegisterPricesHandler registers the http handlers for service Prices to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterPricesHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterPricesHandlerClient(ctx, mux, NewPricesClient(conn))
}
// RegisterPricesHandlerClient registers the http handlers for service Prices
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "PricesClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "PricesClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "PricesClient" to call the correct interceptors.
func RegisterPricesHandlerClient(ctx context.Context, mux *runtime.ServeMux, client PricesClient) error {
mux.Handle("POST", pattern_Prices_GetPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/pricesrpc.Prices/GetPrice", runtime.WithHTTPPathPattern("/v1/aperture/price"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Prices_GetPrice_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Prices_GetPrice_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Prices_GetPrice_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "aperture", "price"}, ""))
)
var (
forward_Prices_GetPrice_0 = runtime.ForwardResponseMessage
)

View File

@@ -0,0 +1,50 @@
// Code generated by falafel 0.9.1. DO NOT EDIT.
// source: prices.proto
// +build js
package pricesrpc
import (
"context"
gateway "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/protobuf/encoding/protojson"
)
func RegisterPricesJSONCallbacks(registry map[string]func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error))) {
marshaler := &gateway.JSONPb{
MarshalOptions: protojson.MarshalOptions{
UseProtoNames: true,
EmitUnpopulated: true,
},
}
registry["pricesrpc.Prices.GetPrice"] = func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
req := &GetPriceRequest{}
err := marshaler.Unmarshal([]byte(reqJSON), req)
if err != nil {
callback("", err)
return
}
client := NewPricesClient(conn)
resp, err := client.GetPrice(ctx, req)
if err != nil {
callback("", err)
return
}
respBytes, err := marshaler.Marshal(resp)
if err != nil {
callback("", err)
return
}
callback(string(respBytes), nil)
}
}

15
pricesrpc/prices.proto Normal file
View File

@@ -0,0 +1,15 @@
syntax = "proto3";
package pricesrpc;
option go_package = "github.com/lightninglabs/aperture/pricesrpc";
service Prices { rpc GetPrice(GetPriceRequest) returns (GetPriceResponse); }
message GetPriceRequest {
string path = 1;
string http_request_text = 2;
}
message GetPriceResponse { int64 price_sats = 1; }

View File

@@ -0,0 +1,104 @@
{
"swagger": "2.0",
"info": {
"title": "prices.proto",
"version": "version not set"
},
"tags": [
{
"name": "Prices"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/v1/aperture/price": {
"post": {
"operationId": "Prices_GetPrice",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/pricesrpcGetPriceResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/pricesrpcGetPriceRequest"
}
}
],
"tags": [
"Prices"
]
}
}
},
"definitions": {
"pricesrpcGetPriceRequest": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
"http_request_text": {
"type": "string"
}
}
},
"pricesrpcGetPriceResponse": {
"type": "object",
"properties": {
"price_sats": {
"type": "string",
"format": "int64"
}
}
},
"protobufAny": {
"type": "object",
"properties": {
"type_url": {
"type": "string"
},
"value": {
"type": "string",
"format": "byte"
}
}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

8
pricesrpc/prices.yaml Normal file
View File

@@ -0,0 +1,8 @@
type: google.api.Service
config_version: 3
http:
rules:
- selector: pricesrpc.Prices.GetPrice
post: "/v1/aperture/price"
body: "*"

101
pricesrpc/prices_grpc.pb.go Normal file
View File

@@ -0,0 +1,101 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package pricesrpc
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// PricesClient is the client API for Prices service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PricesClient interface {
GetPrice(ctx context.Context, in *GetPriceRequest, opts ...grpc.CallOption) (*GetPriceResponse, error)
}
type pricesClient struct {
cc grpc.ClientConnInterface
}
func NewPricesClient(cc grpc.ClientConnInterface) PricesClient {
return &pricesClient{cc}
}
func (c *pricesClient) GetPrice(ctx context.Context, in *GetPriceRequest, opts ...grpc.CallOption) (*GetPriceResponse, error) {
out := new(GetPriceResponse)
err := c.cc.Invoke(ctx, "/pricesrpc.Prices/GetPrice", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// PricesServer is the server API for Prices service.
// All implementations must embed UnimplementedPricesServer
// for forward compatibility
type PricesServer interface {
GetPrice(context.Context, *GetPriceRequest) (*GetPriceResponse, error)
mustEmbedUnimplementedPricesServer()
}
// UnimplementedPricesServer must be embedded to have forward compatible implementations.
type UnimplementedPricesServer struct {
}
func (UnimplementedPricesServer) GetPrice(context.Context, *GetPriceRequest) (*GetPriceResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPrice not implemented")
}
func (UnimplementedPricesServer) mustEmbedUnimplementedPricesServer() {}
// UnsafePricesServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to PricesServer will
// result in compilation errors.
type UnsafePricesServer interface {
mustEmbedUnimplementedPricesServer()
}
func RegisterPricesServer(s grpc.ServiceRegistrar, srv PricesServer) {
s.RegisterService(&Prices_ServiceDesc, srv)
}
func _Prices_GetPrice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPriceRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PricesServer).GetPrice(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pricesrpc.Prices/GetPrice",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PricesServer).GetPrice(ctx, req.(*GetPriceRequest))
}
return interceptor(ctx, in, info, handler)
}
// Prices_ServiceDesc is the grpc.ServiceDesc for Prices service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Prices_ServiceDesc = grpc.ServiceDesc{
ServiceName: "pricesrpc.Prices",
HandlerType: (*PricesServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetPrice",
Handler: _Prices_GetPrice_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "prices.proto",
}

View File

@@ -1,206 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: pricesrpc/rpc.proto
package pricesrpc
import (
context "context"
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type GetPriceRequest struct {
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetPriceRequest) Reset() { *m = GetPriceRequest{} }
func (m *GetPriceRequest) String() string { return proto.CompactTextString(m) }
func (*GetPriceRequest) ProtoMessage() {}
func (*GetPriceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_a48c5d96e99c79ae, []int{0}
}
func (m *GetPriceRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetPriceRequest.Unmarshal(m, b)
}
func (m *GetPriceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetPriceRequest.Marshal(b, m, deterministic)
}
func (m *GetPriceRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetPriceRequest.Merge(m, src)
}
func (m *GetPriceRequest) XXX_Size() int {
return xxx_messageInfo_GetPriceRequest.Size(m)
}
func (m *GetPriceRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GetPriceRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GetPriceRequest proto.InternalMessageInfo
func (m *GetPriceRequest) GetPath() string {
if m != nil {
return m.Path
}
return ""
}
type GetPriceResponse struct {
Price int64 `protobuf:"varint,3,opt,name=price,proto3" json:"price,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetPriceResponse) Reset() { *m = GetPriceResponse{} }
func (m *GetPriceResponse) String() string { return proto.CompactTextString(m) }
func (*GetPriceResponse) ProtoMessage() {}
func (*GetPriceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_a48c5d96e99c79ae, []int{1}
}
func (m *GetPriceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetPriceResponse.Unmarshal(m, b)
}
func (m *GetPriceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetPriceResponse.Marshal(b, m, deterministic)
}
func (m *GetPriceResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetPriceResponse.Merge(m, src)
}
func (m *GetPriceResponse) XXX_Size() int {
return xxx_messageInfo_GetPriceResponse.Size(m)
}
func (m *GetPriceResponse) XXX_DiscardUnknown() {
xxx_messageInfo_GetPriceResponse.DiscardUnknown(m)
}
var xxx_messageInfo_GetPriceResponse proto.InternalMessageInfo
func (m *GetPriceResponse) GetPrice() int64 {
if m != nil {
return m.Price
}
return 0
}
func init() {
proto.RegisterType((*GetPriceRequest)(nil), "pricesrpc.GetPriceRequest")
proto.RegisterType((*GetPriceResponse)(nil), "pricesrpc.GetPriceResponse")
}
func init() { proto.RegisterFile("pricesrpc/rpc.proto", fileDescriptor_a48c5d96e99c79ae) }
var fileDescriptor_a48c5d96e99c79ae = []byte{
// 182 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2e, 0x28, 0xca, 0x4c,
0x4e, 0x2d, 0x2e, 0x2a, 0x48, 0xd6, 0x2f, 0x2a, 0x48, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
0xe2, 0x84, 0x0b, 0x2a, 0xa9, 0x72, 0xf1, 0xbb, 0xa7, 0x96, 0x04, 0x80, 0xf8, 0x41, 0xa9, 0x85,
0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42, 0x5c, 0x2c, 0x05, 0x89, 0x25, 0x19, 0x12, 0x8c, 0x0a, 0x8c,
0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92, 0x06, 0x97, 0x00, 0x42, 0x59, 0x71, 0x41, 0x7e, 0x5e, 0x71,
0xaa, 0x90, 0x08, 0x17, 0x2b, 0xd8, 0x1c, 0x09, 0x66, 0x05, 0x46, 0x0d, 0xe6, 0x20, 0x08, 0xc7,
0xc8, 0x97, 0x8b, 0x0d, 0xac, 0xac, 0x58, 0xc8, 0x99, 0x8b, 0x03, 0xa6, 0x47, 0x48, 0x4a, 0x0f,
0x6e, 0xa5, 0x1e, 0x9a, 0x7d, 0x52, 0xd2, 0x58, 0xe5, 0x20, 0x96, 0x38, 0xe9, 0x46, 0x69, 0xa7,
0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xe7, 0x64, 0xa6, 0x67, 0x94, 0xe4,
0x65, 0xe6, 0xa5, 0xe7, 0x24, 0x26, 0x15, 0xeb, 0x27, 0x16, 0xa4, 0x16, 0x95, 0x94, 0x16, 0xa5,
0xea, 0xc3, 0xf5, 0x27, 0xb1, 0x81, 0x3d, 0x68, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x0d, 0x3d,
0x77, 0x8f, 0xf7, 0x00, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// PricesClient is the client API for Prices service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type PricesClient interface {
GetPrice(ctx context.Context, in *GetPriceRequest, opts ...grpc.CallOption) (*GetPriceResponse, error)
}
type pricesClient struct {
cc *grpc.ClientConn
}
func NewPricesClient(cc *grpc.ClientConn) PricesClient {
return &pricesClient{cc}
}
func (c *pricesClient) GetPrice(ctx context.Context, in *GetPriceRequest, opts ...grpc.CallOption) (*GetPriceResponse, error) {
out := new(GetPriceResponse)
err := c.cc.Invoke(ctx, "/pricesrpc.Prices/GetPrice", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// PricesServer is the server API for Prices service.
type PricesServer interface {
GetPrice(context.Context, *GetPriceRequest) (*GetPriceResponse, error)
}
// UnimplementedPricesServer can be embedded to have forward compatible implementations.
type UnimplementedPricesServer struct {
}
func (*UnimplementedPricesServer) GetPrice(ctx context.Context, req *GetPriceRequest) (*GetPriceResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPrice not implemented")
}
func RegisterPricesServer(s *grpc.Server, srv PricesServer) {
s.RegisterService(&_Prices_serviceDesc, srv)
}
func _Prices_GetPrice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPriceRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PricesServer).GetPrice(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pricesrpc.Prices/GetPrice",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PricesServer).GetPrice(ctx, req.(*GetPriceRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Prices_serviceDesc = grpc.ServiceDesc{
ServiceName: "pricesrpc.Prices",
HandlerType: (*PricesServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetPrice",
Handler: _Prices_GetPrice_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "pricesrpc/rpc.proto",
}

View File

@@ -1,17 +0,0 @@
syntax="proto3";
package pricesrpc;
option go_package = "github.com/lightninglabs/aperture/pricesrpc";
service Prices {
rpc GetPrice(GetPriceRequest) returns (GetPriceResponse);
}
message GetPriceRequest {
string path = 1;
}
message GetPriceResponse {
int64 price = 3;
}

View File

@@ -155,9 +155,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// resources.
acceptAuth := p.authenticator.Accept(&r.Header, resourceName)
if !acceptAuth {
price, err := target.pricer.GetPrice(
r.Context(), r.URL.Path,
)
price, err := target.pricer.GetPrice(r.Context(), r)
if err != nil {
prefixLog.Errorf("error getting "+
"resource price: %v", err)
@@ -197,7 +195,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
if !ok {
price, err := target.pricer.GetPrice(
r.Context(), r.URL.Path,
r.Context(), r,
)
if err != nil {
prefixLog.Errorf("error getting "+