From 19b6dc8d1e3536729a7e4550275b53b1b0d4c8a1 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Wed, 26 May 2021 19:50:34 -0700 Subject: [PATCH 1/5] feat(cli): add a list retrievals command Currently, there is no way to inspect retrievals on a client. This adds said command, allow with corresponding APIs --- api/api_full.go | 4 + api/mocks/mock_full.go | 30 ++++ api/proxy_gen.go | 20 +++ api/types.go | 19 ++ build/openrpc/full.json.gz | Bin 23305 -> 23431 bytes build/openrpc/miner.json.gz | Bin 7846 -> 7844 bytes build/openrpc/worker.json.gz | Bin 2579 -> 2580 bytes cli/client.go | 187 ++++++++++++++++++++ documentation/en/api-v1-unstable-methods.md | 60 +++++++ documentation/en/cli-lotus.md | 22 +++ node/impl/client/client.go | 78 ++++++++ 11 files changed, 420 insertions(+) diff --git a/api/api_full.go b/api/api_full.go index e524906e3..3dc503f46 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -344,6 +344,10 @@ type FullNode interface { // ClientRetrieveWithEvents initiates the retrieval of a file, as specified in the order, and provides a channel // of status updates. ClientRetrieveWithEvents(ctx context.Context, order RetrievalOrder, ref *FileRef) (<-chan marketevents.RetrievalEvent, error) //perm:admin + // ClientListRetrievals returns information about retrievals made by the local client + ClientListRetrievals(ctx context.Context) ([]RetrievalInfo, error) //perm:write + // ClientGetRetrievalUpdates returns status of updated retrieval deals + ClientGetRetrievalUpdates(ctx context.Context) (<-chan RetrievalInfo, error) //perm:write // ClientQueryAsk returns a signed StorageAsk from the specified miner. ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.StorageAsk, error) //perm:read // ClientCalcCommP calculates the CommP and data size of the specified CID diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index efe5eb89d..71c621846 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -580,6 +580,21 @@ func (mr *MockFullNodeMockRecorder) ClientGetDealUpdates(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientGetDealUpdates", reflect.TypeOf((*MockFullNode)(nil).ClientGetDealUpdates), arg0) } +// ClientGetRetrievalUpdates mocks base method +func (m *MockFullNode) ClientGetRetrievalUpdates(arg0 context.Context) (<-chan api.RetrievalInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientGetRetrievalUpdates", arg0) + ret0, _ := ret[0].(<-chan api.RetrievalInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ClientGetRetrievalUpdates indicates an expected call of ClientGetRetrievalUpdates +func (mr *MockFullNodeMockRecorder) ClientGetRetrievalUpdates(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientGetRetrievalUpdates", reflect.TypeOf((*MockFullNode)(nil).ClientGetRetrievalUpdates), arg0) +} + // ClientHasLocal mocks base method func (m *MockFullNode) ClientHasLocal(arg0 context.Context, arg1 cid.Cid) (bool, error) { m.ctrl.T.Helper() @@ -655,6 +670,21 @@ func (mr *MockFullNodeMockRecorder) ClientListImports(arg0 interface{}) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientListImports", reflect.TypeOf((*MockFullNode)(nil).ClientListImports), arg0) } +// ClientListRetrievals mocks base method +func (m *MockFullNode) ClientListRetrievals(arg0 context.Context) ([]api.RetrievalInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientListRetrievals", arg0) + ret0, _ := ret[0].([]api.RetrievalInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ClientListRetrievals indicates an expected call of ClientListRetrievals +func (mr *MockFullNodeMockRecorder) ClientListRetrievals(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientListRetrievals", reflect.TypeOf((*MockFullNode)(nil).ClientListRetrievals), arg0) +} + // ClientMinerQueryOffer mocks base method func (m *MockFullNode) ClientMinerQueryOffer(arg0 context.Context, arg1 address.Address, arg2 cid.Cid, arg3 *cid.Cid) (api.QueryOffer, error) { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 8880fb24c..6b4dfa4a1 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -179,6 +179,8 @@ type FullNodeStruct struct { ClientGetDealUpdates func(p0 context.Context) (<-chan DealInfo, error) `perm:"write"` + ClientGetRetrievalUpdates func(p0 context.Context) (<-chan RetrievalInfo, error) `perm:"write"` + ClientHasLocal func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"write"` ClientImport func(p0 context.Context, p1 FileRef) (*ImportRes, error) `perm:"admin"` @@ -189,6 +191,8 @@ type FullNodeStruct struct { ClientListImports func(p0 context.Context) ([]Import, error) `perm:"write"` + ClientListRetrievals func(p0 context.Context) ([]RetrievalInfo, error) `perm:"write"` + ClientMinerQueryOffer func(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (QueryOffer, error) `perm:"read"` ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*storagemarket.StorageAsk, error) `perm:"read"` @@ -1293,6 +1297,14 @@ func (s *FullNodeStub) ClientGetDealUpdates(p0 context.Context) (<-chan DealInfo return nil, xerrors.New("method not supported") } +func (s *FullNodeStruct) ClientGetRetrievalUpdates(p0 context.Context) (<-chan RetrievalInfo, error) { + return s.Internal.ClientGetRetrievalUpdates(p0) +} + +func (s *FullNodeStub) ClientGetRetrievalUpdates(p0 context.Context) (<-chan RetrievalInfo, error) { + return nil, xerrors.New("method not supported") +} + func (s *FullNodeStruct) ClientHasLocal(p0 context.Context, p1 cid.Cid) (bool, error) { return s.Internal.ClientHasLocal(p0, p1) } @@ -1333,6 +1345,14 @@ func (s *FullNodeStub) ClientListImports(p0 context.Context) ([]Import, error) { return *new([]Import), xerrors.New("method not supported") } +func (s *FullNodeStruct) ClientListRetrievals(p0 context.Context) ([]RetrievalInfo, error) { + return s.Internal.ClientListRetrievals(p0) +} + +func (s *FullNodeStub) ClientListRetrievals(p0 context.Context) ([]RetrievalInfo, error) { + return *new([]RetrievalInfo), xerrors.New("method not supported") +} + func (s *FullNodeStruct) ClientMinerQueryOffer(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (QueryOffer, error) { return s.Internal.ClientMinerQueryOffer(p0, p1, p2, p3) } diff --git a/api/types.go b/api/types.go index 83de131a2..9d887b0a1 100644 --- a/api/types.go +++ b/api/types.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/lotus/chain/types" datatransfer "github.com/filecoin-project/go-data-transfer" @@ -176,3 +177,21 @@ type MessagePrototype struct { Message types.Message ValidNonce bool } + +type RetrievalInfo struct { + PayloadCID cid.Cid + ID retrievalmarket.DealID + PieceCID *cid.Cid + PricePerByte abi.TokenAmount + UnsealPrice abi.TokenAmount + + Status retrievalmarket.DealStatus + Message string // more information about deal state, particularly errors + Provider peer.ID + BytesReceived uint64 + BytesPaidFor uint64 + TotalPaid abi.TokenAmount + + TransferChannelID *datatransfer.ChannelID + DataTransfer *DataTransferChannel +} diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 394f1998be7c464c835d2474d93a843971cb659d..3a8c7cf9beeb001e4fb8901bc67d32b7ed6cb759 100644 GIT binary patch delta 22762 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 V?h^_Y0>aaiPDr);S{5?Ge*yn0-$noc diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index db17586d0786d2a8dd5de9d00d4de98fc2ce0e10..ed3c7a2a177f95e35e20e9da1ba6d33a9b1602d9 100644 GIT binary patch delta 6052 zcmV;V7hCA2J)}Lbq|>u~0zLtM?y&;espBpg3X!J-vd0Lhfc^9B zbct<-NieyWWJU$5^ZDk$cMXX}9U_gTRq2=t$ieVrCqf9{Dtu=RYU{{1L81_y>46z9 zj;wQumtk=+GlYRl3lWBAI9@eme_nMZhTjj&()uRNGUYyc8D*N%o+SsE1(g|Gzk%g6 ztc99?IBwOF7RQOAZyuSf>>vw^&P*|Z-s4+hQj7D~$e2PO9S>se=qBJT%SU^P#l3+7 zi#-GxdIQb7rCSb*V+2%KEWh(h38+duO%hVOpYejg6hC}GsD;2(KBL4!9$*Uud>5G< zZ7je)8{mU)gPR5VLS$qa1QY55wt!4j5ufva$l*ielISf7!DJ4;Vz%J#zmTinZ$3`` zdUJOE>&Nk5Z_Xxf{~Dj&{0tDe#~vjPN4b0GVQ$$2A2Glv@Tr4<3)!LtAhASSUkGoE zKZ|wp>jDvALfhsoCWeW9(F06GA2}n7x?f05ilu*c96$_+>Dh@%uyy5tm*tpHU9)w*~p zn{>leyJ4!=iugdr9Mz0cDVnu1RD)47--Vry6)sLji=V0qK)&2Q7bxB{9R!rl`*Zu`Mm5R(>KL@W-Z}|6c__wzymKEoOT9*iO z2-nHM+2k7*J|Gs}6jMpDLj4G=vnE-MeH;8eSmy0-@*87}Q1|j@F6kPXSlK|s$cMwo z15J0X-o*~q9Ktm+v4VWV!iU4cuahSTAb*b)ZmL`^JcqmEPQz(k}_O`yteqeucK`?G@ZZ2TvZvE;t}Ux-c=CxHQEyc=J+0w)$_{> z!N`;?kS9h^+cp)&r`q1R3tQQ~9!#oU(nPm+(f^gwPw)SE_~+L@|9y{s{y*lvKYu>+ zy^p`VF+V;0{N~-H_p|?&zQ1|!K3v`Z`hRRzI=Ny`w{-t_IHib1ND+OH*qMJ<0h=U& z>?OaSf}<52QL;V3a}rsrXZ~H@Lf~2hTUq|g>0;``Ca1wbPsIuPIQdbB7OYX z2TWq=4c$(^*D^l9hx9XfJVbb)O@GU{!4C2nbX;Dd+v&E9w+}AnoeF+V(0_lU#%R!c zY8iYCP=2{@hCKVB*D^%9;K=wlu{(cG-YiV=%L4uHzy4)B6+8ed7;1qUVOMq10Fqxr zt489RYSt*1FCr$gaEgeW8J&*BW?85B8iy6@SZ0n$oN)?Fuw<=LyQ^D9;R?e^Hl}<$ zXJ8*HlgaB8D>)Qh68*>1o}!KA3jSI=x2pe20;Oi5X10ouCu>3=)uvz*T>=I|Q% z$h((DY_Z;Ka?(B^1}(_o7_vonf#_KIOwFpS*O)4esj?rYO2~<&KybXA+Sp%|s(X!Q z1-U=Wf!sRpT*I#-&$2)bN?Gx4h0b>b#R`WyvAA9AQ1+s>Ud(pY<62ZS(hvmwF7u%} z>&lP(cCsRNajx@Sx_=h2Q-ALtz|K{jdc3k2YuF#CBBru(*B6mPNamFUf9l)2yE#u( zqstkFuTGuqn!uqj7QIgAdkAC8IA3~R;nn%TJTwt5WghB|^a{UN32MsMz0q->l0NLs4uu8u%$gx{$i-Ik`7sp2#;QL{;HMXmjC`Gu;RHsqJTMn0F9 znl`>>P}|wg*X*`+x4vf729Po2xXcHP0#Ckg_Q5v$V1Ju^usgvm)s-$%UME%e!A?~B zUYb|Y&-#D~ zCi6FZ_DjJ+R9&%aUYZ;?*qtDj8>){J+s+>Ocz4oJu=Z951J1D(Mdw9QQuOO*gy#!p zjPk?n2Nh6L-L@pG2>(4|=a(0m%Og7MwoW8xe}6Y;Kvz^@)I;r{QXU&-G_rLq)a>#8 zj(fZ_ks{4EX}riRqlFrBfu)W?2MaF(d#OyzFqq_P_qU06!**Ug2)0bP}PLrv4NnR$w=7PKfIbeHVr9^eL*oqtF zUlnCU{#BcVMC2OzXyjw7@}auAY-}TIj->7`CmS&W*>VA=xE&e?xuTJzmMs=H$Z-L5 zG3N`wkk2rg7fL$G5|(%`GuPB&FLi9oV1Ea5x6|pgjBsD!X+fiKwGBGg{LPoX~!ChyTTn8=1+({BDcb7XKcm_?>K8Lm)WOj*V*p+D+Li3D(zTkl3N|b-U$7S7uAcCv{_>HGK7S z_DvSN=ti}vg^W=rwvjS<>S@t>N-fW30#X0v8oK_jZ}NtC+a9bzIotE@T{^$Y33 z(wZ-9YA44vH>#~sZF#D#0oev*1AmZJ-QgJ^7beig|5Wj;vk2`7cGuf%@VCL=27ep; z-6#B2T|g@#>;t_IZ-TD?zA-AhLEdD84eU0s+rVxEyZZ#Ys>_8XeqAG2Ioux6CW?7 z-DqQjH(FpXv_J#F4Fm@ee6n$UZ-StGP8|ocG|=e7Z;VPI=nXC%X$N(GU$Saed9ojk zUEUz_-XLv3beAUM4Z&Z$k%28eEzYfxADJi3JdZkp(*rRk-m$vCO z+NRMq`>1UMmp6*0Q8b6CXn#&OF6&Oj8APZa_hv5?Rb|-t@H{q z-m39pyVByHVJ8QvGdfPP7-80|J-JZ%=tANM%q~!^V1HU@aZj z2RI-GeEA;m3AUCt@_^4EL$#fz^ZhQ_iha>kuafUH08kBCvP8oUBLoF~z%on!=qTnsyT@oj? zLEww3fKee>m5*#o3^sjd*4o?c+<+9jow@XFPJ7Des%yg|1`rdEZ1`A>yCX7nvUHqi z4j)HFSIjGTmMtLTvyQ&nk4L75`1}Mc{Dpjln2CcafkQn6ECg*IOwo-0zzm2hH2qM2 ze>9xF=bWyHL`fF;0KL0+)cfepJ!q8+Mr9FFnLMkrCgqIex=5L%x9%#fcXMleciLPq zSAn%vcOuKFyG9PZufo!jK&`ACk=$gquL_FqcaJ1)2L{H>qfWF)3N9J2DDuhwFu;)K zU;>%IXiARE1;nHU%C$4n>Moe>aK- zoX1%th>KQ{q8OQ4&BHaqxq=ic&MiDJMZko%jVvHkjVM$oe#8yoHi6P%46cn{&N)!gzagc=}LpC?wm2LVTBy~qGWsGo#DAuG7> zCK9yv7b3IHe88Cj;MuA=6afz(5mq_+{FCY$sh@uEJ2QjrEulaby76*P14Xi@lOYvY z0aKHD6*_;Ova0I7z!+a#l8JDTtFmlJN9FT;zKvXYhN?1itTDAKBp5pu8*rh=u(`CM z7sUi>@>3FHE4ih1-TElWiH#)gsU&WUI{4RUR!IVR{cNS-K=-p`s$0&c&_>oZnrX^f zKz1wl+Gckw^%0cCbW*xchn-F*mfU@LA+owxSE7G+JA>itljBY+y1GvMeiHoWLdHMG zIAJxle=gO5PUX(Rzt#MwI+b{(zjcMf#c9is zR>*(I7<(ei#b_Dl)NwA15jQ&IkL&PCaDFZqa%_!GkO1v5rQ$7mUU zAP>(lvQjTD31%4D@}BG9+3(~AJ7`58diG;D>|&dN;=R>@|6qEH?kEo!p-i=4vWixX zf5#lvnbK1MJJ!8PYJDSAFl{=YJ|=m&_nKDCiDVEl4c$*-7LnKacKH#vVC zILK$varH)i<3V%d4p5~%vJxwuc9Pgqlsf~s_-2T}KL2Bi3G^P{5|fH3>ByKu9~}>3 z-CWg39 z3{?)z+*jS^8CuYRDOJVZmn77_b}WAqbc+eowe2IaYNI~*1u&UWZr0ZosLkkgrWc+r zqhp$eR_LhP>*P4qHAvN=F|_J>#DHx+x>mJRm4HGa|1}ZE)ks`fwXu_fRGzs*S~QXz z30T=B>?Vcfs^3%HhZjiBnPpv36Q;k3mZT+Vs1McPla?n@DOx)?O~aE>1Py;)O!(ss zLsnr()p|j|0E|JiWHMEp!ln~mkRP@tgOqL$%={(8cKe-(MQXBY*v@9~4;u_3Ulw|( zEkcB!!PJ1~yo^?-$!|4&4^*cuc>jWK5`^Y>xg~z><*mV#(ZgJ5N?Xy_o()t#D_4YcUoD)c;{Wg|j9%LvOp8J=n(-w;*FDEi!DD`OAK{$|x_ z0x8w>;N~UROy(+}0eSsgd;TSOQ99%uG_aHFHul9*&%y?cNNcl1d@#}6=ZrYYOMT=A zFMqPYs{W=;qJe)H-$okp0-3fZ*lavvpq8DYnY~kN7gd$j5os-HR+`#kcj=lfI_hm@ zKk1IH-#PFtqJ8BJIRRr=&HGa&{iVcCBBHLm1ypw+a8Ux_CP^!hC8#T6#w!al_{xQB zVdRL9YG2WTu&DB~nur(fDst#uJyDoyf##qeI}0&4;gx?MB)sx`hS3C|uljxEl|>RJ zu8~VU_A`PutCRs9r=z#97W|S`WOY4cTWe}(7Ygr-Tb>ItYhP9O*aHTc^m6OT&}|tR z#|jh#chwf{u&+%DaK#kh=3dZRFm`irGf0mwjjg=CPH;1kkFV+a1hjwnxaRs^hGwV3 zA;H{%xUPT7o6Dpu-*}Hzz1M)mwjJ0PQ%ZG%p{p)6zHH;mHoojiX9XDo-y>~cUlCGu zr`#v%-68Ls62b+b3_vC*RN8jFPDyQhB}xK@Y+GJDLa2oRqr4094Fz9CQ6F57&uiT4 z+iX_fJqxRDbd${R3!RobVslkpy?nAAu~C8v{_ODp+x zbaXtL4Xx8t*gHBN9=|>sbcd%$!`TcTozBp#GaGh}5kgTSLwJs4Os}UFH-p3g`r0l=(szzjs~yc>!YdJ86Lq|=k=^>_KwkOYjt#44#gYj-*MqZ(0+B_dBs^=9OL$i zYw>^UCHVv~Ge#W|MDdt0GJ2g}=cwB~>h^9rr=wnP)H(UnXc<3Kp9P25B;EAn8N8F%)Zr*+lE@I|y z#*BInTG77UoaDOsldei6&bCV6`irZ4@&B%6eie6D+(CrBFzet8|zYZaemY6K*X-Q eTus?qEip8no^GH1e*gdg|NoyZG4TZAeE|T10-kgL delta 6055 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 diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index d0a18b43acd268400f6888f7f34900d5f665319e..943246923ca199ecdf1a6682f8a0c342242bf704 100644 GIT binary patch literal 2580 zcmV+v3hVVBiwFP!00000|Li?&bJ{xAe?_C`OLNBo0)(b~>qGW-Gt(C~x!rzfG8%wWJDWZnNJ)C41z2A6D;I+P~JD)C9ZR#$Ps#@ zKhiO=p)nw?dvR_d5Q2*%^mNUxl>ik8hGgS{DG-dfjTot#G);&eP@_J&X7g)ydwYv5 zECbIYVut&8HGrA39!6d>Y+;`W;+Z7~gkHwc?AYg$hD#QGomgi7B(<)ol}U`PKiE_7 zh~8&-B%ber!FX}5n?6wn0{2f^t(Jv92i{13dN;T5P;fr}Yvu#)pUrP9OdKa9i?~C< zeGrOjJY(WYu&^I%T3{{#5D~FrL}m!FunGxSe4ejJ+}wA*Y~iCHU@M%QR0#y%7Z`5l z78dY#Km|CsuS5WPGkgIyQMx6Z+}v92Ry(y@IUHMP&sgBPHx{M}BBn^qAUT#<(Kv5H9ZH zsZze|H=C2NOT*?~a~zrZV_$GhSJTxlLv!TvQPU$*foKw+HhsY#XaAW1YfSk6ee85k z+j>rEXW<`=j9hR^`U(+LhO2Od-i$bRH(Br%f^36b!ZK$`t0o~erKoYURO-ErX)_H6 zguQSE=(VyL;7?HYwB+`OFy;Kjm3lPodVK8$gpT6s%OO$IsJR6y~w#?mVU~xJzlTFD*!gxDHDoE@cxOBT6a}wrt0TONntYx;%alm5Hj| zxY~_7G&inymSe>!BQE_3(O#4^=Lz7l`JYAmC1I0F)_HyOg_*9+^InM1KA7h;mXcj>^F?g!eZUgZFVOJ1& zT!!}+r*U&D{8E#Y{jCw)lwbFe+r$lN&-(To(8;t=;J?Lieow{Ww3TyYI27ClDX&0E z!(650A_1H&AVEN##@DZ#{izhPZ1FIFT1gAS9PS~F8}TuE2uVZIz*}en420f>sG~bW z4^v=KziZ~3@sLzRsB#5lS#r0WXKD@O-xN3}DP;I|Qn<9)lpTmH>G|A#8~g`&$pumy7V*YQHvm=XET# zpRv?)hv6yd*kK`Lx79h@O)cchDe0_Z!#XxRu-NeQBzA_1o2p8^(;L;>AB* z8)85mS;2oyPGvncq{pfK$h|OF``|~W+4lhN+~x}6i=Jyb8MUTTb{-UjBMqW6y=YNF zjmZ?caDXW~rg2VQ9qIiKLWJ1Loo-NCTJaXtTFVqe{|Ps>!X)Ead-RjoKspc7nf7KK z(&?#DN8W+w|KN{*`@xKR{*RG2hS|8&9n(%Q>jeRH+xK1LVs8^)NmaQTyxe}qm!S;g zHoc%a-mBxim+aJbb58bG{#@F87j~JwHMO050>iSvm|xqptkX~ zjekWp{xqj@CSeh)#G5PNY9Z&!99NGz6ExI;=UxfYKA7`NUVC{Ky|zoWT{<+o)XOP) zsdlevI~STZ-DLVm?_li;m4!xuLdz>oEUKxA-CNQe>rffKxLMy>dOdfR-sYCBsA|u? zt^o5Kt`X<%hN`Xvl4mNrmfes?#GOQH3JZQF5`p=yx!~&t`pgwlQ=OPr-?A*9gw78%1Z9&=oS(v#&;DBr7Q$pku}47TF9dD#(aqP#iaA;Bzlgj$HwvpH z8^$1WSrCY;wU`WtF%Q%{%Z^E$yJy7|eZ}9VZQi$8^iHteP9mxA0!#`wa*ClUxT@ zppY)mkJQ`doyn{sNa7k$2MImA1g7*a(`TfkZ9Bq297lkZ;2^rh)<73ZFTj`! z4;(a_A%gyGeh|_^1P!g_B0U@SbL`9)@Xb*Yk056|Z}^Zy0_0RR7??FeR1dH?_z=I3+( literal 2579 zcmV+u3hebCiwFP!00000|Li?&bJ{xAe?_C`OLNEJJv8N8AF{WbnZB^e?e;^H*$Ddp zDz@Y+$w_F2|Gp#J7#rKccA-m%r!#F4I!8y+dDoG6!rTQWToVs)yU}U%v4JU@a6EXz ziYgoM0Dt7lljv$RMDItJ*ueK7B<0M9Xtx`!Qw#3#(!dU=8Mh=Je1F1>I2!a%YJ9_IpzpV2OdDUBODqcl1lRN@7|89Syl;9Dt_z~b33{VH z(g`u4F(kHqd0`+Bf{PRMbi;0x0ObjWWaE-45RBN37^#{xO^6;)qdvJ|%NurgcZUru zJ;xzpfd_a!Krm-LjJ#pkz%CKQ36{VUdKt%yQ7;i z-AQ`3(zrv~HdRz6r5hcJ=zu_HJgWz^Fyq$S;LmBsU#ma3l9mXW`Kb`=Zq*JBdAtk| zw)+NlD2sgxI|n?zG-7ipST4T+{G2S z#eBuuDSU-aVIF(#&tuwwyOj3&(t=co>#zi3Q#QphqNEaj%WizQlo%JI%i;G>nW);0 ztKGO`bK`pFIaZu9V$+`x?nOy+o&YYJ|5>$P5jL%4oi|5cnd#a*AA|@Uf_dKHvTC`S z5=;AKGLfK)t*xI}skkr|Ge5Out1a8HS+=u&wq?6y6JFAuX^`yH#O67G?zzoAh1m9z zr^uq`8Np3-Dk8l9>25n6b+lYAhAY8 zhDa=1L4aV%bQ%sTE?7yGdPD@O6_k)Q;{!S=2*tbYD&$s`f!^ zAN1Ia&fAA2Fxg&c5Y2*Ygr-1u-DWvf==S1er~=h_4@yXf=gz>qkn*&Sp-%gY>5;5TMyBrMfh#CUt7KNI+i-j zSn9dM@RW4yu@JJ?>YneX7V_nkbk?z99UC57Z1^tceBughAQHYZ38Z`>>+m?s?yx^ynMtU%lUf&Qxf~i&rLFrGP-8#%M39Uy@ynfUU*5@j~RoC7x!#q zh#|FP1^+QQmCe+U9;fyr55iy_f*+Y?-y^(pn=6PfdamhY)P_pgdr;tyGz`!5!bR~l zCR6Cr0;cGM#yNR?r1w7v5n?NMwnb@a#amEoMJa~C6K-mSNhXWV_$M)ebRVQO>o2;b z+gIbRoP*>3;E#X1-hw;skFhg>#iZMt(5|=Wdmi*U_r1Wy-X*@0s&YMex&4eULm9|j zdO>x(SI2uV*{SX1ob0dtxwQE%>eP11S6AxR(2e}!sbBI#J9Q58(1hm@e9ttOy*z)c zHbk`{Iyys?Q&yuD`ba?a1j`zDCpnglaHpb)N)Q##meiK&Af)RMEY;CxN$Si&ZR2Yj z|B7sUH>YwYVG*mun`_`|A?Mm0SC2XqG}M9TK?%|!nDb0tdwCYUwoA2LIySr1%PD%P zcCTqS7n-)+Wco8VJtC#ON5v5vOQ5C^d=0aAj6XoRhSE|p$@2^S7n zXuLoK{X6(UNCOcxTge7V$Q*eMp3@=O_+rU`lNf! zh@3T&jI*1|0QHY{)CW!VL6h$b_FFlb$xxO{`hg)-c3cywhv)sUHIBW!Cz&^~b^D%d zUbo%toL9Dbhsr)V*~D*zs(*PDR7nPk;4)e0+00BFG@Emx9%yWHb1sp`6t$6>fdE7V pAQqgpNF+SQ{1cjAWVY9qD(ScTc)7e?{x<*s|Np=VL?Tam006&?0`~v_ diff --git a/cli/client.go b/cli/client.go index 84e077943..a0a36cf40 100644 --- a/cli/client.go +++ b/cli/client.go @@ -92,6 +92,7 @@ var clientCmd = &cli.Command{ WithCategory("retrieval", clientFindCmd), WithCategory("retrieval", clientRetrieveCmd), WithCategory("retrieval", clientCancelRetrievalDealCmd), + WithCategory("retrieval", clientListRetrievalsCmd), WithCategory("util", clientCommPCmd), WithCategory("util", clientCarGenCmd), WithCategory("util", clientBalancesCmd), @@ -1209,6 +1210,192 @@ var clientRetrieveCmd = &cli.Command{ }, } +var clientListRetrievalsCmd = &cli.Command{ + Name: "list-retrievals", + Usage: "List retrieval market deals", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"v"}, + Usage: "print verbose deal details", + }, + &cli.BoolFlag{ + Name: "color", + Usage: "use color in display output", + Value: true, + }, + &cli.BoolFlag{ + Name: "show-failed", + Usage: "show failed/failing deals", + }, + &cli.BoolFlag{ + Name: "completed", + Usage: "show completed retrievals", + }, + &cli.BoolFlag{ + Name: "watch", + Usage: "watch deal updates in real-time, rather than a one time list", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPIV1(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + verbose := cctx.Bool("verbose") + color := cctx.Bool("color") + watch := cctx.Bool("watch") + showFailed := cctx.Bool("show-failed") + completed := cctx.Bool("completed") + + localDeals, err := api.ClientListRetrievals(ctx) + if err != nil { + return err + } + + if watch { + updates, err := api.ClientGetRetrievalUpdates(ctx) + if err != nil { + return err + } + + for { + tm.Clear() + tm.MoveCursor(1, 1) + + err = outputRetrievalDeals(ctx, tm.Screen, localDeals, verbose, color, showFailed, completed) + if err != nil { + return err + } + + tm.Flush() + + select { + case <-ctx.Done(): + return nil + case updated := <-updates: + var found bool + for i, existing := range localDeals { + if existing.ID == updated.ID { + localDeals[i] = updated + found = true + break + } + } + if !found { + localDeals = append(localDeals, updated) + } + } + } + } + + return outputRetrievalDeals(ctx, cctx.App.Writer, localDeals, verbose, color, showFailed, completed) + }, +} + +func outputRetrievalDeals(ctx context.Context, out io.Writer, localDeals []lapi.RetrievalInfo, verbose bool, color bool, showFailed bool, completed bool) error { + var deals []api.RetrievalInfo + for _, deal := range localDeals { + if !showFailed && retrievalmarket.IsTerminalError(deal.Status) { + continue + } + if !completed && retrievalmarket.IsTerminalSuccess(deal.Status) { + continue + } + deals = append(deals, deal) + } + + tableColumns := []tablewriter.Column{ + tablewriter.Col("PayloadCID"), + tablewriter.Col("DealId"), + tablewriter.Col("Provider"), + tablewriter.Col("Status"), + tablewriter.Col("PricePerByte"), + tablewriter.Col("Received"), + tablewriter.Col("TotalPaid"), + } + + if verbose { + tableColumns = append(tableColumns, + tablewriter.Col("PieceCID"), + tablewriter.Col("UnsealPrice"), + tablewriter.Col("BytesPaidFor"), + tablewriter.Col("TransferChannelID"), + tablewriter.Col("TransferStatus"), + ) + } + tableColumns = append(tableColumns, tablewriter.NewLineCol("Message")) + + w := tablewriter.New(tableColumns...) + + for _, d := range deals { + w.Write(toRetrievalOutput(d, color, verbose)) + } + + return w.Flush(out) +} + +func toRetrievalOutput(d api.RetrievalInfo, color bool, verbose bool) map[string]interface{} { + + payloadCID := d.PayloadCID.String() + provider := d.Provider.String() + if !verbose { + payloadCID = ellipsis(payloadCID, 8) + provider = ellipsis(provider, 8) + } + + retrievalOutput := map[string]interface{}{ + "PayloadCID": payloadCID, + "DealId": d.ID, + "Provider": provider, + "Status": retrievalStatusString(color, d.Status), + "PricePerByte": types.FIL(d.PricePerByte), + "Received": units.BytesSize(float64(d.BytesReceived)), + "TotalPaid": types.FIL(d.TotalPaid), + "Message": d.Message, + } + + if verbose { + transferChannelID := "" + if d.TransferChannelID != nil { + transferChannelID = d.TransferChannelID.String() + } + transferStatus := "" + if d.DataTransfer != nil { + transferStatus = datatransfer.Statuses[d.DataTransfer.Status] + } + pieceCID := "" + if d.PieceCID != nil { + pieceCID = d.PieceCID.String() + } + + retrievalOutput["PieceCID"] = pieceCID + retrievalOutput["UnsealPrice"] = types.FIL(d.UnsealPrice) + retrievalOutput["BytesPaidFor"] = units.BytesSize(float64(d.BytesPaidFor)) + retrievalOutput["TransferChannelID"] = transferChannelID + retrievalOutput["TransferStatus"] = transferStatus + } + return retrievalOutput +} + +func retrievalStatusString(c bool, status retrievalmarket.DealStatus) string { + s := retrievalmarket.DealStatuses[status] + if !c { + return s + } + + if retrievalmarket.IsTerminalError(status) { + return color.RedString(s) + } + if retrievalmarket.IsTerminalSuccess(status) { + return color.GreenString(s) + } + return s +} + var clientInspectDealCmd = &cli.Command{ Name: "inspect-deal", Usage: "Inspect detailed information about deal's lifecycle and the various stages it goes through", diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index be326b3e8..b62323e4c 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -44,11 +44,13 @@ * [ClientGetDealInfo](#ClientGetDealInfo) * [ClientGetDealStatus](#ClientGetDealStatus) * [ClientGetDealUpdates](#ClientGetDealUpdates) + * [ClientGetRetrievalUpdates](#ClientGetRetrievalUpdates) * [ClientHasLocal](#ClientHasLocal) * [ClientImport](#ClientImport) * [ClientListDataTransfers](#ClientListDataTransfers) * [ClientListDeals](#ClientListDeals) * [ClientListImports](#ClientListImports) + * [ClientListRetrievals](#ClientListRetrievals) * [ClientMinerQueryOffer](#ClientMinerQueryOffer) * [ClientQueryAsk](#ClientQueryAsk) * [ClientRemoveImport](#ClientRemoveImport) @@ -1199,6 +1201,54 @@ Response: } ``` +### ClientGetRetrievalUpdates +ClientGetRetrievalUpdates returns status of updated retrieval deals + + +Perms: write + +Inputs: `null` + +Response: +```json +{ + "PayloadCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ID": 5, + "PieceCID": null, + "PricePerByte": "0", + "UnsealPrice": "0", + "Status": 0, + "Message": "string value", + "Provider": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "BytesReceived": 42, + "BytesPaidFor": 42, + "TotalPaid": "0", + "TransferChannelID": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "DataTransfer": { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": null + } + } +} +``` + ### ClientHasLocal ClientHasLocal indicates whether a certain CID is locally stored. @@ -1266,6 +1316,16 @@ Response: `null` ClientListImports lists imported files and their root CIDs +Perms: write + +Inputs: `null` + +Response: `null` + +### ClientListRetrievals +ClientListRetrievals returns information about retrievals made by the local client + + Perms: write Inputs: `null` diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index f9eb3aac1..1e1d949a1 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -377,6 +377,7 @@ COMMANDS: find Find data in the network retrieve Retrieve data from network cancel-retrieval Cancel a retrieval deal by deal ID; this also cancels the associated transfer + list-retrievals List retrieval market deals STORAGE: deal Initialize storage deal with a miner query-ask Find a miners ask @@ -521,6 +522,27 @@ OPTIONS: ``` +### lotus client list-retrievals +``` +NAME: + lotus client list-retrievals - List retrieval market deals + +USAGE: + lotus client list-retrievals [command options] [arguments...] + +CATEGORY: + RETRIEVAL + +OPTIONS: + --verbose, -v print verbose deal details (default: false) + --color use color in display output (default: true) + --show-failed show failed/failing deals (default: false) + --completed show completed retrievals (default: false) + --watch watch deal updates in real-time, rather than a one time list (default: false) + --help, -h show help (default: false) + +``` + ### lotus client deal ``` NAME: diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 370cde5da..c5d5ebc89 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "sort" "time" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" @@ -835,6 +836,83 @@ func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref return } +func (a *API) ClientListRetrievals(ctx context.Context) ([]api.RetrievalInfo, error) { + deals, err := a.Retrieval.ListDeals() + if err != nil { + return nil, err + } + dataTransfersByID, err := a.transfersByID(ctx) + if err != nil { + return nil, err + } + out := make([]api.RetrievalInfo, 0, len(deals)) + for _, v := range deals { + // Find the data transfer associated with this deal + var transferCh *api.DataTransferChannel + if v.ChannelID != nil { + if ch, ok := dataTransfersByID[*v.ChannelID]; ok { + transferCh = &ch + } + } + out = append(out, a.newRetrievalInfoWithTransfer(transferCh, v)) + } + sort.Slice(out, func(a, b int) bool { + return out[a].ID < out[b].ID + }) + return out, nil +} + +func (a *API) ClientGetRetrievalUpdates(ctx context.Context) (<-chan api.RetrievalInfo, error) { + updates := make(chan api.RetrievalInfo) + + unsub := a.Retrieval.SubscribeToEvents(func(_ rm.ClientEvent, deal rm.ClientDealState) { + updates <- a.newRetrievalInfo(ctx, deal) + }) + + go func() { + defer unsub() + <-ctx.Done() + }() + + return updates, nil +} + +func (a *API) newRetrievalInfoWithTransfer(ch *api.DataTransferChannel, deal rm.ClientDealState) api.RetrievalInfo { + return api.RetrievalInfo{ + PayloadCID: deal.PayloadCID, + ID: deal.ID, + PieceCID: deal.PieceCID, + PricePerByte: deal.PricePerByte, + UnsealPrice: deal.UnsealPrice, + Status: deal.Status, + Message: deal.Message, + Provider: deal.Sender, + BytesReceived: deal.TotalReceived, + BytesPaidFor: deal.BytesPaidFor, + TotalPaid: deal.FundsSpent, + TransferChannelID: deal.ChannelID, + DataTransfer: ch, + } +} + +func (a *API) newRetrievalInfo(ctx context.Context, v rm.ClientDealState) api.RetrievalInfo { + // Find the data transfer associated with this deal + var transferCh *api.DataTransferChannel + if v.ChannelID != nil { + state, err := a.DataTransfer.ChannelState(ctx, *v.ChannelID) + + // Note: If there was an error just ignore it, as the data transfer may + // be not found if it's no longer active + if err == nil { + ch := api.NewDataTransferChannel(a.Host.ID(), state) + ch.Stages = state.Stages() + transferCh = &ch + } + } + + return a.newRetrievalInfoWithTransfer(transferCh, v) +} + type multiStoreRetrievalStore struct { storeID multistore.StoreID store *multistore.Store From 9c2467b17c66b6fe79f181272783e60797d43acc Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Thu, 27 May 2021 11:18:24 -0700 Subject: [PATCH 2/5] fix(cli): patch for output given fil-markets IsTerminalError ahving a bug --- cli/client.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cli/client.go b/cli/client.go index a0a36cf40..91069bc53 100644 --- a/cli/client.go +++ b/cli/client.go @@ -1296,10 +1296,14 @@ var clientListRetrievalsCmd = &cli.Command{ }, } +func isTerminalError(status retrievalmarket.DealStatus) bool { + // should patch this in go-fil-markets but to solve the problem immediate and not have buggy output + return retrievalmarket.IsTerminalError(status) || status == retrievalmarket.DealStatusErrored +} func outputRetrievalDeals(ctx context.Context, out io.Writer, localDeals []lapi.RetrievalInfo, verbose bool, color bool, showFailed bool, completed bool) error { var deals []api.RetrievalInfo for _, deal := range localDeals { - if !showFailed && retrievalmarket.IsTerminalError(deal.Status) { + if !showFailed && isTerminalError(deal.Status) { continue } if !completed && retrievalmarket.IsTerminalSuccess(deal.Status) { @@ -1387,7 +1391,7 @@ func retrievalStatusString(c bool, status retrievalmarket.DealStatus) string { return s } - if retrievalmarket.IsTerminalError(status) { + if isTerminalError(status) { return color.RedString(s) } if retrievalmarket.IsTerminalSuccess(status) { From 9e73e43272b05845fef8bc90a9d4313033efe127 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Thu, 27 May 2021 11:24:08 -0700 Subject: [PATCH 3/5] fix(cli): add one more error state --- cli/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/client.go b/cli/client.go index 91069bc53..b9e7b45ac 100644 --- a/cli/client.go +++ b/cli/client.go @@ -1298,7 +1298,7 @@ var clientListRetrievalsCmd = &cli.Command{ func isTerminalError(status retrievalmarket.DealStatus) bool { // should patch this in go-fil-markets but to solve the problem immediate and not have buggy output - return retrievalmarket.IsTerminalError(status) || status == retrievalmarket.DealStatusErrored + return retrievalmarket.IsTerminalError(status) || status == retrievalmarket.DealStatusErrored || status == retrievalmarket.DealStatusCancelled } func outputRetrievalDeals(ctx context.Context, out io.Writer, localDeals []lapi.RetrievalInfo, verbose bool, color bool, showFailed bool, completed bool) error { var deals []api.RetrievalInfo From 3fbe2b320d72762829608654f0623e48e37b3443 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Thu, 27 May 2021 15:00:31 -0700 Subject: [PATCH 4/5] feat(v0api): add list-retrievals to v0 --- api/v0api/full.go | 4 ++ api/v0api/proxy_gen.go | 20 ++++++++++ api/v0api/v0mocks/mock_full.go | 30 +++++++++++++++ cli/client.go | 2 +- documentation/en/api-v0-methods.md | 62 +++++++++++++++++++++++++++++- 5 files changed, 116 insertions(+), 2 deletions(-) diff --git a/api/v0api/full.go b/api/v0api/full.go index 5e5d61595..076c37013 100644 --- a/api/v0api/full.go +++ b/api/v0api/full.go @@ -326,6 +326,10 @@ type FullNode interface { // of status updates. ClientRetrieveWithEvents(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) //perm:admin // ClientQueryAsk returns a signed StorageAsk from the specified miner. + // ClientListRetrievals returns information about retrievals made by the local client + ClientListRetrievals(ctx context.Context) ([]api.RetrievalInfo, error) //perm:write + // ClientGetRetrievalUpdates returns status of updated retrieval deals + ClientGetRetrievalUpdates(ctx context.Context) (<-chan api.RetrievalInfo, error) //perm:write ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.StorageAsk, error) //perm:read // ClientCalcCommP calculates the CommP and data size of the specified CID ClientDealPieceCID(ctx context.Context, root cid.Cid) (api.DataCIDSize, error) //perm:read diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index bd0da070e..fc2fc4186 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -97,6 +97,8 @@ type FullNodeStruct struct { ClientGetDealUpdates func(p0 context.Context) (<-chan api.DealInfo, error) `perm:"write"` + ClientGetRetrievalUpdates func(p0 context.Context) (<-chan api.RetrievalInfo, error) `perm:"write"` + ClientHasLocal func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"write"` ClientImport func(p0 context.Context, p1 api.FileRef) (*api.ImportRes, error) `perm:"admin"` @@ -107,6 +109,8 @@ type FullNodeStruct struct { ClientListImports func(p0 context.Context) ([]api.Import, error) `perm:"write"` + ClientListRetrievals func(p0 context.Context) ([]api.RetrievalInfo, error) `perm:"write"` + ClientMinerQueryOffer func(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (api.QueryOffer, error) `perm:"read"` ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*storagemarket.StorageAsk, error) `perm:"read"` @@ -716,6 +720,14 @@ func (s *FullNodeStub) ClientGetDealUpdates(p0 context.Context) (<-chan api.Deal return nil, xerrors.New("method not supported") } +func (s *FullNodeStruct) ClientGetRetrievalUpdates(p0 context.Context) (<-chan api.RetrievalInfo, error) { + return s.Internal.ClientGetRetrievalUpdates(p0) +} + +func (s *FullNodeStub) ClientGetRetrievalUpdates(p0 context.Context) (<-chan api.RetrievalInfo, error) { + return nil, xerrors.New("method not supported") +} + func (s *FullNodeStruct) ClientHasLocal(p0 context.Context, p1 cid.Cid) (bool, error) { return s.Internal.ClientHasLocal(p0, p1) } @@ -756,6 +768,14 @@ func (s *FullNodeStub) ClientListImports(p0 context.Context) ([]api.Import, erro return *new([]api.Import), xerrors.New("method not supported") } +func (s *FullNodeStruct) ClientListRetrievals(p0 context.Context) ([]api.RetrievalInfo, error) { + return s.Internal.ClientListRetrievals(p0) +} + +func (s *FullNodeStub) ClientListRetrievals(p0 context.Context) ([]api.RetrievalInfo, error) { + return *new([]api.RetrievalInfo), xerrors.New("method not supported") +} + func (s *FullNodeStruct) ClientMinerQueryOffer(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (api.QueryOffer, error) { return s.Internal.ClientMinerQueryOffer(p0, p1, p2, p3) } diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 7a1fa55db..7bcfaf47c 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -580,6 +580,21 @@ func (mr *MockFullNodeMockRecorder) ClientGetDealUpdates(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientGetDealUpdates", reflect.TypeOf((*MockFullNode)(nil).ClientGetDealUpdates), arg0) } +// ClientGetRetrievalUpdates mocks base method +func (m *MockFullNode) ClientGetRetrievalUpdates(arg0 context.Context) (<-chan api.RetrievalInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientGetRetrievalUpdates", arg0) + ret0, _ := ret[0].(<-chan api.RetrievalInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ClientGetRetrievalUpdates indicates an expected call of ClientGetRetrievalUpdates +func (mr *MockFullNodeMockRecorder) ClientGetRetrievalUpdates(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientGetRetrievalUpdates", reflect.TypeOf((*MockFullNode)(nil).ClientGetRetrievalUpdates), arg0) +} + // ClientHasLocal mocks base method func (m *MockFullNode) ClientHasLocal(arg0 context.Context, arg1 cid.Cid) (bool, error) { m.ctrl.T.Helper() @@ -655,6 +670,21 @@ func (mr *MockFullNodeMockRecorder) ClientListImports(arg0 interface{}) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientListImports", reflect.TypeOf((*MockFullNode)(nil).ClientListImports), arg0) } +// ClientListRetrievals mocks base method +func (m *MockFullNode) ClientListRetrievals(arg0 context.Context) ([]api.RetrievalInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientListRetrievals", arg0) + ret0, _ := ret[0].([]api.RetrievalInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ClientListRetrievals indicates an expected call of ClientListRetrievals +func (mr *MockFullNodeMockRecorder) ClientListRetrievals(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientListRetrievals", reflect.TypeOf((*MockFullNode)(nil).ClientListRetrievals), arg0) +} + // ClientMinerQueryOffer mocks base method func (m *MockFullNode) ClientMinerQueryOffer(arg0 context.Context, arg1 address.Address, arg2 cid.Cid, arg3 *cid.Cid) (api.QueryOffer, error) { m.ctrl.T.Helper() diff --git a/cli/client.go b/cli/client.go index b9e7b45ac..96e7560e5 100644 --- a/cli/client.go +++ b/cli/client.go @@ -1238,7 +1238,7 @@ var clientListRetrievalsCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - api, closer, err := GetFullNodeAPIV1(cctx) + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err } diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index a8b760f8a..ca0c7ddcf 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -44,11 +44,13 @@ * [ClientGetDealInfo](#ClientGetDealInfo) * [ClientGetDealStatus](#ClientGetDealStatus) * [ClientGetDealUpdates](#ClientGetDealUpdates) + * [ClientGetRetrievalUpdates](#ClientGetRetrievalUpdates) * [ClientHasLocal](#ClientHasLocal) * [ClientImport](#ClientImport) * [ClientListDataTransfers](#ClientListDataTransfers) * [ClientListDeals](#ClientListDeals) * [ClientListImports](#ClientListImports) + * [ClientListRetrievals](#ClientListRetrievals) * [ClientMinerQueryOffer](#ClientMinerQueryOffer) * [ClientQueryAsk](#ClientQueryAsk) * [ClientRemoveImport](#ClientRemoveImport) @@ -1197,6 +1199,54 @@ Response: } ``` +### ClientGetRetrievalUpdates +ClientGetRetrievalUpdates returns status of updated retrieval deals + + +Perms: write + +Inputs: `null` + +Response: +```json +{ + "PayloadCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ID": 5, + "PieceCID": null, + "PricePerByte": "0", + "UnsealPrice": "0", + "Status": 0, + "Message": "string value", + "Provider": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "BytesReceived": 42, + "BytesPaidFor": 42, + "TotalPaid": "0", + "TransferChannelID": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "DataTransfer": { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": null + } + } +} +``` + ### ClientHasLocal ClientHasLocal indicates whether a certain CID is locally stored. @@ -1264,6 +1314,17 @@ Response: `null` ClientListImports lists imported files and their root CIDs +Perms: write + +Inputs: `null` + +Response: `null` + +### ClientListRetrievals +ClientQueryAsk returns a signed StorageAsk from the specified miner. +ClientListRetrievals returns information about retrievals made by the local client + + Perms: write Inputs: `null` @@ -1310,7 +1371,6 @@ Response: ``` ### ClientQueryAsk -ClientQueryAsk returns a signed StorageAsk from the specified miner. Perms: read From 93a2530803526431736df7fd776d1827de0786a8 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Tue, 1 Jun 2021 16:02:35 -0700 Subject: [PATCH 5/5] fix(cli): make failed retrievals show by default --- cli/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/client.go b/cli/client.go index 96e7560e5..1dcd59e72 100644 --- a/cli/client.go +++ b/cli/client.go @@ -1227,6 +1227,7 @@ var clientListRetrievalsCmd = &cli.Command{ &cli.BoolFlag{ Name: "show-failed", Usage: "show failed/failing deals", + Value: true, }, &cli.BoolFlag{ Name: "completed",