Skip to content

Commit

Permalink
Eliminate Terminated state
Browse files Browse the repository at this point in the history
  • Loading branch information
NorseDreki committed Feb 28, 2024
1 parent 4cac721 commit 362c9bd
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 118 deletions.
5 changes: 2 additions & 3 deletions src/commonMain/kotlin/com/norsedreki/BufferedTransform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ fun <T> Flow<T>.bufferedTransform(
val storage = mutableListOf<T>()

collect { item ->
val willDrain = shouldEmptyBuffer(storage, item)
if (willDrain) {
//TODO would not drain until new tag is met (thus not producing intermediate results)
val willEmpty = shouldEmptyBuffer(storage, item)
if (willEmpty) {
//storage.onEach { emit(it) }
storage.clear()
}
Expand Down
69 changes: 33 additions & 36 deletions src/commonMain/kotlin/com/norsedreki/dogcat/Dogcat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,31 @@ import com.norsedreki.dogcat.Command.*
import com.norsedreki.dogcat.Command.Start.*
import com.norsedreki.dogcat.LogFilter.ByPackage
import com.norsedreki.dogcat.LogFilter.Substring
import com.norsedreki.dogcat.state.AppliedFiltersState
import com.norsedreki.dogcat.state.Device
import com.norsedreki.dogcat.state.PublicState.*
import com.norsedreki.dogcat.state.PublicState
import com.norsedreki.dogcat.state.DogcatState
import com.norsedreki.dogcat.state.DogcatState.Active
import com.norsedreki.dogcat.state.DogcatState.Inactive
import com.norsedreki.dogcat.state.LogFiltersState
import com.norsedreki.logger.Logger
import com.norsedreki.logger.context
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onCompletion
import com.norsedreki.logger.Logger
import com.norsedreki.logger.context

class Dogcat(
private val filters: AppliedFiltersState,
private val logLines: LogLines,
private val filters: LogFiltersState,
private val shell: Shell
) {
) {
private val stateSubject = MutableStateFlow<DogcatState>(Inactive)

private val stateSubject = MutableStateFlow<PublicState>(Inactive)
val state = stateSubject.asStateFlow().onCompletion { Logger.d("${context()} (5) COMPLETION, state") }
val state = stateSubject.asStateFlow()
.onCompletion {
Logger.d("${context()} (5) COMPLETION, state")
}

suspend operator fun invoke(command: Command) {
Logger.d("${context()} Command $command")
Logger.d("${context()} Dogcat got command: $command")

when (command) {
is Start -> {
Expand All @@ -35,15 +38,13 @@ class Dogcat(
ClearLogs -> {
stateSubject.emit(Inactive)

// keyboard input hangs upon clearing? when no emulators
shell.clearLogLines()
captureLogLines()
}

is FilterBy -> {
stateSubject.emit(Inactive)

// Do not re-capture log lines if filter hasn't changed
filters.apply(command.filter)

if (command.filter is Substring) {
Expand All @@ -65,69 +66,65 @@ class Dogcat(
}
}

Stop -> { // clear pad?
Stop -> {
stateSubject.emit(Inactive)

logLines.stop()
stateSubject.emit(Terminated)
}
}
}

private suspend fun start(subcommand: Start) {
shell.validateShellOrThrow()

val running = shell.deviceRunning().first()

if (!running) {
val ci = Terminated
stateSubject.emit(ci)
return
}

when (subcommand) {
is PickForegroundApp -> {
val packageName = shell.foregroundPackageName()
val userId = shell.appIdFor(packageName)
val appId = shell.appIdFor(packageName)

filters.apply(ByPackage(packageName, appId))

filters.apply(ByPackage(packageName, userId))
Logger.d("${context()} Startup with foreground app, resolved to package '$packageName' and user ID '$userId'")
Logger.d("${context()} Start with foreground app '$packageName', app ID '$appId'")
}

is PickAppPackage -> {
stateSubject.emit(Inactive)
//stateSubject.emit(Inactive)

val packageName = subcommand.packageName
val userId = shell.appIdFor(packageName)
val appId = shell.appIdFor(packageName)

filters.apply(ByPackage(packageName, appId))

filters.apply(ByPackage(packageName, userId))
Logger.d("Startup package name '$packageName', resolved user ID to '$userId'")
Logger.d("Start with package name '$packageName', app ID '$appId'")
}

is PickAllApps -> {
Logger.d("${context()} Startup with no package filters")
Logger.d("${context()} Start with no package filters")
}
}

captureLogLines()
}

private suspend fun captureLogLines(restartSource: Boolean = true) {
Logger.d("${context()} Dogcat, captureLogLines with restartSource=$restartSource")

val filterLines = logLines.capture(restartSource)
Logger.d("${context()} created shared lines in dogcat $filterLines")

val device = Device(
shell.deviceName(),
shell.deviceRunning()
)

val ci = Active(
val active = Active(
filterLines
.onCompletion { Logger.d("${context()} (1) COMPLETED: Capturing input filterLines $it") },
.onCompletion { Logger.d("${context()} (4) COMPLETED: Capturing input filterLines $it") },

filters.applied,
filters.state,

device
)

stateSubject.emit(ci)
stateSubject.emit(active)
}
}
4 changes: 2 additions & 2 deletions src/commonMain/kotlin/com/norsedreki/dogcat/LogLines.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class LogLines(
)
.withIndex()
.onCompletion {
Logger.d("${context()} COMPLETION (2): Full log lines pipeline")
Logger.d("${context()} COMPLETION (3): Full log lines pipeline")
}
.flowOn(dispatcherCpu)
}
Expand Down Expand Up @@ -127,7 +127,7 @@ class LogLines(
)
.onCompletion {
Logger.d(
"${context()} COMPLETION (3): ADB logcat log lines shred by 'shareIn")
"${context()} COMPLETION (2): ADB logcat log lines shred by 'shareIn")
}
}
}
20 changes: 20 additions & 0 deletions src/commonMain/kotlin/com/norsedreki/dogcat/state/DogcatState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.norsedreki.dogcat.state

import com.norsedreki.dogcat.LogLine
import kotlinx.coroutines.flow.Flow

sealed interface DogcatState {

data class Active(
val lines: Flow<IndexedValue<LogLine>>,
val filters: Flow<LogFilters>,
val device: Device,
) : DogcatState

data object Inactive : DogcatState
}

data class Device(
val label: String,
val isOnline: Flow<Boolean>
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,48 @@ import com.norsedreki.dogcat.DogcatConfig.DEFAULT_MIN_LOG_LEVEL
import com.norsedreki.dogcat.LogFilter
import com.norsedreki.dogcat.LogFilter.MinLogLevel
import com.norsedreki.dogcat.LogFilter.Substring
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import com.norsedreki.logger.Logger
import com.norsedreki.logger.context
import kotlin.reflect.KClass


typealias AppliedFilters = Map<KClass<out LogFilter>, LogFilter>
typealias LogFilters = Map<KClass<out LogFilter>, LogFilter>

interface AppliedFiltersState {
val applied: StateFlow<AppliedFilters>
interface LogFiltersState {

val state: StateFlow<LogFilters>

suspend fun apply(filter: LogFilter)

suspend fun reset(filterClass: KClass<out LogFilter>)
}

class DefaultAppliedFiltersState : AppliedFiltersState {
class DefaultLogFiltersState : LogFiltersState {

private val defaultFilters: AppliedFilters =
private val defaultFilters: LogFilters =
mapOf(
Substring::class to Substring(""),
MinLogLevel::class to MinLogLevel(DEFAULT_MIN_LOG_LEVEL)
)

private val appliedFiltersState = MutableStateFlow(defaultFilters)
override val applied = appliedFiltersState.asStateFlow()
private val stateSubject = MutableStateFlow(defaultFilters)
override val state = stateSubject.asStateFlow()

override suspend fun apply(filter: LogFilter) {
val next = appliedFiltersState.value + (filter::class to filter)
appliedFiltersState.emit(next)
val next = stateSubject.value + (filter::class to filter)
stateSubject.emit(next)
}

override suspend fun reset(filterClass: KClass<out LogFilter>) {
val default = defaultFilters[filterClass]

val next = if (default != null) {
appliedFiltersState.value + (filterClass to default)
stateSubject.value + (filterClass to default)
} else {
appliedFiltersState.value - filterClass
stateSubject.value - filterClass
}

appliedFiltersState.emit(next)
stateSubject.emit(next)
}
}
25 changes: 0 additions & 25 deletions src/commonMain/kotlin/com/norsedreki/dogcat/state/PublicState.kt

This file was deleted.

22 changes: 3 additions & 19 deletions src/nativeMain/kotlin/ui/AppPresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import com.norsedreki.dogcat.Command.Start.*
import com.norsedreki.dogcat.Dogcat
import com.norsedreki.dogcat.LogFilter.*
import com.norsedreki.dogcat.LogLevel.*
import com.norsedreki.dogcat.state.PublicState
import com.norsedreki.dogcat.state.PublicState.Active
import com.norsedreki.dogcat.state.DogcatState.Active
import com.norsedreki.logger.Logger
import com.norsedreki.logger.context
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import com.norsedreki.logger.Logger
import com.norsedreki.logger.context
import ui.logLines.LogLinesPresenter
import ui.status.StatusPresenter
import userInput.Arguments
Expand Down Expand Up @@ -43,9 +42,6 @@ class AppPresenter(
view.start()

val scope = CoroutineScope(coroutineContext)
scope.launch {
collectDogcatEvents()
}
scope.launch {
collectKeypresses()
}
Expand All @@ -63,18 +59,6 @@ class AppPresenter(
view.stop()
}

// no need for this anymore
private suspend fun collectDogcatEvents() {
dogcat
.state
.filterIsInstance<PublicState.Terminated>()
.collect {
println(
"Either ADB is not found in your PATH or it's found but no emulator is running "
)
}
}

@OptIn(ExperimentalCoroutinesApi::class)
private suspend fun collectKeypresses() {
dogcat
Expand Down
7 changes: 1 addition & 6 deletions src/nativeMain/kotlin/ui/logLines/LogLinesPresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import AppConfig.DEFAULT_TAG_WIDTH
import AppState
import com.norsedreki.dogcat.Dogcat
import com.norsedreki.dogcat.Unparseable
import com.norsedreki.dogcat.state.PublicState.*
import com.norsedreki.dogcat.state.DogcatState.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
Expand Down Expand Up @@ -91,11 +91,6 @@ class LogLinesPresenter(

emptyFlow()
}

Terminated -> {
Logger.d("${context()} No more reading lines, terminated")
emptyFlow()
}
}
}
.buffer(0) //omg!
Expand Down
4 changes: 2 additions & 2 deletions src/nativeMain/kotlin/ui/status/StatusPresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.norsedreki.dogcat.Command.FilterBy
import com.norsedreki.dogcat.Dogcat
import com.norsedreki.dogcat.LogFilter.ByPackage
import com.norsedreki.dogcat.LogFilter.Substring
import com.norsedreki.dogcat.state.PublicState.Active
import com.norsedreki.dogcat.state.DogcatState.Active
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
Expand Down Expand Up @@ -35,7 +35,7 @@ class StatusPresenter(
//.take(1)
.mapLatest { it }
.onEach {
val filters = it.applied.first()
val filters = it.filters.first()

filters[ByPackage::class]?.let {
appState.filterByPackage(it as ByPackage, true)
Expand Down
Loading

0 comments on commit 362c9bd

Please sign in to comment.