[Go back to tutorial home](tutorial.md) # Step 6: handle multi-user with presence *(Estimated time: 1h30mn)* What if the Pawn activity could be played by multiple players at the same time? After all, it's a logical feature for a game. That's what we will doing in this step. ### Connect to a server From the begining of this tutorial we use Sugarizer stand alone. All HTML and JavaScript are run locallly and do not depend of external code. For this step however, because we need to have communication between multiple clients, we will need a Sugarizer Server too. The Sugarizer Server is a backend that provide connection features to Sugarizer Apps. You could install a Sugarizer Server locally following instruction [here](https://github.com/llaske/sugarizer-server/blob/master/README.md) or use the test server available on [https://dev.sugarizer.org](https://dev.sugarizer.org). To see if you're connected to a server, click on the Neighborhood view - the icon with multiple dot - on the Sugarizer toolbar. Because you're not connected yet, here is the message you will see: ![](images/tutorial_step6_1.png) To connect to a server, click on the button to access to settings, then to "About my server" icon to display the server settings window. ![](images/tutorial_step6_2.png) Check the connected box and type the URL of your server, may be `http://localhost:8080` (if you've installed your own server) or `https://dev.sugarizer.org`. You will have to choose few images as password, then click on restart. If everything is right, you will see now the full Neighborhood view. ![](images/tutorial_step6_3.png) And you're now connected. ### What is meant by sharing an instance Suppose that Michaël, a user connected on the same server as you wants to Chat. He will launch the Chat activity. ![](images/tutorial_step6_4.png) ***Tip***: *To connect to Sugarizer with two users on the same computer, open a new "in private" browser window. So you will be able to create a new user. It's what we've done here and what we'll do below to simulate the user Michaël.* Then, once the activity is open, he can share the activity by clicking on the toolbar Neighborhood button in the Network palette. It's a way for the user to say: *"I want to share my activity on the network"*. ![](images/tutorial_step6_5.png) From your Neighborhood view you will see the icon of the activity suddenly appear near the Michaël's icon. Just pass the mouse on the activity icon and click the Join menu and you will be able to join Michaël. ![](images/tutorial_step6_6.png). The Chat activity will open on your side using Michaël colors, and the Chat can start between users. ![](images/tutorial_step6_7.png) Easy, isn't it ? And thanks to the unique Sugarizer presence framework, do the same thing for our Pawn activity will not be so complex. ### Add the presence palette All activities that could be shared have to include the Network palette in its toolbar. Like in the Chat activity it's the way for user to share its current work and allow other users to join. Let's do it in Pawn activity. First start by adding a button for the network in the `index.html` file. We add it just after the existing `add` button. We will now define this new button in the `css/activity.css` file. We define also the two buttons included in the palette. Note that all icons are already included in the `lib/sugar-web/graphics/icons/actions` directory. #main-toolbar #network-button { background-image: url(../lib/sugar-web/graphics/icons/actions/zoom-home.svg); } #private-button { background-image: url(../lib/sugar-web/graphics/icons/actions/zoom-home.svg); width: 47px; height: 47px; margin: 4px 2px; color: white; color: transparent; background-color: transparent; background-position: center; background-repeat: no-repeat; background-size: contain; border: 0; border-radius: 5.5px; } #shared-button { background-image: url(../lib/sugar-web/graphics/icons/actions/zoom-neighborhood.svg); width: 47px; height: 47px; margin: 4px 2px; color: white; color: transparent; background-color: transparent; background-position: center; background-repeat: no-repeat; background-size: contain; border: 0; border-radius: 5.5px; } The name "palette" refer to a popup menu in the toolbar. When the user click on the toolbar icon, the popup appear and display items inside - most often other buttons. To handle this feature Sugar-Web expose a Palette library and, more precisely, a PresencePalette too. As usual, to integrate this library, we will update the dependancies list at the first line of `activity/activity.js`. define(["sugar-web/activity/activity", "sugar-web/env", "sugar-web/graphics/icon", "webL10n","sugar-web/graphics/presencepalette"], function (activity, env, icon, webL10n, presencepalette) { This palette must be initialized in the code. You just have to call the PresencePalette constructor with the toolbar element. So add this line in the end of the require function of `activity/activity.js`: // Link presence palette var palette = new presencepalette.PresencePalette(document.getElementById("network-button"), undefined); Let's test the result by launching our Pawn activity. ![](images/tutorial_step6_8.png) The new Network button and palette is here. We now have to implement the magic inside. ### How presence works Before further implementation let's pause to explain what exactly Sugarizer presence framework is and what it does. The presence framework provide a real time communication between a set of clients. To do that the framework is based on the [publish/subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) pattern. Every client could create one or more **topics**. Other clients could **subscribe** to these topics and everyone could **publish** messages on a topic. When a message is published on a topic, only clients connected to this topic receive the message. In the context of Sugarizer, clients are Sugarizer App/WebApp connected to the Server. One topic is a shared activity. The Sugarizer Server is responsible to keep the list of topics and clients and dispatch messages to clients subscribed to topics. So the server is the central point and in fact, clients communicate only with the server. Let's take an example. Michaël, Lionel and Bastien are three users connected to the same Sugarizer Server. Michaël share a Chat activity. Lionel decide to join the activity. Bastien share its own Paint activity but he's alone on the activity. ![](images/tutorial_step6_9.png) The server know that two activities are shared: one Chat activity with Michaël and Lionel as subscribers, one Paint activity with only Bastien as subscriber. If Michaël post a message for the Chat activity, the server will automatically send back the message to Michaël and Lionel but not to Bastien. Easy to understand isn't it? ### Share the instance Now, let's update our Pawn activity to integrate presence. Start first by handling the click on the Share button. We will add a listener to handle `shared` event of the palette in the `activity/activity.js` file. // Link presence palette var presence = null; var palette = new presencepalette.PresencePalette(document.getElementById("network-button"), undefined); palette.addEventListener('shared', function() { palette.popDown(); console.log("Want to share"); presence = activity.getPresenceObject(function(error, network) { if (error) { console.log("Sharing error"); return; } network.createSharedActivity('org.sugarlabs.Pawn', function(groupId) { console.log("Activity shared"); }); network.onDataReceived(onNetworkDataReceived); }); }); In this listener, we have to retrieve the presence object. As usual it's exposed by the `activity` object. So you just need a call to `activity.getPresenceObject` method. If everything goes well, you will retrieve a presence object. That's a way to indicate that you're connected to a server. The `createSharedActivity` on this object allow you to create a new shared activity. You must pass as parameter the type of the activity so Sugarizer could display the right icon in the neighborhood view. Then you receive the unique identifier of the share in the `groupId` parameter of the callback. Finally we register a callback to handle message received, with a call to `onDataReceived` method. We will have a look on this callback later. Now that our activity is shared, we have to slightly update the Plus button listener. Because now we should notify other users when a new pawn is played. Here's how the new listener will look like: // Handle click on add document.getElementById("add-button").addEventListener('click', function (event) { pawns.push(currentenv.user.colorvalue); drawPawns(); document.getElementById("user").innerHTML = "