Sinds enkele dagen ondersteunt de presence server ook het versturen van SMSjes als er geen activiteit is op de apparaten van de gebruiker. Dit is dus een soort van ‘last resort’ om de gebruiker te verwittigen van een gebeurtenis. De SMSjes worden gratis verzonden, en het enige dat ervoor nodig is, is een GSM nummer dat geregistreerd staat op een account van Google. Dat werkt als volgt:

Gebruikers van Google Calendar kunnen zichzelf laten verwittigen via SMS wanneer er een afspraak volgt, door dit in te stellen bij de afspraak. Aangezien Google Calendar ook een Python API heeft, kan de server dus een ‘afspraak’ aanmaken die binnen één minuut begint op de kalender van de gebruiker, en hem daarvan verwittigen één minuut voor het beginnen van de afspraak. Op die manier zal er dan bijna onmiddellijk een SMSje naar de gebruiker gestuurd worden om hem hiervan te verwittigen, en dat is exact wat we nodig hebben.

Verder heb ik ook nog gezorgd voor integratie met gnome-screensaver: wanneer een apparaat met de gnome desktopomgeving niet de meest actieve client op het netwerk is, is het nu mogelijk om dit apparaat automatisch zijn scherm te laten blokkeren. Dit om ongeauthoriseerde toegang te voorkomen en/of energie te besparen.

Buiten het uitgebreid testen van de presence client en het oplossen van bijhorende bugs, zijn dit de dingen die ik de voorbije weken heb verwezenlijkt:

  • Refactoring: de code voldoet nu beter aan python standaarden, waarin het de conventie is om de namen van  ‘private’ methods en member variabelen (die niet verplicht opgelegd worden in python) vooraf te laten gaan door een underscore (‘_’). Op die manier kunnen IDE’s beter aangeven welke methods tot de interface van de klassen behoren.
    Ook heb ik pyLint, een tool zoals lint voor C, losgelaten op de code. Dit omdat python zelf de code pas ‘checkt’ wanneer hij gerund wordt. Op deze manier ben ik er zeker van dat er geen ongedeclareerde variabelen gebruikt worden en dat ik geen tikfouten heb gemaakt.
  • Fallbacks: indien een bepaalde library niet geïnstalleerd is, zal het programma proberen om in een soort van compatibiliteitsmodus te draaien. Een voorbeeld hiervan is het runnen van de applicatie zonder dat er avahi-support is geïnstalleerd. Het programma zal dan proberen te verbinden met een default server.
  • Een globaal notificatie framework: om te voldoen aan het user scenario 3 uit voorgaande blogpost heb ik gezorgd voor een notificatie-framework, waarnaar applicaties hun notificaties kunnen versturen als ze willen dat de gebruiker deze ook op andere machines kan lezen waarop hij werkt. De presence client en server zullen er dan voor zorgen dat deze notificatie weergegeven wordt op het apparaat waarop de gebruiker op dat moment het actiefst bezig is.
  • DBus ondersteuning: er is nu een extra klasse, presenceClientDBusListener, die een presence client aanmaakt en ervoor zorgt dat hij bestuurd kan worden via DBus. Concreet komt dit erop neer dat andere applicaties ‘messages’ kunnen sturen naar de presence client. Zo is het nu mogelijk om het presence level te updaten via een DBus-aanroep, of om op die manier notificaties en berichten te versturen.
  • User Interfaces: op een desktop PC worden notificaties weergegeven door gebruik te maken van libnotify, hetgeen ervoor zorgt dat de notificaties op de system-native manier worden weergegeven. De berichten komen op een desktop PC  aan in een klein gtk-kadertje, omdat het de bedoeling is dat dit gebruikt wordt voor snelle, kleine messages en niet voor uitgebreide chatsessies. De gebruiker heeft hierin de mogelijkheid om te replyen.
    In Android werk ik met het standaard notificatie-framework. Dit zorgt ervoor dat berichten in een notificatie weegegeven worden waarop geklikt kan worden om een antwoord te sturen.
  • Thesis: nagedacht over een inhoudstabel voor de thesis. Hierna volgt de voorlopige versie

Voorlopige inhoudstafel

User scenario’s

Doorsturen van notificaties
Messaging
‘context-aware’ systemen: apparaat weet of het actief gebruikt wordt

Gebruikte talen/pakketten/libraries

Python

Avahi/zeroconf
DBus
gtk + libnotify
Python socket library

Java

Android SDK (eclipse)

Implementatie presence server

User handlers => schaalbaarheid

=> server verzorgt logins en kent userHandlers (voor messaging)

Verbinding: avahi of rechtstreeks

=> gebruik binnen bedrijf voor communicatie tussen collega’s: avahi
=> 1 persoon met veel apparaten op verschillende plaatsen (notifications): rechtstreeks

Bijgehouden data: client list, most active

Implementatie presence client

Desktop

Modulairiteit (dbus) => Info voor andere programma’s: isMostActive(), sendNotification(), sendMessageToUser()
User Interface: mogelijkheid tot vervanging
Bijgehouden data: isMostActive, presence list (afweging data verstuurd)
Integratie met presence agent Kristof

Nokia?
Android

PresenceService
ConnectionHandler
ActivityHandler => keyboard lock
UI/presenceClient
notifications op android

Om te bekijken welke kant ik verder uit wil met de presence agent, heb ik enkele gebruikersscenario’s opgesteld, waarin de mogelijkheden van gebruik van de presence agent worden besproken.

Scenario 1: instant messaging

Persoon A wil persoon B een bericht sturen, maar weet niet waar deze persoon zich bevindt en of hij op de een of andere manier online is. Hij zal dan gewoon zijn bericht naar de presence server waarop persoon B is aangesloten sturen, die ervoor zal zorgen dat het bericht aankomt op de machine waarvan het het meest waarschijnlijk is dat hij zich dicht bij persoon B bevindt.
Wanneer de server weet dat persoon B druk bezig is kan hij dit melden aan persoon A, die dan weet dat hij persoon B best enkel stoort als het belangrijk is. Hierbij is het belangrijk dat er automatisch bepaald wordt of de gebruiker druk bezig is (en dat de gebruiker dit dus niet manueel ingeeft), aangezien de gebruiker kan vergeten zijn status te updaten, terwijl een presence agent dit altijd doet. Wanneer persoon A weet dat de status accuraat is, zal hij minder geneigd zijn tóch te proberen persoon B te contacteren met minder belangrijk nieuws.

Scenario 2: instant messaging (2)

Gelijkaardig aan scenario 1, met het verschil dat het versturen van berichten gebeurt via een instant messaging toepassing. De presence agent kan dan via een plugin (of via D-Bus) de IM applicatie verwittigen wanneer de status van de gebruiker verandert. Dit is specifiek per IM applicatie.
Het voordeel van nog steeds met een aparte server te werken (in plaats van simpelweg de status te laten aanpassen door de lokale presence agent) is dat één enkele presence agent maar bepaalde activiteit op de computer van een gebruiker kan meten, terwijl een netwerk van presence agents zekerder kan zijn van het feit dat de gebruiker achter een bepaald apparaat zit. Een machine heeft immers een bepaalde aanwezigheid binnen het netwerk.

Scenario 3: globaal notificatie-framework

Op dit moment is het alleen maar mogelijk voor een applicatie die op een bepaalde machine draait om de gebruiker van een gebeurtenis/update te waarschuwen op deze machine, tenzij hij gebruik maakt van e-mail of een ad-hoc —en vaak minder robuust— notificatiesysteem. Met een multi-device presence agent zou het echter mogelijk zijn een D-Bus service te broadcasten waarnaar applicaties notificaties kunnen versturen. Deze service (die in de presence agent zou zitten) kan dan een bericht naar de server sturen, die de juiste client zal verwittigen.
Voorbeelden van notificaties die nut hebben op de non-originating machine zijn:

  • het huidig afspelende nummer in een muziekspeler-applicatie die gebruikt wordt om het hele huis/bedrijf van muziek te voorzien
  • een taak die voltooid is op een bepaalde machine (het downloaden van een bestand, het compileren van een programma, het afdrukken van een document op een gedeelde printer,…)
  • een kritieke fout op een server (zodat de serveradministrator deze zo snel mogelijk kan oplossen)
  • de wasmachine die klaar is met de was

Scenario 4: betere schatting van aanwezigheid van de gebruiker

Doordat de verschillende machines waarop de gebruiker werkt nu met een grotere zekerheid kunnen bepalen wanneer deze persoon ze niet gebruikt (bijvoorbeeld: wanneer een gebruiker zeer actief is op een bepaalde computer, is de kans klein dat hij ook werkt op een andere computer), kunnen deze machines veel energie-efficiënter werken. Zo kan wanneer de computer niet gebruikt wordt het scherm automatisch uitgeschakeld worden.
Een bijkomend voordeel hiervan is verhoogde veiligheid: de computer van een persoon kan automatisch geblokkeerd worden wanneer deze persoon zich niet in de buurt bevindt.

Aangezien deze blog er momenteel niet kleurrijk genoeg uitziet, hier wat android screenshots:

In het volgende screenshot zie je wat er gebeurt wanneer ik de android client heb opgestart. Gezien er dan activiteit gedetecteerd wordt op het android toestel, zal hij dit laten weten aan de presence server, die op zijn beurt de andere clients ervan verwittigt. Eén van deze andere clients is mijn desktop (waarvan je de output ziet in het consolevenster rechts van de Android emulator. Merk ook de notificatie rechtsboven op die de gebruiker verwittigt dat zijn machine momenteel niet de meest actieve op zijn netwerk is.

androidonline

Op de volgende afbeelding heb ik het scherm van de Android telefoon geblokkeerd (hetgeen automatisch gebeurt als de gebruiker de telefoon een tijdje niet gebruikt heeft, of wanneer hij hiervoor kiest). Merk op dat de desktop client zichzelf dan zal zien als de meest actieve client op het netwerk.

androidaway

De voorbije dagen ben ik vooral bezig geweest met het werkend krijgen van de Android implementatie van de Presence Agent, hetgeen nu ook gelukt is. Presence wordt gedetecteerd door te kijken of de input al dan niet gelocked is. Hiervoor biedt de Android API de KeyGuardManager klasse, waar ik lang naar heb moeten zoeken.

Voor Android heb ik ook een (spartaanse) gebruikersinterface gemaakt, zodat de gebruiker met een gebruikersnaam naar keuze kan inloggen. De handigheid die Android hierbij biedt is dat een gebruikersinterface gemakkelijk gescheiden kan worden gehouden van de service die hij voorziet, zodat deze service constant op de achtergrond kan blijven draaien (hetgeen ervoor zorgt dat de gebruiker zich niet in de presence agent-interface moet bevinden, wat handig is voor een programma dat gebruikersactiviteit meet).

De desktop client laat nu ook notifications aan de gebruiker zien wanneer de huidige machine de meest actieve op het netwerk wordt, of wanneer het deze status verliest. De client weet nu dus ook wanneer dit het geval is.

Tenslotte heb ik een soort van ‘Instant messaging’ ontwikkeld, waarbij verschillende users berichten naar elkaar kunnen versturen, en de server ervoor zorgt dat het bericht aankomt op de meest actieve machine van deze gebruiker. Ook de avahi service werkt nu naar behoren.

Na ongeveer 3 dagen prutsen met Android heb ik eindelijk een presence client die meerdere keren een presence lijst van zijn peers kan ontvangen. Tijd om ervoor te zorgen dat zijn eigen presence gedetecteerd en verstuurd wordt, en dat de username niet langer statisch is.

Met behulp van Avahi’s DBus-interface is het nu mogelijk om de presence server automatisch te detecteren, als deze zich op het lokale netwerk bevindt. Dit betekent dat de verschillende clients niet moeten vragen om een serveradres.

Verder ben ik de voorbije dagen aan het proberen geweest om een presence client (het netwerkgedeelte van de presence agent) voor Google’s Android-platform te maken. Gezien dit gebaseerd is op Java (en niet op Python) moet ik hiervoor heel wat code herschrijven, hetgeen een tijdje duurt. Momenteel heb ik een programma dat zich kan aanmelden op een (vaste) server met een (vaste) login, en één keer de lijst van zijn peers kan ontvangen.

De kans is echter klein dat ik uiteindelijk ook de Android-client met Avahi ga laten werken, omwille van twee redenen: ten eerste is er momenteel geen fatsoenlijke Avahi/zeroconf-implementatie beschikbaar.  Ten tweede (en belangrijker) zal een Android-telefoon meestal voor presence gebruikt worden wanneer de gebruiker hiermee onderweg is (en zich dus niet binnen een wifi-netwerk bevindt). We hebben om deze reden dus een extern IP-adres voor de server nodig, hetgeen we niet over het internet kunnen opvragen door middel van Avahi/zeroconf. Een mogelijkheid bestaat eventueel wel om later een centrale server te gebruiken, waarmee alle ‘kleine’ servers verbinden, een beetje zoals momenteel de PresenceServer de verschillende users verdeelt over zijn UserHandlers.

De voorbije twee dagen heb ik me voornamelijk bezig gehouden met het verbeteren van de bestaande code, in plaats van met het toevoegen van functionaliteit.

Hiervoor ben ik begonnen met het schrijven van Unit Tests (hetgeen gemakkelijk is dankzij de unittesting library in Python), die al meteen een bug lieten bovenkomen. Gesloten sockets werden namelijk niet verwijderd uit de socketList van de server. Ook bleek uit de Unit Tests dat, wanneer een client zijn socket sloot, de geüpdate presence list nog niet werd gebroadcast naar alle andere clients.

Aangezien ik toch aan het refactoren was, heb ik meteen ook maar een hoop exception handling code geschreven, zodat de server niet crasht bij de kleinste fout, maar deze proper afhandelt en dan verder loopt.

Verder heb ik ook de code van de originele facadedaemon lichtjes aangepast, zodat lokaal de presence wordt aangegeven als ‘away’ indien er een andere computer in het netwerk zit die een hoger presence level heeft dan de huidige client. Hij stuurt nu ook een presence level van ’5′ uit indien presence gedetecteerd wordt.

Door het integreren van mijn code met het bestaande framework heb ik nog een foutje ontdekt. Het was me namelijk blijkbaar ontgaan dat TCP werkt met streams in plaats van messages. Aangezien de facadedaemon vaak van presence verandert, zou het kunnen dat 2 of meer presence messages als 1 message worden gezien. Bijgevolg eindigen alle messages nu met de code ‘///’, om aan te geven dat de message daar stopt.

De voorbije dagen was ik wederom verbaasd over de snelheid waarmee in Python code geschreven kan worden. Volgende aanpassingen heb ik gemaakt:

  • De server kan nu ook connecties van buiten localhost aannemen (hetgeen nogal cruciaal is voor het verbinden van meerdere presence agents), door gebruik te maken van het IP-adres 0.0.0.0 in plaats van gethostname() bij het bind()en. De laatste optie was degene die vermeld was in de officiële Python documentatie, maar blijkt -ondanks wat daar gezegd wordt- enkel te werken voor localhost.
  • Er is nu een (redelijk basic) client die gebruikt kan worden door de presence agent om te communiceren met de server.
  • De server heeft nu de mogelijkheid om meerdere accounts te voorzien, zodat één server kan gebruikt worden voor een hele hoop gebruikers. Per gebruiker wordt dan een nieuw thread gestart dat ongeveer dezelfde functionaliteit biedt als de oorspronkelijke server. De server is daarvoor opgesplitst in twee klassen: UserHandler (dat voor één gebruiker de activiteit bijhoudt) en PresenceServer (dat inkomende connecties accepteert, UserHandlers aanmaakt en verbindingen doorverwijst naar de juiste UserHandler).
  • Er worden nu meerdere presence levels ondersteund, in de vorm van integers. Voorheen was het voor een agent enkel mogelijk om ‘present’ of ‘away’ te zijn, terwijl er nu een getal kan gekozen worden om het ‘aanwezigheidsniveau’ aan te geven.
  • Tenslotte is de code nog wat opgeschoond, met aandacht voor error handling. Bijkomend worden de UserHandlers ook gesloten wanneer er geen clients meer mee verbonden zijn, om resources te besparen.

Deze week heb ik ontdekt wat een geweldige programmeertaal Python is, en dit door het schrijven van een (basic) server die kan gaan dienen voor de communicatie tussen de verschillende presence agents op verschillende clients.

De server zorgt ervoor dat de verschillende clients kunnen laten weten wanneer de gebruiker op hun machine ‘present’ of ‘away’ is, en dat bij een update de vernieuwde lijst naar alle clients doorgestuurd wordt. Heel anders dan bij socketprogramming in C werd de meeste tijd gespendeerd aan programmeren in plaats van aan debuggen.

Dank ook aan de zeer overzichtelijke Python documentatie, die me alles vertelt wat ik moet weten over socket programming in Python (de hele server heb ik gemaakt op een plaats zonder internettoegang).

Up next: zorgen dat de clients ook daadwerkelijk communiceren met de server, zodat we niet gewoon 2 telnet-gebruikers hebben. Uiteindelijk moet het ook de bedoeling zijn dat het systeem gedecentraliseerd zal werken.

Bronroll

Follow

Get every new post delivered to your Inbox.