Skip to content

Commit 440f0e0

Browse files
alanleedevuffoltzl
authored and
uffoltzl
committed
Convert FileIoHandler.java to Kotlin (facebook#50612)
Summary: Pull Request resolved: facebook#50612 Java to Kotlin conversion Changelog: [Internal] Reviewed By: cortinico Differential Revision: D72742937 fbshipit-source-id: b72b51460555226fa7fe99f4ca5290f46c478291
1 parent 5fabed8 commit 440f0e0

File tree

3 files changed

+163
-193
lines changed

3 files changed

+163
-193
lines changed

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3238,9 +3238,9 @@ public abstract interface class com/facebook/react/modules/websocket/WebSocketMo
32383238
public abstract fun onMessage (Lokio/ByteString;Lcom/facebook/react/bridge/WritableMap;)V
32393239
}
32403240

3241-
public class com/facebook/react/packagerconnection/FileIoHandler : java/lang/Runnable {
3241+
public final class com/facebook/react/packagerconnection/FileIoHandler : java/lang/Runnable {
32423242
public fun <init> ()V
3243-
public fun handlers ()Ljava/util/Map;
3243+
public final fun handlers ()Ljava/util/Map;
32443244
public fun run ()V
32453245
}
32463246

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/FileIoHandler.java

Lines changed: 0 additions & 191 deletions
This file was deleted.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.packagerconnection
9+
10+
import android.os.Handler
11+
import android.os.Looper
12+
import android.util.Base64
13+
import com.facebook.common.logging.FLog
14+
import java.io.FileInputStream
15+
import java.io.FileNotFoundException
16+
import java.io.IOException
17+
import org.json.JSONObject
18+
19+
public class FileIoHandler : Runnable {
20+
21+
private class TtlFileInputStream(path: String?) {
22+
private val stream = FileInputStream(path)
23+
private var ttl: Long = System.currentTimeMillis() + FILE_TTL
24+
25+
private fun extendTtl() {
26+
ttl = System.currentTimeMillis() + FILE_TTL
27+
}
28+
29+
fun expiredTtl(): Boolean = System.currentTimeMillis() >= ttl
30+
31+
@Throws(IOException::class)
32+
fun read(size: Int): String {
33+
extendTtl()
34+
val buffer = ByteArray(size)
35+
val bytesRead = stream.read(buffer)
36+
return Base64.encodeToString(buffer, 0, bytesRead, Base64.DEFAULT)
37+
}
38+
39+
@Throws(IOException::class)
40+
fun close() {
41+
stream.close()
42+
}
43+
}
44+
45+
private var nextHandle = 1
46+
private val handler = Handler(Looper.getMainLooper())
47+
private val openFiles: MutableMap<Int, TtlFileInputStream> = mutableMapOf()
48+
private val requestHandlers: MutableMap<String, RequestHandler> = mutableMapOf()
49+
50+
init {
51+
requestHandlers["fopen"] =
52+
object : RequestOnlyHandler() {
53+
override fun onRequest(params: Any?, responder: Responder) {
54+
synchronized(openFiles) {
55+
try {
56+
val paramsObj =
57+
params as JSONObject?
58+
?: throw Exception(
59+
"params must be an object { mode: string, filename: string }")
60+
val mode = paramsObj.optString("mode") ?: throw Exception("missing params.mode")
61+
val filename =
62+
paramsObj.optString("filename") ?: throw Exception("missing params.filename")
63+
require(mode == "r") { "unsupported mode: $mode" }
64+
65+
responder.respond(addOpenFile(filename))
66+
} catch (e: Exception) {
67+
responder.error(e.toString())
68+
}
69+
}
70+
}
71+
}
72+
requestHandlers["fclose"] =
73+
object : RequestOnlyHandler() {
74+
override fun onRequest(params: Any?, responder: Responder) {
75+
synchronized(openFiles) {
76+
try {
77+
if (params !is Number) {
78+
throw Exception("params must be a file handle")
79+
}
80+
val stream =
81+
openFiles[params]
82+
?: throw Exception("invalid file handle, it might have timed out")
83+
84+
openFiles.remove(params)
85+
stream.close()
86+
responder.respond("")
87+
} catch (e: Exception) {
88+
responder.error(e.toString())
89+
}
90+
}
91+
}
92+
}
93+
requestHandlers["fread"] =
94+
object : RequestOnlyHandler() {
95+
override fun onRequest(params: Any?, responder: Responder) {
96+
synchronized(openFiles) {
97+
try {
98+
val paramsObj =
99+
params as JSONObject?
100+
?: throw Exception(
101+
"params must be an object { file: handle, size: number }")
102+
val file = paramsObj.optInt("file")
103+
if (file == 0) {
104+
throw Exception("invalid or missing file handle")
105+
}
106+
val size = paramsObj.optInt("size")
107+
if (size == 0) {
108+
throw Exception("invalid or missing read size")
109+
}
110+
val stream =
111+
openFiles[file]
112+
?: throw Exception("invalid file handle, it might have timed out")
113+
114+
responder.respond(stream.read(size))
115+
} catch (e: Exception) {
116+
responder.error(e.toString())
117+
}
118+
}
119+
}
120+
}
121+
}
122+
123+
public fun handlers(): Map<String, RequestHandler> = requestHandlers
124+
125+
@Throws(FileNotFoundException::class)
126+
private fun addOpenFile(filename: String): Int {
127+
val handle = nextHandle++
128+
openFiles[handle] = TtlFileInputStream(filename)
129+
if (openFiles.size == 1) {
130+
handler.postDelayed(this@FileIoHandler, FILE_TTL)
131+
}
132+
return handle
133+
}
134+
135+
override fun run() {
136+
// clean up files that are past their expiry date
137+
synchronized(openFiles) {
138+
openFiles.entries.removeAll { (_, stream) ->
139+
if (stream.expiredTtl()) {
140+
try {
141+
stream.close()
142+
} catch (e: IOException) {
143+
FLog.e(TAG, "Failed to close expired file", e)
144+
}
145+
true
146+
} else {
147+
false
148+
}
149+
}
150+
151+
if (openFiles.isNotEmpty()) {
152+
handler.postDelayed(this, FILE_TTL)
153+
}
154+
}
155+
}
156+
157+
private companion object {
158+
private val TAG: String = JSPackagerClient::class.java.simpleName
159+
private const val FILE_TTL = 30_000L
160+
}
161+
}

0 commit comments

Comments
 (0)