Skip to content

Commit

Permalink
Release 3.2.0 (#491)
Browse files Browse the repository at this point in the history
* fix: p2p scheme ignore for http.

* feat: add swarm resources command

* feat: todo, add mode and mtime for file

* feat: complete swarm resources cmd.

* feat: gateway cid filter

* test: swarm resources test.

* feat: cidstore list size.

* feat: add mtime and mode for file command.

* feat: files command add mode and mtime

* feat: cidstore add batch support

* feat: file stats ouput add mtime and mode.

* feat: ls add mtime and mode.

* feat: add file rbset can't with preserve-motime.

* feat: ls command out format mode and mtime.

* feat: two step check need token auth enable.

* refactor: http interceptor.

* feat: update go.mod for mtime and mode

* chore: delete debug log.

* feat: update go-btfs-files dependency.

* feat: update btfs config version for bootstramp peers replace

* feat: update dashboard cid and btfs version.

* chore: comment for cid.

* fix: http interceptor token valid

* feat: go.sum update.

* fix: add cid check

* fix: cid check.

* feat: update go.mod

* feat: update dashboard cid.

* fix: cid is empty str.

* chore: dashboard cid.

---------

Co-authored-by: cody <[email protected]>
Co-authored-by: Cody <[email protected]>
Co-authored-by: cody <[email protected]>
  • Loading branch information
4 people authored Jan 2, 2025
1 parent c0cc0bc commit a76a30e
Show file tree
Hide file tree
Showing 21 changed files with 953 additions and 61 deletions.
67 changes: 65 additions & 2 deletions core/commands/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"math/big"
"os"
"path"
"strconv"
"strings"
"time"

"github.com/bittorrent/go-btfs/chain/abi"
chainconfig "github.com/bittorrent/go-btfs/chain/config"
Expand All @@ -32,11 +34,30 @@ import (
// ErrDepthLimitExceeded indicates that the max depth has been exceeded.
var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")

type TimeParts struct {
t *time.Time
}

func (t TimeParts) MarshalJSON() ([]byte, error) {
return t.t.MarshalJSON()
}

// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *TimeParts) UnmarshalJSON(data []byte) (err error) {
// Fractional seconds are handled implicitly by Parse.
tt, err := time.Parse("\"2006-01-02T15:04:05Z\"", string(data))
*t = TimeParts{&tt}
return
}

type AddEvent struct {
Name string
Hash string `json:",omitempty"`
Bytes int64 `json:",omitempty"`
Size string `json:",omitempty"`
Mode string `json:",omitempty"`
Mtime int64 `json:",omitempty"`
}

const (
Expand All @@ -61,6 +82,10 @@ const (
peerIdName = "peer-id"
pinDurationCountOptionName = "pin-duration-count"
uploadToBlockchainOptionName = "to-blockchain"
preserveModeOptionName = "preserve-mode"
preserveMtimeOptionName = "preserve-mtime"
modeOptionName = "mode"
mtimeOptionName = "mtime"
)

const adderOutChanSize = 8
Expand Down Expand Up @@ -168,6 +193,10 @@ only-hash, and progress/status related flags) will change the final hash.
cmds.StringOption(peerIdName, "The peer id to encrypt the file."),
cmds.IntOption(pinDurationCountOptionName, "d", "Duration for which the object is pinned in days.").WithDefault(0),
cmds.BoolOption(uploadToBlockchainOptionName, "add file meta to blockchain").WithDefault(false),
cmds.BoolOption(preserveModeOptionName, "Apply existing POSIX permissions to created UnixFS entries. Disables raw-leaves. (experimental)"),
cmds.BoolOption(preserveMtimeOptionName, "Apply existing POSIX modification time to created UnixFS entries. Disables raw-leaves. (experimental)"),
cmds.UintOption(modeOptionName, "Custom POSIX file mode to store in created UnixFS entries. Disables raw-leaves. (experimental)"),
cmds.Int64Option(mtimeOptionName, "Custom POSIX modification time to store in created UnixFS entries (seconds before or after the Unix Epoch). Disables raw-leaves. (experimental)"),
},
PreRun: func(req *cmds.Request, env cmds.Environment) error {
quiet, _ := req.Options[quietOptionName].(bool)
Expand Down Expand Up @@ -214,6 +243,10 @@ only-hash, and progress/status related flags) will change the final hash.
peerId, _ := req.Options[peerIdName].(string)
pinDuration, _ := req.Options[pinDurationCountOptionName].(int)
uploadToBlockchain, _ := req.Options[uploadToBlockchainOptionName].(bool)
preserveMode, _ := req.Options[preserveModeOptionName].(bool)
preserveMtime, _ := req.Options[preserveMtimeOptionName].(bool)
mode, _ := req.Options[modeOptionName].(uint)
mtime, _ := req.Options[mtimeOptionName].(int64)

hashFunCode, ok := mh.Names[strings.ToLower(hashFunStr)]
if !ok {
Expand Down Expand Up @@ -250,6 +283,9 @@ only-hash, and progress/status related flags) will change the final hash.

options.Unixfs.TokenMetadata(tokenMetadata),
options.Unixfs.PinDuration(int64(pinDuration)),

options.Unixfs.PreserveMode(preserveMode),
options.Unixfs.PreserveMtime(preserveMtime),
}

if cidVerSet {
Expand All @@ -260,6 +296,19 @@ only-hash, and progress/status related flags) will change the final hash.
opts = append(opts, options.Unixfs.RawLeaves(rawblks))
}

// Storing optional mode or mtime (UnixFS 1.5) requires root block
// to always be 'dag-pb' and not 'raw'. Below adjusts raw-leaves setting, if possible.
if preserveMode || preserveMtime || mode != 0 || mtime != 0 {
// Error if --raw-leaves flag was explicitly passed by the user.
// (let user make a decision to manually disable it and retry)
if rbset && rawblks {
return fmt.Errorf("%s can't be used with UnixFS metadata like mode or modification time", rawLeavesOptionName)
}
// No explicit preference from user, disable raw-leaves and continue
rbset = true
rawblks = false
}

if trickle {
opts = append(opts, options.Unixfs.Layout(options.TrickleLayout))
}
Expand All @@ -270,6 +319,13 @@ only-hash, and progress/status related flags) will change the final hash.
opts = append(opts, options.Unixfs.PeerId(peerId))
}

if mode != 0 {
opts = append(opts, options.Unixfs.Mode(os.FileMode(mode)))
}
if mtime != 0 {
opts = append(opts, options.Unixfs.Mtime(mtime))
}

opts = append(opts, nil) // events option placeholder

var added int
Expand Down Expand Up @@ -304,12 +360,19 @@ only-hash, and progress/status related flags) will change the final hash.
output.Name = path.Join(addit.Name(), output.Name)
}

if err := res.Emit(&AddEvent{
addEvent := AddEvent{
Name: output.Name,
Hash: h,
Bytes: output.Bytes,
Size: output.Size,
}); err != nil {
Mtime: output.Mtime,
}

if output.Mode != 0 {
addEvent.Mode = "0" + strconv.FormatUint(uint64(output.Mode), 8)
}

if err := res.Emit(&addEvent); err != nil {
return err
}
}
Expand Down
235 changes: 235 additions & 0 deletions core/commands/cidstore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package commands

import (
"fmt"
"io"
"strings"

cmds "github.com/bittorrent/go-btfs-cmds"
"github.com/bittorrent/go-btfs/core/commands/cmdenv"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
)

const (
SizeOptionName = "size"
batchOptionName = "batch"
)

const (
FilterKeyPrefix = "/gateway/filter/cid"
)

const (
cidSeparator = ","
)

var CidStoreCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Manage cid stored in this node but don't want to be get by gateway api.",
ShortDescription: "Commands for generate, update, get and list access-keys stored in this node.",
},
Subcommands: map[string]*cmds.Command{
"add": addCidCmd,
"del": delCidCmd,
"get": getCidCmd,
"has": hasCidCmd,
"list": listCidCmd,
},
NoLocal: true,
}

var addCidCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Add cid to store.",
},
Options: []cmds.Option{
cmds.BoolOption(batchOptionName, "b", "batch add cids, cids split by , and all exits will be deleted").WithDefault(false),
},
Arguments: []cmds.Argument{
cmds.StringArg("cid", true, false, "cid to add to store"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
return err
}

batch, _ := req.Options[batchOptionName].(bool)
if batch {
cids := strings.Split(req.Arguments[0], cidSeparator)
batch, err := nd.Repo.Datastore().Batch(req.Context)
if err != nil {
return cmds.EmitOnce(res, err.Error())
}

// check if all cid is valid if not return
err = validateCIDs(cids)
if err != nil {
return cmds.EmitOnce(res, err.Error())
}

// delete all exits
results, err := nd.Repo.Datastore().Query(req.Context, query.Query{
Prefix: FilterKeyPrefix,
})
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
for v := range results.Next() {
err = batch.Delete(req.Context, datastore.NewKey(NewGatewayFilterKey(string(v.Value))))
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
}

for _, v := range cids {
if v == "" {
continue
}
err = batch.Put(req.Context, datastore.NewKey(NewGatewayFilterKey(v)), []byte(v))
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
}
err = batch.Commit(req.Context)
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
return cmds.EmitOnce(res, "Add batch ok.")
}

cid := req.Arguments[0]
err = validateCIDs([]string{cid})
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
err = nd.Repo.Datastore().Put(req.Context, datastore.NewKey(NewGatewayFilterKey(cid)),
[]byte(req.Arguments[0]))
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
return cmds.EmitOnce(res, "Add ok.")
},
}

var getCidCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Get cid from store.",
},
Arguments: []cmds.Argument{
cmds.StringArg("cid", true, false, "cid to add to store"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
return err
}
v, err := nd.Repo.Datastore().Get(req.Context, datastore.NewKey(NewGatewayFilterKey(req.Arguments[0])))
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
return cmds.EmitOnce(res, string(v))
},
}

var delCidCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Delete cid from store.",
},
Arguments: []cmds.Argument{
cmds.StringArg("cid", true, false, "cid to add to store"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
return err
}
err = nd.Repo.Datastore().Delete(req.Context, datastore.NewKey(NewGatewayFilterKey(req.Arguments[0])))
if err != nil {
return cmds.EmitOnce(res, err.Error())
}
return cmds.EmitOnce(res, "Del ok.")
},
}

var hasCidCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Check cid exits in store",
},
Arguments: []cmds.Argument{
cmds.StringArg("cid", true, false, "cid to add to store"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
return err
}
exits, err := nd.Repo.Datastore().Has(req.Context, datastore.NewKey(NewGatewayFilterKey(req.Arguments[0])))
if err != nil {
return err
}
if !exits {
return cmds.EmitOnce(res, "Cid not exits")
}
return cmds.EmitOnce(res, "Cid exits")
},
}

var listCidCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "List all cids in store",
},
Options: []cmds.Option{
cmds.IntOption(SizeOptionName, "s", "Number of cids to return."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
return err
}
size, _ := req.Options[SizeOptionName].(int)
results, err := nd.Repo.Datastore().Query(req.Context, query.Query{
Prefix: FilterKeyPrefix,
Limit: size,
})
if err != nil {
return err
}
var resStr []string
for v := range results.Next() {
resStr = append(resStr, string(v.Value))
}
return cmds.EmitOnce(res, resStr)
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, cids []string) error {
for _, v := range cids {
_, err := w.Write([]byte(v + "\n"))
if err != nil {
return err
}
}
return nil
}),
},
Type: []string{},
}

func NewGatewayFilterKey(key string) string {
return fmt.Sprintf("%s/%s", FilterKeyPrefix, key)
}

func validateCIDs(cids []string) error {
for _, c := range cids {
if c == "" {
continue
}
_, err := cid.Decode(c)
if err != nil {
return fmt.Errorf("Invalid CID: %s", c)
}
}
return nil
}
7 changes: 7 additions & 0 deletions core/commands/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ func TestCommands(t *testing.T) {
"/swarm/filters/add",
"/swarm/filters/rm",
"/swarm/peers",
"/swarm/resources",
"/urlstore",
"/urlstore/add",
"/version",
Expand Down Expand Up @@ -364,6 +365,12 @@ func TestCommands(t *testing.T) {
"/dashboard/logout",
"/dashboard/change",
"/dashboard/validate",
"/cidstore",
"/cidstore/add",
"/cidstore/get",
"/cidstore/has",
"/cidstore/del",
"/cidstore/list",
}

cmdSet := make(map[string]struct{})
Expand Down
Loading

0 comments on commit a76a30e

Please sign in to comment.