@craft-native/android 0.0.197 → 0.0.199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craft-native/android",
3
- "version": "0.0.197",
3
+ "version": "0.0.199",
4
4
  "homepage": "https://github.com/craft-native/craft/tree/main/packages/android#readme",
5
5
  "repository": {
6
6
  "type": "git",
@@ -917,7 +917,7 @@ internal object CraftNativeMedia {
917
917
  }
918
918
 
919
919
  fun local(context: Context, address: String): File? =
920
- address.takeIf { it.isNotBlank() }?.let { file(context, it) }?.takeIf(File::exists)
920
+ address.takeIf { it.isNotBlank() }?.let { file(context, it) }?.takeIf { it.isFile && it.length() > 0 }
921
921
 
922
922
  private fun describe(address: String, file: File) = JSONObject().put("ok", true).put("url", address).put("path", file.absolutePath).put("size", file.length())
923
923
 
@@ -951,15 +951,24 @@ internal object CraftNativeMedia {
951
951
  headers.keys().forEach { name -> connection.setRequestProperty(name, headers.optString(name)) }
952
952
  try {
953
953
  val status = connection.responseCode
954
- if (status !in 200..299) return@runCatching CraftNativeCapabilityResult(data = JSONObject().put("ok", false).put("url", address).put("status", status))
954
+ if (status != 200) return@runCatching CraftNativeCapabilityResult(data = JSONObject().put("ok", false).put("url", address).put("status", status))
955
955
  val target = file(context, address)
956
956
  target.parentFile?.mkdirs()
957
957
  // Written aside and moved into place, so a half-written file is never played.
958
- val staging = File(target.parentFile, "${java.util.UUID.randomUUID()}.part")
959
- connection.inputStream.use { input -> staging.outputStream().use { input.copyTo(it) } }
960
- if (!staging.renameTo(target)) {
958
+ val staging = File(target.parentFile, "${target.name}.part")
959
+ try {
960
+ val size = connection.inputStream.use { input -> staging.outputStream().use { input.copyTo(it) } }
961
+ val expected = connection.contentLengthLong
962
+ if (size <= 0 || (expected >= 0 && size != expected)) {
963
+ return@runCatching CraftNativeCapabilityResult(code = "NETWORK_ERROR", message = "media.keep received an incomplete file")
964
+ }
965
+ synchronized(inFlight) {
966
+ if (!staging.renameTo(target)) {
967
+ return@runCatching CraftNativeCapabilityResult(code = "IO_ERROR", message = "media.keep could not store the file")
968
+ }
969
+ }
970
+ } finally {
961
971
  staging.delete()
962
- return@runCatching CraftNativeCapabilityResult(code = "IO_ERROR", message = "media.keep could not store the file")
963
972
  }
964
973
  CraftNativeCapabilityResult(data = describe(address, target))
965
974
  } finally {
@@ -983,7 +992,14 @@ internal object CraftNativeMedia {
983
992
  fun prune(context: Context, keep: List<String>): Int {
984
993
  val wanted = keep.map { file(context, it).name }.toSet()
985
994
  var removed = 0
986
- root(context).listFiles()?.forEach { file -> if (file.name !in wanted && file.delete()) removed++ }
995
+ synchronized(inFlight) {
996
+ // A concurrent keep owns its target and staging file until it finishes.
997
+ val active = inFlight.keys.map { file(context, it).name }.toSet()
998
+ root(context).listFiles()?.forEach { file ->
999
+ val target = file.name.removeSuffix(".part")
1000
+ if (target !in active && file.name !in wanted && file.delete()) removed++
1001
+ }
1002
+ }
987
1003
  return removed
988
1004
  }
989
1005