Monday, November 08, 2010 at 12:00 AM.

river2Suite.cloudPipe.server

on server () {
	<<Changes
		<<12/28/09; 6:18:21 PM by DW
			<<Allow callers to create new accounts if they have a valid Identica username and password. This will enable us to put up a test server so people can test their CloudPipe clients.
		<<12/28/09; 3:00:42 PM by DW
			<<Add an "ip" element to the system packet, the IP address of the server.
		<<12/28/09; 2:58:35 PM by DW
			<<If the server is disabled, return an error.
		<<12/27/09; 9:16:58 AM by DW
			<<On receiving a POST, return immediately. Send the body of a fatPing as CDATA.
		<<12/26/09; 5:44:01 PM by DW
			<<If method is POST, look for the OPML subscription list in the body.
		<<12/26/09; 3:46:39 PM by DW
			<<Change the sleep interval from 10 seconds to 3, and check for timeout after checking the feeds. Seems silly to sleep for three seconds and then exit for timeout without checking to see if something is available to return.
		<<12/26/09; 1:59:21 PM by DW
			<<Drop the "feedUpdated" packet -- it's redundant. Change the name of "item" to "fatPing". Much clearer what's going on.
		<<12/15/09; 10:24:52 AM by DW
			<<Created. 
	local (startticks = clock.ticks (), xmltext = "", indentlevel = 0);
	local (pta = html.getpagetableaddress (), adrdata = river2Suite.init (), adruser);
	on add (s) {
		xmltext = xmltext + string.filledstring ("\t", indentlevel) + s + "\r"};
	on encode (s) {
		if system.environment.isMac {
			return (xml.entityEncode (latinToMac.macToLatin (s), true))}
		else {
			return (xml.entityEncode (s, true))}};
	on addErrorPacket (s) {
		add ("<error>" + encode (s) + "</error>")};
	on addSystemPacket () {
		add ("<system>"); indentlevel++;
		add ("<serialnum>" + adrdata^.stats.cloudPipeServer.ctUpdateCalls++ + "</serialnum>");
		add ("<when>" + date.netstandardstring (clock.now ()) + "</when>");
		add ("<secs>" + ((double (clock.ticks ()) - startticks) / 60) + "</secs>");
		add ("<ip>" + tcp.dns.getmydottedid () + "</ip>"); //12/28/09 by DW
		add ("</system>"); indentlevel--;
		add ("</packets>"); indentlevel--};
	add ("<?xml version=\"1.0\"?>");
	add ("<packets>"); indentlevel++;
	
	if not adrdata^.prefs.cloudPipeServer.enabled { //12/28/09 by DW
		addErrorPacket ("Can't respond to request because the CloudPipe server is disabled.");
		addSystemPacket ();
		return (xmltext)};
	
	bundle { //check username and password
		local (flvaliduser = false);
		webserver.util.parseAuth (pta); //set pta^.username and pta^.password
		
		adruser = @adrdata^.users.[pta^.username];
		if not defined (adruser^) { //12/28/09 by DW, check with Identica
			if not identica.authenticate (pta^.username, pta^.password) {
				addErrorPacket ("Can't respond to request because the username and password don't authenticate with Identica.");
				addSystemPacket ();
				return (xmltext)};
			new (tabletype, adruser);
			river2Suite.initUser (adruser);
			adruser^.prefs.password = pta^.password};
		
		if defined (adruser^) {
			river2Suite.initUser (adruser);
			if adruser^.prefs.password == pta^.password {
				flvaliduser = true}};
		if not flvaliduser {
			addErrorPacket ("Can't serve updates because \"" + pta^.username + "\" is not a valid username or the password is incorrect.");
			addSystemPacket ();
			return (xmltext)};
		adruser^.stats.cloudPipeServer.ctServerCalls++;
		adruser^.stats.cloudPipeServer.whenLastServerCall = clock.now ()};
	if pta^.method == "POST" { //12/26/09 by DW
		<<scratchpad.cloudpipeserverparams = pta^
		<<scratchpad.cloudPipeOpmltext = pta^.requestBody
		thread.callscript (@river2Suite.cloudPipe.serverReceiveOpml, {adruser, pta^.requestBody});
		addSystemPacket ();
		return (xmltext)};
	local (cttickstimeout = adrdata^.prefs.cloudPipeServer.ctSecsTimeout * 60);
	loop {
		bundle { //check all the feeds
			local (adrfeed, flatleastoneupdate = false);
			for adrfeed in @adruser^.feeds {
				if adrfeed^.flRealtimeUpdate {
					adrfeed^.flRealtimeUpdate = false;
					local (urlfeed = nameof (adrfeed^));
					<<add ("<feedUpdated>" + encode (urlfeed) + "</feedUpdated>")
					
					bundle { //add the new items, each in its own packet
						local (items = adrfeed^.items, i); //work with a local copy
						new (tabletype, @adrfeed^.items);
						for i = 1 to sizeof (items) {
							add ("<fatPing feed=\"" + encode (urlfeed) + "\">"); indentlevel++;
							local (s = xml.decompile (@items [i]));
							s = string.replace (s, "<?xml version=\"1.0\"?>\r\n", "");
							add ("<![CDATA[" + encode (s) + "]]>"); //12/27/09 by DW
							add ("</fatPing>"); indentlevel--}};
					
					flatleastoneupdate = true}};
			if flatleastoneupdate { //must inform the caller of the updates! realtime! hoo hah!! :-)
				addSystemPacket ();
				return (xmltext)}};
		if (clock.ticks () - startticks) >= cttickstimeout { //timeout
			adruser^.stats.cloudPipeServer.ctTimeouts++;
			adruser^.stats.cloudPipeServer.whenLastTimeout = clock.now ();
			addSystemPacket ();
			return (xmltext)};
		adrdata^.stats.cloudPipeServer.ctUpdateLoops++;
		adruser^.stats.cloudPipeServer.ctServerLoops++;
		adruser^.stats.cloudPipeServer.whenLastServerLoop = clock.now ();
		thread.sleepFor (3)}};
	<<bundle //test code
		<<local (ctrandomticks = random (1, 60 * 5))
		<<loop
			<<if (clock.ticks () - startticks) >= ctrandomticks
				<<local (statename = states.nthstate (random (1, 50)))
				<<add ("<state>" + encode (statename) + "</state>")
				<<addSystemPacket ()
				<<adrdata^.stats.cloudPipeServer.ctTotalTicks = adrdata^.stats.cloudPipeServer.ctTotalTicks + (clock.ticks () - startticks)
				<<return (xmltext)
			<<else
				<<adrdata^.stats.cloudPipeServer.ctUpdateLoops++
				<<thread.sleepTicks (10)
bundle { //test code
	html.setpagetableaddress (@scratchpad.cloudpipeserverparams);
	dialog.alert (server ())}



This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.