@@ -13,6 +13,7 @@ import software.amazon.awssdk.services.s3.model.GetObjectRequest
13
13
import software.amazon.awssdk.services.s3.model.HeadObjectRequest
14
14
import java.io.InputStream
15
15
import java.io.SequenceInputStream
16
+ import java.time.Instant
16
17
import java.util.Enumeration
17
18
18
19
internal val AVAILABLE_PROCESSORS = Runtime .getRuntime().availableProcessors()
@@ -35,14 +36,13 @@ public class S3InputStream(
35
36
mutator : (GetObjectRequest .Builder ) -> Unit = {}
36
37
) : InputStream() {
37
38
private val scope = CoroutineScope (Dispatchers .IO )
38
- private val parts = byteRange(
39
- s3.headObject(
40
- HeadObjectRequest .builder()
41
- .bucket(bucket)
42
- .key(key)
43
- .build()
44
- ).get().contentLength()
45
- )
39
+ private val s3Object = s3.headObject(
40
+ HeadObjectRequest .builder()
41
+ .bucket(bucket)
42
+ .key(key)
43
+ .build()
44
+ ).get()
45
+ private val parts = byteRange(s3Object.contentLength())
46
46
private val streams = parts.mapIndexed { i, (begin, end) ->
47
47
scope.async(CoroutineName (" chunk-${i + 1 } " ), CoroutineStart .LAZY ) {
48
48
s3.getObject(
@@ -56,26 +56,38 @@ public class S3InputStream(
56
56
).await().asInputStream()
57
57
}
58
58
}.toMutableList()
59
- private val buffer = SequenceInputStream (
60
- object : Enumeration <InputStream > {
61
- private val iterator = streams.iterator()
59
+ private val buffer: SequenceInputStream by lazy {
60
+ SequenceInputStream (
61
+ object : Enumeration <InputStream > {
62
+ private val iterator = streams.iterator()
62
63
63
- override fun hasMoreElements (): Boolean {
64
- // Starts downloading the next chunks ahead.
65
- streams.take(parallelism).forEach { it.start() }
66
- return iterator.hasNext()
67
- }
64
+ override fun hasMoreElements (): Boolean {
65
+ // Starts downloading the next chunks ahead.
66
+ streams.take(parallelism).forEach { it.start() }
67
+ return iterator.hasNext()
68
+ }
68
69
69
- override fun nextElement (): InputStream = runBlocking {
70
- iterator.use { it.await() }
70
+ override fun nextElement (): InputStream = runBlocking {
71
+ iterator.use { it.await() }
72
+ }
71
73
}
72
- }
73
- )
74
-
75
- override fun read (): Int {
76
- return buffer.read()
74
+ )
77
75
}
78
76
77
+ public val eTag: String? = s3Object.eTag()
78
+ public val contentLength: Long? = s3Object.contentLength()
79
+ public val lastModified: Instant ? = s3Object.lastModified()
80
+ public val metadata: Map <String , String > = s3Object.metadata()
81
+ public val contentType: String? = s3Object.contentType()
82
+ public val contentEncoding: String? = s3Object.contentEncoding()
83
+ public val contentDisposition: String? = s3Object.contentDisposition()
84
+ public val contentLanguage: String? = s3Object.contentLanguage()
85
+ public val versionId: String? = s3Object.versionId()
86
+ public val cacheControl: String? = s3Object.cacheControl()
87
+ public val expires: Instant ? = s3Object.expires()
88
+
89
+ override fun read (): Int = buffer.read()
90
+
79
91
override fun close () {
80
92
buffer.close()
81
93
}
0 commit comments