Rename database namespace

This commit is contained in:
Philipp Heckel 2022-01-18 14:28:48 -05:00
parent e87cc33f13
commit 8fcef8ddee
28 changed files with 316 additions and 52 deletions

View file

@ -0,0 +1,256 @@
{
"formatVersion": 1,
"database": {
"version": 7,
"identityHash": "ecb1b85b2ae822dc62b2843620368477",
"entities": [
{
"tableName": "Subscription",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `baseUrl` TEXT NOT NULL, `topic` TEXT NOT NULL, `instant` INTEGER NOT NULL, `mutedUntil` INTEGER NOT NULL, `upAppId` TEXT, `upConnectorToken` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "topic",
"columnName": "topic",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "instant",
"columnName": "instant",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mutedUntil",
"columnName": "mutedUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "upAppId",
"columnName": "upAppId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upConnectorToken",
"columnName": "upConnectorToken",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_Subscription_baseUrl_topic",
"unique": true,
"columnNames": [
"baseUrl",
"topic"
],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_baseUrl_topic` ON `${TABLE_NAME}` (`baseUrl`, `topic`)"
},
{
"name": "index_Subscription_upConnectorToken",
"unique": true,
"columnNames": [
"upConnectorToken"
],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_upConnectorToken` ON `${TABLE_NAME}` (`upConnectorToken`)"
}
],
"foreignKeys": []
},
{
"tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `deleted` INTEGER NOT NULL, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "notificationId",
"columnName": "notificationId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "priority",
"columnName": "priority",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "3"
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "attachment.name",
"columnName": "attachment_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.type",
"columnName": "attachment_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.size",
"columnName": "attachment_size",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.expires",
"columnName": "attachment_expires",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.url",
"columnName": "attachment_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.contentUri",
"columnName": "attachment_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.progress",
"columnName": "attachment_progress",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"subscriptionId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `tag` TEXT NOT NULL, `level` INTEGER NOT NULL, `message` TEXT NOT NULL, `exception` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "level",
"columnName": "level",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "exception",
"columnName": "exception",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ecb1b85b2ae822dc62b2843620368477')"
]
}
}

View file

@ -2,8 +2,8 @@ package io.heckel.ntfy.app
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import io.heckel.ntfy.data.Database import io.heckel.ntfy.db.Database
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
class Application : Application() { class Application : Application() {

View file

@ -1,4 +1,4 @@
package io.heckel.ntfy.data package io.heckel.ntfy.db
import android.content.Context import android.content.Context
import androidx.room.* import androidx.room.*

View file

@ -1,4 +1,4 @@
package io.heckel.ntfy.data package io.heckel.ntfy.db
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context

View file

@ -1,9 +1,9 @@
package io.heckel.ntfy.log package io.heckel.ntfy.log
import android.content.Context import android.content.Context
import io.heckel.ntfy.data.Database import io.heckel.ntfy.db.Database
import io.heckel.ntfy.data.LogDao import io.heckel.ntfy.db.LogDao
import io.heckel.ntfy.data.LogEntry import io.heckel.ntfy.db.LogEntry
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -2,7 +2,7 @@ package io.heckel.ntfy.msg
import android.os.Build import android.os.Build
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.util.* import io.heckel.ntfy.util.*
import okhttp3.* import okhttp3.*

View file

@ -3,8 +3,8 @@ package io.heckel.ntfy.msg
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.util.joinTagsMap import io.heckel.ntfy.util.joinTagsMap
import io.heckel.ntfy.util.splitTags import io.heckel.ntfy.util.splitTags

View file

@ -16,7 +16,7 @@ import androidx.work.WorkerParameters
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.* import io.heckel.ntfy.db.*
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.util.queryFilename import io.heckel.ntfy.util.queryFilename
import okhttp3.OkHttpClient import okhttp3.OkHttpClient

View file

@ -1,9 +1,9 @@
package io.heckel.ntfy.msg package io.heckel.ntfy.msg
import android.content.Context import android.content.Context
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.up.Distributor import io.heckel.ntfy.up.Distributor
import io.heckel.ntfy.util.safeLet import io.heckel.ntfy.util.safeLet

View file

@ -2,8 +2,8 @@ package io.heckel.ntfy.msg
import android.util.Base64 import android.util.Base64
import com.google.gson.Gson import com.google.gson.Gson
import io.heckel.ntfy.data.Attachment import io.heckel.ntfy.db.Attachment
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.util.joinTags import io.heckel.ntfy.util.joinTags
import io.heckel.ntfy.util.toPriority import io.heckel.ntfy.util.toPriority

View file

@ -9,8 +9,8 @@ import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.* import io.heckel.ntfy.db.*
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.ui.DetailActivity import io.heckel.ntfy.ui.DetailActivity
import io.heckel.ntfy.ui.MainActivity import io.heckel.ntfy.ui.MainActivity

View file

@ -1,9 +1,9 @@
package io.heckel.ntfy.service package io.heckel.ntfy.service
import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.db.ConnectionState
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.util.topicUrl import io.heckel.ntfy.util.topicUrl

View file

@ -13,9 +13,9 @@ import androidx.core.content.ContextCompat
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.db.ConnectionState
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationDispatcher import io.heckel.ntfy.msg.NotificationDispatcher
@ -227,7 +227,7 @@ class SubscriberService : Service() {
repository.updateState(subscriptionIds, state) repository.updateState(subscriptionIds, state)
} }
private fun onNotificationReceived(subscription: Subscription, notification: io.heckel.ntfy.data.Notification) { private fun onNotificationReceived(subscription: Subscription, notification: io.heckel.ntfy.db.Notification) {
// If permanent wakelock is not enabled, still take the wakelock while notifications are being dispatched // If permanent wakelock is not enabled, still take the wakelock while notifications are being dispatched
if (!repository.getWakelockEnabled()) { if (!repository.getWakelockEnabled()) {
// Wakelocks are reference counted by default so that should work neatly here // Wakelocks are reference counted by default so that should work neatly here

View file

@ -4,10 +4,10 @@ import android.app.AlarmManager
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.db.ConnectionState
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.NotificationParser import io.heckel.ntfy.msg.NotificationParser
import io.heckel.ntfy.util.topicUrl import io.heckel.ntfy.util.topicUrl

View file

@ -14,7 +14,7 @@ import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -21,7 +21,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.firebase.FirebaseMessenger
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService

View file

@ -19,7 +19,7 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.stfalcon.imageviewer.StfalconImageViewer import com.stfalcon.imageviewer.StfalconImageViewer
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.* import io.heckel.ntfy.db.*
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.DownloadManager import io.heckel.ntfy.msg.DownloadManager
import io.heckel.ntfy.util.* import io.heckel.ntfy.util.*

View file

@ -4,8 +4,8 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -20,7 +20,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.work.* import androidx.work.*
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.firebase.FirebaseMessenger
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService

View file

@ -10,9 +10,9 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.ConnectionState import io.heckel.ntfy.db.ConnectionState
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.util.topicShortUrl import io.heckel.ntfy.util.topicShortUrl
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*

View file

@ -5,7 +5,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import io.heckel.ntfy.data.* import io.heckel.ntfy.db.*
import io.heckel.ntfy.up.Distributor import io.heckel.ntfy.up.Distributor
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -8,8 +8,8 @@ import android.widget.RadioButton
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Database import io.heckel.ntfy.db.Database
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -20,7 +20,7 @@ import androidx.preference.*
import androidx.preference.Preference.OnPreferenceClickListener import androidx.preference.Preference.OnPreferenceClickListener
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.service.SubscriberService import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.util.formatBytes import io.heckel.ntfy.util.formatBytes

View file

@ -4,7 +4,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.randomString import io.heckel.ntfy.util.randomString

View file

@ -6,8 +6,8 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.provider.OpenableColumns import android.provider.OpenableColumns
import android.view.Window import android.view.Window
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.db.Subscription
import java.security.SecureRandom import java.security.SecureRandom
import java.text.DateFormat import java.text.DateFormat
import java.text.StringCharacterIterator import java.text.StringCharacterIterator

View file

@ -4,8 +4,8 @@ import android.content.Context
import androidx.work.CoroutineWorker import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.data.Database import io.heckel.ntfy.db.Database
import io.heckel.ntfy.data.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationDispatcher import io.heckel.ntfy.msg.NotificationDispatcher

View file

@ -6,11 +6,12 @@ import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage import com.google.firebase.messaging.RemoteMessage
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Attachment import io.heckel.ntfy.db.Attachment
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.data.PROGRESS_NONE
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.msg.* import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.MESSAGE_ENCODING_BASE64
import io.heckel.ntfy.msg.NotificationDispatcher
import io.heckel.ntfy.service.SubscriberService import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.util.toPriority import io.heckel.ntfy.util.toPriority
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

View file

@ -0,0 +1,7 @@
New features:
* Report logs: Copy/export logs to help troubleshooting (#94)
* WebSockets (experimental): Use WebSockets to subscribe to topics (#96, #100, #97)
Bug fixes:
* Support for binary UnifiedPush messages (#101)