forked from Qortal/qortal
catbref
3 years ago
6 changed files with 512 additions and 39 deletions
@ -0,0 +1,86 @@
|
||||
package org.qortal.data.network; |
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType; |
||||
import javax.xml.bind.annotation.XmlAccessorType; |
||||
import java.util.Arrays; |
||||
|
||||
// All properties to be converted to JSON via JAXB
|
||||
@XmlAccessorType(XmlAccessType.FIELD) |
||||
public class OnlineTradeData { |
||||
|
||||
protected long timestamp; |
||||
protected byte[] publicKey; // Could be BOB's or ALICE's
|
||||
protected byte[] signature; // Not always present
|
||||
protected String atAddress; // Not always present
|
||||
|
||||
// Constructors
|
||||
|
||||
// necessary for JAXB serialization
|
||||
protected OnlineTradeData() { |
||||
} |
||||
|
||||
public OnlineTradeData(long timestamp, byte[] publicKey, byte[] signature, String address) { |
||||
this.timestamp = timestamp; |
||||
this.publicKey = publicKey; |
||||
this.signature = signature; |
||||
this.atAddress = address; |
||||
} |
||||
|
||||
public OnlineTradeData(long timestamp, byte[] publicKey) { |
||||
this(timestamp, publicKey, null, null); |
||||
} |
||||
|
||||
public long getTimestamp() { |
||||
return this.timestamp; |
||||
} |
||||
|
||||
public byte[] getPublicKey() { |
||||
return this.publicKey; |
||||
} |
||||
|
||||
public byte[] getSignature() { |
||||
return this.signature; |
||||
} |
||||
|
||||
public String getAtAddress() { |
||||
return this.atAddress; |
||||
} |
||||
|
||||
// Comparison
|
||||
|
||||
@Override |
||||
public boolean equals(Object other) { |
||||
if (other == this) |
||||
return true; |
||||
|
||||
if (!(other instanceof OnlineTradeData)) |
||||
return false; |
||||
|
||||
OnlineTradeData otherOnlineTradeData = (OnlineTradeData) other; |
||||
|
||||
// Very quick comparison
|
||||
if (otherOnlineTradeData.timestamp != this.timestamp) |
||||
return false; |
||||
|
||||
if (!Arrays.equals(otherOnlineTradeData.publicKey, this.publicKey)) |
||||
return false; |
||||
|
||||
if (otherOnlineTradeData.atAddress != null && !otherOnlineTradeData.atAddress.equals(this.atAddress)) |
||||
return false; |
||||
|
||||
if (this.atAddress != null && !this.atAddress.equals(otherOnlineTradeData.atAddress)) |
||||
return false; |
||||
|
||||
if (!Arrays.equals(otherOnlineTradeData.signature, this.signature)) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
// Pretty lazy implementation
|
||||
return (int) this.timestamp; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,110 @@
|
||||
package org.qortal.network.message; |
||||
|
||||
import com.google.common.primitives.Ints; |
||||
import com.google.common.primitives.Longs; |
||||
import org.qortal.data.network.OnlineTradeData; |
||||
import org.qortal.transform.Transformer; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.UnsupportedEncodingException; |
||||
import java.nio.ByteBuffer; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* For requesting which trades are online from remote peer, given our list of online trades. |
||||
* |
||||
* Groups of: number of entries, timestamp, then AT trade pubkey for each entry. |
||||
*/ |
||||
public class GetOnlineTradesMessage extends Message { |
||||
private List<OnlineTradeData> onlineTrades; |
||||
private byte[] cachedData; |
||||
|
||||
public GetOnlineTradesMessage(List<OnlineTradeData> onlineTrades) { |
||||
this(-1, onlineTrades); |
||||
} |
||||
|
||||
private GetOnlineTradesMessage(int id, List<OnlineTradeData> onlineTrades) { |
||||
super(id, MessageType.GET_ONLINE_TRADES); |
||||
|
||||
this.onlineTrades = onlineTrades; |
||||
} |
||||
|
||||
public List<OnlineTradeData> getOnlineTrades() { |
||||
return this.onlineTrades; |
||||
} |
||||
|
||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException { |
||||
int tradeCount = bytes.getInt(); |
||||
|
||||
List<OnlineTradeData> onlineTrades = new ArrayList<>(tradeCount); |
||||
|
||||
while (tradeCount > 0) { |
||||
long timestamp = bytes.getLong(); |
||||
|
||||
for (int i = 0; i < tradeCount; ++i) { |
||||
byte[] publicKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; |
||||
bytes.get(publicKey); |
||||
|
||||
onlineTrades.add(new OnlineTradeData(timestamp, publicKey)); |
||||
} |
||||
|
||||
if (bytes.hasRemaining()) { |
||||
tradeCount = bytes.getInt(); |
||||
} else { |
||||
// we've finished
|
||||
tradeCount = 0; |
||||
} |
||||
} |
||||
|
||||
return new GetOnlineTradesMessage(id, onlineTrades); |
||||
} |
||||
|
||||
@Override |
||||
protected synchronized byte[] toData() { |
||||
if (this.cachedData != null) |
||||
return this.cachedData; |
||||
|
||||
// Shortcut in case we have no online accounts
|
||||
if (this.onlineTrades.isEmpty()) { |
||||
this.cachedData = Ints.toByteArray(0); |
||||
return this.cachedData; |
||||
} |
||||
|
||||
// How many of each timestamp
|
||||
Map<Long, Integer> countByTimestamp = new HashMap<>(); |
||||
|
||||
for (OnlineTradeData onlineTradeData : this.onlineTrades) { |
||||
Long timestamp = onlineTradeData.getTimestamp(); |
||||
countByTimestamp.compute(timestamp, (k, v) -> v == null ? 1 : ++v); |
||||
} |
||||
|
||||
// We should know exactly how many bytes to allocate now
|
||||
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH) |
||||
+ this.onlineTrades.size() * Transformer.PUBLIC_KEY_LENGTH; |
||||
|
||||
try { |
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize); |
||||
|
||||
for (long timestamp : countByTimestamp.keySet()) { |
||||
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp))); |
||||
|
||||
bytes.write(Longs.toByteArray(timestamp)); |
||||
|
||||
for (OnlineTradeData onlineTradeData : this.onlineTrades) { |
||||
if (onlineTradeData.getTimestamp() == timestamp) |
||||
bytes.write(onlineTradeData.getPublicKey()); |
||||
} |
||||
} |
||||
|
||||
this.cachedData = bytes.toByteArray(); |
||||
return this.cachedData; |
||||
} catch (IOException e) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,123 @@
|
||||
package org.qortal.network.message; |
||||
|
||||
import com.google.common.primitives.Ints; |
||||
import com.google.common.primitives.Longs; |
||||
import org.qortal.data.network.OnlineTradeData; |
||||
import org.qortal.transform.Transformer; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.UnsupportedEncodingException; |
||||
import java.nio.ByteBuffer; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* For sending list of which trades are online to remote peer. |
||||
* |
||||
* Groups of: number of entries, timestamp, then pubkey + sig + AT address for each entry. |
||||
*/ |
||||
public class OnlineTradesMessage extends Message { |
||||
private List<OnlineTradeData> onlineTrades; |
||||
private byte[] cachedData; |
||||
|
||||
public OnlineTradesMessage(List<OnlineTradeData> onlineTrades) { |
||||
this(-1, onlineTrades); |
||||
} |
||||
|
||||
private OnlineTradesMessage(int id, List<OnlineTradeData> onlineTrades) { |
||||
super(id, MessageType.ONLINE_TRADES); |
||||
|
||||
this.onlineTrades = onlineTrades; |
||||
} |
||||
|
||||
public List<OnlineTradeData> getOnlineTrades() { |
||||
return this.onlineTrades; |
||||
} |
||||
|
||||
public static Message fromByteBuffer(int id, ByteBuffer bytes) throws UnsupportedEncodingException { |
||||
int tradeCount = bytes.getInt(); |
||||
|
||||
List<OnlineTradeData> onlineTrades = new ArrayList<>(tradeCount); |
||||
|
||||
while (tradeCount > 0) { |
||||
long timestamp = bytes.getLong(); |
||||
|
||||
for (int i = 0; i < tradeCount; ++i) { |
||||
byte[] publicKey = new byte[Transformer.PUBLIC_KEY_LENGTH]; |
||||
bytes.get(publicKey); |
||||
|
||||
byte[] signature = new byte[Transformer.SIGNATURE_LENGTH]; |
||||
bytes.get(signature); |
||||
|
||||
byte[] addressBytes = new byte[Transformer.ADDRESS_LENGTH]; |
||||
bytes.get(addressBytes); |
||||
String address = new String(addressBytes, StandardCharsets.UTF_8); |
||||
|
||||
onlineTrades.add(new OnlineTradeData(timestamp, publicKey, signature, address)); |
||||
} |
||||
|
||||
if (bytes.hasRemaining()) { |
||||
tradeCount = bytes.getInt(); |
||||
} else { |
||||
// we've finished
|
||||
tradeCount = 0; |
||||
} |
||||
} |
||||
|
||||
return new OnlineTradesMessage(id, onlineTrades); |
||||
} |
||||
|
||||
@Override |
||||
protected synchronized byte[] toData() { |
||||
if (this.cachedData != null) |
||||
return this.cachedData; |
||||
|
||||
// Shortcut in case we have no online trade entries
|
||||
if (this.onlineTrades.isEmpty()) { |
||||
this.cachedData = Ints.toByteArray(0); |
||||
return this.cachedData; |
||||
} |
||||
|
||||
// How many of each timestamp
|
||||
Map<Long, Integer> countByTimestamp = new HashMap<>(); |
||||
|
||||
for (OnlineTradeData onlineTradeData : this.onlineTrades) { |
||||
Long timestamp = onlineTradeData.getTimestamp(); |
||||
countByTimestamp.compute(timestamp, (k, v) -> v == null ? 1 : ++v); |
||||
} |
||||
|
||||
// We should know exactly how many bytes to allocate now
|
||||
int byteSize = countByTimestamp.size() * (Transformer.INT_LENGTH + Transformer.TIMESTAMP_LENGTH) |
||||
+ this.onlineTrades.size() * (Transformer.PUBLIC_KEY_LENGTH + Transformer.SIGNATURE_LENGTH + Transformer.ADDRESS_LENGTH); |
||||
|
||||
try { |
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(byteSize); |
||||
|
||||
for (long timestamp : countByTimestamp.keySet()) { |
||||
bytes.write(Ints.toByteArray(countByTimestamp.get(timestamp))); |
||||
|
||||
bytes.write(Longs.toByteArray(timestamp)); |
||||
|
||||
for (OnlineTradeData onlineTradeData : this.onlineTrades) { |
||||
if (onlineTradeData.getTimestamp() == timestamp) { |
||||
bytes.write(onlineTradeData.getPublicKey()); |
||||
|
||||
bytes.write(onlineTradeData.getSignature()); |
||||
|
||||
bytes.write(onlineTradeData.getAtAddress().getBytes(StandardCharsets.UTF_8)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
this.cachedData = bytes.toByteArray(); |
||||
return this.cachedData; |
||||
} catch (IOException e) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue