-
Notifications
You must be signed in to change notification settings - Fork 40
Sendfil Service #512
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
Sendfil Service #512
Changes from 6 commits
5f66eda
6585907
3c893d8
15e82f5
1b0aea5
10cb87d
20450fa
a3275c2
f48c2e8
a351a47
0cf7553
a643871
8b80325
1d9152a
32f8352
dc07833
6ef1ad7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| FROM golang:1.15.5-buster | ||
| MAINTAINER Textile <contact@textile.io> | ||
|
|
||
| # This is (in large part) copied (with love) from | ||
| # https://hub.docker.com/r/ipfs/go-ipfs/dockerfile | ||
|
|
||
| # Install deps | ||
| RUN apt-get update && apt-get install -y \ | ||
| libssl-dev \ | ||
| ca-certificates | ||
|
|
||
| ENV SRC_DIR /textile | ||
|
|
||
| # Download packages first so they can be cached. | ||
| COPY go.mod go.sum $SRC_DIR/ | ||
| RUN cd $SRC_DIR \ | ||
| && go mod download | ||
|
|
||
| COPY . $SRC_DIR | ||
|
|
||
| # Build the thing. | ||
| RUN cd $SRC_DIR \ | ||
| && TXTL_BUILD_FLAGS="CGO_ENABLED=0 GOOS=linux" make build-sendfild | ||
|
|
||
| # Get su-exec, a very minimal tool for dropping privileges, | ||
| # and tini, a very minimal init daemon for containers | ||
| ENV SUEXEC_VERSION v0.2 | ||
| ENV TINI_VERSION v0.19.0 | ||
| RUN set -eux; \ | ||
| dpkgArch="$(dpkg --print-architecture)"; \ | ||
| case "${dpkgArch##*-}" in \ | ||
| "amd64" | "armhf" | "arm64") tiniArch="tini-static-$dpkgArch" ;;\ | ||
| *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ | ||
| esac; \ | ||
| cd /tmp \ | ||
| && git clone https://github.com/ncopa/su-exec.git \ | ||
| && cd su-exec \ | ||
| && git checkout -q $SUEXEC_VERSION \ | ||
| && make su-exec-static \ | ||
| && cd /tmp \ | ||
| && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/$tiniArch \ | ||
| && chmod +x tini | ||
|
|
||
| # Now comes the actual target image, which aims to be as small as possible. | ||
| FROM busybox:1.31.1-glibc | ||
| LABEL maintainer="Textile <contact@textile.io>" | ||
|
|
||
| # Get the textile binary, entrypoint script, and TLS CAs from the build container. | ||
| ENV SRC_DIR /textile | ||
| COPY --from=0 $SRC_DIR/sendfild /usr/local/bin/sendfild | ||
| COPY --from=0 /tmp/su-exec/su-exec-static /sbin/su-exec | ||
| COPY --from=0 /tmp/tini /sbin/tini | ||
| COPY --from=0 /etc/ssl/certs /etc/ssl/certs | ||
|
|
||
| # This shared lib (part of glibc) doesn't seem to be included with busybox. | ||
| COPY --from=0 /lib/*-linux-gnu*/libdl.so.2 /lib/ | ||
|
|
||
| # Copy over SSL libraries. | ||
| COPY --from=0 /usr/lib/*-linux-gnu*/libssl.so* /usr/lib/ | ||
| COPY --from=0 /usr/lib/*-linux-gnu*/libcrypto.so* /usr/lib/ | ||
|
|
||
| # listenAddrs | ||
| EXPOSE 7006 | ||
|
|
||
| # Create the repo directory. | ||
| ENV SENDFIL_PATH /data/sendfil | ||
| RUN mkdir -p $SENDFIL_PATH \ | ||
| && adduser -D -h $SENDFIL_PATH -u 1000 -G users sendfil \ | ||
| && chown sendfil:users $SENDFIL_PATH | ||
|
|
||
| # Switch to a non-privileged user. | ||
| USER sendfil | ||
|
|
||
| ENTRYPOINT ["/sbin/tini", "--", "sendfild"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| FROM golang:1.15.5-buster | ||
|
|
||
| RUN apt-get update && apt-get install -y \ | ||
| libssl-dev \ | ||
| ca-certificates | ||
|
|
||
| RUN go get github.com/go-delve/delve/cmd/dlv | ||
|
|
||
| ENV SRC_DIR /textile | ||
|
|
||
| COPY go.mod go.sum $SRC_DIR/ | ||
| RUN cd $SRC_DIR \ | ||
| && go mod download | ||
|
|
||
| COPY . $SRC_DIR | ||
|
|
||
| RUN cd $SRC_DIR \ | ||
| && CGO_ENABLED=0 GOOS=linux go build -gcflags "all=-N -l" -o sendfild api/sendfild/main.go | ||
|
|
||
| FROM debian:buster | ||
| LABEL maintainer="Textile <contact@textile.io>" | ||
|
|
||
| ENV SRC_DIR /textile | ||
| COPY --from=0 /go/bin/dlv /usr/local/bin/dlv | ||
| COPY --from=0 /etc/ssl/certs /etc/ssl/certs | ||
| COPY --from=0 $SRC_DIR/sendfild /usr/local/bin/sendfild | ||
|
|
||
| EXPOSE 10006 | ||
| EXPOSE 8010 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same about 1006? |
||
|
|
||
| ENV SENDFIL_PATH /data/sendfil | ||
| RUN adduser --home $SENDFIL_PATH --disabled-login --gecos "" --ingroup users sendfil | ||
|
|
||
| USER sendfil | ||
|
|
||
| ENTRYPOINT ["dlv", "--listen=0.0.0.0:40000", "--headless=true", "--accept-multiclient", "--continue", "--api-version=2", "exec", "/usr/local/bin/sendfild"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| package client | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "time" | ||
|
|
||
| "github.com/textileio/textile/v2/api/sendfild/pb" | ||
| "google.golang.org/grpc" | ||
| "google.golang.org/protobuf/types/known/timestamppb" | ||
| ) | ||
|
|
||
| type Client struct { | ||
| c pb.SendFilServiceClient | ||
| conn *grpc.ClientConn | ||
| } | ||
|
asutula marked this conversation as resolved.
|
||
|
|
||
| func New(target string, opts ...grpc.DialOption) (*Client, error) { | ||
| conn, err := grpc.Dial(target, opts...) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("creating gRPC client conn: %v", err) | ||
| } | ||
|
|
||
| c := pb.NewSendFilServiceClient(conn) | ||
|
|
||
| return &Client{ | ||
| c: c, | ||
| conn: conn, | ||
| }, nil | ||
| } | ||
|
|
||
| type SendFilOption = func(*pb.SendFilRequest) | ||
|
|
||
| func SendFilWait() SendFilOption { | ||
| return func(req *pb.SendFilRequest) { | ||
| req.Wait = true | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Early in review so I'm not entirely sure, but I can imagine that Open question: should the "Wait" thing be encouraged if there's risk that the API timeouts and somehow the "send fil" continues after the API call errored? Maybe safer to discourage this use? (assuming my guess now of what "wait" means)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah good point. I think it is normal and fine to want to wait here, and there is a chance that the underlying lotus call to |
||
| } | ||
| } | ||
|
|
||
| func (c *Client) SendFil(ctx context.Context, from, to string, amountNanoFil int64, opts ...SendFilOption) (*pb.Txn, error) { | ||
| req := &pb.SendFilRequest{ | ||
| From: from, | ||
| To: to, | ||
| AmountNanoFil: amountNanoFil, | ||
| } | ||
| for _, opt := range opts { | ||
| opt(req) | ||
| } | ||
| res, err := c.c.SendFil(ctx, req) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return res.Txn, nil | ||
| } | ||
|
|
||
| type TxnOption = func(*pb.TxnRequest) | ||
|
|
||
| func TxnWait() TxnOption { | ||
| return func(req *pb.TxnRequest) { | ||
| req.Wait = true | ||
| } | ||
| } | ||
|
|
||
| func (c *Client) Txn(ctx context.Context, messageCid string, opts ...TxnOption) (*pb.Txn, error) { | ||
|
asutula marked this conversation as resolved.
Outdated
|
||
| req := &pb.TxnRequest{ | ||
| MessageCid: messageCid, | ||
| } | ||
| for _, opt := range opts { | ||
| opt(req) | ||
| } | ||
| res, err := c.c.Txn(ctx, req) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return res.Txn, nil | ||
| } | ||
|
|
||
| type ListTxnsOption = func(*pb.ListTxnsRequest) | ||
|
|
||
| func ListTxnsFrom(from string) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.FromFilter = from | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsTo(to string) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.ToFilter = to | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsInvolving(involving string) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.InvolvingFilter = involving | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsAmountNanoFilLt(amountNanoFil int64) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.AmountNanoFilLtFilter = amountNanoFil | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsAmountNanoFilGt(amountNanoFil int64) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.AmountNanoFilGtFilter = amountNanoFil | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsAmountNanoFilLteq(amountNanoFil int64) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.AmountNanoFilLteqFilter = amountNanoFil | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsAmountNanoFilGteq(amountNanoFil int64) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.AmountNanoFilGteqFilter = amountNanoFil | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsAmountNanoFilEq(amountNanoFil int64) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.AmountNanoFilEqFilter = amountNanoFil | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsMessageState(messageState pb.MessageState) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.MessageStateFilter = messageState | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsWaiting(waitingFilter pb.WaitingFilter) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.WaitingFilter = waitingFilter | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsCreatedAfter(time time.Time) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.CreatedAfter = timestamppb.New(time) | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsCreatedBefore(time time.Time) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.CreatedBefore = timestamppb.New(time) | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsUpdatedAfter(time time.Time) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.UpdatedAfter = timestamppb.New(time) | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsUpdatedBefore(time time.Time) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.UpdatedBefore = timestamppb.New(time) | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsAscending() ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.Ascending = true | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsMoreToken(moreToken int64) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.MoreToken = moreToken | ||
| } | ||
| } | ||
|
|
||
| func ListTxnsLimit(limit int64) ListTxnsOption { | ||
| return func(req *pb.ListTxnsRequest) { | ||
| req.Limit = limit | ||
| } | ||
| } | ||
|
|
||
| func (c *Client) ListTxns(ctx context.Context, opts ...ListTxnsOption) ([]*pb.Txn, bool, int64, error) { | ||
| req := &pb.ListTxnsRequest{} | ||
| for _, opt := range opts { | ||
| opt(req) | ||
| } | ||
| res, err := c.c.ListTxns(ctx, req) | ||
| if err != nil { | ||
| return nil, false, 0, err | ||
| } | ||
| return res.Txns, res.More, res.MoreToken, nil | ||
| } | ||
|
|
||
| func (c *Client) Close() error { | ||
| if c == nil { | ||
| return nil | ||
| } | ||
| return c.conn.Close() | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be 5000 considering new standards?