package org.gnunet.transport;

import org.gnunet.transport.messages.BlacklistInitMessage;
import org.gnunet.transport.messages.BlacklistQueryMessage;
import org.gnunet.transport.messages.BlacklistReplyMessage;
import org.gnunet.util.Client;
import org.gnunet.util.Configuration;
import org.gnunet.util.RunaboutMessageReceiver;

/**
 * Transport blacklist.
 */
public class Blacklist {
    /**
     * Callback that decided whether to accept or reject peers.
     */
    private final BlacklistCallback blacklistCallback;
    /**
     * Client connecting to the transport service.
     */
    private Client client;

    private final class TransportBlacklistReceiver extends RunaboutMessageReceiver {
        void visit(BlacklistQueryMessage m) {
            boolean allowed = blacklistCallback.checkAllowed(m.peer);
            BlacklistReplyMessage mr = new BlacklistReplyMessage();
            mr.isAllowed = allowed;
            mr.peer = m.peer;
            client.send(mr);
        }

        @Override
        public void handleError() {
            client.reconnect();
            client.send(new BlacklistInitMessage());
        }
    }

    /**
     * Install a blacklist callback.  The service will be queried for all
     * existing connections as well as any fresh connections to check if
     * they are permitted.
     * The blacklist is active until the Transport handle is destroyed.
     * When the transport handle that installed the blacklist is destroyed,
     * all hosts that were denied in the past will automatically be
     * whitelisted again.  This is the only way to re-enable
     * connections from peers that were previously blacklisted.
     */
    public Blacklist(Configuration configuration, BlacklistCallback blacklistCallback) {
        this.blacklistCallback = blacklistCallback;
        client = new Client("transport", configuration);
        client.send(new BlacklistInitMessage());
        client.installReceiver(new TransportBlacklistReceiver());
    }

    public void destroy() {
        client.disconnect();
        client = null;
    }
}
