mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat/decoupling (#4685)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
40244f8337
commit
2c49db8041
254 changed files with 5132 additions and 2666 deletions
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
/** Interface for triggering updates to application widgets. */
|
||||
interface AppWidgetUpdater {
|
||||
/** Triggers an update for all app widgets. */
|
||||
suspend fun updateAll()
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import okio.ByteString
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.proto.AdminMessage
|
||||
import org.meshtastic.proto.ChannelSet
|
||||
import org.meshtastic.proto.LocalConfig
|
||||
import org.meshtastic.proto.NeighborInfo
|
||||
|
||||
/** Interface for sending commands and packets to the mesh network. */
|
||||
@Suppress("TooManyFunctions")
|
||||
interface CommandSender {
|
||||
/** Starts the command sender with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Returns the current packet ID. */
|
||||
fun getCurrentPacketId(): Long
|
||||
|
||||
/** Returns the cached local configuration. */
|
||||
fun getCachedLocalConfig(): LocalConfig
|
||||
|
||||
/** Returns the cached channel set. */
|
||||
fun getCachedChannelSet(): ChannelSet
|
||||
|
||||
/** Generates a new unique packet ID. */
|
||||
fun generatePacketId(): Int
|
||||
|
||||
/** The latest neighbor info received from the connected radio. */
|
||||
var lastNeighborInfo: NeighborInfo?
|
||||
|
||||
/** Start times of traceroute requests for duration calculation. */
|
||||
val tracerouteStartTimes: MutableMap<Int, Long>
|
||||
|
||||
/** Start times of neighbor info requests for duration calculation. */
|
||||
val neighborInfoStartTimes: MutableMap<Int, Long>
|
||||
|
||||
/** Sets the session passkey for admin messages. */
|
||||
fun setSessionPasskey(key: ByteString)
|
||||
|
||||
/** Sends a data packet to the mesh. */
|
||||
fun sendData(p: DataPacket)
|
||||
|
||||
/** Sends an admin message to a specific node. */
|
||||
fun sendAdmin(
|
||||
destNum: Int,
|
||||
requestId: Int = generatePacketId(),
|
||||
wantResponse: Boolean = false,
|
||||
initFn: () -> AdminMessage,
|
||||
)
|
||||
|
||||
/** Sends our current position to the mesh. */
|
||||
fun sendPosition(pos: org.meshtastic.proto.Position, destNum: Int? = null, wantResponse: Boolean = false)
|
||||
|
||||
/** Requests the position of a specific node. */
|
||||
fun requestPosition(destNum: Int, currentPosition: Position)
|
||||
|
||||
/** Sets a fixed position for a node. */
|
||||
fun setFixedPosition(destNum: Int, pos: Position)
|
||||
|
||||
/** Requests user info from a specific node. */
|
||||
fun requestUserInfo(destNum: Int)
|
||||
|
||||
/** Requests a traceroute to a specific node. */
|
||||
fun requestTraceroute(requestId: Int, destNum: Int)
|
||||
|
||||
/** Requests telemetry from a specific node. */
|
||||
fun requestTelemetry(requestId: Int, destNum: Int, typeValue: Int)
|
||||
|
||||
/** Requests neighbor info from a specific node. */
|
||||
fun requestNeighborInfo(requestId: Int, destNum: Int)
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/** Interface for managing database instances and cache limits. */
|
||||
interface DatabaseManager {
|
||||
/** Reactive stream of the current database cache limit. */
|
||||
val cacheLimit: StateFlow<Int>
|
||||
|
||||
/** Returns the current database cache limit from storage. */
|
||||
fun getCurrentCacheLimit(): Int
|
||||
|
||||
/** Sets the database cache limit. */
|
||||
fun setCacheLimit(limit: Int)
|
||||
|
||||
/** Switches the active database to the one associated with the given [address]. */
|
||||
suspend fun switchActiveDatabase(address: String?)
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
|
||||
interface DeviceHardwareRepository {
|
||||
/**
|
||||
* Retrieves device hardware information by its model ID and optional target string.
|
||||
*
|
||||
* @param hwModel The hardware model identifier.
|
||||
* @param target Optional PlatformIO target environment name to disambiguate multiple variants.
|
||||
* @param forceRefresh If true, the local cache will be invalidated and data will be fetched remotely.
|
||||
* @return A [Result] containing the [DeviceHardware] on success (or null if not found), or an exception on failure.
|
||||
*/
|
||||
suspend fun getDeviceHardwareByModel(
|
||||
hwModel: Int,
|
||||
target: String? = null,
|
||||
forceRefresh: Boolean = false,
|
||||
): Result<DeviceHardware?>
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import org.meshtastic.proto.FromRadio
|
||||
|
||||
/** Interface for dispatching non-packet [FromRadio] variants to their respective handlers. */
|
||||
interface FromRadioPacketHandler {
|
||||
/** Processes a [FromRadio] message. */
|
||||
fun handleFromRadio(proto: FromRadio)
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
|
||||
/** Interface for managing store-and-forward history replay requests. */
|
||||
interface HistoryManager {
|
||||
/**
|
||||
* Requests a history replay from the radio.
|
||||
*
|
||||
* @param trigger A string identifying the trigger for the request (for logging).
|
||||
* @param myNodeNum The local node number.
|
||||
* @param storeForwardConfig The store-and-forward module configuration.
|
||||
* @param transport The transport method being used (for logging).
|
||||
*/
|
||||
fun requestHistoryReplay(
|
||||
trigger: String,
|
||||
myNodeNum: Int?,
|
||||
storeForwardConfig: ModuleConfig.StoreForwardConfig?,
|
||||
transport: String,
|
||||
)
|
||||
|
||||
/**
|
||||
* Updates the last requested history marker.
|
||||
*
|
||||
* @param source A string identifying the source of the update (for logging).
|
||||
* @param lastRequest The timestamp or sequence number of the last received history message.
|
||||
* @param transport The transport method being used (for logging).
|
||||
*/
|
||||
fun updateStoreForwardLastRequest(source: String, lastRequest: Int, transport: String)
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
interface HomoglyphPrefs {
|
||||
val homoglyphEncodingEnabled: Boolean
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MeshUser
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.model.service.ServiceAction
|
||||
|
||||
/** Interface for handling UI-triggered actions and administrative commands for the mesh. */
|
||||
@Suppress("TooManyFunctions")
|
||||
interface MeshActionHandler {
|
||||
/** Starts the handler with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Processes a service action from the UI. */
|
||||
fun onServiceAction(action: ServiceAction)
|
||||
|
||||
/** Sets the owner of the local node. */
|
||||
fun handleSetOwner(u: MeshUser, myNodeNum: Int)
|
||||
|
||||
/** Sends a data packet through the mesh. */
|
||||
fun handleSend(p: DataPacket, myNodeNum: Int)
|
||||
|
||||
/** Requests the position of a remote node. */
|
||||
fun handleRequestPosition(destNum: Int, position: Position, myNodeNum: Int)
|
||||
|
||||
/** Removes a node from the database by its node number. */
|
||||
fun handleRemoveByNodenum(nodeNum: Int, requestId: Int, myNodeNum: Int)
|
||||
|
||||
/** Sets the owner of a remote node. */
|
||||
fun handleSetRemoteOwner(id: Int, destNum: Int, payload: ByteArray)
|
||||
|
||||
/** Gets the owner of a remote node. */
|
||||
fun handleGetRemoteOwner(id: Int, destNum: Int)
|
||||
|
||||
/** Sets the configuration of the local node. */
|
||||
fun handleSetConfig(payload: ByteArray, myNodeNum: Int)
|
||||
|
||||
/** Sets the configuration of a remote node. */
|
||||
fun handleSetRemoteConfig(id: Int, destNum: Int, payload: ByteArray)
|
||||
|
||||
/** Gets the configuration of a remote node. */
|
||||
fun handleGetRemoteConfig(id: Int, destNum: Int, config: Int)
|
||||
|
||||
/** Sets the module configuration of a remote node. */
|
||||
fun handleSetModuleConfig(id: Int, destNum: Int, payload: ByteArray)
|
||||
|
||||
/** Gets the module configuration of a remote node. */
|
||||
fun handleGetModuleConfig(id: Int, destNum: Int, config: Int)
|
||||
|
||||
/** Sets the ringtone of a remote node. */
|
||||
fun handleSetRingtone(destNum: Int, ringtone: String)
|
||||
|
||||
/** Gets the ringtone of a remote node. */
|
||||
fun handleGetRingtone(id: Int, destNum: Int)
|
||||
|
||||
/** Sets canned messages on a remote node. */
|
||||
fun handleSetCannedMessages(destNum: Int, messages: String)
|
||||
|
||||
/** Gets canned messages from a remote node. */
|
||||
fun handleGetCannedMessages(id: Int, destNum: Int)
|
||||
|
||||
/** Sets a channel configuration on the local node. */
|
||||
fun handleSetChannel(payload: ByteArray?, myNodeNum: Int)
|
||||
|
||||
/** Sets a channel configuration on a remote node. */
|
||||
fun handleSetRemoteChannel(id: Int, destNum: Int, payload: ByteArray?)
|
||||
|
||||
/** Gets a channel configuration from a remote node. */
|
||||
fun handleGetRemoteChannel(id: Int, destNum: Int, index: Int)
|
||||
|
||||
/** Requests neighbor information from a remote node. */
|
||||
fun handleRequestNeighborInfo(requestId: Int, destNum: Int)
|
||||
|
||||
/** Begins editing settings on a remote node. */
|
||||
fun handleBeginEditSettings(destNum: Int)
|
||||
|
||||
/** Commits settings edits on a remote node. */
|
||||
fun handleCommitEditSettings(destNum: Int)
|
||||
|
||||
/** Reboots a remote node into DFU mode. */
|
||||
fun handleRebootToDfu(destNum: Int)
|
||||
|
||||
/** Requests telemetry from a remote node. */
|
||||
fun handleRequestTelemetry(requestId: Int, destNum: Int, type: Int)
|
||||
|
||||
/** Requests a remote node to shut down. */
|
||||
fun handleRequestShutdown(requestId: Int, destNum: Int)
|
||||
|
||||
/** Requests a remote node to reboot. */
|
||||
fun handleRequestReboot(requestId: Int, destNum: Int)
|
||||
|
||||
/** Requests a remote node to reboot in OTA mode. */
|
||||
fun handleRequestRebootOta(requestId: Int, destNum: Int, mode: Int, hash: ByteArray?)
|
||||
|
||||
/** Requests a factory reset on a remote node. */
|
||||
fun handleRequestFactoryReset(requestId: Int, destNum: Int)
|
||||
|
||||
/** Requests a node database reset on a remote node. */
|
||||
fun handleRequestNodedbReset(requestId: Int, destNum: Int, preserveFavorites: Boolean)
|
||||
|
||||
/** Gets the connection status of a remote node. */
|
||||
fun handleGetDeviceConnectionStatus(requestId: Int, destNum: Int)
|
||||
|
||||
/** Updates the last used device address. */
|
||||
fun handleUpdateLastAddress(deviceAddr: String?)
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.MyNodeInfo
|
||||
import org.meshtastic.proto.NodeInfo
|
||||
|
||||
/** Interface for managing the configuration flow, including local node info and metadata. */
|
||||
interface MeshConfigFlowManager {
|
||||
/** Starts the manager with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Handles received local node information. */
|
||||
fun handleMyInfo(myInfo: MyNodeInfo)
|
||||
|
||||
/** Handles received local device metadata. */
|
||||
fun handleLocalMetadata(metadata: DeviceMetadata)
|
||||
|
||||
/** Handles received node information. */
|
||||
fun handleNodeInfo(info: NodeInfo)
|
||||
|
||||
/** Returns the number of nodes received in the current stage. */
|
||||
val newNodeCount: Int
|
||||
|
||||
/** Handles the completion of a configuration stage. */
|
||||
fun handleConfigComplete(configCompleteId: Int)
|
||||
|
||||
/** Triggers a request for the full device configuration. */
|
||||
fun triggerWantConfig()
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.meshtastic.proto.Channel
|
||||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.LocalConfig
|
||||
import org.meshtastic.proto.LocalModuleConfig
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
|
||||
/** Interface for handling device and module configuration updates. */
|
||||
interface MeshConfigHandler {
|
||||
/** Starts the handler with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Reactive local configuration. */
|
||||
val localConfig: StateFlow<LocalConfig>
|
||||
|
||||
/** Reactive local module configuration. */
|
||||
val moduleConfig: StateFlow<LocalModuleConfig>
|
||||
|
||||
/** Handles a received device configuration. */
|
||||
fun handleDeviceConfig(config: Config)
|
||||
|
||||
/** Handles a received module configuration. */
|
||||
fun handleModuleConfig(config: ModuleConfig)
|
||||
|
||||
/** Handles a received channel configuration. */
|
||||
fun handleChannel(channel: Channel)
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.proto.Telemetry
|
||||
|
||||
/** Interface for managing the connection lifecycle and status with the mesh radio. */
|
||||
interface MeshConnectionManager {
|
||||
/** Starts the connection manager with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Called when the radio configuration has been fully loaded. */
|
||||
fun onRadioConfigLoaded()
|
||||
|
||||
/** Initiates the configuration synchronization stage. */
|
||||
fun startConfigOnly()
|
||||
|
||||
/** Initiates the node information synchronization stage. */
|
||||
fun startNodeInfoOnly()
|
||||
|
||||
/** Called when the node database is ready and fully populated. */
|
||||
fun onNodeDbReady()
|
||||
|
||||
/** Updates the telemetry information for the local node. */
|
||||
fun updateTelemetry(t: Telemetry)
|
||||
|
||||
/** Updates and returns the current status notification. */
|
||||
fun updateStatusNotification(telemetry: Telemetry? = null): Any
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
|
||||
/** Interface for handling incoming mesh data packets and routing them to the appropriate handlers. */
|
||||
interface MeshDataHandler {
|
||||
/** Starts the handler with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/**
|
||||
* Processes a received mesh packet.
|
||||
*
|
||||
* @param packet The received mesh packet.
|
||||
* @param myNodeNum The local node number.
|
||||
* @param logUuid Optional UUID for logging purposes.
|
||||
* @param logInsertJob Optional job that tracks the insertion of the packet into the log.
|
||||
*/
|
||||
fun handleReceivedData(packet: MeshPacket, myNodeNum: Int, logUuid: String? = null, logInsertJob: Job? = null)
|
||||
|
||||
/**
|
||||
* Persists a data packet in the history and triggers notifications if necessary.
|
||||
*
|
||||
* @param dataPacket The data packet to remember.
|
||||
* @param myNodeNum The local node number.
|
||||
* @param updateNotification Whether to trigger a notification for this packet.
|
||||
*/
|
||||
fun rememberDataPacket(dataPacket: DataPacket, myNodeNum: Int, updateNotification: Boolean = true)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.proto.Position
|
||||
|
||||
/** Interface for managing the local node's location updates and reporting. */
|
||||
interface MeshLocationManager {
|
||||
/** Starts location updates and reports them via the given function. */
|
||||
fun start(scope: CoroutineScope, sendPositionFn: (Position) -> Unit)
|
||||
|
||||
/** Stops location updates. */
|
||||
fun stop()
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
|
||||
/** Interface for processing incoming radio messages and mesh packets. */
|
||||
interface MeshMessageProcessor {
|
||||
/** Starts the processor with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Handles a raw message received from the radio. */
|
||||
fun handleFromRadio(bytes: ByteArray, myNodeNum: Int?)
|
||||
|
||||
/** Handles a received mesh packet. */
|
||||
fun handleReceivedMeshPacket(packet: MeshPacket, myNodeNum: Int?)
|
||||
|
||||
/** Clears the buffer of early received packets. */
|
||||
fun clearEarlyPackets()
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
/** Interface for the central router that orchestrates specialized mesh packet handlers. */
|
||||
interface MeshRouter {
|
||||
/** Starts the router and its sub-components with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Access to the data handler. */
|
||||
val dataHandler: MeshDataHandler
|
||||
|
||||
/** Access to the configuration handler. */
|
||||
val configHandler: MeshConfigHandler
|
||||
|
||||
/** Access to the traceroute handler. */
|
||||
val tracerouteHandler: TracerouteHandler
|
||||
|
||||
/** Access to the neighbor info handler. */
|
||||
val neighborInfoHandler: NeighborInfoHandler
|
||||
|
||||
/** Access to the configuration flow manager. */
|
||||
val configFlowManager: MeshConfigFlowManager
|
||||
|
||||
/** Access to the MQTT manager. */
|
||||
val mqttManager: MqttManager
|
||||
|
||||
/** Access to the action handler. */
|
||||
val actionHandler: MeshActionHandler
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.proto.ClientNotification
|
||||
import org.meshtastic.proto.Telemetry
|
||||
|
||||
const val SERVICE_NOTIFY_ID = 101
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
interface MeshServiceNotifications {
|
||||
fun clearNotifications()
|
||||
|
||||
fun initChannels()
|
||||
|
||||
fun updateServiceStateNotification(summaryString: String?, telemetry: Telemetry?): Any
|
||||
|
||||
suspend fun updateMessageNotification(
|
||||
contactKey: String,
|
||||
name: String,
|
||||
message: String,
|
||||
isBroadcast: Boolean,
|
||||
channelName: String?,
|
||||
isSilent: Boolean = false,
|
||||
)
|
||||
|
||||
suspend fun updateWaypointNotification(
|
||||
contactKey: String,
|
||||
name: String,
|
||||
message: String,
|
||||
waypointId: Int,
|
||||
isSilent: Boolean = false,
|
||||
)
|
||||
|
||||
suspend fun updateReactionNotification(
|
||||
contactKey: String,
|
||||
name: String,
|
||||
emoji: String,
|
||||
isBroadcast: Boolean,
|
||||
channelName: String?,
|
||||
isSilent: Boolean = false,
|
||||
)
|
||||
|
||||
fun showAlertNotification(contactKey: String, name: String, alert: String)
|
||||
|
||||
fun showNewNodeSeenNotification(node: Node)
|
||||
|
||||
fun showOrUpdateLowBatteryNotification(node: Node, isRemote: Boolean)
|
||||
|
||||
fun showClientNotification(clientNotification: ClientNotification)
|
||||
|
||||
fun cancelMessageNotification(contactKey: String)
|
||||
|
||||
fun cancelLowBatteryNotification(node: Node)
|
||||
|
||||
fun clearClientNotification(notification: ClientNotification)
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
/** Interface for managing background workers for mesh-related tasks. */
|
||||
interface MeshWorkerManager {
|
||||
/** Enqueues a worker to send a specific packet. */
|
||||
fun enqueueSendMessage(packetId: Int)
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
/** Interface for filtering messages based on user-configured filter words. */
|
||||
interface MessageFilter {
|
||||
/**
|
||||
* Determines if a message should be filtered.
|
||||
*
|
||||
* @param message The message text to check.
|
||||
* @param isFilteringDisabled Whether filtering is disabled for the current contact.
|
||||
* @return true if the message should be filtered, false otherwise.
|
||||
*/
|
||||
fun shouldFilter(message: String, isFilteringDisabled: Boolean = false): Boolean
|
||||
|
||||
/** Rebuilds the internal filter patterns. Should be called after filter words are updated. */
|
||||
fun rebuildPatterns()
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
/**
|
||||
* Interface for enqueuing background work for transmitting messages. This allows the domain layer to trigger durable
|
||||
* transmission without depending on Android-specific WorkManager.
|
||||
*/
|
||||
interface MessageQueue {
|
||||
suspend fun enqueue(packetId: Int)
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.proto.MqttClientProxyMessage
|
||||
|
||||
/** Interface for managing MQTT proxy communication. */
|
||||
interface MqttManager {
|
||||
/** Starts the MQTT manager with the given coroutine scope and settings. */
|
||||
fun start(scope: CoroutineScope, enabled: Boolean, proxyToClientEnabled: Boolean)
|
||||
|
||||
/** Stops the MQTT manager. */
|
||||
fun stop()
|
||||
|
||||
/** Handles an MQTT proxy message from the radio. */
|
||||
fun handleMqttProxyMessage(message: MqttClientProxyMessage)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
|
||||
/** Interface for handling neighbor info responses from the mesh. */
|
||||
interface NeighborInfoHandler {
|
||||
/** Starts the neighbor info handler with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/**
|
||||
* Processes a neighbor info packet.
|
||||
*
|
||||
* @param packet The received mesh packet.
|
||||
*/
|
||||
fun handleNeighborInfo(packet: MeshPacket)
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.meshtastic.core.model.MyNodeInfo
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.NodeInfo
|
||||
import org.meshtastic.core.model.util.NodeIdLookup
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.Paxcount
|
||||
import org.meshtastic.proto.StatusMessage
|
||||
import org.meshtastic.proto.Telemetry
|
||||
import org.meshtastic.proto.User
|
||||
import org.meshtastic.proto.NodeInfo as ProtoNodeInfo
|
||||
import org.meshtastic.proto.Position as ProtoPosition
|
||||
|
||||
/** Interface for managing the in-memory node database and processing received node information. */
|
||||
@Suppress("TooManyFunctions")
|
||||
interface NodeManager : NodeIdLookup {
|
||||
/** Reactive map of all nodes by their number. */
|
||||
val nodeDBbyNodeNum: Map<Int, Node>
|
||||
|
||||
/** Reactive map of all nodes by their ID string. */
|
||||
val nodeDBbyID: Map<String, Node>
|
||||
|
||||
/** Whether the node database is ready. */
|
||||
val isNodeDbReady: StateFlow<Boolean>
|
||||
|
||||
/** Sets whether the node database is ready. */
|
||||
fun setNodeDbReady(ready: Boolean)
|
||||
|
||||
/** Whether node database writes are allowed. */
|
||||
val allowNodeDbWrites: StateFlow<Boolean>
|
||||
|
||||
/** Sets whether node database writes are allowed. */
|
||||
fun setAllowNodeDbWrites(allowed: Boolean)
|
||||
|
||||
/** Starts the node manager with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** The local node number. */
|
||||
var myNodeNum: Int?
|
||||
|
||||
/** Loads the cached node database from the repository. */
|
||||
fun loadCachedNodeDB()
|
||||
|
||||
/** Clears the in-memory node database. */
|
||||
fun clear()
|
||||
|
||||
/** Returns information about the local node. */
|
||||
fun getMyNodeInfo(): MyNodeInfo?
|
||||
|
||||
/** Returns the local node ID. */
|
||||
fun getMyId(): String
|
||||
|
||||
/** Returns a list of all known nodes. */
|
||||
fun getNodes(): List<NodeInfo>
|
||||
|
||||
/** Processes a received user packet. */
|
||||
fun handleReceivedUser(fromNum: Int, p: User, channel: Int = 0, manuallyVerified: Boolean = false)
|
||||
|
||||
/** Processes a received position packet. */
|
||||
fun handleReceivedPosition(fromNum: Int, myNodeNum: Int, p: ProtoPosition, defaultTime: Long)
|
||||
|
||||
/** Processes a received telemetry packet. */
|
||||
fun handleReceivedTelemetry(fromNum: Int, telemetry: Telemetry)
|
||||
|
||||
/** Processes a received paxcounter packet. */
|
||||
fun handleReceivedPaxcounter(fromNum: Int, p: Paxcount)
|
||||
|
||||
/** Processes a received node status message. */
|
||||
fun handleReceivedNodeStatus(fromNum: Int, s: StatusMessage)
|
||||
|
||||
/** Updates the status string for a node. */
|
||||
fun updateNodeStatus(nodeNum: Int, status: String?)
|
||||
|
||||
/** Updates a node using a transformation function. */
|
||||
fun updateNode(nodeNum: Int, withBroadcast: Boolean = true, channel: Int = 0, transform: (Node) -> Node)
|
||||
|
||||
/** Removes a node from the in-memory database by its number. */
|
||||
fun removeByNodenum(nodeNum: Int)
|
||||
|
||||
/** Installs node information from a ProtoNodeInfo object. */
|
||||
fun installNodeInfo(info: ProtoNodeInfo, withBroadcast: Boolean = true)
|
||||
|
||||
/** Inserts hardware metadata for a node. */
|
||||
fun insertMetadata(nodeNum: Int, metadata: DeviceMetadata)
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.meshtastic.core.model.MyNodeInfo
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.NodeSortOption
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.LocalStats
|
||||
import org.meshtastic.proto.User
|
||||
|
||||
/**
|
||||
* Repository interface for managing node-related data.
|
||||
*
|
||||
* This component provides access to the mesh's node database, local device information, and mesh-wide statistics. It
|
||||
* supports reactive queries for node lists, counts, and filtered/sorted views.
|
||||
*
|
||||
* This interface is shared across platforms via Kotlin Multiplatform (KMP).
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
interface NodeRepository {
|
||||
/** Reactive flow of hardware info about our local radio device. */
|
||||
val myNodeInfo: StateFlow<MyNodeInfo?>
|
||||
|
||||
/**
|
||||
* Reactive flow of information about the locally connected node as seen by the mesh.
|
||||
*
|
||||
* This includes its position, telemetry, and user information as reflected in the mesh's node DB.
|
||||
*/
|
||||
val ourNodeInfo: StateFlow<Node?>
|
||||
|
||||
/** The unique userId (hex string, e.g., "!1234abcd") of our local node. */
|
||||
val myId: StateFlow<String?>
|
||||
|
||||
/** Reactive flow of the latest local stats telemetry received from the radio. */
|
||||
val localStats: StateFlow<LocalStats>
|
||||
|
||||
/** A reactive map of all known nodes in the mesh, keyed by their 32-bit node number. */
|
||||
val nodeDBbyNum: StateFlow<Map<Int, Node>>
|
||||
|
||||
/** Flow emitting the count of nodes currently considered "online" (heard from recently). */
|
||||
val onlineNodeCount: Flow<Int>
|
||||
|
||||
/** Flow emitting the total number of nodes in the database. */
|
||||
val totalNodeCount: Flow<Int>
|
||||
|
||||
/**
|
||||
* Updates the cached local stats telemetry.
|
||||
*
|
||||
* @param stats The new [LocalStats].
|
||||
*/
|
||||
fun updateLocalStats(stats: LocalStats)
|
||||
|
||||
/**
|
||||
* Returns the node number used for log queries.
|
||||
*
|
||||
* Maps the local node's number to a constant (e.g., 0) to distinguish it from remote logs.
|
||||
*/
|
||||
fun effectiveLogNodeId(nodeNum: Int): Flow<Int>
|
||||
|
||||
/**
|
||||
* Returns the [Node] associated with a given [userId].
|
||||
*
|
||||
* @param userId The hex string identifier.
|
||||
* @return The found [Node] or a fallback object.
|
||||
*/
|
||||
fun getNode(userId: String): Node
|
||||
|
||||
/**
|
||||
* Returns the [User] info for a given [nodeNum].
|
||||
*
|
||||
* @param nodeNum The 32-bit node number.
|
||||
* @return The associated [User] proto.
|
||||
*/
|
||||
fun getUser(nodeNum: Int): User
|
||||
|
||||
/**
|
||||
* Returns the [User] info for a given [userId].
|
||||
*
|
||||
* @param userId The hex string identifier.
|
||||
* @return The associated [User] proto.
|
||||
*/
|
||||
fun getUser(userId: String): User
|
||||
|
||||
/**
|
||||
* Returns a reactive flow of nodes filtered and sorted according to the parameters.
|
||||
*
|
||||
* @param sort The [NodeSortOption] to apply.
|
||||
* @param filter A search string for filtering by name or ID.
|
||||
* @param includeUnknown Whether to include nodes with unset hardware models.
|
||||
* @param onlyOnline Whether to include only nodes currently considered online.
|
||||
* @param onlyDirect Whether to include only nodes heard directly (0 hops away).
|
||||
*/
|
||||
fun getNodes(
|
||||
sort: NodeSortOption = NodeSortOption.LAST_HEARD,
|
||||
filter: String = "",
|
||||
includeUnknown: Boolean = true,
|
||||
onlyOnline: Boolean = false,
|
||||
onlyDirect: Boolean = false,
|
||||
): Flow<List<Node>>
|
||||
|
||||
/** Returns all nodes that haven't been heard from since the given timestamp. */
|
||||
suspend fun getNodesOlderThan(lastHeard: Int): List<Node>
|
||||
|
||||
/** Returns all nodes with unknown hardware models. */
|
||||
suspend fun getUnknownNodes(): List<Node>
|
||||
|
||||
/**
|
||||
* Deletes all nodes from the database.
|
||||
*
|
||||
* @param preserveFavorites If true, nodes marked as favorite will not be deleted.
|
||||
*/
|
||||
suspend fun clearNodeDB(preserveFavorites: Boolean = false)
|
||||
|
||||
/** Clears the local node's connection info from the cache. */
|
||||
suspend fun clearMyNodeInfo()
|
||||
|
||||
/**
|
||||
* Deletes a specific node by its node number.
|
||||
*
|
||||
* @param num The node number to delete.
|
||||
*/
|
||||
suspend fun deleteNode(num: Int)
|
||||
|
||||
/**
|
||||
* Deletes multiple nodes by their node numbers.
|
||||
*
|
||||
* @param nodeNums The list of node numbers to delete.
|
||||
*/
|
||||
suspend fun deleteNodes(nodeNums: List<Int>)
|
||||
|
||||
/**
|
||||
* Updates the personal notes for a node.
|
||||
*
|
||||
* @param num The node number.
|
||||
* @param notes The human-readable notes to persist.
|
||||
*/
|
||||
suspend fun setNodeNotes(num: Int, notes: String)
|
||||
|
||||
/**
|
||||
* Upserts a [Node] into the persistent database.
|
||||
*
|
||||
* @param node The [Node] model to save.
|
||||
*/
|
||||
suspend fun upsert(node: Node)
|
||||
|
||||
/**
|
||||
* Installs initial configuration data (local info and remote nodes) into the database.
|
||||
*
|
||||
* Used during the initial connection handshake.
|
||||
*/
|
||||
suspend fun installConfig(mi: MyNodeInfo, nodes: List<Node>)
|
||||
|
||||
/**
|
||||
* Persists hardware metadata for a node.
|
||||
*
|
||||
* @param nodeNum The node number.
|
||||
* @param metadata The [DeviceMetadata] to save.
|
||||
*/
|
||||
suspend fun insertMetadata(nodeNum: Int, metadata: DeviceMetadata)
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.QueueStatus
|
||||
import org.meshtastic.proto.ToRadio
|
||||
|
||||
/** Interface for handling the transmission of packets to the radio and managing the packet queue. */
|
||||
interface PacketHandler {
|
||||
/** Starts the packet handler with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/** Sends a command/packet directly to the radio. */
|
||||
fun sendToRadio(p: ToRadio)
|
||||
|
||||
/** Adds a mesh packet to the queue for sending. */
|
||||
fun sendToRadio(packet: MeshPacket)
|
||||
|
||||
/** Processes queue status updates from the radio. */
|
||||
fun handleQueueStatus(queueStatus: QueueStatus)
|
||||
|
||||
/** Removes a pending response for a request. */
|
||||
fun removeResponse(dataRequestId: Int, complete: Boolean)
|
||||
|
||||
/** Stops the packet queue. */
|
||||
fun stopPacketQueue()
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.meshtastic.core.model.ContactSettings
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.Message
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.Reaction
|
||||
import org.meshtastic.proto.ChannelSettings
|
||||
|
||||
/**
|
||||
* Repository interface for managing mesh packets and message history.
|
||||
*
|
||||
* This component provides methods for persisting received packets, querying message history, tracking unread counts,
|
||||
* and managing contact-specific settings. It supports both reactive (Flow) and one-shot (suspend) queries.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
interface PacketRepository {
|
||||
/** Reactive flow of all persisted waypoints (GPS locations). */
|
||||
fun getWaypoints(): Flow<List<DataPacket>>
|
||||
|
||||
/** Reactive flow of all conversation contacts, keyed by their contact identifier. */
|
||||
fun getContacts(): Flow<Map<String, DataPacket>>
|
||||
|
||||
/** Reactive paged flow of conversation contacts. */
|
||||
fun getContactsPaged(): Flow<PagingData<DataPacket>>
|
||||
|
||||
/** Returns the total number of messages in a conversation. */
|
||||
suspend fun getMessageCount(contact: String): Int
|
||||
|
||||
/** Returns the count of unread messages in a conversation. */
|
||||
suspend fun getUnreadCount(contact: String): Int
|
||||
|
||||
/** Reactive flow of the UUID of the first unread message in a conversation. */
|
||||
fun getFirstUnreadMessageUuid(contact: String): Flow<Long?>
|
||||
|
||||
/** Reactive flow indicating whether a conversation has any unread messages. */
|
||||
fun hasUnreadMessages(contact: String): Flow<Boolean>
|
||||
|
||||
/** Reactive flow of the total unread message count across all conversations. */
|
||||
fun getUnreadCountTotal(): Flow<Int>
|
||||
|
||||
/** Clears the unread status for messages in a conversation up to the given timestamp. */
|
||||
suspend fun clearUnreadCount(contact: String, timestamp: Long)
|
||||
|
||||
/** Updates the identifier of the last read message in a conversation. */
|
||||
suspend fun updateLastReadMessage(contact: String, messageUuid: Long, lastReadTimestamp: Long)
|
||||
|
||||
/** Returns all packets currently queued for transmission. */
|
||||
suspend fun getQueuedPackets(): List<DataPacket>?
|
||||
|
||||
/**
|
||||
* Persists a packet in the database.
|
||||
*
|
||||
* @param myNodeNum The local node number at the time of receipt.
|
||||
* @param contactKey The identifier of the associated conversation.
|
||||
* @param packet The [DataPacket] to save.
|
||||
* @param receivedTime The timestamp (ms) the packet was received.
|
||||
* @param read Whether the packet should be marked as already read.
|
||||
* @param filtered Whether the packet was filtered by message rules.
|
||||
*/
|
||||
suspend fun savePacket(
|
||||
myNodeNum: Int,
|
||||
contactKey: String,
|
||||
packet: DataPacket,
|
||||
receivedTime: Long,
|
||||
read: Boolean = true,
|
||||
filtered: Boolean = false,
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns a reactive flow of messages for a conversation.
|
||||
*
|
||||
* @param contact The conversation identifier.
|
||||
* @param limit Optional maximum number of messages to return.
|
||||
* @param includeFiltered Whether to include messages that were marked as filtered.
|
||||
* @param getNode Callback to fetch node info for message sender attribution.
|
||||
*/
|
||||
suspend fun getMessagesFrom(
|
||||
contact: String,
|
||||
limit: Int? = null,
|
||||
includeFiltered: Boolean = true,
|
||||
getNode: suspend (String?) -> Node,
|
||||
): Flow<List<Message>>
|
||||
|
||||
/** Returns a paged flow of messages for a conversation. */
|
||||
fun getMessagesFromPaged(contact: String, getNode: suspend (String?) -> Node): Flow<PagingData<Message>>
|
||||
|
||||
/** Returns a paged flow of messages for a conversation, with filtering options. */
|
||||
fun getMessagesFromPaged(
|
||||
contactKey: String,
|
||||
includeFiltered: Boolean,
|
||||
getNode: suspend (String?) -> Node,
|
||||
): Flow<PagingData<Message>>
|
||||
|
||||
/** Updates the transmission status of a packet. */
|
||||
suspend fun updateMessageStatus(d: DataPacket, m: MessageStatus)
|
||||
|
||||
/** Updates the identifier of a persisted packet. */
|
||||
suspend fun updateMessageId(d: DataPacket, id: Int)
|
||||
|
||||
/** Deletes messages by their database UUIDs. */
|
||||
suspend fun deleteMessages(uuidList: List<Long>)
|
||||
|
||||
/** Deletes all messages and settings for the given contacts. */
|
||||
suspend fun deleteContacts(contactList: List<String>)
|
||||
|
||||
/** Deletes a waypoint by its ID. */
|
||||
suspend fun deleteWaypoint(id: Int)
|
||||
|
||||
/** Reactive flow of all contact settings (e.g., mute status). */
|
||||
fun getContactSettings(): Flow<Map<String, ContactSettings>>
|
||||
|
||||
/** Returns the settings for a specific contact. */
|
||||
suspend fun getContactSettings(contact: String): ContactSettings
|
||||
|
||||
/** Mutes the given contacts until the specified timestamp. */
|
||||
suspend fun setMuteUntil(contacts: List<String>, until: Long)
|
||||
|
||||
/** Reactive flow of the number of filtered messages for a contact. */
|
||||
fun getFilteredCountFlow(contactKey: String): Flow<Int>
|
||||
|
||||
/** Returns the total count of filtered messages for a contact. */
|
||||
suspend fun getFilteredCount(contactKey: String): Int
|
||||
|
||||
/** Disables or enables message filtering for a specific contact. */
|
||||
suspend fun setContactFilteringDisabled(contactKey: String, disabled: Boolean)
|
||||
|
||||
/** Clears all packet and message history from the database. */
|
||||
suspend fun clearPacketDB()
|
||||
|
||||
/** Migrates channel-specific message history when encryption keys change. */
|
||||
suspend fun migrateChannelsByPSK(oldSettings: List<ChannelSettings>, newSettings: List<ChannelSettings>)
|
||||
|
||||
/** Marks all messages from a specific sender as filtered or unfiltered. */
|
||||
suspend fun updateFilteredBySender(senderId: String, filtered: Boolean)
|
||||
|
||||
/** Returns a packet by its mesh-layer packet ID. */
|
||||
suspend fun getPacketByPacketId(packetId: Int): DataPacket?
|
||||
|
||||
/** Returns a packet by its internal database ID. */
|
||||
suspend fun getPacketById(id: Int): DataPacket?
|
||||
|
||||
/** Inserts a packet into the database. */
|
||||
suspend fun insert(
|
||||
packet: DataPacket,
|
||||
myNodeNum: Int,
|
||||
contactKey: String,
|
||||
receivedTime: Long,
|
||||
read: Boolean = true,
|
||||
filtered: Boolean = false,
|
||||
)
|
||||
|
||||
/** Updates an existing packet in the database. */
|
||||
suspend fun update(packet: DataPacket)
|
||||
|
||||
/** Persists a message reaction (emoji). */
|
||||
suspend fun insertReaction(reaction: Reaction, myNodeNum: Int)
|
||||
|
||||
/** Updates an existing reaction. */
|
||||
suspend fun updateReaction(reaction: Reaction)
|
||||
|
||||
/** Returns a reaction associated with a specific packet ID. */
|
||||
suspend fun getReactionByPacketId(packetId: Int): Reaction?
|
||||
|
||||
/** Finds all packets matching a specific packet ID. */
|
||||
suspend fun findPacketsWithId(packetId: Int): List<DataPacket>
|
||||
|
||||
/** Finds all reactions associated with a specific packet ID. */
|
||||
suspend fun findReactionsWithId(packetId: Int): List<Reaction>
|
||||
|
||||
/**
|
||||
* Updates the Store-and-Forward PlusPlus (SFPP) status for packets.
|
||||
*
|
||||
* @param packetId The packet ID.
|
||||
* @param from The sender node number.
|
||||
* @param to The recipient node number.
|
||||
* @param hash The SFPP commit hash.
|
||||
* @param status The new SFPP-specific message status.
|
||||
* @param rxTime The receipt time from the mesh.
|
||||
* @param myNodeNum The local node number.
|
||||
*/
|
||||
suspend fun updateSFPPStatus(
|
||||
packetId: Int,
|
||||
from: Int,
|
||||
to: Int,
|
||||
hash: ByteArray,
|
||||
status: MessageStatus,
|
||||
rxTime: Long,
|
||||
myNodeNum: Int?,
|
||||
)
|
||||
|
||||
/** Updates the SFPP status of packets matching the given commit hash. */
|
||||
suspend fun updateSFPPStatusByHash(hash: ByteArray, status: MessageStatus, rxTime: Long)
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.meshtastic.proto.Channel
|
||||
import org.meshtastic.proto.ChannelSet
|
||||
import org.meshtastic.proto.ChannelSettings
|
||||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.DeviceProfile
|
||||
import org.meshtastic.proto.LocalConfig
|
||||
import org.meshtastic.proto.LocalModuleConfig
|
||||
import org.meshtastic.proto.ModuleConfig
|
||||
|
||||
interface RadioConfigRepository {
|
||||
/** Flow representing the [ChannelSet] data store. */
|
||||
val channelSetFlow: Flow<ChannelSet>
|
||||
|
||||
/** Clears the [ChannelSet] data in the data store. */
|
||||
suspend fun clearChannelSet()
|
||||
|
||||
/** Replaces the [ChannelSettings] list with a new [settingsList]. */
|
||||
suspend fun replaceAllSettings(settingsList: List<ChannelSettings>)
|
||||
|
||||
/** Updates the [ChannelSettings] list with the provided channel. */
|
||||
suspend fun updateChannelSettings(channel: Channel)
|
||||
|
||||
/** Flow representing the [LocalConfig] data store. */
|
||||
val localConfigFlow: Flow<LocalConfig>
|
||||
|
||||
/** Clears the [LocalConfig] data in the data store. */
|
||||
suspend fun clearLocalConfig()
|
||||
|
||||
/** Updates [LocalConfig] from each [Config] oneOf. */
|
||||
suspend fun setLocalConfig(config: Config)
|
||||
|
||||
/** Flow representing the [LocalModuleConfig] data store. */
|
||||
val moduleConfigFlow: Flow<LocalModuleConfig>
|
||||
|
||||
/** Clears the [LocalModuleConfig] data in the data store. */
|
||||
suspend fun clearLocalModuleConfig()
|
||||
|
||||
/** Updates [LocalModuleConfig] from each [ModuleConfig] oneOf. */
|
||||
suspend fun setLocalModuleConfig(config: ModuleConfig)
|
||||
|
||||
/** Flow representing the combined [DeviceProfile] protobuf. */
|
||||
val deviceProfileFlow: Flow<DeviceProfile>
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.InterfaceId
|
||||
import org.meshtastic.core.model.MeshActivity
|
||||
|
||||
/** Interface for the low-level radio interface that handles raw byte communication. */
|
||||
interface RadioInterfaceService {
|
||||
/** Reactive connection state of the radio. */
|
||||
val connectionState: StateFlow<ConnectionState>
|
||||
|
||||
/** Flow of the current device address. */
|
||||
val currentDeviceAddressFlow: StateFlow<String?>
|
||||
|
||||
/** Whether we are currently using a mock interface. */
|
||||
fun isMockInterface(): Boolean
|
||||
|
||||
/** Flow of raw data received from the radio. */
|
||||
val receivedData: SharedFlow<ByteArray>
|
||||
|
||||
/** Flow of radio activity events. */
|
||||
val meshActivity: SharedFlow<MeshActivity>
|
||||
|
||||
/** Sends a raw byte array to the radio. */
|
||||
fun sendToRadio(bytes: ByteArray)
|
||||
|
||||
/** Initiates the connection to the radio. */
|
||||
fun connect()
|
||||
|
||||
/** Returns the current device address. */
|
||||
fun getDeviceAddress(): String?
|
||||
|
||||
/** Sets the device address to connect to. */
|
||||
fun setDeviceAddress(deviceAddr: String?): Boolean
|
||||
|
||||
/** Constructs a full radio address for the specific interface type. */
|
||||
fun toInterfaceAddress(interfaceId: InterfaceId, rest: String): String
|
||||
|
||||
/** Called by an interface when it has successfully connected. */
|
||||
fun onConnect()
|
||||
|
||||
/** Called by an interface when it has disconnected. */
|
||||
fun onDisconnect(isPermanent: Boolean)
|
||||
|
||||
/** Called by an interface when it has disconnected with an error. */
|
||||
fun onDisconnect(error: Any)
|
||||
|
||||
/** Called by an interface when it has received raw data from the radio. */
|
||||
fun handleFromRadio(bytes: ByteArray)
|
||||
|
||||
/** The scope in which interface-related coroutines should run. */
|
||||
val serviceScope: CoroutineScope
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
import org.meshtastic.core.model.Node
|
||||
|
||||
/** Interface for broadcasting service-level events to the application. */
|
||||
interface ServiceBroadcasts {
|
||||
/** Subscribes a receiver to mesh broadcasts. */
|
||||
fun subscribeReceiver(receiverName: String, packageName: String)
|
||||
|
||||
/** Broadcasts received data to the application. */
|
||||
fun broadcastReceivedData(dataPacket: DataPacket)
|
||||
|
||||
/** Broadcasts that the radio connection state has changed. */
|
||||
fun broadcastConnection()
|
||||
|
||||
/** Broadcasts that node information has changed. */
|
||||
fun broadcastNodeChange(node: Node)
|
||||
|
||||
/** Broadcasts that the status of a message has changed. */
|
||||
fun broadcastMessageStatus(packetId: Int, status: MessageStatus)
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import co.touchlab.kermit.Severity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.service.ServiceAction
|
||||
import org.meshtastic.core.model.service.TracerouteResponse
|
||||
import org.meshtastic.proto.ClientNotification
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
|
||||
/**
|
||||
* Interface for managing background service state, connection status, and mesh events.
|
||||
*
|
||||
* This repository acts as the primary data bridge between the long-running mesh service and the UI/Feature layers. It
|
||||
* maintains reactive flows for connection status, error messages, and incoming mesh traffic.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
interface ServiceRepository {
|
||||
/** Reactive flow of the current connection state. */
|
||||
val connectionState: StateFlow<ConnectionState>
|
||||
|
||||
/**
|
||||
* Updates the current connection state.
|
||||
*
|
||||
* @param connectionState The new [ConnectionState].
|
||||
*/
|
||||
fun setConnectionState(connectionState: ConnectionState)
|
||||
|
||||
/**
|
||||
* Reactive flow of high-level client notifications.
|
||||
*
|
||||
* These represent events from the mesh client that may require UI feedback.
|
||||
*/
|
||||
val clientNotification: StateFlow<ClientNotification?>
|
||||
|
||||
/**
|
||||
* Sets the current client notification.
|
||||
*
|
||||
* @param notification The [ClientNotification] to display or act upon.
|
||||
*/
|
||||
fun setClientNotification(notification: ClientNotification?)
|
||||
|
||||
/** Clears the current client notification. */
|
||||
fun clearClientNotification()
|
||||
|
||||
/**
|
||||
* Reactive flow of human-readable error messages.
|
||||
*
|
||||
* These are typically shown as snackbars or dialogs in the UI.
|
||||
*/
|
||||
val errorMessage: StateFlow<String?>
|
||||
|
||||
/**
|
||||
* Sets an error message to be displayed.
|
||||
*
|
||||
* @param text The error message text.
|
||||
* @param severity The [Severity] level of the error.
|
||||
*/
|
||||
fun setErrorMessage(text: String, severity: Severity = Severity.Error)
|
||||
|
||||
/** Clears the current error message. */
|
||||
fun clearErrorMessage()
|
||||
|
||||
/**
|
||||
* Reactive flow of connection progress messages.
|
||||
*
|
||||
* Used during the handshake and config loading phase to provide status updates to the user.
|
||||
*/
|
||||
val connectionProgress: StateFlow<String?>
|
||||
|
||||
/**
|
||||
* Sets the connection progress message.
|
||||
*
|
||||
* @param text The progress description (e.g., "Downloading Node DB...").
|
||||
*/
|
||||
fun setConnectionProgress(text: String)
|
||||
|
||||
/**
|
||||
* Flow of all raw [MeshPacket] objects received from the mesh.
|
||||
*
|
||||
* Subscribing to this flow allows components to react to any incoming traffic.
|
||||
*/
|
||||
val meshPacketFlow: SharedFlow<MeshPacket>
|
||||
|
||||
/**
|
||||
* Emits a mesh packet into the flow.
|
||||
*
|
||||
* Called by the packet processor when new data arrives from the radio.
|
||||
*
|
||||
* @param packet The received [MeshPacket].
|
||||
*/
|
||||
suspend fun emitMeshPacket(packet: MeshPacket)
|
||||
|
||||
/** Reactive flow of the most recent traceroute result. */
|
||||
val tracerouteResponse: StateFlow<TracerouteResponse?>
|
||||
|
||||
/**
|
||||
* Sets the traceroute response.
|
||||
*
|
||||
* @param value The [TracerouteResponse] result.
|
||||
*/
|
||||
fun setTracerouteResponse(value: TracerouteResponse?)
|
||||
|
||||
/** Clears the current traceroute response. */
|
||||
fun clearTracerouteResponse()
|
||||
|
||||
/** Reactive flow of the most recent neighbor info response (formatted string). */
|
||||
val neighborInfoResponse: StateFlow<String?>
|
||||
|
||||
/**
|
||||
* Sets the neighbor info response.
|
||||
*
|
||||
* @param value The human-readable neighbor info string.
|
||||
*/
|
||||
fun setNeighborInfoResponse(value: String?)
|
||||
|
||||
/** Clears the current neighbor info response. */
|
||||
fun clearNeighborInfoResponse()
|
||||
|
||||
/** Flow of service actions requested by the UI (e.g., "Favorite Node", "Mute Node"). */
|
||||
val serviceAction: Flow<ServiceAction>
|
||||
|
||||
/**
|
||||
* Dispatches a service action to be handled by the background service.
|
||||
*
|
||||
* @param action The [ServiceAction] to perform.
|
||||
*/
|
||||
suspend fun onServiceAction(action: ServiceAction)
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
|
||||
/** Interface for handling traceroute responses from the mesh. */
|
||||
interface TracerouteHandler {
|
||||
/** Starts the traceroute handler with the given coroutine scope. */
|
||||
fun start(scope: CoroutineScope)
|
||||
|
||||
/**
|
||||
* Processes a traceroute packet.
|
||||
*
|
||||
* @param packet The received mesh packet.
|
||||
* @param logUuid Optional UUID for the associated log entry.
|
||||
* @param logInsertJob Optional job for the log entry insertion, to ensure ordering.
|
||||
*/
|
||||
fun handleTraceroute(packet: MeshPacket, logUuid: String?, logInsertJob: Job?)
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository.usecase
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import org.meshtastic.core.common.util.HomoglyphCharacterStringTransformer
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.model.Capabilities
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.MessageStatus
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.HomoglyphPrefs
|
||||
import org.meshtastic.core.repository.MessageQueue
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.proto.Config
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Use case for sending a message over the mesh network.
|
||||
*
|
||||
* This component orchestrates the process of:
|
||||
* 1. Resolving the destination and sender information.
|
||||
* 2. Handling implicit actions for direct messages (e.g., sharing contacts, favoriting).
|
||||
* 3. Applying message transformations (e.g., homoglyph encoding).
|
||||
* 4. Persisting the outgoing message in the local history.
|
||||
* 5. Enqueuing the message for durable delivery via the platform's message queue.
|
||||
*
|
||||
* This implementation is platform-agnostic and relies on injected repositories and controllers.
|
||||
*/
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
class SendMessageUseCase(
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val packetRepository: PacketRepository,
|
||||
private val radioController: RadioController,
|
||||
private val homoglyphEncodingPrefs: HomoglyphPrefs,
|
||||
private val messageQueue: MessageQueue,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Executes the send message workflow.
|
||||
*
|
||||
* @param text The plain text message to send.
|
||||
* @param contactKey The identifier of the target contact or channel (e.g., "0!ffffffff" for broadcast).
|
||||
* @param replyId Optional ID of a message being replied to.
|
||||
*/
|
||||
@Suppress("NestedBlockDepth", "LongMethod", "CyclomaticComplexMethod")
|
||||
suspend operator fun invoke(
|
||||
text: String,
|
||||
contactKey: String = "0${DataPacket.ID_BROADCAST}",
|
||||
replyId: Int? = null,
|
||||
) {
|
||||
val channel = contactKey[0].digitToIntOrNull()
|
||||
val dest = if (channel != null) contactKey.substring(1) else contactKey
|
||||
|
||||
val ourNode = nodeRepository.ourNodeInfo.value
|
||||
val fromId = ourNode?.user?.id ?: DataPacket.ID_LOCAL
|
||||
|
||||
// logic for direct messages
|
||||
if (channel == null) {
|
||||
val destNode = nodeRepository.getNode(dest)
|
||||
val fwVersion = ourNode?.metadata?.firmware_version
|
||||
val isClientBase = ourNode?.user?.role == Config.DeviceConfig.Role.CLIENT_BASE
|
||||
val capabilities = Capabilities(fwVersion)
|
||||
|
||||
if (capabilities.canSendVerifiedContacts) {
|
||||
sendSharedContact(destNode)
|
||||
} else {
|
||||
if (!destNode.isFavorite && !isClientBase) {
|
||||
favoriteNode(destNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply homoglyph encoding
|
||||
val finalMessageText =
|
||||
if (homoglyphEncodingPrefs.homoglyphEncodingEnabled) {
|
||||
HomoglyphCharacterStringTransformer.optimizeUtf8StringWithHomoglyphs(text)
|
||||
} else {
|
||||
text
|
||||
}
|
||||
|
||||
val packetId = Random.nextInt(1, Int.MAX_VALUE)
|
||||
|
||||
val packet =
|
||||
DataPacket(dest, channel ?: 0, finalMessageText, replyId).apply {
|
||||
from = fromId
|
||||
id = packetId
|
||||
status = MessageStatus.QUEUED
|
||||
}
|
||||
|
||||
try {
|
||||
// Write to the DB to immediately reflect the queued state on the UI
|
||||
packetRepository.savePacket(
|
||||
myNodeNum = ourNode?.num ?: 0,
|
||||
contactKey = contactKey,
|
||||
packet = packet,
|
||||
receivedTime = nowMillis,
|
||||
)
|
||||
|
||||
// Enqueue for durable transmission via the platform-specific queue
|
||||
messageQueue.enqueue(packetId)
|
||||
} catch (ex: Exception) {
|
||||
Logger.e(ex) { "Failed to enqueue message packet" }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun favoriteNode(node: Node) {
|
||||
try {
|
||||
radioController.favoriteNode(node.num)
|
||||
} catch (ex: Exception) {
|
||||
Logger.e(ex) { "Favorite node error" }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun sendSharedContact(node: Node) {
|
||||
try {
|
||||
radioController.sendSharedContact(node.num)
|
||||
} catch (ex: Exception) {
|
||||
Logger.e(ex) { "Send shared contact error" }
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue