diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/javascript/GenerateJsUtils.java b/protocol/src/main/java/com/zfoo/protocol/serializer/javascript/GenerateJsUtils.java index 7b90dbaf..c55e0911 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/javascript/GenerateJsUtils.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/javascript/GenerateJsUtils.java @@ -152,11 +152,20 @@ public abstract class GenerateJsUtils { var fields = registration.getFields(); var fieldRegistrations = registration.getFieldRegistrations(); var jsBuilder = new StringBuilder(); + if (registration.isCompatible()) { + jsBuilder.append("const beforeWriteIndex = buffer.getWriteOffset();").append(LS); + jsBuilder.append(TAB).append(StringUtils.format("buffer.writeInt({});", registration.getPredictionLength())).append(LS); + } else { + jsBuilder.append(TAB).append("buffer.writeInt(-1);").append(LS); + } for (var i = 0; i < fields.length; i++) { var field = fields[i]; var fieldRegistration = fieldRegistrations[i]; jsSerializer(fieldRegistration.serializer()).writeObject(jsBuilder, "packet." + field.getName(), 1, field, fieldRegistration); } + if (registration.isCompatible()) { + jsBuilder.append(TAB).append(StringUtils.format("buffer.adjustPadding({}, beforeWriteIndex);", registration.getPredictionLength())).append(LS); + } return jsBuilder.toString(); } @@ -168,9 +177,11 @@ public abstract class GenerateJsUtils { var field = fields[i]; var fieldRegistration = fieldRegistrations[i]; if (field.isAnnotationPresent(Compatible.class)) { - jsBuilder.append(TAB).append("if (!buffer.isReadable()) {").append(LS); - jsBuilder.append(TAB + TAB).append("return packet;").append(LS); + jsBuilder.append(TAB).append("if (buffer.compatibleRead(beforeReadIndex, length)) {").append(LS); + var compatibleReadObject = jsSerializer(fieldRegistration.serializer()).readObject(jsBuilder, 2, field, fieldRegistration); + jsBuilder.append(TAB+ TAB).append(StringUtils.format("packet.{} = {};", field.getName(), compatibleReadObject)).append(LS); jsBuilder.append(TAB).append("}").append(LS); + continue; } var readObject = jsSerializer(fieldRegistration.serializer()).readObject(jsBuilder, 1, field, fieldRegistration); jsBuilder.append(TAB).append(StringUtils.format("packet.{} = {};", field.getName(), readObject)).append(LS); diff --git a/protocol/src/main/resources/javascript/ProtocolTemplate.js b/protocol/src/main/resources/javascript/ProtocolTemplate.js index 6791801d..9f62e2d6 100644 --- a/protocol/src/main/resources/javascript/ProtocolTemplate.js +++ b/protocol/src/main/resources/javascript/ProtocolTemplate.js @@ -8,18 +8,24 @@ const {} = function({}) { }; {}.write = function(buffer, packet) { - if (buffer.writePacketFlag(packet)) { + if (packet === null) { + buffer.writeInt(0); return; } {} }; {}.read = function(buffer) { - if (!buffer.readBoolean()) { + const length = buffer.readInt(); + if (length === 0) { return null; } + const beforeReadIndex = buffer.getReadOffset(); const packet = new {}(); {} + if (length > 0) { + buffer.setReadOffset(beforeReadIndex + length); + } return packet; }; diff --git a/protocol/src/main/resources/javascript/buffer/ByteBuffer.js b/protocol/src/main/resources/javascript/buffer/ByteBuffer.js index 2fcc66f4..e0202e95 100644 --- a/protocol/src/main/resources/javascript/buffer/ByteBuffer.js +++ b/protocol/src/main/resources/javascript/buffer/ByteBuffer.js @@ -49,6 +49,32 @@ const ByteBuffer = function() { this.buffer = new ArrayBuffer(initSize); this.bufferView = new DataView(this.buffer, 0, this.buffer.byteLength); + this.adjustPadding = function(predictionLength, beforeWriteIndex) { + const currentWriteIndex = this.writeOffset; + const predictionCount = this.writeIntCount(predictionLength); + const length = currentWriteIndex - beforeWriteIndex - predictionCount; + const lengthCount = this.writeIntCount(length); + const padding = lengthCount - predictionCount; + if (padding === 0) { + this.setWriteOffset(beforeWriteIndex); + this.writeInt(length); + this.setWriteOffset(currentWriteIndex); + } else { + const retainedByteBuf = this.buffer.slice(currentWriteIndex - length, currentWriteIndex); + this.setWriteOffset(beforeWriteIndex); + this.writeInt(length); + this.writeBytes(retainedByteBuf); + } + } + + this.compatibleRead = function(beforeReadIndex, length) { + return length !== -1 && this.getReadOffset() < length + beforeReadIndex; + } + + this.getWriteOffset = function() { + return this.writeOffset; + } + this.setWriteOffset = function(writeOffset) { if (writeOffset > this.buffer.byteLength) { throw new Error('index out of bounds exception: readerIndex: ' + this.readOffset + @@ -58,6 +84,10 @@ const ByteBuffer = function() { this.writeOffset = writeOffset; }; + this.getReadOffset = function() { + return this.readOffset; + } + this.setReadOffset = function(readOffset) { if (readOffset > this.writeOffset) { throw new Error('index out of bounds exception: readerIndex: ' + this.readOffset + @@ -201,6 +231,25 @@ const ByteBuffer = function() { this.writeByte(value >>> 28); }; + this.writeIntCount = function(value) { + if (!(minInt <= value && value <= maxInt)) { + throw new Error('value must range between minInt:-2147483648 and maxInt:2147483647'); + } + if (value >>> 7 === 0) { + return 1; + } + if (value >>> 14 === 0) { + return 2; + } + if (value >>> 21 === 0) { + return 3; + } + if (value >>> 28 === 0) { + return 4; + } + return 5; + } + this.readInt = function() { let b = this.readByte(); let value = b & 0x7F;