Section 10.2. Using the Server Management API

10.2. Using the Server Management API

Once a connection to the Admin Service has been established, you can use the Server Management API to query the Admin Service to monitor the running and installed applications, manage the server and administrators, and edit the server's configuration settings. The API provides the necessary remote methods to perform these actions. Accessing the remote methods on the Admin Service is done the same way as accessing remote methods in a FlashCom application as illustrated in Chapter 9. The NetConnection.call( ) method is used to access every admin method:

 adminConn.call("remoteMethod" [, responder [, arg1, ...arg   n   ]]); 

The first parameter to the call( ) method is the method name to run on the Admin Service. The second parameter is the responder object to handle the information returned from the Admin Service. Additional parameters can be passed as arguments that the remote method expects, which vary by method.

If the connection to the remote method succeeds, an information object containing the data generated by the remote method is returned. Whether the method succeeds or fails, the onResult( ) callback method of the responder object is always triggered. Unlike calls to typical FlashCom application methods, Server Management API calls made to the Admin Service do not call an onStatus( ) handler to report errors. Instead, the level and code properties of the response object passed to the onResult( ) method indicate whether the method was successful or there was some error during execution. Table 10-1 lists the properties of the response object returned by the Admin Service to the onResult( ) handler.

Table 10-1. Response object properties returned by the Admin Service

Property

Description

code

If the remote method failed, the code is "NetConnection.Call.Failed"

(FCSContstants.CALL_FAILED), "NetConnection.Admin.CommandFailed" (FCSConstants.ADMIN_COMMAND_FAILED), or "NetConnection.Call.BadValue" (FCSConstants.ADMIN_BAD_VALUE). If the remote method succeeds, the code is "NetConnection.Call.Success" (FCSConstants.CALL_SUCCESS).

data

Optional property. Most methods will return a data object with additional return parameters.

description

Optional property. If the method fails, some remote methods will also return a description property with additional information on why the method failed.

level

The type of response returned. Either "status" or "error".

timestamp

The server time at which the method was executed.


The response object passed back from the Admin Service has properties similar to the object returned to the NetConnection.onStatus( ) method. The Admin Service response object also has a timestamp property, which can be used to track how old the current data set is, and an optional data property, which may contain many additional pieces of information relative to the API operation that was performed.

The Server Management API methods can be grouped into four main categories: application, instance, server, and configuration methods. The entire list of API methods is long and well documented by Macromedia. A comprehensive Help panel entry for the Server Management API is installed with the communication components in Flash MX 2004. The Server Management ActionScript Dictionary, which documents the Server Management API, can also be downloaded in PDF format or accessed as LiveDocs in HTML format from the Macromedia web site:

http://www.macromedia.com/support/documentation/en/flashcom

The FCSAdminAdaptor class shown in Example 10-4 is a client-level wrapper to the Server Management API. Along with hiding the actual NetConnection implementation, this ActionScript 2.0 class provides an equivalent method for each Server Management API method, but in a format that is more familiar to most developers. The methods are also strictly typed so the compiler will catch any errors to speed up the overall development and debugging process of an application. The rest of this chapter will rely upon this class. The class file can be downloaded from the book's web site and is included here so you can browse it to get an understanding of all of the methods that the Server Management API exposes.

Example 10-4. The FCSAdminAdaptor Class
 import com.oreilly.pfcs.admin.FCSAdminConnector; import com.oreilly.pfcs.admin.PendingAdminCall; class com.oreilly.pfcs.admin.FCSAdminAdaptor extends Object {   private var __adminConn:FCSAdminConnector;   function FCSAdminAdaptor (aconn:FCSAdminConnector) {     __adminConn = aconn; // store the connection locally   }   function addAdmin (aname:String, apassword:String,                       ascope:String):PendingAdminCall {     return doRMI("addAdmin", arguments);   }   function addApp (aname:String):PendingAdminCall {     return doRMI("addApp", arguments);   }   function broadcastMsg (scope:String, methodName:String):PendingAdminCall {     return doRMI("broadcastMsg", arguments);   }   function changePswd (adminName:String, password:String,                        scope:String):PendingAdminCall {     return doRMI("changePswd", arguments);   }   public function gc (Void):PendingAdminCall {     return doRMI("gc");   }   public function getActiveInstances (Void):PendingAdminCall {     return doRMI("getActiveInstances");   }   public function getAdaptors (Void):PendingAdminCall {     return doRMI("getAdaptors");   }   public function getAdminContext (Void):PendingAdminCall {     return doRMI("getAdminContext");   }   public function getApps (Void):PendingAdminCall {     return doRMI("getApps");   }   public function getAppStats (applicationName:String):PendingAdminCall {     return doRMI("getAppStats", arguments);   }   public function getConfig (key:String, scope:String):PendingAdminCall {     return doRMI("getConfig", arguments);   }   public function getInstanceStats (instanceName:String):PendingAdminCall {     return doRMI("getInstanceStats", arguments);   }   public function getIOStats (Void):PendingAdminCall {     return doRMI("getIOStats");   }   public function getLicenseInfo (Void):PendingAdminCall {     return doRMI("getLicenseInfo");   }   public function getLiveStreams (instanceName:String):PendingAdminCall {     return doRMI("getLiveStreams", arguments);   }   public function getLiveStreamStats (instanceName:String,                                       streamName:String):PendingAdminCall {     return doRMI("getLiveStreamStats", arguments);   }   public function getMsgCacheStats ( ):PendingAdminCall {     return doRMI("getMsgCacheStats");   }   public function getNetStreams (instanceName:String):PendingAdminCall {     return doRMI("getNetStreams", arguments);   }   public function getNetStreamStats (instanceName:String,                                      streamName:String):PendingAdminCall {     return doRMI("getNetStreamStats", arguments);   }   public function getScriptStats (instanceName:String):PendingAdminCall {     return doRMI("getScriptStats", arguments);   }   public function getServerStats ( ):PendingAdminCall {     return doRMI("getServerStats");   }   public function getSharedObjects (instanceName:String):PendingAdminCall {     return doRMI("getSharedObjects", arguments);   }   public function getSharedObjectStats (instanceName:String,                                          sharedObjectName:String):PendingAdminCall {     return doRMI("getSharedObjectStats", arguments);   }   public function getUsers (instanceName:String):PendingAdminCall {     return doRMI("getUsers", arguments);   }   public function getUserStats (instanceName:String,                                  userID:String):PendingAdminCall {     return doRMI("getUserStats", arguments);   }   public function getVHosts (adaptorName):PendingAdminCall {     return doRMI("getVHosts", arguments);   }   public function ping ( ):PendingAdminCall {     return doRMI("ping");   }   public function getVHostStats (adaptorName:String,                                  vHostName:String):PendingAdminCall {     return doRMI("getVHostStats", arguments);   }   public function reloadApp (instanceName:String):PendingAdminCall {     return doRMI("reloadApp", arguments);   }   public function removeAdmin (adminName:String, scope:String):PendingAdminCall {     return doRMI("removeAdmin", arguments);   }   public function removeApp (applicationName:String):PendingAdminCall {     return doRMI("removeApp", arguments);   }   public function restartVHost (scope:String):PendingAdminCall {     return doRMI("restartVHost", arguments);   }   public function setConfig (key:String, value:String,                              scope:String):PendingAdminCall {     return doRMI("setConfig", arguments);   }   public function startServer (type:String):PendingAdminCall {     return doRMI("startServer", arguments);   }   public function startVHost (vHostName:String):PendingAdminCall {     return doRMI("startVHost", arguments);   }   public function stopServer (type:String):PendingAdminCall {     return doRMI("stopServer", arguments);   }   public function stopVHost (vHostName:String):PendingAdminCall {     return doRMI("stopVHost", arguments);   }   public function unloadApp (instanceName:String):PendingAdminCall {     return doRMI("unloadApp", arguments);   }   private function doRMI (aname, argsCol):PendingAdminCall {     if (argsCol == undefined) argsCol = new Array( );     var pc:PendingAdminCall = new PendingAdminCall(aname);     argsCol.unshift(pc);     argsCol.unshift(aname);     __adminConn.call.apply(__adminConn, argsCol);     return pc;   } } 

To gain access to the simplified API, you must first construct an FCSAdminConnector instance and pass that connection to the FCSAdminAdaptor constructor as shown in Example 10-5; this creates a new instance of the FCSAdminAdaptor class on which you can invoke methods of the Server Management API.

Example 10-5. Constructing the FCSAdminAdaptor Instance
 import com.oreilly.pfcs.admin.FCSAdminAdaptor; import com.oreilly.pfcs.admin.FCSAdminConnector; listener = new Object( ); listener.connect = function (eo) {   //   this   is the   FCSAdminConnector   instance stored in   adminConn   _global.adminAPI = new FCSAdminAdaptor(this); // Create the API adaptor. }; listener.fault = function (eo) {   trace("The connection attempt was unsuccessful"); }; adminConn = new FCSAdminConnector ("   www.yourhost.com   ",                   "1111",  "username", "password", listener); adminConn.connect( ); 

To execute a method of the API, you call the method directly on the instance of the FCSAdminAdaptor . The method will then return a PendingAdminCall object as the result. Here, we call the getApps( ) method on the _global.adminAPI , which is an FCSAdminAdaptor instance we created in Example 10-5.

 var pendingCall:PendingAdminCall = _global.adminAPI.getApps(  ); 

The PendingAdminCall object is your way of receiving the results from the Admin Service. The PendingAdminCall class internally defines the onResult( ) method for you and tests whether the method invocation was successful. If the method call was a success, the instance will dispatch a result event and pass on the returned data from the Admin Service. If the method call failed, the instance will dispatch a fault event and pass along the status code from the Admin Service. This saves time writing error handling tests for each method invocation so your onResult( ) handlers do not end up looking like this:

 response.onResult = function (result) {   if (result.code == "NetConnection.Call.Failed"        result.code == "NetConnection.Admin.CommandFailed"        result.code == "NetConnection.Call.BadValue") {     // Body to handle failure   } else {     // Body to handle success   } }; 

You can register a listener for the result and fault events with the addEventListener( ) method:

 listener = new Object(  ); listener.result = function (resObj) {   // Handle the results passed in   resObj   } listener.fault = function (errObj) {   // Handle the error passed in   errObj   } pendingCall.addEventListener("result", listener); pendingCall.addEventListener("fault", listener); 

However, the PendingAdminCall object already has a listener attached as the responder property. The listener is already registered to receive both the result and fault events. It is up to you to define the method that handles those events by overriding the result( ) and fault( ) methods of that responder object as follows :

 pendingCall.responder.result = function (resObj) {   // Handle the results }; pendingCall.responder.fault = function (errObj) {   // Handle the error }; 

Example 10-6 illustrates how to execute a Server Management API method with the FCSAdminAdaptor class and handle the expected results using the PendingAdminCall object and the default listener in the responder property.

Example 10-6. Executing an API method
 // Using the same connection and initialization code from Example 10-5... import com.oreilly.pfcs.admin.PendingAdminCall; // Make a call on the   _global.adminAPI   instance created in Example 10-5. var pendingCall:PendingAdminCall = _global.adminAPI.getApps( ); // Handler for successful attempt. pendingCall.responder.result = function (result) {   // Handle the results here } // Handler for failed attempt. pendingCall.responder.fault = function (result) {   // Handle the error here. } 

The FCSAdminAdaptor and the PendingAdminCall classes provide a framework to execute methods of the Server Management API and handle the resulting data and errors. Using these classes will result in writing less code while making the code more readable.

Now that we have discussed how to use these tools, let's discuss the different Server Management API methods that we can call.

10.2.1. Application Methods

The application-related methods of the Server Management API allow you to obtain a list of and statistics on installed applications, add an application directory, and delete an application. The application- related methods are:

getApps( )
getAppStats(applicationName)
addApp(applicationName)
removeApp(applicationName)

Example 10-7 illustrates how to execute the getApps( ) method and map the results to a List component.

Example 10-7. Using the getApps( ) method
 import com.oreilly.pfcs.admin.PendingAdminCall; // Using the same adminAPI object from Example 10-5... var appsCall:PendingAdminCall = adminAPI.getApps( ); appsCall.responder.result = function (res) {   // This is the list of installed applications.   _root.appsList.dataProvider = res.data; }; 

Once you have the list of installed applications, you can use that information to gather the statistics for each one or delete one of the applications. If you are using a List component to display the applications, you can set the component's dataProvider property to the data property of the result because the List component will accept an array of strings as the dataProvider , which is exactly what the Admin Service returns as the data property. You can access the selected application name with the List instance's selectedItem property. (A similar operation is performed in Example 10-9.) Example 10-8 creates a listener for the change event broadcast by the List component and retrieves the statistics for the selected application.

Example 10-8. Using the getAppStats( ) method
 function change (event) {   var target = event.target;   var appName = target.selectedItem;   var appStatsCall:PendingAdminCall = adminAPI.getAppStats(appName);   appStatsCall.responder.result = function (res) {     for (var i in res.data) {       trace(i + " : " + res.data[i]);     }   }; } _root.appsList.addEventListener("change", this); 

The statistics returned by the getAppStats( ) method are cumulative for all of the instances of that application and are located in the data property of the result object. Sample output from the getAppStats( ) method follows. These are the many properties of the data object returned in the response:

 up_time : 804046 launch_time : Thu Nov 25 13:35:39 GMT-0600 2004 total_instances_unloaded : 5466 total_instances_loaded : 5495 rejected : 0 accepted : 44276 connected : 41 total_disconnects : 44235 total_connects : 44276 msg_dropped : 1812162 msg_out : 210880117 msg_in : 40181444 bytes_out : 16123434107 bytes_in : 2718399445 bw_out : 38080 bw_in : 3601 

The addApp( ) and removeApp( ) methods allow you to add and remove an application. The addApp( ) method will create a directory for an application. Since no application files are required for a FlashCom application, the application will run even without a main.asc file. In the absence of a main.asc file to manage connection requests , the default behavior is to accept all connections and grant users unlimited read and write access to streams and shared object data. That would allow arbitrary users to upload any data or stream any audio or video from a client they've constructed that accesses your server. So use caution when using the Server Management API to add an application. If you do not write a main.asc file to the application directory (which isn't supported via the API), you may unwittingly expose the server to unwanted users. The removeApp( ) method deletes the specified application folder and all associated stream and shared object files contained within.

The addApp( ) method can create an empty application that effectively exposes your server. The removeApp( ) method does not offer any additional prompts, warnings, or chances to abort the operation, so consider it extremely dangerous. If the integrity of the Admin Service is ever compromised, this method would allow any attacker to destroy all of the application files. If a person knows the administrative username and password, he can execute any method of the Server Management API on the server or virtual hosts for which he has privileges. Superusers can do whatever they want to the entire server and any virtual host. Virtual host administrators can do whatever they want within the context of a virtual host. For these reasons, limit administrative access to only the most trusted and knowledgeable developers.


10.2.2. Instance Methods

The instance-related methods of the Server Management API provide the ability to monitor running instances and their users, shared objects, and streams. The list of instance methods is:

getActiveInstances( )
getInstanceStats(instanceName)
getLiveStreams(instanceName)
getLiveStreamStats(instanceName, streamName)
getNetStreams(instanceName)
getNetStreamStats(instanceName, streamId)
getScriptStats(instanceName)
getSharedObjects(instanceName)
getSharedObjectStats(instanceName, soName, persistence)
getUsers(instanceName)
getUserStats(instanceName, userId)
reloadApp(instanceName)
unloadApp(instanceName)

To start inspecting an instance of an application, you first need to get the list of all of the active instances. This can easily be done by calling the getActiveInstances( ) method:

 function listInstances (  ) {   var appsCall:PendingAdminCall = adminAPI.getActiveInstances(  );   appsCall.responder.result = function (res) {     _root.appsList.dataProvider = res.data;   }; } 

The results of the getActiveInstances( ) method contain a data property that is an array of all the instance names of the running applications. This array can then be bound to the dataProvider property of any list-based component.

Once you have a list of all of the available instances, you can use the List component to control the currently selected application. In that case, the selectedItem property of the List component can be used as the argument for the other instance methods to create a list of the shared objects, streams, and users for an item selected in the list. The instance name can also be used to unload and reload the application with the appropriate methods.

Other methods to drill down into specific statistics on shared objects, streams, and users are available. Like the other instance methods, these methods require that you either know the unique name representing the resource or you use one of the available methods to gather the available names of the resource to choose from and use in the API call. For example, if we wanted to further inspect the available information about a particular user , we would call getUsers( ) first and then use the list of connected users to call the getUserStats( ) method, as Example 10-9 illustrates.

Example 10-9. Using getUserStats( ) to display statistics for a user
 function listUsers (  ) {   var rCall:PendingAdminCall = adminAPI.getUsers(_root.appsList.selectedItem);   rCall.responder.result = function (res) {     _root.userList.dataProvider = res.data;   }; } function change (e) {   var rCall:PendingAdminCall = adminAPI.getUserStats(_root.appsList.selectedItem,                                    _root.userList.selectedItem);   rCall.responder.result = function (res) {     // Display the resulting data to the user somehow (not shown).   }; } _root.userList.addEventListener("change", this); /* Example results from the   getUserStats( )   method. stream_ids {     0 : 1 } msg_queue {     other : 0     video : 0     audio : 0     total_queues : 3 } protocol : rtmp connect_time : Fri Dec 3 10:37:08 GMT-0600 2004 msg_dropped : 0 msg_out : 921 msg_in : 14 bytes_out : 279434 bytes_in : 660 */ 

10.2.3. Server Methods

The set of methods supported by the Server Management API related to monitoring and controlling the server is thorough enough to be able to monitor the vital statistics of the server and bandwidth consumption. FlashCom Servers can also be configured to serve multiple-host environments, and the Server Management API has a collection of methods capable of handling a virtual host configuration. The list of server-related methods is as follows (items in square brackets are optional arguments):

broadcastMsg(scope, methodName [, arg1, ... argn]);
gc( )
getAdaptors( )
getAdminContext( )
getIOStats( )
getLicenseInfo( )
getMsgCacheStats( )
getServerStats( )
getVHosts( )
getVHostStats([adaptorName, vhostName])
ping( )
restartVHost([scope])
startServer(type)
startVHost(vhostName)
stopServer(type)
stopVHost(vhostName)

The server-related methods of the Server Management API are bound to a more strict security policy than the application- and instance-related methods. There are two levels of administrative access for the FlashCom Admin Service: server administrators and virtual host administrators. Server administrators have superuser access and are not restricted in any way. Virtual host administrators have the capability to manage only a single virtual host and cannot access any server-wide methods or execute methods on another virtual host.

10.2.3.1 broadcastMsg( )

The broadcastMsg( ) method is not documented in the official API documentation but is a powerful method that provides the mechanism to distribute a message to any user connected to the server. This method requires two arguments and can accept additional optional arguments to be supplied to the corresponding handler on the client side. The scope argument specifies the reach of the message. You can send a message to all connections to the server, to an adaptor, to a virtual host, to all instances of an application, or to a single instance of an application, depending on the scope parameter. The various possibilities for scope are:


"Server"

Send a message to the entire server.


" VHost "

Send a message to the virtual host that you are connected to.


"App: name "

Send a message to all instances of an application.


"App: name / instance "

Send a message to a single instance of an application.


"Adaptor"

Send a message to the adaptor to which you are connected.


"Adaptor: name "

Send a message to another adaptor.


"Adaptor: name /VHost: name "

Send a message to a virtual host on a different adaptor.


"Adaptor: name :VHost: name /App: name "

Send a message to an application on another virtual host.


"Adaptor: name :VHost: name /App: name / instanceName "

Send a message to an application instance on another virtual host.

The methodName argument, the second parameter sent to broadcastMsg( ) , specifies the method name to be executed on the client. The optional additional arguments represent the parameters that you want to pass to that method. The method definition in the connecting clients must be assigned to the NetConnection object used to connect to the FlashCom Server. Example 10-10 shows how to use broadcastMsg( ) from a client to send a message to all connected clients.

Example 10-10. broadcastMsg( ) example
 // Broadcasting code, invoked from the client to control the Admin Service. adminAPI.broadcastMsg("Server", "onAdminMessage", "message from admin"); // Reception code on the client. my_conn = new NetConnection( ); mY_conn.connect("rtmp://flashcomserver.yourdomain.com/app/instance"); my_conn.onAdminMessage = function (msg) {   trace("A message came from the Server Management API : " + msg); }; 

10.2.3.2 Other server-related methods

Most of the other server-related methods of the Server Management API provide a means to gather the statistics of the server. For example, the getServerStats( ) method returns a collection of data including the CPU and memory consumption of the FlashCom Server as well as the current and historical bandwidth use.

Like the instance-related methods, the server-related methods provide a way to inspect each adaptor and virtual host and provide methods to list the adaptors and virtual hosts configured on the server. The configuration options of the server allow you to have multiple adaptors and have multiple virtual hosts linked to each adaptor, forming a possibly complex tree of virtual hosts. In order to inspect a virtual host, you will first have to list the adaptors and choose the virtual host that is linked to that specific adaptor before you can survey the statistics for a single virtual host.

The server-related methods also provide the means to start and stop the entire FlashCom Server ( stopServer( ) ) or a virtual host ( stopVHost( ) ). These methods do not provide any opportunities to back out, so use them cautiously.


10.2.4. Configuration API Methods

The last group of methods in the Server Management API is used to configure the server. These methods provide a developer-level API to access the various .xml configuration files that control how the server operates.

Allowing a friendly GUI to these files is a convenient way to handle the server's configuration but is also very dangerous if the proper controls are not established to restrict intruders from accessing the interface. There are no safeguards or checks built into the API methods, so an unwanted change to a configuration file could be disastrous.


The configuration-related methods of the Server Management API are:

addAdmin(userName, password [, scope])
changePswd(userName, newPassword [, scope])
getConfig(key [, scope])
setConfig(key, value [, scope])

The addAdmin( ) method allows you to create additional username/password combinations to allow users to log into the Admin Service. The scope argument allows the ability to give a new administrator access to either the entire server by specifying "Server" or to a virtual host by specifying the path to the virtual host as " adaptorName/vhostName ". Administrators have access to all the API calls available for the server or virtual host to which they are granted access.

The changePswd( ) method changes the password of an existing administrative account without specifying the old password. The second parameter is the new password. Virtual host administrators can change only their own password.


The getConfig( ) and setConfig( ) methods are more complex; they provide direct access to the .xml configuration files. These methods should be considered very dangerous and probably should be left alone. The configuration files are easy to edit with a simple text editor. Keeping client access to remote configuration options to an absolute minimum will keep the FlashCom Server secure.



Programming Flash Communication Server
Programming Flash Communication Server
ISBN: 0596005040
EAN: 2147483647
Year: 2003
Pages: 203

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net