package com.skcraft.playblock.queue; import io.netty.buffer.ByteBufInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import net.minecraft.entity.player.EntityPlayer; import org.apache.logging.log4j.Level; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.sk89q.forge.AbstractBehavior; import com.sk89q.forge.BehaviorPayload; import com.sk89q.forge.ResponseTracker; import com.skcraft.playblock.PlayBlock; import com.skcraft.playblock.media.InvalidLengthException; import com.skcraft.playblock.media.Media; import com.skcraft.playblock.network.BehaviorType; import com.skcraft.playblock.network.Enqueue; import com.skcraft.playblock.network.EnqueueResponse; import com.skcraft.playblock.network.EnqueueResponse.Response; import com.skcraft.playblock.player.MediaPlayerHost; /** * Accepts requests to add media clips to the queue, as well as for managing the * queue and listing its contents. */ public class QueueBehavior extends AbstractBehavior { private final MediaPlayerHost host; /** * Create a new queue behavior. * * @param host * the host, or null if it is the client */ public QueueBehavior(MediaPlayerHost host) { this.host = host; } /** * Get the current media queue of the host. * * @return the media queue, or null if the host is not in queue mode */ private MediaQueue getQueue() { return host.getQueue(); } /** * Submit a URI to be added to the queue. * * @param uri * the URI * @return a future */ public ListenableFuture<EnqueueResponse> sendEnqueueRequest(String uri) { Enqueue enqueue = new Enqueue(); enqueue.setUri(uri); ListenableFuture<EnqueueResponse> future = PlayBlock.getRuntime().getTracker().track(enqueue); firePayloadSend(new BehaviorPayload(BehaviorType.ENQUEUE, enqueue), null); return future; } /** * Send a response to an queue add attempt. * * @param request * the original payload with the request to enqueue * @param player * the player to send it to * @param type * the type of response * @param media * the media clip, or null */ protected void sendEnqueueResponse(Enqueue request, EntityPlayer player, Response type, Media media) { EnqueueResponse response = new EnqueueResponse(type, media); ResponseTracker.markResponseFor(request, response); List<EntityPlayer> players = new ArrayList<EntityPlayer>(); players.add(player); firePayloadSend(new BehaviorPayload(BehaviorType.ENQUEUE_RESULT, response), players); } /** * Read an {@link Enqueue}. * * @param player * the player * @param enqueue * the payload */ private void handleClientEnqueue(final EntityPlayer player, final Enqueue enqueue) { MediaQueue queue = getQueue(); // Check to see whether we have a queue if (queue == null) { sendEnqueueResponse(enqueue, player, Response.ERROR_NO_QUEUE, new Media(enqueue.getUri())); return; } ListenableFuture<Media> future = PlayBlock.getRuntime().getQueueSupervisor().submit(queue, enqueue.getUri()); // Add a callback Futures.addCallback(future, new FutureCallback<Media>() { @Override public void onSuccess(Media result) { sendEnqueueResponse(enqueue, player, Response.OK, result); } @Override public void onFailure(Throwable t) { Media media = new Media(enqueue.getUri()); if (t instanceof InvalidLengthException) { sendEnqueueResponse(enqueue, player, Response.ERROR_UNKNOWN_LENGTH, media); } else { PlayBlock.log(Level.INFO, "Failed to enqueue " + enqueue.getUri() + " from " + player.getCommandSenderName(), t); sendEnqueueResponse(enqueue, player, Response.ERROR_INTERNAL, media); } } }); } @Override public void readPayload(EntityPlayer player, BehaviorPayload payload, ByteBufInputStream in) throws IOException { // Server if (host != null) { if (payload.isType(BehaviorType.ENQUEUE)) { Enqueue enqueue = new Enqueue(); enqueue.read(in); handleClientEnqueue(player, enqueue); } // Client } else { if (payload.isType(BehaviorType.ENQUEUE_RESULT)) { EnqueueResponse response = new EnqueueResponse(); response.read(in); PlayBlock.getRuntime().getTracker().fireFuture(response); } } } }