Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Notify] SQLite database for subscriptions and messages #1208

Merged
merged 8 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/Database.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Database"
BuildableName = "Database"
BlueprintName = "Database"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Database"
BuildableName = "Database"
BlueprintName = "Database"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
4 changes: 3 additions & 1 deletion Example/IntegrationTests/Push/NotifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ final class NotifyTests: XCTestCase {
keychainStorage: keychain,
environment: .sandbox)
let keyserverURL = URL(string: "https://keys.walletconnect.com")!
let sqlite = try! MemorySqlite()
// Note:- prod project_id do not exists on staging, we can use gmDappProjectId
let client = NotifyClientFactory.create(projectId: InputConfig.gmDappProjectId,
keyserverURL: keyserverURL,
keyserverURL: keyserverURL,
sqlite: sqlite,
logger: notifyLogger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
Expand Down
2 changes: 1 addition & 1 deletion Example/WalletApp/ApplicationLayer/LoggingService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ final class LoggingService {
SentrySDK.capture(error: LoggingError.networking(log.aggregated))
case .warn(let log):
// Example of setting level to warning
var event = Event(level: .warning)
let event = Event(level: .warning)
event.message = SentryMessage(formatted: log.aggregated)
SentrySDK.capture(event: event)
default:
Expand Down
5 changes: 4 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ let package = Package(
path: "Sources/Web3Wallet"),
.target(
name: "WalletConnectNotify",
dependencies: ["WalletConnectPairing", "WalletConnectPush", "WalletConnectIdentity", "WalletConnectSigner"],
dependencies: ["WalletConnectPairing", "WalletConnectPush", "WalletConnectIdentity", "WalletConnectSigner", "Database"],
path: "Sources/WalletConnectNotify"),
.target(
name: "WalletConnectPush",
Expand Down Expand Up @@ -130,6 +130,9 @@ let package = Package(
.target(
name: "WalletConnectVerify",
dependencies: ["WalletConnectUtils", "WalletConnectNetworking"]),
.target(
name: "Database",
dependencies: []),
.target(
name: "WalletConnectModal",
dependencies: ["QRCode", "WalletConnectSign"],
Expand Down
46 changes: 46 additions & 0 deletions Sources/Database/DiskSqlite.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Foundation
import SQLite3

public final class DiskSqlite: Sqlite {

private let path: String

private var db: OpaquePointer?

public init(path: String) {
self.path = path
}

public func openDatabase() throws {
guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else {
throw SQLiteError.openDatabase(path: path)
}
}

public func query<Row: SqliteRow>(sql: String) throws -> [Row] {
var queryStatement: OpaquePointer?
guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else {
throw SQLiteError.queryPrepare(statement: sql)
}
var rows: [Row] = []
while sqlite3_step(queryStatement) == SQLITE_ROW {
let decoder = SqliteRowDecoder(statement: queryStatement)
guard let row = try? Row(decoder: decoder) else { continue }
rows.append(row)
}
sqlite3_finalize(queryStatement)
return rows
}

public func execute(sql: String) throws {
var error: UnsafeMutablePointer<CChar>?
guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else {
let message = error.map { String(cString: $0) }
throw SQLiteError.exec(error: message)
}
}

public func closeConnection() {
sqlite3_close(db)
}
}
44 changes: 44 additions & 0 deletions Sources/Database/MemorySqlite.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Foundation
import SQLite3

public final class MemorySqlite: Sqlite {

private var db: OpaquePointer?

public init() throws {
guard sqlite3_open_v2(":memory:", &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else {
throw SQLiteError.openDatabaseMemory
}
}

public func openDatabase() throws {
// No op
}

public func query<Row: SqliteRow>(sql: String) throws -> [Row] {
var queryStatement: OpaquePointer?
guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else {
throw SQLiteError.queryPrepare(statement: sql)
}
var rows: [Row] = []
while sqlite3_step(queryStatement) == SQLITE_ROW {
let decoder = SqliteRowDecoder(statement: queryStatement)
guard let row = try? Row(decoder: decoder) else { continue }
rows.append(row)
}
sqlite3_finalize(queryStatement)
return rows
}

public func execute(sql: String) throws {
var error: UnsafeMutablePointer<CChar>?
guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else {
let message = error.map { String(cString: $0) }
throw SQLiteError.exec(error: message)
}
}

public func closeConnection() {
// No op
}
}
50 changes: 50 additions & 0 deletions Sources/Database/SQLiteQuery.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import Foundation

public struct SqliteQuery {

public static func replace(table: String, rows: [SqliteRow]) throws -> String {
var values: [String] = []

for row in rows {
values.append(row.encode().values
.map { "'\($0.value)'" }
.joined(separator: ", "))
}

guard let first = rows.first else {
throw Errors.rowsNotFound
}

let formattedArguments = first.encode().values
.map { $0.argument }
.joined(separator: ", ")

let formattedValues = values
.map { "(\($0))" }
.joined(separator: ",\n")

return """
REPLACE INTO \(table) (\(formattedArguments)) VALUES
\(formattedValues);
"""
}

public static func select(table: String) -> String {
return "SELECT * FROM \(table);"
}

public static func select(table: String, where argument: String, equals value: String) -> String {
return "SELECT * FROM \(table) WHERE \(argument) = '\(value)';"
}

public static func delete(table: String, where argument: String, equals value: String) -> String {
return "DELETE FROM \(table) WHERE \(argument) = '\(value)';"
}
}

extension SqliteQuery {

enum Errors: Error {
case rowsNotFound
}
}
20 changes: 20 additions & 0 deletions Sources/Database/Sqlite.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Foundation
import SQLite3

public protocol Sqlite {

/// Opening A New Database Connection
func openDatabase() throws

/// Evaluate an SQL Statement
/// - Parameter sql: SQL query
/// - Returns: Table rows array
func query<Row: SqliteRow>(sql: String) throws -> [Row]

/// One-Step query execution
/// - Parameter sql: SQL query
func execute(sql: String) throws

/// Closing A Database Connection
func closeConnection()
}
11 changes: 11 additions & 0 deletions Sources/Database/SqliteError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

public enum SQLiteError: Error {
case openDatabase(path: String)
case openDatabaseMemory
case queryPrepare(statement: String)
case exec(error: String?)
case decodeString(index: Int32)
case stringIsNotBase64
case stringIsNotTimestamp
}
12 changes: 12 additions & 0 deletions Sources/Database/SqliteRow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation

public protocol SqliteRow {

/// SqliteRow initialization
/// - Parameter decoder: SqliteRowDecoder instance
init(decoder: SqliteRowDecoder) throws

/// SqliteRow encoding
/// - Returns: SqliteRowEncoder instance
func encode() -> SqliteRowEncoder
}
51 changes: 51 additions & 0 deletions Sources/Database/SqliteRowDecoder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Foundation
import SQLite3

public class SqliteRowDecoder {

private let statement: OpaquePointer?

init(statement: OpaquePointer?) {
self.statement = statement
}

/// Decode string from column at index
/// - Parameter index: Column index
/// - Returns: Decoded string
public func decodeString(at index: Int32) throws -> String {
guard let raw = sqlite3_column_text(statement, index) else {
throw SQLiteError.decodeString(index: index)
}
return String(cString: raw)
}

/// Decode bool from column at index
/// - Parameter index: Column index
/// - Returns: Decoded bool
public func decodeBool(at index: Int32) throws -> Bool {
let string = try decodeString(at: index)
return (string as NSString).boolValue
}

/// Decode codable object from column at index
/// - Parameter index: Column index
/// - Returns: Decoded codable object
public func decodeCodable<T: Codable>(at index: Int32) throws -> T {
let string = try decodeString(at: index)
guard let data = Data(base64Encoded: string) else {
throw SQLiteError.stringIsNotBase64
}
return try JSONDecoder().decode(T.self, from: data)
}

/// Decode date from column at index
/// - Parameter index: Column index
/// - Returns: Decoded date
public func decodeDate(at index: Int32) throws -> Date {
let string = try decodeString(at: index)
guard let interval = TimeInterval(string) else {
throw SQLiteError.stringIsNotTimestamp
}
return Date(timeIntervalSince1970: interval)
}
}
33 changes: 33 additions & 0 deletions Sources/Database/SqliteRowEncoder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Foundation

public struct SqliteRowEncoder {
struct Value {
let argument: String
let value: String
}

var values: [Value] = []

public init() { }

public mutating func encodeString(_ value: String, for argument: String) {
let value = Value(argument: argument, value: value)
values.append(value)
}

public mutating func encodeDate(_ value: Date, for argument: String) {
let value = Value(argument: argument, value: String(value.timeIntervalSince1970))
values.append(value)
}

public mutating func encodeCodable<T: Codable>(_ value: T, for argument: String) {
let data = try! JSONEncoder().encode(value)
let value = Value(argument: argument, value: data.base64EncodedString())
values.append(value)
}

public mutating func encodeBool(_ value: Bool, for argument: String) {
let value = Value(argument: argument, value: String(value))
values.append(value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ final class NotifyAccountProvider {
case currentAccountNotFound
}

private var currentAccount: Account?
private(set) var currentAccount: Account?

func setAccount(_ account: Account) {
self.currentAccount = account
Expand Down
Loading
Loading