mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-03 01:17:41 +08:00
优化:发送通道Webhook
支持http/socks5代理
优化:服务端应答`Http 204 No Content`时特殊处理(更新日志状态为成功) #234
This commit is contained in:
parent
9107fa4589
commit
5eed98121e
@ -2,21 +2,36 @@ package com.idormy.sms.forwarder.entity.setting
|
|||||||
|
|
||||||
import com.idormy.sms.forwarder.R
|
import com.idormy.sms.forwarder.R
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
import java.net.Proxy
|
||||||
|
|
||||||
data class WebhookSetting(
|
data class WebhookSetting(
|
||||||
val method: String? = "POST",
|
val method: String = "POST",
|
||||||
var webServer: String = "",
|
var webServer: String = "",
|
||||||
val secret: String? = "",
|
val secret: String = "",
|
||||||
val response: String? = "",
|
val response: String = "",
|
||||||
val webParams: String? = "",
|
val webParams: String = "",
|
||||||
val headers: Map<String, String>?,
|
val headers: Map<String, String> = mapOf(),
|
||||||
|
val proxyType: Proxy.Type = Proxy.Type.DIRECT,
|
||||||
|
val proxyHost: String = "",
|
||||||
|
val proxyPort: String = "",
|
||||||
|
val proxyAuthenticator: Boolean = false,
|
||||||
|
val proxyUsername: String = "",
|
||||||
|
val proxyPassword: String = "",
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
fun getMethodCheckId(): Int {
|
fun getMethodCheckId(): Int {
|
||||||
return when (method) {
|
return when (method) {
|
||||||
null, "POST" -> R.id.rb_method_post
|
"POST" -> R.id.rb_method_post
|
||||||
"PUT" -> R.id.rb_method_put
|
"PUT" -> R.id.rb_method_put
|
||||||
"PATCH" -> R.id.rb_method_patch
|
"PATCH" -> R.id.rb_method_patch
|
||||||
else -> R.id.rb_method_get
|
else -> R.id.rb_method_get
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getProxyTypeCheckId(): Int {
|
||||||
|
return when (proxyType) {
|
||||||
|
Proxy.Type.HTTP -> R.id.rb_proxyHttp
|
||||||
|
Proxy.Type.SOCKS -> R.id.rb_proxySocks
|
||||||
|
else -> R.id.rb_proxyNone
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,9 +4,11 @@ import android.text.TextUtils
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CompoundButton
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.RadioGroup
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.idormy.sms.forwarder.R
|
import com.idormy.sms.forwarder.R
|
||||||
@ -41,11 +43,12 @@ import io.reactivex.SingleObserver
|
|||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import java.net.Proxy
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
@Page(name = "Webhook")
|
@Page(name = "Webhook")
|
||||||
@Suppress("PrivatePropertyName")
|
@Suppress("PrivatePropertyName")
|
||||||
class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnClickListener {
|
class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
||||||
|
|
||||||
private val TAG: String = WebhookFragment::class.java.simpleName
|
private val TAG: String = WebhookFragment::class.java.simpleName
|
||||||
private var titleBar: TitleBar? = null
|
private var titleBar: TitleBar? = null
|
||||||
@ -132,13 +135,17 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
|
|||||||
binding!!.etResponse.setText(settingVo.response)
|
binding!!.etResponse.setText(settingVo.response)
|
||||||
binding!!.etWebParams.setText(settingVo.webParams)
|
binding!!.etWebParams.setText(settingVo.webParams)
|
||||||
//set header
|
//set header
|
||||||
if (settingVo.headers != null) {
|
for ((key, value) in settingVo.headers) {
|
||||||
for ((key, value) in settingVo.headers) {
|
addHeaderItemLinearLayout(
|
||||||
addHeaderItemLinearLayout(
|
headerItemMap, binding!!.layoutHeaders, key, value
|
||||||
headerItemMap, binding!!.layoutHeaders, key, value
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
|
||||||
|
binding!!.etProxyHost.setText(settingVo.proxyHost)
|
||||||
|
binding!!.etProxyPort.setText(settingVo.proxyPort)
|
||||||
|
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
|
||||||
|
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
|
||||||
|
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -151,9 +158,26 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
|
|||||||
binding!!.btnAddHeader.setOnClickListener {
|
binding!!.btnAddHeader.setOnClickListener {
|
||||||
addHeaderItemLinearLayout(headerItemMap, binding!!.layoutHeaders, null, null)
|
addHeaderItemLinearLayout(headerItemMap, binding!!.layoutHeaders, null, null)
|
||||||
}
|
}
|
||||||
|
binding!!.sbProxyAuthenticator.setOnCheckedChangeListener(this)
|
||||||
|
binding!!.rgProxyType.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int ->
|
||||||
|
if (checkedId == R.id.rb_proxyHttp || checkedId == R.id.rb_proxySocks) {
|
||||||
|
binding!!.layoutProxyHost.visibility = View.VISIBLE
|
||||||
|
binding!!.layoutProxyPort.visibility = View.VISIBLE
|
||||||
|
binding!!.layoutProxyAuthenticator.visibility = if (binding!!.sbProxyAuthenticator.isChecked) View.VISIBLE else View.GONE
|
||||||
|
} else {
|
||||||
|
binding!!.layoutProxyHost.visibility = View.GONE
|
||||||
|
binding!!.layoutProxyPort.visibility = View.GONE
|
||||||
|
binding!!.layoutProxyAuthenticator.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
LiveEventBus.get(KEY_SENDER_TEST, String::class.java).observe(this) { mCountDownHelper?.finish() }
|
LiveEventBus.get(KEY_SENDER_TEST, String::class.java).observe(this) { mCountDownHelper?.finish() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
|
||||||
|
//注意:因为只有一个监听,暂不需要判断id
|
||||||
|
binding!!.layoutProxyAuthenticator.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
@SingleClick
|
@SingleClick
|
||||||
override fun onClick(v: View) {
|
override fun onClick(v: View) {
|
||||||
try {
|
try {
|
||||||
@ -233,7 +257,26 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
|
|||||||
val webParams = binding!!.etWebParams.text.toString().trim()
|
val webParams = binding!!.etWebParams.text.toString().trim()
|
||||||
val headers = getHeadersFromHeaderItemMap(headerItemMap)
|
val headers = getHeadersFromHeaderItemMap(headerItemMap)
|
||||||
|
|
||||||
return WebhookSetting(method, webServer, secret, response, webParams, headers)
|
val proxyType: Proxy.Type = when (binding!!.rgProxyType.checkedRadioButtonId) {
|
||||||
|
R.id.rb_proxyHttp -> Proxy.Type.HTTP
|
||||||
|
R.id.rb_proxySocks -> Proxy.Type.SOCKS
|
||||||
|
else -> Proxy.Type.DIRECT
|
||||||
|
}
|
||||||
|
val proxyHost = binding!!.etProxyHost.text.toString().trim()
|
||||||
|
val proxyPort = binding!!.etProxyPort.text.toString().trim()
|
||||||
|
|
||||||
|
if (proxyType != Proxy.Type.DIRECT && (TextUtils.isEmpty(proxyHost) || TextUtils.isEmpty(proxyPort))) {
|
||||||
|
throw Exception(getString(R.string.invalid_host_or_port))
|
||||||
|
}
|
||||||
|
|
||||||
|
val proxyAuthenticator = binding!!.sbProxyAuthenticator.isChecked
|
||||||
|
val proxyUsername = binding!!.etProxyUsername.text.toString().trim()
|
||||||
|
val proxyPassword = binding!!.etProxyPassword.text.toString().trim()
|
||||||
|
if (proxyAuthenticator && TextUtils.isEmpty(proxyUsername) && TextUtils.isEmpty(proxyPassword)) {
|
||||||
|
throw Exception(getString(R.string.invalid_username_or_password))
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebhookSetting(method, webServer, secret, response, webParams, headers, proxyType, proxyHost, proxyPort, proxyAuthenticator, proxyUsername, proxyPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.idormy.sms.forwarder.utils.interceptor
|
||||||
|
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.workDataOf
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.idormy.sms.forwarder.entity.result.SendResponse
|
||||||
|
import com.idormy.sms.forwarder.utils.Log
|
||||||
|
import com.idormy.sms.forwarder.utils.Worker
|
||||||
|
import com.idormy.sms.forwarder.workers.UpdateLogsWorker
|
||||||
|
import com.xuexiang.xutil.XUtil
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class NoContentInterceptor(private val logId: Long) : Interceptor {
|
||||||
|
|
||||||
|
private val TAG: String = NoContentInterceptor::class.java.simpleName
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val originalResponse = chain.proceed(chain.request())
|
||||||
|
|
||||||
|
if (originalResponse.code() == 204) {
|
||||||
|
val response = "HTTP 204 No Content"
|
||||||
|
Log.d(TAG, response)
|
||||||
|
/*
|
||||||
|
// 创建一个空的响应体
|
||||||
|
val message = "{\"Code\":0, \"Msg\":\"\", \"Data\":{}}"
|
||||||
|
val emptyJsonBody = ResponseBody.create(MediaType.parse("application/json"), message)
|
||||||
|
// 使用新的响应体替换原始响应中的响应体
|
||||||
|
return originalResponse.newBuilder()
|
||||||
|
.body(emptyJsonBody)
|
||||||
|
.header("Content-Length", message.length.toString())
|
||||||
|
.build()
|
||||||
|
*/
|
||||||
|
//TODO: 暂时特殊处理,更新日志状态为成功
|
||||||
|
val sendResponse = SendResponse(logId, 2, response)
|
||||||
|
val request = OneTimeWorkRequestBuilder<UpdateLogsWorker>()
|
||||||
|
.setInitialDelay(200, TimeUnit.MILLISECONDS)
|
||||||
|
.setInputData(
|
||||||
|
workDataOf(
|
||||||
|
Worker.UPDATE_LOGS to Gson().toJson(sendResponse)
|
||||||
|
)
|
||||||
|
).build()
|
||||||
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
return originalResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
import com.idormy.sms.forwarder.R
|
||||||
import com.idormy.sms.forwarder.database.entity.Rule
|
import com.idormy.sms.forwarder.database.entity.Rule
|
||||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
import com.idormy.sms.forwarder.entity.setting.WebhookSetting
|
import com.idormy.sms.forwarder.entity.setting.WebhookSetting
|
||||||
@ -11,16 +12,29 @@ import com.idormy.sms.forwarder.utils.AppUtils
|
|||||||
import com.idormy.sms.forwarder.utils.Log
|
import com.idormy.sms.forwarder.utils.Log
|
||||||
import com.idormy.sms.forwarder.utils.SendUtils
|
import com.idormy.sms.forwarder.utils.SendUtils
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
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.idormy.sms.forwarder.utils.interceptor.NoContentInterceptor
|
||||||
import com.xuexiang.xhttp2.XHttp
|
import com.xuexiang.xhttp2.XHttp
|
||||||
import com.xuexiang.xhttp2.callback.SimpleCallBack
|
import com.xuexiang.xhttp2.callback.SimpleCallBack
|
||||||
import com.xuexiang.xhttp2.exception.ApiException
|
import com.xuexiang.xhttp2.exception.ApiException
|
||||||
|
import com.xuexiang.xutil.net.NetworkUtils
|
||||||
|
import com.xuexiang.xutil.resource.ResUtils
|
||||||
|
import okhttp3.Credentials
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.Route
|
||||||
|
import java.net.Authenticator
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import java.net.PasswordAuthentication
|
||||||
|
import java.net.Proxy
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.Date
|
||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
|
||||||
class WebhookUtils {
|
class WebhookUtils {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -57,7 +71,7 @@ class WebhookUtils {
|
|||||||
val mac = Mac.getInstance("HmacSHA256")
|
val mac = Mac.getInstance("HmacSHA256")
|
||||||
mac.init(
|
mac.init(
|
||||||
SecretKeySpec(
|
SecretKeySpec(
|
||||||
setting.secret?.toByteArray(StandardCharsets.UTF_8),
|
setting.secret.toByteArray(StandardCharsets.UTF_8),
|
||||||
"HmacSHA256"
|
"HmacSHA256"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -65,7 +79,7 @@ class WebhookUtils {
|
|||||||
sign = URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8")
|
sign = URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
var webParams = setting.webParams?.trim()
|
var webParams = setting.webParams.trim()
|
||||||
|
|
||||||
//支持HTTP基本认证(Basic Authentication)
|
//支持HTTP基本认证(Basic Authentication)
|
||||||
val regex = "^(https?://)([^:]+):([^@]+)@(.+)"
|
val regex = "^(https?://)([^:]+):([^@]+)@(.+)"
|
||||||
@ -90,7 +104,7 @@ class WebhookUtils {
|
|||||||
Log.d(TAG, "method = GET, Url = $requestUrl")
|
Log.d(TAG, "method = GET, Url = $requestUrl")
|
||||||
XHttp.get(requestUrl).keepJson(true)
|
XHttp.get(requestUrl).keepJson(true)
|
||||||
} else if (setting.method == "GET" && !TextUtils.isEmpty(webParams)) {
|
} else if (setting.method == "GET" && !TextUtils.isEmpty(webParams)) {
|
||||||
webParams = webParams.toString().replace("[from]", URLEncoder.encode(from, "UTF-8"))
|
webParams = webParams.replace("[from]", URLEncoder.encode(from, "UTF-8"))
|
||||||
.replace("[content]", URLEncoder.encode(content, "UTF-8"))
|
.replace("[content]", URLEncoder.encode(content, "UTF-8"))
|
||||||
.replace("[msg]", URLEncoder.encode(content, "UTF-8"))
|
.replace("[msg]", URLEncoder.encode(content, "UTF-8"))
|
||||||
.replace("[org_content]", URLEncoder.encode(orgContent, "UTF-8"))
|
.replace("[org_content]", URLEncoder.encode(orgContent, "UTF-8"))
|
||||||
@ -114,7 +128,7 @@ class WebhookUtils {
|
|||||||
}
|
}
|
||||||
Log.d(TAG, "method = GET, Url = $requestUrl")
|
Log.d(TAG, "method = GET, Url = $requestUrl")
|
||||||
XHttp.get(requestUrl).keepJson(true)
|
XHttp.get(requestUrl).keepJson(true)
|
||||||
} else if (!webParams.isNullOrEmpty() && webParams.startsWith("{")) {
|
} else if (webParams.isNotEmpty() && webParams.startsWith("{")) {
|
||||||
val bodyMsg = webParams.replace("[from]", from)
|
val bodyMsg = webParams.replace("[from]", from)
|
||||||
.replace("[content]", escapeJson(content))
|
.replace("[content]", escapeJson(content))
|
||||||
.replace("[msg]", escapeJson(content))
|
.replace("[msg]", escapeJson(content))
|
||||||
@ -136,7 +150,7 @@ class WebhookUtils {
|
|||||||
else -> XHttp.post(requestUrl).keepJson(true).upJson(bodyMsg)
|
else -> XHttp.post(requestUrl).keepJson(true).upJson(bodyMsg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (webParams.isNullOrEmpty()) {
|
if (webParams.isEmpty()) {
|
||||||
webParams = "from=[from]&content=[content]×tamp=[timestamp]"
|
webParams = "from=[from]&content=[content]×tamp=[timestamp]"
|
||||||
if (!TextUtils.isEmpty(sign)) webParams += "&sign=[sign]"
|
if (!TextUtils.isEmpty(sign)) webParams += "&sign=[sign]"
|
||||||
}
|
}
|
||||||
@ -171,7 +185,7 @@ class WebhookUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//添加headers
|
//添加headers
|
||||||
for ((key, value) in setting.headers?.entries!!) {
|
for ((key, value) in setting.headers.entries) {
|
||||||
request.headers(key, value)
|
request.headers(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,24 +194,65 @@ class WebhookUtils {
|
|||||||
request.addInterceptor(BasicAuthInterceptor(matches[2], matches[3]))
|
request.addInterceptor(BasicAuthInterceptor(matches[2], matches[3]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//设置代理
|
||||||
|
if ((setting.proxyType == Proxy.Type.HTTP || setting.proxyType == Proxy.Type.SOCKS)
|
||||||
|
&& !TextUtils.isEmpty(setting.proxyHost) && !TextUtils.isEmpty(setting.proxyPort)
|
||||||
|
) {
|
||||||
|
//代理服务器的IP和端口号
|
||||||
|
Log.d(TAG, "proxyHost = ${setting.proxyHost}, proxyPort = ${setting.proxyPort}")
|
||||||
|
val proxyHost = if (NetworkUtils.isIP(setting.proxyHost)) setting.proxyHost else NetworkUtils.getDomainAddress(setting.proxyHost)
|
||||||
|
if (!NetworkUtils.isIP(proxyHost)) {
|
||||||
|
throw Exception(String.format(ResUtils.getString(R.string.invalid_proxy_host), proxyHost))
|
||||||
|
}
|
||||||
|
val proxyPort: Int = setting.proxyPort.toInt()
|
||||||
|
|
||||||
|
Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
|
||||||
|
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))
|
||||||
|
|
||||||
|
//代理的鉴权账号密码
|
||||||
|
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, setting.proxyPassword)
|
||||||
|
response.request().newBuilder()
|
||||||
|
.header("Proxy-Authorization", credential)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Authenticator.setDefault(object : Authenticator() {
|
||||||
|
override fun getPasswordAuthentication(): PasswordAuthentication {
|
||||||
|
return PasswordAuthentication(setting.proxyUsername, setting.proxyPassword.toCharArray())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
request.ignoreHttpsCert() //忽略https证书
|
request.ignoreHttpsCert() //忽略https证书
|
||||||
.retryCount(SettingUtils.requestRetryTimes) //超时重试的次数
|
.retryCount(SettingUtils.requestRetryTimes) //超时重试的次数
|
||||||
.retryDelay(SettingUtils.requestDelayTime * 1000) //超时重试的延迟时间
|
.retryDelay(SettingUtils.requestDelayTime * 1000) //超时重试的延迟时间
|
||||||
.retryIncreaseDelay(SettingUtils.requestDelayTime * 1000) //超时重试叠加延时
|
.retryIncreaseDelay(SettingUtils.requestDelayTime * 1000) //超时重试叠加延时
|
||||||
.timeStamp(true) //url自动追加时间戳,避免缓存
|
.timeStamp(true) //url自动追加时间戳,避免缓存
|
||||||
.addInterceptor(LoggingInterceptor(logId)) //增加一个log拦截器, 记录请求日志
|
.addInterceptor(LoggingInterceptor(logId)) //增加一个log拦截器, 记录请求日志
|
||||||
.execute(object : SimpleCallBack<String>() {
|
.addInterceptor(NoContentInterceptor(logId)) //拦截 HTTP 204 响应
|
||||||
|
.execute(object : SimpleCallBack<Any>() {
|
||||||
|
|
||||||
override fun onError(e: ApiException) {
|
override fun onError(e: ApiException) {
|
||||||
|
e.printStackTrace()
|
||||||
Log.e(TAG, e.detailMessage)
|
Log.e(TAG, e.detailMessage)
|
||||||
val status = 0
|
val status = 0
|
||||||
SendUtils.updateLogs(logId, status, e.displayMessage)
|
SendUtils.updateLogs(logId, status, e.displayMessage)
|
||||||
SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId)
|
SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(response: String) {
|
override fun onSuccess(resp: Any) {
|
||||||
|
val response = resp.toString()
|
||||||
Log.i(TAG, response)
|
Log.i(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.updateLogs(logId, status, response)
|
||||||
SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId)
|
SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId)
|
||||||
}
|
}
|
||||||
|
@ -248,6 +248,153 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/BarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/proxy_settings"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/rg_proxyType"
|
||||||
|
style="@style/rg_style"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_proxyNone"
|
||||||
|
style="@style/rg_rb_style"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/proxy_none" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_proxyHttp"
|
||||||
|
style="@style/rg_rb_style"
|
||||||
|
android:text="@string/proxy_http" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/rb_proxySocks"
|
||||||
|
style="@style/rg_rb_style"
|
||||||
|
android:text="@string/proxy_socks" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutProxyHost"
|
||||||
|
style="@style/BarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/hostname" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_proxyHost"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutProxyPort"
|
||||||
|
style="@style/BarStyle.Switch"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/port" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_proxyPort"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:digits="0123456789"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="5"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:text="@string/proxy_authenticator" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
||||||
|
android:id="@+id/sb_proxyAuthenticator"
|
||||||
|
style="@style/SwitchButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutProxyAuthenticator"
|
||||||
|
style="@style/BarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/username" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_proxyUsername"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:text="@string/password" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_proxyPassword"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_passWordButton="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user