Skip to content

Commit

Permalink
Merge pull request #107 from gitxiaofeng/master
Browse files Browse the repository at this point in the history
undo缺陷修复
  • Loading branch information
gitxiaofeng authored Jul 28, 2021
2 parents 6f0e429 + 3b9f5ab commit fdb0fe6
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 27 deletions.
153 changes: 135 additions & 18 deletions case-server/src/main/java/com/xiaoju/framework/handler/Room.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
package com.xiaoju.framework.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.flipkart.zjsonpatch.JsonDiff;
import com.flipkart.zjsonpatch.JsonPatch;
import com.xiaoju.framework.entity.persistent.TestCase;
import com.xiaoju.framework.mapper.TestCaseMapper;
import com.xiaoju.framework.service.CaseBackupService;
import com.xiaoju.framework.service.RecordService;
import com.xiaoju.framework.util.BitBaseUtil;
import com.xiaoju.framework.util.TreeUtil;
import org.apache.poi.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.websocket.Session;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import static com.flipkart.zjsonpatch.DiffFlags.ADD_ORIGINAL_VALUE_ON_REPLACE;
import static com.flipkart.zjsonpatch.DiffFlags.OMIT_MOVE_OPERATION;

/**
* Created by didi on 2021/3/22.
*/
Expand All @@ -40,12 +44,21 @@ public abstract class Room {

private static final int MAX_PLAYER_COUNT = 100;
public final List<Player> players = new ArrayList<>();

public final List<String> undoDiffs = new LinkedList<>();
public final List<String> redoDiffs = new LinkedList<>();
private Integer undoPosition;
private Integer redoPosition;

public final Map<Session, Client> cs = new ConcurrentHashMap<>();

public static TestCaseMapper caseMapper;
public static RecordService recordService;
public static CaseBackupService caseBackupService;

ObjectMapper jsonMapper = new ObjectMapper();
JsonNodeFactory FACTORY = JsonNodeFactory.instance;

protected String testCaseContent;
protected TestCase testCase;

Expand Down Expand Up @@ -77,6 +90,8 @@ public Room(Long id) {
if (StringUtils.isEmpty(res)) {
LOGGER.error(Thread.currentThread().getName() + ": 用例内容为空");
}
undoPosition = undoDiffs.size();
redoPosition = redoDiffs.size();
}

private TimerTask createBroadcastTimerTask() {
Expand Down Expand Up @@ -159,8 +174,44 @@ private void internalHandleMessage(Player p, String msg,
p.setLastReceivedMessageId(msgId);

//todo: testCase.apply(msg) 新增如上的方法.
if (msg.endsWith("undo")) {
undo();
} else if (msg.endsWith("redo")) {
redo();
} else {
broadcastMessage(msg);
}
}

broadcastMessage(msg);
private void undo() {
roomLock.lock();
undoPosition --;
redoPosition --;
broadcastRoomMessage(CaseMessageType.EDITOR, undoDiffs.get(undoPosition));
try {
JsonNode target = JsonPatch.apply(jsonMapper.readTree(undoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent));
testCaseContent = target.toString();
} catch (Exception e) {
roomLock.unlock();
LOGGER.error("undo json parse error。", e);
}
roomLock.unlock();
}

private void redo() {
roomLock.lock();
broadcastRoomMessage(CaseMessageType.EDITOR, redoDiffs.get(redoPosition));
try {
JsonNode target = JsonPatch.apply(jsonMapper.readTree(redoDiffs.get(undoPosition)), jsonMapper.readTree(testCaseContent));
testCaseContent = target.toString();
} catch (Exception e) {
roomLock.unlock();
LOGGER.error("redo json parse error。", e);
}

undoPosition ++;
redoPosition ++;
roomLock.unlock();
}

private void internalHandleCtrlMessage(String msg) {
Expand Down Expand Up @@ -190,22 +241,55 @@ private void broadcastMessage(String msg) {
} else {
int seperateIndex = msg.indexOf('|');
String sendSessionId = msg.substring(0, seperateIndex);
JSONObject request = JSON.parseObject(msg.substring(seperateIndex + 1));
JSONArray patch = (JSONArray) request.get("patch");
long currentVersion = ((JSONObject) request.get("case")).getLong("base");
testCaseContent = ((JSONObject) request.get("case")).toJSONString().replace("\"base\":" + currentVersion, "\"base\":" + (currentVersion + 1));
for (Player p : players) {
if (sendSessionId.equals(p.getClient().getSession().getId())) { //ack消息
String msgAck = "[[{\"op\":\"replace\",\"path\":\"/base\",\"value\":" + (currentVersion + 1) + "}]]";
p.getBufferedMessages().add(msgAck);
} else { // notify消息
String msgNotify = patch.toJSONString().replace("[[{", "[[{\"op\":\"replace\",\"path\":\"/base\",\"value\":" + (currentVersion + 1) + "},{");
p.getBufferedMessages().add(msgNotify);
try {
JsonNode request = jsonMapper.readTree(msg.substring(seperateIndex + 1));
ArrayNode patch = (ArrayNode) request.get("patch");
long currentVersion = ((JsonNode) request.get("case")).get("base").asLong();
String tmpTestCaseContent = ((JsonNode) request.get("case")).toString().replace("\"base\":" + currentVersion, "\"base\":" + (currentVersion + 1));;
ArrayNode patchReverse = (ArrayNode) JsonDiff.asJson(jsonMapper.readTree(tmpTestCaseContent),
jsonMapper.readTree(testCaseContent==null?testCase.getCaseContent():testCaseContent), EnumSet.of(ADD_ORIGINAL_VALUE_ON_REPLACE, OMIT_MOVE_OPERATION));

testCaseContent = tmpTestCaseContent;
ArrayNode patchNew = patchTraverse(patch);

ObjectNode basePatch = FACTORY.objectNode();
basePatch.put("op", "replace");
basePatch.put("path", "/base");
basePatch.put("value", currentVersion + 1);
patchNew.add(basePatch);
// String msgNotify = patch.toString().replace("[[{", "[[{\"op\":\"replace\",\"path\":\"/base\",\"value\":" + (currentVersion + 1) + "},{");
redoDiffs.add(redoPosition++, patchNew.toString());
undoDiffs.add(undoPosition++, patchReverse.toString());

for (Player p : players) {
if (sendSessionId.equals(p.getClient().getSession().getId())) { //ack消息
String msgAck = "[[{\"op\":\"replace\",\"path\":\"/base\",\"value\":" + (currentVersion + 1) + "}]]";
p.getBufferedMessages().add(msgAck);
p.undoCount ++;
} else { // notify消息
// String msgNotify = patch.toString().replace("[[{", "[[{\"op\":\"replace\",\"path\":\"/base\",\"value\":" + (currentVersion + 1) + "},{");
p.getBufferedMessages().add(patchNew.toString());
p.undoCount ++;
}
}
} catch (Exception e) {
LOGGER.error("json 操作失败。", e);
}
}
}

private ArrayNode patchTraverse(ArrayNode patch) {
ArrayNode patchesNew = FACTORY.arrayNode();
try {
for (int i = 0; i < patch.size(); i++) {
patchesNew.addAll((ArrayNode) patch.get(i));
}
} catch (Exception e) {
LOGGER.error("转换客户端发送patch失败。", e);
}
return patchesNew;
}

private void broadcastTimerTick() {
// 给每一个player广播消息
for (Player p : players) {
Expand Down Expand Up @@ -296,6 +380,11 @@ public static final class Player {

private Integer pingCount;

// private Integer undoPosition;
// private Integer redoPosition;
private Integer undoCount;
private Integer redoCount;

// private final boolean isRecord;

/**
Expand All @@ -320,9 +409,37 @@ private Player(Room room, Client client) {
this.client = client;
this.enterTimeStamp = System.currentTimeMillis();
this.pingCount = 0;
// this.undoPosition = room.undoDiffs.size();
// this.redoPosition = room.redoDiffs.size();
this.undoCount = 0;
this.redoCount = 0;
// isRecord = client.getRecordId();
}

public Boolean undo() {
if (this.undoCount <= 0) {
LOGGER.warn("当前用户未编辑过,无法进行undo。用户是:" + this.client.getClientName());
return false;
}
this.undoCount --;
// this.undoPosition --;
this.redoCount ++;
// this.redoPosition --;
return true;
}

public Boolean redo() {
if (this.redoCount <= 0) {
LOGGER.warn("当前用户未undo过,无法进行redo。用户是:" + this.client.getClientName());
return false;
}
this.undoCount ++;
// this.undoPosition ++;
this.redoCount --;
// this.redoPosition ++;
return true;
}

public Room getRoom() {
return room;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;

import static com.flipkart.zjsonpatch.DiffFlags.ADD_EXPLICIT_REMOVE_ADD_ON_REPLACE;
import static com.flipkart.zjsonpatch.DiffFlags.ADD_ORIGINAL_VALUE_ON_REPLACE;

/**
Expand Down
2 changes: 1 addition & 1 deletion case-server/src/main/resources/web/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
</head>
<body>
<div id="root"></div>
<script th:src="@{/umi.2415d0c2.js}"></script>
<script th:src="@{/umi.c3201dac.js}"></script>
</body>
</html>

Large diffs are not rendered by default.

Loading

0 comments on commit fdb0fe6

Please sign in to comment.