优化:发送通道参数默认值(避免反序列化时空指针)

This commit is contained in:
pppscn 2024-04-09 15:07:22 +08:00
parent 27fa30a5e1
commit 9107fa4589
33 changed files with 202 additions and 184 deletions

View File

@ -4,21 +4,21 @@ import java.io.Serializable
data class BarkSetting(
//推送地址
var server: String,
var server: String = "",
//分组名称
val group: String? = "",
val group: String = "",
//消息图标
val icon: String? = "",
val icon: String = "",
//消息声音
val sound: String? = "",
val sound: String = "",
//消息角标
val badge: String? = "",
val badge: String = "",
//消息链接
val url: String? = "",
val url: String = "",
//通知级别
val level: String? = "active",
val level: String = "active",
//标题模板
val title: String? = "",
val title: String = "",
//加密算法
val transformation: String = "none",
//加密密钥

View File

@ -5,12 +5,12 @@ import java.io.Serializable
data class DingtalkGroupRobotSetting(
var token: String = "",
var secret: String? = "",
var atAll: Boolean? = false,
var atMobiles: String? = "",
var atDingtalkIds: String? = "",
var msgtype: String? = "text",
val titleTemplate: String? = "",
var secret: String = "",
var atAll: Boolean = false,
var atMobiles: String = "",
var atDingtalkIds: String = "",
var msgtype: String = "text",
val titleTemplate: String = "",
) : Serializable {
fun getMsgTypeCheckId(): Int {

View File

@ -10,13 +10,13 @@ data class DingtalkInnerRobotSetting(
val appSecret: String = "",
val userIds: String = "",
val msgKey: String = "sampleText",
val titleTemplate: String? = "",
val titleTemplate: String = "",
val proxyType: Proxy.Type = Proxy.Type.DIRECT,
val proxyHost: String? = "",
val proxyPort: String? = "",
val proxyAuthenticator: Boolean? = false,
val proxyUsername: String? = "",
val proxyPassword: String? = "",
val proxyHost: String = "",
val proxyPort: String = "",
val proxyAuthenticator: Boolean = false,
val proxyUsername: String = "",
val proxyPassword: String = "",
) : Serializable {
fun getProxyTypeCheckId(): Int {

View File

@ -4,19 +4,19 @@ import com.idormy.sms.forwarder.R
import java.io.Serializable
data class EmailSetting(
var mailType: String? = "",
var fromEmail: String? = "",
var pwd: String? = "",
var nickname: String? = "",
var host: String? = "",
var port: String? = "",
var ssl: Boolean? = false,
var startTls: Boolean? = false,
var title: String? = "",
var mailType: String = "",
var fromEmail: String = "",
var pwd: String = "",
var nickname: String = "",
var host: String = "",
var port: String = "",
var ssl: Boolean = false,
var startTls: Boolean = false,
var title: String = "",
var recipients: MutableMap<String, Pair<String, String>> = mutableMapOf(),
var toEmail: String? = "",
var keystore: String? = "",
var password: String? = "",
var toEmail: String = "",
var keystore: String = "",
var password: String = "",
var encryptionProtocol: String = "Plain", //加密协议: S/MIME、OpenPGP、Plain不传证书
) : Serializable {

View File

@ -5,14 +5,14 @@ import java.io.Serializable
data class FeishuSetting(
var webhook: String = "",
val secret: String? = "",
val msgType: String? = "interactive",
val titleTemplate: String? = "",
val secret: String = "",
val msgType: String = "interactive",
val titleTemplate: String = "",
val messageCard: String = "", //自定义消息卡片
) : Serializable {
fun getMsgTypeCheckId(): Int {
return if (msgType == null || msgType == "interactive") {
return if (msgType == "interactive") {
R.id.rb_msg_type_interactive
} else {
R.id.rb_msg_type_text

View File

@ -4,6 +4,6 @@ import java.io.Serializable
data class GotifySetting(
var webServer: String = "",
val title: String? = "",
val priority: String? = "",
val title: String = "",
val priority: String = "",
) : Serializable

View File

@ -5,11 +5,11 @@ import java.io.Serializable
data class PushplusSetting(
var website: String = "www.pushplus.plus",
var token: String = "",
val topic: String? = "",
val template: String? = "",
val channel: String? = "",
val webhook: String? = "",
val callbackUrl: String? = "",
val validTime: String? = "",
val titleTemplate: String? = "",
val topic: String = "",
val template: String = "",
val channel: String = "",
val webhook: String = "",
val callbackUrl: String = "",
val validTime: String = "",
val titleTemplate: String = "",
) : Serializable

View File

@ -4,7 +4,7 @@ import java.io.Serializable
data class ServerchanSetting(
var sendKey: String = "",
var channel: String? = "",
var openid: String? = "",
var titleTemplate: String? = "",
var channel: String = "",
var openid: String = "",
var titleTemplate: String = "",
) : Serializable

View File

@ -6,7 +6,7 @@ import java.io.Serializable
data class SmsSetting(
var simSlot: Int = 0,
var mobiles: String = "",
var onlyNoNetwork: Boolean? = false,
var onlyNoNetwork: Boolean = false,
) : Serializable {
fun getSmsSimSlotCheckId(): Int {

View File

@ -4,12 +4,12 @@ import com.idormy.sms.forwarder.R
import java.io.Serializable
data class SocketSetting(
val method: String? = "MQTT",
val method: String = "MQTT",
var address: String = "", //IP地址
val port: Int = 0, //端口号
val msgTemplate: String = "", //消息模板
val secret: String? = "", //签名密钥
val response: String? = "", //成功应答关键字
val secret: String = "", //签名密钥
val response: String = "", //成功应答关键字
val username: String = "", //用户名
val password: String = "", //密码
val inCharset: String = "", //输入编码
@ -23,7 +23,7 @@ data class SocketSetting(
fun getMethodCheckId(): Int {
return when (method) {
null, "MQTT" -> R.id.rb_method_mqtt
"MQTT" -> R.id.rb_method_mqtt
"TCP" -> R.id.rb_method_tcp
"UDP" -> R.id.rb_method_udp
else -> R.id.rb_method_mqtt

View File

@ -5,19 +5,19 @@ import java.io.Serializable
import java.net.Proxy
data class TelegramSetting(
val method: String? = "POST",
val method: String = "POST",
var apiToken: String = "",
val chatId: String = "",
val proxyType: Proxy.Type = Proxy.Type.DIRECT,
val proxyHost: String? = "",
val proxyPort: String? = "",
val proxyAuthenticator: Boolean? = false,
val proxyUsername: String? = "",
val proxyPassword: String? = "",
val proxyHost: String = "",
val proxyPort: String = "",
val proxyAuthenticator: Boolean = false,
val proxyUsername: String = "",
val proxyPassword: String = "",
) : Serializable {
fun getMethodCheckId(): Int {
return if (method == null || method == "POST") R.id.rb_method_post else R.id.rb_method_get
return if (method == "GET") R.id.rb_method_get else R.id.rb_method_post
}
fun getProxyTypeCheckId(): Int {

View File

@ -3,5 +3,5 @@ package com.idormy.sms.forwarder.entity.setting
import java.io.Serializable
data class UrlSchemeSetting(
var urlScheme: String,
var urlScheme: String = "",
) : Serializable

View File

@ -8,16 +8,16 @@ data class WeworkAgentSetting(
var corpID: String = "",
val agentID: String = "",
val secret: String = "",
val atAll: Boolean? = false,
val toUser: String? = "@all",
val toParty: String? = "",
val toTag: String? = "",
val atAll: Boolean = false,
val toUser: String = "@all",
val toParty: String = "",
val toTag: String = "",
val proxyType: Proxy.Type = Proxy.Type.DIRECT,
val proxyHost: String? = "",
val proxyPort: String? = "",
val proxyAuthenticator: Boolean? = false,
val proxyUsername: String? = "",
val proxyPassword: String? = "",
val proxyHost: String = "",
val proxyPort: String = "",
val proxyAuthenticator: Boolean = false,
val proxyUsername: String = "",
val proxyPassword: String = "",
val customizeAPI: String = "https://qyapi.weixin.qq.com",
) : Serializable {

View File

@ -4,11 +4,11 @@ import com.idormy.sms.forwarder.R
import java.io.Serializable
data class WeworkRobotSetting(
var webHook: String,
var webHook: String = "",
val msgType: String = "text",
var atAll: Boolean? = false,
var atUserIds: String? = "",
var atMobiles: String? = "",
var atAll: Boolean = false,
var atUserIds: String = "",
var atMobiles: String = "",
) : Serializable {
fun getMsgTypeCheckId(): Int {

View File

@ -196,7 +196,7 @@ class EmailFragment : BaseFragment<FragmentSendersEmailBinding?>(), View.OnClick
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
if (!TextUtils.isEmpty(settingVo.mailType)) {
mailType = settingVo.mailType.toString()
mailType = settingVo.mailType
//TODO: 替换mailType为当前语言避免切换语言后失效历史包袱怎么替换比较优雅
if (mailType == "other" || mailType == "其他邮箱" || mailType == "其他郵箱") {
mailType = getString(R.string.other_mail_type)
@ -222,8 +222,8 @@ class EmailFragment : BaseFragment<FragmentSendersEmailBinding?>(), View.OnClick
}
} else {
//兼容旧版本
val emails = settingVo.toEmail?.split(",")
if (!emails.isNullOrEmpty()) {
val emails = settingVo.toEmail.split(",")
if (emails.isNotEmpty()) {
for (email in emails.toTypedArray()) {
addRecipientItem(email)
}

View File

@ -18,7 +18,15 @@ import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
import com.idormy.sms.forwarder.databinding.FragmentSendersWeworkAgentBinding
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.setting.WeworkAgentSetting
import com.idormy.sms.forwarder.utils.*
import com.idormy.sms.forwarder.utils.CommonUtils
import com.idormy.sms.forwarder.utils.EVENT_TOAST_ERROR
import com.idormy.sms.forwarder.utils.KEY_SENDER_CLONE
import com.idormy.sms.forwarder.utils.KEY_SENDER_ID
import com.idormy.sms.forwarder.utils.KEY_SENDER_TEST
import com.idormy.sms.forwarder.utils.KEY_SENDER_TYPE
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.XToastUtils
import com.idormy.sms.forwarder.utils.sender.WeworkAgentUtils
import com.jeremyliao.liveeventbus.LiveEventBus
import com.xuexiang.xaop.annotation.SingleClick
@ -34,7 +42,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.net.Proxy
import java.util.*
import java.util.Date
@Page(name = "企业微信应用")
@Suppress("PrivatePropertyName")
@ -125,9 +133,9 @@ class WeworkAgentFragment : BaseFragment<FragmentSendersWeworkAgentBinding?>(),
binding!!.etToUser.setText(settingVo.toUser)
binding!!.etToParty.setText(settingVo.toParty)
binding!!.etToTag.setText(settingVo.toTag)
binding!!.layoutToUser.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.layoutToParty.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.layoutToTag.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.layoutToUser.visibility = if (settingVo.atAll) View.GONE else View.VISIBLE
binding!!.layoutToParty.visibility = if (settingVo.atAll) View.GONE else View.VISIBLE
binding!!.layoutToTag.visibility = if (settingVo.atAll) View.GONE else View.VISIBLE
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)

View File

@ -1,4 +1,4 @@
package com.idormy.sms.forwarder.utils.sender
package com.idormy.sms.forwarder.utils.interceptor
import okhttp3.Credentials
import okhttp3.Interceptor

View File

@ -1,4 +1,4 @@
package com.idormy.sms.forwarder.utils.sender
package com.idormy.sms.forwarder.utils.interceptor
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.utils.Log

View File

@ -10,6 +10,8 @@ import com.idormy.sms.forwarder.entity.setting.BarkSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.BasicAuthInterceptor
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -33,9 +35,9 @@ class BarkUtils {
) {
//Log.i(TAG, "sendMsg setting:$setting msgInfo:$msgInfo rule:$rule senderIndex:$senderIndex logId:$logId msgId:$msgId")
val title: String = if (rule != null) {
msgInfo.getTitleForSend(setting.title.toString(), rule.regexReplace)
msgInfo.getTitleForSend(setting.title, rule.regexReplace)
} else {
msgInfo.getTitleForSend(setting.title.toString())
msgInfo.getTitleForSend(setting.title)
}
val content: String = if (rule != null) {
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
@ -60,12 +62,12 @@ class BarkUtils {
msgMap["title"] = title
msgMap["body"] = content
msgMap["isArchive"] = 1
if (!TextUtils.isEmpty(setting.group)) msgMap["group"] = setting.group.toString()
if (!TextUtils.isEmpty(setting.icon)) msgMap["icon"] = setting.icon.toString()
if (!TextUtils.isEmpty(setting.level)) msgMap["level"] = setting.level.toString()
if (!TextUtils.isEmpty(setting.sound)) msgMap["sound"] = setting.sound.toString()
if (!TextUtils.isEmpty(setting.badge)) msgMap["badge"] = setting.badge.toString()
if (!TextUtils.isEmpty(setting.url)) msgMap["url"] = setting.url.toString()
if (!TextUtils.isEmpty(setting.group)) msgMap["group"] = setting.group
if (!TextUtils.isEmpty(setting.icon)) msgMap["icon"] = setting.icon
if (!TextUtils.isEmpty(setting.level)) msgMap["level"] = setting.level
if (!TextUtils.isEmpty(setting.sound)) msgMap["sound"] = setting.sound
if (!TextUtils.isEmpty(setting.badge)) msgMap["badge"] = setting.badge
if (!TextUtils.isEmpty(setting.url)) msgMap["url"] = setting.url
//自动复制验证码
val pattern = Regex("(?<!回复)(验证码|授权码|校验码|检验码|确认码|激活码|动态码|安全码|(验证)?代码|校验代码|检验代码|激活代码|确认代码|动态代码|安全代码|登入码|认证码|识别码|短信口令|动态密码|交易码|上网密码|动态口令|随机码|驗證碼|授權碼|校驗碼|檢驗碼|確認碼|激活碼|動態碼|(驗證)?代碼|校驗代碼|檢驗代碼|確認代碼|激活代碼|動態代碼|登入碼|認證碼|識別碼|一次性密码|[Cc][Oo][Dd][Ee]|[Vv]erification)")

View File

@ -10,6 +10,7 @@ import com.idormy.sms.forwarder.entity.setting.DingtalkGroupRobotSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -44,7 +45,7 @@ class DingtalkGroupRobotUtils private constructor() {
val timestamp = System.currentTimeMillis()
val stringToSign = "$timestamp\n" + setting.secret
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(setting.secret?.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
mac.init(SecretKeySpec(setting.secret.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
val signData = mac.doFinal(stringToSign.toByteArray(StandardCharsets.UTF_8))
val sign = URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8")
requestUrl += "&timestamp=$timestamp&sign=$sign"
@ -53,16 +54,16 @@ class DingtalkGroupRobotUtils private constructor() {
Log.i(TAG, "requestUrl:$requestUrl")
val msgMap: MutableMap<String, Any> = mutableMapOf()
msgMap["msgtype"] = setting.msgtype ?: "text"
msgMap["msgtype"] = setting.msgtype
val atMap: MutableMap<String, Any> = mutableMapOf()
msgMap["at"] = atMap
if (setting.atAll == true) {
if (setting.atAll) {
atMap["isAtAll"] = true
} else {
atMap["isAtAll"] = false
if (!TextUtils.isEmpty(setting.atMobiles)) {
val atMobilesArray: Array<String> = setting.atMobiles.toString().replace("[,;]".toRegex(), ",").trim(',').split(',').toTypedArray()
val atMobilesArray: Array<String> = setting.atMobiles.replace("[,;]".toRegex(), ",").trim(',').split(',').toTypedArray()
if (atMobilesArray.isNotEmpty()) {
atMap["atMobiles"] = atMobilesArray
for (atMobile in atMobilesArray) {
@ -73,7 +74,7 @@ class DingtalkGroupRobotUtils private constructor() {
}
}
if (!TextUtils.isEmpty(setting.atDingtalkIds)) {
val atDingtalkIdsArray: Array<String> = setting.atDingtalkIds.toString().replace("[,;]".toRegex(), ",").trim(',').split(',').toTypedArray()
val atDingtalkIdsArray: Array<String> = setting.atDingtalkIds.replace("[,;]".toRegex(), ",").trim(',').split(',').toTypedArray()
if (atDingtalkIdsArray.isNotEmpty()) {
atMap["atDingtalkIds"] = atDingtalkIdsArray
for (atDingtalkId in atDingtalkIdsArray) {
@ -86,7 +87,7 @@ class DingtalkGroupRobotUtils private constructor() {
}
if ("markdown" == msgMap["msgtype"]) {
val titleTemplate = setting.titleTemplate.toString()
val titleTemplate = setting.titleTemplate
val title = rule?.let { msgInfo.getTitleForSend(titleTemplate, it.regexReplace) } ?: msgInfo.getTitleForSend(titleTemplate)
msgMap["markdown"] = mutableMapOf<String, Any>("title" to title, "text" to content)
} else {

View File

@ -11,6 +11,7 @@ import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.SharedPreference
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -63,25 +64,25 @@ class DingtalkInnerRobotUtils private constructor() {
if (!NetworkUtils.isIP(proxyHost)) {
throw Exception(String.format(getString(R.string.invalid_proxy_host), proxyHost))
}
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890
val proxyPort: Int = setting.proxyPort.toInt()
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
//代理的鉴权账号密码
if (setting.proxyAuthenticator == true && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
if (setting.proxyAuthenticator && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")
if (setting.proxyType == Proxy.Type.HTTP) {
request.okproxyAuthenticator { _: Route?, response: Response ->
//设置代理服务器账号密码
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
val credential = Credentials.basic(setting.proxyUsername, setting.proxyPassword)
response.request().newBuilder().header("Proxy-Authorization", credential).build()
}
} else {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
return PasswordAuthentication(setting.proxyUsername, setting.proxyPassword.toCharArray())
}
})
}
@ -144,9 +145,9 @@ class DingtalkInnerRobotUtils private constructor() {
val msgParam: MutableMap<String, Any> = mutableMapOf()
if ("sampleMarkdown" == setting.msgKey) {
msgParam["title"] = if (rule != null) {
msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace)
msgInfo.getTitleForSend(setting.titleTemplate, rule.regexReplace)
} else {
msgInfo.getTitleForSend(setting.titleTemplate.toString())
msgInfo.getTitleForSend(setting.titleTemplate)
}
msgParam["text"] = content
} else {
@ -172,25 +173,25 @@ class DingtalkInnerRobotUtils private constructor() {
if (!NetworkUtils.isIP(proxyHost)) {
throw Exception(String.format(getString(R.string.invalid_proxy_host), proxyHost))
}
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890
val proxyPort: Int = setting.proxyPort.toInt()
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
//代理的鉴权账号密码
if (setting.proxyAuthenticator == true && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
if (setting.proxyAuthenticator && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")
if (setting.proxyType == Proxy.Type.HTTP) {
request.okproxyAuthenticator { _: Route?, response: Response ->
//设置代理服务器账号密码
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
val credential = Credentials.basic(setting.proxyUsername, setting.proxyPassword)
response.request().newBuilder().header("Proxy-Authorization", credential).build()
}
} else {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
return PasswordAuthentication(setting.proxyUsername, setting.proxyPassword.toCharArray())
}
})
}

View File

@ -38,9 +38,9 @@ class EmailUtils {
msgId: Long = 0L
) {
val title: String = if (rule != null) {
msgInfo.getTitleForSend(setting.title.toString(), rule.regexReplace)
msgInfo.getTitleForSend(setting.title, rule.regexReplace)
} else {
msgInfo.getTitleForSend(setting.title.toString())
msgInfo.getTitleForSend(setting.title)
}
val message: String = if (rule != null) {
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
@ -144,21 +144,21 @@ class EmailUtils {
val job = launch(Dispatchers.IO) {
try {
// 设置邮件参数
val host = setting.host.toString()
val port = setting.port.toString()
val from = setting.fromEmail.toString()
val password = setting.pwd.toString()
val nickname = msgInfo.getTitleForSend(setting.nickname.toString())
val host = setting.host
val port = setting.port
val from = setting.fromEmail
val password = setting.pwd
val nickname = msgInfo.getTitleForSend(setting.nickname)
setting.recipients.ifEmpty {
//兼容旧的设置
val emails = setting.toEmail.toString().replace("[,;]".toRegex(), ",").trim(',').split(',')
val emails = setting.toEmail.replace("[,;]".toRegex(), ",").trim(',').split(',')
emails.forEach {
setting.recipients[it] = Pair("", "")
}
}
val content = message.replace("\n", "<br>")
val openSSL = setting.ssl == true
val startTls = setting.startTls == true
val openSSL = setting.ssl
val startTls = setting.startTls
//发件人S/MIME私钥用于签名
var signingPrivateKey: PrivateKey? = null
@ -167,17 +167,17 @@ class EmailUtils {
var senderPGPSecretKeyRing: PGPSecretKeyRing? = null
var senderPGPSecretKeyPassword = ""
if (!setting.keystore.isNullOrEmpty() && !setting.password.isNullOrEmpty()) {
if (setting.keystore.isNotEmpty() && setting.password.isNotEmpty()) {
try {
val keystoreStream = if (setting.keystore!!.startsWith("/")) {
val keystoreStream = if (setting.keystore.startsWith("/")) {
FileInputStream(setting.keystore)
} else {
val decodedBytes = Base64.decode(setting.keystore!!)
val decodedBytes = Base64.decode(setting.keystore)
ByteArrayInputStream(decodedBytes)
}
when (setting.encryptionProtocol) {
"S/MIME" -> {
val keystorePassword = setting.password.toString()
val keystorePassword = setting.password
val keyStore = KeyStore.getInstance("PKCS12")
keyStore.load(keystoreStream, keystorePassword.toCharArray())
val privateKeyAlias = keyStore.aliases().toList().first { keyStore.isKeyEntry(it) }
@ -187,7 +187,7 @@ class EmailUtils {
"OpenPGP" -> {
senderPGPSecretKeyRing = PGPainless.readKeyRing().secretKeyRing(keystoreStream)
senderPGPSecretKeyPassword = setting.password.toString()
senderPGPSecretKeyPassword = setting.password
}
}
} catch (e: Exception) {

View File

@ -11,6 +11,7 @@ import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.SharedPreference
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException

View File

@ -10,6 +10,7 @@ import com.idormy.sms.forwarder.entity.setting.FeishuSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -89,9 +90,9 @@ class FeishuUtils private constructor() {
) {
val from: String = msgInfo.from
val title: String = if (rule != null) {
msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace)
msgInfo.getTitleForSend(setting.titleTemplate, rule.regexReplace)
} else {
msgInfo.getTitleForSend(setting.titleTemplate.toString())
msgInfo.getTitleForSend(setting.titleTemplate)
}
val content: String = if (rule != null) {
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
@ -103,24 +104,22 @@ class FeishuUtils private constructor() {
Log.i(TAG, "requestUrl:$requestUrl")
val msgMap: MutableMap<String, Any> = mutableMapOf()
if (setting.secret != null) {
val timestamp = System.currentTimeMillis() / 1000
val stringToSign = "$timestamp\n" + setting.secret
Log.i(TAG, "stringToSign = $stringToSign")
val timestamp = System.currentTimeMillis() / 1000
val stringToSign = "$timestamp\n" + setting.secret
Log.i(TAG, "stringToSign = $stringToSign")
//使用HmacSHA256算法计算签名
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(stringToSign.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
val signData = mac.doFinal(byteArrayOf())
val sign = String(Base64.encode(signData, Base64.NO_WRAP))
//使用HmacSHA256算法计算签名
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(stringToSign.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
val signData = mac.doFinal(byteArrayOf())
val sign = String(Base64.encode(signData, Base64.NO_WRAP))
msgMap["timestamp"] = timestamp
msgMap["sign"] = sign
}
msgMap["timestamp"] = timestamp
msgMap["sign"] = sign
//组装报文
val requestMsg: String
if (setting.msgType == null || setting.msgType == "interactive") {
if (setting.msgType == "interactive") {
msgMap["msg_type"] = "interactive"
if (TextUtils.isEmpty(setting.messageCard.trim())) {
msgMap["card"] = "{{CARD_BODY}}"

View File

@ -8,6 +8,8 @@ import com.idormy.sms.forwarder.entity.setting.GotifySetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.BasicAuthInterceptor
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -26,9 +28,9 @@ class GotifyUtils {
msgId: Long = 0L
) {
val title: String = if (rule != null) {
msgInfo.getTitleForSend(setting.title.toString(), rule.regexReplace)
msgInfo.getTitleForSend(setting.title, rule.regexReplace)
} else {
msgInfo.getTitleForSend(setting.title.toString())
msgInfo.getTitleForSend(setting.title)
}
val content: String = if (rule != null) {
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)

View File

@ -10,6 +10,7 @@ import com.idormy.sms.forwarder.entity.setting.PushplusSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -29,9 +30,9 @@ class PushplusUtils private constructor() {
msgId: Long = 0L
) {
val title: String = if (rule != null) {
msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace)
msgInfo.getTitleForSend(setting.titleTemplate, rule.regexReplace)
} else {
msgInfo.getTitleForSend(setting.titleTemplate.toString())
msgInfo.getTitleForSend(setting.titleTemplate)
}
val content: String = if (rule != null) {
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
@ -47,16 +48,16 @@ class PushplusUtils private constructor() {
msgMap["content"] = content
if (!TextUtils.isEmpty(title)) msgMap["title"] = title
if (!TextUtils.isEmpty(setting.template)) msgMap["template"] = setting.template.toString()
if (!TextUtils.isEmpty(setting.topic)) msgMap["topic"] = setting.topic.toString()
if (!TextUtils.isEmpty(setting.template)) msgMap["template"] = setting.template
if (!TextUtils.isEmpty(setting.topic)) msgMap["topic"] = setting.topic
if (setting.website == getString(R.string.pushplus_plus)) {
if (!TextUtils.isEmpty(setting.channel)) msgMap["channel"] = setting.channel.toString()
if (!TextUtils.isEmpty(setting.webhook)) msgMap["webhook"] = setting.webhook.toString()
if (!TextUtils.isEmpty(setting.callbackUrl)) msgMap["callbackUrl"] = setting.callbackUrl.toString()
if (!TextUtils.isEmpty(setting.channel)) msgMap["channel"] = setting.channel
if (!TextUtils.isEmpty(setting.webhook)) msgMap["webhook"] = setting.webhook
if (!TextUtils.isEmpty(setting.callbackUrl)) msgMap["callbackUrl"] = setting.callbackUrl
if (!TextUtils.isEmpty(setting.validTime)) {
val validTime = setting.validTime?.toInt()
if (validTime != null && validTime > 0) {
val validTime = setting.validTime.toInt()
if (validTime > 0) {
msgMap["timestamp"] = System.currentTimeMillis() + validTime * 1000L
}
}

View File

@ -9,6 +9,7 @@ import com.idormy.sms.forwarder.entity.setting.ServerchanSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -27,9 +28,9 @@ class ServerchanUtils {
msgId: Long = 0L
) {
val title: String = if (rule != null) {
msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace)
msgInfo.getTitleForSend(setting.titleTemplate, rule.regexReplace)
} else {
msgInfo.getTitleForSend(setting.titleTemplate.toString())
msgInfo.getTitleForSend(setting.titleTemplate)
}
val content: String = if (rule != null) {
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)

View File

@ -2,13 +2,13 @@ package com.idormy.sms.forwarder.utils.sender
import android.Manifest
import android.content.pm.PackageManager
import com.idormy.sms.forwarder.utils.Log
import androidx.core.app.ActivityCompat
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.database.entity.Rule
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.setting.SmsSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.PhoneUtils
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
@ -30,7 +30,7 @@ class SmsUtils {
msgId: Long = 0L
) {
//仅当无网络时启用 && 判断是否真实有网络
if (setting.onlyNoNetwork == true && NetworkUtils.isHaveInternet() && NetworkUtils.isAvailableByPing()) {
if (setting.onlyNoNetwork && NetworkUtils.isHaveInternet() && NetworkUtils.isAvailableByPing()) {
SendUtils.updateLogs(logId, 0, getString(R.string.OnlyNoNetwork))
SendUtils.senderLogic(0, msgInfo, rule, senderIndex, msgId)
return

View File

@ -57,7 +57,7 @@ class SocketUtils {
if (!TextUtils.isEmpty(setting.secret)) {
val stringToSign = "$timestamp\n" + setting.secret
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(setting.secret?.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
mac.init(SecretKeySpec(setting.secret.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
val signData = mac.doFinal(stringToSign.toByteArray(StandardCharsets.UTF_8))
sign = URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8")
}
@ -87,7 +87,7 @@ class SocketUtils {
// 从服务器接收响应
val response = input.readLine()
Log.d(TAG, "从服务器接收的响应: $response")
val status = if (!setting.response.isNullOrEmpty() && !response.contains(setting.response)) 0 else 2
val status = if (setting.response.isNotEmpty() && !response.contains(setting.response)) 0 else 2
SendUtils.updateLogs(logId, status, response)
SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId)
} catch (e: Exception) {
@ -143,7 +143,7 @@ class SocketUtils {
override fun messageArrived(topic: String?, inMessage: MqttMessage?) {
val payload = inMessage?.payload?.toString(Charset.forName(setting.inCharset))
Log.d(TAG, "Received message on topic $topic: $payload")
val status = if (!setting.response.isNullOrEmpty() && !payload?.contains(setting.response)!!) 0 else 2
val status = if (setting.response.isNotEmpty() && !payload?.contains(setting.response)!!) 0 else 2
SendUtils.updateLogs(logId, status, payload.toString())
SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId)
}

View File

@ -10,6 +10,7 @@ import com.idormy.sms.forwarder.entity.setting.TelegramSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -37,7 +38,7 @@ class TelegramUtils private constructor() {
logId: Long = 0L,
msgId: Long = 0L
) {
if (setting.method == null || setting.method == "POST") {
if (setting.method == "POST") {
msgInfo.content = htmlEncode(msgInfo.content)
msgInfo.simInfo = htmlEncode(msgInfo.simInfo)
}
@ -55,7 +56,7 @@ class TelegramUtils private constructor() {
}
Log.i(TAG, "requestUrl:$requestUrl")
val request = if (setting.method != null && setting.method == "GET") {
val request = if (setting.method == "GET") {
requestUrl += "?chat_id=" + setting.chatId + "&text=" + URLEncoder.encode(content, "UTF-8")
Log.i(TAG, "requestUrl:$requestUrl")
XHttp.get(requestUrl)
@ -80,21 +81,20 @@ class TelegramUtils private constructor() {
if (!NetworkUtils.isIP(proxyHost)) {
throw Exception(String.format(getString(R.string.invalid_proxy_host), proxyHost))
}
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890
val proxyPort: Int = setting.proxyPort.toInt()
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
//代理的鉴权账号密码
if (setting.proxyAuthenticator == true
&& (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))
if (setting.proxyAuthenticator && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))
) {
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")
if (setting.proxyType == Proxy.Type.HTTP) {
request.okproxyAuthenticator { _: Route?, response: Response ->
//设置代理服务器账号密码
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
val credential = Credentials.basic(setting.proxyUsername, setting.proxyPassword)
response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build()
@ -102,7 +102,7 @@ class TelegramUtils private constructor() {
} else {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
return PasswordAuthentication(setting.proxyUsername, setting.proxyPassword.toCharArray())
}
})
}

View File

@ -11,6 +11,7 @@ import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.SharedPreference
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -60,25 +61,25 @@ class WeworkAgentUtils private constructor() {
if (!NetworkUtils.isIP(proxyHost)) {
throw Exception(String.format(getString(R.string.invalid_proxy_host), proxyHost))
}
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890
val proxyPort: Int = setting.proxyPort.toInt()
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
//代理的鉴权账号密码
if (setting.proxyAuthenticator == true && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
if (setting.proxyAuthenticator && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")
if (setting.proxyType == Proxy.Type.HTTP) {
request.okproxyAuthenticator { _: Route?, response: Response ->
//设置代理服务器账号密码
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
val credential = Credentials.basic(setting.proxyUsername, setting.proxyPassword)
response.request().newBuilder().header("Proxy-Authorization", credential).build()
}
} else {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
return PasswordAuthentication(setting.proxyUsername, setting.proxyPassword.toCharArray())
}
})
}
@ -135,9 +136,9 @@ class WeworkAgentUtils private constructor() {
}
val textMsgMap: MutableMap<String, Any> = mutableMapOf()
textMsgMap["touser"] = setting.toUser.toString()
textMsgMap["toparty"] = setting.toParty.toString()
textMsgMap["totag"] = setting.toTag.toString()
textMsgMap["touser"] = setting.toUser
textMsgMap["toparty"] = setting.toParty
textMsgMap["totag"] = setting.toTag
textMsgMap["msgtype"] = "text"
textMsgMap["agentid"] = setting.agentID
val textText: MutableMap<String, Any> = mutableMapOf()
@ -160,25 +161,25 @@ class WeworkAgentUtils private constructor() {
if (!NetworkUtils.isIP(proxyHost)) {
throw Exception(String.format(getString(R.string.invalid_proxy_host), proxyHost))
}
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890
val proxyPort: Int = setting.proxyPort.toInt()
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
//代理的鉴权账号密码
if (setting.proxyAuthenticator == true && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
if (setting.proxyAuthenticator && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))) {
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")
if (setting.proxyType == Proxy.Type.HTTP) {
request.okproxyAuthenticator { _: Route?, response: Response ->
//设置代理服务器账号密码
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
val credential = Credentials.basic(setting.proxyUsername, setting.proxyPassword)
response.request().newBuilder().header("Proxy-Authorization", credential).build()
}
} else {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
return PasswordAuthentication(setting.proxyUsername, setting.proxyPassword.toCharArray())
}
})
}

View File

@ -8,6 +8,7 @@ import com.idormy.sms.forwarder.entity.setting.WeworkRobotSetting
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.interceptor.LoggingInterceptor
import com.xuexiang.xhttp2.XHttp
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
@ -43,14 +44,14 @@ class WeworkRobotUtils private constructor() {
if (setting.msgType == "markdown") {
msgMap["markdown"] = contextMap
} else {
if (setting.atAll == true) {
if (setting.atAll) {
contextMap["mentioned_list"] = arrayListOf("@all")
} else {
if (!setting.atUserIds.isNullOrEmpty()) {
contextMap["mentioned_list"] = setting.atUserIds!!.split(",")
if (setting.atUserIds.isNotEmpty()) {
contextMap["mentioned_list"] = setting.atUserIds.split(",")
}
if (!setting.atMobiles.isNullOrEmpty()) {
contextMap["mentioned_mobile_list"] = setting.atMobiles!!.split(",")
if (setting.atMobiles.isNotEmpty()) {
contextMap["mentioned_mobile_list"] = setting.atMobiles.split(",")
}
}
msgMap["text"] = contextMap

View File

@ -86,7 +86,7 @@ class SendWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
if (SettingUtils.enableSilentPeriodLogs) {
isSilentPeriod = true
} else {
Log.e("SendWorker", "免打扰(禁用转发)时间段")
Log.e(TAG, "免打扰(禁用转发)时间段")
return@withContext Result.failure(workDataOf("send" to "failed"))
}
}
@ -98,9 +98,9 @@ class SendWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
val key = CipherUtils.md5(msgInfo.type + msgInfo.from + msgInfo.content)
val timestamp: Long = System.currentTimeMillis()
var timestampPrev: Long by HistoryUtils(key, timestamp)
Log.d("SendWorker", "duplicateMessagesLimits=$duplicateMessagesLimits, timestamp=$timestamp, timestampPrev=$timestampPrev, msgInfo=$msgInfo")
Log.d(TAG, "duplicateMessagesLimits=$duplicateMessagesLimits, timestamp=$timestamp, timestampPrev=$timestampPrev, msgInfo=$msgInfo")
if (timestampPrev != timestamp && timestamp - timestampPrev <= duplicateMessagesLimits) {
Log.e("SendWorker", "过滤重复消息机制")
Log.e(TAG, "过滤重复消息机制")
timestampPrev = timestamp
return@withContext Result.failure(workDataOf("send" to "failed"))
}
@ -114,7 +114,7 @@ class SendWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
val ruleListMatched: MutableList<Rule> = mutableListOf()
for (rule in ruleList) {
Log.d("SendWorker", rule.toString())
Log.d(TAG, rule.toString())
if (rule.checkMsg(msgInfo)) ruleListMatched.add(rule)
}
if (ruleListMatched.isEmpty()) {
@ -137,7 +137,7 @@ class SendWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
} catch (e: Exception) {
e.printStackTrace()
Log.e("SendWorker", "SendWorker error: ${e.message}")
Log.e(TAG, "SendWorker error: ${e.message}")
return@withContext Result.failure(workDataOf("send" to e.message.toString()))
}