Recording details duplicate and display

This commit is contained in:
relikd
2020-04-08 18:53:00 +02:00
parent e7560479ee
commit d0056c0275
8 changed files with 120 additions and 51 deletions

View File

@@ -14,7 +14,7 @@ public class SOCKS5Adapter: AdapterSocket {
var internalStatus: SOCKS5AdapterStatus = .invalid
let helloData = Data(bytes: UnsafePointer<UInt8>(([0x05, 0x01, 0x00] as [UInt8])), count: 3)
let helloData = Data([0x05, 0x01, 0x00])
public enum ReadTag: Int {
case methodResponse = -20000, connectResponseFirstPart, connectResponseSecondPart

View File

@@ -48,6 +48,7 @@ class DBWrapper {
// MARK: - Init
func initContentOfDB() {
QLog.Debug("SQLite path: \(URL.internalDB())")
DispatchQueue.global().async {
#if IOS_SIMULATOR
self.generateTestData()
@@ -226,7 +227,9 @@ class DBWrapper {
func listOfRecordings() -> [Recording] { AppDB?.allRecordings() ?? [] }
func recordingGetCurrent() -> Recording? { AppDB?.ongoingRecording() }
func recordingStartNew() -> Recording? { try? AppDB?.startNewRecording() }
func recordingStopAll() { AppDB?.stopRecordings() }
func recordingStop(_ r: inout Recording) { AppDB?.stopRecording(&r) }
func recordingPersist(_ r: Recording) { AppDB?.persistRecordingLogs(r) }
func recordingUpdate(_ r: Recording) {
AppDB?.updateRecording(r)
@@ -239,6 +242,10 @@ class DBWrapper {
}
}
func recordingDetails(_ r: Recording) -> [(domain: String?, count: Int32)]? {
AppDB?.getRecordingsLogs(r)
}
// MARK: - Helper methods

View File

@@ -9,7 +9,7 @@ struct GroupedDomain {
struct FilterOptions: OptionSet {
let rawValue: Int32
static let none = FilterOptions(rawValue: 0)
static let none = FilterOptions([])
static let blocked = FilterOptions(rawValue: 1 << 0)
static let ignored = FilterOptions(rawValue: 1 << 1)
static let any = FilterOptions(rawValue: 0b11)
@@ -28,7 +28,6 @@ enum SQLiteError: Error {
class SQLiteDatabase {
private let dbPointer: OpaquePointer?
private init(dbPointer: OpaquePointer?) {
// print("SQLite path: \(URL.internalDB())")
self.dbPointer = dbPointer
}
@@ -158,6 +157,7 @@ extension SQLiteDatabase {
try? self.createTable(table: DNSQueryT.self)
try? self.createTable(table: DNSFilterT.self)
try? self.createTable(table: Recording.self)
try? self.createTable(table: RecordingLog.self)
}
}
@@ -172,9 +172,9 @@ private struct DNSQueryT: SQLTable {
static var createStatement: String {
return """
CREATE TABLE IF NOT EXISTS req(
ts BIGINT DEFAULT (strftime('%s','now')),
domain VARCHAR(255) NOT NULL,
logOpt INT DEFAULT 0
ts INTEGER DEFAULT (strftime('%s','now')),
domain TEXT NOT NULL,
logOpt INTEGER DEFAULT 0
);
"""
}
@@ -254,8 +254,8 @@ private struct DNSFilterT: SQLTable {
static var createStatement: String {
return """
CREATE TABLE IF NOT EXISTS filter(
domain VARCHAR(255) UNIQUE NOT NULL,
opt INT DEFAULT 0
domain TEXT UNIQUE NOT NULL,
opt INTEGER DEFAULT 0
);
"""
}
@@ -310,6 +310,7 @@ extension SQLiteDatabase {
// MARK: - Recordings
struct Recording: SQLTable {
let id: sqlite3_int64
let start: Timestamp
let stop: Timestamp?
var appId: String? = nil
@@ -318,10 +319,11 @@ struct Recording: SQLTable {
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),
id INTEGER PRIMARY KEY,
start INTEGER DEFAULT (strftime('%s','now')),
stop INTEGER,
appid TEXT,
title TEXT,
notes TEXT
);
"""
@@ -332,33 +334,37 @@ 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
func startNewRecording() throws -> Recording {
try run(sql: "INSERT INTO rec (stop) VALUES (NULL);", bind: nil) { stmt -> Recording in
try ifStep(stmt, SQLITE_DONE)
return ongoingRecording()!
return try getRecording(withID: sqlite3_last_insert_rowid(dbPointer))
}
}
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 stopRecording(_ r: inout Recording) {
guard r.stop == nil else { return }
let theID = r.id
try? run(sql: "UPDATE rec SET stop = (strftime('%s','now')) WHERE id = ? LIMIT 1;", bind: {
self.bindInt64($0, 1, theID)
}) { stmt -> Void in
try ifStep(stmt, SQLITE_DONE)
r = try getRecording(withID: theID)
}
}
func updateRecording(_ r: Recording) {
try? run(sql: "UPDATE rec SET title = ?, appid = ?, notes = ? WHERE start = ? LIMIT 1;", bind: {
try? run(sql: "UPDATE rec SET title = ?, appid = ?, notes = ? WHERE id = ? 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)
&& self.bindTextOrNil($0, 3, r.notes) && self.bindInt64($0, 4, r.id)
}) { 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? deleteRecordingLogs(r.id)
return try run(sql: "DELETE FROM rec WHERE id = ? LIMIT 1;", bind: {
self.bindInt64($0, 1, r.id)
}) {
try ifStep($0, SQLITE_DONE)
return sqlite3_changes(dbPointer) > 0
@@ -368,12 +374,13 @@ extension SQLiteDatabase {
// MARK: read
func readRecording(_ stmt: OpaquePointer) -> Recording {
let end = sqlite3_column_int64(stmt, 1)
return Recording(start: sqlite3_column_int64(stmt, 0),
let end = sqlite3_column_int64(stmt, 2)
return Recording(id: sqlite3_column_int64(stmt, 0),
start: sqlite3_column_int64(stmt, 1),
stop: end == 0 ? nil : end,
appId: readText(stmt, 2),
title: readText(stmt, 3),
notes: readText(stmt, 4))
appId: readText(stmt, 3),
title: readText(stmt, 4),
notes: readText(stmt, 5))
}
func ongoingRecording() -> Recording? {
@@ -388,4 +395,68 @@ extension SQLiteDatabase {
allRows($0) { readRecording($0) }
}
}
func getRecording(withID: sqlite3_int64) throws -> Recording {
try run(sql: "SELECT * FROM rec WHERE id = ? LIMIT 1;", bind: {
self.bindInt64($0, 1, withID)
}) {
try ifStep($0, SQLITE_ROW)
return readRecording($0)
}
}
}
// MARK:
private struct RecordingLog: SQLTable {
let rID: Int32
let ts: Timestamp
let domain: String
static var createStatement: String {
return """
CREATE TABLE IF NOT EXISTS recLog(
rid INTEGER REFERENCES rec(id) ON DELETE CASCADE,
ts INTEGER,
domain TEXT
);
"""
}
}
extension SQLiteDatabase {
// MARK: write
func persistRecordingLogs(_ r: Recording) {
guard let end = r.stop else {
return
}
try? run(sql: """
INSERT INTO recLog (rid, ts, domain) SELECT ?, ts, domain FROM req
WHERE req.ts >= ? AND req.ts <= ?
""", bind: {
self.bindInt64($0, 1, r.id) && self.bindInt64($0, 2, r.start) && self.bindInt64($0, 3, end)
}) {
try ifStep($0, SQLITE_DONE)
}
}
private func deleteRecordingLogs(_ recId: sqlite3_int64) throws -> Int32 {
try run(sql: "DELETE FROM recLog WHERE rid = ?;", bind: {
self.bindInt64($0, 1, recId)
}) {
try ifStep($0, SQLITE_DONE)
return sqlite3_changes(dbPointer)
}
}
// MARK: read
func getRecordingsLogs(_ r: Recording) -> [(domain: String?, count: Int32)]? {
try? run(sql: "SELECT domain, COUNT() FROM recLog WHERE rid = ? GROUP BY domain;", bind: {
self.bindInt64($0, 1, r.id)
}) {
allRows($0) { (readText($0, 0), sqlite3_column_int($0, 1)) }
}
}
}

View File

@@ -20,11 +20,7 @@ extension Array where Element == GroupedDomain {
}
extension Recording {
func stoppedCopy() -> Recording {
stop != nil ? self : Recording(start: start, stop: Timestamp(Date().timeIntervalSince1970),
appId: appId, title: title, notes: notes)
}
var fallbackTitle: String { get { "Unnamed #\(start)" } }
var fallbackTitle: String { get { "Unnamed Recording #\(id)" } }
var duration: Timestamp? { get { stop == nil ? nil : stop! - start } }
var durationString: String? { get { stop == nil ? nil : TimeFormat.from(duration!) } }
}

View File

@@ -8,17 +8,14 @@ class TVCPreviousRecords: UITableViewController {
NotifyRecordingChanged.observe(call: #selector(recordingDidChange(_:)), on: self)
}
func stopRecording(_ record: Recording?) {
guard let r = record?.stoppedCopy() else {
return
}
func insertAndEditRecording(_ r: Recording) {
insertNewRecord(r)
editRecord(r, isNewRecording: true)
}
@objc private func recordingDidChange(_ notification: Notification) {
let (new, deleted) = notification.object as! (Recording, Bool)
if let i = dataSource.firstIndex(where: { $0.start == new.start }) {
if let i = dataSource.firstIndex(where: { $0.id == new.id }) {
if deleted {
dataSource.remove(at: i)
tableView.deleteRows(at: [IndexPath(row: i)], with: .automatic)

View File

@@ -2,14 +2,11 @@ import UIKit
class TVCRecordingDetails: UITableViewController {
var record: Recording!
private var dataSource: [(domain: String, count: Int)] = [
("apple.com", 3),
("cdn.apple.com", 1)
]
private var dataSource: [(domain: String?, count: Int32)]!
override func viewDidLoad() {
title = record.title ?? record.fallbackTitle
// TODO: load db entries
dataSource = DBWrp.recordingDetails(record) ?? []
}

View File

@@ -35,24 +35,24 @@ class VCEditRecording: UIViewController, UITextFieldDelegate, UITextViewDelegate
if deleteOnCancel { // aka newly created
// if remains true, `viewDidDisappear` will delete the record
deleteOnCancel = false
// TODO: copy db entries in new table for editing
}
QLog.Debug("updating record \(record.start)")
QLog.Debug("updating record #\(record.id)")
record.title = (inputTitle.text == "") ? nil : inputTitle.text
record.notes = (inputNotes.text == "") ? nil : inputNotes.text
dismiss(animated: true) {
DBWrp.recordingUpdate(self.record)
DBWrp.recordingPersist(self.record)
}
}
@IBAction func didTapCancel(_ sender: UIBarButtonItem) {
QLog.Debug("discard edit of record \(record.start)")
QLog.Debug("discard edit of record #\(record.id)")
dismiss(animated: true)
}
override func viewDidDisappear(_ animated: Bool) {
if deleteOnCancel {
QLog.Debug("deleting record \(record.start)")
QLog.Debug("deleting record #\(record.id)")
DBWrp.recordingDelete(record)
deleteOnCancel = false
}

View File

@@ -45,9 +45,10 @@ class VCRecordings: UIViewController, UINavigationControllerDelegate {
startTimer(animate: true)
} else {
stopTimer(animate: true)
DBWrp.recordingStopAll()
DBWrp.recordingStop(&currentRecording!)
prevRecController.popToRootViewController(animated: true)
(prevRecController.topViewController as! TVCPreviousRecords).stopRecording(currentRecording!)
let editVC = (prevRecController.topViewController as! TVCPreviousRecords)
editVC.insertAndEditRecording(currentRecording!)
currentRecording = nil // otherwise it will restart
}
}