Recordings interface

This commit is contained in:
relikd
2020-04-02 18:28:20 +02:00
parent 144773ddaa
commit 79f836016a
13 changed files with 690 additions and 98 deletions

View File

@@ -1,6 +1,7 @@
import UIKit
let DBWrp = DBWrapper()
fileprivate var AppDB: SQLiteDatabase? { get { try? SQLiteDatabase.open() } }
class DBWrapper {
private var latestModification: Timestamp = 0
@@ -49,11 +50,11 @@ class DBWrapper {
func initContentOfDB() {
DispatchQueue.global().async {
#if IOS_SIMULATOR
// self.generateTestData()
// DispatchQueue.main.async {
// // dont know why main queue is needed, wont start otherwise
// Timer.repeating(2, call: #selector(self.insertRandomEntry), on: self)
// }
self.generateTestData()
DispatchQueue.main.async {
// dont know why main queue is needed, wont start otherwise
Timer.repeating(2, call: #selector(self.insertRandomEntry), on: self)
}
#endif
self.dataF_init()
self.dataAB_init()
@@ -100,7 +101,7 @@ class DBWrapper {
// MARK: - Partial Update History
@objc private func syncNewestLogs() {
QLog.Debug("\(#function)")
//QLog.Debug("\(#function)")
#if !IOS_SIMULATOR
guard currentVPNState == .on else { return }
#endif
@@ -220,6 +221,25 @@ class DBWrapper {
}
// MARK: - Recordings
func listOfRecordings() -> [Recording] { AppDB?.allRecordings() ?? [] }
func recordingGetCurrent() -> Recording? { AppDB?.ongoingRecording() }
func recordingStartNew() -> Recording? { try? AppDB?.startNewRecording() }
func recordingStopAll() { AppDB?.stopRecordings() }
func recordingUpdate(_ r: Recording) {
AppDB?.updateRecording(r)
NotifyRecordingChanged.post((r, false))
}
func recordingDelete(_ r: Recording) {
if (try? AppDB?.deleteRecording(r)) == true {
NotifyRecordingChanged.post((r, true))
}
}
// MARK: - Helper methods
private func dataA_index(of domain: String) -> Int? {
@@ -270,7 +290,7 @@ extension DBWrapper {
}
@objc private func insertRandomEntry() {
QLog.Debug("Inserting 1 periodic log entry")
//QLog.Debug("Inserting 1 periodic log entry")
try? AppDB?.insertDNSQuery("\(arc4random() % 5).count.test.com", blocked: true)
}
}

View File

@@ -25,12 +25,10 @@ enum SQLiteError: Error {
// MARK: - SQLiteDatabase
var AppDB: SQLiteDatabase? { get { try? SQLiteDatabase.open() } }
class SQLiteDatabase {
private let dbPointer: OpaquePointer?
private init(dbPointer: OpaquePointer?) {
// print("SQLite path: \(basePath!.absoluteString)")
// print("SQLite path: \(URL.internalDB())")
self.dbPointer = dbPointer
}
@@ -133,18 +131,15 @@ private extension SQLiteDatabase {
sqlite3_bind_text(stmt, col, (value as NSString).utf8String, -1, nil) == SQLITE_OK
}
func bindTextOrNil(_ stmt: OpaquePointer, _ col: Int32, _ value: String?) -> Bool {
sqlite3_bind_text(stmt, col, (value == nil) ? nil : (value! as NSString).utf8String, -1, nil) == SQLITE_OK
}
func readText(_ stmt: OpaquePointer, _ col: Int32) -> String? {
let val = sqlite3_column_text(stmt, col)
return (val != nil ? String(cString: val!) : nil)
}
func readGroupedDomain(_ stmt: OpaquePointer) -> GroupedDomain {
GroupedDomain(domain: readText(stmt, 0) ?? "",
total: sqlite3_column_int(stmt, 1),
blocked: sqlite3_column_int(stmt, 2),
lastModified: sqlite3_column_int64(stmt, 3))
}
func allRows<T>(_ stmt: OpaquePointer, _ fn: (OpaquePointer) -> T) -> [T] {
var r: [T] = []
while (sqlite3_step(stmt) == SQLITE_ROW) { r.append(fn(stmt)) }
@@ -162,6 +157,7 @@ extension SQLiteDatabase {
func initScheme() {
try? self.createTable(table: DNSQueryT.self)
try? self.createTable(table: DNSFilterT.self)
try? self.createTable(table: Recording.self)
}
}
@@ -217,6 +213,13 @@ extension SQLiteDatabase {
// MARK: read
func readGroupedDomain(_ stmt: OpaquePointer) -> GroupedDomain {
GroupedDomain(domain: readText(stmt, 0) ?? "",
total: sqlite3_column_int(stmt, 1),
blocked: sqlite3_column_int(stmt, 2),
lastModified: sqlite3_column_int64(stmt, 3))
}
func domainList(since ts: Timestamp = 0) -> [GroupedDomain]? {
try? run(sql: "SELECT domain, COUNT(*), SUM(logOpt&1), MAX(ts) FROM req \(ts == 0 ? "" : "WHERE ts > ?") GROUP BY domain ORDER BY 4 DESC;", bind: {
ts == 0 || self.bindInt64($0, 1, ts)
@@ -302,3 +305,87 @@ extension SQLiteDatabase {
do { try createFilter() } catch { updateFilter() }
}
}
// MARK: - Recordings
struct Recording: SQLTable {
let start: Timestamp
let stop: Timestamp?
var appId: String? = nil
var title: String? = nil
var notes: String? = nil
static var createStatement: String {
return """
CREATE TABLE IF NOT EXISTS rec(
start BIGINT DEFAULT (strftime('%s','now')),
stop BIGINT,
appid VARCHAR(255),
title VARCHAR(255),
notes TEXT
);
"""
}
}
extension SQLiteDatabase {
// MARK: write
func startNewRecording(_ title: String? = nil, appBundle: String? = nil) throws -> Recording {
try run(sql: "INSERT INTO rec (title, appid) VALUES (?, ?);", bind: {
self.bindTextOrNil($0, 1, title) && self.bindTextOrNil($0, 2, appBundle)
}) { stmt -> Recording in
try ifStep(stmt, SQLITE_DONE)
return ongoingRecording()!
}
}
func stopRecordings() {
try? run(sql: "UPDATE rec SET stop = (strftime('%s','now')) WHERE stop IS NULL;", bind: nil) { stmt -> Void in
sqlite3_step(stmt)
}
}
func updateRecording(_ r: Recording) {
try? run(sql: "UPDATE rec SET title = ?, appid = ?, notes = ? WHERE start = ? LIMIT 1;", bind: {
self.bindTextOrNil($0, 1, r.title) && self.bindTextOrNil($0, 2, r.appId)
&& self.bindTextOrNil($0, 3, r.notes) && self.bindInt64($0, 4, r.start)
}) { stmt -> Void in
sqlite3_step(stmt)
}
}
func deleteRecording(_ r: Recording) throws -> Bool {
try run(sql: "DELETE FROM rec WHERE start = ? LIMIT 1;", bind: {
self.bindInt64($0, 1, r.start)
}) {
try ifStep($0, SQLITE_DONE)
return sqlite3_changes(dbPointer) > 0
}
}
// MARK: read
func readRecording(_ stmt: OpaquePointer) -> Recording {
let end = sqlite3_column_int64(stmt, 1)
return Recording(start: sqlite3_column_int64(stmt, 0),
stop: end == 0 ? nil : end,
appId: readText(stmt, 2),
title: readText(stmt, 3),
notes: readText(stmt, 4))
}
func ongoingRecording() -> Recording? {
try? run(sql: "SELECT * FROM rec WHERE stop IS NULL LIMIT 1;", bind: nil) {
try ifStep($0, SQLITE_ROW)
return readRecording($0)
}
}
func allRecordings() -> [Recording]? {
try? run(sql: "SELECT * FROM rec WHERE stop IS NOT NULL;", bind: nil) {
allRows($0) { readRecording($0) }
}
}
}