All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bt.magnet.UtMetadataMessageHandler Maven / Gradle / Ivy

There is a newer version: 1.10
Show newest version
package bt.magnet;

import bt.bencoding.BEParser;
import bt.bencoding.model.BEInteger;
import bt.bencoding.model.BEMap;
import bt.bencoding.model.BEObject;
import bt.protocol.DecodingContext;
import bt.protocol.EncodingContext;
import bt.protocol.handler.MessageHandler;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;

public class UtMetadataMessageHandler implements MessageHandler {
    private final Collection> supportedTypes = Collections.singleton(UtMetadata.class);

    @Override
    public boolean encode(EncodingContext context, UtMetadata message, ByteBuffer buffer) {
        boolean encoded = false;
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            writeMessage(message, bos);
            byte[] payload = bos.toByteArray();
            if (buffer.remaining() >= payload.length) {
                buffer.put(payload);
                encoded = true;
            }
        } catch (IOException e) {
            // can't happen
        }
        return encoded;
    }

    private void writeMessage(UtMetadata message, OutputStream out) throws IOException {
        BEMap m = new BEMap(null, new HashMap>() {{
            put(UtMetadata.messageTypeField(), new BEInteger(null, BigInteger.valueOf(message.getType().id())));
            put(UtMetadata.pieceIndexField(), new BEInteger(null, BigInteger.valueOf(message.getPieceIndex())));
            if (message.getData().isPresent()) {
                put(UtMetadata.totalSizeField(), new BEInteger(null, BigInteger.valueOf(message.getTotalSize().get())));
            }
        }});
        m.writeTo(out);
        if (message.getData().isPresent()) {
            out.write(message.getData().get());
        }
    }

    @Override
    public int decode(DecodingContext context, ByteBuffer buffer) {
        byte[] payload = new byte[buffer.remaining()];
        buffer.get(payload);
        try (BEParser parser = new BEParser(payload)) {
            BEMap m = parser.readMap();
            int length = m.getContent().length;
            UtMetadata.Type messageType = getMessageType(m);
            int pieceIndex = getPieceIndex(m);
            switch (messageType) {
                case REQUEST: {
                    context.setMessage(UtMetadata.request(pieceIndex));
                    return length;
                }
                case DATA: {
                    byte[] data = Arrays.copyOfRange(payload, length, payload.length);
                    context.setMessage(UtMetadata.data(pieceIndex, getTotalSize(m), data));
                    return payload.length;
                }
                case REJECT: {
                    context.setMessage(UtMetadata.reject(pieceIndex));
                    return length;
                }
                default: {
                    throw new IllegalStateException("Unknown message type: " + messageType.name());
                }
            }
        }
    }

    private UtMetadata.Type getMessageType(BEMap m) {
        BEInteger type = (BEInteger) m.getValue().get(UtMetadata.messageTypeField());
        int typeId = type.getValue().intValueExact();
        return UtMetadata.Type.forId(typeId);
    }

    private int getPieceIndex(BEMap m) {
        return getIntAttribute(UtMetadata.pieceIndexField(), m);
    }

    private int getTotalSize(BEMap m) {
        return getIntAttribute(UtMetadata.totalSizeField(), m);
    }

    private int getIntAttribute(String name, BEMap m) {
        BEInteger value = ((BEInteger) m.getValue().get(name));
        if (value == null) {
            throw new IllegalStateException("Message attribute is missing: " + name);
        }
        return value.getValue().intValueExact();
    }

    @Override
    public Collection> getSupportedTypes() {
        return supportedTypes;
    }

    @Override
    public Class readMessageType(ByteBuffer buffer) {
        return UtMetadata.class;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy