<lambda>null1 package expo.modules.updates.manifest
2
3 import android.util.Log
4 import expo.modules.jsonutils.require
5 import expo.modules.structuredheaders.Dictionary
6 import expo.modules.structuredheaders.StringItem
7 import expo.modules.updates.UpdatesConfiguration
8 import expo.modules.updates.db.UpdatesDatabase
9 import org.json.JSONObject
10
11 /**
12 * Utility methods for reading and writing JSON metadata from manifests (e.g. `serverDefinedHeaders`
13 * and `manifestFilters`, both used for rollouts) to and from SQLite.
14 */
15 object ManifestMetadata {
16 private val TAG = ManifestMetadata::class.java.simpleName
17
18 private const val EXTRA_PARAMS_KEY = "extraParams"
19 private const val MANIFEST_SERVER_DEFINED_HEADERS_KEY = "serverDefinedHeaders"
20 private const val MANIFEST_FILTERS_KEY = "manifestFilters"
21
22 private fun getJSONObject(
23 key: String,
24 database: UpdatesDatabase,
25 configuration: UpdatesConfiguration
26 ): JSONObject? {
27 return try {
28 val jsonString = database.jsonDataDao()!!
29 .loadJSONStringForKey(key, configuration.scopeKey!!)
30 if (jsonString != null) JSONObject(jsonString) else null
31 } catch (e: Exception) {
32 Log.e(TAG, "Error retrieving $key from database", e)
33 null
34 }
35 }
36
37 @JvmStatic fun getServerDefinedHeaders(
38 database: UpdatesDatabase,
39 configuration: UpdatesConfiguration
40 ): JSONObject? {
41 return getJSONObject(MANIFEST_SERVER_DEFINED_HEADERS_KEY, database, configuration)
42 }
43
44 fun getManifestFilters(
45 database: UpdatesDatabase,
46 configuration: UpdatesConfiguration
47 ): JSONObject? {
48 return getJSONObject(MANIFEST_FILTERS_KEY, database, configuration)
49 }
50
51 fun getExtraParams(
52 database: UpdatesDatabase,
53 configuration: UpdatesConfiguration
54 ): Map<String, String>? {
55 return getJSONObject(EXTRA_PARAMS_KEY, database, configuration)?.asStringStringMap()
56 }
57
58 fun setExtraParam(
59 database: UpdatesDatabase,
60 configuration: UpdatesConfiguration,
61 key: String,
62 value: String?
63 ) {
64 // this is done within a transaction to ensure consistency
65 database.jsonDataDao()!!.updateJSONStringForKey(EXTRA_PARAMS_KEY, configuration.scopeKey!!) { previousValue ->
66 val jsonObject = previousValue?.let { JSONObject(it) }
67 val extraParamsToWrite = (jsonObject?.asStringStringMap()?.toMutableMap() ?: mutableMapOf()).also {
68 if (value != null) {
69 it[key] = value
70 } else {
71 it.remove(key)
72 }
73 }.toMap()
74
75 // ensure that this can be serialized to a structured-header dictionary
76 // this will throw for invalid values
77 Dictionary.valueOf(extraParamsToWrite.mapValues { elem -> StringItem.valueOf(elem.value) }).serialize()
78
79 JSONObject(extraParamsToWrite).toString()
80 }
81 }
82
83 fun saveMetadata(
84 responseHeaderData: ResponseHeaderData,
85 database: UpdatesDatabase,
86 configuration: UpdatesConfiguration
87 ) {
88 val fieldsToSet = mutableMapOf<String, String>()
89 if (responseHeaderData.serverDefinedHeaders != null) {
90 fieldsToSet[MANIFEST_SERVER_DEFINED_HEADERS_KEY] = responseHeaderData.serverDefinedHeaders.toString()
91 }
92 if (responseHeaderData.manifestFilters != null) {
93 fieldsToSet[MANIFEST_FILTERS_KEY] = responseHeaderData.manifestFilters.toString()
94 }
95 if (fieldsToSet.isNotEmpty()) {
96 database.jsonDataDao()!!.setMultipleFields(fieldsToSet, configuration.scopeKey!!)
97 }
98 }
99
100 private fun JSONObject.asStringStringMap(): Map<String, String> {
101 return buildMap {
102 this@asStringStringMap.keys().asSequence().forEach { key ->
103 this[key] = this@asStringStringMap.require(key)
104 }
105 }
106 }
107 }
108