mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-13 17:25:04 -04:00
refactor: use SDK remote admin API, eliminate sendRemoteAdmin
- Replace all isLocalNode/sendRemoteAdmin patterns with client.admin.forNode(NodeId(destNum)).method() - Use client.sendReaction() instead of manual MeshPacket construction - Use client.admin.forNode(dest).getDeviceMetadata() for remote metadata - Delete sendRemoteAdmin() and isLocalNode() helpers - Remove unused imports (AdminMessage, Data, MeshPacket from SdkStateBridge) Net: -131 lines, all admin ops now go through SDK's typed API with proper ACK tracking and session-key retry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -173,38 +173,22 @@ class SdkRadioController(
|
||||
|
||||
override suspend fun setOwner(destNum: Int, user: User, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.setOwner(user)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(set_owner = user))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).setOwner(user)
|
||||
}
|
||||
|
||||
override suspend fun setConfig(destNum: Int, config: Config, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.setConfig(config)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(set_config = config))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).setConfig(config)
|
||||
}
|
||||
|
||||
override suspend fun setModuleConfig(destNum: Int, config: ModuleConfig, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.setModuleConfig(config)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(set_module_config = config))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).setModuleConfig(config)
|
||||
}
|
||||
|
||||
override suspend fun setRemoteChannel(destNum: Int, channel: Channel, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.setChannel(channel)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(set_channel = channel))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).setChannel(channel)
|
||||
}
|
||||
|
||||
override suspend fun setFixedPosition(destNum: Int, position: Position) {
|
||||
@@ -215,162 +199,88 @@ class SdkRadioController(
|
||||
altitude = position.altitude,
|
||||
time = position.time,
|
||||
)
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.setFixedPosition(protoPos)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(set_fixed_position = protoPos))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).setFixedPosition(protoPos)
|
||||
}
|
||||
|
||||
override suspend fun setRingtone(destNum: Int, ringtone: String) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.setRingtone(ringtone)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(set_ringtone_message = ringtone))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).setRingtone(ringtone)
|
||||
}
|
||||
|
||||
override suspend fun setCannedMessages(destNum: Int, messages: String) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.setCannedMessages(messages)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(set_canned_message_module_messages = messages))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).setCannedMessages(messages)
|
||||
}
|
||||
|
||||
// ── Remote admin (getters) ──────────────────────────────────────────────
|
||||
|
||||
override suspend fun getOwner(destNum: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.getOwner()
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(get_owner_request = true), wantResponse = true)
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).getOwner()
|
||||
}
|
||||
|
||||
override suspend fun getConfig(destNum: Int, configType: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
val type = AdminMessage.ConfigType.fromValue(configType) ?: return
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.getConfig(type)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(get_config_request = type), wantResponse = true)
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).getConfig(type)
|
||||
}
|
||||
|
||||
override suspend fun getModuleConfig(destNum: Int, moduleConfigType: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
val type = AdminMessage.ModuleConfigType.fromValue(moduleConfigType) ?: return
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.getModuleConfig(type)
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(get_module_config_request = type), wantResponse = true)
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).getModuleConfig(type)
|
||||
}
|
||||
|
||||
override suspend fun getChannel(destNum: Int, index: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.getChannel(ChannelIndex(index))
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(get_channel_request = index + 1), wantResponse = true)
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).getChannel(ChannelIndex(index))
|
||||
}
|
||||
|
||||
override suspend fun getRingtone(destNum: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.getRingtone()
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(get_ringtone_request = true), wantResponse = true)
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).getRingtone()
|
||||
}
|
||||
|
||||
override suspend fun getCannedMessages(destNum: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.getCannedMessages()
|
||||
} else {
|
||||
sendRemoteAdmin(
|
||||
c,
|
||||
destNum,
|
||||
AdminMessage(get_canned_message_module_messages_request = true),
|
||||
wantResponse = true,
|
||||
)
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).getCannedMessages()
|
||||
}
|
||||
|
||||
override suspend fun getDeviceConnectionStatus(destNum: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.getDeviceConnectionStatus()
|
||||
} else {
|
||||
sendRemoteAdmin(
|
||||
c,
|
||||
destNum,
|
||||
AdminMessage(get_device_connection_status_request = true),
|
||||
wantResponse = true,
|
||||
)
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).getDeviceConnectionStatus()
|
||||
}
|
||||
|
||||
// ── Lifecycle commands ───────────────────────────────────────────────────
|
||||
|
||||
override suspend fun reboot(destNum: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.reboot()
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(reboot_seconds = 0))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).reboot()
|
||||
}
|
||||
|
||||
override suspend fun rebootToDfu(nodeNum: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(nodeNum)) {
|
||||
c.admin.enterDfuMode()
|
||||
} else {
|
||||
sendRemoteAdmin(c, nodeNum, AdminMessage(enter_dfu_mode_request = true))
|
||||
}
|
||||
c.admin.forNode(NodeId(nodeNum)).enterDfuMode()
|
||||
}
|
||||
|
||||
override suspend fun requestRebootOta(requestId: Int, destNum: Int, mode: Int, hash: ByteArray?) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.rebootOta()
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(reboot_ota_seconds = 0))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).rebootOta()
|
||||
}
|
||||
|
||||
override suspend fun shutdown(destNum: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.shutdown()
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(shutdown_seconds = 0))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).shutdown()
|
||||
}
|
||||
|
||||
override suspend fun factoryReset(destNum: Int, packetId: Int) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.factoryReset()
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(factory_reset_config = 1))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).factoryReset()
|
||||
}
|
||||
|
||||
override suspend fun nodedbReset(destNum: Int, packetId: Int, preserveFavorites: Boolean) {
|
||||
val c = requireClient()
|
||||
if (isLocalNode(destNum)) {
|
||||
c.admin.nodeDbReset()
|
||||
} else {
|
||||
sendRemoteAdmin(c, destNum, AdminMessage(nodedb_reset = true))
|
||||
}
|
||||
c.admin.forNode(NodeId(destNum)).nodeDbReset()
|
||||
}
|
||||
|
||||
override suspend fun removeByNodenum(packetId: Int, nodeNum: Int) {
|
||||
@@ -459,17 +369,27 @@ class SdkRadioController(
|
||||
// ── Edit settings (transactional) ───────────────────────────────────────
|
||||
|
||||
override suspend fun beginEditSettings(destNum: Int) {
|
||||
val c = client ?: return
|
||||
val msg = AdminMessage(begin_edit_settings = true)
|
||||
val target = if (isLocalNode(destNum)) NodeId(c.ownNode.value?.num ?: 0) else NodeId(destNum)
|
||||
sendRemoteAdmin(c, target.raw, msg)
|
||||
val c = requireClient()
|
||||
val target = resolveTarget(c, destNum)
|
||||
val payload = AdminMessage.ADAPTER.encode(AdminMessage(begin_edit_settings = true))
|
||||
c.send(
|
||||
portnum = PortNum.ADMIN_APP,
|
||||
payload = payload,
|
||||
to = target,
|
||||
wantAck = false,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun commitEditSettings(destNum: Int) {
|
||||
val c = client ?: return
|
||||
val msg = AdminMessage(commit_edit_settings = true)
|
||||
val target = if (isLocalNode(destNum)) NodeId(c.ownNode.value?.num ?: 0) else NodeId(destNum)
|
||||
sendRemoteAdmin(c, target.raw, msg)
|
||||
val c = requireClient()
|
||||
val target = resolveTarget(c, destNum)
|
||||
val payload = AdminMessage.ADAPTER.encode(AdminMessage(commit_edit_settings = true))
|
||||
c.send(
|
||||
portnum = PortNum.ADMIN_APP,
|
||||
payload = payload,
|
||||
to = target,
|
||||
wantAck = true,
|
||||
)
|
||||
}
|
||||
|
||||
// ── Utility ─────────────────────────────────────────────────────────────
|
||||
@@ -490,34 +410,8 @@ class SdkRadioController(
|
||||
|
||||
// ── Private helpers ─────────────────────────────────────────────────────
|
||||
|
||||
private fun isLocalNode(destNum: Int): Boolean {
|
||||
if (destNum == 0) return true
|
||||
val ownNum = client?.ownNode?.value?.num ?: return true
|
||||
return destNum == ownNum
|
||||
}
|
||||
|
||||
private suspend fun sendRemoteAdmin(
|
||||
c: RadioClient,
|
||||
destNum: Int,
|
||||
adminMsg: AdminMessage,
|
||||
wantResponse: Boolean = false,
|
||||
) {
|
||||
val payload = AdminMessage.ADAPTER.encode(adminMsg).toByteString()
|
||||
try {
|
||||
c.send(
|
||||
MeshPacket(
|
||||
to = destNum,
|
||||
want_ack = true,
|
||||
decoded = Data(
|
||||
portnum = PortNum.ADMIN_APP,
|
||||
payload = payload,
|
||||
want_response = wantResponse,
|
||||
),
|
||||
),
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Logger.e(e) { "sendRemoteAdmin to $destNum failed" }
|
||||
throw e
|
||||
}
|
||||
private fun resolveTarget(c: RadioClient, destNum: Int): NodeId {
|
||||
if (destNum == 0) return NodeId(c.ownNode.value?.num ?: 0)
|
||||
return NodeId(destNum)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
@@ -42,13 +41,11 @@ import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.core.repository.UiPrefs
|
||||
import org.meshtastic.proto.AdminMessage
|
||||
import org.meshtastic.proto.ClientNotification
|
||||
import org.meshtastic.proto.Data
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.User
|
||||
import org.meshtastic.sdk.AdminResult
|
||||
import org.meshtastic.sdk.ChannelIndex
|
||||
import org.meshtastic.sdk.ConnectionState as SdkConnectionState
|
||||
import org.meshtastic.sdk.MeshEvent
|
||||
import org.meshtastic.sdk.NodeChange
|
||||
@@ -330,18 +327,11 @@ class SdkStateBridge(
|
||||
val channel = action.contactKey[0].digitToInt()
|
||||
val destId = action.contactKey.substring(1)
|
||||
val destNum = runCatching { DataPacket.parseNodeNum(destId) }.getOrDefault(DataPacket.BROADCAST)
|
||||
client.send(
|
||||
MeshPacket(
|
||||
to = destNum,
|
||||
channel = channel,
|
||||
want_ack = true,
|
||||
decoded = Data(
|
||||
portnum = PortNum.TEXT_MESSAGE_APP,
|
||||
payload = action.emoji.encodeToByteArray().toByteString(),
|
||||
emoji = EMOJI_INDICATOR,
|
||||
reply_id = action.replyId,
|
||||
),
|
||||
),
|
||||
client.sendReaction(
|
||||
emoji = action.emoji,
|
||||
to = NodeId(destNum),
|
||||
channel = ChannelIndex(channel),
|
||||
replyId = action.replyId,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -365,27 +355,12 @@ class SdkStateBridge(
|
||||
}
|
||||
|
||||
is ServiceAction.GetDeviceMetadata -> {
|
||||
val payload = AdminMessage.ADAPTER.encode(
|
||||
AdminMessage(get_device_metadata_request = true),
|
||||
).toByteString()
|
||||
client.send(
|
||||
MeshPacket(
|
||||
to = action.destNum,
|
||||
want_ack = true,
|
||||
decoded = Data(
|
||||
portnum = PortNum.ADMIN_APP,
|
||||
payload = payload,
|
||||
want_response = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
client.admin.forNode(NodeId(action.destNum)).getDeviceMetadata()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val EMOJI_INDICATOR = 1
|
||||
|
||||
private fun mapConnectionState(sdkState: SdkConnectionState): AppConnectionState = when (sdkState) {
|
||||
is SdkConnectionState.Disconnected -> AppConnectionState.Disconnected
|
||||
is SdkConnectionState.Connecting -> AppConnectionState.Connecting(attempt = sdkState.attempt)
|
||||
|
||||
Reference in New Issue
Block a user