package com.bgycc.smartcanteen.viewModel; import android.text.TextUtils; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModel; import com.bgycc.smartcanteen.command.CommandProgressCallback; import com.bgycc.smartcanteen.command.CommandHandler; import com.bgycc.smartcanteen.command.LogCommandHandler; import com.bgycc.smartcanteen.command.UpdateCommandHandler; import com.bgycc.smartcanteen.command.WifiConfigCommandHandler; import com.bgycc.smartcanteen.entity.Command; import com.bgycc.smartcanteen.entity.CommandResponse; import com.bgycc.smartcanteen.executor.SCTaskExecutor; import com.bgycc.smartcanteen.socket.SCWebSocketClient; import com.bgycc.smartcanteen.socket.SCWebSocketListener; import com.bgycc.smartcanteen.socket.SCWebSocketListenerAdapter; import com.bgycc.smartcanteen.state.CommandState; import com.bgycc.smartcanteen.repository.CommandRepository; import com.blankj.utilcode.util.LogUtils; import com.google.gson.Gson; import com.google.gson.JsonObject; import java.util.List; import static com.bgycc.smartcanteen.utils.SmartCanteenUtils.TAG; /** * 监听本地扫码、服务器下发的设置指令 <br/> * 设备指令需要匹配以下规则: <br/> * 1、action非"PAY_RESULT" <br/><br/> * 监听Command数据库的变动,按如下流程进行处理: <br/> * 从数据库读取 -> 解析执行 -> 更新到数据库 */ public class CommandViewModel extends ViewModel implements CommandProgressCallback { private CommandRepository commandRepository; private Gson gson; private String deviceSN; private MutableLiveData<CommandState> commandState = new MutableLiveData<>(); private LiveData<List<Command>> dataLiveData; public LiveData<CommandState> getCommandStateEvent() { return commandState; } public CommandViewModel(CommandRepository commandRepository, Gson gson, String deviceSN) { this.commandRepository = commandRepository; this.gson = gson; this.deviceSN = deviceSN; // 监听数据库的变动,并执行未完成的指令 this.dataLiveData = commandRepository.queryUndoneCommand(); this.dataLiveData.observeForever(dataObserver); this.commandState.postValue(new CommandState(CommandState.IDLE)); } public void initialize() { SCWebSocketClient.getInstance().addListener(listener); } @Override protected void onCleared() { super.onCleared(); if (dataLiveData != null) { dataLiveData.removeObserver(dataObserver); } } private Observer<List<Command>> dataObserver = commands -> { if (commands == null || commands.isEmpty()) { commandState.postValue(new CommandState(CommandState.IDLE)); return; } Command first = commands.get(0); RequestRunnable runnable = new RequestRunnable(first); SCTaskExecutor.getInstance().executeOnDiskIO(runnable); }; @Override public void progress(String message, int progress) { commandState.postValue(new CommandState(CommandState.WAIT, message, progress)); } private SCWebSocketListener listener = new SCWebSocketListenerAdapter() { private static final String RESPONSE_PAY_RESULT = "PAY_RESULT"; @Override public void onMessage(String action, JsonObject obj, String original) { // 设备指令需要匹配以下规则: // 1、action非"PAY_RESULT" if (TextUtils.isEmpty(action) || action.equals(RESPONSE_PAY_RESULT)) return; LogUtils.d(TAG, "设备下发指令: " + original); ResponseRunnable runnable = new ResponseRunnable(original, action); SCTaskExecutor.getInstance().executeOnDiskIO(runnable); } }; private class RequestRunnable implements Runnable { // 每条指令执行间隔 private static final long EXEC_INTERVAL = 1500; private Command command; RequestRunnable(Command command) { this.command = command; } @Override public void run() { CommandHandler handler = null; try { switch (command.getAction()) { case Command.LOG_UPLOAD: handler = new LogCommandHandler(command, gson, deviceSN,CommandViewModel.this); break; case Command.APP_UPDATE: handler = new UpdateCommandHandler(command, gson, CommandViewModel.this); break; case Command.CONFIG_WIFI: handler = new WifiConfigCommandHandler(command, gson, CommandViewModel.this); break; } } catch (Exception e) { commandState.postValue(new CommandState(CommandState.FAILED, e.getMessage())); handler = null; } if (handler == null) { LogUtils.w(TAG, "无法识别指令: " + command.toString()); commandFinishAndUpdateDB(); return; } try { commandState.postValue(new CommandState(CommandState.WAIT)); CommandResponse response = handler.run(); if (response.success()) { commandState.postValue(new CommandState(CommandState.SUCCESS, response.getMessage())); } else { commandState.postValue(new CommandState(CommandState.FAILED, response.getMessage())); } } catch (Exception e) { commandState.postValue(new CommandState(CommandState.FAILED, e.getMessage())); } finally { commandFinishAndUpdateDB(); } } // 将执行完毕的指令更新到数据库,此时会触发dataObserver的动作(会继续搜索下一条未执行完毕的指令) private void commandFinishAndUpdateDB() { try { Thread.sleep(EXEC_INTERVAL); } catch (InterruptedException e) { LogUtils.w(TAG, e.getMessage(), e); } finally { command.finish(); commandRepository.updateCommand(command); } } } private class ResponseRunnable implements Runnable { private String response; private String action; ResponseRunnable(String response, String action) { this.response = response; this.action = action; } @Override public void run() { // 指令插入到数据库,则会触发dataObserver Command command = new Command(response, action); long lastInsertId = commandRepository.insertCommand(command); if (lastInsertId == -1) { LogUtils.w(TAG, "指令插入到数据库失败: " + command.toString()); } } } }