6.10 Buddy Lists 2.0

With the release of SmartFoxServer 1.6 the buddy-list system has been greatly enhanced with new features that help integrating an instant messaging systems in your multi-player applications.

Among the new functionalities that were introduced there are:

 

» Buddy Variables

offline variables example

Buddy variables allow to define custom states for each buddy: a typical usage is to set one variable with the current status of the buddy (e.g. available, occupied, invisible etc...). This feature already existed in previous versions of the server ( see SmartMessenger example ) but it didn't allow to store these values. Buddy variables only existed during the user session.

The Buddy List 2.0 framework not only adds the ability to persist all buddy variables but it also introduces off-line buddy variables.

While regular variables become "active" when its owner comes online in the system, off-line variables are loaded regardless the user is online or not, providing further informations for each entry in the buddy-list.
A typical usage for these variables is to define an image, a status or additional informations such as country, email, rank etc...

We established a simple new convention where each buddy variable starting with a $ symbol is treated as an off-line variable, so it will available for all clients regardless that the buddy is online or not.

This is a simple code example:

var buddyVariables:Object = {}
buddyVariables.$rank = 5
buddyVariables.$country = "Italy"
buddyVariables.$image = "animal.png"

smartFox.setBuddyVariables( buddyVariables )
	

 

» Enhanced security options

Another important aspect with buddy-list based application is preventing unwanted messages, flooding and being able to selectively disable annoying users.

The Buddy List 2.0 adds the following functionalities:

  1. Block / unblock users in the buddy list: when a user is blocked he will continue to see you in his buddy list but he won't be able to send any message.

  2. Buddy list requests: each time a user adds a buddy to his list the latter will receive a notification and he will be able to accept or refuse the request.
    Example:
  3. Mutual add buddy: when this feature is turned on both users involved in a "add buddy transaction" will be added to their respective buddy list after the target user as accepted the request.
    Example:
  4. Mutual remove buddy: when one of the two users removes a buddy from his list the same will happen the buddy user.
    Example:

 

» What's new in the API

While server side there are a lot of new things going on, on the client side the Flash/Flex API handle most of the new features transparently. Developers won't find big changes in the new API and all the old pre-1.6 applications will keep working without a hitch.

The API now expose the following new items, related with buddy list management:

The server side framework has also been enriched with the corresponding client side method: addBuddy, removeBuddy, setBuddyVariables, setBuddyBlockStatus, requestAddBuddyPermission. This will enable developers to take full control on buddy list management in their server side logic.

 

» Custom Persistence classes

The new Buddy List 2.0 doesn't use a file-based storage system anymore. Instead, it uses an internal high-performance database which provides better speed and security.

If the way in which this is handled still doesn't match your requirements, we also provide the ability to write your own Java classes that are responsible for loading/saving all buddy lists within a specific Zone. ( Each Zone can specify its own "buddy list persister" )

The interface for a Buddy List persister class is pretty simple:

public class MyPersister extends AbstractBuddyPersister
{
	@Override
	public void init( Object param ) { }

	@Override
	public void destroy( Object param )	{ }

	@Override
	public StorableBuddyList loadList( String userName ) { }

	@Override
	public boolean saveList( String userName, StorableBuddyList buddyList ) { }
	
	@Override
	public Map<String, String> getOfflineVariables( String userName ) { }

	@Override
	public boolean removeOfflineBuddy( String owner, String buddyName ) { }
}
	

Let's go through each method and see what they are used for:

Here's an example of a very simple persistence class:

package test.persister;

import it.gotoandplay.smartfoxserver.SmartFoxServer;
import it.gotoandplay.smartfoxserver.data.buddylist.StorableBuddyItem;
import it.gotoandplay.smartfoxserver.data.buddylist.StorableBuddyList;
import it.gotoandplay.smartfoxserver.data.buddylist.persistence.AbstractBuddyPersister;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class SFSCustomBuddyPersiter extends AbstractBuddyPersister 
{

	@Override
	public void init(Object param) 
	{
		info("CUSTOM Persister initialized.");
	}

	@Override
	public void destroy(Object param) 
	{
		info("CUSTOM Persister shutting down.");
	}

	@Override
	public StorableBuddyList loadList(String userName) 
	{
		Random rnd = new Random();

		StorableBuddyList theList = new StorableBuddyList(userName);
		theList.buddies = new ArrayList<StorableBuddyItem>();

		for (int i = 0; i < 10; i++)
		{
			StorableBuddyItem buddyItem = new StorableBuddyItem("Buddy__" + rnd.nextInt(1000));
			//buddyItem.isBlocked = false;

			theList.buddies.add(buddyItem);
		}

		info("Buddy List loaded for user: " + userName);
		return theList;
	}

	@Override
	public boolean saveList(String userName, StorableBuddyList buddyList) 
	{
		// TODO Auto-generated method stub
		info("Saving buddy list for user: " + userName);
		for (StorableBuddyItem buddyItem : buddyList.buddies)
		{
			System.out.println("\t> " + buddyItem.name);
		}

		return true;
	}

	@Override
	public Map<String, String> getOfflineVariables(String userName) 
	{
		info("getOfflineVariables called for user: " + userName);
		return new HashMap<String, String>();
	}

	@Override
	public boolean removeOfflineBuddy(String owner, String buddyName) 
	{
		// Called when removing a buddy that is currently offline
		// and the mutualRemove is active 

		return true;
	}

	private void info(String msg)
	{
		SmartFoxServer.log.info(msg);
	}
}

In the loadList() method we create a fake buddy list by generating random user names, just to give you an idea of how this should work. When you deploy the persister class and test it with the provided client side example (See tutorial 8.16) you will notice that each user will load a buddy list of 10 random names.

Similarly, in the saveList() method, we simply go through the buddy list elements in the passed list and output each buddy name. It will be the developer's job to fill the code with the actual logic that stores data to his preferred location and format. Possible solutions would include local or remote files, databases, web services etc..

Finally, when the class is complete, you will need to deploy and activate it.

NOTE: One last note about thread safety: when coding your buddy-list persister classes, you should always assume that you're dealing with a multi-threaded environment and make the appropriate choices in order to ensure thread safety for all objects that could be accessed concurrently.

» Learn more

You can find more details about the new BuddyList 2.0 by checking these documents:

 


  doc index