@@ -388,6 +388,75 @@ impl OsError for std::io::Error {
388388
389389pub type Result < T > = std:: result:: Result < T , Error > ;
390390
391+ #[ derive( Diagnostic , Debug , Clone , Error ) ]
392+ #[ diagnostic(
393+ url(
394+ "https://spkenv.dev/error_codes#{}" ,
395+ self . code( ) . unwrap_or_else( || Box :: new( "spfs::generic" ) )
396+ )
397+ ) ]
398+ pub enum PayloadError {
399+ #[ error( "payload did not exist: {0}" ) ]
400+ UnknownPayload ( encoding:: Digest ) ,
401+ #[ error( "invalid digest: {0}" ) ]
402+ InvalidDigest ( String ) ,
403+ #[ error( "storage read error from {0} at {1}: {2}" ) ]
404+ StorageReadError ( & ' static str , std:: path:: PathBuf , #[ source] Arc < io:: Error > ) ,
405+ #[ error( "storage write error from {0} at {1}: {2}" ) ]
406+ StorageWriteError ( & ' static str , std:: path:: PathBuf , #[ source] Arc < io:: Error > ) ,
407+ #[ error( "Cannot write to a repository which has been pinned in time" ) ]
408+ RepositoryIsPinned ,
409+ #[ error( "Error communicating with the server: {0:?}" ) ]
410+ Tonic ( Box < tonic:: Status > ) ,
411+ #[ error( "payload error: {0}" ) ]
412+ String ( String ) ,
413+ }
414+
415+ impl PayloadError {
416+ /// Return true if this error suggests the call might succeed if retried on
417+ /// a secondary repository.
418+ #[ inline]
419+ pub fn try_next_repo ( & self ) -> bool {
420+ matches ! ( self , PayloadError :: UnknownPayload ( _) )
421+ }
422+ }
423+
424+ impl OsError for PayloadError {
425+ fn os_error ( & self ) -> Option < i32 > {
426+ match self {
427+ #[ cfg( unix) ]
428+ Self :: UnknownPayload ( _) => Some ( libc:: ENOENT ) ,
429+ #[ cfg( windows) ]
430+ Self :: UnknownPayload ( _) => {
431+ Some ( windows:: Win32 :: Foundation :: ERROR_FILE_NOT_FOUND . 0 as i32 )
432+ }
433+ Self :: StorageReadError ( _, _, err) => err. os_error ( ) ,
434+ Self :: StorageWriteError ( _, _, err) => err. os_error ( ) ,
435+ _ => None ,
436+ }
437+ }
438+ }
439+
440+ impl From < String > for PayloadError {
441+ fn from ( err : String ) -> Self {
442+ Self :: String ( err)
443+ }
444+ }
445+
446+ impl From < & str > for PayloadError {
447+ fn from ( err : & str ) -> Self {
448+ Self :: String ( err. to_string ( ) )
449+ }
450+ }
451+
452+ impl From < tonic:: Status > for PayloadError {
453+ fn from ( value : tonic:: Status ) -> Self {
454+ PayloadError :: Tonic ( Box :: new ( value) )
455+ }
456+ }
457+
458+ pub type PayloadResult < T > = std:: result:: Result < T , PayloadError > ;
459+
391460#[ derive( Diagnostic , Debug , Clone , Error ) ]
392461#[ diagnostic(
393462 url(
@@ -413,9 +482,9 @@ pub enum SyncError {
413482 #[ error( "manifest '{0}' could not be read: {1}" ) ]
414483 ManifestReadError ( Digest , Arc < Error > ) ,
415484 #[ error( "payload '{0}' could not be read: {1}" ) ]
416- PayloadReadError ( Digest , Arc < Error > ) ,
485+ PayloadReadError ( Digest , Arc < PayloadError > ) ,
417486 #[ error( "payload '{0}' could not be written: {1}" ) ]
418- PayloadWriteError ( Digest , Arc < Error > ) ,
487+ PayloadWriteError ( Digest , Arc < PayloadError > ) ,
419488 #[ error(
420489 "source repository provided payload that did not match the requested digest: wanted {0}, got {1}. wrote {2} bytes"
421490 ) ]
0 commit comments