Changes to LoadRequest

pull/86/head
Louis Royer 5 years ago
parent 230092ab2a
commit c5e8a7df39

@ -74,7 +74,7 @@ Payload contains
4 bytes: [(bytes 24-27): FILENAME SIZE] (cannot be > to PAYLOAD_SIZE - 20 or be zero) 4 bytes: [(bytes 24-27): FILENAME SIZE] (cannot be > to PAYLOAD_SIZE - 20 or be zero)
y bytes: [<FILENAME>] y bytes: [<FILENAME>]
2 bytes: port used to register on tracker 2 bytes: port used to register on tracker
? bytes: hostname used to register on tracker followed by \n ? bytes: hostname used to register on tracker
``` ```
Possible responses: Load Response, or Denied Possible responses: Load Response, or Denied

@ -57,6 +57,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable {
protected String dirStorage; protected String dirStorage;
protected boolean success = false; protected boolean success = false;
protected Logger logger; protected Logger logger;
protected HostItem client;
/** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage /** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage
* @param filename name of file to download * @param filename name of file to download
@ -64,13 +65,15 @@ public abstract class ClientDownload extends ServeErrors implements Runnable {
* @param partsSubdir directory to store .part files * @param partsSubdir directory to store .part files
* @param dirStorage directory to write assembled file * @param dirStorage directory to write assembled file
* @param logger Logger * @param logger Logger
* @param client HostItem of the application
*/ */
public ClientDownload(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage, Logger logger) { public ClientDownload(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) {
this.partsSubdir = partsSubdir; this.partsSubdir = partsSubdir;
this.dirStorage = dirStorage; this.dirStorage = dirStorage;
this.filename = filename; this.filename = filename;
this.hostList = hostList; this.hostList = hostList;
this.logger = logger; this.logger = logger;
this.client = client;
this.stop = false; this.stop = false;
} }
@ -125,16 +128,15 @@ public abstract class ClientDownload extends ServeErrors implements Runnable {
} }
/** Create a clientDownloadPart /** Create a clientDownloadPart
* @param filename name of the file to download
* @param hostItem Hostitem of the server * @param hostItem Hostitem of the server
*/ */
protected abstract ClientDownloadPart createDownloadPart(String filename, HostItem hostItem); protected abstract ClientDownloadPart createDownloadPart(HostItem hostItem);
/** Starts threads for each server in hostList. /** Starts threads for each server in hostList.
*/ */
protected void initThreads() { protected void initThreads() {
for(HostItem hostItem: hostList) { for(HostItem hostItem: hostList) {
sockList.add(createDownloadPart(filename, hostItem)); sockList.add(createDownloadPart(hostItem));
} }
for(ClientDownloadPart c: sockList) { for(ClientDownloadPart c: sockList) {
Thread t = new Thread(c); Thread t = new Thread(c);
@ -289,7 +291,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable {
* @throws InternalError * @throws InternalError
*/ */
protected void setSize() throws InternalError { protected void setSize() throws InternalError {
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE)); ProtocolP2PPacket<?> d = createProtocolP2PPacket(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE, client));
try { try {
d.sendRequest(getHostItemSocket(hostList.get(0))); d.sendRequest(getHostItemSocket(hostList.get(0)));
try { try {

@ -26,6 +26,7 @@ import exception.RemoteException;
import tools.Logger; import tools.Logger;
import tools.LogLevel; import tools.LogLevel;
import tools.ServeErrors; import tools.ServeErrors;
import tools.HostItem;
/** Class to download file parts. /** Class to download file parts.
* @author Louis Royer * @author Louis Royer
@ -46,18 +47,21 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable
protected static final long MAX_PARTIAL_SIZE = 4096; protected static final long MAX_PARTIAL_SIZE = 4096;
protected ClientDownload manager; protected ClientDownload manager;
protected Logger logger; protected Logger logger;
protected HostItem client;
/** Constructor with filename, socket, and part subdir /** Constructor with filename, socket, and part subdir
* @param filename name of file to download * @param filename name of file to download
* @param socket socket to use * @param socket socket to use
* @param partsSubdir directory to store .part files * @param partsSubdir directory to store .part files
* @param logger Logger * @param logger Logger
* @param client HostItem of the application
*/ */
public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger) { public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger, HostItem client) {
this.manager = manager; this.manager = manager;
this.partsSubdir = partsSubdir; this.partsSubdir = partsSubdir;
this.filename = filename; this.filename = filename;
this.logger = logger; this.logger = logger;
this.client = client;
stop = false; stop = false;
failed = false; failed = false;
pendingTasks = new ArrayList<>(); pendingTasks = new ArrayList<>();
@ -224,7 +228,7 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable
} }
// send request // send request
try { try {
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE)); ProtocolP2PPacket<?> d = createProtocolP2PPacket(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE, client));
d.sendRequest(getSocket()); d.sendRequest(getSocket());
return d; return d;
} catch (InternalError e) { } catch (InternalError e) {

@ -25,6 +25,7 @@ import remoteException.NotFound;
import remoteException.NotATracker; import remoteException.NotATracker;
import tools.Logger; import tools.Logger;
import tools.LogLevel; import tools.LogLevel;
import tools.HostItem;
import clientP2P.ClientDownloadPart; import clientP2P.ClientDownloadPart;
/** Class to download file parts on tcp. /** Class to download file parts on tcp.
@ -42,9 +43,10 @@ public class ClientDownloadPartTCP extends ClientDownloadPart {
* @param socket socket to use * @param socket socket to use
* @param partsSubdir directory to store .part files * @param partsSubdir directory to store .part files
* @param logger Logger * @param logger Logger
* @param client HostItem of the application
*/ */
public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger) { public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger, HostItem client) {
super(manager, filename, partsSubdir, logger); super(manager, filename, partsSubdir, logger, client);
this.socket = socket; this.socket = socket;
} }

@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import tools.Logger; import tools.Logger;
import tools.LogLevel; import tools.LogLevel;
import tools.HostItem;
import clientP2P.ClientDownloadPart; import clientP2P.ClientDownloadPart;
/** Class to download file parts on udp. /** Class to download file parts on udp.
@ -42,9 +43,10 @@ public class ClientDownloadPartUDP extends ClientDownloadPart {
* @param socket socket to use * @param socket socket to use
* @param partsSubdir directory to store .part files * @param partsSubdir directory to store .part files
* @param logger Logger * @param logger Logger
* @param client HostItem of the application
*/ */
public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger) { public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger, HostItem client) {
super(manager, filename, partsSubdir, logger); super(manager, filename, partsSubdir, logger, client);
this.socket = socket; this.socket = socket;
} }

@ -50,17 +50,17 @@ public class ClientDownloadTCP extends ClientDownload {
* @param partsSubdir directory to store .part files * @param partsSubdir directory to store .part files
* @param dirStorage directory to write assembled file * @param dirStorage directory to write assembled file
* @param logger Logger * @param logger Logger
* @param client HostItem of the application
*/ */
public ClientDownloadTCP(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage, Logger logger) { public ClientDownloadTCP(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) {
super(filename, hostList, partsSubdir, dirStorage, logger); super(filename, hostList, partsSubdir, dirStorage, logger, client);
} }
/** Create a clientDownloadPart /** Create a clientDownloadPart
* @param filename name of the file to download
* @param hostItem Hostitem of the server * @param hostItem Hostitem of the server
*/ */
protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) { protected ClientDownloadPart createDownloadPart(HostItem hostItem) {
return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger); return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger, client);
} }
/** Close HostItem socket /** Close HostItem socket

@ -50,17 +50,17 @@ public class ClientDownloadUDP extends ClientDownload {
* @param partsSubdir directory to store .part files * @param partsSubdir directory to store .part files
* @param dirStorage directory to write assembled file * @param dirStorage directory to write assembled file
* @param logger Logger * @param logger Logger
* @param client HostItem of the application
*/ */
public ClientDownloadUDP(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage, Logger logger) { public ClientDownloadUDP(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) {
super(filename, hostList, partsSubdir, dirStorage, logger); super(filename, hostList, partsSubdir, dirStorage, logger, client);
} }
/** Create a clientDownloadPart /** Create a clientDownloadPart
* @param filename name of the file to download
* @param hostItem Hostitem of the server * @param hostItem Hostitem of the server
*/ */
protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) { protected ClientDownloadPart createDownloadPart(HostItem hostItem) {
return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger); return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger, client);
} }
/** Implementation of writeLog /** Implementation of writeLog

@ -46,6 +46,7 @@ public abstract class ClientManagement extends ServeErrors implements Runnable {
protected String partsSubdir; protected String partsSubdir;
protected List<HostItem> hostList; protected List<HostItem> hostList;
protected HostItem tracker; protected HostItem tracker;
protected HostItem client;
protected Logger logger; protected Logger logger;
protected Scanner scanner; protected Scanner scanner;
protected ClientDownload downLoader; protected ClientDownload downLoader;
@ -56,13 +57,15 @@ public abstract class ClientManagement extends ServeErrors implements Runnable {
* @param partsSubdir subdirectory to store file parts * @param partsSubdir subdirectory to store file parts
* @param logger Loggger * @param logger Loggger
* @param scanner Scanner used to read input * @param scanner Scanner used to read input
* @param client HostItem of the application
*/ */
public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) {
this.scanner = scanner; this.scanner = scanner;
this.baseDirectory = baseDirectory; this.baseDirectory = baseDirectory;
this.tracker = tracker; this.tracker = tracker;
this.partsSubdir = partsSubdir; this.partsSubdir = partsSubdir;
this.logger = logger; this.logger = logger;
this.client = client;
try { try {
initHostList(); initHostList();
} catch (InternalError e) { } catch (InternalError e) {

@ -24,16 +24,17 @@ public class ClientManagementTCP extends ClientManagement {
* @param partsSubdir subdirectory to store file parts * @param partsSubdir subdirectory to store file parts
* @param logger Loggger * @param logger Loggger
* @param scanner Scanner used to read input * @param scanner Scanner used to read input
* @param client HostItem of the application
*/ */
public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) {
super(baseDirectory, tracker, partsSubdir, logger, scanner); super(baseDirectory, tracker, partsSubdir, logger, scanner, client);
} }
/** Initialize downloader /** Initialize downloader
* @param filename Name of the file to download * @param filename Name of the file to download
*/ */
protected void initDownloader(String filename) { protected void initDownloader(String filename) {
downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger); downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger, client);
} }

@ -23,16 +23,17 @@ public class ClientManagementUDP extends ClientManagement {
* @param partsSubdir subdirectory to store file parts * @param partsSubdir subdirectory to store file parts
* @param logger Loggger * @param logger Loggger
* @param scanner Scanner used to read input * @param scanner Scanner used to read input
* @param client HostItem of the application
*/ */
public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) {
super(baseDirectory, tracker, partsSubdir, logger, scanner); super(baseDirectory, tracker, partsSubdir, logger, scanner, client);
} }
/** Initialize downloader /** Initialize downloader
* @param filename Name of the file to download * @param filename Name of the file to download
*/ */
protected void initDownloader(String filename) { protected void initDownloader(String filename) {
downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger); downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger, client);
} }
/** Implementation of writeLog /** Implementation of writeLog

@ -178,7 +178,7 @@ public class ClientP2P {
case "upd": // to avoid users typos case "upd": // to avoid users typos
case "2" : case "2" :
System.out.println("Starting with UDP"); System.out.println("Starting with UDP");
ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner); ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner, c.server);
tclient = new Thread(cmudp); tclient = new Thread(cmudp);
break; break;
case "TCP": case "TCP":
@ -186,7 +186,7 @@ public class ClientP2P {
case "1": case "1":
default: default:
System.out.println("Starting with TCP"); System.out.println("Starting with TCP");
ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner); ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner, c.server);
tclient = new Thread(cmtcp); tclient = new Thread(cmtcp);
break; break;
} }

@ -6,6 +6,7 @@ import localException.ProtocolError;
import localException.InternalError; import localException.InternalError;
import localException.SizeError; import localException.SizeError;
import tools.BytesArrayTools; import tools.BytesArrayTools;
import tools.HostItem;
/** Representation of payload for load request. /** Representation of payload for load request.
* @author Louis Royer * @author Louis Royer
@ -17,18 +18,20 @@ public class LoadRequest extends Payload {
private String filename; private String filename;
private long maxSizePartialContent; private long maxSizePartialContent;
private long offset; private long offset;
private HostItem hostItem;
static final private int OFFSET_POSITION = PAYLOAD_START_POSITION; static final private int OFFSET_POSITION = PAYLOAD_START_POSITION;
static final private int MAX_SIZE_PARTIAL_CONTENT_POSITION = OFFSET_POSITION + 8; static final private int MAX_SIZE_PARTIAL_CONTENT_POSITION = OFFSET_POSITION + 8;
static final private int FILENAME_SIZE_POSITION = MAX_SIZE_PARTIAL_CONTENT_POSITION + 8; static final private int FILENAME_SIZE_POSITION = MAX_SIZE_PARTIAL_CONTENT_POSITION + 8;
static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4; static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4;
/** Constructor (typically used by the server) with a filename parameter. /** Constructor (typically used by the client) with a filename parameter.
* @param filename name of the file to download. Must not be empty. * @param filename name of the file to download. Must not be empty.
* @param offset offset of the bloc * @param offset offset of the bloc
* @param maxSizePartialContent partial content in response should not excess this size, but this can be less (by example if endoffile is reached or server doesn't have the full block requested) * @param maxSizePartialContent partial content in response should not excess this size, but this can be less (by example if endoffile is reached or server doesn't have the full block requested)
* @param hostItem hostItem used by the client to register on the tracker
* @throws InternalError * @throws InternalError
*/ */
public LoadRequest(String filename, long offset, long maxSizePartialContent) throws InternalError { public LoadRequest(String filename, long offset, long maxSizePartialContent, HostItem hostItem) throws InternalError {
super(RequestResponseCode.LOAD_REQUEST); super(RequestResponseCode.LOAD_REQUEST);
/* assert to help debugging */ /* assert to help debugging */
assert filename.length() != 0 : "Payload size of LoadRequest must not be empty"; assert filename.length() != 0 : "Payload size of LoadRequest must not be empty";
@ -38,9 +41,10 @@ public class LoadRequest extends Payload {
this.filename = filename; this.filename = filename;
this.maxSizePartialContent = maxSizePartialContent; this.maxSizePartialContent = maxSizePartialContent;
this.offset = offset; this.offset = offset;
this.hostItem = hostItem;
} }
/** Constructor (typically used by client) with a byte[] parameter containing the Packet received. /** Constructor (typically used by server) with a byte[] parameter containing the Packet received.
* @param packet the full Packet received * @param packet the full Packet received
* @throws SizeError * @throws SizeError
* @throws InternalError * @throws InternalError
@ -64,6 +68,12 @@ public class LoadRequest extends Payload {
/* Read filename */ /* Read filename */
int size = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION); int size = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION);
filename = BytesArrayTools.readString(packet, FILENAME_POSITION, size); filename = BytesArrayTools.readString(packet, FILENAME_POSITION, size);
/* Read hostItem */
int portPosition = FILENAME_POSITION + size;
int hostnameStartPosition = portPosition + 2;
int hostnameSize = getPayloadSize(packet) - hostnameStartPosition;
hostItem = new HostItem(BytesArrayTools.readString(packet, hostnameStartPosition, hostnameSize), BytesArrayTools.readInt16Bits(packet, portPosition));
} }
/** Returns a byte[] containing Packet with padding. /** Returns a byte[] containing Packet with padding.
@ -75,8 +85,9 @@ public class LoadRequest extends Payload {
protected byte[] toPacket() throws InternalError { protected byte[] toPacket() throws InternalError {
// compute size // compute size
int filenameSize = filename.length(); int filenameSize = filename.length();
int size = FILENAME_POSITION + filenameSize; String hostname = hostItem.getHostname();
byte[] packet = new byte[size + 1]; // java initialize all to zero int size = 1 + FILENAME_POSITION + filenameSize + 2 + hostname.length();
byte[] packet = new byte[size]; // java initialize all to zero
// set request/response code // set request/response code
packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
// set Payload size // set Payload size
@ -89,7 +100,15 @@ public class LoadRequest extends Payload {
BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize); BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize);
// Write filename // Write filename
BytesArrayTools.write(packet, filename, FILENAME_POSITION); BytesArrayTools.write(packet, filename, FILENAME_POSITION);
return packet; // Write hostitem
int portPosition = FILENAME_POSITION + filenameSize;
try {
BytesArrayTools.write16Bits(packet, portPosition, hostItem.getPort());
BytesArrayTools.write(packet, hostname, portPosition + 2);
return packet;
} catch (SizeError e) {
throw new InternalError();
}
} }
/** filename getter. /** filename getter.
@ -112,4 +131,11 @@ public class LoadRequest extends Payload {
public long getMaxSizePartialContent() { public long getMaxSizePartialContent() {
return maxSizePartialContent; return maxSizePartialContent;
} }
/** hostItem getter.
* @return hostItem
*/
public HostItem getHostItem() {
return hostItem;
}
} }

@ -18,17 +18,22 @@ public enum RequestResponseCode {
DISCOVER_REQUEST(CodeType.REQUEST_TRACKER, (byte)0x03), DISCOVER_REQUEST(CodeType.REQUEST_TRACKER, (byte)0x03),
REGISTER(CodeType.REQUEST_TRACKER, (byte)0x04), REGISTER(CodeType.REQUEST_TRACKER, (byte)0x04),
UNREGISTER(CodeType.REQUEST_TRACKER, (byte)0x05), UNREGISTER(CodeType.REQUEST_TRACKER, (byte)0x05),
RATIO_REQUEST(CodeType.REQUEST_TRACKER, (byte)0x06),
UPDATE_RATIO(CodeType.REQUEST_TRACKER, (byte)0x07),
LIST_RESPONSE(CodeType.RESPONSE, (byte)0x80), LIST_RESPONSE(CodeType.RESPONSE, (byte)0x80),
LOAD_RESPONSE(CodeType.RESPONSE, (byte)0x81), LOAD_RESPONSE(CodeType.RESPONSE, (byte)0x81),
HASH_RESPONSE(CodeType.RESPONSE, (byte)0x82), HASH_RESPONSE(CodeType.RESPONSE, (byte)0x82),
DISCOVER_RESPONSE(CodeType.RESPONSE, (byte)0x83), DISCOVER_RESPONSE(CodeType.RESPONSE, (byte)0x83),
RATIO_RESPONSE(CodeType.RESPONSE, (byte)0x86),
VERSION_ERROR(CodeType.ERROR, (byte)0xC0), VERSION_ERROR(CodeType.ERROR, (byte)0xC0),
PROTOCOL_ERROR(CodeType.ERROR, (byte)0xC1), PROTOCOL_ERROR(CodeType.ERROR, (byte)0xC1),
INTERNAL_ERROR(CodeType.ERROR, (byte)0xC2), INTERNAL_ERROR(CodeType.ERROR, (byte)0xC2),
EMPTY_DIRECTORY(CodeType.ERROR, (byte)0xC3), EMPTY_DIRECTORY(CodeType.ERROR, (byte)0xC3),
NOT_FOUND(CodeType.ERROR, (byte)0xC4), NOT_FOUND(CodeType.ERROR, (byte)0xC4),
EMPTY_FILE(CodeType.ERROR, (byte)0xC5), EMPTY_FILE(CodeType.ERROR, (byte)0xC5),
NOT_A_TRACKER(CodeType.ERROR, (byte)0xC6); NOT_A_TRACKER(CodeType.ERROR, (byte)0xC6),
UNKNOWN_HOST(CodeType.ERROR, (byte)0xC7),
DENIED(CodeType.ERROR, (byte)0xC8);
public final CodeType codeType; public final CodeType codeType;
public final byte codeValue; public final byte codeValue;

Loading…
Cancel
Save