package org.red5.server.plugin.admin; /* * RED5 Open Source Flash Server - http://www.osflash.org/red5 * * Copyright (c) 2006-2009 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Set; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.red5.server.api.event.IEvent; import org.red5.server.api.scope.IBasicScope; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.IScopeHandler; import org.red5.server.api.service.IServiceCall; import org.red5.server.api.service.ServiceUtils; import org.red5.server.plugin.admin.stats.ScopeStatistics; import org.red5.server.plugin.admin.stats.UserStatistics; import org.red5.server.scope.Scope; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ResourceBundleMessageSource; /** * Primary "admin" class, it handles all the features and functions of a * standard red5 application. This code is based on original code in the * admin application. * * @author Paul Gregoire */ public class AdminHandler implements IScopeHandler { private static Logger log = Red5LoggerFactory.getLogger(AdminHandler.class, "admin"); private static ResourceBundleMessageSource messageSource; private IScope scope; private HashMap<Integer, String> scopes; private int scopeId = 0; private ApplicationContext context; public boolean start(IScope scope) { log.info("start: {}", scope); return true; } public void stop(IScope scope) { log.info("stop: {}", scope); if (scope != null) { //un-initializing admin scope and children ((Scope) this.scope).uninit(); } } public boolean handleEvent(IEvent event) { log.debug("Scope event: {}", event); return false; } public boolean connect(IConnection conn, IScope scope, Object[] params) { log.info("connect - conn: {} params: {} scope: {}", new Object[]{conn, params, scope}); return true; } public void disconnect(IConnection conn, IScope scope) { log.info("disconnect"); // Get the previously stored username String rid = conn.getClient().getId(); // Unregister user log.info("Client with id {} disconnected.", rid); } public boolean join(IClient client, IScope scope) { log.info("join - client: {} scope: {}", new Object[]{client, scope}); return true; } public void leave(IClient client, IScope scope) { log.info("leave"); } public boolean addChildScope(IBasicScope scope) { log.info("addChildScope: {}", scope); return false; } public void removeChildScope(IBasicScope scope) { log.info("removeChildScope: {}", scope); } public boolean serviceCall(IConnection conn, IServiceCall call) { log.info("serviceCall {}", call); return true; } /** * Get all running applications * * @return HashMap containing all applications */ public HashMap<Integer, Object> getApplications() { IScope root = ScopeUtils.findRoot(scope); Iterator<String> iter = (Iterator<String>) root.getScopeNames(); HashMap<Integer, Object> apps = new HashMap<Integer, Object>(); int id = 0; while (iter.hasNext()) { String name = iter.next(); String name2 = name.substring(1, name.length()); int size = getConnections(name2).size(); HashMap<String, String> app = new HashMap<String, String>(); app.put("name", name2); app.put("clients", size + ""); apps.put(id, app); id++; } return apps; } /** * Get Application statistics. * * @param scopeName * @return HashMap with the statistics */ public HashMap<Integer, HashMap<String, String>> getStatistics(String scopeName) { ScopeStatistics scopestats = new ScopeStatistics(); return scopestats.getStats(getScope(scopeName)); } /** * Get Client statistics * * @param userid * @return HashMap with the statistics */ public HashMap<Integer, HashMap<String, String>> getUserStatistics(String userid) { UserStatistics userstats = new UserStatistics(); return userstats.getStats(userid, scope); } /** * Get all the scopes * * @param scopeName * @return HashMap containing all the scopes */ public HashMap<Integer, String> getScopes(String scopeName) { IScope root = ScopeUtils.findRoot(scope); IScope scopeObj = root.getScope(scopeName); scopes = new HashMap<Integer, String>(); try { getRooms(scopeObj, 0); } catch (NullPointerException npe) { log.debug(npe.toString()); } return scopes; } /** * Get all the scopes * * @param root * the scope to from * @param depth * scope depth */ public void getRooms(IScope root, int depth) { Iterator<String> iter = (Iterator<String>) root.getScopeNames(); String indent = ""; for (int i = 0; i < depth; i++) { indent += " "; } while (iter.hasNext()) { String name = iter.next(); String name2 = name.substring(1, name.length()); try { IScope parent = root.getScope(name2); // parent getRooms(parent, depth + 1); scopes.put(scopeId, indent + name2); scopeId++; // log.info("Found scope: "+name2); } catch (NullPointerException npe) { log.debug(npe.toString()); } } } /** * Get all the connections (clients) * * @param scopeName * @return HashMap with all clients in the given scope */ public HashMap<Integer, String> getConnections(String scopeName) { HashMap<Integer, String> connections = new HashMap<Integer, String>(); IScope root = getScope(scopeName); if (root != null) { Set<IClient> clients = root.getClients(); Iterator<IClient> client = clients.iterator(); int id = 0; while (client.hasNext()) { IClient c = client.next(); String user = c.getId(); connections.put(id, user); id++; } } return connections; } /** * Kill a client * * @param userid */ public void killUser(String userid) { IScope root = ScopeUtils.findRoot(scope); Set<IClient> clients = root.getClients(); Iterator<IClient> client = clients.iterator(); while (client.hasNext()) { IClient c = client.next(); if (c.getId().equals(userid)) { c.disconnect(); } } } /** * Get an scope by name * * @param scopeName * @return IScope the requested scope */ private IScope getScope(String scopeName) { IScope root = ScopeUtils.findRoot(scope); return getScopes(root, scopeName); } /** * Search through all the scopes in the given scope to a scope with the * given name * * @param root * @param scopeName * @return IScope the requested scope */ private IScope getScopes(IScope root, String scopeName) { // log.info("Found scope "+root.getName()); if (root.getName().equals(scopeName)) { return root; } else { Iterator<String> iter = (Iterator<String>) root.getScopeNames(); while (iter.hasNext()) { String name = iter.next(); String name2 = name.substring(1, name.length()); try { IScope parent = root.getScope(name2); IScope scope = getScopes(parent, scopeName); if (scope != null) { return scope; } } catch (NullPointerException npe) { log.debug(npe.toString()); } } } return null; } /** * Get the root scope * * @return IScope */ public IScope getScope() { return scope; } public void setScope(IScope scope) { this.scope = scope; } public void setContext(ApplicationContext ctx) { this.context = ctx; messageSource = (ResourceBundleMessageSource) context.getBean("adminMessageSource"); } /** * Method for setting locale property on the connection. * * @param localeId */ public void setLocale(String localeId) { IConnection conn = Red5.getConnectionLocal(); if (conn != null) { conn.setAttribute("locale", localeId); } } /** * onError callback invoker. * * @param code * @param args */ public static boolean sendError(String code, Object[] args) { boolean sent = false; IConnection conn = Red5.getConnectionLocal(); if (conn != null) { Locale locale = Locale.ENGLISH; if (conn.hasAttribute("locale")) { // http://java.sun.com/j2se/1.5.0/docs/api/java/util/Locale.html String[] parts = conn.getStringAttribute("locale").split("[-_]"); if (parts.length == 1) { locale = new Locale(parts[0]); } else { locale = new Locale(parts[0], parts[1]); } } String errorMessage = messageSource.getMessage(code, args, locale); log.debug("Sending error to client: {}", errorMessage); if (ServiceUtils.invokeOnConnection(conn, "onError", new Object[]{errorMessage})) { //call succeeded sent = true; } else { log.warn("Send error failed - client id: {} method: {}", conn.getClient().getId()); } } else { log.warn("Connection was not found for sending error"); } return sent; } /** * Locale echo test. */ public void echo() { sendError("echo", null); } }