generate PHP API
authorMark Huang <mlhuang@cs.princeton.edu>
Wed, 25 Oct 2006 20:32:44 +0000 (20:32 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Wed, 25 Oct 2006 20:32:44 +0000 (20:32 +0000)
php/.cvsignore [new file with mode: 0644]
php/Makefile [new file with mode: 0644]
php/footer.php [new file with mode: 0644]
php/header.php [new file with mode: 0644]
php/methods.py [new file with mode: 0755]

diff --git a/php/.cvsignore b/php/.cvsignore
new file mode 100644 (file)
index 0000000..da15e22
--- /dev/null
@@ -0,0 +1,2 @@
+methods.php
+plcapi.php
diff --git a/php/Makefile b/php/Makefile
new file mode 100644 (file)
index 0000000..14cf10d
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# (Re)builds PHP API. PHP classes must be defined in a single file.
+#
+# Mark Huang <mlhuang@cs.princeton.edu>
+# Copyright (C) 2006 The Trustees of Princeton University
+#
+# $Id: Makefile,v 1.1 2006/09/06 15:34:41 mlhuang Exp $
+#
+
+all: plcapi.php
+
+methods.php: methods.py ../PLC/__init__.py ../PLC/Methods/__init__.py
+       PYTHONPATH=.. python $< | \
+       sed -e "s/^/  /" > $@
+
+plcapi.php: header.php methods.php footer.php
+       sed -e "s/@DATE@/$$(date)/" header.php | \
+       cat - methods.php footer.php > $@
+
+clean:
+       rm -f plcapi.php methods.php
+
+.PHONY: all clean
diff --git a/php/footer.php b/php/footer.php
new file mode 100644 (file)
index 0000000..466ea72
--- /dev/null
@@ -0,0 +1,3 @@
+}
+
+?>
diff --git a/php/header.php b/php/header.php
new file mode 100644 (file)
index 0000000..6b3dd2c
--- /dev/null
@@ -0,0 +1,190 @@
+<?php
+//
+// PlanetLab Central Slice API (PLCAPI) PHP interface
+//
+// DO NOT EDIT. This file was automatically generated at
+// @DATE@.
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2005-2006 The Trustees of Princeton University
+//
+// $Id: gen_php_api.py,v 1.13 2006/03/23 04:29:08 mlhuang Exp $
+//
+//
+
+require_once 'plc_config.php';
+
+class PLCAPI
+{
+  var $auth;
+  var $server;
+  var $port;
+  var $path;
+  var $errors;
+  var $trace;
+  var $calls;
+  var $multicall;
+
+  function PLCAPI ($auth,
+                  $server = PLC_API_HOST,
+                  $port = 8000, # PLC_API_PORT,
+                  $path = PLC_API_PATH,
+                  $cainfo = NULL)
+  {
+    $this->auth = $auth;
+    $this->server = $server;
+    $this->port = $port;
+    $this->path = $path;
+    $this->cainfo = $cainfo;
+    $this->errors = array();
+    $this->trace = array();
+    $this->calls = array ();
+    $this->multicall = false;
+  }
+
+  function error_log($error_msg, $backtrace_level = 1)
+  {
+    $backtrace = debug_backtrace();
+    $file = $backtrace[$backtrace_level]['file'];
+    $line = $backtrace[$backtrace_level]['line'];
+
+    $this->errors[] = 'PLCAPI error:  ' . $error_msg . ' in ' . $file . ' on line ' . $line;
+    error_log(end($this->errors));
+  }
+
+  function error ()
+  {
+    if (empty($this->trace)) {
+      return NULL;
+    } else {
+      $last_trace = end($this->trace);
+      return implode("\\n", $last_trace['errors']);
+    }
+  }
+
+  function trace ()
+  {
+    return $this->trace;
+  }
+
+  function microtime_float()
+  {
+    list($usec, $sec) = explode(" ", microtime());
+    return ((float) $usec + (float) $sec);
+  }
+
+  function call($method, $args = NULL)
+  {
+    if ($this->multicall) {
+       $this->calls[] = array ('methodName' => $method,
+                               'params' => $args);
+       return NULL;
+    } else {
+       return $this->internal_call ($method, $args, 3);
+    }
+  }
+
+  function internal_call ($method, $args = NULL, $backtrace_level = 2)
+  {
+    $curl = curl_init();
+
+    // Verify peer certificate if talking over SSL
+    if ($this->port == 443) {
+      curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 2);
+      if (!empty($this->cainfo)) {
+       curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo);
+      } elseif (defined('PLC_API_SSL_CRT')) {
+        curl_setopt($curl, CURLOPT_CAINFO, PLC_API_SSL_CRT);
+      }
+      $url = 'https://';
+    } else {
+      $url = 'http://';
+    }
+
+    // Set the URL for the request
+    $url .= $this->server . ':' . $this->port . '/' . $this->path;
+    curl_setopt($curl, CURLOPT_URL, $url);
+
+    // Marshal the XML-RPC request as a POST variable
+    $request = xmlrpc_encode_request($method, $args);
+    curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
+
+    // Construct the HTTP header
+    $header[] = 'Content-type: text/xml';
+    $header[] = 'Content-length: ' . strlen($request);
+    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
+
+    // Set some miscellaneous options
+    curl_setopt($curl, CURLOPT_TIMEOUT, 30);
+
+    // Get the output of the request
+    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+    $t0 = $this->microtime_float();
+    $output = curl_exec($curl);
+    $t1 = $this->microtime_float();
+
+    if (curl_errno($curl)) {
+      $this->error_log('curl: ' . curl_error($curl), true);
+      $ret = NULL;
+    } else {
+      $ret = xmlrpc_decode($output);
+      if (is_array($ret) && xmlrpc_is_fault($ret)) {
+        $this->error_log('Fault Code ' . $ret['faultCode'] . ': ' .
+                         $ret['faultString'], $backtrace_level, true);
+       $ret = NULL;
+      }
+    }
+
+    curl_close($curl);
+
+    $this->trace[] = array('method' => $method,
+                           'args' => $args,
+                           'runtime' => $t1 - $t0,
+                           'return' => $ret,
+                           'errors' => $this->errors);
+    $this->errors = array();
+
+    return $ret;
+  }
+
+  function begin()
+  {
+    if (!empty($this->calls)) {
+      $this->error_log ('Warning: multicall already in progress');
+    }
+
+    $this->multicall = true;
+  }
+
+  function commit ()
+  {
+    if (!empty ($this->calls)) {
+      $ret = array();
+      $results = $this->internal_call ('system.multicall', array ($this->calls));
+      foreach ($results as $result) {
+        if (is_array($result)) {
+          if (xmlrpc_is_fault($result)) {
+            $this->error_log('Fault Code ' . $result['faultCode'] . ': ' .
+                             $result['faultString'], 1, true);
+            $ret[] = NULL;
+          } else {
+            $ret[] = $result[0];
+          }
+        } else {
+          $ret[] = $result;
+        }
+      }
+    } else {
+      $ret = NULL;
+    }
+
+    $this->calls = array ();
+    $this->multicall = false;
+
+    return $ret;
+  }
+
+  //
+  // PLCAPI Methods
+  //
+
diff --git a/php/methods.py b/php/methods.py
new file mode 100755 (executable)
index 0000000..0b54370
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+#
+# Generates the PLCAPI interface for the website PHP code.
+#
+# Mark Huang <mlhuang@cs.princeton.edu>
+# Copyright (C) 2005 The Trustess of Princeton University
+#
+# $Id: gen_php_api.py,v 1.13 2006/03/23 04:29:08 mlhuang Exp $
+#
+
+import os, sys
+import time
+
+from PLC.API import PLCAPI
+from PLC.Method import *
+from PLC.Auth import Auth
+
+# Class functions
+api = PLCAPI(None)
+
+api.methods.sort()
+for method in api.methods:
+    # Skip system. methods
+    if "system." in method:
+        continue
+
+    function = api.callable(method)
+
+    # Commented documentation
+    lines = ["// " + line.strip() for line in function.__doc__.strip().split("\n")]
+    print "\n".join(lines)
+    print
+
+    # Function declaration
+    print "function " + function.name,
+
+    # PHP function arguments
+    args = []
+    (min_args, max_args, defaults) = function.args()
+    parameters = zip(max_args, function.accepts, defaults)
+
+    for name, expected, default in parameters:
+        # Skip auth structures (added automatically)
+        if isinstance(expected, Auth) or \
+           (isinstance(expected, Mixed) and \
+            filter(lambda sub: isinstance(sub, Auth), expected)):
+            continue
+
+        # Declare parameter
+        arg = "$" + name
+
+        # Set optional parameters to special value NULL
+        if name not in min_args:
+            arg += " = NULL"
+
+        args.append(arg)
+
+    # Write function declaration
+    print "(" + ", ".join(args) + ")"
+
+    # Begin function body
+    print "{"
+
+    # API function arguments
+    for name, expected, default in parameters:
+        # Automatically added auth structures
+        if isinstance(expected, Auth) or \
+           (isinstance(expected, Mixed) and \
+            filter(lambda sub: isinstance(sub, Auth), expected)):
+            print "  $args[] = $this->auth;"
+            continue
+
+        if name in min_args:
+            print "  $args[] = $%s;" % name
+        else:
+            print "  if ($%s !== NULL) { $args[] = $%s; }" % (name, name)
+
+    # Call API function
+    print "  return $this->call('%s', $args);" % method
+
+    # End function body
+    print "}"
+    print