Implement MAC lookup (#68)

* Implement MAC lookup

* Refine error processing

* Use long to store MAC consistently

* Link back to macvendors.co

* Undo some havoc

* Do not show mac spans for TV

* Show MAC and IP in a consistent order

* Add IP spans by ipinfo.io

* Add SpanFormatter

* Fix IPv6 ipinfo.io link

* Refine SpanFormatter

* Fix pressing the link
This commit is contained in:
Mygod
2019-01-26 21:20:40 +08:00
committed by GitHub
parent 94114f7a4b
commit d4208affbb
38 changed files with 562 additions and 112 deletions

View File

@@ -4,9 +4,11 @@ import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import be.mygod.vpnhotspot.App.Companion.app
@Database(entities = [ClientRecord::class, TrafficRecord::class], version = 1)
@Database(entities = [ClientRecord::class, TrafficRecord::class], version = 2)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
companion object {
@@ -14,6 +16,9 @@ abstract class AppDatabase : RoomDatabase() {
val instance by lazy {
Room.databaseBuilder(app.deviceStorage, AppDatabase::class.java, DB_NAME)
.addMigrations(
Migration2
)
.allowMainThreadQueries()
.build()
}
@@ -21,4 +26,9 @@ abstract class AppDatabase : RoomDatabase() {
abstract val clientRecordDao: ClientRecord.Dao
abstract val trafficRecordDao: TrafficRecord.Dao
object Migration2 : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) =
database.execSQL("ALTER TABLE `ClientRecord` ADD COLUMN `macLookupPending` INTEGER NOT NULL DEFAULT 1")
}
}

View File

@@ -7,13 +7,14 @@ import androidx.room.*
data class ClientRecord(@PrimaryKey
val mac: Long,
var nickname: CharSequence = "",
var blocked: Boolean = false) {
var blocked: Boolean = false,
var macLookupPending: Boolean = true) {
@androidx.room.Dao
abstract class Dao {
@Query("SELECT * FROM `ClientRecord` WHERE `mac` = :mac")
abstract fun lookup(mac: Long): ClientRecord?
abstract suspend fun lookup(mac: Long): ClientRecord?
fun lookupOrDefault(mac: Long) = lookup(mac) ?: ClientRecord(mac)
suspend fun lookupOrDefault(mac: Long) = lookup(mac) ?: ClientRecord(mac)
@Query("SELECT * FROM `ClientRecord` WHERE `mac` = :mac")
abstract fun lookupSync(mac: Long): LiveData<ClientRecord>
@@ -23,7 +24,7 @@ data class ClientRecord(@PrimaryKey
fun update(value: ClientRecord) = check(updateInternal(value) == value.mac)
@Transaction
open fun upsert(mac: Long, operation: ClientRecord.() -> Unit) = lookupOrDefault(mac).apply {
open suspend fun upsert(mac: Long, operation: ClientRecord.() -> Unit) = lookupOrDefault(mac).apply {
operation()
update(this)
}

View File

@@ -50,8 +50,9 @@ fun String.macToLong(): Long = ByteBuffer.allocate(8).run {
long
}
fun Iterable<Byte>.macToString() = joinToString(":") { "%02x".format(it) }
fun Long.macToString(): String = ByteBuffer.allocate(8).run {
order(ByteOrder.LITTLE_ENDIAN)
putLong(this@macToString)
array().take(6).joinToString(":") { "%02x".format(it) }
array().take(6).macToString()
}

View File

@@ -55,8 +55,9 @@ data class TrafficRecord(
SUM(TrafficRecord.receivedBytes) AS receivedBytes
FROM TrafficRecord LEFT JOIN TrafficRecord AS Next ON TrafficRecord.id = Next.previousId
/* We only want to find the last record for each chain so that we don't double count */
WHERE TrafficRecord.mac = :mac AND Next.id IS NULL""")
abstract fun queryStats(mac: Long): ClientStats
WHERE TrafficRecord.mac = :mac AND Next.id IS NULL
""")
abstract suspend fun queryStats(mac: Long): ClientStats
}
}