Introduce Dagger2
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
@@ -34,6 +35,10 @@ dependencies {
|
|||||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
implementation 'com.github.vmichalak:sonos-controller:v.0.1'
|
implementation 'com.github.vmichalak:sonos-controller:v.0.1'
|
||||||
|
implementation 'com.google.dagger:dagger-android:2.15'
|
||||||
|
implementation 'com.google.dagger:dagger-android-support:2.15'
|
||||||
|
kapt 'com.google.dagger:dagger-android-processor:2.15'
|
||||||
|
kapt 'com.google.dagger:dagger-compiler:2.15'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
<uses-permission android:name="io.bartek.permission.TTS_HTTP_SERVICE" />
|
<uses-permission android:name="io.bartek.permission.TTS_HTTP_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".ttsserver.TTSApplication"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|||||||
@@ -13,17 +13,22 @@ import android.widget.TextView
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.AppCompatImageButton
|
import androidx.appcompat.widget.AppCompatImageButton
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
|
import dagger.android.support.DaggerAppCompatActivity
|
||||||
import io.bartek.R
|
import io.bartek.R
|
||||||
import io.bartek.ttsserver.help.HelpActivity
|
import io.bartek.ttsserver.help.HelpActivity
|
||||||
import io.bartek.ttsserver.preference.PreferencesActivity
|
import io.bartek.ttsserver.preference.PreferencesActivity
|
||||||
import io.bartek.ttsserver.service.ForegroundService
|
import io.bartek.ttsserver.service.ForegroundService
|
||||||
import io.bartek.ttsserver.service.ServiceState
|
import io.bartek.ttsserver.service.ServiceState
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : DaggerAppCompatActivity() {
|
||||||
private lateinit var serverControlButton: AppCompatImageButton
|
private lateinit var serverControlButton: AppCompatImageButton
|
||||||
private lateinit var promptText: TextView
|
private lateinit var promptText: TextView
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var context: Context
|
||||||
|
|
||||||
private val receiver = object : BroadcastReceiver() {
|
private val receiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
(intent?.getStringExtra(ForegroundService.STATE) ?: ServiceState.STOPPED.name)
|
(intent?.getStringExtra(ForegroundService.STATE) ?: ServiceState.STOPPED.name)
|
||||||
|
|||||||
11
app/src/main/java/io/bartek/ttsserver/TTSApplication.kt
Normal file
11
app/src/main/java/io/bartek/ttsserver/TTSApplication.kt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package io.bartek.ttsserver
|
||||||
|
|
||||||
|
import dagger.android.support.DaggerApplication
|
||||||
|
import io.bartek.ttsserver.di.DaggerAppComponent
|
||||||
|
|
||||||
|
class TTSApplication : DaggerApplication() {
|
||||||
|
override fun applicationInjector() = DaggerAppComponent.builder().create(this).let {
|
||||||
|
it.inject(this)
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/src/main/java/io/bartek/ttsserver/di/AndroidModule.kt
Normal file
24
app/src/main/java/io/bartek/ttsserver/di/AndroidModule.kt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package io.bartek.ttsserver.di
|
||||||
|
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.android.ContributesAndroidInjector
|
||||||
|
import io.bartek.ttsserver.MainActivity
|
||||||
|
import io.bartek.ttsserver.help.HelpActivity
|
||||||
|
import io.bartek.ttsserver.preference.PreferencesActivity
|
||||||
|
import io.bartek.ttsserver.service.ForegroundService
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class AndroidModule {
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun mainActivity(): MainActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun helpActivity(): HelpActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun preferencesActivity(): PreferencesActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun foregroundService(): ForegroundService
|
||||||
|
}
|
||||||
23
app/src/main/java/io/bartek/ttsserver/di/AppComponent.kt
Normal file
23
app/src/main/java/io/bartek/ttsserver/di/AppComponent.kt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package io.bartek.ttsserver.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.BindsInstance
|
||||||
|
import dagger.Component
|
||||||
|
import dagger.android.AndroidInjector
|
||||||
|
import dagger.android.support.AndroidSupportInjectionModule
|
||||||
|
import io.bartek.ttsserver.TTSApplication
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Component(modules = [AndroidSupportInjectionModule::class, AndroidModule::class, TTSModule::class])
|
||||||
|
interface AppComponent : AndroidInjector<TTSApplication> {
|
||||||
|
|
||||||
|
@Component.Builder
|
||||||
|
abstract class Builder : AndroidInjector.Builder<TTSApplication>() {
|
||||||
|
|
||||||
|
@BindsInstance
|
||||||
|
abstract fun appContext(context: Context)
|
||||||
|
|
||||||
|
override fun seedInstance(instance: TTSApplication) = appContext(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
60
app/src/main/java/io/bartek/ttsserver/di/TTSModule.kt
Normal file
60
app/src/main/java/io/bartek/ttsserver/di/TTSModule.kt
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package io.bartek.ttsserver.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.speech.tts.TextToSpeech
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import io.bartek.ttsserver.network.NetworkUtil
|
||||||
|
import io.bartek.ttsserver.service.ForegroundNotificationFactory
|
||||||
|
import io.bartek.ttsserver.sonos.SonosQueue
|
||||||
|
import io.bartek.ttsserver.tts.TTS
|
||||||
|
import io.bartek.ttsserver.tts.TTSStatusHolder
|
||||||
|
import io.bartek.ttsserver.web.WebServerFactory
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class TTSModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun ttsStatusHolder() = TTSStatusHolder()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun textToSpeech(context: Context, ttsStatusHolder: TTSStatusHolder) =
|
||||||
|
TextToSpeech(context, ttsStatusHolder)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun tts(context: Context, textToSpeech: TextToSpeech, ttsStatusHolder: TTSStatusHolder) =
|
||||||
|
TTS(context, textToSpeech, ttsStatusHolder)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun webServerFactory(
|
||||||
|
preferences: SharedPreferences,
|
||||||
|
context: Context,
|
||||||
|
tts: TTS,
|
||||||
|
sonos: SonosQueue
|
||||||
|
) =
|
||||||
|
WebServerFactory(preferences, context, tts, sonos)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun preferences(context: Context) = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun networkUtil(context: Context) = NetworkUtil(context)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun sonosQueue(tts: TTS, networkUtil: NetworkUtil, preferences: SharedPreferences) =
|
||||||
|
SonosQueue(tts, networkUtil, preferences)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun foregroundNotificationFactory(context: Context) = ForegroundNotificationFactory(context)
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ import android.net.wifi.WifiManager
|
|||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
|
|
||||||
|
|
||||||
object NetworkUtil {
|
class NetworkUtil(private val context: Context) {
|
||||||
fun getIpAddress(context: Context): String {
|
fun getIpAddress(): String {
|
||||||
return (context.getApplicationContext().getSystemService(WIFI_SERVICE) as WifiManager).let {
|
return (context.getApplicationContext().getSystemService(WIFI_SERVICE) as WifiManager).let {
|
||||||
inetAddress(it.dhcpInfo.ipAddress).toString().substring(1)
|
inetAddress(it.dhcpInfo.ipAddress).toString().substring(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,35 @@
|
|||||||
package io.bartek.ttsserver.service
|
package io.bartek.ttsserver.service
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Service
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import androidx.preference.PreferenceManager
|
import dagger.android.DaggerService
|
||||||
import io.bartek.ttsserver.preference.PreferenceKey
|
import io.bartek.ttsserver.preference.PreferenceKey
|
||||||
import io.bartek.ttsserver.web.WebServer
|
import io.bartek.ttsserver.web.WebServer
|
||||||
|
import io.bartek.ttsserver.web.WebServerFactory
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class ForegroundService : Service() {
|
class ForegroundService : DaggerService() {
|
||||||
private lateinit var preferences: SharedPreferences
|
|
||||||
private var wakeLock: PowerManager.WakeLock? = null
|
private var wakeLock: PowerManager.WakeLock? = null
|
||||||
private var isServiceStarted = false
|
private var isServiceStarted = false
|
||||||
private var webServer: WebServer? = null
|
private var webServer: WebServer? = null
|
||||||
private val port: Int
|
private val port: Int
|
||||||
get() = preferences.getInt(PreferenceKey.PORT, 8080)
|
get() = preferences.getInt(PreferenceKey.PORT, 8080)
|
||||||
private val notificationFactory = ForegroundNotificationFactory(this)
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var preferences: SharedPreferences
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var webServerFactory: WebServerFactory
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var notificationFactory: ForegroundNotificationFactory
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
startForeground(1, notificationFactory.createForegroundNotification(port))
|
startForeground(1, notificationFactory.createForegroundNotification(port))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +47,7 @@ class ForegroundService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
webServer?.stop()
|
||||||
webServer = null
|
webServer = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,8 +61,11 @@ class ForegroundService : Service() {
|
|||||||
acquire()
|
acquire()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
webServer = WebServer(port, this)
|
webServer = webServerFactory.createWebServer()
|
||||||
state = ServiceState.RUNNING
|
webServer?.let {
|
||||||
|
state = ServiceState.RUNNING
|
||||||
|
it.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stopService() {
|
private fun stopService() {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package io.bartek.ttsserver.sonos
|
package io.bartek.ttsserver.sonos
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
import com.vmichalak.sonoscontroller.SonosDiscovery
|
import com.vmichalak.sonoscontroller.SonosDiscovery
|
||||||
|
import io.bartek.ttsserver.network.NetworkUtil
|
||||||
|
import io.bartek.ttsserver.preference.PreferenceKey
|
||||||
import io.bartek.ttsserver.service.ForegroundService
|
import io.bartek.ttsserver.service.ForegroundService
|
||||||
import io.bartek.ttsserver.service.ServiceState
|
import io.bartek.ttsserver.service.ServiceState
|
||||||
import io.bartek.ttsserver.tts.TTS
|
import io.bartek.ttsserver.tts.TTS
|
||||||
@@ -24,7 +27,7 @@ private class Consumer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun consume(data: SonosTTSRequestData) {
|
private fun consume(data: SonosTTSRequestData) =
|
||||||
SonosDiscovery.discover().firstOrNull { it.zoneGroupState.name == data.zone }?.let {
|
SonosDiscovery.discover().firstOrNull { it.zoneGroupState.name == data.zone }?.let {
|
||||||
val file = tts.createTTSFile(data.text, data.language)
|
val file = tts.createTTSFile(data.text, data.language)
|
||||||
val filename = file.name
|
val filename = file.name
|
||||||
@@ -34,16 +37,30 @@ private class Consumer(
|
|||||||
it.clip(url, "")
|
it.clip(url, "")
|
||||||
it.volume = currentVolume
|
it.volume = currentVolume
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SonosQueue(tts: TTS, host: String, port: Int) {
|
class SonosQueue(
|
||||||
|
private val tts: TTS,
|
||||||
|
private val networkUtil: NetworkUtil,
|
||||||
|
private val preferences: SharedPreferences
|
||||||
|
) {
|
||||||
private val queue: BlockingQueue<SonosTTSRequestData> = LinkedBlockingQueue()
|
private val queue: BlockingQueue<SonosTTSRequestData> = LinkedBlockingQueue()
|
||||||
private val consumer = Thread(Consumer(tts, host, port, queue)).also {
|
private val host: String
|
||||||
it.name = "SONOS_QUEUE"
|
get() = networkUtil.getIpAddress()
|
||||||
|
private val port: Int
|
||||||
|
get() = preferences.getInt(PreferenceKey.PORT, 8080)
|
||||||
|
private var consumer: Thread? = null
|
||||||
|
|
||||||
|
fun run() {
|
||||||
|
consumer?.interrupt()
|
||||||
|
consumer = Thread(Consumer(tts, host, port, queue)).also { it.name = "SonosQueue" }
|
||||||
|
consumer?.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
init { consumer.start() }
|
fun stop() {
|
||||||
|
consumer?.interrupt()
|
||||||
|
consumer = null
|
||||||
|
}
|
||||||
|
|
||||||
fun push(data: SonosTTSRequestData) = queue.add(data)
|
fun push(data: SonosTTSRequestData) = queue.add(data)
|
||||||
}
|
}
|
||||||
@@ -13,10 +13,16 @@ import java.util.*
|
|||||||
|
|
||||||
data class SpeechData(val stream: InputStream, val size: Long)
|
data class SpeechData(val stream: InputStream, val size: Long)
|
||||||
|
|
||||||
class TTS(private val context: Context, initListener: TextToSpeech.OnInitListener) {
|
class TTS(
|
||||||
private val tts = TextToSpeech(context, initListener)
|
private val context: Context,
|
||||||
|
private val tts: TextToSpeech,
|
||||||
|
private val ttsStausHolder: TTSStatusHolder
|
||||||
|
) {
|
||||||
private val messageDigest = MessageDigest.getInstance("SHA-256")
|
private val messageDigest = MessageDigest.getInstance("SHA-256")
|
||||||
|
|
||||||
|
val status: TTSStatus
|
||||||
|
get() = ttsStausHolder.status
|
||||||
|
|
||||||
fun createTTSFile(text: String, language: Locale): File {
|
fun createTTSFile(text: String, language: Locale): File {
|
||||||
val digest = hash(text, language)
|
val digest = hash(text, language)
|
||||||
val filename = "tts_$digest.wav"
|
val filename = "tts_$digest.wav"
|
||||||
@@ -34,7 +40,7 @@ class TTS(private val context: Context, initListener: TextToSpeech.OnInitListene
|
|||||||
lock.wait()
|
lock.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!lock.success) {
|
if (!lock.success) {
|
||||||
throw TTSException()
|
throw TTSException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
app/src/main/java/io/bartek/ttsserver/tts/TTSStatusHolder.kt
Normal file
22
app/src/main/java/io/bartek/ttsserver/tts/TTSStatusHolder.kt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package io.bartek.ttsserver.tts
|
||||||
|
|
||||||
|
import android.speech.tts.TextToSpeech
|
||||||
|
|
||||||
|
enum class TTSStatus(private val status: Int) {
|
||||||
|
READY(TextToSpeech.SUCCESS),
|
||||||
|
ERROR(TextToSpeech.ERROR),
|
||||||
|
UNLOADED(1);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun of(status: Int) = values().firstOrNull { it.status == status } ?: UNLOADED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TTSStatusHolder : TextToSpeech.OnInitListener {
|
||||||
|
var status = TTSStatus.UNLOADED
|
||||||
|
private set
|
||||||
|
|
||||||
|
override fun onInit(status: Int) {
|
||||||
|
this.status = TTSStatus.of(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ enum class Endpoint(val uri: String, val id: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Endpoints {
|
object Endpoints {
|
||||||
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
|
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -2,47 +2,56 @@ package io.bartek.ttsserver.web
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.speech.tts.TextToSpeech
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import fi.iki.elonen.NanoHTTPD
|
import fi.iki.elonen.NanoHTTPD
|
||||||
import fi.iki.elonen.NanoHTTPD.Response.Status.*
|
import fi.iki.elonen.NanoHTTPD.Response.Status.*
|
||||||
import io.bartek.ttsserver.network.NetworkUtil
|
|
||||||
import io.bartek.ttsserver.preference.PreferenceKey
|
import io.bartek.ttsserver.preference.PreferenceKey
|
||||||
import io.bartek.ttsserver.service.ForegroundService
|
import io.bartek.ttsserver.service.ForegroundService
|
||||||
import io.bartek.ttsserver.service.ServiceState
|
import io.bartek.ttsserver.service.ServiceState
|
||||||
import io.bartek.ttsserver.sonos.SonosQueue
|
import io.bartek.ttsserver.sonos.SonosQueue
|
||||||
import io.bartek.ttsserver.tts.TTS
|
import io.bartek.ttsserver.tts.TTS
|
||||||
|
import io.bartek.ttsserver.tts.TTSStatus
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
|
|
||||||
|
|
||||||
class WebServer(port: Int, private val context: Context) : NanoHTTPD(port),
|
class WebServer(
|
||||||
TextToSpeech.OnInitListener {
|
port: Int,
|
||||||
private val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
private val context: Context,
|
||||||
private val tts = TTS(context, this)
|
private val preferences: SharedPreferences,
|
||||||
private val endpoints = Endpoints()
|
private val tts: TTS,
|
||||||
private val sonos = SonosQueue(tts, NetworkUtil.getIpAddress(context), port)
|
private val sonos: SonosQueue
|
||||||
|
) : NanoHTTPD(port) {
|
||||||
override fun serve(session: IHTTPSession?): Response {
|
override fun serve(session: IHTTPSession?): Response {
|
||||||
try {
|
try {
|
||||||
|
assertThatTTSIsReady()
|
||||||
|
|
||||||
session?.let {
|
session?.let {
|
||||||
return when (endpoints.match(it.uri)) {
|
return dispatch(it)
|
||||||
Endpoint.SAY -> say(it)
|
|
||||||
Endpoint.WAVE -> wave(it)
|
|
||||||
Endpoint.SONOS -> sonos(it)
|
|
||||||
Endpoint.SONOS_CACHE -> sonosCache(it)
|
|
||||||
Endpoint.UNKNOWN -> throw ResponseException(NOT_FOUND, "")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw ResponseException(BAD_REQUEST, "")
|
throw ResponseException(BAD_REQUEST, "")
|
||||||
} catch (e: ResponseException) {
|
}
|
||||||
throw e
|
catch (e: ResponseException) { throw e }
|
||||||
} catch (e: Exception) {
|
catch (e: Exception) { throw ResponseException(INTERNAL_ERROR, e.toString(), e) }
|
||||||
throw ResponseException(INTERNAL_ERROR, e.toString(), e)
|
}
|
||||||
|
|
||||||
|
private fun dispatch(it: IHTTPSession): Response {
|
||||||
|
return when (Endpoints.match(it.uri)) {
|
||||||
|
Endpoint.SAY -> say(it)
|
||||||
|
Endpoint.WAVE -> wave(it)
|
||||||
|
Endpoint.SONOS -> sonos(it)
|
||||||
|
Endpoint.SONOS_CACHE -> sonosCache(it)
|
||||||
|
Endpoint.UNKNOWN -> throw ResponseException(NOT_FOUND, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertThatTTSIsReady() {
|
||||||
|
if (tts.status != TTSStatus.READY) {
|
||||||
|
throw ResponseException(NOT_ACCEPTABLE, "Server is not ready yet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,10 +129,11 @@ class WebServer(port: Int, private val context: Context) : NanoHTTPD(port),
|
|||||||
throw ResponseException(METHOD_NOT_ALLOWED, "")
|
throw ResponseException(METHOD_NOT_ALLOWED, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
val filename = Uri.parse(session.uri).lastPathSegment ?: throw ResponseException(BAD_REQUEST, "")
|
val filename =
|
||||||
|
Uri.parse(session.uri).lastPathSegment ?: throw ResponseException(BAD_REQUEST, "")
|
||||||
val file = File(context.cacheDir, filename)
|
val file = File(context.cacheDir, filename)
|
||||||
|
|
||||||
if(!file.exists()) {
|
if (!file.exists()) {
|
||||||
throw ResponseException(NOT_FOUND, "")
|
throw ResponseException(NOT_FOUND, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,10 +142,9 @@ class WebServer(port: Int, private val context: Context) : NanoHTTPD(port),
|
|||||||
return newFixedLengthResponse(OK, MIME_WAVE, stream, size)
|
return newFixedLengthResponse(OK, MIME_WAVE, stream, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInit(status: Int) = start()
|
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
super.start()
|
super.start()
|
||||||
|
sonos.run()
|
||||||
LocalBroadcastManager
|
LocalBroadcastManager
|
||||||
.getInstance(context)
|
.getInstance(context)
|
||||||
.sendBroadcast(Intent(ForegroundService.CHANGE_STATE).also {
|
.sendBroadcast(Intent(ForegroundService.CHANGE_STATE).also {
|
||||||
@@ -145,6 +154,7 @@ class WebServer(port: Int, private val context: Context) : NanoHTTPD(port),
|
|||||||
|
|
||||||
override fun stop() {
|
override fun stop() {
|
||||||
super.stop()
|
super.stop()
|
||||||
|
sonos.stop()
|
||||||
LocalBroadcastManager
|
LocalBroadcastManager
|
||||||
.getInstance(context)
|
.getInstance(context)
|
||||||
.sendBroadcast(Intent(ForegroundService.CHANGE_STATE).also {
|
.sendBroadcast(Intent(ForegroundService.CHANGE_STATE).also {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package io.bartek.ttsserver.web
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import io.bartek.ttsserver.preference.PreferenceKey
|
||||||
|
import io.bartek.ttsserver.sonos.SonosQueue
|
||||||
|
import io.bartek.ttsserver.tts.TTS
|
||||||
|
|
||||||
|
class WebServerFactory(
|
||||||
|
private val preferences: SharedPreferences,
|
||||||
|
private val context: Context,
|
||||||
|
private val tts: TTS,
|
||||||
|
private val sonos: SonosQueue
|
||||||
|
) {
|
||||||
|
fun createWebServer() =
|
||||||
|
WebServer(preferences.getInt(PreferenceKey.PORT, 8080), context, preferences, tts, sonos)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user