diff --git a/app/src/main/java/com/idormy/sms/forwarder/model/vo/ResVo.java b/app/src/main/java/com/idormy/sms/forwarder/model/vo/ResVo.java new file mode 100644 index 00000000..ba939936 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/model/vo/ResVo.java @@ -0,0 +1,55 @@ +package com.idormy.sms.forwarder.model.vo; + +import lombok.Data; + +@Data +public class ResVo { + public static final int ERROR_CODE = 500; + public static final int Suess_CODE = 200; + private int code; + private String msg; + private String auth; + private SmsHubVo heartbeat; + private T data; + + public ResVo setSuessces(T data) { + this.setCode(Suess_CODE); + this.setData(data); + this.setMsg(""); + return this; + } + + public ResVo setError(Throwable e) { + this.setCode(ERROR_CODE); + this.setMsg(e.getMessage()); + return this; + } + + public ResVo setError(String msg) { + this.setCode(ERROR_CODE); + this.setMsg(msg); + return this; + } + + public static ResVo suessces(T data) { + ResVo resVo = new ResVo<>(); + resVo.setCode(Suess_CODE); + resVo.setData(data); + resVo.setMsg(""); + return resVo; + } + + public static ResVo error(Throwable e) { + ResVo resVo = new ResVo<>(); + resVo.setCode(ERROR_CODE); + resVo.setMsg(e.getMessage()); + return resVo; + } + + public static ResVo error(String msg) { + ResVo resVo = new ResVo<>(); + resVo.setCode(ERROR_CODE); + resVo.setMsg(msg); + return resVo; + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/model/vo/SmsHubVo.java b/app/src/main/java/com/idormy/sms/forwarder/model/vo/SmsHubVo.java index b08adff2..a5bb56b4 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/model/vo/SmsHubVo.java +++ b/app/src/main/java/com/idormy/sms/forwarder/model/vo/SmsHubVo.java @@ -28,7 +28,7 @@ public class SmsHubVo implements Serializable { public SmsHubVo(Type type, Integer simId, String content, String target) { this.msgId = UUID.randomUUID().toString(); - if (channel != null) { + if (simId != null) { String simInfo = simId == 2 ? SettingUtil.getAddExtraSim2() : SettingUtil.getAddExtraSim1(); //自定义备注优先 simInfo = "SIM" + simId + ":" + simInfo; this.channel = simInfo; @@ -37,6 +37,7 @@ public class SmsHubVo implements Serializable { this.target = target; this.action = Action.receive.code(); this.type = type.code; + this.ts = System.currentTimeMillis() + ""; } //唯一id @@ -51,22 +52,25 @@ public class SmsHubVo implements Serializable { private String errMsg; //手机号(;分隔)或包名 private String target; - //状态或操作 + //状态或操作 0:发送短信, 1:接收到的消息, 2:操作处理成功, 3:操作处理失败, -1:心跳包 (包含deviceInfo字段,children里带有两次心跳间收到的消息) private String action; - //消息类型 + //消息类型 app:通知 phone:来电, sms:短信, battery:电池信息 private String type; //时间戳 private String ts; //两次交互之间接收到的消息 private List children; - public static SmsHubVo heartbeatInstance() { + public static SmsHubVo heartbeatInstance(List data) { SmsHubVo smsHubVo = new SmsHubVo(); HashMap deviInfoMap = getDevInfoMap(false); smsHubVo.setDeviceInfo(JSON.toJSONString(deviInfoMap)); smsHubVo.setChannel("SIM1:" + SimUtil.getSimInfo(1) + SettingUtil.getAddExtraSim1() + ";SIM2:" + SimUtil.getSimInfo(2) + SettingUtil.getAddExtraSim2()); smsHubVo.setTs(Long.toString(System.currentTimeMillis())); smsHubVo.setAction(SmsHubVo.Action.heartbeat.code()); + if (data != null && data.size() > 0) { + smsHubVo.setChildren(data); + } return smsHubVo; } diff --git a/app/src/main/java/com/idormy/sms/forwarder/receiver/BaseServlet.java b/app/src/main/java/com/idormy/sms/forwarder/receiver/BaseServlet.java index 5e46acdf..1602ba47 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/receiver/BaseServlet.java +++ b/app/src/main/java/com/idormy/sms/forwarder/receiver/BaseServlet.java @@ -5,7 +5,9 @@ import android.content.Context; import android.util.Log; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.util.IOUtils; +import com.idormy.sms.forwarder.model.vo.ResVo; import com.idormy.sms.forwarder.model.vo.SmsHubVo; import com.idormy.sms.forwarder.utils.BackupDbTask; import com.idormy.sms.forwarder.utils.SettingUtil; @@ -14,6 +16,7 @@ import com.idormy.sms.forwarder.utils.SmsHubActionHandler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.StringUtil; import java.io.BufferedReader; import java.io.File; @@ -43,7 +46,7 @@ public class BaseServlet extends HttpServlet { public static final String SMSHUB_PATH = "/send_api"; private static final long serialVersionUID = 1L; private static final String TAG = "BaseServlet"; - private static final SmsHubActionHandler.SmsHubMode smsHubMode = SmsHubActionHandler.SmsHubMode.server; + public static final SmsHubActionHandler.SmsHubMode smsHubMode = SmsHubActionHandler.SmsHubMode.server; public BaseServlet(String path, Context context) { this.path = path; @@ -115,18 +118,6 @@ public class BaseServlet extends HttpServlet { } } - private void notFound(HttpServletRequest req, HttpServletResponse resp) throws IOException { - PrintWriter writer = resp.getWriter(); - try { - String text = "NOT FOUND"; - resp.setStatus(HttpServletResponse.SC_NOT_FOUND); - writer.println(text); - } catch (Exception e) { - e.printStackTrace(); - } finally { - IOUtils.close(writer); - } - } private void send_api(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setCharacterEncoding("utf-8"); @@ -135,28 +126,31 @@ public class BaseServlet extends HttpServlet { try { String read = read(reader); Log.i(TAG, "Request message:" + read); - List smsHubVos = JSON.parseArray(read, SmsHubVo.class); - if (smsHubVos.size() == 1 && SmsHubVo.Action.heartbeat.code().equals(smsHubVos.get(0).getAction())) { - smsHubVos.clear(); - SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance(); - smsHubVos.add(smsHubVo); - List data = SmsHubActionHandler.getData(smsHubMode); - if (data != null && data.size() > 0) { - smsHubVo.setChildren(data); - } - } else { - for (SmsHubVo vo : smsHubVos) { + SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance(SmsHubActionHandler.getData(smsHubMode)); + ResVo> result = ResVo.suessces(null); + if (StringUtil.isNotBlank(read)) { + ResVo> obj = JSON.parseObject(read, new TypeReference>>() { + }.getType()); + List data = obj.getData(); + for (SmsHubVo vo : data) { SmsHubActionHandler.handle(TAG, vo); } - List data = SmsHubActionHandler.getData(smsHubMode); - if (data != null && data.size() > 0) { - SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance(); - smsHubVo.setChildren(data); - smsHubVos.add(smsHubVo); - } + result.setData(data); } + result.setHeartbeat(smsHubVo); resp.setContentType("application/json;charset=utf-8"); - String text = JSON.toJSONString(smsHubVos); + StringBuilder sb = new StringBuilder(); + int i = 0; + for (SmsHubVo datum : result.getData()) { + if (SmsHubVo.Action.failure.code().equals(datum.getAction())) { + sb.append(",").append("第").append(i++).append("条处理失败:").append(datum.getErrMsg()); + } + i++; + } + if (sb.length() > 0) { + result.setError(sb.substring(1)); + } + String text = JSON.toJSONString(result); writer.println(text); } catch (Exception e) { e.printStackTrace(); @@ -170,8 +164,9 @@ public class BaseServlet extends HttpServlet { private void printErrMsg(HttpServletResponse resp, PrintWriter writer, Exception e) { String text = "Internal server error: " + e.getMessage(); Log.e(TAG, text); - resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - writer.println(text); + resp.setStatus(HttpServletResponse.SC_OK); + resp.setContentType("application/json;charset=utf-8"); + writer.println(JSON.toJSONString(ResVo.error(text))); } //一键克隆——查询接口 diff --git a/app/src/main/java/com/idormy/sms/forwarder/sender/SmsHubApiTask.java b/app/src/main/java/com/idormy/sms/forwarder/sender/SmsHubApiTask.java index 1111a8db..f7472dfa 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/sender/SmsHubApiTask.java +++ b/app/src/main/java/com/idormy/sms/forwarder/sender/SmsHubApiTask.java @@ -6,29 +6,26 @@ import android.util.Log; import com.alibaba.fastjson.JSON; import com.idormy.sms.forwarder.model.vo.SmsHubVo; -import com.idormy.sms.forwarder.utils.HttpUtil; -import com.idormy.sms.forwarder.utils.SettingUtil; -import com.idormy.sms.forwarder.utils.SmsHubActionHandler; +import com.idormy.sms.forwarder.utils.*; + +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; -import java.util.List; -import java.util.Objects; -import java.util.Timer; -import java.util.TimerTask; /** * 主动发送短信轮询任务 - * * @author xxc * 2022/1/10 9:53 */ public class SmsHubApiTask extends TimerTask { + private static Boolean hasInit = false; public static final long DELAY_SECONDS = 30; private static final String TAG = "SmsHubApiTask"; - private static final SmsHubActionHandler.SmsHubMode smsHubMode = SmsHubActionHandler.SmsHubMode.client; - private static Boolean hasInit = false; private static Timer sendApiTimer; @SuppressLint("StaticFieldLeak") private static Context context; + private static final SmsHubActionHandler.SmsHubMode smsHubMode = SmsHubActionHandler.SmsHubMode.client; + @SuppressLint("HandlerLeak") public static void init(Context context) { @@ -42,6 +39,35 @@ public class SmsHubApiTask extends TimerTask { } } + @Override + public void run() { + List data = SmsHubActionHandler.getData(smsHubMode); + SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance(data); + String url = SettingUtil.getSmsHubApiUrl(); + boolean asRetry = data != null && data.size() > 0; + AtomicBoolean isSusess = new AtomicBoolean(false); + Runnable runnable = () -> { + HttpUtil.asyncPostJson(TAG, url, smsHubVo, response -> { + //HttpUtil.Toast(TAG, "Response:" + response.code() + "," + responseStr); + if (response.code() == 200) { + isSusess.set(true); + String responseStr = Objects.requireNonNull(response.body()).string(); + List vos = JSON.parseArray(responseStr, SmsHubVo.class); + for (SmsHubVo vo : vos) { + SmsHubActionHandler.handle(TAG, vo); + } + SmsHubActionHandler.putData(smsHubMode, vos.toArray(new SmsHubVo[0])); + } + }, null, asRetry); + }; + if (asRetry) { + new Thread(runnable).start(); + } else { + runnable.run(); + } + } + + public static void updateTimer() { cancelTimer(); if (SettingUtil.getSwitchEnableSmsHubApi()) { @@ -69,32 +95,4 @@ public class SmsHubApiTask extends TimerTask { sendApiTimer.schedule(new SmsHubApiTask(), 3000, seconds * 1000); } } - - @Override - public void run() { - try { - SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance(); - List data = SmsHubActionHandler.getData(smsHubMode); - if (data != null && data.size() > 0) { - smsHubVo.setChildren(data); - } - smsHubVo.setChildren(data); - String url = SettingUtil.getSmsHubApiUrl(); - HttpUtil.asyncPostJson(TAG, url, smsHubVo, response -> { - //HttpUtil.Toast(TAG, "Response:" + response.code() + "," + responseStr); - if (response.code() == 200) { - String responseStr = Objects.requireNonNull(response.body()).string(); - List vos = JSON.parseArray(responseStr, SmsHubVo.class); - for (SmsHubVo vo : vos) { - SmsHubActionHandler.handle(TAG, vo); - } - SmsHubActionHandler.putData(smsHubMode, vos.toArray(new SmsHubVo[0])); - } - }, null); - } catch (Exception e) { - HttpUtil.Toast(TAG, "SmsHubApiTask 执行出错,请检查问题后重新开启" + e.getMessage()); - cancelTimer(); - SettingUtil.switchEnableSmsHubApi(false); - } - } } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/HttpUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/HttpUtil.java index a417aead..4a73ce04 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/HttpUtil.java +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/HttpUtil.java @@ -9,11 +9,13 @@ import androidx.annotation.NonNull; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import com.hjq.toast.ToastUtils; +import com.idormy.sms.forwarder.sender.RetryIntercepter; import java.io.IOException; import java.net.URLEncoder; import java.util.Map; import java.util.Objects; +import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.Callback; @@ -25,7 +27,8 @@ import okhttp3.Response; @SuppressWarnings("unchecked") public class HttpUtil { - private static final OkHttpClient client = new OkHttpClient(); + private static OkHttpClient client; + private static OkHttpClient retryClient; private static final String TAG = "HttpUtil"; private static Boolean hasInit = false; @SuppressLint("StaticFieldLeak") @@ -40,30 +43,43 @@ public class HttpUtil { hasInit = true; HttpUtil.context = context; + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + //设置读取超时时间 + clientBuilder + .readTimeout(Define.REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .writeTimeout(Define.REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .connectTimeout(Define.REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS); + client = clientBuilder.build(); + //设置重试拦截器 + int retryTimes = SettingUtil.getRetryTimes(); + int delayTime = SettingUtil.getDelayTime(); + if (retryTimes > 0) + clientBuilder.addInterceptor(new RetryIntercepter.Builder().executionCount(retryTimes).retryInterval(delayTime).build()); + retryClient = clientBuilder.build(); } } - public static void asyncGet(String tag, String url, Object param, Lamda.Consumer onResponse, Lamda.Consumer onFailure) { + public static void asyncGet(String tag, String url, Object param, Lamda.Consumer onResponse, Lamda.Consumer onFailure, boolean doRetry) { StringBuilder resUrl = appendQueryStr(tag, url, param); Request request = new Request.Builder().url(resUrl.toString()).get().build(); Lamda.Func func = call -> { call.enqueue(new Callback0(tag, onResponse, onFailure)); return null; }; - callAndCatch(tag, request, func); + callAndCatch(tag, request, func, doRetry); } - public static void asyncPostJson(String tag, String url, Object param, Lamda.Consumer onResponse, Lamda.Consumer onFailure) { + public static void asyncPostJson(String tag, String url, Object param, Lamda.Consumer onResponse, Lamda.Consumer onFailure, boolean doRetry) { String jsonString = JSON.toJSONString(param); Request request = new Request.Builder().url(url).post(RequestBody.create(jsonString, MEDIA_TYPE_JSON)).build(); Lamda.Func func = call -> { call.enqueue(new Callback0(tag, onResponse, onFailure)); return null; }; - callAndCatch(tag, request, func); + callAndCatch(tag, request, func, doRetry); } - public static String postJson(String tag, String url, Object param) { + public static String postJson(String tag, String url, Object param, boolean doRetry) { String jsonString = JSON.toJSONString(param); Request request = new Request.Builder().url(url).post(RequestBody.create(jsonString, MEDIA_TYPE_JSON)).build(); Lamda.Func func = call -> { @@ -73,10 +89,10 @@ public class HttpUtil { } return null; }; - return callAndCatch(tag, request, func); + return callAndCatch(tag, request, func, doRetry); } - public static String get(String tag, String url, Object param) { + public static String get(String tag, String url, Object param, boolean doRetry) { StringBuilder resUrl = appendQueryStr(tag, url, param); Request request = new Request.Builder().url(resUrl.toString()).get().build(); Lamda.Func func = call -> { @@ -86,7 +102,7 @@ public class HttpUtil { } return null; }; - return callAndCatch(tag, request, func); + return callAndCatch(tag, request, func, doRetry); } public static void Toast(String Tag, String data) { @@ -119,9 +135,9 @@ public class HttpUtil { return resUrl; } - public static String callAndCatch(String tag, Request request, Lamda.Func func) { + public static String callAndCatch(String tag, Request request, Lamda.Func func, boolean doRetry) { try { - Call call = client.newCall(request); + Call call = (doRetry ? retryClient : client).newCall(request); return func.execute(call); } catch (Exception e) { Toast(tag, "请求失败:" + e.getMessage()); @@ -158,7 +174,7 @@ public class HttpUtil { @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { - Log.d(tag, "onResponse:" + response.code() + ":" + Objects.requireNonNull(response.body()).toString()); + Log.d(tag, "onResponse:" + response.code() + ":" + JSON.toJSONString(Objects.requireNonNull(response.body()))); if (onResponse != null) onResponse.executeThrowRunTimeExcp(response); } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SmsHubActionHandler.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SmsHubActionHandler.java index 4a59658a..8269c69a 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/SmsHubActionHandler.java +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SmsHubActionHandler.java @@ -4,8 +4,10 @@ import android.annotation.SuppressLint; import android.content.Context; import android.util.Log; +import com.alibaba.fastjson.JSON; import com.idormy.sms.forwarder.model.LogModel; import com.idormy.sms.forwarder.model.vo.SmsHubVo; +import com.idormy.sms.forwarder.sender.SmsHubApiTask; import java.util.ArrayList; import java.util.Arrays; @@ -56,8 +58,17 @@ public class SmsHubActionHandler { } } + private static long falg = System.currentTimeMillis(); + public static synchronized void putData(SmsHubMode smsHubMode, SmsHubVo... smsHubVos) { if (isEnable(smsHubMode)) { + if (smsHubMode == SmsHubMode.server) { + long l = falg; + falg = System.currentTimeMillis(); + if (System.currentTimeMillis() - l > SmsHubApiTask.DELAY_SECONDS * 3) { + return; + } + } Objects.requireNonNull(cache.get(smsHubMode)).addAll(Arrays.asList(smsHubVos)); } } @@ -79,11 +90,12 @@ public class SmsHubActionHandler { } public static void handle(String tag, SmsHubVo vo) { + Log.i(tag, JSON.toJSONString(vo)); String action = vo.getAction(); if (SmsHubVo.Action.send.code().equals(action)) { send(tag, vo); } else { - String errMsg = "暂不支持的action:" + action; + String errMsg = "暂不支持的action[" + action + "]"; vo.setErrMsg(errMsg); vo.setAction(SmsHubVo.Action.failure.code()); } @@ -97,11 +109,12 @@ public class SmsHubActionHandler { try { if (SmsHubVo.Action.send.code().equals(vo.getAction())) { vo.setType(SmsHubVo.Type.sms.code()); - logId = LogUtil.addLog(new LogModel(vo.getType(), vo.getTarget(), vo.getContent(), "SIM" + vo.getChannel(), RULE_ID)); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { - int simId = Integer.parseInt(vo.getChannel()); - vo.setChannel("SIM" + simId); - msg = SmsUtil.sendSms(SimUtil.getSubscriptionIdBySimId(simId), vo.getTarget(), vo.getContent()); + int subscriptionIdBySimId = SimUtil.getSubscriptionIdBySimId(Integer.parseInt(vo.getChannel()) - 1); + msg = SmsUtil.sendSms(subscriptionIdBySimId, vo.getTarget(), vo.getContent()); + String simInfo = "SIM" + (subscriptionIdBySimId + 1); + vo.setChannel(simInfo); + logId = LogUtil.addLog(new LogModel(vo.getType(), vo.getTarget(), vo.getContent(), simInfo, RULE_ID)); if (msg == null) { failure = false; HttpUtil.Toast(tag, "短信发送成功");