SOAP Schnittstelle - State of the art

Hi paresy,

hast Du auf Deiner Roapmap das SOAP-Interface zu überarbeiten? So wie es aktuell sich darstellt ist es irgendwie nicht mehr „up2date“…

Beispielsweise werden Rpc/encoded wsdls nicht mehr von JAXWS 2.0 supportet.

Könntest Du evtl. eine Überarbeitung der Schnittstelle auf aktuelle Vorgehensweisen mit auf Deinen Fahrplan nehmen?

Viele Grüße
Sascha

Da die Library dahinter von Embarcadero (ehemals CodeGear, ehemals Borland) kommt und sie von denen nicht aktualisiert wird, wird es sehr unwahrscheinlich sein, dass es für IP-Symcon ein update vom SOAP Interface geben wird.

Vielleicht kannst du ja in PHP einen besseren SOAP Server nachbauen!?
http://php.net/manual/de/book.soap.php

paresy

Hm, okay… Das ist natürlich wirklich suboptimal.

Wenn ein php soap-server gebaut werden soll, wie greift dieser denn auf die interna von IP-Symcon zu? Geschieht dass dann über die „internen“ Funktionen von IP-Symcon und ist eher als ein Wrapper zu verstehen?

Natürlich könnte man auch den Code des aktuellen SOAP-Servers auch anpassen. Steht dieser irgendwie zur Verfügung oder wäre hier ein kompletter nachbau notwendig?

Also ich meine damit, wie die aktuelle Library die bestehenden Funktionen des Servers in ein SOAP-Interface umwandelt…
Es müsste eine Automatik geschaffen werden, die automatisch von Dir erstellte interne Funktionen via SOAP zur Verfügung stellt…

Viele Grüße
Sascha

Schau dir mal die Funktion IPS_GetFunctionList an. Damit könntest du eine WSDL generieren lassen. Und der Rest ist dann theoretisch ein wenig Codegenerierung und Eval-Statements

paresy

Welche PHP-Version ist in der aktuellsten Live-Version in Benutzung? Bräuchte noch extensions wie php_xsl.dll die ich zwar runterladen kann aber die genaue version bräuchte, damit die zu IPS passt…

Extension php_xsl.dll not loaded. Missing dependency: php5.dll

Habe die dll aus „php-5.3.1-nts-Win32-VC9-x86.zip“

Aktuell wird PHP Version 5.3.1 benutzt. Lässt sich übrigens folgendermaßen bequem herausfinden:

<?php phpinfo(); ?>

Du brauchst die Dateien aus der VC6 Thread-Safe.

Es wird die 5.3.1-„ThreadSafe“-Version verwendet, erkennbar an der Existenz einer „php5ts.dll“, und diese mit VC6 kompiliert, nicht mit VC9. Die …nts… Version ist deshalb nicht nutzbar.

Tommi

In der GetFunctionsList wird mit Type_ gearbeitet. Gibt es eine übersicht welche Nummer für welchen Type steht?

Es werden ja auch „Objekte“ als returnValue übergeben. Irgendwie muss ich die Struktur ja auch erkennen und ins WSDL-File übernehmen können.

Stimmt - Da scheinen noch Typinformationen zu fehlen. Falls du die anderen Funktionen (also ohne Array Support) über PHP abbilden (quasi WSDL + SOAP) kannst, werde ich mein bestes tun, dir die fehlenden Informationen auch noch über die PHP Funktionen zur Verfügung zu stellen.

Zu der Type_ Definition. Lad dir mal das Delphi SDK runter. Dort ist alles definiert.

paresy

Hast Du eine Idee warum

file_get_contents("php://input");

auf dem IPS-Webfront nicht funktioniert? Versuche gerade eingehende POST Daten im RAW-Format zu analysieren…
Jedenfalls sind die returns der Funktion immer leer.

Viele Grüße
Sascha

Ich habe mich mit alternativen zu SOAP beschäftigt. Was meiner Meinung nach auch sehr gut für IP-Symcon in Frage kommen würde ist eine JSON-Schnittstelle.

Vorteile dafür wären beispielsweise:

[ul]
[li]Die Funktionen von IPS können so genutzt werden, wie sie in den Befehlsrefenzen angegeben werden (http://www.ip-symcon.de/service/dokumentation/befehlsreferenz/)[/li][li]Schnelle Integrations ins Webfront[/li][li]Bereits vorhandene Möglichkeit zur User-Auth (Webfront Login)[/li][li]Sehr schnelle Replys mit wenig Daten-Overhead. Besonders gut geeignet für dünne Leitungen (wie z.B. UMTS, HSDPA usw…)[/li][/ul]

Einen initialen Wrapper dafür habe ich mal geschrieben. Dieser muß lediglich im Webfront plaziert werden. Weitere Anpassungen sind nicht nötig.


<?php
ini_set('display_errors', 1);
ini_set('error_reporting', E_ERROR);

$postdata = $GLOBALS['QUERY_STRING'];
$request = json_decode($postdata);

// Check if the request results in bad json object.
if ( $request == null )
{
   echo createErrorMsg("IPS-JSON request failed! Invalid header or postdata.");
   exit;
}

// Check if we got a valid json object.
if (! isset($request->{'function'}) )
{
   echo createErrorMsg("Request failed due to an invalid JSON object.");
   exit;
}

// Check if the given method is callable.
if ( is_callable($request->{'function'}, false, $functionname) )
{
   $result = call_user_func_array($functionname, $request->{'paras'});

   if ( $result == "" )
   {
      echo createErrorMsg("Calling the requested function failed! Check syntax and parameters.");
      exit;
   }
   echo json_encode($result);
} else
{
   echo createErrorMsg("Invalid IPS function!");
   exit;
}

/*
 * Creates a JSON error object which can be returned to the caller.
 */
function createErrorMsg($text)
{
   $arr = array(
      "reqCtrlObject" => "ERROR",
      "message"       => $text
   );
   return json_encode($arr);
}
?>

Dazu habe ich auch einen Test PHP-Client zusammengebastelt… Dieser könnte wie folgt aussehen und bringt auch gleich die nötige Auth mit:


<?php

$request = IPSFunction("IPS_GetObject", array(0));

$ips_url  = "https://mein.dyndnshost.de/json.php";
$ips_user = "meinlogin";
$ips_pass = "meinpass";

// Init php-curl.
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $ips_url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_USERPWD, "$ips_user:$ips_pass");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));

// Exec curl request.
$content = curl_exec($ch);
curl_close($ch);

if ( $content == false )
{
   echo "JSON request failed!
";
} else
{
   $result = json_decode($content);

   if ( $result->{reqCtrlObject} == "ERROR" )
   {
      echo $result->{message} ."
";
   } else
   {
      echo $content;
   }
}

// Function which builds the request-object. 
function IPSFunction($function, $paras)
{
   $request = array(
      "function" => $function,
      "paras"    => $paras
   );
   return $request;
}
?>

Da die JSON-Schnittstelle nicht sprachengebunden ist, könnte beispielsweise auch ein Curl-Aufruf von der Unix-Shell ein gewünschtes Ergebnis bringen.


curl -k -u meinlogin:meinpass-X POST -d '{"function":"IPS_GetObject","paras":[0]}' http://mein.dyndnshost.de/json.php

Wie gesagt, das ganze ist noch mit der heissen Nadel gestrickt und auch noch nicht ausgiebig getestet. So könnte ich mir jedenfalls eine/die neue/zusätzliche Schnittstelle vorstellen.

Ich werde an dem ganzen noch ein paar Optiomierungen vornehmen, mit anderen Sprachen testen und versuchen rauszufinden, wo es evtl. Schwachstellen bzw. Nachbesserungsbedarf gibt…

Any comments?

Viele Grüße
Sascha

Das Ergebnis auf „“ zu prüfen erzeugt bei jedem GetValue auf einen leeren String einen Fehler ;). Da würde ich doch dazu raten, einen eigenen Error-Handler zu benutzen, der die Fehlermeldung ordentlich weiterleitet. Der PHP-Client kann den Fehler dann auch ordentlich über trigger_error($msg, E_USER_WARNING) ausgeben.

Stimmt… An den Fall habe ich garnicht gedacht. Habe die Abfrage mal rausgenommen… Problem ist nun, dass der Client den ich gebaut habe natürlich mit einem leeren String nicht klarkommt. phpCurl erwartet einfach bei einem request eine Antwort, die natürlich bei einem leeren String ausbleibt…

Hast Du Code wie Du Deine Idee umsetzen würdest?

Viele Grüße
Sascha

Nutz doch lieber file_get_contents. Das kann auch alles…braucht aber keine extra Extension.

Hier ein Beispiel wie ich es genutzt habe:

paresy

Ich habe die JSON Schnittstelle noch ein wenig getestet… Meine Testumgebung war nun jedoch „Android“. Android supportet von Haus aus wesentlich besser eine JSON Umgebung… Beispielcode hierfür gibts anbei.

Der Weg:

[ul]
[li]Importieren von „IPSjson-android-v1.0.jar“ in das Projekt (Configure Buildpath unter Eclipse).[/li][li]Copy & Paste des Beispielcodes in die Hauptklasse der Android-Applikation[/li][li]Anpassungen vornehmen (Host, Port, Login, Passwort, SSL ja/nein)[/li][li]Wenn gewollt, kann die gewünschte Funktion angepasst werden, die via JSON aufgerufen werden soll.[/li][li]Auf dem IP-Symcon-Server muß die in den vorherigen Posts vorhandene PHP-Datei als /jsonrpc.php vorhanden sein. Der Request geht immer nach http(s)://<host>:<port>/jsonrpc.php[/li][li]Fertig[/li][/ul]

Beispielcode:


import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import de.realriot.libs.ipsjson.IPSException;
import de.realriot.libs.ipsjson.IPSjson;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class AndroidTest extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        TextView tv = new TextView(this);
        
        IPSjson ips = null;
		try {
			ips = new IPSjson("host", "port", "login", "pass", true);
		} catch (IPSException e) {
			tv.setText("ERROR: " + e.getMessage());
			setContentView(tv);
		}
        try {
        	JSONObject result = ips.IPS("IPS_GetObject", new Object[] {0} );
        	
        	// Add ObjectName to the TextView object.
        	tv.setText("Object: " + result.get("ObjectName").toString() + "

ChildrenIDs:
");
        	
        	// Add the ChildrenIDs to the TextView object.
        	JSONArray nameArray=result.getJSONArray("ChildrenIDs");
        	for ( int i = 0; i < nameArray.length(); i++ )
        		tv.setText(tv.getText() + "- " + nameArray.getString(i) + "
");
        	
        	// Set the contentView.
        	setContentView(tv);
		} catch (IPSException e) {
			tv.setText("IPS-Exception: " + e.getMessage());
			setContentView(tv);
		} catch (JSONException e) {
			tv.setText("ERROR: " + e.getMessage());
			setContentView(tv);
		}
    }
}

Kommentare erwünscht :wink:

Viele Grüße
Sascha

IPSjson-android-v1.0.rar (8.57 KB)

Hi,

ich versuche gerade vergeblich mit jquery via deiner JSON-Schnittstelle Daten zu holen. Ich bekomme immer die gleiche Fehlermeldung (Calling the requested function failed! Check syntax and parameters)

Es kommt bei folgender Zeile in json.php:

$result = call_user_func_array($functionname, $request->{'paras'});

immer ein leeres Resultat raus, und ich weiß einfach nicht warum.

Mein simples Test-Script schaut so aus:


var data_in = 
{ 
"function" : "IPS_GetName",
"paras" : "44137"
};
							
var dataString = JSON.stringify(data_in);
var test = "";
$.post('../json.php', dataString ,  test);
alert(test);

Ich werd einfach nicht schlau draus - Hat jemand eine Ahnung, woran das liegen könnte?

EDIT:
… ich bin jetzt schon so weit, dass ich es mit einer Variable ans laufen bringe. Ich habe noch immer Probleme, mit dem Parameter-Array. In welcher Syntax muss das genau übergeben werden?
Ich habe folgende Übergaben schon probiert:
‚paras‘ : ‚12345‘
'paras : ‚array(12345)‘

Die einzig funktionierende Variante ist:
‚paras‘ : 12345
da muss ich dann aber im JSON.php die call function anpassen:

$result = call_user_func_array($functionname, array($request->{'paras'}));

das funktioniert aber leider nur mit einem Parameter.

Danke,
Philipp