Skip to content

Commit af88596

Browse files
committed
feat: add daemon command
1 parent 1cff889 commit af88596

File tree

13 files changed

+612
-169
lines changed

13 files changed

+612
-169
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lassie
2+
*.car

cli/flags.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package cli
2+
3+
import "github.com/urfave/cli/v2"
4+
5+
// IsVerbose is a global var signaling if the CLI is running in
6+
// verbose mode or not (default: false).
7+
var IsVerbose bool
8+
9+
// FlagVerbose enables verbose mode, which shows verbose information about
10+
// operations invoked in the CLI. It should be included as a flag on the
11+
// top-level command (e.g. lassie -v).
12+
var FlagVerbose = &cli.BoolFlag{
13+
Name: "verbose",
14+
Aliases: []string{"v"},
15+
Usage: "enable verbose mode for logging",
16+
Destination: &IsVerbose,
17+
}
18+
19+
// IsVeryVerbose is a global var signaling if the CLI is running in
20+
// very verbose mode or not (default: false).
21+
var IsVeryVerbose bool
22+
23+
// FlagVerbose enables verbose mode, which shows verbose information about
24+
// operations invoked in the CLI. It should be included as a flag on the
25+
// top-level command (e.g. lassie -v).
26+
var FlagVeryVerbose = &cli.BoolFlag{
27+
Name: "very-verbose",
28+
Aliases: []string{"vv"},
29+
Usage: "enable very verbose mode for debugging",
30+
Destination: &IsVeryVerbose,
31+
}

cmd/lassie/daemon.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
lcli "github.com/filecoin-project/lassie/cli"
7+
httpserver "github.com/filecoin-project/lassie/server/http"
8+
"github.com/urfave/cli/v2"
9+
)
10+
11+
var daemonFlags = []cli.Flag{
12+
&cli.StringFlag{
13+
Name: "address",
14+
Aliases: []string{"a"},
15+
Usage: "the address the http server listens on",
16+
Value: "127.0.0.1",
17+
DefaultText: "127.0.0.1",
18+
EnvVars: []string{"LASSIE_ADDRESS"},
19+
},
20+
&cli.UintFlag{
21+
Name: "port",
22+
Aliases: []string{"p"},
23+
Usage: "the port the http server listens on",
24+
Value: 0,
25+
DefaultText: "random",
26+
EnvVars: []string{"LASSIE_PORT"},
27+
},
28+
lcli.FlagVerbose,
29+
lcli.FlagVeryVerbose,
30+
}
31+
32+
var daemonCmd = &cli.Command{
33+
Name: "daemon",
34+
Usage: "Starts a lassie daemon, accepting http requests",
35+
Before: before,
36+
Flags: daemonFlags,
37+
Action: daemonCommand,
38+
}
39+
40+
func daemonCommand(cctx *cli.Context) error {
41+
address := cctx.String("address")
42+
port := cctx.Uint("port")
43+
httpServer, err := httpserver.NewHttpServer(cctx.Context, address, port)
44+
if err != nil {
45+
log.Errorw("failed to create http server", "err", err)
46+
return err
47+
}
48+
49+
serverErrChan := make(chan error, 1)
50+
go func() {
51+
fmt.Printf("Lassie daemon listening on address %s\n", httpServer.Addr())
52+
fmt.Println("Hit CTRL-C to stop the daemon")
53+
serverErrChan <- httpServer.Start()
54+
}()
55+
56+
select {
57+
case <-cctx.Done(): // command was cancelled
58+
case err = <-serverErrChan: // error from server
59+
log.Errorw("failed to start http server", "err", err)
60+
}
61+
62+
fmt.Println("Shutting down Lassie daemon")
63+
if err = httpServer.Close(); err != nil {
64+
log.Errorw("failed to close http server", "err", err)
65+
}
66+
67+
fmt.Println("Lassie daemon stopped")
68+
if err != nil {
69+
return cli.Exit(err, 1)
70+
}
71+
72+
return nil
73+
}

cmd/lassie/fetch.go

+12-142
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,46 @@ package main
33
import (
44
"context"
55
"fmt"
6-
"log"
76
"strings"
87
"time"
98

109
"github.com/dustin/go-humanize"
11-
"github.com/filecoin-project/lassie/cmd/lassie/internal"
12-
"github.com/filecoin-project/lassie/pkg/client"
10+
lcli "github.com/filecoin-project/lassie/cli"
11+
"github.com/filecoin-project/lassie/internal"
1312
"github.com/filecoin-project/lassie/pkg/events"
14-
"github.com/filecoin-project/lassie/pkg/indexerlookup"
1513
"github.com/filecoin-project/lassie/pkg/retriever"
1614
"github.com/filecoin-project/lassie/pkg/types"
17-
blocks "github.com/ipfs/go-block-format"
1815
"github.com/ipfs/go-cid"
19-
"github.com/ipfs/go-datastore"
20-
dss "github.com/ipfs/go-datastore/sync"
2116
"github.com/ipfs/go-graphsync/storeutil"
22-
blockstore "github.com/ipfs/go-ipfs-blockstore"
2317
carblockstore "github.com/ipld/go-car/v2/blockstore"
2418
"github.com/libp2p/go-libp2p/core/peer"
25-
"github.com/multiformats/go-multiaddr"
2619
"github.com/urfave/cli/v2"
2720
)
2821

2922
var fetchProviderAddrInfo *peer.AddrInfo
3023

3124
var fetchCmd = &cli.Command{
3225
Name: "fetch",
33-
Usage: "fetch content from Filecoin",
26+
Usage: "Fetches content from Filecoin",
27+
Before: before,
3428
Action: Fetch,
3529
Flags: []cli.Flag{
3630
&cli.StringFlag{
3731
Name: "output",
3832
Aliases: []string{"o"},
39-
Usage: "The CAR file to write to, may be an existing or a new CAR",
33+
Usage: "the CAR file to write to, may be an existing or a new CAR",
4034
TakesFile: true,
4135
},
4236
&cli.DurationFlag{
4337
Name: "timeout",
4438
Aliases: []string{"t"},
45-
Usage: "Consider it an error after not receiving a response from a storage provider for this long",
39+
Usage: "consider it an error after not receiving a response from a storage provider for this long",
4640
Value: 20 * time.Second,
4741
},
4842
&cli.BoolFlag{
4943
Name: "progress",
5044
Aliases: []string{"p"},
51-
Usage: "Print progress output",
45+
Usage: "print progress output",
5246
},
5347
&cli.StringFlag{
5448
Name: "provider",
@@ -60,6 +54,8 @@ var fetchCmd = &cli.Command{
6054
return err
6155
},
6256
},
57+
lcli.FlagVerbose,
58+
lcli.FlagVeryVerbose,
6359
},
6460
}
6561

@@ -95,15 +91,15 @@ func Fetch(c *cli.Context) error {
9591
}
9692
}
9793
timeout := c.Duration("timeout")
98-
bstore := &putCbBlockstore{parentOpener: parentOpener, cb: putCb}
94+
bstore := internal.NewPutCbBlockstore(parentOpener, putCb)
9995

10096
linkSystem := storeutil.LinkSystemForBlockstore(bstore)
10197

10298
var ret *retriever.Retriever
10399
if fetchProviderAddrInfo == nil {
104-
ret, err = setupRetriever(c, timeout)
100+
ret, err = internal.SetupRetriever(c.Context, timeout)
105101
} else {
106-
ret, err = setupRetrieverWithFinder(c, timeout, explicitCandidateFinder{provider: *fetchProviderAddrInfo})
102+
ret, err = internal.SetupRetrieverWithFinder(c.Context, timeout, explicitCandidateFinder{provider: *fetchProviderAddrInfo})
107103
}
108104
if err != nil {
109105
return err
@@ -142,132 +138,6 @@ func Fetch(c *cli.Context) error {
142138
return bstore.Finalize()
143139
}
144140

145-
func setupRetriever(c *cli.Context, timeout time.Duration) (*retriever.Retriever, error) {
146-
return setupRetrieverWithFinder(c, timeout, indexerlookup.NewCandidateFinder("https://cid.contact"))
147-
}
148-
149-
func setupRetrieverWithFinder(c *cli.Context, timeout time.Duration, finder retriever.CandidateFinder) (*retriever.Retriever, error) {
150-
datastore := dss.MutexWrap(datastore.NewMapDatastore())
151-
152-
host, err := internal.InitHost(c.Context, multiaddr.StringCast("/ip4/0.0.0.0/tcp/6746"))
153-
if err != nil {
154-
return nil, err
155-
}
156-
157-
retrievalClient, err := client.NewClient(datastore, host, nil)
158-
if err != nil {
159-
return nil, err
160-
}
161-
162-
indexer := indexerlookup.NewCandidateFinder("https://cid.contact")
163-
164-
retrieverCfg := retriever.RetrieverConfig{
165-
DefaultMinerConfig: retriever.MinerConfig{
166-
RetrievalTimeout: timeout,
167-
},
168-
}
169-
170-
ret, err := retriever.NewRetriever(c.Context, retrieverCfg, retrievalClient, indexer)
171-
if err != nil {
172-
return nil, err
173-
}
174-
ret.Start()
175-
return ret, nil
176-
}
177-
178-
// putCbBlockstore simply calls a callback on each put(), with the number of blocks put
179-
var _ blockstore.Blockstore = (*putCbBlockstore)(nil)
180-
181-
type putCbBlockstore struct {
182-
// parentOpener lazily opens the parent blockstore upon first call to this blockstore.
183-
// This avoids blockstore instantiation until there is some interaction from the retriever.
184-
// In the case of CARv2 blockstores, this will avoid creation of empty .car files should
185-
// the retriever fail to find any candidates.
186-
parentOpener func() (*carblockstore.ReadWrite, error)
187-
// parent is lazily instantiated and should not be directly used; use parentBlockstore instead.
188-
parent *carblockstore.ReadWrite
189-
cb func(putCount int, putBytes int)
190-
}
191-
192-
func (pcb *putCbBlockstore) DeleteBlock(ctx context.Context, cid cid.Cid) error {
193-
pbs, err := pcb.parentBlockstore()
194-
if err != nil {
195-
return err
196-
}
197-
return pbs.DeleteBlock(ctx, cid)
198-
}
199-
func (pcb *putCbBlockstore) Has(ctx context.Context, cid cid.Cid) (bool, error) {
200-
pbs, err := pcb.parentBlockstore()
201-
if err != nil {
202-
return false, err
203-
}
204-
return pbs.Has(ctx, cid)
205-
}
206-
func (pcb *putCbBlockstore) Get(ctx context.Context, cid cid.Cid) (blocks.Block, error) {
207-
pbs, err := pcb.parentBlockstore()
208-
if err != nil {
209-
return nil, err
210-
}
211-
return pbs.Get(ctx, cid)
212-
}
213-
func (pcb *putCbBlockstore) GetSize(ctx context.Context, cid cid.Cid) (int, error) {
214-
pbs, err := pcb.parentBlockstore()
215-
if err != nil {
216-
return 0, err
217-
}
218-
return pbs.GetSize(ctx, cid)
219-
}
220-
func (pcb *putCbBlockstore) Put(ctx context.Context, block blocks.Block) error {
221-
pbs, err := pcb.parentBlockstore()
222-
if err != nil {
223-
return err
224-
}
225-
pcb.cb(1, len(block.RawData()))
226-
return pbs.Put(ctx, block)
227-
}
228-
func (pcb *putCbBlockstore) PutMany(ctx context.Context, blocks []blocks.Block) error {
229-
pbs, err := pcb.parentBlockstore()
230-
if err != nil {
231-
return err
232-
}
233-
var byts int
234-
for _, b := range blocks {
235-
byts += len(b.RawData())
236-
}
237-
pcb.cb(len(blocks), byts)
238-
return pbs.PutMany(ctx, blocks)
239-
}
240-
func (pcb *putCbBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
241-
pbs, err := pcb.parentBlockstore()
242-
if err != nil {
243-
return nil, err
244-
}
245-
return pbs.AllKeysChan(ctx)
246-
}
247-
func (pcb *putCbBlockstore) HashOnRead(enabled bool) {
248-
if pbs, err := pcb.parentBlockstore(); err != nil {
249-
log.Printf("Failed to instantiate blockstore while setting HashOnRead: %v\n", err)
250-
} else {
251-
pbs.HashOnRead(enabled)
252-
}
253-
}
254-
func (pcb *putCbBlockstore) Finalize() error {
255-
if pbs, err := pcb.parentBlockstore(); err != nil {
256-
return err
257-
} else {
258-
return pbs.Finalize()
259-
}
260-
}
261-
func (pcb *putCbBlockstore) parentBlockstore() (*carblockstore.ReadWrite, error) {
262-
if pcb.parent == nil {
263-
var err error
264-
if pcb.parent, err = pcb.parentOpener(); err != nil {
265-
return nil, err
266-
}
267-
}
268-
return pcb.parent, nil
269-
}
270-
271141
type progressPrinter struct {
272142
candidatesFound int
273143
}

cmd/lassie/lassie.go

-27
This file was deleted.

0 commit comments

Comments
 (0)