Moodle 2.0: AMF server

Moodle 2.0: AMF server

by Jérôme Mouneyrac -
Number of replies: 19
Zend framework and Adobe offer a nice solution (Zend_Amf) to make Flex communicate with PHP using AMF protocol. In order to make it works, the developer needs to create value objects on the PHP server side and on the Flex server side.

I'd like to implement a solution for Moodle and generate these PHP value objects for the PHP server side. It will be an optional work once SOAP and REST servers will be fully working. Any suggestion is welcome here.

If you have a look into the CVS Head you'll find an alpha AMF implementation that works with primary type (string, integer).
Average of ratings: Useful (1)
In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
Hi Jerome,

I am interested in working with the web services and particularly with the amf support in Moodle 2. I have some questions :

  • In order to try it out I'm guessing I can use some of the test clients in contrib/patches/dfws/client/ with the web service servers in Moodle HEAD??
  • Is the stuff in the contrib/patches/dfws/webservices all integrated into Moodle HEAD?
  • I can't see any test Flash client there, is there a client available to test the web services using amf?
Thanks for your time and this exciting contribution to Moodle!

Jamie
In reply to Jamie Pratt

Re: Moodle 2.0: AMF server

by Jérôme Mouneyrac -
Hi Jamie,
you're welcome to work on the Amf server smile
contrib/patches/dfws/client is outdated now. All is in the 'webservice' folder into HEAD.
I didn't commit my Flex client, because it is just a connection test: I didn't implement any authentication, the web service url is hard coded into the services-config.xml, and it doesn't support object.

I used Flex Builder to create the client. Here is my connection client code, if it can help to start:

main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

<mx:RemoteObject id="myservice"
showBusyCursor="true"
source="Moodle CLient"
destination="zend"
result="Alert.show(event.result.toString())">
</mx:RemoteObject>

<mx:Script>
<![CDATA[
import mx.controls.Alert;
var oneArray:Array = new Array("admin");
]]>
</mx:Script>

<mx:Button label="Call service" click="myservice.tmp_get_users(oneArray).toString"/>

</mx:Application>

Note: to test it, you'll have to change the tmp_get_users() function into user/external.php on the PHP side in order to return a string. Add return "Hello", at the beginning of this function.

services-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="zend-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="zend">
<channels>
<channel ref="zend-endpoint"/>
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="zend-endpoint"
class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://jerome.moodle.com/Moodle_HEAD/moodle/webservice/amf/server.php"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>

What I think we need to do:
1- we need to implement authentication call: it's about the same code than above, we call a method returning a generated Token (string). We just need to implement a mock authentication method on the PHP side. Petr will write all the authentication system for web services.
2- The web service URL needs to be moved from the services-config.xml into the main.mxml. We need to generate this URL with specific GET parameter (token + function location).
3- we need to support object communication. Object description should be into the webservice function docblock. I already wrote a function extracting the information. We would just need to generate the "Value object".

That's it smile
In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
Hi Jerome,

Thanks for your quick reply!

I am interested in helping out with the amf server implementation.

Will have a play with the web services servers on my local test server today.

Jamie
In reply to Jamie Pratt

Re: Moodle 2.0: AMF server

by Jérôme Mouneyrac -
This would be great Jamie smile We have very few feedback on them.

In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
Hi Jerome,

Have been playing with the amf server and it seems that it supports more than just the integer and string types, object and arrays are correctly passed.

I modified your code above and wrote this in moodleclient.mxml :
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:RemoteObject id="myservice"
showBusyCursor="true"
source="Moodle CLient"
destination="zend"
result="respondToResult(event.result);">
</mx:RemoteObject>
<mx:Script>
<![CDATA[
import mx.controls.Alert;
var oneArray:Array = new Array("admin");
function respondToResult(result:Object){
 textarea1.text = describeType(result);
 for (var els:String in result){
 for (var props:String in result[els]){
 textarea1.text += "result["+els+"]["+props+"] = "+result[els][props]+"("+typeof(result[els][props])+")"+"\n";
 }
 }
}
]]>
</mx:Script>
<mx:Button label="Call service" click="myservice.tmp_get_users(oneArray).toString"/>
<mx:TextArea id="textarea1" width="600" height="400" x="0" y="30"/>
</mx:Application>
This correctly was able to access the properties of the returned object within the array and output the following :

<type name="Array" base="Object" isDynamic="true" isFinal="false" isStatic="false">
 <extendsClass type="Object"/>
 <accessor name="length" access="readwrite" type="uint" declaredBy="Array"/>
</type>result[0][confirmed] = 1(string)
result[0][description] = (string)
result[0][theme] = (string)
result[0][email] = me@nospam.org(string)
result[0][auth] = manual(string)
result[0][country] = TH(string)
result[0][timezone] = 99(string)
result[0][mailformat] = 1(string)
result[0][id] = 2(string)
result[0][firstname] = Admin(string)
result[0][lang] = en_utf8(string)
result[0][city] = Chiang Mai(string)
result[0][username] = admin(string)
result[0][idnumber] = (string)
result[0][lastname] = User(string)
result[0][emailstop] = 0(string)
In reply to Jamie Pratt

Re: Moodle 2.0: AMF server

by Jérôme Mouneyrac -
Hi Jamie,
That's a really great news! cool

Can you write a test Flex/Flash client using all the current web service functions into user_external class (get/create/update/delete) in HEAD? If you can call bulk operations for each of them it would be a cool test.





In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
Hi Jerome,

Found that the following patch was needed in order to get the amf server to return error messages to the client :

Index: webservice/amf/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/webservice/amf/lib.php,v
retrieving revision 1.3
diff -u -r1.3 lib.php
--- webservice/amf/lib.php 12 Mar 2009 09:03:47 -0000 1.3
+++ webservice/amf/lib.php 21 Mar 2009 08:22:55 -0000
@@ -54,6 +54,7 @@
 
 /// run the Zend AMF server
 $server = new Zend_Amf_Server();
+ $server->setProduction(false);
 $server->setClass($classpath."_external");
 $response = $server->handle();
 echo $response;
Wonder if we could include a switch so that we could turn the debug output on or off to the admin interface? Would other servers need this functionality as well? Servers could be off, on with debug messages returned to client or on in production mode.

Jamie

In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
I committed a test client for batch operations exposed by user/external.php

You can try it out by checking out the latest version of Moodle HEAD and going to {rooturl}/webservice/amf/testclient/
In reply to Jamie Pratt

Re: Moodle 2.0: AMF server

by Jérôme Mouneyrac -
Awesome Jamie. I tested, it works fine. That's great to see it running smile
How long did it take you to do it?
In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
It took more than a day actually. This is my first Flex app so it took me some time to find my way around. I think though that potentially some very powerful user interfaces could be built very quickly using Flex to connect to Moodle web services. There are loads of great interactive charting facilities available and things like forms, data grids and tree views are very easy to create.
In reply to Jamie Pratt

Re: Moodle 2.0: AMF server

by Jérôme Mouneyrac -
Good to know. One day sounds very good for this first client user interface. It took me half a day to make the client speaks with the server.

We would need to integrate some authentication to your client. We could first call tmp_get_token($params) from the ws_authentication class. Then we add the token to the url + the ws function location (user in this case).

I'm not sure how to do it, but I know we can declare the server url into the mxml file (not in the service config file). I had a quick look I think it's what your client do.
The swf file should first call the authentication function then construct dynamically the amfurl (passing token + function location as GET param).

What do you think about that?
In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
As I said here "Moodle 2.0 : some questions that need to be considered if we want to have web services available for client side Flash / Java / js etc"

  • actually the web services are already authenticating themselves using regular http cookies - the same session data is available as for other Moodle scripts.
  • probably we should use the 'token' you refer to instead of cookies.
  • but I think that we need to call a function in php when we generate the page that embeds the Flash and then pass the token into the client side app through the html Flashvars tag just as we have passed in the url to the amf server. The client app should not have to log in as the user is logged in already.
In reply to Jamie Pratt

Re: Moodle 2.0: AMF server

by Jérôme Mouneyrac -
I don't think an embedded client app should behave differently than a not embedded client app. I mean when an app uses web services, this app is an external app. It should not bypass the "usual" ws authentication scheme even if it's embedded into Moodle.
Let's have other opinion smile
I think you can contact Petr about that.

Or maybe give an example of something we can not do without some information into the HTML. I can't see one.
In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
Hi Jerome,

To summarize my thinking :

  • if (!every time a user loads a page with an embedded Flash movie or other code that uses web services you want the user to have to enter their username and password again){
    • we must have some other way to authenticate the user.
    • if (we don't use cookies){
      • we must use another type of token. We can pass this into the Flash movie using html.
    • }
  • } else {
    • every Flash object that uses web services is going to be a pain.
  • }
smile

Jamie
In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Penny Leach -
Hey Jerome

I had to implement AMF for a project here... it's on top of 1.9 of course, but it uses Zend AMF.

Anyway, I wrote a small Introspection class, that reads in from $CFG a list of directories that have AMF blessed service files in them.

Each class that wants its methods exposed as AMF services must implement a simple Interface (no contract methods, just so the Introspection stuff can differentiate which ones to use).

For each of the services it finds, it uses php5's Reflection stuff to find the public methods and their arguments, and returns them.

Then, my awesome colleague Jordi wrote a flash client (which he's releasing under the WTFPL) which connects to local/amf/server.php and by default calls the getMethods method on the Introspection class, and then offers an interface to make simple method calls and prints the result.

You can check this out here:

http://git.penny.liip.ch/?p=moodle.git;a=tree;f=local/amf;hb=refs/heads/mdl19-common

which wants to go inside local/ in a normal moodle 1.9 checkout.

At the moment I am using this successfully to connect to a custom build question type that just records scores and state from a flash game.

Since the flash client runs in the browser, when it makes AMF connections, it sends the same cookies as the normal request, so it runs as the logged in user.

You could use it to test some of the Moodle 2.0 stuff you're doing, except that it must use class methods of course, you can't use it to test functions (but you're free to modify it of course). You just have to:

make a amfservices/ directory somewhere and set $CFG->amf_servicepaths (this can be an array)

Eg: mine looks like:

$CFG->amf_introspection = true;
$CFG->amf_servicepaths = $CFG->dirroot . '/question/type/externalflash/services/';

make a file in that directory and create a new class


class something implements AmfService {
public method someService() {
}
public method someotherService($foo, $bar) {
}
}

The only gotchas are that class state doesn't really get kept, and constructors can't take arguments.... essentially method calls are treated like static - so make sure they take all the arguments they need and don't expect state to be kept between calls.
In reply to Penny Leach

Re: Moodle 2.0: AMF server

by Penny Leach -
Just an update - the flash side has been pushed into its own git repository, publicly available here:

http://git.penny.liip.ch/?p=amftester.git;a=summary

which can be cloned like

git clone http://git.penny.liip.ch/git/amftester.git
In reply to Penny Leach

Re: Moodle 2.0: AMF server

by Jérôme Mouneyrac -
thanks Penny. I have a look at it.
In reply to Jérôme Mouneyrac

Re: Moodle 2.0: AMF server

by Jamie Pratt -
Hi,

Have modified Jordi's AMF web service browser to use as a test client. Quoting from what I wrote here on the tracker where you can find a patch to get the service browser working in Moodle HEAD:

"Have created a new amf service browser client. You can use a user's token or a username and password to log in to the client. A patch that applies to the latest version of Moodle HEAD is attached.

I have modified the zend server so that it supplies details of all the available methods for the logged in user. It interprets the data in the class dynamically generated by Moodle and passes all the data to Flash through an extra remote service method. The client displays form entry fields for each argument and arguments for the method can be entered using JSON syntax ie. use {} to enclose an object and [] to enclose an array."


Jamie