1 package shark
2 
3 import java.io.File
4 import java.io.IOException
5 import okio.Buffer
6 import okio.BufferedSource
7 import okio.Okio
8 import okio.Source
9 
10 /**
11  * A [DualSourceProvider] that invokes [throwIfCanceled] before every read, allowing
12  * cancellation of IO based work built on top by throwing an exception.
13  */
14 class ThrowingCancelableFileSourceProvider(
15   private val file: File,
16   private val throwIfCanceled: Runnable
17 ) : DualSourceProvider {
18 
openStreamingSourcenull19   override fun openStreamingSource(): BufferedSource {
20     val realSource = Okio.source(file.inputStream())
21     return Okio.buffer(object : Source by realSource {
22       override fun read(
23         sink: Buffer,
24         byteCount: Long
25       ): Long {
26         throwIfCanceled.run()
27         return realSource.read(sink, byteCount)
28       }
29     })
30   }
31 
openRandomAccessSourcenull32   override fun openRandomAccessSource(): RandomAccessSource {
33     val channel = file.inputStream().channel
34     return object : RandomAccessSource {
35       override fun read(
36         sink: Buffer,
37         position: Long,
38         byteCount: Long
39       ): Long {
40         throwIfCanceled.run()
41         return channel.transferTo(position, byteCount, sink)
42       }
43 
44       override fun close() {
45         try {
46           channel.close()
47         } catch (ignored: Throwable) {
48           SharkLog.d(ignored) { "Failed to close file, ignoring" }
49         }
50       }
51     }
52   }
53 }
54