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

来源:互联网 发布:php开发工具安装 编辑:程序博客网 时间:2024/05/22 02:08
官方最新《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 版本预先指定在以下位置:

[plain] view plaincopyprint?
  1. Java5 - js-engine.jar, jython-engine.jar, groovy-engine.jar   
  2. 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 实现类

[html] view plaincopyprint?
  1. <bean id="web.handler" class="org.red5.server.webapp.oflaDemo.MultiThreadedApplicationAdapter" />   

                * Javascript 实现

[html] view plaincopyprint?
  1. <bean id="web.handler" class="org.red5.server.script.rhino.RhinoScriptFactory">   
  2.   <constructor-arg index="0" value="classpath:applications/main.js"/>   
  3.   <constructor-arg index="1">   
  4.     <list>   
  5.      <value>org.red5.server.api.IScopeHandler</value>   
  6.      <value>org.red5.server.adapter.IApplication</value>   
  7.     </list>   
  8. </constructor-arg>   
  9. <constructor-arg index="2">   
  10.  <value>org.red5.server.adapter.ApplicationAdapter</value>   
  11. </constructor-arg>   
  12. </bean>   

                * Ruby 实现

[html] view plaincopyprint?
  1. <bean id="web.handler" class="org.springframework.scripting.jruby.JRubyScriptFactory">   
  2. <constructor-arg index="0" value="classpath:applications/main.rb"/>   
  3. <constructor-arg index="1">   
  4.  <list>   
  5.   <value>org.red5.server.api.IScopeHandler</value>   
  6.   <value>org.red5.server.adapter.IApplication</value>   
  7.  </list>   
  8. </constructor-arg>   
  9. </bean>   

                * Groovy 实现

[html] view plaincopyprint?
  1. <bean id="web.handler" class="org.red5.server.script.groovy.GroovyScriptFactory">   
  2. <constructor-arg index="0" value="classpath:applications/main.groovy"/>   
  3. <constructor-arg index="1">   
  4.  <list>   
  5.   <value>org.red5.server.api.IScopeHandler</value>   
  6.   <value>org.red5.server.adapter.IApplication</value>   
  7.  </list>   
  8. </constructor-arg>   
  9. </bean>   

                * Python 实现

[html] view plaincopyprint?
  1. Red5 Open Source   
  2. Flash Server (0.7.1) 51   
  3. <bean id="web.handler" class="org.red5.server.script.jython.JythonScriptFactory">   
  4.  <constructor-arg index="0" value="classpath:applications/main.py"/>   
  5.  <constructor-arg index="1">   
  6.   <list>   
  7.       <value>org.red5.server.api.IScopeHandler</value>   
  8.       <value>org.red5.server.adapter.IApplication</value>  
  9. Scripting Implementations   
  10.   </list>   
  11.  </constructor-arg>   
  12.         <constructor-arg index="2">   
  13.   <list>   
  14.             <value>One</value>   
  15.             <value>2</value>   
  16.             <value>III</value>   
  17.         </list>   
  18.     </constructor-arg>   
  19. </bean>   

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

                i. JRuby 应用适配器实现

[ruby] view plaincopyprint?
  1. # JRuby   
  2. require 'java'   
  3. module RedFive   
  4.     include_package "org.red5.server.api"   
  5.     include_package "org.red5.server.api.stream"   
  6.     include_package "org.red5.server.api.stream.support"   
  7.     include_package "org.red5.server.adapter"   
  8.     include_package "org.red5.server.stream"   
  9. end   
  10.   
  11. # application.rb - a translation into Ruby of the ofla demo application, a red5 example.   
  12.   
  13. # @author Paul Gregoire   
  14. #  
  15. class Application < RedFive::ApplicationAdapter   
  16.     attr_reader :appScope:serverStream   
  17.         attr_writer :appScope:serverStream   
  18.         def initialize   
  19.            #call super to init the superclass, in this case a Java class   
  20.            super   
  21.            puts "Initializing ruby application"   
  22.         end   
  23.         def appStart(app)   
  24.         puts "Ruby appStart"   
  25.                 @appScope = app   
  26.                 return true   
  27.         end   
  28.         def appConnect(conn, params)   
  29.                 puts "Ruby appConnect"   
  30.                 measureBandwidth(conn)   
  31.                 puts "Ruby appConnect 2"   
  32.                 if conn.instance_of?(RedFive::IStreamCapableConnection)   
  33.                     puts "Got stream capable connection"   
  34.                         sbc = RedFive::SimpleBandwidthConfigure.new   
  35.                         sbc.setMaxBurst(8388608)   
  36.                         sbc.setBurst(8388608)   
  37.                         sbc.setOverallBandwidth(8388608)   
  38.                         conn.setBandwidthConfigure(sbc)   
  39.                 end   
  40.                 return super   
  41.         end   
  42.         def appDisconnect(conn)   
  43.                 puts "Ruby appDisconnect"   
  44.                 if appScope == conn.getScope && @serverStream != nil   
  45.                         @serverStream.close   
  46.                 end   
  47.                 super   
  48.         end   
  49.         def toString   
  50.         return "Ruby toString"   
  51.         end   
  52.     def setScriptContext(scriptContext)   
  53.            puts "Ruby application setScriptContext"   
  54.     end   
  55.     def method_missing(m, *args)   
  56.       super unless @value.respond_to?(m)   
  57.       return @value.send(m, *args)   
  58.     end   
  59. end  

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

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

[java] view plaincopyprint?
  1. package org.red5.server.webapp.oflaDemo;   
  2.                
  3. import java.util.Map;   
  4. public interface IDemoService {   
  5.         /**  
  6.      * Getter for property 'listOfAvailableFLVs'.  
  7.      *  
  8.      * @return Value for property 'listOfAvailableFLVs'.  
  9.      */   
  10.     public Map getListOfAvailableFLVs();   
  11.     public Map getListOfAvailableFLVs(String string);   
  12. }   

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

[html] view plaincopyprint?
  1. <bean id="demoService.service" class="org.springframework.scripting.jruby.JRubyScriptFactory">   
  2.    <constructor-arg index="0" value="classpath:applications/demoservice.rb"/>   
  3.    <constructor-arg index="1">   
  4.       <list>   
  5.          <value>org.red5.server.webapp.oflaDemo.IDemoService</value>   
  6.       </list>   
  7.    </constructor-arg>   
  8. </bean>   

                iii. JRuby 脚本实现接口

[ruby] view plaincopyprint?
  1. # JRuby - style   
  2. require 'java'   
  3. module RedFive   
  4.     include_package "org.springframework.core.io"   
  5.     include_package "org.red5.server.webapp.oflaDemo"   
  6. end   
  7. include_class "org.red5.server.api.Red5"   
  8. include_class "java.util.HashMap"   
  9.   
  10. # demoservice.rb - a translation into Ruby of the ofla demo application, a red5 example.   
  11.   
  12. # @author Paul Gregoire   
  13.   
  14. class DemoService < RedFive::DemoServiceImpl   
  15.     attr_reader :filesMap   
  16.     attr_writer :filesMap   
  17.         def initialize   
  18.            puts "Initializing ruby demoservice"   
  19.            super   
  20.            @filesMap = HashMap.new   
  21.         end  
  22.  def getListOfAvailableFLVs   
  23.                 puts "Getting the FLV files"   
  24.                 begin   
  25.             dirname = File.expand_path('webapps/oflaDemo/streams').to_s   
  26.                         Dir.open(dirname).entries.grep(/\.flv$/) do |dir|   
  27.                             dir.each do |flvName|   
  28.                             fileInfo = HashMap.new   
  29.                             stats = File.stat(dirname+'/'+flvName)   
  30.                             fileInfo["name"] = flvName   
  31.                             fileInfo["lastModified"] = stats.mtime   
  32.                             fileInfo["size"] = stats.size || 0   
  33.                     @filesMap[flvName] = fileInfo   
  34.                     print 'FLV Name:', flvName   
  35.                     print 'Last modified date:', stats.mtime   
  36.                     print 'Size:', stats.size || 0   
  37.                     print '-------'   
  38.                 end   
  39.             end   
  40.                 rescue Exception => ex   
  41.                         puts "Error in getListOfAvailableFLVs #{errorType} \n"   
  42.                         puts "Exception: #{ex} \n"   
  43.                         puts caller.join("\n");   
  44.                 end   
  45.                 return filesMap   
  46.         end   
  47.         def formatDate(date)   
  48.                 return date.strftime("%d/%m/%Y %I:%M:%S")   
  49.         end   
  50.     def method_missing(m, *args)   
  51.       super unless @value.respond_to?(m)   
  52.       return @value.send(m, *args)   
  53.     end   
  54. end   

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

[java] view plaincopyprint?
  1. package org.red5.server.webapp.oflaDemo;   
  2. import java.io.File;   
  3. import java.io.IOException;   
  4. import java.text.SimpleDateFormat;   
  5. import java.util.Date;   
  6. import java.util.HashMap;   
  7. import java.util.Locale;   
  8. import java.util.Map;   
  9. import org.apache.commons.logging.Log;   
  10. import org.apache.commons.logging.LogFactory;   
  11. import org.red5.server.api.IScope;   
  12. import org.red5.server.api.Red5;   
  13. import org.springframework.core.io.Resource;   
  14. public class DemoService {   
  15.         protected static Log log = LogFactory.getLog(DemoService.class.getName());   
  16.   
  17.  /**  
  18.      * Getter for property 'listOfAvailableFLVs'. 
  19. Scripting Implementations  
  20.      *  
  21.      * @return Value for property 'listOfAvailableFLVs'.  
  22.      */   
  23.     public Map getListOfAvailableFLVs() {   
  24.                 IScope scope = Red5.getConnectionLocal().getScope();   
  25.                 Map<String, Map> filesMap = new HashMap<String, Map>();   
  26.                 Map<String, Object> fileInfo;   
  27.                 try {   
  28.                         log.debug("getting the FLV files");   
  29.                         Resource[] flvs = scope.getResources("streams/*.flv");   
  30.                         if (flvs != null) {   
  31.                                 for (Resource flv : flvs) {   
  32.                                         File file = flv.getFile();   
  33.                                         Date lastModifiedDate = new Date(file.lastModified());   
  34.                                         String lastModified = formatDate(lastModifiedDate);   
  35.                                         String flvName = flv.getFile().getName();   
  36.                                         String flvBytes = Long.toString(file.length());   
  37.                                         if (log.isDebugEnabled()) {   
  38.                                                 log.debug("flvName: " + flvName);   
  39.                                                 log.debug("lastModified date: " + lastModified);   
  40.                                                 log.debug("flvBytes: " + flvBytes);   
  41.                                                 log.debug("-------");   
  42.                                         }   
  43.                                         fileInfo = new HashMap<String, Object>();   
  44.                                         fileInfo.put("name", flvName);   
  45.                                         fileInfo.put("lastModified", lastModified);   
  46.                                         fileInfo.put("size", flvBytes);   
  47.                                         filesMap.put(flvName, fileInfo);   
  48.                                 }   
  49. }   
  50.                         Resource[] mp3s = scope.getResources("streams/*.mp3");   
  51.                         if (mp3s != null) {   
  52.                                 for (Resource mp3 : mp3s) {   
  53.                                         File file = mp3.getFile();   
  54.                                         Date lastModifiedDate = new Date(file.lastModified());   
  55.                                         String lastModified = formatDate(lastModifiedDate);   
  56.                                         String flvName = mp3.getFile().getName();   
  57.                                         String flvBytes = Long.toString(file.length());   
  58.                                         if (log.isDebugEnabled()) {   
  59.                                                 log.debug("flvName: " + flvName);   
  60.                                                 log.debug("lastModified date: " + lastModified);   
  61.                                                 log.debug("flvBytes: " + flvBytes);   
  62.                                                 log.debug("-------");   
  63.                                         }   
  64.                                         fileInfo = new HashMap<String, Object>();   
  65.                                         fileInfo.put("name", flvName);   
  66.                                         fileInfo.put("lastModified", lastModified);   
  67.                                         fileInfo.put("size", flvBytes);   
  68.                                         filesMap.put(flvName, fileInfo);   
  69.                                 }   
  70.                         }   
  71.                 } catch (IOException e) {   
  72.                         log.error(e);   
  73.                 }   
  74.                 return filesMap;   
  75.         }   
  76.           
  77.         private String formatDate(Date date) {   
  78.                 SimpleDateFormat formatter;   
  79.                 String pattern = "dd/MM/yy H:mm:ss";   
  80.                 Locale locale = new Locale("en""US");   
  81.                 formatter = new SimpleDateFormat(pattern, locale);   
  82.                 return formatter.format(date);   
  83.         }   
  84. }    

        a.Flex AS3 方法调用服务

[plain] view plaincopyprint?
  1. [Bindable]   
  2. public var videoList:ArrayCollection;   
  3. public function catchVideos():void{   
  4.         // call server-side method   
  5.         // create a responder and set it to getMediaList   
  6.         var nc_responder:Responder = new Responder(getMediaList, null);   
  7.         // call the server side method to get list of FLV's   
  8.         nc.call("demoService.getListOfAvailableFLVs", nc_responder);   
  9. }   
  10. public function getMediaList(list:Object):void{   
  11.         // this is the result of the server side getListOfAvailableFLVs   
  12.         var mediaList:Array = new Array();   
  13.         for(var items:String in list){   
  14.             mediaList.push({label:items, size:list[items].size, dateModified:list[items].lastModifi   
  15.         }   
  16.         // videoList is bindable and the datagrid is set to use this for it's dataprovider   
  17.         // wrap it in an ArrayCollection first   
  18.         videoList = new ArrayCollection(mediaList);   
  19. }   

        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
原创粉丝点击