I apologize in advance if the question seems incomprehensible, since android development and kotlin are not my main stack. I will try to explain in as clear a language as possible.
I have a class that is responsible for intercepting data from HTTP-request. This implementation reflects the following code
class PocketScoutInterceptor() : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val timestamp = System.currentTimeMillis()
val request: Request = chain.request()
val requestTime = System.nanoTime()
val response: Response = chain.proceed(request)
val responseTime = System.nanoTime()
val duration = ((responseTime - requestTime) / 10e6) // in milliseconds
buildPacket(timestamp, duration, request, response)
return response
}
fun buildPacket(timestamp: Long, duration: Double, request: Request, response: Response) {
val reqBody = request.body
val respBody = response.body?.string()
val packet = Packet(
id = 0,
userId = PocketScoutConfig.userId,
deviceId = PocketScoutConfig.deviceId,
sessionId = PocketScoutConfig.sessionId,
timestamp = timestamp,
duration = duration.roundToInt(),
protocol = "http",
request = room.entities.Request(
request_method = request.method,
request_url = request.url.toUrl().toString(),
request_headers = request.headers.toMultimap() as Mapping,
request_body = (reqBody?.toString() ?: ""),
request_size = (reqBody?.toString()?.length ?: 0),
),
room.entities.Response(
response_code = response.code,
response_headers = response.headers.toMultimap() as Mapping,
response_body = (respBody ?: ""),
response_size = (respBody?.length ?: 0),
)
)
}
}
Further, I need to save this data in a local database, I chose room. Created the following implementation:
data class Mapping (
val header: Map<String, List<String>>
)
data class Request(
val request_method: String?,
val request_url: String?,
val request_headers: Mapping?,
val request_body: String,
val request_size: Int,
)
data class Response(
val response_code: Int?,
val response_headers: Mapping?,
val response_body: String?,
val response_size: Int?,
)
@Entity(
tableName = "packets"
)
data class Packet(
@PrimaryKey val id: Int,
val userId: String,
val deviceId: String,
val sessionId: String,
val timestamp: Long?,
val duration: Int?,
val protocol: String?,
@Embedded val request: Request?,
@Embedded val response: Response?,
)
Next I created a database class
@TypeConverters(value = [RoomTypeConverters::class])
@Database(
version = 1,
entities = [Packet::class],
exportSchema = false
)
abstract class NetworkDatabase : RoomDatabase() {
abstract fun packetDao(): PacketDao
}
And himself Dao class that is responsible for all actions with the database
@Dao
interface PacketDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun add(vararg packet: Packet)
@Delete
fun del(vararg packet: Packet)
@Query("SELECT * FROM packets")
fun getAll(): Array<Packet>
@Query("SELECT * FROM packets WHERE userId LIKE :userId")
fun findByUser(userId: String): List<Packet>
@Query("SELECT * FROM packets WHERE sessionId LIKE :deviceId")
fun findByDevice(deviceId: String): List<Packet>
@Query("SELECT * FROM packets WHERE sessionId LIKE :sessionId")
fun findBySession(sessionId: String): List<Packet>
@Query("SELECT * FROM packets WHERE userId LIKE :userId AND deviceId LIKE :deviceId")
fun findByUserAndDevice(userId: String, deviceId: String): List<Packet>
}
I just have to learn how to save data in local storage. I've watched several videos on this topic and read the documentation several times, but as far as my example is concerned, I can't find an answer. Maybe you can help me
CodePudding user response:
1). You need to build the database via the Room databaseBuilder
function/method. The following change to the @Database annotated class would do this and would return a singleton:-
@TypeConverters(value = [RoomTypeConverters::class])
@Database(entities = [Packet::class], version = 1, exportSchema = false)
abstract class NetworkDatabase: RoomDatabase() {
abstract fun packetDao(): PacketDao
companion object {
@Volatile
private var instance: NetworkDatabase? = null;
fun getInstance(context: Context): NetworkDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,NetworkDatabase::class.java,"the_database.db")
.allowMainThreadQueries() /* for brevity/convenience but shouldn't really run stuff on the main thread */
.build()
}
return instance as NetworkDatabase
}
}
}
- Note ideally you would access the database off the main thread. However the above allows the database access to be via the main thread and thus easier to demonstrate.
2). The next stage is to actually use the above, as an example consider the following activity code (working example):-
class MainActivity : AppCompatActivity() {
lateinit var db: NetworkDatabase
lateinit var dao: PacketDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/* Get an instance of NetworkDatabase and the packetDao */
db = NetworkDatabase.getInstance(this)
dao = db.packetDao()
/* add some data (1 row)*/
val m1 = Mapping(header = mapOf())
dao.add(
Packet(
id = 10,
deviceId =
"device10",
sessionId = "session100",
timestamp = System.currentTimeMillis(),
protocol = "HTML",
request = Request(requestMethod = "the method", requestUrl = "blah", requestHeaders = m1,
requestBody = "ReqBody", requestSize = 10),
userId = "userxxx",
duration = 200,
response = Response(100,m1,"RspBody",210)
)
)
/* Extract all rows and write to the log */
for(p in dao.getAll()) {
Log.d("DBINFO","Packet ID is ${p.id} DeviceId is ${p.deviceId} Duration is ${p.duration} ....")
}
}
}
The above, when run (for the first time) results in the log containing :-
D/DBINFO: Packet ID is 10 DeviceId is device10 Duration is 200 ....
Obviously you would build the Packet(s) via your Interceptor