协议编写 Kotlin 封装

134 阅读23分钟

import android.os.Parcelable
import androidx.annotation.FloatRange
import androidx.annotation.IntRange
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 获取Portable摘要信息响应
 * 操作码: 0xe09b (TMP_APPV2_OP_MER_PORTABLE_SUMMARY_INFO_GET)
 */
@Parcelize
data class PortableSummaryInfoGetResponse(
    /**
     * 错误码
     */
    @SerializedName("error_code")
    val errorCode: Int? = null,
    
    /**
     * 结果数据
     */
    val result: PortableSummaryInfo? = null
) : Parcelable

@Parcelize
data class PortableSummaryInfo(
    /**
     * 设备当前的网络模式
     * 值域: router/3g_4g_modem/usb_tethering/re/ap/hotspot
     */
    @SerializedName("network_mode")
    @NetworkMode
    val networkMode: String? = null,
    
    /**
     * 设备当前的操作模式
     * 值域: Router/Extender
     */
    @SerializedName("portable_mode")
    @PortableMode
    val portableMode: String? = null,
    
    /**
     * 支持的internet_mode列表
     * 可选字段,portable_mode为router时传递
     */
    @SerializedName("support_mode_list")
    val supportModeList: List<String>? = null,
    
    /**
     * Router模式信息
     * 可选字段,portable_mode为router时传递
     */
    @SerializedName("router_mode_info")
    val routerModeInfo: RouterModeInfo? = null,
    
    /**
     * Extender模式信息
     * 可选字段,portable_mode为extender时传递
     */
    @SerializedName("extender_mode_info")
    val extenderModeInfo: ExtenderModeInfo? = null,
    
    /**
     * Host WiFi信息
     * 可选字段,portable_mode为extender时传递
     */
    @SerializedName("host_wifi_info")
    val hostWifiInfo: HostWifiInfo? = null,
    
    /**
     * 设备当前档位之间子模式切换需要等待的时间(单位:秒)
     */
    @SerializedName("switch_mode_time")
    val switchModeTime: Int? = null,
    
    /**
     * 设备是否支持portal检测
     */
    @SerializedName("portal_detect_support")
    val portalDetectSupport: Boolean? = null
) : Parcelable

/**
 * Router模式信息
 */
@Parcelize
data class RouterModeInfo(
    /**
     * internet模式,值域: backup/load_balance
     */
    @InternetMode
    val mode: String? = null,
    
    /**
     * 各个入网方式的配置
     */
    @SerializedName("info_list")
    val infoList: List<ConnectionStatusBean>? = null
) : Parcelable

/**
 * 连接状态信息
 */
@Parcelize
data class ConnectionStatusBean(
    /**
     * 入网方式,值域: ethernet/usb/hotspot
     */
    @SerializedName("connection_type")
    @ConnectionType
    val connectionType: String? = null,
    
    /**
     * 预期流量分配量,值域: 0-10
     */
    @SerializedName("load_configuration")
    @IntRange(from = 0, to = 10)
    val loadConfiguration: Int? = null,
    
    /**
     * 优先级,值域: 1-3,优先级1>2>3
     */
    @IntRange(from = 1, to = 3)
    val priority: Int? = null,
    
    /**
     * 连接状态
     * backup模式: use/idle/off/no_internet/unplugged
     * load_balance模式: on/off/no_internet/unplugged
     */
    @ConnectionStatus
    val status: String? = null,
    
    /**
     * 实时流量占比
     * 可选字段,仅load_balance模式下返回
     * 值域: 0-100,精确到小数点后一位
     */
    @SerializedName("traffic_rate")
    @FloatRange(from = 0.0, to = 100.0)
    val trafficRate: Float? = null,
    
    /**
     * USB类型
     * USB独有字段,值域: 3g_4g_modem/usb_tethering
     */
    @SerializedName("usb_type")
    @UsbType
    val usbType: String? = null,
    
    /**
     * Host WiFi的SSID(Base64编码)
     * hotspot独有字段,status不为off时返回
     */
    @SerializedName("host_wifi_ssid")
    val hostWifiSsid: String? = null,
    
    /**
     * Host WiFi的MAC地址
     * hotspot独有字段,status不为off时返回
     */
    @SerializedName("host_wifi_mac")
    val hostWifiMac: String? = null
) : Parcelable

/**
 * Extender模式信息
 */
@Parcelize
data class ExtenderModeInfo(
    /**
     * ethernet口是否接入
     */
    @SerializedName("ethernet_plugged")
    val ethernetPlugged: Boolean? = null,
    
    /**
     * ethernet口是否连接(网络是否连通)
     */
    @SerializedName("ethernet_connected")
    val ethernetConnected: Boolean? = null
) : Parcelable

/**
 * Host WiFi信息
 */
@Parcelize
data class HostWifiInfo(
    /**
     * host wifi是否开启
     */
    @SerializedName("host_wifi_enable")
    val hostWifiEnable: Boolean? = null,
    
    /**
     * host wifi的SSID(Base64编码)
     * host_wifi_enable为true且已连接前端网络时才传
     */
    @SerializedName("host_wifi_ssid")
    val hostWifiSsid: String? = null,
    
    /**
     * host wifi的MAC地址
     * host_wifi_enable为true且已连接前端网络时才传
     */
    @SerializedName("host_wifi_mac")
    val hostWifiMac: String? = null
) : Parcelable

// ==================== 注解定义 ====================

/**
 * 网络模式注解
 */
@StringDef(
    NetworkModeValue.ROUTER,
    NetworkModeValue.THREE_G_4G_MODEM,
    NetworkModeValue.USB_TETHERING,
    NetworkModeValue.RE,
    NetworkModeValue.AP,
    NetworkModeValue.HOTSPOT
)
@Retention(AnnotationRetention.SOURCE)
annotation class NetworkMode

object NetworkModeValue {
    const val ROUTER = "router"
    const val THREE_G_4G_MODEM = "3g_4g_modem"
    const val USB_TETHERING = "usb_tethering"
    const val RE = "re"
    const val AP = "ap"
    const val HOTSPOT = "hotspot"
}

/**
 * Portable模式注解
 */
@StringDef(
    PortableModeValue.ROUTER,
    PortableModeValue.EXTENDER
)
@Retention(AnnotationRetention.SOURCE)
annotation class PortableMode

object PortableModeValue {
    const val ROUTER = "Router"
    const val EXTENDER = "Extender"
}

/**
 * 连接状态注解
 */
@StringDef(
    ConnectionStatusValue.USE,
    ConnectionStatusValue.IDLE,
    ConnectionStatusValue.OFF,
    ConnectionStatusValue.NO_INTERNET,
    ConnectionStatusValue.UNPLUGGED,
    ConnectionStatusValue.ON
)
@Retention(AnnotationRetention.SOURCE)
annotation class ConnectionStatus

object ConnectionStatusValue {
    // backup模式状态
    const val USE = "use"
    const val IDLE = "idle"
    const val OFF = "off"
    const val NO_INTERNET = "no_internet"
    const val UNPLUGGED = "unplugged"
    
    // load_balance模式状态
    const val ON = "on"
}

/**
 * USB类型注解
 */
@StringDef(
    UsbTypeValue.THREE_G_4G_MODEM,
    UsbTypeValue.USB_TETHERING
)
@Retention(AnnotationRetention.SOURCE)
annotation class UsbType

object UsbTypeValue {
    const val THREE_G_4G_MODEM = "3g_4g_modem"
    const val USB_TETHERING = "usb_tethering"
}

import android.os.Parcelable
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 修改指定入网方式的启用状态
 * 操作码: 0xe09d (TMP_APPV2_OP_MER_PORTABLE_ROUTER_INTERNET_CONNECTION_STATUS_SET)
 */
@Parcelize
data class PortableRouterInternetConnectionStatusSet(
    /**
     * 启用状态
     * true: 开启、建立连接
     * false: 关闭、断开连接
     */
    val enable: Boolean? = null,
    
    /**
     * 要设置的入网方式
     * 值域: ethernet/usb/hotspot
     */
    @SerializedName("connection_type")
    @ConnectionType
    val connectionType: String? = null
) : Parcelable

/**
 * 设置USB类型
 * 操作码: 0xe09e (TMP_APPV2_OP_MER_PORTABLE_USB_TYPE_SET)
 */
@Parcelize
data class PortableUsbTypeSet(
    /**
     * USB类型
     * 值域: 3g_4g_modem/usb_tethering
     */
    @SerializedName("usb_type")
    @UsbType
    val usbType: String? = null
) : Parcelable

/**
 * hotspot模式检测Portal状态
 * 操作码: 0xe09f (TMP_APPV2_OP_MER_PORTABLE_PORTAL_DETECT)
 */
@Parcelize
data class PortablePortalDetect(
    /**
     * 激活或获取portal detect
     * activate: 激活portal detect
     * check: 重复拉取当前detect状态
     * 注意:仅hotspot模式下支持
     */
    @PortalDetectAction
    val action: String? = null
) : Parcelable

// ==================== 注解定义 ====================

/**
 * Portal检测动作注解
 */
@StringDef(
    PortalDetectActionValue.ACTIVATE,
    PortalDetectActionValue.CHECK
)
@Retention(AnnotationRetention.SOURCE)
annotation class PortalDetectAction

object PortalDetectActionValue {
    /**
     * 激活portal detect
     */
    const val ACTIVATE = "activate"
    
    /**
     * 重复拉取当前detect状态
     */
    const val CHECK = "check"
}

import android.os.Parcelable
import androidx.annotation.IntRange
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 获取USB Internet信息响应
 * 操作码: 0xe08d (TMP_APPV2_OP_MER_USB_INTERNET_INFO_GET)
 */
@Parcelize
data class UsbInternetInfoGetResponse(
    /**
     * 错误码
     */
    @SerializedName("error_code")
    val errorCode: Int? = null,
    
    /**
     * 结果数据
     */
    val result: UsbInternetInfo? = null
) : Parcelable

@Parcelize
data class UsbInternetInfo(
    /**
     * USB状态
     * 值域: unknown/plugged/unplugged/identifying
     */
    @SerializedName("usb_status")
    @UsbStatus
    val usbStatus: String? = null,
    
    /**
     * SIM卡状态
     * 值域: unknown/ready/pin_lock/puk_lock
     */
    @SerializedName("sim_status")
    @SimStatus
    val simStatus: String? = null,
    
    /**
     * Internet连接状态
     * 值域: unknown/connected/connecting/disconnected
     */
    @SerializedName("conn_status")
    @ConnectionStatusInternet
    val connStatus: String? = null,
    
    /**
     * 信号强度百分比
     * 值域: 0-100
     */
    @SerializedName("signal_percent")
    @IntRange(from = 0, to = 100)
    val signalPercent: Int? = null,
    
    /**
     * IP地址
     */
    val ip: String? = null,
    
    /**
     * 默认网关
     */
    val gateway: String? = null,
    
    /**
     * 主DNS
     */
    @SerializedName("mDNS")
    val mainDns: String? = null,
    
    /**
     * 备用DNS
     */
    @SerializedName("sDNS")
    val secondaryDns: String? = null,
    
    /**
     * ISP文件的MD5码
     * 32字节的十六进制数,字母为大写
     */
    @SerializedName("isp_file_md5")
    val ispFileMd5: String? = null,
    
    /**
     * ISP文件绝对路径
     */
    @SerializedName("isp_file_path")
    val ispFilePath: String? = null,
    
    /**
     * 国家名称
     */
    val location: String? = null,
    
    /**
     * 运营商名称
     */
    val isp: String? = null,
    
    /**
     * 是否使用手动拨号配置
     */
    @SerializedName("is_manual")
    val isManual: Boolean? = null,
    
    /**
     * 国家名称编号
     * 值域需参考设备传回的ISP文件
     */
    @SerializedName("location_index")
    val locationIndex: Int? = null,
    
    /**
     * 运营商名称编号
     * 值域需参考设备传回的ISP文件
     */
    @SerializedName("isp_index")
    val ispIndex: Int? = null,
    
    /**
     * 手动拨号号码
     * 合法值域: 十进制数、'#'、'*'
     */
    val number: String? = null,
    
    /**
     * 手动拨号APN名称
     */
    val apn: String? = null,
    
    /**
     * 手动拨号认证用户名
     */
    val username: String? = null,
    
    /**
     * 手动拨号认证密码
     */
    val password: String? = null,
    
    /**
     * 3G/4G连接模式
     * 值域: auto/demand/manually
     */
    @SerializedName("conn_mode")
    @ConnectionMode
    val connMode: String? = null,
    
    /**
     * 最大空闲时间(单位:分钟)
     * 值域: 0-99,0表示always
     */
    @SerializedName("max_idle_time")
    @IntRange(from = 0, to = 99)
    val maxIdleTime: Int? = null,
    
    /**
     * 授权类型
     * 值域: auto/PAP/CHAP
     */
    @SerializedName("auth_type")
    @AuthType
    val authType: String? = null,
    
    /**
     * 最大传输单元
     * 值域由设备端确认
     */
    @SerializedName("mtu_size")
    val mtuSize: Int? = null,
    
    /**
     * 是否开启自定义DNS
     */
    @SerializedName("use_custom_dns")
    val useCustomDns: Boolean? = null,
    
    /**
     * 自定义DNS信息
     * 可选字段,仅当use_custom_dns为true时传
     */
    @SerializedName("custom_dns_info")
    val customDnsInfo: CustomDnsInfo? = null
) : Parcelable

/**
 * 自定义DNS信息
 */
@Parcelize
data class CustomDnsInfo(
    /**
     * 首选DNS
     */
    val dns1: String? = null,
    
    /**
     * 备选DNS
     */
    val dns2: String? = null
) : Parcelable

// ==================== 注解定义 ====================

/**
 * USB状态注解
 */
@StringDef(
    UsbStatusValue.UNKNOWN,
    UsbStatusValue.PLUGGED,
    UsbStatusValue.UNPLUGGED,
    UsbStatusValue.IDENTIFYING
)
@Retention(AnnotationRetention.SOURCE)
annotation class UsbStatus

object UsbStatusValue {
    const val UNKNOWN = "unknown"
    const val PLUGGED = "plugged"
    const val UNPLUGGED = "unplugged"
    const val IDENTIFYING = "identifying"
}

/**
 * SIM卡状态注解
 */
@StringDef(
    SimStatusValue.UNKNOWN,
    SimStatusValue.READY,
    SimStatusValue.PIN_LOCK,
    SimStatusValue.PUK_LOCK
)
@Retention(AnnotationRetention.SOURCE)
annotation class SimStatus

object SimStatusValue {
    const val UNKNOWN = "unknown"
    const val READY = "ready"
    const val PIN_LOCK = "pin_lock"
    const val PUK_LOCK = "puk_lock"
}

/**
 * Internet连接状态注解
 */
@StringDef(
    ConnectionStatusInternetValue.UNKNOWN,
    ConnectionStatusInternetValue.CONNECTED,
    ConnectionStatusInternetValue.CONNECTING,
    ConnectionStatusInternetValue.DISCONNECTED
)
@Retention(AnnotationRetention.SOURCE)
annotation class ConnectionStatusInternet

object ConnectionStatusInternetValue {
    const val UNKNOWN = "unknown"
    const val CONNECTED = "connected"
    const val CONNECTING = "connecting"
    const val DISCONNECTED = "disconnected"
}

/**
 * 连接模式注解
 */
@StringDef(
    ConnectionModeValue.AUTO,
    ConnectionModeValue.DEMAND,
    ConnectionModeValue.MANUALLY
)
@Retention(AnnotationRetention.SOURCE)
annotation class ConnectionMode

object ConnectionModeValue {
    const val AUTO = "auto"
    const val DEMAND = "demand"
    const val MANUALLY = "manually"
}

/**
 * 授权类型注解
 */
@StringDef(
    AuthTypeValue.AUTO,
    AuthTypeValue.PAP,
    AuthTypeValue.CHAP
)
@Retention(AnnotationRetention.SOURCE)
annotation class AuthType

object AuthTypeValue {
    const val AUTO = "auto"
    const val PAP = "PAP"
    const val CHAP = "CHAP"
}

import android.os.Parcelable
import androidx.annotation.IntRange
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 设置USB Internet信息
 * 操作码: 0xe08e (TMP_APPV2_OP_MER_USB_INTERNET_INFO_SET)
 */
@Parcelize
data class UsbInternetInfoSet(
    /**
     * 是否使用手动拨号配置
     */
    @SerializedName("is_manual")
    val isManual: Boolean? = null,
    
    /**
     * 国家名称编号
     * 值域需参考设备传回的ISP文件
     */
    @SerializedName("location_index")
    val locationIndex: Int? = null,
    
    /**
     * 运营商名称编号
     * 值域需参考设备传回的ISP文件
     */
    @SerializedName("isp_index")
    val ispIndex: Int? = null,
    
    /**
     * 手动拨号号码(Base64编码)
     * 合法值域: 十进制数、'#'、'*'
     */
    val number: String? = null,
    
    /**
     * 手动拨号APN名称(Base64编码)
     */
    val apn: String? = null,
    
    /**
     * 手动拨号认证用户名(Base64编码)
     */
    val username: String? = null,
    
    /**
     * 手动拨号认证密码(Base64编码)
     */
    val password: String? = null,
    
    /**
     * 3G/4G连接模式
     * 值域: auto/demand/manually
     */
    @SerializedName("conn_mode")
    @ConnectionMode
    val connMode: String? = null,
    
    /**
     * 最大空闲时间(单位:分钟)
     * 值域: 0-99,0表示always
     */
    @SerializedName("max_idle_time")
    @IntRange(from = 0, to = 99)
    val maxIdleTime: Int? = null,
    
    /**
     * 授权类型
     * 值域: auto/PAP/CHAP
     */
    @SerializedName("auth_type")
    @AuthType
    val authType: String? = null,
    
    /**
     * 最大传输单元
     * 值域由设备端确认
     */
    @SerializedName("mtu_size")
    val mtuSize: Int? = null,
    
    /**
     * 是否开启自定义DNS
     */
    @SerializedName("use_custom_dns")
    val useCustomDns: Boolean? = null,
    
    /**
     * 自定义DNS信息
     * 可选字段,仅当use_custom_dns为true时传
     */
    @SerializedName("custom_dns_info")
    val customDnsInfo: CustomDnsInfo? = null
) : Parcelable

import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 解锁PIN码
 * 操作码: 0xe08f (TMP_APPV2_OP_MER_USB_INTERNET_PIN_UNLOCK)
 */
@Parcelize
data class UsbInternetPinUnlock(
    /**
     * PIN码的值
     * 值域: 4-8位十进制数
     * 示例: "1234", "12345678"
     */
    @SerializedName("pin_code")
    val pinCode: String? = null
) : Parcelable {
    
    companion object {
        /**
         * PIN码最小长度
         */
        const val PIN_CODE_MIN_LENGTH = 4
        
        /**
         * PIN码最大长度
         */
        const val PIN_CODE_MAX_LENGTH = 8
        
        /**
         * 验证PIN码格式是否合法
         * @param pinCode PIN码字符串
         * @return true表示格式合法,false表示不合法
         */
        fun isValidPinCode(pinCode: String?): Boolean {
            if (pinCode.isNullOrEmpty()) return false
            
            // 检查长度
            if (pinCode.length !in PIN_CODE_MIN_LENGTH..PIN_CODE_MAX_LENGTH) {
                return false
            }
            
            // 检查是否为纯数字
            return pinCode.all { it.isDigit() }
        }
    }
}

import android.os.Parcelable
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * IPV4信息获取响应
 * 操作码: 0xe02c (TMP_APPV2_OP_MER_IPV4_GET)
 */
@Parcelize
data class Ipv4GetResponse(
    /**
     * 错误码
     */
    @SerializedName("error_code")
    val errorCode: Int? = null,
    
    /**
     * 结果数据
     */
    val result: Ipv4Info? = null
) : Parcelable

@Parcelize
data class Ipv4Info(
    /**
     * 当前设备返回的wan信息是否是从backup mode拿到的
     * 可选字段,不支持mer_backup_auto_wan组件则不传
     */
    @SerializedName("ipv4_wan_from_backup")
    val ipv4WanFromBackup: Boolean? = null,
    
    /**
     * Backup类型
     * 值域: ethernet/mobile_5g/lte
     * 可选字段,不支持mer_backup_auto_wan组件则不传
     */
    @SerializedName("backup_mode")
    @BackupMode
    val backupMode: String? = null,
    
    /**
     * 是否支持WAN类型自动检测
     * 可选字段,请求参数connection_type为ethernet时传
     * 各拨号方式下均需要返回
     */
    @SerializedName("is_support_auto_detect")
    val isSupportAutoDetect: Boolean? = null,
    
    /**
     * 支持的拨号方式集合
     * 可选字段,请求参数connection_type不为空时传
     * 元素值域同dial_type,不返回时APP维持原逻辑
     * 各拨号方式下均需要返回
     */
    @SerializedName("support_dial_type_list")
    val supportDialTypeList: List<String>? = null,
    
    /**
     * WAN配置信息
     */
    val wan: WanInfo? = null,
    
    /**
     * LAN配置信息
     */
    val lan: LanInfo? = null
) : Parcelable

/**
 * WAN配置信息
 */
@Parcelize
data class WanInfo(
    /**
     * 拨号类型
     * 值域: dynamic_ip/static_ip/pppoe/l2tp/pptp
     */
    @SerializedName("dial_type")
    @DialType
    val dialType: String? = null,
    
    /**
     * IP信息
     * 用于 dynamic_ip、static_ip、pppoe 场景
     */
    @SerializedName("ip_info")
    val ipInfo: IpInfo? = null,
    
    /**
     * 主IP信息
     * 用于 l2tp、pptp 场景
     */
    @SerializedName("ip1_info")
    val ip1Info: Ip1Info? = null,
    
    /**
     * 次IP信息
     * 用于 l2tp、pptp 场景
     */
    @SerializedName("ip2_info")
    val ip2Info: Ip2Info? = null,
    
    /**
     * 用户信息
     * 用于 pppoe、l2tp、pptp 场景
     */
    @SerializedName("user_info")
    val userInfo: UserInfo? = null,
    
    /**
     * 是否启用Ping
     * 判断该字段是否存在来决定是否显示开关按钮
     * 用于 dynamic_ip、static_ip、pppoe 场景
     */
    @SerializedName("enable_ping")
    val enablePing: Boolean? = null,
    
    /**
     * 是否启用自动DNS
     * 用于 dynamic_ip、pppoe 场景
     */
    @SerializedName("enable_auto_dns")
    val enableAutoDns: Boolean? = null,
    
    /**
     * PPPoE服务信息
     * 可选字段,支持pppoe_service组件才返回
     * 用于 pppoe 场景
     */
    @SerializedName("service_info")
    val serviceInfo: ServiceInfo? = null,
    
    /**
     * 次级连接类型
     * 用于 l2tp、pptp 场景
     * 值域: static_ip/dynamic_ip
     */
    @SerializedName("secondary_connection")
    @SecondaryConnection
    val secondaryConnection: String? = null
) : Parcelable

/**
 * IP信息(用于dynamic_ip、static_ip、pppoe)
 */
@Parcelize
data class IpInfo(
    /**
     * IP地址
     */
    val ip: String? = null,
    
    /**
     * 子网掩码
     */
    val mask: String? = null,
    
    /**
     * 网关
     */
    val gateway: String? = null,
    
    /**
     * 主DNS
     */
    val dns1: String? = null,
    
    /**
     * 备DNS
     */
    val dns2: String? = null
) : Parcelable

/**
 * 主IP信息(用于l2tp、pptp)
 */
@Parcelize
data class Ip1Info(
    /**
     * IP地址
     */
    val ip: String? = null,
    
    /**
     * DNS
     */
    val dns: String? = null
) : Parcelable

/**
 * 次IP信息(用于l2tp、pptp)
 */
@Parcelize
data class Ip2Info(
    /**
     * IP地址
     */
    val ip: String? = null,
    
    /**
     * 子网掩码
     */
    val mask: String? = null,
    
    /**
     * 网关
     */
    val gateway: String? = null,
    
    /**
     * 主DNS
     */
    val dns1: String? = null,
    
    /**
     * 备DNS
     */
    val dns2: String? = null
) : Parcelable

/**
 * 用户信息(用于pppoe、l2tp、pptp)
 */
@Parcelize
data class UserInfo(
    /**
     * 用户名(Base64编码)
     */
    val username: String? = null,
    
    /**
     * VPN服务器地址
     * 用于 l2tp、pptp 场景
     */
    @SerializedName("vpn_server")
    val vpnServer: String? = null
) : Parcelable

/**
 * PPPoE服务信息
 */
@Parcelize
data class ServiceInfo(
    /**
     * 是否启用
     * 默认关闭,开启后输入advance内容
     */
    val enable: Boolean? = null,
    
    /**
     * 服务器名称(Base64编码)
     * 字符串,0-31位,Access Concentrator name
     */
    @SerializedName("server_name")
    val serverName: String? = null,
    
    /**
     * 服务名称(Base64编码)
     * 字符串,0-31位
     */
    @SerializedName("service_name")
    val serviceName: String? = null
) : Parcelable

/**
 * LAN配置信息
 */
@Parcelize
data class LanInfo(
    /**
     * IP信息
     */
    @SerializedName("ip_info")
    val ipInfo: LanIpInfo? = null
) : Parcelable

/**
 * LAN IP信息
 */
@Parcelize
data class LanIpInfo(
    /**
     * IP地址
     */
    val ip: String? = null,
    
    /**
     * 子网掩码
     */
    val mask: String? = null
) : Parcelable

// ==================== 注解定义 ====================

/**
 * 拨号类型注解
 */
@StringDef(
    DialTypeValue.DYNAMIC_IP,
    DialTypeValue.STATIC_IP,
    DialTypeValue.PPPOE,
    DialTypeValue.L2TP,
    DialTypeValue.PPTP
)
@Retention(AnnotationRetention.SOURCE)
annotation class DialType

object DialTypeValue {
    const val DYNAMIC_IP = "dynamic_ip"
    const val STATIC_IP = "static_ip"
    const val PPPOE = "pppoe"
    const val L2TP = "l2tp"
    const val PPTP = "pptp"
}

/**
 * Backup模式注解
 */
@StringDef(
    BackupModeValue.ETHERNET,
    BackupModeValue.MOBILE_5G,
    BackupModeValue.LTE
)
@Retention(AnnotationRetention.SOURCE)
annotation class BackupMode

object BackupModeValue {
    const val ETHERNET = "ethernet"
    const val MOBILE_5G = "mobile_5g"
    const val LTE = "lte"
}

/**
 * 次级连接类型注解
 */
@StringDef(
    SecondaryConnectionValue.STATIC_IP,
    SecondaryConnectionValue.DYNAMIC_IP
)
@Retention(AnnotationRetention.SOURCE)
annotation class SecondaryConnection

object SecondaryConnectionValue {
    const val STATIC_IP = "static_ip"
    const val DYNAMIC_IP = "dynamic_ip"
}

import android.os.Parcelable
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * IPV4信息设置
 * 操作码: 0xe02d (TMP_APPV2_OP_MER_IPV4_SET)
 */
@Parcelize
data class Ipv4Set(
    /**
     * 入网方式
     * 可选字段,仅便携路由传
     * 值域: ethernet/hotspot
     * 各拨号方式下均需要设置
     */
    @SerializedName("connection_type")
    @ConnectionType
    val connectionType: String? = null,
    
    /**
     * WAN设置信息
     */
    val wan: WanSetInfo? = null
) : Parcelable

/**
 * WAN设置信息
 */
@Parcelize
data class WanSetInfo(
    /**
     * 拨号类型
     * 值域: dynamic_ip/static_ip/pppoe/l2tp/pptp
     * 非enable_ping时,必选
     */
    @SerializedName("dial_type")
    @DialType
    val dialType: String? = null,
    
    /**
     * 是否启用Ping
     * 如需要设置,可单独发送该参数,无需发送wan的其他参数信息
     */
    @SerializedName("enable_ping")
    val enablePing: Boolean? = null,
    
    /**
     * 是否启用自动DNS
     * 用于 dynamic_ip、pppoe 场景
     */
    @SerializedName("enable_auto_dns")
    val enableAutoDns: Boolean? = null,
    
    /**
     * IP信息
     * - dynamic_ip场景:当enable_auto_dns为false时设置dns1/dns2
     * - static_ip场景:必须设置完整信息(非enable_ping时,必选)
     * - pppoe场景:当enable_auto_dns为false时设置dns1/dns2
     */
    @SerializedName("ip_info")
    val ipInfo: IpSetInfo? = null,
    
    /**
     * 用户信息
     * 用于 pppoe、l2tp、pptp 场景(非enable_ping时,必选)
     */
    @SerializedName("user_info")
    val userInfo: UserSetInfo? = null,
    
    /**
     * PPPoE服务信息
     * 可选字段,支持pppoe_service组件才发送
     * 用于 pppoe 场景
     */
    @SerializedName("service_info")
    val serviceInfo: ServiceInfo? = null,
    
    /**
     * 次级连接类型
     * 用于 l2tp、pptp 场景(必选)
     * 值域: dynamic_ip/static_ip
     */
    @SerializedName("secondary_connection")
    @SecondaryConnection
    val secondaryConnection: String? = null,
    
    /**
     * 连接信息
     * 用于 l2tp、pptp 场景
     * 只有secondary_connection为static_ip时,才有connection_info数据
     */
    @SerializedName("connection_info")
    val connectionInfo: ConnectionInfo? = null
) : Parcelable

/**
 * IP设置信息
 */
@Parcelize
data class IpSetInfo(
    /**
     * IP地址
     * static_ip场景必选
     */
    val ip: String? = null,
    
    /**
     * 子网掩码
     * static_ip场景必选
     */
    val mask: String? = null,
    
    /**
     * 网关
     * static_ip场景必选
     */
    val gateway: String? = null,
    
    /**
     * 主DNS
     * static_ip场景必选
     * dynamic_ip/pppoe场景在enable_auto_dns为false时设置
     */
    val dns1: String? = null,
    
    /**
     * 备DNS
     * dynamic_ip/pppoe场景在enable_auto_dns为false时可选
     */
    val dns2: String? = null
) : Parcelable

/**
 * 用户设置信息
 */
@Parcelize
data class UserSetInfo(
    /**
     * 用户名(Base64编码)
     * pppoe/l2tp/pptp场景使用
     */
    val username: String? = null,
    
    /**
     * 密码(Base64编码)
     * pppoe/l2tp/pptp场景使用
     */
    val password: String? = null,
    
    /**
     * VPN服务器地址
     * 用于 l2tp、pptp 场景
     */
    @SerializedName("vpn_server")
    val vpnServer: String? = null
) : Parcelable

/**
 * 连接信息(用于l2tp、pptp的static_ip模式)
 */
@Parcelize
data class ConnectionInfo(
    /**
     * IP地址
     */
    val ip: String? = null,
    
    /**
     * 子网掩码
     */
    val mask: String? = null,
    
    /**
     * 网关
     */
    val gateway: String? = null,
    
    /**
     * 主DNS
     */
    val dns1: String? = null,
    
    /**
     * 备DNS
     */
    val dns2: String? = null
) : Parcelable

/**
 * 自动检测拨号方式响应
 * 操作码: 0xe09a (TMP_APPV2_OP_WAN_AUTO_DETECT)
 */
@Parcelize
data class WanAutoDetectResponse(
    /**
     * 错误码
     */
    @SerializedName("error_code")
    val errorCode: Int? = null,
    
    /**
     * 结果数据
     */
    val result: WanAutoDetectResult? = null
) : Parcelable

@Parcelize
data class WanAutoDetectResult(
    /**
     * 检测到的拨号方式
     * 值域同0xe02c的dial_type
     * 仅当detect_status为detected时返回
     */
    @SerializedName("dial_type")
    @DialType
    val dialType: String? = null,
    
    /**
     * 检测状态
     * 值域: detecting/detected/not_detected/disconnected
     * 
     * 轮询逻辑:
     * - detecting: 间隔detect_wait_time后下发下一次detect请求
     * - detected/not_detected/disconnected: 最终状态,停止轮询
     */
    @SerializedName("detect_status")
    @DetectStatus
    val detectStatus: String? = null,
    
    /**
     * 下次检测等待时间(轮询间隔)
     * 单位:毫秒
     */
    @SerializedName("detect_wait_time")
    val detectWaitTime: Int? = null
) : Parcelable

// ==================== 注解定义 ====================

/**
 * 检测状态注解
 */
@StringDef(
    DetectStatusValue.DETECTING,
    DetectStatusValue.DETECTED,
    DetectStatusValue.NOT_DETECTED,
    DetectStatusValue.DISCONNECTED
)
@Retention(AnnotationRetention.SOURCE)
annotation class DetectStatus

object DetectStatusValue {
    /**
     * 检测中(需要继续轮询)
     */
    const val DETECTING = "detecting"
    
    /**
     * 已检测到(最终状态)
     */
    const val DETECTED = "detected"
    
    /**
     * 未检测到(最终状态)
     */
    const val NOT_DETECTED = "not_detected"
    
    /**
     * 已断开连接(最终状态)
     */
    const val DISCONNECTED = "disconnected"
}

import android.os.Parcelable
import androidx.annotation.IntDef
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 设备发现响应
 * 文件格式: tdp.discover.<ip地址>.r.json
 * 示例: tdp.discover.192.168.0.2.r.json
 */
@Parcelize
data class DeviceDiscoverResponse(
    /**
     * 错误码
     */
    @SerializedName("error_code")
    val errorCode: Int? = null,
    
    /**
     * 结果数据
     */
    val result: DeviceInfo? = null
) : Parcelable

@Parcelize
data class DeviceInfo(
    /**
     * MAC地址
     * 格式: AA-BB-CC-DD-EE-FF
     */
    val mac: String? = null,
    
    /**
     * 硬件版本
     */
    @SerializedName("hardware_version")
    val hardwareVersion: String? = null,
    
    /**
     * 设备类型
     * 值域: MER.ROUTER/MER.RE/MER.MESH/MER.MIFI/MER.LTEGATEWAY/
     *       MER.PLC/MER.PON/MER.DSL/MER.PORTABLE
     */
    @SerializedName("device_type")
    @DeviceType
    val deviceType: String? = null,
    
    /**
     * IP地址
     */
    val ip: String? = null,
    
    /**
     * 设备ID(需要MD5加密)
     */
    @SerializedName("device_id")
    val deviceId: String? = null,
    
    /**
     * 设备型号
     */
    @SerializedName("device_model")
    val deviceModel: String? = null,
    
    /**
     * 工厂默认状态
     * 
     * 定义说明:
     * - 如果设备处于非主模式时返回false
     * - 如果为主模式(Router设备的Router模式,Repeater设备的Repeater模式):
     *   当启用default_password和is_quick_setup_finished时,如果设置了密码,
     *   则返回false,否则维持原有逻辑(在QS Apply之后置为false)
     * 
     * 注意:此字段在2022.08.08重新定义,原有含义存在理解偏差
     */
    @SerializedName("factory_default")
    val factoryDefault: Boolean? = null,
    
    /**
     * TMP端口列表
     */
    @SerializedName("tmp_port")
    val tmpPort: List<Int>? = null,
    
    /**
     * 设备昵称(Base64编码)
     */
    val nickname: String? = null,
    
    /**
     * SSH2 Banner类型
     * 0或不传:默认以SSH开头
     * 1:banner需要以TPS替换SSH作为开头
     */
    @SerializedName("banner_type")
    @BannerType
    val bannerType: Int? = null,
    
    /**
     * 默认密码状态(2022.08.08新增)
     * 0:设备处于非默认密码状态,不需要设置初始密码
     * 1:设备处于默认密码状态,需要设置初始密码
     */
    @SerializedName("default_password")
    @DefaultPasswordStatus
    val defaultPassword: Int? = null,
    
    /**
     * 是否完成Quick Setup(2022.08.08新增)
     */
    @SerializedName("is_quick_setup_finished")
    val isQuickSetupFinished: Boolean? = null,
    
    /**
     * Easy Mesh信息
     * 可选字段,支持Easy Mesh组件时需要返回
     */
    @SerializedName("easy_mesh_info")
    val easyMeshInfo: EasyMeshInfo? = null
) : Parcelable

/**
 * Easy Mesh信息
 */
@Parcelize
data class EasyMeshInfo(
    /**
     * Easy Mesh工作模式
     * 值域: main/satellite
     */
    @EasyMeshMode
    val mode: String? = null,
    
    /**
     * 是否组网
     */
    @SerializedName("is_meshed")
    val isMeshed: Boolean? = null,
    
    /**
     * 当前组网的Main Router的MAC地址
     * 如果未组网,也要返回,但是返回空字符串
     * 格式: AA-BB-CC-DD-EE-FF
     */
    @SerializedName("master_device_mac")
    val masterDeviceMac: String? = null
) : Parcelable

// ==================== 注解定义 ====================

/**
 * 设备类型注解
 */
@StringDef(
    DeviceTypeValue.ROUTER,
    DeviceTypeValue.RE,
    DeviceTypeValue.MESH,
    DeviceTypeValue.MIFI,
    DeviceTypeValue.LTE_GATEWAY,
    DeviceTypeValue.PLC,
    DeviceTypeValue.PON,
    DeviceTypeValue.DSL,
    DeviceTypeValue.PORTABLE
)
@Retention(AnnotationRetention.SOURCE)
annotation class DeviceType

object DeviceTypeValue {
    const val ROUTER = "MER.ROUTER"
    const val RE = "MER.RE"
    const val MESH = "MER.MESH"
    const val MIFI = "MER.MIFI"
    const val LTE_GATEWAY = "MER.LTEGATEWAY"
    const val PLC = "MER.PLC"
    const val PON = "MER.PON"
    const val DSL = "MER.DSL"
    const val PORTABLE = "MER.PORTABLE"
}

/**
 * Banner类型注解
 */
@IntDef(
    BannerTypeValue.DEFAULT_SSH,
    BannerTypeValue.TPS_REPLACE_SSH
)
@Retention(AnnotationRetention.SOURCE)
annotation class BannerType

object BannerTypeValue {
    /**
     * 默认以SSH开头
     */
    const val DEFAULT_SSH = 0
    
    /**
     * banner需要以TPS替换SSH作为开头
     */
    const val TPS_REPLACE_SSH = 1
}

/**
 * 默认密码状态注解
 */
@IntDef(
    DefaultPasswordStatusValue.NON_DEFAULT,
    DefaultPasswordStatusValue.DEFAULT
)
@Retention(AnnotationRetention.SOURCE)
annotation class DefaultPasswordStatus

object DefaultPasswordStatusValue {
    /**
     * 设备处于非默认密码状态,不需要设置初始密码
     */
    const val NON_DEFAULT = 0
    
    /**
     * 设备处于默认密码状态,需要设置初始密码
     */
    const val DEFAULT = 1
}

/**
 * Easy Mesh模式注解
 */
@StringDef(
    EasyMeshModeValue.MAIN,
    EasyMeshModeValue.SATELLITE
)
@Retention(AnnotationRetention.SOURCE)
annotation class EasyMeshMode

object EasyMeshModeValue {
    /**
     * 主路由模式
     */
    const val MAIN = "main"
    
    /**
     * 卫星节点模式
     */
    const val SATELLITE = "satellite"
}

/**
 * 设备发现工具类
 */
object DeviceDiscoverUtils {
    /**
     * 根据IP地址生成设备发现响应文件名
     * @param ipAddress IP地址
     * @return 文件名,格式: tdp.discover.<ip>.r.json
     */
    fun generateFileName(ipAddress: String): String {
        return "tdp.discover.$ipAddress.r.json"
    }
    
    /**
     * 从文件名中提取IP地址
     * @param fileName 文件名,格式: tdp.discover.<ip>.r.json
     * @return IP地址,如果格式不正确返回null
     */
    fun extractIpFromFileName(fileName: String): String? {
        val regex = Regex("^tdp\\.discover\\.(\\d+\\.\\d+\\.\\d+\\.\\d+)\\.r\\.json$")
        return regex.find(fileName)?.groupValues?.get(1)
    }
    
    /**
     * 验证文件名格式是否正确
     * @param fileName 文件名
     * @return true表示格式正确,false表示格式错误
     */
    fun isValidFileName(fileName: String): Boolean {
        return fileName.matches(Regex("^tdp\\.discover\\.\\d+\\.\\d+\\.\\d+\\.\\d+\\.r\\.json$"))
    }
    
    /**
     * 判断设备是否需要设置初始密码
     * @param deviceInfo 设备信息
     * @return true表示需要设置初始密码
     */
    fun needSetInitialPassword(deviceInfo: DeviceInfo?): Boolean {
        return deviceInfo?.defaultPassword == DefaultPasswordStatusValue.DEFAULT
    }
    
    /**
     * 判断设备是否完成Quick Setup
     * @param deviceInfo 设备信息
     * @return true表示已完成Quick Setup
     */
    fun isQuickSetupFinished(deviceInfo: DeviceInfo?): Boolean {
        return deviceInfo?.isQuickSetupFinished == true
    }
    
    /**
     * 判断设备是否已组网
     * @param deviceInfo 设备信息
     * @return true表示已组网
     */
    fun isMeshed(deviceInfo: DeviceInfo?): Boolean {
        return deviceInfo?.easyMeshInfo?.isMeshed == true
    }
}

import android.os.Parcelable
import androidx.annotation.IntRange
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 获取IPv6信息
 * 操作码: 0xe0a8 (TMP_APPV2_OP_MER_IPV6_GET)
 */
@Parcelize
data class IPv6InfoResult(
    /**
     * IPv6开关
     */
    val enable: Boolean = false,

    /**
     * WAN配置信息
     */
    val wan: WanBean? = null,

    /**
     * LAN配置信息
     */
    val lan: LanBean? = null
) : Parcelable

@Parcelize
data class WanBean(
    /**
     * 入网方式,值域: ethernet/hotspot,仅便携路由传
     */
    @SerializedName("connection_type")
    @ConnectionType
    val connectionType: String? = null,

    /**
     * 支持的入网方式集合,仅便携路由传
     */
    @SerializedName("support_connection_type_list")
    val supportConnectionTypeList: List<String>? = null,

    /**
     * 拨号方式,值域: static_ip/dynamic_ip/pppoe/6to4/bridge
     */
    @SerializedName("dial_type")
    @DialType
    val dialType: String? = null,

    /**
     * 支持的拨号方式列表,非便携路由机型传
     */
    @SerializedName("support_dial_type_list")
    val supportDialTypeList: List<String>? = null,

    /**
     * 各入网方式支持的拨号方式列表,便携路由机型传
     */
    @SerializedName("support_dial_type_list_by_connection_type")
    val supportDialTypeListByConnectionType: Map<String, List<String>>? = null,

    /**
     * 静态IP配置信息
     */
    @SerializedName("static_ip_info")
    val staticIpInfo: StaticIpInfoBean? = null,

    /**
     * 动态IP配置信息
     */
    @SerializedName("dynamic_ip_info")
    val dynamicIpInfo: DynamicIpInfoBean? = null,

    /**
     * PPPoE配置信息
     */
    @SerializedName("pppoe_info")
    val pppoeInfo: PppoeInfoBean? = null,

    /**
     * 6to4配置信息
     */
    @SerializedName("6to4_info")
    val to4Info: To4InfoBean? = null
) : Parcelable

@Parcelize
data class StaticIpInfoBean(
    /**
     * IPv6地址
     */
    val ip: String? = null,

    /**
     * 默认网关
     */
    val gateway: String? = null,

    /**
     * 首选DNS
     */
    val dns1: String? = null,

    /**
     * 备选DNS
     */
    val dns2: String? = null,

    /**
     * 最大传输单元的大小,默认值1500
     */
    @SerializedName("mtu_size")
    val mtuSize: Int? = null
) : Parcelable

@Parcelize
data class DynamicIpInfoBean(
    /**
     * IPv6地址
     */
    val ip: String? = null,

    /**
     * 首选DNS
     */
    val dns1: String? = null,

    /**
     * 备选DNS
     */
    val dns2: String? = null,

    /**
     * 获取IPv6地址的方式,值域: auto/slaac/dhcpv6/non_address
     */
    @SerializedName("get_address_type")
    @GetAddressType
    val getAddressType: String? = null,

    /**
     * 支持的获取IPv6地址的方式集合
     */
    @SerializedName("support_get_address_type_list")
    val supportGetAddressTypeList: List<String>? = null,

    /**
     * 设定DNS地址的方式,值域: auto/custom
     */
    @SerializedName("dns_address_type")
    @DnsAddressType
    val dnsAddressType: String? = null,

    /**
     * 支持的设定DNS地址的方式集合
     */
    @SerializedName("support_dns_address_type_list")
    val supportDnsAddressTypeList: List<String>? = null,

    /**
     * 前缀授权开关,首次获取时默认为false
     */
    @SerializedName("prefix_delegain_enable")
    val prefixDelegainEnable: Boolean = false
) : Parcelable

@Parcelize
data class PppoeInfoBean(
    /**
     * IPv6地址
     */
    val ip: String? = null,

    /**
     * 首选DNS
     */
    val dns1: String? = null,

    /**
     * 备选DNS
     */
    val dns2: String? = null,

    /**
     * 是否与IPv4使用相同账号,首次获取时默认为false
     */
    @SerializedName("enable_share_ipv4")
    val enableShareIpv4: Boolean = false,

    /**
     * 用户名,Base64编码
     */
    val username: String? = null,

    /**
     * 密码,Base64编码
     */
    val password: String? = null,

    /**
     * 获取IPv6地址的方式,值域: auto/slaac/dhcpv6/specified_by_isp/non_address
     */
    @SerializedName("get_address_type")
    @GetAddressType
    val getAddressType: String? = null,

    /**
     * 支持的获取IPv6地址的方式集合
     */
    @SerializedName("support_get_address_type_list")
    val supportGetAddressTypeList: List<String>? = null,

    /**
     * get_address_type为specified_by_isp时设置的IPv6地址
     */
    @SerializedName("isp_ipv6_address")
    val ispIpv6Address: String? = null,

    /**
     * 设定DNS地址的方式,值域: auto/custom/get_from_isp
     */
    @SerializedName("dns_address_type")
    @DnsAddressType
    val dnsAddressType: String? = null,

    /**
     * 支持的设定DNS地址的方式集合
     */
    @SerializedName("support_dns_address_type_list")
    val supportDnsAddressTypeList: List<String>? = null,

    /**
     * 前缀授权开关,首次获取时默认为false
     */
    @SerializedName("prefix_delegain_enable")
    val prefixDelegainEnable: Boolean = false,

    /**
     * 是否已经连接成功
     */
    @SerializedName("is_connect")
    val isConnect: Boolean = false
) : Parcelable

@Parcelize
data class To4InfoBean(
    /**
     * IPv4地址
     */
    val ip: String? = null,

    /**
     * IPv4的子网掩码
     */
    val mask: String? = null,

    /**
     * IPv4的网关
     */
    val gateway: String? = null,

    /**
     * 首选DNS
     */
    val dns1: String? = null,

    /**
     * 备选DNS
     */
    val dns2: String? = null,

    /**
     * 隧道地址
     */
    @SerializedName("tunnel_address")
    val tunnelAddress: String? = null,

    /**
     * 自定义DNS地址开关
     */
    @SerializedName("custom_dns_enable")
    val customDnsEnable: Boolean = false,

    /**
     * 是否已经连接成功
     */
    @SerializedName("is_connect")
    val isConnect: Boolean = false
) : Parcelable

@Parcelize
data class LanBean(
    /**
     * 当前的分配类型,值域: dhcpv6/slaac_stateless_dhcp/slaac_rdnss/nd_proxy
     */
    @SerializedName("assigned_type")
    @AssignedType
    val assignedType: String? = null,

    /**
     * 支持的分配类型集合
     */
    @SerializedName("support_assigned_type_list")
    val supportAssignedTypeList: List<String>? = null,

    /**
     * DHCPv6配置信息
     */
    @SerializedName("dhcpv6_info")
    val dhcpv6Info: Dhcpv6InfoBean? = null,

    /**
     * SLAAC无状态DHCP配置信息
     */
    @SerializedName("slaac_stateless_dhcp_info")
    val slaacStatelessDhcpInfo: SlaacStatelessDhcpInfoBean? = null,

    /**
     * SLAAC RDNSS配置信息
     */
    @SerializedName("slaac_rdnss_info")
    val slaacRdnssInfo: SlaacRdnssInfoBean? = null,

    /**
     * ND Proxy配置信息
     */
    @SerializedName("nd_proxy_info")
    val ndProxyInfo: NdProxyInfoBean? = null
) : Parcelable

@Parcelize
data class Dhcpv6InfoBean(
    /**
     * 地址前缀
     */
    @SerializedName("address_prefix")
    val addressPrefix: String? = null,

    /**
     * 地址
     */
    val address: String? = null,

    /**
     * 释放时间,默认值为86400
     */
    @SerializedName("release_time")
    val releaseTime: Int? = null
) : Parcelable

@Parcelize
data class SlaacStatelessDhcpInfoBean(
    /**
     * 地址前缀
     */
    @SerializedName("address_prefix")
    val addressPrefix: String? = null,

    /**
     * 地址
     */
    val address: String? = null
) : Parcelable

@Parcelize
data class SlaacRdnssInfoBean(
    /**
     * 地址前缀
     */
    @SerializedName("address_prefix")
    val addressPrefix: String? = null,

    /**
     * 地址
     */
    val address: String? = null
) : Parcelable

@Parcelize
data class NdProxyInfoBean(
    /**
     * 地址
     */
    val address: String? = null
) : Parcelable

// ==================== 注解定义 ====================

/**
 * 连接类型注解
 */
@StringDef(
    ConnectionTypeValue.ETHERNET,
    ConnectionTypeValue.HOTSPOT
)
@Retention(AnnotationRetention.SOURCE)
annotation class ConnectionType

object ConnectionTypeValue {
    const val ETHERNET = "ethernet"
    const val HOTSPOT = "hotspot"
}

/**
 * 拨号方式注解
 */
@StringDef(
    DialTypeValue.STATIC_IP,
    DialTypeValue.DYNAMIC_IP,
    DialTypeValue.PPPOE,
    DialTypeValue.TO4,
    DialTypeValue.BRIDGE
)
@Retention(AnnotationRetention.SOURCE)
annotation class DialType

object DialTypeValue {
    const val STATIC_IP = "static_ip"
    const val DYNAMIC_IP = "dynamic_ip"
    const val PPPOE = "pppoe"
    const val TO4 = "6to4"
    const val BRIDGE = "bridge"
}

/**
 * 获取地址类型注解
 */
@StringDef(
    GetAddressTypeValue.AUTO,
    GetAddressTypeValue.SLAAC,
    GetAddressTypeValue.DHCPV6,
    GetAddressTypeValue.NON_ADDRESS,
    GetAddressTypeValue.SPECIFIED_BY_ISP
)
@Retention(AnnotationRetention.SOURCE)
annotation class GetAddressType

object GetAddressTypeValue {
    const val AUTO = "auto"
    const val SLAAC = "slaac"
    const val DHCPV6 = "dhcpv6"
    const val NON_ADDRESS = "non_address"
    const val SPECIFIED_BY_ISP = "specified_by_isp"
}

/**
 * DNS地址类型注解
 */
@StringDef(
    DnsAddressTypeValue.AUTO,
    DnsAddressTypeValue.CUSTOM,
    DnsAddressTypeValue.GET_FROM_ISP
)
@Retention(AnnotationRetention.SOURCE)
annotation class DnsAddressType

object DnsAddressTypeValue {
    const val AUTO = "auto"
    const val CUSTOM = "custom"
    const val GET_FROM_ISP = "get_from_isp"
}

/**
 * 分配类型注解
 */
@StringDef(
    AssignedTypeValue.DHCPV6,
    AssignedTypeValue.SLAAC_STATELESS_DHCP,
    AssignedTypeValue.SLAAC_RDNSS,
    AssignedTypeValue.ND_PROXY
)
@Retention(AnnotationRetention.SOURCE)
annotation class AssignedType

object AssignedTypeValue {
    const val DHCPV6 = "dhcpv6"
    const val SLAAC_STATELESS_DHCP = "slaac_stateless_dhcp"
    const val SLAAC_RDNSS = "slaac_rdnss"
    const val ND_PROXY = "nd_proxy"
}

import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * 设置IPv6信息
 * 操作码: 0xe0a9 (TMP_APPV2_OP_MER_IPV6_SET)
 */
@Parcelize
data class IPv6SetRequest(
    @SerializedName("params")
    val params: IPv6SetParams
) : Parcelable

@Parcelize
data class IPv6SetParams(
    /**
     * IPv6开关
     */
    val enable: Boolean = false,

    /**
     * WAN配置信息
     */
    val wan: WanSetBean? = null,

    /**
     * LAN配置信息
     */
    val lan: LanSetBean? = null
) : Parcelable

@Parcelize
data class WanSetBean(
    /**
     * 入网方式,值域: ethernet/hotspot,仅便携路由传
     */
    @SerializedName("connection_type")
    @ConnectionType
    val connectionType: String? = null,

    /**
     * 拨号方式,值域: static_ip/dynamic_ip/pppoe/6to4/bridge
     */
    @SerializedName("dial_type")
    @DialType
    val dialType: String? = null,

    /**
     * 静态IP配置信息,仅当dial_type为static_ip时传
     */
    @SerializedName("static_ip_info")
    val staticIpInfo: StaticIpSetBean? = null,

    /**
     * 动态IP配置信息,仅当dial_type为dynamic_ip时传
     */
    @SerializedName("dynamic_ip_info")
    val dynamicIpInfo: DynamicIpSetBean? = null,

    /**
     * PPPoE配置信息,仅当dial_type为pppoe时传
     */
    @SerializedName("pppoe_info")
    val pppoeInfo: PppoeSetBean? = null,

    /**
     * 6to4配置信息,仅当dial_type为6to4时传
     */
    @SerializedName("6to4_info")
    val to4Info: To4SetBean? = null
) : Parcelable

@Parcelize
data class StaticIpSetBean(
    /**
     * IPv6地址
     */
    val ip: String? = null,

    /**
     * 默认网关
     */
    val gateway: String? = null,

    /**
     * 首选DNS
     */
    val dns1: String? = null,

    /**
     * 备选DNS
     */
    val dns2: String? = null,

    /**
     * 最大传输单元的大小,默认值1500
     */
    @SerializedName("mtu_size")
    val mtuSize: Int? = null
) : Parcelable

@Parcelize
data class DynamicIpSetBean(
    /**
     * 获取IPv6地址的方式,值域: auto/slaac/dhcpv6/non_address
     */
    @SerializedName("get_address_type")
    @GetAddressType
    val getAddressType: String? = null,

    /**
     * 设定DNS地址的方式,值域: auto/custom
     */
    @SerializedName("dns_address_type")
    @DnsAddressType
    val dnsAddressType: String? = null,

    /**
     * 自定义的首选DNS,仅当dns_address_type为custom时传
     */
    val dns1: String? = null,

    /**
     * 自定义的备选DNS,仅当dns_address_type为custom时传
     */
    val dns2: String? = null,

    /**
     * 前缀授权开关,首次获取时默认为false
     */
    @SerializedName("prefix_delegain_enable")
    val prefixDelegainEnable: Boolean = false
) : Parcelable

@Parcelize
data class PppoeSetBean(
    /**
     * 是否与IPv4使用相同账号,首次获取时默认为false
     */
    @SerializedName("enable_share_ipv4")
    val enableShareIpv4: Boolean = false,

    /**
     * 用户名,Base64编码
     */
    val username: String? = null,

    /**
     * 密码,Base64编码
     */
    val password: String? = null,

    /**
     * 获取IPv6地址的方式,值域: auto/slaac/dhcpv6/specified_by_isp/non_address
     */
    @SerializedName("get_address_type")
    @GetAddressType
    val getAddressType: String? = null,

    /**
     * get_address_type为specified_by_isp时设置的IPv6地址
     */
    @SerializedName("isp_ipv6_address")
    val ispIpv6Address: String? = null,

    /**
     * 设定DNS地址的方式,值域: auto/custom
     */
    @SerializedName("dns_address_type")
    @DnsAddressType
    val dnsAddressType: String? = null,

    /**
     * 自定义的首选DNS,仅当dns_address_type为custom时传
     */
    val dns1: String? = null,

    /**
     * 自定义的备选DNS,仅当dns_address_type为custom时传
     */
    val dns2: String? = null,

    /**
     * 前缀授权开关,首次获取时默认为false
     */
    @SerializedName("prefix_delegain_enable")
    val prefixDelegainEnable: Boolean = false
) : Parcelable

@Parcelize
data class To4SetBean(
    /**
     * 自定义DNS地址开关
     */
    @SerializedName("custom_dns_enable")
    val customDnsEnable: Boolean = false,

    /**
     * 自定义的首选DNS,仅当custom_dns_enable为true时传
     */
    val dns1: String? = null,

    /**
     * 自定义的备选DNS,仅当custom_dns_enable为true时传
     */
    val dns2: String? = null
) : Parcelable

@Parcelize
data class LanSetBean(
    /**
     * 当前的分配类型,值域: dhcpv6/slaac_stateless_dhcp/slaac_rdnss/nd_proxy
     */
    @SerializedName("assigned_type")
    @AssignedType
    val assignedType: String? = null,

    /**
     * DHCPv6配置信息,仅当assigned_type为dhcpv6时传
     */
    @SerializedName("dhcpv6_info")
    val dhcpv6Info: Dhcpv6SetBean? = null,

    /**
     * SLAAC无状态DHCP配置信息,仅当assigned_type为slaac_stateless_dhcp时传
     */
    @SerializedName("slaac_stateless_dhcp_info")
    val slaacStatelessDhcpInfo: SlaacStatelessDhcpSetBean? = null,

    /**
     * SLAAC RDNSS配置信息,仅当assigned_type为slaac_rdnss时传
     */
    @SerializedName("slaac_rdnss_info")
    val slaacRdnssInfo: SlaacRdnssSetBean? = null
) : Parcelable

@Parcelize
data class Dhcpv6SetBean(
    /**
     * 地址前缀
     */
    @SerializedName("address_prefix")
    val addressPrefix: String? = null,

    /**
     * 释放时间,默认值为86400
     */
    @SerializedName("release_time")
    val releaseTime: Int? = null
) : Parcelable

@Parcelize
data class SlaacStatelessDhcpSetBean(
    /**
     * 地址前缀
     */
    @SerializedName("address_prefix")
    val addressPrefix: String? = null
) : Parcelable

@Parcelize
data class SlaacRdnssSetBean(
    /**
     * 地址前缀
     */
    @SerializedName("address_prefix")
    val addressPrefix: String? = null
) : Parcelable

import android.os.Parcelable
import androidx.annotation.StringDef
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

/**
 * PPPoE或6to4模式下连接IPv6
 * 操作码: 0xe0ac (TMP_APPV2_OP_MER_IPV6_CONNECT)
 */
@Parcelize
data class IPv6ConnectRequest(
    @SerializedName("params")
    val params: IPv6ConnectParams
) : Parcelable

@Parcelize
data class IPv6ConnectParams(
    /**
     * IPv6开关
     */
    val enable: Boolean = false,

    /**
     * WAN配置信息
     */
    val wan: WanConnectBean? = null,

    /**
     * LAN配置信息
     */
    val lan: LanSetBean? = null
) : Parcelable

@Parcelize
data class WanConnectBean(
    /**
     * 入网方式,值域: ethernet/hotspot,仅便携路由传
     */
    @SerializedName("connection_type")
    @ConnectionType
    val connectionType: String? = null,

    /**
     * 拨号方式,值域: pppoe/6to4
     */
    @SerializedName("dial_type")
    @ConnectDialType
    val dialType: String? = null,

    /**
     * PPPoE配置信息,仅当dial_type为pppoe时传
     */
    @SerializedName("pppoe_info")
    val pppoeInfo: PppoeSetBean? = null,

    /**
     * 6to4配置信息,仅当dial_type为6to4时传
     */
    @SerializedName("6to4_info")
    val to4Info: To4SetBean? = null
) : Parcelable

/**
 * 连接拨号方式注解(仅支持pppoe和6to4)
 */
@StringDef(
    ConnectDialTypeValue.PPPOE,
    ConnectDialTypeValue.TO4
)
@Retention(AnnotationRetention.SOURCE)
annotation class ConnectDialType

object ConnectDialTypeValue {
    const val PPPOE = "pppoe"
    const val TO4 = "6to4"
}