1
- using Google . Protobuf ;
2
- using Ipfs . CoreApi ;
3
- using Newtonsoft . Json . Linq ;
1
+ using Ipfs . CoreApi ;
4
2
using System . Collections . Generic ;
5
3
using System . Linq ;
6
4
using System . Threading ;
7
5
using System . Threading . Tasks ;
6
+ using System ;
7
+ using System . IO ;
8
+ using Newtonsoft . Json ;
8
9
10
+ #nullable enable
9
11
namespace Ipfs . Http
10
12
{
11
13
class PinApi : IPinApi
@@ -17,41 +19,174 @@ internal PinApi(IpfsClient ipfs)
17
19
this . ipfs = ipfs ;
18
20
}
19
21
20
- public async Task < IEnumerable < Cid > > AddAsync ( string path , bool recursive = true , CancellationToken cancel = default ( CancellationToken ) )
22
+ public async Task < IEnumerable < Cid > > AddAsync ( string path , PinAddOptions options , CancellationToken cancel = default )
21
23
{
22
- var opts = "recursive=" + recursive . ToString ( ) . ToLowerInvariant ( ) ;
23
- var json = await ipfs . DoCommandAsync ( "pin/add" , cancel , path , opts ) ;
24
- return ( ( JArray ) JObject . Parse ( json ) [ "Pins" ] )
25
- . Select ( p => ( Cid ) ( string ) p ) ;
24
+ options ??= new PinAddOptions ( ) ;
25
+ var optList = new List < string >
26
+ {
27
+ "recursive=" + options . Recursive . ToString ( ) . ToLowerInvariant ( )
28
+ } ;
29
+ if ( ! string . IsNullOrEmpty ( options . Name ) )
30
+ {
31
+ optList . Add ( "name=" + options . Name ) ;
32
+ }
33
+ var json = await ipfs . DoCommandAsync ( "pin/add" , cancel , path , optList . ToArray ( ) ) ;
34
+ var dto = JsonConvert . DeserializeObject < PinChangeResponseDto > ( json ) ;
35
+ var pins = dto ? . Pins ?? new List < string > ( ) ;
36
+ return pins . Select ( p => ( Cid ) p ) ;
26
37
}
27
38
28
- public async Task < IEnumerable < Cid > > ListAsync ( CancellationToken cancel = default ( CancellationToken ) )
39
+ public async Task < IEnumerable < Cid > > AddAsync ( string path , PinAddOptions options , IProgress < BlocksPinnedProgress > progress , CancellationToken cancel = default )
29
40
{
30
- var json = await ipfs . DoCommandAsync ( "pin/ls" , cancel ) ;
31
- var keys = ( JObject ) ( JObject . Parse ( json ) [ "Keys" ] ) ;
32
- return keys
33
- . Properties ( )
34
- . Select ( p => ( Cid ) p . Name ) ;
41
+ options ??= new PinAddOptions ( ) ;
42
+ var optList = new List < string >
43
+ {
44
+ "recursive=" + options . Recursive . ToString ( ) . ToLowerInvariant ( ) ,
45
+ "progress=true"
46
+ } ;
47
+ if ( ! string . IsNullOrEmpty ( options . Name ) )
48
+ {
49
+ optList . Add ( "name=" + options . Name ) ;
50
+ }
51
+ var pinned = new List < Cid > ( ) ;
52
+ var stream = await ipfs . PostDownloadAsync ( "pin/add" , cancel , path , optList . ToArray ( ) ) ;
53
+ using var sr = new StreamReader ( stream ) ;
54
+ while ( ! sr . EndOfStream && ! cancel . IsCancellationRequested )
55
+ {
56
+ var line = await sr . ReadLineAsync ( ) ;
57
+ if ( string . IsNullOrWhiteSpace ( line ) )
58
+ continue ;
59
+ var dto = JsonConvert . DeserializeObject < PinChangeResponseDto > ( line ) ;
60
+ if ( dto is null )
61
+ continue ;
62
+ if ( dto . Progress . HasValue )
63
+ {
64
+ progress ? . Report ( new BlocksPinnedProgress { BlocksPinned = dto . Progress . Value } ) ;
65
+ }
66
+ if ( dto . Pins != null )
67
+ {
68
+ foreach ( var p in dto . Pins )
69
+ {
70
+ pinned . Add ( ( Cid ) p ) ;
71
+ }
72
+ }
73
+ }
74
+ return pinned ;
35
75
}
36
76
37
- public async Task < IEnumerable < Cid > > ListAsync ( PinType type , CancellationToken cancel = default ( CancellationToken ) )
77
+ public async IAsyncEnumerable < PinListItem > ListAsync ( [ System . Runtime . CompilerServices . EnumeratorCancellation ] CancellationToken cancel = default )
38
78
{
39
- var typeOpt = type . ToString ( ) . ToLowerInvariant ( ) ;
40
- var json = await ipfs . DoCommandAsync ( "pin/ls" , cancel ,
41
- null ,
42
- $ "type={ typeOpt } ") ;
43
- var keys = ( JObject ) ( JObject . Parse ( json ) [ "Keys" ] ) ;
44
- return keys
45
- . Properties ( )
46
- . Select ( p => ( Cid ) p . Name ) ;
79
+ // Default non-streaming, no names
80
+ foreach ( var item in await ListItemsOnceAsync ( null , new List < string > ( ) , cancel ) )
81
+ {
82
+ yield return item ;
83
+ }
84
+ }
85
+
86
+ public async IAsyncEnumerable < PinListItem > ListAsync ( PinType type , [ System . Runtime . CompilerServices . EnumeratorCancellation ] CancellationToken cancel = default )
87
+ {
88
+ var opts = new List < string > { $ "type={ type . ToString ( ) . ToLowerInvariant ( ) } " } ;
89
+ foreach ( var item in await ListItemsOnceAsync ( null , opts , cancel ) )
90
+ {
91
+ yield return item ;
92
+ }
93
+ }
94
+
95
+ public async IAsyncEnumerable < PinListItem > ListAsync ( PinListOptions options , [ System . Runtime . CompilerServices . EnumeratorCancellation ] CancellationToken cancel = default )
96
+ {
97
+ options ??= new PinListOptions ( ) ;
98
+ var opts = new List < string > ( ) ;
99
+ if ( options . Type != PinType . All )
100
+ opts . Add ( $ "type={ options . Type . ToString ( ) . ToLowerInvariant ( ) } ") ;
101
+ if ( ! string . IsNullOrEmpty ( options . Name ) )
102
+ {
103
+ opts . Add ( $ "name={ options . Name } ") ;
104
+ opts . Add ( "names=true" ) ;
105
+ }
106
+ else if ( options . Names )
107
+ {
108
+ opts . Add ( "names=true" ) ;
109
+ }
110
+
111
+ if ( options . Stream )
112
+ {
113
+ await foreach ( var item in ListItemsStreamAsync ( null , opts , options . Names , cancel ) )
114
+ {
115
+ yield return item ;
116
+ }
117
+ }
118
+ else
119
+ {
120
+ foreach ( var item in await ListItemsOnceAsync ( null , opts , cancel ) )
121
+ {
122
+ yield return item ;
123
+ }
124
+ }
47
125
}
48
126
49
127
public async Task < IEnumerable < Cid > > RemoveAsync ( Cid id , bool recursive = true , CancellationToken cancel = default ( CancellationToken ) )
50
128
{
51
129
var opts = "recursive=" + recursive . ToString ( ) . ToLowerInvariant ( ) ;
52
130
var json = await ipfs . DoCommandAsync ( "pin/rm" , cancel , id , opts ) ;
53
- return ( ( JArray ) JObject . Parse ( json ) [ "Pins" ] )
54
- . Select ( p => ( Cid ) ( string ) p ) ;
131
+ var dto = JsonConvert . DeserializeObject < PinChangeResponseDto > ( json ) ;
132
+ var pins = dto ? . Pins ?? new List < string > ( ) ;
133
+ return pins . Select ( p => ( Cid ) p ) ;
134
+ }
135
+
136
+ // Internal helper used by ListAsync overloads
137
+
138
+ async IAsyncEnumerable < PinListItem > ListItemsStreamAsync ( string ? path , List < string > opts , bool includeNames , [ System . Runtime . CompilerServices . EnumeratorCancellation ] CancellationToken cancel )
139
+ {
140
+ opts = new List < string > ( opts ) { "stream=true" } ;
141
+ var stream = await ipfs . PostDownloadAsync ( "pin/ls" , cancel , path , opts . ToArray ( ) ) ;
142
+ using var sr = new StreamReader ( stream ) ;
143
+ while ( ! sr . EndOfStream && ! cancel . IsCancellationRequested )
144
+ {
145
+ var line = await sr . ReadLineAsync ( ) ;
146
+ if ( string . IsNullOrWhiteSpace ( line ) )
147
+ continue ;
148
+ var dto = JsonConvert . DeserializeObject < PinLsObjectDto > ( line ) ;
149
+ if ( dto is null || string . IsNullOrEmpty ( dto . Cid ) )
150
+ continue ;
151
+ yield return new PinListItem
152
+ {
153
+ Cid = ( Cid ) dto . Cid ! ,
154
+ Type = ParseType ( dto . Type ) ,
155
+ Name = dto . Name
156
+ } ;
157
+ }
158
+ }
159
+
160
+ async Task < IEnumerable < PinListItem > > ListItemsOnceAsync ( string ? path , List < string > opts , CancellationToken cancel )
161
+ {
162
+ var json = await ipfs . DoCommandAsync ( "pin/ls" , cancel , path , opts . ToArray ( ) ) ;
163
+ var root = JsonConvert . DeserializeObject < PinListResponseDto > ( json ) ;
164
+ var list = new List < PinListItem > ( ) ;
165
+ if ( root ? . Keys != null )
166
+ {
167
+ foreach ( var kv in root . Keys )
168
+ {
169
+ list . Add ( new PinListItem
170
+ {
171
+ Cid = ( Cid ) kv . Key ! ,
172
+ Type = ParseType ( kv . Value ? . Type ) ,
173
+ Name = string . IsNullOrEmpty ( kv . Value ? . Name ) ? null : kv . Value ! . Name
174
+ } ) ;
175
+ }
176
+ }
177
+ return list ;
178
+ }
179
+
180
+ static PinType ParseType ( string ? t )
181
+ {
182
+ return t ? . ToLowerInvariant ( ) switch
183
+ {
184
+ "direct" => PinType . Direct ,
185
+ "indirect" => PinType . Indirect ,
186
+ "recursive" => PinType . Recursive ,
187
+ "all" => PinType . All ,
188
+ _ => PinType . All
189
+ } ;
55
190
}
56
191
57
192
}
0 commit comments