From c4bc1fb4d577f51a69ecdbdd2f8d6602b09a1bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8C=B6=E8=8C=B6?= Date: Sun, 4 Aug 2024 15:30:53 +0800 Subject: [PATCH] feat: support expiration and encryption --- compiler/src/main/kotlin/codegen/CodegenStep.kt | 11 ++++++----- .../kotlin/codegen/PreferencesImplClasses.kt | 17 ++++++++++++++++- .../src/main/kotlin/model/CustomData.kt | 2 +- runtime/src/main/kotlin/Preferences.kt | 14 ++++++++++++++ 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/compiler/src/main/kotlin/codegen/CodegenStep.kt b/compiler/src/main/kotlin/codegen/CodegenStep.kt index 5c283f4..3214be0 100644 --- a/compiler/src/main/kotlin/codegen/CodegenStep.kt +++ b/compiler/src/main/kotlin/codegen/CodegenStep.kt @@ -154,6 +154,12 @@ abstract class CodegenStep { else -> value.takeIf { it.isNotEmpty() } } + fun KSAnnotation?.findIntArgument(name: String) = + when (val value = findArgument(name)?.value as? Int) { + null -> null + else -> value + } + fun FileSpec.write(originatingDeclarations: Iterable) = write(originatingDeclarations.mapNotNull { it.containingFile }.toSet()) @@ -188,7 +194,6 @@ abstract class CodegenStep { ) { val factoryClassName = className("PreferencesFactory") val factoryImplClassName = className("PreferencesFactoryImpl") - val objectTypeConverters = typeConverters.filter { it.classKind == ClassKind.OBJECT } val classTypeConverters = typeConverters.filter { it.classKind != ClassKind.OBJECT } val classTypeConvertersParams = classTypeConverters.map { @@ -198,10 +203,6 @@ abstract class CodegenStep { ) } - // If there are non-singleton TypeConverters, the user needs to manually inject - // them. - val needInjectTypeConverters = objectTypeConverters.isNotEmpty() - fun mutableClassName(raw: KSClassDeclaration) = className("Mutable" + raw.simpleName.asString()) diff --git a/compiler/src/main/kotlin/codegen/PreferencesImplClasses.kt b/compiler/src/main/kotlin/codegen/PreferencesImplClasses.kt index fae77b5..51757f2 100644 --- a/compiler/src/main/kotlin/codegen/PreferencesImplClasses.kt +++ b/compiler/src/main/kotlin/codegen/PreferencesImplClasses.kt @@ -48,6 +48,7 @@ import com.squareup.kotlinpoet.INT import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.LONG import com.squareup.kotlinpoet.MemberName +import com.squareup.kotlinpoet.MemberName.Companion.member import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.SET @@ -70,10 +71,24 @@ class PreferencesImplClasses : CodegenStep() { val mutableImplClassName = context.mutableImplClassName(preferences) val annotation = requireNotNull(preferences.findAnnotation(Preferences)) val id = annotation.findStringArgument("id") ?: preferences.simpleName.asString() + val expires = annotation.findIntArgument("expires") ?: -1 + val cryptKey = annotation.findStringArgument("cryptKey") ?: "" val mmkvPropertySpec = PropertySpec.builder("mmkv", MMKV) .addModifiers(KModifier.OVERRIDE) - .initializer("%T.mmkvWithID(%S)", MMKV, id) + .initializer(buildCodeBlock { + add("%T.mmkvWithID(%S", MMKV, id) + if (cryptKey.isNotEmpty()) { + add(", %M, %S)", MMKV.member("SINGLE_PROCESS_MODE"), cryptKey) + } else { + add(")") + } + if (expires > -1) { + beginControlFlow(".apply·{") + addStatement("enableAutoKeyExpire(%L)", expires) + endControlFlow() + } + }) .build() val defaultPropertySpec = PropertySpec.builder("default", dataClassName) diff --git a/integration-tests/generation/src/main/kotlin/model/CustomData.kt b/integration-tests/generation/src/main/kotlin/model/CustomData.kt index d59e4a2..88fb698 100644 --- a/integration-tests/generation/src/main/kotlin/model/CustomData.kt +++ b/integration-tests/generation/src/main/kotlin/model/CustomData.kt @@ -22,7 +22,7 @@ import com.meowool.mmkv.ktx.PersistDefaultValue import com.meowool.mmkv.ktx.Preferences import java.util.Date -@Preferences +@Preferences(expires = 100, cryptKey = "abc") data class CustomData( @PersistDefaultValue val date: Date = Date(), diff --git a/runtime/src/main/kotlin/Preferences.kt b/runtime/src/main/kotlin/Preferences.kt index 399b981..39851c2 100644 --- a/runtime/src/main/kotlin/Preferences.kt +++ b/runtime/src/main/kotlin/Preferences.kt @@ -73,4 +73,18 @@ annotation class Preferences( * For example: `GeneralSettings` -> `generalSettings`. */ val name: String = "", + + /** + * The expiration time (in milliseconds) for the preferences. + * If set to a value greater than -1, the preferences will expire after the specified time. + * If set to -1 (the default value), the preferences will never expire. + */ + val expires: Int = -1, + + /** + * The encryption key to use for the preferences. + * If set to a non-empty string, the preferences will be encrypted using the specified key. + * If left empty (the default value), the preferences will not be encrypted. + */ + val cryptKey: String = "", )