《Red5 用户参考手册》之十二:Red5 核心技术第五章 脚本实现

官方最新《Red5 用户参考手册》全套下载地址
        I. 选择一个脚本实现
        级别:初级
        RED5 含有以下脚本语言的解释器:
                * Javascript - version 1.6 (Mozilla Rhino version 1.6 R7)
                * JRuby - version 1.0.1 (Ruby version 1.8.5)
                * Jython - version 2.2 (Python version 2.1)
                * Groovy - version 1.0
                * Beanshell - version 2.0b4
        RED5 的以后版本可能会含有以下脚本语言的解释器:
                * JudoScript
                * Scala
                * PHP(这个不一般,我们可能会只是提供一个桥梁)
                * Actionscript (可能会是 SSAS)

        脚本实现类根据你的 Java 版本预先指定在以下位置:

Java5 - js-engine.jar, jython-engine.jar, groovy-engine.jar 
Java6 - resources.jar

        文件的位置:/META-INF/services/javax.script.ScriptEngineFactory
        读取自定义在 jdk 或 jre 的类会比在其他地方定义的类优先考虑。
        II. 配置 Spring
        级别:中级
        第一步是定位你的 web 应用 red5-web.xml 文件。在这个 xml 配置文件中 web.scope bean 的定义必须提供一个 web.handler,这个处理程序就是你的 Red5 应用(一个必须扩展 org.red5.server.adapter.ApplicationAdapter 类的应用)。
        这个应用提供对 Red5 服务器的访问,并提供已创建的所有服务实例。服务实例和应用本身可以使用脚本。定义在 Spring 配置文件中的 bean 不能具有相同的 id,这里是一些 web 处理程序的定义示例:

                * Java 实现类

<bean id="web.handler" class="org.red5.server.webapp.oflaDemo.MultiThreadedApplicationAdapter" /> 

                * Javascript 实现

<bean id="web.handler" class="org.red5.server.script.rhino.RhinoScriptFactory"> 
  <constructor-arg index="0" value="classpath:applications/main.js"/> 
  <constructor-arg index="1"> 
    <list> 
     <value>org.red5.server.api.IScopeHandler</value> 
     <value>org.red5.server.adapter.IApplication</value> 
    </list> 
</constructor-arg> 
<constructor-arg index="2"> 
 <value>org.red5.server.adapter.ApplicationAdapter</value> 
</constructor-arg> 
</bean> 

                * Ruby 实现

<bean id="web.handler" class="org.springframework.scripting.jruby.JRubyScriptFactory"> 
<constructor-arg index="0" value="classpath:applications/main.rb"/> 
<constructor-arg index="1"> 
 <list> 
  <value>org.red5.server.api.IScopeHandler</value> 
  <value>org.red5.server.adapter.IApplication</value> 
 </list> 
</constructor-arg> 
</bean> 

                * Groovy 实现

<bean id="web.handler" class="org.red5.server.script.groovy.GroovyScriptFactory"> 
<constructor-arg index="0" value="classpath:applications/main.groovy"/> 
<constructor-arg index="1"> 
 <list> 
  <value>org.red5.server.api.IScopeHandler</value> 
  <value>org.red5.server.adapter.IApplication</value> 
 </list> 
</constructor-arg> 
</bean> 

                * Python 实现

Red5 Open Source 
Flash Server (0.7.1) 51 
<bean id="web.handler" class="org.red5.server.script.jython.JythonScriptFactory"> 
 <constructor-arg index="0" value="classpath:applications/main.py"/> 
 <constructor-arg index="1"> 
  <list> 
      <value>org.red5.server.api.IScopeHandler</value> 
      <value>org.red5.server.adapter.IApplication</value>
Scripting Implementations 
  </list> 
 </constructor-arg> 
        <constructor-arg index="2"> 
  <list> 
            <value>One</value> 
            <value>2</value> 
            <value>III</value> 
        </list> 
    </constructor-arg> 
</bean> 

        一般来说,使用脚本类的配置文件是使用构造函数的参数(见解释部分),其顺序如下:
                * 参数 1 - 脚本源文件的位置
                * 参数 2 - 脚本实现的 Java 接口。扩展了应用程序的接口基本样板请参考上面的例子。你不需要在你所有脚本定义里都使用这些接口。
                * 参数 3 - 脚本扩展的 Java 类。扩展的类并不总是必要,这取决于脚本引擎的实现。
        示例 classpath 位置:物理磁盘里的 "oflaDemo" 依赖的应用等同于 webapps/oflaDemo/WEB-INF/applications。
        III. 创建一个应用脚本
        1.应用适配器
        一些语言中,使用脚本编写应用程序适配器比在其他语言中要难得多,藉此我介绍 Ruby 的例子,它的效果很好并易于编写和整合。这个应用服务在其他支持的语言中也很容易编写,但它们至少需要 Java 接口。

                i. JRuby 应用适配器实现

# JRuby 
require 'java' 
module RedFive 
    include_package "org.red5.server.api" 
    include_package "org.red5.server.api.stream" 
    include_package "org.red5.server.api.stream.support" 
    include_package "org.red5.server.adapter" 
    include_package "org.red5.server.stream" 
end 
# 
# application.rb - a translation into Ruby of the ofla demo application, a red5 example. 
# 
# @author Paul Gregoire 
#
class Application < RedFive::ApplicationAdapter 
    attr_reader :appScope, :serverStream 
        attr_writer :appScope, :serverStream 
        def initialize 
           #call super to init the superclass, in this case a Java class 
           super 
           puts "Initializing ruby application" 
        end 
        def appStart(app) 
        puts "Ruby appStart" 
                @appScope = app 
                return true 
        end 
        def appConnect(conn, params) 
                puts "Ruby appConnect" 
                measureBandwidth(conn) 
                puts "Ruby appConnect 2" 
                if conn.instance_of?(RedFive::IStreamCapableConnection) 
                    puts "Got stream capable connection" 
                        sbc = RedFive::SimpleBandwidthConfigure.new 
                        sbc.setMaxBurst(8388608) 
                        sbc.setBurst(8388608) 
                        sbc.setOverallBandwidth(8388608) 
                        conn.setBandwidthConfigure(sbc) 
                end 
                return super 
        end 
        def appDisconnect(conn) 
                puts "Ruby appDisconnect" 
                if appScope == conn.getScope && @serverStream != nil 
                        @serverStream.close 
                end 
                super 
        end 
        def toString 
        return "Ruby toString" 
        end 
    def setScriptContext(scriptContext) 
           puts "Ruby application setScriptContext" 
    end 
    def method_missing(m, *args) 
      super unless @value.respond_to?(m) 
      return @value.send(m, *args) 
    end 
end

        2.应用服务
        这里是一个 Java 接口的示例(是的,假设方法是空的),这个接口用于为搜集一系列的文件并将它们以 Map(名-值 对)返回给调用者的应用提供一个模板。

                i. 由脚本执行简单的 Java 接口

package org.red5.server.webapp.oflaDemo; 
             
import java.util.Map; 
public interface IDemoService { 
        /** 
     * Getter for property 'listOfAvailableFLVs'. 
     * 
     * @return Value for property 'listOfAvailableFLVs'. 
     */ 
    public Map getListOfAvailableFLVs(); 
    public Map getListOfAvailableFLVs(String string); 
} 

                ii. Spring bean 关于脚本实现的接口的定义

<bean id="demoService.service" class="org.springframework.scripting.jruby.JRubyScriptFactory"> 
   <constructor-arg index="0" value="classpath:applications/demoservice.rb"/> 
   <constructor-arg index="1"> 
      <list> 
         <value>org.red5.server.webapp.oflaDemo.IDemoService</value> 
      </list> 
   </constructor-arg> 
</bean> 

                iii. JRuby 脚本实现接口

# JRuby - style 
require 'java' 
module RedFive 
    include_package "org.springframework.core.io" 
    include_package "org.red5.server.webapp.oflaDemo" 
end 
include_class "org.red5.server.api.Red5" 
include_class "java.util.HashMap" 
# 
# demoservice.rb - a translation into Ruby of the ofla demo application, a red5 example. 
# 
# @author Paul Gregoire 
# 
class DemoService < RedFive::DemoServiceImpl 
    attr_reader :filesMap 
    attr_writer :filesMap 
        def initialize 
           puts "Initializing ruby demoservice" 
           super 
           @filesMap = HashMap.new 
        end
 def getListOfAvailableFLVs 
                puts "Getting the FLV files" 
                begin 
            dirname = File.expand_path('webapps/oflaDemo/streams').to_s 
                        Dir.open(dirname).entries.grep(/\.flv$/) do |dir| 
                            dir.each do |flvName| 
                            fileInfo = HashMap.new 
                            stats = File.stat(dirname+'/'+flvName) 
                            fileInfo["name"] = flvName 
                            fileInfo["lastModified"] = stats.mtime 
                            fileInfo["size"] = stats.size || 0 
                    @filesMap[flvName] = fileInfo 
                    print 'FLV Name:', flvName 
                    print 'Last modified date:', stats.mtime 
                    print 'Size:', stats.size || 0 
                    print '-------' 
                end 
            end 
                rescue Exception => ex 
                        puts "Error in getListOfAvailableFLVs #{errorType} \n" 
                        puts "Exception: #{ex} \n" 
                        puts caller.join("\n"); 
                end 
                return filesMap 
        end 
        def formatDate(date) 
                return date.strftime("%d/%m/%Y %I:%M:%S") 
        end 
    def method_missing(m, *args) 
      super unless @value.respond_to?(m) 
      return @value.send(m, *args) 
    end 
end 

                iv. Java 应用实现接口,基于 Ruby 代码(在不需要使用脚本时的代码)

package org.red5.server.webapp.oflaDemo; 
import java.io.File; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.HashMap; 
import java.util.Locale; 
import java.util.Map; 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.red5.server.api.IScope; 
import org.red5.server.api.Red5; 
import org.springframework.core.io.Resource; 
public class DemoService { 
        protected static Log log = LogFactory.getLog(DemoService.class.getName()); 

 /** 
     * Getter for property 'listOfAvailableFLVs'.
Scripting Implementations 
     * 
     * @return Value for property 'listOfAvailableFLVs'. 
     */ 
    public Map getListOfAvailableFLVs() { 
                IScope scope = Red5.getConnectionLocal().getScope(); 
                Map<String, Map> filesMap = new HashMap<String, Map>(); 
                Map<String, Object> fileInfo; 
                try { 
                        log.debug("getting the FLV files"); 
                        Resource[] flvs = scope.getResources("streams/*.flv"); 
                        if (flvs != null) { 
                                for (Resource flv : flvs) { 
                                        File file = flv.getFile(); 
                                        Date lastModifiedDate = new Date(file.lastModified()); 
                                        String lastModified = formatDate(lastModifiedDate); 
                                        String flvName = flv.getFile().getName(); 
                                        String flvBytes = Long.toString(file.length()); 
                                        if (log.isDebugEnabled()) { 
                                                log.debug("flvName: " + flvName); 
                                                log.debug("lastModified date: " + lastModified); 
                                                log.debug("flvBytes: " + flvBytes); 
                                                log.debug("-------"); 
                                        } 
                                        fileInfo = new HashMap<String, Object>(); 
                                        fileInfo.put("name", flvName); 
                                        fileInfo.put("lastModified", lastModified); 
                                        fileInfo.put("size", flvBytes); 
                                        filesMap.put(flvName, fileInfo); 
                                } 
} 
                        Resource[] mp3s = scope.getResources("streams/*.mp3"); 
                        if (mp3s != null) { 
                                for (Resource mp3 : mp3s) { 
                                        File file = mp3.getFile(); 
                                        Date lastModifiedDate = new Date(file.lastModified()); 
                                        String lastModified = formatDate(lastModifiedDate); 
                                        String flvName = mp3.getFile().getName(); 
                                        String flvBytes = Long.toString(file.length()); 
                                        if (log.isDebugEnabled()) { 
                                                log.debug("flvName: " + flvName); 
                                                log.debug("lastModified date: " + lastModified); 
                                                log.debug("flvBytes: " + flvBytes); 
                                                log.debug("-------"); 
                                        } 
                                        fileInfo = new HashMap<String, Object>(); 
                                        fileInfo.put("name", flvName); 
                                        fileInfo.put("lastModified", lastModified); 
                                        fileInfo.put("size", flvBytes); 
                                        filesMap.put(flvName, fileInfo); 
                                } 
                        } 
                } catch (IOException e) { 
                        log.error(e); 
                } 
                return filesMap; 
        } 
        
        private String formatDate(Date date) { 
                SimpleDateFormat formatter; 
                String pattern = "dd/MM/yy H:mm:ss"; 
                Locale locale = new Locale("en", "US"); 
                formatter = new SimpleDateFormat(pattern, locale); 
                return formatter.format(date); 
        } 
}  

        a.Flex AS3 方法调用服务

[Bindable] 
public var videoList:ArrayCollection; 
public function catchVideos():void{ 
        // call server-side method 
        // create a responder and set it to getMediaList 
        var nc_responder:Responder = new Responder(getMediaList, null); 
        // call the server side method to get list of FLV's 
        nc.call("demoService.getListOfAvailableFLVs", nc_responder); 
} 
public function getMediaList(list:Object):void{ 
        // this is the result of the server side getListOfAvailableFLVs 
        var mediaList:Array = new Array(); 
        for(var items:String in list){ 
            mediaList.push({label:items, size:list[items].size, dateModified:list[items].lastModifi 
        } 
        // videoList is bindable and the datagrid is set to use this for it's dataprovider 
        // wrap it in an ArrayCollection first 
        videoList = new ArrayCollection(mediaList); 
} 

        IV. 创建你自己的解释器
        级别:高级
        在打开这个话题之前先提一下上周末 02/2007 试图建立一个PHP解释器,那阵势一个痛苦的过程哈,四个小时之后我不得不放弃。这件事我汲取的教训就是你首先得断定你的脚本语言可以作为应用程序运行,而不是作为 HTTP 请求处理器。这里可以先测试一下:X 语言是否可以编译成一个可执行程序,或者它可以使用命令行运行?如果可以的话,那它就可以进行轻易整合。
        V. 脚本信息的相关链接
                * Spring 脚本
                        http://static.springframework.org/spring/docs/2.0.x/reference/dynamic-language.html
                        http://rhinoinspring.sourceforge.net/
                * Java 脚本
                        http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/
                        http://blogs.sun.com/sundararajan/  
                        https://scripting.dev.java.net/
                        http://today.java.net/pub/a/today/2006/04/11/scripting-for-java-platform.html  
                        http://www.javaworld.com/javaworld/jw-03-2005/jw-0314-scripting_p.html
                        http://www.oreillynet.com/onjava/blog/2004/01/java_scripting_half_the_size_h.html  
                        http://www.robert-tolksdorf.de/vmlanguages.html
                * Javascript
                        http://www.mozilla.org/rhino/  
                        http://www.mozilla.org/rhino/ScriptingJava.html
                * Ruby
                        http://jruby.codehaus.org/
                * BeanShell
                        http://www.beanshell.org/
                * Python
                        http://www.jython.org/Project/  
                        http://www.onjava.com/pub/a/onjava/2002/03/27/jython.html  
                        http://jepp.sourceforge.net/  
                        http://jpe.sourceforge.net/
                        http://jpype.sourceforge.net/
                * Groovy
                        http://groovy.codehaus.org/
原文链接: http://trac.red5.org/wiki/Documentation/UsersReferenceManual/Red5CoreTechnologies/05-Scripting-Implementations
posted @ 2012-07-26 17:40  Defonds  阅读(36)  评论(0编辑  收藏  举报