4. Schnelleinstieg

Der GREYHOUND Server bietet über die "RPC Schnittstelle" (Remote Procedure Call) eine API an, über die sämtliche Funktionen des Servers genutzt werden können. Auch der GREYHOUND Client verwendet diese Schnittstelle, was im Umkehrschluss bedeutet, dass alles, was der GREYHOUND Client macht, auch über die API zur Verfügung steht. Der Server stellt die API über drei Protokolle bereit: das binäre und proprietäre RPCP Protokoll, das HTTP-basierte XML-RPC Protokoll und das HTTP-basierte JSON-RPC Protokoll. Im Folgenden wird die JSON-RPC API beschrieben, da sie am einfachsten zu verwenden ist.
Das JSON-RPC Protokoll ist recht einfach erklärt: es wird immer ein HTTP POST gesendet, in den HTTP Headern wird als Content-Type "application/json" übergeben und sowohl der Body des Requests, als auch die Antwort enthalten Daten im JSON Format. Die URL ist die URL des GREYHOUND Servers mit angehängtem "/json". In der von GREYHOUND verwendeten Version 1.1 des JSON-RPC Protokolls ist ein Request wie folgt aufgebaut:
JSON RPC Request:
1
2
3
4
5
6
7
8
9
10
POST /json HTTP/1.1
Host: ip-des-greyhound-servers
Content-Type: application/json
Authorization: Basic MGRiZjY0Mjk5NDA0MGM3MGI0ZjNkOTc1Y2MwNzZjZGEtYWRtaW46VGVzdDEyMyE=

{
    "version": "1.1",
    "method": "RpcItems.Get",
    "params": [ 123, false ]
}

Das JSON-RPC Format sieht vor, dass eine weitere Eigenschaft "id" übergeben werden kann, um den Request und die zugehörige Antwort eindeutig zu identifizieren. Bei der GREYHOUND API ist dieser Wert optional - wird eine "id" im Request mit angegeben, so wird diese auch in der Antwort wieder mit zurück gegeben, andernfalls wird sie weggelassen.

Im Request-Body werden also, neben der JSON-RPC Version 1.1, die aufzurufende Methode und die Parameter dazu übergeben. Die Authentifizierung läuft über HTTP Basic Auth. Dabei werden Benutzername und Passwort durch einen Doppelpunkt getrennt und Base-64 codiert. Bei GREYHOUND gibt es hier eine wichtige Besonderheit: als Benutzername wird bei der Authentifizierung über die API nicht nur der Benutzername eines GREYHOUND Benutzers übergeben, sondern eine sogenannte Client-ID, gefolgt von einem Bindestrich und dem eigentlichen Benutzernamen. Die Client-ID sollte während einer Anwendungssitzung gleich bleiben, kann also ähnlich betrachtet werden, wie eine selbst gewählte Session-ID. Anhand der Client-ID kann der GREYHOUND Server einzelne verbundene Anwendungs-Sessions auseinander halten und z.B. Sperrungen von Elementen korrekt behandeln (gesperrte Elemente können nur innerhalb der Anwendungs-Session, die das Element gesperrt hat, bearbeitet werden). Die Client-ID muss exakt 32 Zeichen lang sein und darf die Buchstaben a-f, A-F und Ziffern enthalten. Am einfachsten ist es, einen zufälligen String zu erzeugen und davon einen MD5 Hash zu bilden.
Für das obige Beispiel wurde der GREYHOUND Benutzer admin mit dem Passwort Test123! verwendet und die Client-ID 0dbf642994040c70b4f3d975cc076cda. Für die Basic Authentifizierung wird der Benutzername dann aus der Client-ID und dem GREYHOUND Benutzernamen zusammen gesetzt: 0dbf642994040c70b4f3d975cc076cda-admin, dann ein Doppelpunkt und das Passwort angehängt: 0dbf642994040c70b4f3d975cc076cda-admin:Test123! und das Ganze dann Base-64 codiert: MGRiZjY0Mjk5NDA0MGM3MGI0ZjNkOTc1Y2MwNzZjZGEtYWRtaW46VGVzdDEyMyE=.
Im Request Body wird im Beispiel als Methode RpcItems.Get verwendet. Die GREYHOUND API ist in unterschiedliche Funktionsblöcke (technisch "Units") unterteilt, die sich jeweils auf einen Aufgabenbereich konzentrieren. Eine Übersicht dieser Units findet sich hier: https://greyhound-software.com/docs/rpc/units
In der Übersicht einer einzelnen Unit findet man zahlreiche Klassen mit Eigenschaften aber ohne Funktionen, sowie eine Klasse mit Funktionen aber ohne Eigenschaften. Diese Klasse ist der Service, der die Funktionen der Unit zur Verfügung stellt und die Datenklassen für Parameter und Rückgabewerte der Funktionen nutzt.
Die Unit, die sich in GREYHOUND mit den Elementen (E-Mails, Telefonnotizen, Kontakten, Aufgaben, usw.) beschäftigt, ist die "rpc_itemslib" Unit: https://greyhound-software.com/docs/rpc/units/units_id=82
Dort findet man in der Liste die Klasse "RpcItems", die etliche Funktionen enthält, aber keine Eigenschaften. Sieht man sich die Beschreibung dieser Klasse an, so findet man in der Liste der Funktionen den Eintrag "Get": https://greyhound-software.com/docs/rpc/classes/classes_id=532
Die Klasse "RpcItems" ist also der Service und "Get ist eine Funktion des Item-Services. Im obigen Beispiel wird also mit "method": "RpcItems.Get" die Get-Funktion im RpcItems Service aufgerufen. Die Get Funktion hat zwei Parameter: ID und MarkAsReading. Die ID gibt an, welches Element abgerufen werden soll und MarkAsReading steuert, ob der Server am Element eine Markierung setzen soll, dass es gerade vom aktuellen Benutzer gelesen wird (im GREYHOUND Client sieht man dies als gelbe Markierung an den Elementen). Der aktuelle Benutzer in der RPC Schnittstelle ist der Benutzer, über den die Authentifizierung im Basic Auth erfolgt - im Beispiel also der Benutzer "admin". Da im Beispiel-Aufruf die Parameter 123 und false übergeben wurden, wird also über die Get Methode des RpcItem-Services das Element mit der ID 123 abgerufen und dabei nicht als "lesend" markiert. Den Lesestatus nutzt man in der Regel nur, wenn man eine wirkliche Client-Anwendung baut, ähnlich dem GREYHOUND Client. Wenn man Elemente über Skripte o.ä. abruft, um sie technisch zu verarbeiten, wäre es eher irritierend, wenn für andere Benutzer dann ständig angezeigt würde, dass das Element gerade gelesen wird.
Die Antwort, die vom GREYHOUND Server zurück geliefert wird hat immer den HTTP Status 200 (OK) und enthält immer JSON als HTTP Body. Im Fehlerfall wird also kein Statuscode 400 o.ä. geliefert, sondern ebenfalls der Statuscode 200. Die Antwort hat im Erfolgsfall folgendes Format:
JSON-RPC Ergebnis:
1
2
3
4
5
6
{
    "version": "1.1",
    "result": {
        // Ergebnis
    }
}
Es gibt also eine Eigenschaft "result", in der das Ergebnis des API Requests steht.
Im Fehlerfall hat die Antwort folgendes Format:
JSON-RPC Fehler:
1
2
3
4
5
6
7
8
{
    "version": "1.1",
    "error": {
        "name": "Exception",
        "code": 403,
        "message": "Invalid username or password (Username: \"admin\")."
    }
}
Es gibt also keine Eigenschaft "result". Stattdessen gibt es eine Eigenschaft "error" mit den Eigenschaften "code" (Fehlercode) und "message" (Fehlerbeschreibung).
Die Verwendung der GREYHOUND API über das JSON-RPC Protokoll ist also relativ einfach: es werden immer HTTP POST Requests geschickt und es kommen immer HTTP Antworten mit Statuscode 200 zurück. Der Inhalt ist sowohl beim Senden als auch bei den Antworten immer JSON. Fehler werden innerhalb der JSON Antwort mitgeteilt.

Der GREYHOUND Server lässt in Antworten alle "leeren" Werte weg, um Bandbreite zu sparen. Als leere Werte gelten dabei die Zahl 0, leere Strings, leere Objekte und leere Arrays. In Requests können in Objekten ebenfalls alle leeren Werte weg gelassen werden. Der Server betrachtet sie dann je nach Datentyp als 0, leeren String, leeren Array oder leeres Objekt. Wenn in einer Antwort vom Server also in Objekten Eigenschaften "fehlen", dann bedeutet das, dass sie einen leeren Wert haben.

Abgesehen von der allgemeinen Verwendung der API sind folgende Dinge nützlich oder hilfreich bei der Nutzung:
In den meisten Services gibt es jeweils die Funktionen Get, GetList, New, Put, Delete, Lock und Unlock. GetList liefert immer eine Liste von Einträgen, Get einen einzelnen Eintrag (der bei einigen Services umfangreichere Details enthalten kann als bei GetList). Wenn bei GetList ein Parameter "AdvancedFields" vorhanden ist, dann bedeutet das in der Regel, dass Referenzen auf andere Daten in der Antwort nur befüllt werden, wenn der Parameter als true übergeben wird - andernfalls werden Referenzen auf andere Daten weg gelassen. New legt einen neuen Eintrag an, Put ändert einen bestehenden Eintrag und Delete löscht einen Eintrag. Lock und Unlock dienen der Sperrung von Einträgen.
Die meisten Daten in GREYHOUND unterliegen einem Sperr-Mechanismus der ausschließen soll, dass mehrere Benutzer gleichzeitig dieselben Objekte bearbeiten. Das betrifft nicht nur Elemente (also E-Mails, Kontakte, Notizen usw.) sondern auch Benutzer, Gruppen, Filter usw. Alle Schreibzugriffe (z.B. die Funktionen Put und Delete) erfordern, dass vorher das Element gesperrt und nach dem Schreibzugriff wieder entsperrt wird (bei Delete entfällt das Entsperren, da das Objekt dann nicht mehr existiert). Dazu dienen die Funktionen Lock und Unlock, die ebenfalls in den meisten Services enthalten sind und als Parameter die ID des Objekts erwarten, das gesperrt oder entsperrt werden soll. Um also z.B. den Kontakt mit der ID 12345 zu bearbeiten, muss man folgende Requests senden:
Element sperren:
1
2
3
4
5
{
    "version": "1.1",
    "method": "RpcItems.Lock",
    "params": [ 12345 ]
}
Element ändern:
1
2
3
4
5
6
7
8
9
{
    "version": "1.1",
    "method": "RpcItems.Put",
    "params": [
        {
            // Daten des Elements
        }
    ]
}
Element entsperren:
1
2
3
4
5
{
    "version": "1.1",
    "method": "RpcItems.Lock",
    "params": [ 12345 ]
}

Wichtig: immer, wenn man ein Element sperrt, sollte man sicherstellen, dass es auch wieder entsperrt wird - auch im Fehlerfall. Ansonsten können andere Benutzer (und auch der gleiche Benutzer in einer anderen Anwendung oder Session) das Element nicht wieder entsperren.

Der Code sollte also sinngemäß immer wie folgt aussehen:
Element sperren, bearbeiten und entsperren:
1
2
3
4
5
6
7
callGreyhoundApi( 'RpcItems.Lock', [ item.id ] );

try {
    callGreyhoundApi( 'RpcItems.Put', [ item ] );
} finally {
    callGreyhoundApi( 'RpcItems.Unlock', [ item.id ] );
}

Da die Sperrungen vom Benutzernamen und der Client-ID aus der Authentifizierung abhängen gilt folgendes: nur mit derselben Client-ID und demselben Benutzernamen kann ein gesperrtes Element bearbeitet und wieder entsperrt werden. Alle anderen Client-IDs und alle anderen Benutzer können ein gesperrtes Element nur lesen, aber nicht bearbeiten.

Da HTTP Requests keine dauerhafte Verbindung aufrecht erhalten, erhält der GREYHOUND Server Sessions über die JSON-RPC API (und die XML-RPC API) eine Minute lang aufrecht. D.h. wenn eine Minute lang kein weiterer Request mit derselben Client-ID und demselben Benutzer eintrifft, dann wird die Session beendet und alle Elemente, die in dieser Session gesperrt wurden, werden wieder entsperrt. Trifft danach ein Schreibzugriff mit derselben Client-ID und demselben Benutzer ein, so wird dieser mit einem Fehler abgelehnt, weil das Element nicht mehr gesperrt ist. Andererseits bleiben Elemente dadurch auch nicht dauerhaft gesperrt, wenn ein Skript nach dem Sperren eines Elements mit einem Fehler abgebrochen wurde. Will man eine Sperrung länger aufrecht erhalten, dann muss man dafür sorgen, dass regelmäßig mindestens einmal pro Minute ein Request mit derselben Client-ID und demselben Benutzernamen geschickt wird.