| 1 | package iface |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "iter" |
| 6 | "os" |
| 7 | "time" |
| 8 | |
| 9 | "github.com/ipfs/boxo/files" |
| 10 | "github.com/ipfs/boxo/path" |
| 11 | "github.com/ipfs/go-cid" |
| 12 | "github.com/ipfs/kubo/core/coreiface/options" |
| 13 | ) |
| 14 | |
| 15 | type AddEvent struct { |
| 16 | Name string |
| 17 | Path path.ImmutablePath |
| 18 | Bytes int64 `json:",omitempty"` |
| 19 | Size string `json:",omitempty"` |
| 20 | Mode os.FileMode `json:",omitempty"` |
| 21 | Mtime int64 `json:",omitempty"` |
| 22 | MtimeNsecs int `json:",omitempty"` |
| 23 | } |
| 24 | |
| 25 | // FileType is an enum of possible UnixFS file types. |
| 26 | type FileType int32 |
| 27 | |
| 28 | const ( |
| 29 | // TUnknown means the file type isn't known (e.g., it hasn't been |
| 30 | // resolved). |
| 31 | TUnknown FileType = iota |
| 32 | // TFile is a regular file. |
| 33 | TFile |
| 34 | // TDirectory is a directory. |
| 35 | TDirectory |
| 36 | // TSymlink is a symlink. |
| 37 | TSymlink |
| 38 | ) |
| 39 | |
| 40 | func (t FileType) String() string { |
| 41 | switch t { |
| 42 | case TUnknown: |
| 43 | return "unknown" |
| 44 | case TFile: |
| 45 | return "file" |
| 46 | case TDirectory: |
| 47 | return "directory" |
| 48 | case TSymlink: |
| 49 | return "symlink" |
| 50 | default: |
| 51 | return "<unknown file type>" |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | // DirEntry is a directory entry returned by `Ls`. |
| 56 | type DirEntry struct { |
| 57 | Name string |
| 58 | Cid cid.Cid |
| 59 | |
| 60 | // Only filled when asked to resolve the directory entry. |
| 61 | Size uint64 // The size of the file in bytes (or the size of the symlink). |
| 62 | Type FileType // The type of the file. |
| 63 | Target string // The symlink target (if a symlink). |
| 64 | |
| 65 | Mode os.FileMode |
| 66 | ModTime time.Time |
| 67 | } |
| 68 | |
| 69 | // UnixfsAPI is the basic interface to immutable files in IPFS |
| 70 | // NOTE: This API is heavily WIP, things are guaranteed to break frequently |
| 71 | type UnixfsAPI interface { |
| 72 | // Add imports the data from the reader into merkledag file |
| 73 | // |
| 74 | // TODO: a long useful comment on how to use this for many different scenarios |
| 75 | Add(context.Context, files.Node, ...options.UnixfsAddOption) (path.ImmutablePath, error) |
| 76 | |
| 77 | // Get returns a read-only handle to a file tree referenced by a path |
| 78 | // |
| 79 | // Note that some implementations of this API may apply the specified context |
| 80 | // to operations performed on the returned file |
| 81 | Get(context.Context, path.Path) (files.Node, error) |
| 82 | |
| 83 | // Ls writes the links in a directory to the DirEntry channel. Links aren't |
| 84 | // guaranteed to be returned in order. If an error occurs or the context is |
| 85 | // canceled, the DirEntry channel is closed and an error is returned. |
| 86 | // |
| 87 | // Example: |
| 88 | // |
| 89 | // dirs := make(chan DirEntry) |
| 90 | // lsErr := make(chan error, 1) |
| 91 | // go func() { |
| 92 | // lsErr <- Ls(ctx, p, dirs) |
| 93 | // }() |
| 94 | // for dirEnt := range dirs { |
| 95 | // fmt.Println("Dir name:", dirEnt.Name) |
| 96 | // } |
| 97 | // err := <-lsErr |
| 98 | // if err != nil { |
| 99 | // return fmt.Errorf("error listing directory: %w", err) |
| 100 | // } |
| 101 | Ls(context.Context, path.Path, chan<- DirEntry, ...options.UnixfsLsOption) error |
| 102 | } |
| 103 | |
| 104 | // LsIter returns a go iterator that allows ranging over DirEntry results. |
| 105 | // Iteration stops if the context is canceled or if the iterator yields an |
| 106 | // error. |
| 107 | // |
| 108 | // Example: |
| 109 | // |
| 110 | // for dirEnt, err := LsIter(ctx, ufsAPI, p) { |
| 111 | // if err != nil { |
| 112 | // return fmt.Errorf("error listing directory: %w", err) |
| 113 | // } |
| 114 | // fmt.Println("Dir name:", dirEnt.Name) |
| 115 | // } |
| 116 | func LsIter(ctx context.Context, api UnixfsAPI, p path.Path, opts ...options.UnixfsLsOption) iter.Seq2[DirEntry, error] { |
| 117 | return func(yield func(DirEntry, error) bool) { |
| 118 | ctx, cancel := context.WithCancel(ctx) |
| 119 | defer cancel() // cancel Ls if done iterating early |
| 120 | |
| 121 | dirs := make(chan DirEntry) |
| 122 | lsErr := make(chan error, 1) |
| 123 | go func() { |
| 124 | lsErr <- api.Ls(ctx, p, dirs, opts...) |
| 125 | }() |
| 126 | for dirEnt := range dirs { |
| 127 | if !yield(dirEnt, nil) { |
| 128 | return |
| 129 | } |
| 130 | } |
| 131 | if err := <-lsErr; err != nil { |
| 132 | yield(DirEntry{}, err) |
| 133 | } |
| 134 | } |
| 135 | } |