/* * Copyright 2013-2014 High-Level Technologies * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.zodiark.service.session; import org.atmosphere.cpr.AtmosphereResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zodiark.protocol.Envelope; import org.zodiark.server.Context; import org.zodiark.server.EventBus; import org.zodiark.server.Reply; import org.zodiark.server.ReplyException; import org.zodiark.server.annotation.On; import org.zodiark.service.action.Action; import org.zodiark.service.publisher.PublisherEndpoint; import org.zodiark.service.session.impl.PrivateStreamingSession; import org.zodiark.service.session.impl.PublicStreamingSession; import org.zodiark.service.session.impl.SharedPrivateStreamingSession; import org.zodiark.service.session.impl.ViewStreamingSession; import org.zodiark.service.state.EndpointState; import org.zodiark.service.subscriber.SubscriberEndpoint; import javax.inject.Inject; import java.util.concurrent.ConcurrentHashMap; import static org.zodiark.protocol.Paths.BEGIN_STREAMING_SESSION; import static org.zodiark.protocol.Paths.BEGIN_SUBSCRIBER_STREAMING_SESSION; import static org.zodiark.protocol.Paths.BROADCAST_TO_ALL; import static org.zodiark.protocol.Paths.SERVICE_STREAMING; import static org.zodiark.protocol.Paths.STREAMING_COMPLETE_ACTION; import static org.zodiark.protocol.Paths.STREAMING_EXECUTE_ACTION; import static org.zodiark.protocol.Paths.WOWZA_DEOBFUSCATE; import static org.zodiark.protocol.Paths.WOWZA_OBFUSCATE; /** * The Default StreamingService implementation. */ @On(SERVICE_STREAMING) public class StreamingSessionServiceImpl implements StreamingSessionService { private final Logger logger = LoggerFactory.getLogger(StreamingSessionServiceImpl.class); @Inject public Context context; @Inject public EventBus eventBus; private final ConcurrentHashMap<String, StreamingSession> sessions = new ConcurrentHashMap<>(); @Override public void reactTo(Envelope e, AtmosphereResource r, Reply reply) { } @Override public void reactTo(String path, Object message, Reply reply) { logger.trace("Handling {}", path); switch (path) { case BEGIN_STREAMING_SESSION: PublisherEndpoint p = PublisherEndpoint.class.cast(message); boolean hasStreamingSession = hasStreamingSession(p); if (hasStreamingSession) { terminate(p, reply); } else { initiate(p, reply); } break; case BEGIN_SUBSCRIBER_STREAMING_SESSION: join(SubscriberEndpoint.class.cast(message), reply); break; case STREAMING_EXECUTE_ACTION: Action a = Action.class.cast(message); executeAction(a, reply); break; case STREAMING_COMPLETE_ACTION: p = PublisherEndpoint.class.cast(message); completeAction(p); break; default: logger.error("Not Supported {}", path); } } /** * {@inheritDoc} */ @Override public void completeAction(PublisherEndpoint publisherEndpoint) { publisherEndpoint.actionInProgress(false); final StreamingSession session = sessions.get(publisherEndpoint.uuid()); if (session == null) { throw new IllegalStateException("No live session for " + publisherEndpoint.uuid()); } final Action completedAction = session.pendingAction(); session.pendingAction(null); eventBus.message(WOWZA_DEOBFUSCATE, session, new Reply<StreamingSession, String>() { @Override public void ok(StreamingSession session) { logger.trace("Wowza de-obfuscation executed {}", completedAction); session.completeAction(completedAction); } @Override public void fail(ReplyException replyException) { logger.error("Error finishing Session {}", replyException); } }); } /** * {@inheritDoc} */ @Override public void executeAction(final Action a, final Reply reply) { PublisherEndpoint p = a.subscriber().publisherEndpoint(); final StreamingSession session = sessions.get(p.uuid()); if (session == null) { throw new IllegalStateException("No live session for " + p.uuid()); } session.pendingAction(a); eventBus.message(WOWZA_OBFUSCATE, session, new Reply<StreamingSession, String>() { @Override public void ok(StreamingSession session) { logger.trace("Wowza obfuscation executed {}", a); session.executeAction(a); // TODO: Do we need to call the subscriber reply.ok(a); } @Override public void fail(ReplyException replyException) { reply.fail(ReplyException.DEFAULT); } }); } /** * {@inheritDoc} */ @Override public void terminate(PublisherEndpoint publisherEndpoint, Reply reply) { logger.trace("Terminating streaming session {}", publisherEndpoint); StreamingSession s = sessions.remove(publisherEndpoint.uuid()); s.terminate(); } /** * {@inheritDoc} */ @Override public void initiate(PublisherEndpoint publisherEndpoint, Reply reply) { logger.trace("Starting streaming session {}", publisherEndpoint); StreamingSession s = sessionType(publisherEndpoint); sessions.put(publisherEndpoint.uuid(), s); s.publisher(publisherEndpoint); eventBus.message(BROADCAST_TO_ALL, publisherEndpoint); s.initAndAct(); reply.ok(publisherEndpoint); } /** * {@inheritDoc} */ @Override public void join(SubscriberEndpoint subscriberEndpoint, Reply reply) { boolean hasStreamingSession = hasStreamingSession(subscriberEndpoint.publisherEndpoint()); if (!hasStreamingSession) { reply.fail(ReplyException.DEFAULT); } else { StreamingSession streamingSession = sessions.get(subscriberEndpoint.publisherEndpoint().uuid()); streamingSession.validateAndJoin(subscriberEndpoint, reply); } } private boolean hasStreamingSession(PublisherEndpoint p) { return sessions.get(p.uuid()) == null ? false : true; } private StreamingSession sessionType(PublisherEndpoint p) { EndpointState state = p.state(); switch (state.modeId().mode()) { case PUBLIC: return context.newInstance(PublicStreamingSession.class); case PRIVATE: return context.newInstance(PrivateStreamingSession.class); case SHAREDPRIVATE: return context.newInstance(SharedPrivateStreamingSession.class); case VIEW: return context.newInstance(ViewStreamingSession.class); default: throw new IllegalStateException("Unsupported Session " + state.modeId()); } } }