From 766dc2510b193733507f4f1c040c01597164f7a2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 27 Jun 2011 13:51:19 +0100 Subject: [PATCH] Added php haXe target code to integrate with php-zmq bindings. Added php - specific haXe code in the org.zeromq.ZMQ***.hx classes to wrap the php-zmq binding library. This now allows php-targetted haXe applications to use the zeroMQ messaging library. It was also necessary to re-write some of the unit test methods (in the org/zeromq/test folder) and guide applications to work with php. Edited haxelib.xml file to update details of v1.1.0 hxzmq library --- .gitignore | 6 + INSTALL.md | 46 ++++- README.md | 8 +- guide/buildLinux.hxml | 8 + guide/buildMac64.hxml | 8 + guide/buildWindows.hxml | 8 + haxelib.xml | 3 +- org/zeromq/ZMQ.hx | 123 +++++++++++ org/zeromq/ZMQContext.hx | 19 +- org/zeromq/ZMQException.hx | 10 +- org/zeromq/ZMQPoller.hx | 59 +++++- org/zeromq/ZMQSocket.hx | 194 +++++++++++++++--- org/zeromq/externals/phpzmq/ZMQException.hx | 34 +++ .../externals/phpzmq/ZMQSocketException.hx | 25 +++ org/zeromq/guide/MTRelay.hx | 35 +++- org/zeromq/guide/MTServer.hx | 33 ++- org/zeromq/guide/WUServer.hx | 3 +- org/zeromq/test/TestAll.hx | 2 +- org/zeromq/test/TestPoller.hx | 2 +- org/zeromq/test/TestPubSub.hx | 3 +- org/zeromq/test/TestSocket.hx | 45 +++- org/zeromq/test/TestVersion.hx | 17 +- org/zeromq/test/TestZMQRemoting.hx | 57 ++++- test/buildLinux.hxml | 8 + test/buildMac64.hxml | 8 + test/buildWindows.hxml | 7 + zipexclude.lst | 6 + 27 files changed, 697 insertions(+), 80 deletions(-) create mode 100644 org/zeromq/externals/phpzmq/ZMQException.hx create mode 100644 org/zeromq/externals/phpzmq/ZMQSocketException.hx diff --git a/.gitignore b/.gitignore index e679777..5991b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,15 @@ test/out-cpp/Windows/* test/out-neko/Linux/* test/out-neko/Mac64/* test/out-neko/Windows/* +test/out-php/Linux/* +test/out-php/Mac64/* +test/out-php/Windows/* guide/out-cpp/Linux/* guide/out-cpp/Mac64/* guide/out-cpp/Windows/* guide/out-neko/Linux/* guide/out-neko/Mac64/* guide/out-neko/Windows/* +guide/out-php/Linux/* +guide/out-php/Mac64/* +guide/out-php/Windows/* diff --git a/INSTALL.md b/INSTALL.md index 90e33a7..a7cdfd1 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -7,8 +7,8 @@ To just build or just use hxzmq in a haXe project, you will need a working 0MQ l There are [lots of instructions on the zeromq website][1]. To actually build hxzmq from source, you will need some additional installation steps: -### HXCPP (all platforms) -The hxzmq repository uses the hxcpp build tool to compile hxzmq.ndll from source on all target platforms, for neko and cpp -based applications:. +### HXCPP (all OS, neko and cpp targets) +The hxzmq repository uses the hxcpp build tool to compile hxzmq.ndll from source on all target operating systems, for neko and cpp -based applications:. 1. You need to install the full hxcpp package on your development machine: haxelib install hxcpp @@ -26,6 +26,12 @@ To build hxzmq on Windows, you need to: Both of these are necessary to build hxzmq on Windows, as it refers to header files contained in the libzmq distribution. Note that if you build the debug target libzmq MSVC project, you may encounter errors related to a missing MSVCR100D.dll (debug c++ runtime). + +## PHP-ZMQ (PHP target) +The haXe classes in the org.zeromq namespace (/org/zeromq in the project structure) include php - specific code to integrate the haXe ZMQ API with the [php-zmq PHP zeroMQ binding][3]. + +To use this, install the php-zmq extension following the instructions documented in the php-zmq project. Then compile your PHP - targetted haXe application code including the hxzmq library. Instead of using the hxzmq.ndll C wrapper, the haXe zeroMQ code redirects to the php-zmq class methods. + ## hxzmq Library Installation using haxelib To be able to just use hxzmq to build 0MQ messaging into new haXe applications, @@ -38,7 +44,7 @@ without modifying the or re-building hxzmq from source, you need: include the hxzmq library in your hxml haXe compilation file: -lib hxzmq -3. To run your target executable, your system will need to reach the hxzmq.ndll library file +3. *(For neko and cpp targetted applications only)* To run your target executable, your system will need to reach the hxzmq.ndll library file and the libzmq.dll 0MQ library file. Add both paths to your environment executable PATH variable or copy into a standard library path directory if not in one already (e.g. /usr/lib in linux), or copy both files into the same folder as your newly-minted haXe executable (e.g. either a neko .n or cpp executable). @@ -73,10 +79,11 @@ or or haxe buildLinux.hxml -These create debug - enabled target cpp and neko executables in the test/out-cpp/... and test/out-neko/... folders. +These create debug - enabled target cpp, neko and php executables in the test/out-cpp/... , test/out-neko/... and test/out-php/... folders. Then to run the test executables: -1. Navigate to the folder holding the test executable (cpp or neko, platform), +For neko and cpp: +1. Navigate to the folder holding the test executable (cpp or neko, OS-specific), 2. Ensure that the hxzmq.ndll and libzmq.dll files are on your executable path (or copied into this folder) 3. Run the program @@ -86,6 +93,18 @@ e.g, to build and run the cpp unit test target executable on Mac64: cd out-cpp/Mac64 ./TestAll-debug +For php: +1. Navigate to the folder holding the test index.php file. +2. Ensure that the php-zmq extension is available (run `php -m` and look for `zmq`) +3. Run the program + +e.g, to build and run the php unit test target executable on Mac64: + cd test + haxe buildMac64.hxml + cd out-php/Mac64 + php -f index.php + + You should see output similar to: Class: org.zeromq.test.TestVersion TestVersion.hx:39: version_full:20107 .. @@ -112,19 +131,32 @@ or or haxe buildLinux.hxml -These create debug - enabled target cpp and neko executables in the guide/out-cpp/... and guide/out-neko/... folders. +These create debug - enabled target cpp, neko and php executables in the guide/out-cpp/... or guide/out-neko/... or guide/out-php folders. Then to run the test executables: +For neko or cpp: 1. Navigate to the folder holding the guide executable (cpp or neko, platform), 2. Ensure that the hxzmq.ndll and libzmq.dll files are on your executable path (or copied into this folder) 3. Run the program -e.g, to build and run the neko unit test target executable on Windows: +e.g, to build and run the neko guide target executable on Windows: cd guide haxe buildWindows.hxml cd out-neko/Windows neko run-debug.n +For php: +1. Navigate to the folder holding the guide index.php +2. Ensure that the php-zmq extension is available (run `php -m` and look for `zmq`) +3. Run the program + +e.g, to build and run the php guide target executable on Windows: + cd guide + haxe buildWindows.hxml + cd out-php/Windows + php -f index.php + [1]: http://www.zeromq.org/intro:get-the-software "ZeroMQ installation" [2]: http://haxe.org/doc/cpp/ffi "HXCPP Build Tool" +[3]: http://github.com/mkoppanen/php-zmq diff --git a/README.md b/README.md index 2f00338..4f3155d 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ By Richard Smith [RSBA Technology Ltd] [1] ## Introduction This repository provides C++ binding code that wraps the libzmq library API to create a Neko DLL file, hxzmq.ndll. The ndll is then accessed via the hxzmq org.zeromq package to expose the 0MQ API to haXe application code targetted at C++ or nekovm platforms. + +Also included is wrapper code around the [existing PHP ZeroMQ binding] [12], enabling haXe programs compiled for the PHP environment can slso make use of zeroMQ socket technology. ### Background & Rationale haXe enables applications to be written in a single unified programming language that can then be executed on any combination of an ever-growing number of [target language platforms.] [6]. It is quite possible to write back-end server code targetted at php or C++, with a rich internet application Flash or javascript front-end, plus an iPhone application (via the C++ target), all using a single shared haXe codebase. Code written using non-target specific APIs can be automatically re-used on any of these platforms, such as an application's internal domain model or framework code. Conditional compilation, together with many target - specific APIs contained in the [haXe standard library] [7], provides the opportunity to access platform-specific features, giving the best of both worlds. Most of the target platforms also support extending the standard capabilities by use of externs and Foreign Function Interface mechanisms; an ability which has been used to write hxzmq. haXe is an [open source project] [7]. @@ -131,7 +133,9 @@ Key files and folders contained in this repository: ## Versions -The current release of hxzmq is 1.0.0, compatable with libzmq-2.1.4 or any later 2.1.x version. The latest released hxzmq package shall also be available in the [haxelib repository] [4], accessable via the [haxelib tool] [5] which is included in the standard haXe distribution. +The current release of hxzmq is 1.1.0, compatable with libzmq-2.1.4 or any later 2.1.x version. The latest released hxzmq package shall also be available in the [haxelib repository] [4], accessable via the [haxelib tool] [5] which is included in the standard haXe distribution. + +This version of hxzmq has also been tested against [php-zmq v0.7.0] [13] ## Building and Installation @@ -158,6 +162,8 @@ included with the hxzmq distribution. [9]: http://www.imatix.com/ "iMatix Corporation" [10]: http://haxe.org/doc/cpp/ffi "C++ FC Foreign Function Interface" [11]: http://zguide.zeromq.org/ "0MQ Guide" +[12]: http://github.com/mkoppanen/php-zmq +[13]: http://github.com/mkoppanen/php-zmq/blob/0.7.0 diff --git a/guide/buildLinux.hxml b/guide/buildLinux.hxml index d2c025a..e60601b 100644 --- a/guide/buildLinux.hxml +++ b/guide/buildLinux.hxml @@ -14,3 +14,11 @@ -debug -main org.zeromq.guide.Run +# Build PHP guide target +--next +-cp .. +-php out-php/Linux +-debug +--remap neko:php +-main org.zeromq.guide.Run + diff --git a/guide/buildMac64.hxml b/guide/buildMac64.hxml index 9827a5c..05f56c4 100644 --- a/guide/buildMac64.hxml +++ b/guide/buildMac64.hxml @@ -9,3 +9,11 @@ -main org.zeromq.guide.Run # todo: Neko Mac0SX 64 bit target + +# Build PHP guide target +--next +-cp .. +-php out-php/Mac64 +-debug +--remap neko:php +-main org.zeromq.guide.Run diff --git a/guide/buildWindows.hxml b/guide/buildWindows.hxml index 2a08a15..ea5b86d 100644 --- a/guide/buildWindows.hxml +++ b/guide/buildWindows.hxml @@ -14,3 +14,11 @@ -debug -main org.zeromq.guide.Run +# Build PHP guide target +--next +-cp .. +-php out-php/Windows +-debug +--remap neko:php +-main org.zeromq.guide.Run + diff --git a/haxelib.xml b/haxelib.xml index 640dc38..ce91432 100644 --- a/haxelib.xml +++ b/haxelib.xml @@ -3,6 +3,7 @@ + Haxe language binding for the ZeroMQ socket library - Initial upload, compatable with libzmq 2.1.6+ + Added php target by integrating with php-zmq binding diff --git a/org/zeromq/ZMQ.hx b/org/zeromq/ZMQ.hx index 31013fe..d12cd0c 100644 --- a/org/zeromq/ZMQ.hx +++ b/org/zeromq/ZMQ.hx @@ -223,7 +223,11 @@ class ZMQ { */ public static function strError(e:Int):String { +#if php + return _hx_zmq_str_error(e); +#else return Lib.nekoToHaxe(_hx_zmq_str_error(e)); +#end } /** @@ -511,6 +515,125 @@ class ZMQ { private static var _hx_zmq_ENOCOMPATPROTO = Lib.load("hxzmq", "hx_zmq_ENOCOMPATPROTO", 0); private static var _hx_zmq_ETERM = Lib.load("hxzmq", "hx_zmq_ETERM", 0); + #elseif php + // Load functions and constants from php-zmq + + + private static function _hx_zmq_version_full():Int { + return untyped __php__('ZMQ::LIBZMQ_VER'); + } + // Not supported in php-zmq 0.7.0 + private static function _hx_zmq_version_major():Int { + throw new ZMQException(ENOTSUP); + return null; + } + // Not supported in php-zmq 0.7.0 + private static function _hx_zmq_version_minor():Int { + throw new ZMQException(ENOTSUP); + return null; + } + // Not supported in php-zmq 0.7.0 + private static function _hx_zmq_version_patch():Int { + throw new ZMQException(ENOTSUP); + return null; + } + // Not supported in php-zmq 0.7.0 + private static function _hx_zmq_make_version(major:Int, minor:Int, patch:Int):Int { + throw new ZMQException(ENOTSUP); + return null; + } + // Not supported in php-zmq 0.7.0 + private static function _hx_zmq_str_error(e:Int):String { + return "ZMQ Error"; // php-zmq doesnt expose the str_error function + } + private static function _hx_zmq_catch_signals():Void { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_interrupted():Int { + throw new ZMQException(ENOTSUP); + return null; + } + + + private static function _hx_zmq_ZMQ_PUB():Int {return untyped __php__('ZMQ::SOCKET_PUB');} + private static function _hx_zmq_ZMQ_SUB():Int {return untyped __php__('ZMQ::SOCKET_SUB');} + private static function _hx_zmq_ZMQ_PAIR():Int {return untyped __php__('ZMQ::SOCKET_PAIR');} + private static function _hx_zmq_ZMQ_REQ():Int {return untyped __php__('ZMQ::SOCKET_REQ');} + private static function _hx_zmq_ZMQ_REP():Int {return untyped __php__('ZMQ::SOCKET_REP');} + private static function _hx_zmq_ZMQ_DEALER():Int {return untyped __php__('ZMQ::SOCKET_XREQ');} + private static function _hx_zmq_ZMQ_ROUTER():Int {return untyped __php__('ZMQ::SOCKET_XREP');} + private static function _hx_zmq_ZMQ_PULL():Int {return untyped __php__('ZMQ::SOCKET_PULL');} + private static function _hx_zmq_ZMQ_PUSH():Int {return untyped __php__('ZMQ::SOCKET_PUSH');} + + + private static function _hx_zmq_ZMQ_LINGER():Int {return untyped __php__('ZMQ::SOCKOPT_LINGER');} + private static function _hx_zmq_ZMQ_HWM():Int {return untyped __php__('ZMQ::SOCKOPT_HWM');} + private static function _hx_zmq_ZMQ_RCVMORE():Int {return untyped __php__('ZMQ::SOCKOPT_RCVMORE');} + private static function _hx_zmq_ZMQ_SUBSCRIBE():Int {return untyped __php__('ZMQ::SOCKOPT_SUBSCRIBE');} + private static function _hx_zmq_ZMQ_UNSUBSCRIBE():Int {return untyped __php__('ZMQ::SOCKOPT_UNSUBSCRIBE');} + private static function _hx_zmq_ZMQ_SWAP():Int {return untyped __php__('ZMQ::SOCKOPT_SWAP');} + private static function _hx_zmq_ZMQ_AFFINITY():Int {return untyped __php__('ZMQ::SOCKOPT_AFFINITY');} + private static function _hx_zmq_ZMQ_IDENTITY():Int {return untyped __php__('ZMQ::SOCKOPT_IDENTITY');} + + private static function _hx_zmq_ZMQ_RATE():Int {return untyped __php__('ZMQ::SOCKOPT_RATE');} + private static function _hx_zmq_ZMQ_RECOVERY_IVL():Int {return untyped __php__('ZMQ::SOCKOPT_RECOVERY_IVL');} + private static function _hx_zmq_ZMQ_RECOVERY_IVL_MSEC():Int { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_ZMQ_MCAST_LOOP():Int {return untyped __php__('ZMQ::SOCKOPT_MCAST_LOOP');} + private static function _hx_zmq_ZMQ_SNDBUF():Int {return untyped __php__('ZMQ::SOCKOPT_SNDBUF');} + private static function _hx_zmq_ZMQ_RCVBUF():Int {return untyped __php__('ZMQ::SOCKOPT_RCVBUF');} + private static function _hx_zmq_ZMQ_RECONNECT_IVL():Int { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_ZMQ_RECONNECT_IVL_MAX():Int { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_ZMQ_BACKLOG():Int { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_ZMQ_FD():Int { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_ZMQ_EVENTS():Int { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_ZMQ_TYPE():Int {return untyped __php__('ZMQ::SOCKOPT_TYPE');} + + private static function _hx_zmq_ZMQ_POLLIN():Int {return untyped __php__('ZMQ::POLL_IN');} + private static function _hx_zmq_ZMQ_POLLOUT():Int {return untyped __php__('ZMQ::POLL_OUT');} + private static function _hx_zmq_ZMQ_POLLERR():Int { + throw new ZMQException(ENOTSUP); + return null; + } + private static function _hx_zmq_DONTWAIT():Int {return untyped __php__('ZMQ::MODE_NOBLOCK');} + private static function _hx_zmq_SNDMORE():Int {return untyped __php__('ZMQ::MODE_SNDMORE');} + + // Use the ZMQ::ERR_ENOTSUP for any Exxxx codes not supported by php-zmq binding + private static inline function _hx_zmq_EINVAL():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_ENOTSUP():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_EPROTONOSUPPORT():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_EAGAIN():Int {return untyped __php__('ZMQ::ERR_EAGAIN');} + private static inline function _hx_zmq_ENOMEM():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_ENODEV():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_ENOBUFS():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_ENETDOWN():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_EADDRINUSE():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_EADDRNOTAVAIL():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_ECONNREFUSED():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_EINPROGRESS():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_EMTHREAD():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_EFSM():Int {return untyped __php__('ZMQ::ERR_EFSM');} + private static inline function _hx_zmq_ENOCOMPATPROTO():Int {return untyped __php__('ZMQ::ERR_ENOTSUP');} + private static inline function _hx_zmq_ETERM():Int {return untyped __php__('ZMQ::ERR_ETERM');} + #end } diff --git a/org/zeromq/ZMQContext.hx b/org/zeromq/ZMQContext.hx index 87f6968..4640b35 100644 --- a/org/zeromq/ZMQContext.hx +++ b/org/zeromq/ZMQContext.hx @@ -116,9 +116,22 @@ class ZMQContext { } } - +#if (cpp || neko) private static var _hx_zmq_construct = neko.Lib.load("hxzmq", "hx_zmq_construct", 1); private static var _hx_zmq_term = neko.Lib.load("hxzmq", "hx_zmq_term", 1); - - +#elseif php + private static function _hx_zmq_construct(ioThreads:Int):Dynamic { + // Implement this test explicitly as php-zmq doesnt seem to detect / trap it. + if (ioThreads == 0) { + throw ZMQ.errorTypeToErrNo(EINVAL); + return null; + } + return untyped __php__('new ZMQContext($ioThreads)'); + } + + private static function _hx_zmq_term(ctx:Dynamic):Void { + // Explicity destroy the php ZMQContext object (which invokes zmq_term in the php-zmq binding) + untyped __call__('unset', ctx); + } +#end } \ No newline at end of file diff --git a/org/zeromq/ZMQException.hx b/org/zeromq/ZMQException.hx index 9bc3d0f..44b3e11 100644 --- a/org/zeromq/ZMQException.hx +++ b/org/zeromq/ZMQException.hx @@ -31,9 +31,13 @@ class ZMQException { public var errNo(default,null):Int; - public function new(e:ErrorType) { + // Allows error string to be overriden on creation (e.g. for preserving php-zmq errors) + private var overriddenStr:String; + + public function new(e:ErrorType, ?str:String ) { this.err = e; this.errNo = ZMQ.errorTypeToErrNo(err); + if (str != null) this.overriddenStr = str; } /** @@ -41,7 +45,7 @@ class ZMQException { * @return */ public function str():String { - return ZMQ.strError(errNo); + return { if (overriddenStr != null) overriddenStr else ZMQ.strError(errNo); }; } public function toString():String { @@ -52,6 +56,4 @@ class ZMQException { return b.toString(); } - //private static var _hx_zmq_strerror = neko.Lib.load("hxzmq", "hx_zmq_strerror", 1); - } \ No newline at end of file diff --git a/org/zeromq/ZMQPoller.hx b/org/zeromq/ZMQPoller.hx index 68a93dd..0fe6b9f 100644 --- a/org/zeromq/ZMQPoller.hx +++ b/org/zeromq/ZMQPoller.hx @@ -20,6 +20,9 @@ package org.zeromq; import neko.Lib; +#if php +import php.NativeArray; +#end import org.zeromq.ZMQ; import org.zeromq.ZMQSocket; @@ -105,13 +108,13 @@ class ZMQPoller */ public function poll(?timeout:Int = -1):Int { - - // Split pollItems array into 2 separate arrays to pass to the native layer - var sArray:Array = new Array(); - var eArray:Array = new Array(); - revents = null; // Clear out revents array ready for next set of results revents = new Array(); +#if (neko || cpp) + // Split pollItems array into 2 separate arrays to pass to the native layer + var sArray:Array = new Array(); // ZMQ Sockets + var eArray:Array = new Array(); // Polled Event Types + for (p in pollItems) { sArray.push(p._socket._socketHandle); eArray.push(p._event); @@ -131,6 +134,50 @@ class ZMQPoller } catch (e:Dynamic) { return -1; } +#elseif php + var ZMQPollHandle:Dynamic = untyped __php__('new ZMQPoll()'); + for (p in pollItems) { + var s = p._socket._socketHandle; + var e = p._event; + untyped __php__('$ZMQPollHandle->add($s, $e)'); + } + var _readableNativeArr:NativeArray = untyped __php__('array()'); + var _writableNativeArr:NativeArray = untyped __php__('array()'); + + var r = untyped __php__('$ZMQPollHandle->poll($_readableNativeArr, $_writableNativeArr, $timeout)'); + var errs:NativeArray = untyped __php__('$ZMQPollHandle-> getLastErrors()'); + var errsArr = Lib.toHaxeArray(errs); + if (errsArr.length > 0) { + return -1; + } + // Convert native Array to haXe arrays + var _readableArr:Array = Lib.toHaxeArray(_readableNativeArr); + var _writableArr:Array = Lib.toHaxeArray(_writableNativeArr); + // Iterate over registered sockets to build up revents array + var item = 0; + var numEvents = 0; + for (p in pollItems) { + revents[item] = 0; + // Is this socket in the readableArr returned from the php poll? + for (ra in _readableArr) { + if (ra == p._socket._socketHandle) { + revents[item] |= ZMQ.ZMQ_POLLIN(); + break; + } + } + // Is this socket in the writableArr returned from the php poll? + for (ra in _writableArr) { + if (ra == p._socket._socketHandle) { + revents[item] |= ZMQ.ZMQ_POLLOUT(); + break; + } + } + if (revents[item] != 0) numEvents++; + item++; + } + return numEvents; + +#end } /** @@ -170,7 +217,9 @@ class ZMQPoller return (!pollin(s) && !pollout(s)); } +#if (neko || cpp) private static var _hx_zmq_poll = Lib.load("hxzmq", "hx_zmq_poll", 3); +#end } typedef PollSocketEventTuple = { diff --git a/org/zeromq/ZMQSocket.hx b/org/zeromq/ZMQSocket.hx index 6a3fa92..561cc7d 100644 --- a/org/zeromq/ZMQSocket.hx +++ b/org/zeromq/ZMQSocket.hx @@ -25,6 +25,9 @@ import neko.Lib; import neko.Sys; import org.zeromq.ZMQ; +#if php +import org.zeromq.externals.phpzmq.ZMQSocketException; +#end /** * A 0MQ socket @@ -105,15 +108,23 @@ class ZMQSocket */ public function bind(addr:String) { - if (closed) + if (_socketHandle == null || closed) throw new ZMQException(ENOTSUP); try { +#if (neko || cpp) _hx_zmq_bind(_socketHandle, Lib.haxeToNeko(addr)); +#elseif php + untyped __php__('$this->_socketHandle->bind($addr)'); +#end } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); - } - + } +#if php + catch (e:ZMQSocketException) { + throw new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end } /** @@ -127,14 +138,23 @@ class ZMQSocket */ public function connect(addr:String) { - if (closed) + if (_socketHandle == null || closed) throw new ZMQException(ENOTSUP); try { +#if (neko || cpp) _hx_zmq_connect(_socketHandle, Lib.haxeToNeko(addr)); +#elseif php + untyped __php__('$this->_socketHandle->connect($addr)'); +#end } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); } +#if php + catch (e:ZMQSocketException) { + throw new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end } @@ -144,15 +164,23 @@ class ZMQSocket * See the ZMQ documentation for details on specific options: * http://api.zeromq.org/master:zmq-setsockopt * - * + * C Parameter type optval haXe type expected + * ================= ========================== + * int Int + * int64_t, uint64_t ZMQInt64Type (if neko or cpp) + * Int (if php - will be 64bits on 64bit platforms, else 32 bit) + * binary haxe.io.Bytes + * * @param option SocketOptionsType (defined in ZMQ.hx) * @param optval Either Int or String or Bytes */ public function setsockopt(option:SocketOptionsType, optval:Dynamic):Void { - if (closed) + if (_socketHandle == null || closed) throw new ZMQException(ENOTSUP); - + + var _opt = ZMQ.socketOptionTypeNo(option); + // Handle 32 bit int options if (Lambda.exists(ZMQ.intSocketOptionTypes, function(so) { return so == option; } )) @@ -161,27 +189,48 @@ class ZMQSocket throw new String("Expected Int, got " + optval); try { - _hx_zmq_setintsockopt(_socketHandle, ZMQ.socketOptionTypeNo(option), optval); +#if (neko || cpp) + _hx_zmq_setintsockopt(_socketHandle, _opt, optval); } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); } +#elseif php + untyped __php__('$this->_socketHandle->setsockopt($_opt, $optval)'); + } catch (e:ZMQSocketException) { + new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end // Handle 64 bit int options } else if (Lambda.exists(ZMQ.int64SocketOptionTypes, function(so) { return so == option; } )) { +#if (neko || cpp) var _hi = Reflect.field(optval, "hi"); var _lo = Reflect.field(optval, "lo"); if (_hi == null || _lo == null) { throw new String("Expected ZMQInt64Type, got " + optval); return null; } - +#elseif php + if (!Std.is(optval,Int)) + throw new String("Expected Int, got " + optval); +#end + try { - _hx_zmq_setint64sockopt(_socketHandle, ZMQ.socketOptionTypeNo(option), _hi, _lo); +#if (neko || cpp) + _hx_zmq_setint64sockopt(_socketHandle, _opt, _hi, _lo); } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); } +#elseif php + // If PHPO runing on 64 bit platform, haXe Int is already 64 bits. + // If PHP is running on 32 bits, the setsockopt function converts the input to long (from int) + untyped __php__('$this->_socketHandle->setsockopt($_opt, $optval)'); + } catch (e:ZMQSocketException) { + new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end // Handle bytes options } else if (Lambda.exists(ZMQ.bytesSocketOptionTypes, @@ -192,15 +241,22 @@ class ZMQSocket return null; } try { - _hx_zmq_setbytessockopt(_socketHandle, ZMQ.socketOptionTypeNo(option), optval.getData() ); +#if (neko || cpp) + _hx_zmq_setbytessockopt(_socketHandle, _opt, optval.getData() ); } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); } - +#elseif php + var v = optval.toString(); + untyped __php__('$this->_socketHandle->setsockopt($_opt, $v)'); + } catch (e:ZMQSocketException) { + new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end } else { throw new ZMQException(EINVAL); } - return; + return; } /** @@ -211,9 +267,10 @@ class ZMQSocket */ public function getsockopt(option:SocketOptionsType):Dynamic { - var _optval:Dynamic; + var _optval:Dynamic = null; + var _opt = ZMQ.socketOptionTypeNo(option); - if (closed) { + if (_socketHandle == null || closed) { throw new ZMQException(ENOTSUP); return null; } @@ -223,7 +280,8 @@ class ZMQSocket { try { - _optval = Lib.nekoToHaxe(_hx_zmq_getintsockopt(_socketHandle, ZMQ.socketOptionTypeNo(option))); +#if (neko || cpp) + _optval = Lib.nekoToHaxe(_hx_zmq_getintsockopt(_socketHandle, _opt)); } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); return null; @@ -234,12 +292,28 @@ class ZMQSocket } else { return _optval; } +#elseif php + return untyped __php__('$this->_socketHandle->getSockOpt($_opt)'); + } + catch (e:ZMQSocketException) { + throw new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end + } else if (Lambda.exists(ZMQ.int64SocketOptionTypes, function(so) { return so == option; } )) { +#if php + try { + return untyped __php__('$this->_socketHandle->getSockOpt($_opt)'); + } + catch (e:ZMQSocketException) { + throw new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#elseif (neko || cpp) try { - _optval = Lib.nekoToHaxe(_hx_zmq_getint64sockopt(_socketHandle, ZMQ.socketOptionTypeNo(option))); + _optval = Lib.nekoToHaxe(_hx_zmq_getint64sockopt(_socketHandle, _opt)); } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); return null; @@ -252,24 +326,33 @@ class ZMQSocket } else { return {hi:_optval.hi, lo:_optval.lo}; } + #end + }else if (Lambda.exists(ZMQ.bytesSocketOptionTypes, function(so) { return so == option; } )) { try { - _optval = _hx_zmq_getbytessockopt(_socketHandle, ZMQ.socketOptionTypeNo(option)); +#if (neko || cpp) + _optval = _hx_zmq_getbytessockopt(_socketHandle, _opt); } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); return null; } return Bytes.ofData(_optval); - +#elseif php + var res = untyped __php__('$this->_socketHandle->getSockOpt($_opt)'); + return Bytes.ofString(res); + } catch (e:ZMQSocketException) { + throw new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end } else { throw new ZMQException(EINVAL); return null; } - return null; - + return null; + } /** @@ -282,15 +365,25 @@ class ZMQSocket */ public function sendMsg(data:Bytes, ?flags:SendReceiveFlagType):Void { - if (closed) { + if (_socketHandle == null || closed) { throw new ZMQException(ENOTSUP); } try { +#if (neko || cpp) _hx_zmq_send(_socketHandle, data.getData(), ZMQ.sendReceiveFlagNo(flags)); +#elseif php + + untyped __php__('$this->_socketHandle->send($data->toString(), org_zeromq_ZMQ::sendReceiveFlagNo($flags))'); +#end } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); } +#if php + catch (e:ZMQSocketException) { + throw new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end } @@ -304,24 +397,37 @@ class ZMQSocket */ public function recvMsg(?flags:SendReceiveFlagType):Bytes { - if (closed) + if (_socketHandle == null || closed) throw new ZMQException(ENOTSUP); var bytes:BytesData = null; try { +#if (neko || cpp) bytes = _hx_zmq_rcv(_socketHandle, ZMQ.sendReceiveFlagNo(flags)); + return { + if (bytes == null) { + null; + } else { + Bytes.ofData(bytes); + }; + } +#elseif php + var r:String = _hx_zmq_rcv(_socketHandle, ZMQ.sendReceiveFlagNo(flags)); + if (r != null) { + return Bytes.ofString(r); + } else + return null; +#end } catch (e:Int) { throw new ZMQException(ZMQ.errNoToErrorType(e)); } +#if php + catch (e:ZMQSocketException) { + throw new org.zeromq.ZMQException(ZMQ.errNoToErrorType(e.getCode()), e.getMessage()); + } +#end - return { - if (bytes == null) { - null; - } else { - Bytes.ofData(bytes); - }; - } } @@ -330,11 +436,16 @@ class ZMQSocket * @return */ public function hasReceiveMore():Bool { - if (closed) return false; + if (_socketHandle == null || closed) return false; var r = getsockopt(ZMQ_RCVMORE); +#if (neko || cpp) return (r != null && r.lo == 1); +#elseif php + return (r != null && r == 1); +#end } +#if (neko || cpp) private static var _hx_zmq_construct_socket = neko.Lib.load("hxzmq", "hx_zmq_construct_socket", 2); private static var _hx_zmq_close = neko.Lib.load("hxzmq", "hx_zmq_close", 1); private static var _hx_zmq_bind = neko.Lib.load("hxzmq", "hx_zmq_bind", 2); @@ -347,5 +458,24 @@ class ZMQSocket private static var _hx_zmq_getintsockopt = neko.Lib.load("hxzmq", "hx_zmq_getintsockopt", 2); private static var _hx_zmq_getint64sockopt = neko.Lib.load("hxzmq", "hx_zmq_getint64sockopt", 2); private static var _hx_zmq_getbytessockopt = neko.Lib.load("hxzmq", "hx_zmq_getbytessockopt", 2); - +#elseif php + private static function _hx_zmq_construct_socket(context:Dynamic, type:Int):Dynamic { + return untyped __php__('new ZMQSocket($context, $type)'); + } + private static function _hx_zmq_close(socket:Dynamic):Void { + untyped __call__('unset', socket); + } + private static function _hx_zmq_send(socket:Dynamic, msg:Dynamic, mode:Int):Void { + untyped __php__('$socket->send($msg, $mode)'); + } + private static function _hx_zmq_rcv(socket:Dynamic, mode:Int):String { + var r:Dynamic = untyped __php__('$socket->recv($mode)'); + // Detect if php has returned boolean false value (if NOBLOCK/DONTWAIT used) + if (Std.is(r, Bool) && !r) + return null; + else + return Std.string(r); + } + +#end } diff --git a/org/zeromq/externals/phpzmq/ZMQException.hx b/org/zeromq/externals/phpzmq/ZMQException.hx new file mode 100644 index 0000000..500353f --- /dev/null +++ b/org/zeromq/externals/phpzmq/ZMQException.hx @@ -0,0 +1,34 @@ +/** + * (c) 2011 Richard J Smith + * + * This file is part of hxzmq + * + * hxzmq is free software; you can redistribute it and/or modify it under + * the terms of the Lesser GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * hxzmq is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program. If not, see . + */ + +package org.zeromq.externals.phpzmq; + +/** + * Extern class for php-zmq ZMQException class + */ + +@:native("ZMQException") +extern class ZMQException +{ + + public function getMessage():String; + public function getCode():Int; + public function getFile():String; + public function getLine():String; +} \ No newline at end of file diff --git a/org/zeromq/externals/phpzmq/ZMQSocketException.hx b/org/zeromq/externals/phpzmq/ZMQSocketException.hx new file mode 100644 index 0000000..23e008c --- /dev/null +++ b/org/zeromq/externals/phpzmq/ZMQSocketException.hx @@ -0,0 +1,25 @@ +/** + * (c) 2011 Richard J Smith + * + * This file is part of hxzmq + * + * hxzmq is free software; you can redistribute it and/or modify it under + * the terms of the Lesser GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * hxzmq is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program. If not, see . + */ + +package org.zeromq.externals.phpzmq; + +@:native("ZMQSocketException") +extern class ZMQSocketException extends ZMQException +{ +} \ No newline at end of file diff --git a/org/zeromq/guide/MTRelay.hx b/org/zeromq/guide/MTRelay.hx index 9bdba1b..3411f54 100644 --- a/org/zeromq/guide/MTRelay.hx +++ b/org/zeromq/guide/MTRelay.hx @@ -20,7 +20,9 @@ package org.zeromq.guide; import haxe.io.Bytes; +#if !php import neko.vm.Thread; +#end import neko.Lib; import org.zeromq.ZMQ; @@ -39,7 +41,11 @@ class MTRelay // Connect to step2 and tell it we are ready var xmitter:ZMQSocket = context.socket(ZMQ_PAIR); +#if (neko || cpp) xmitter.connect("inproc://step2"); +#elseif php + xmitter.connect("ipc://step2.ipc"); +#end xmitter.sendMsg(Bytes.ofString("READY")); xmitter.close(); } @@ -49,16 +55,29 @@ class MTRelay // Bind inproc socket before starting step 1 var receiver:ZMQSocket = context.socket(ZMQ_PAIR); +#if (neko || cpp) receiver.bind("inproc://step2"); Thread.create(step1); - +#elseif php + receiver.bind("ipc://step2.ipc"); + untyped __php__(' + $pid = pcntl_fork(); + if($pid == 0) { + step1(); + exit(); + }'); +#end // Wait for signal and pass it on var msgBytes = receiver.recvMsg(); receiver.close(); // Connect to step3 and tell it we are ready var xmitter:ZMQSocket = context.socket(ZMQ_PAIR); +#if (neko || cpp) xmitter.connect("inproc://step3"); +#elseif php + xmitter.connect("ipc://step3.ipc"); +#end xmitter.sendMsg(Bytes.ofString("READY")); xmitter.close(); } @@ -72,11 +91,23 @@ class MTRelay // Bind to inproc: endpoint then start upstream thread var receiver:ZMQSocket = context.socket(ZMQ_PAIR); +#if (neko || cpp) receiver.bind("inproc://step3"); - + // Step2 relays the signal to step 3 Thread.create(step2); +#elseif php + // Use child processes instead of Threads + receiver.bind("ipc://step3.ipc"); + // Step2 relays the signal to step 3 + untyped __php__(' + $pid = pcntl_fork(); + if ($pid == 0) { + step2(); + exit(); + }'); +#end // Wait for signal var msgBytes = receiver.recvMsg(); receiver.close(); diff --git a/org/zeromq/guide/MTServer.hx b/org/zeromq/guide/MTServer.hx index cd23944..e6068bd 100644 --- a/org/zeromq/guide/MTServer.hx +++ b/org/zeromq/guide/MTServer.hx @@ -23,7 +23,9 @@ import haxe.io.Bytes; import haxe.Stack; import neko.Lib; import neko.Sys; +#if !php import neko.vm.Thread; +#end import org.zeromq.ZMQ; import org.zeromq.ZMQContext; import org.zeromq.ZMQPoller; @@ -34,6 +36,7 @@ import org.zeromq.ZMQSocket; * * See: http://zguide.zeromq.org/page:all#Multithreading-with-MQ * Use with HelloWorldClient.hx + * */ class MTServer { @@ -43,8 +46,11 @@ class MTServer // Socket to talk to dispatcher var responder:ZMQSocket = context.socket(ZMQ_REP); +#if (neko || cpp) responder.connect("inproc://workers"); - +#elseif php + responder.connect("ipc://workers.ipc"); +#end ZMQ.catchSignals(); while (true) { @@ -126,9 +132,7 @@ class MTServer } } - public static function main() { - var workerThreads:List = new List(); - + public static function main() { var context:ZMQContext = ZMQContext.instance(); Lib.println ("** MTServer (see: http://zguide.zeromq.org/page:all#Multithreading-with-MQ)"); @@ -139,13 +143,30 @@ class MTServer // Socket to talk to workers var workers:ZMQSocket = context.socket(ZMQ_DEALER); - workers.bind ("inproc://workers"); +#if (neko || cpp) + workers.bind ("inproc://workers"); + // Launch worker thread pool + var workerThreads:List = new List(); for (thread_nbr in 0 ... 5) { workerThreads.add(Thread.create(worker)); } - +#elseif php + workers.bind ("ipc://workers.ipc"); + + // Launch pool of worker processes, due to php's lack of thread support + // See: https://github.com/imatix/zguide/blob/master/examples/PHP/mtserver.php + for (thread_nbr in 0 ... 5) { + untyped __php__(' + $pid = pcntl_fork(); + if ($pid == 0) { + // Running in child process + worker(); + exit(); + }'); + } +#end // Invoke request / reply broker (aka QUEUE device) to connect clients to workers queueDevice(context, clients, workers); diff --git a/org/zeromq/guide/WUServer.hx b/org/zeromq/guide/WUServer.hx index b669284..b1571ce 100644 --- a/org/zeromq/guide/WUServer.hx +++ b/org/zeromq/guide/WUServer.hx @@ -20,7 +20,6 @@ package org.zeromq.guide; import haxe.io.Bytes; import neko.Lib; -import neko.Random; import org.zeromq.ZMQ; import org.zeromq.ZMQContext; import org.zeromq.ZMQSocket; @@ -47,7 +46,7 @@ class WUServer while (true) { // Get values that will fool the boss - var zipcode, temperature, relhumidity; + var zipcode, temperature, relhumidity; zipcode = Std.random(100000) + 1; temperature = Std.random(215) - 80 + 1; relhumidity = Std.random(50) + 10 + 1; diff --git a/org/zeromq/test/TestAll.hx b/org/zeromq/test/TestAll.hx index ccd34a7..72918a0 100644 --- a/org/zeromq/test/TestAll.hx +++ b/org/zeromq/test/TestAll.hx @@ -39,7 +39,7 @@ class TestAll runner.add(new TestMultiPartMessage()); runner.add(new TestReqRep()); runner.add(new TestPoller()); - + // // org.zeromq.remoting package tests runner.add(new TestZMQRemoting()); diff --git a/org/zeromq/test/TestPoller.hx b/org/zeromq/test/TestPoller.hx index 1b8e8a1..5d79fe8 100644 --- a/org/zeromq/test/TestPoller.hx +++ b/org/zeromq/test/TestPoller.hx @@ -63,7 +63,7 @@ class TestPoller extends BaseTest poller.registerSocket(pair.s2, pollinout); var numSocks = poller.poll(); - assertEquals(2, numSocks); + assertEquals(2, numSocks); assertEquals(2, poller.revents.length); assertTrue(poller.pollout(1)); // PAIR socket s1 should be ready for writing assertTrue(poller.pollout(2)); // PAIR socket s2 should be ready for writing diff --git a/org/zeromq/test/TestPubSub.hx b/org/zeromq/test/TestPubSub.hx index 7299961..e9eff7d 100644 --- a/org/zeromq/test/TestPubSub.hx +++ b/org/zeromq/test/TestPubSub.hx @@ -73,10 +73,9 @@ class TestPubSub extends BaseTest Sys.sleep(0.1); // make sure subscriber gets first message published by publisher pair.s1.sendMsg(Bytes.ofString("message")); // send message that shouldnt meet the subscribe filter - pair.s1.sendMsg(Bytes.ofString("xmessage")); // send message that should meet the subscribe filter var msg:Bytes = pair.s2.recvMsg(DONTWAIT); // This is a non-blocking call assertTrue(msg == null); - + pair.s1.sendMsg(Bytes.ofString("xmessage")); // send message that should meet the subscribe filter msg = pair.s2.recvMsg(); // this is a blocking call assertTrue(msg != null); assertTrue(msg.toString() == "xmessage"); diff --git a/org/zeromq/test/TestSocket.hx b/org/zeromq/test/TestSocket.hx index 2b9e806..0ee14e4 100644 --- a/org/zeromq/test/TestSocket.hx +++ b/org/zeromq/test/TestSocket.hx @@ -44,9 +44,9 @@ class TestSocket extends BaseTest assertFalse(s.closed); // Test bind to invalid protocol - assertRaisesZMQException(function() s.bind("ftl://a"), EPROTONOSUPPORT); - assertRaisesZMQException(function() s.bind("tcp://"),EINVAL); - assertRaisesZMQException(function() s.connect("ftl://a"),EPROTONOSUPPORT); + assertRaisesZMQException(function() s.bind("ftl://a"), #if php ENOTSUP #else EPROTONOSUPPORT #end); + assertRaisesZMQException(function() s.bind("tcp://"),#if php ENOTSUP #else EINVAL #end); + assertRaisesZMQException(function() s.connect("ftl://a"),#if php ENOTSUP #else EPROTONOSUPPORT #end); s.close(); @@ -87,11 +87,15 @@ class TestSocket extends BaseTest pair = createBoundPair(ZMQ_PUB, ZMQ_SUB); pair.s1.setsockopt(ZMQ_LINGER, 0); assertTrue(pair.s1.getsockopt(ZMQ_LINGER) == 0); +#if not php + // Setting ZMQ_LINGER to -1 not supported in php-zmq 0.7.0, although since fixed on master branch pair.s1.setsockopt(ZMQ_LINGER, -1); assertTrue(pair.s1.getsockopt(ZMQ_LINGER) == -1); + // ZMQ_EVENTS not supported in php-zmq 0.7.0 var r:Int = pair.s1.getsockopt(ZMQ_EVENTS); assertEquals(ZMQ.ZMQ_POLLOUT(), r); assertRaisesZMQException(function() { pair.s1.setsockopt(ZMQ_EVENTS, 2 ^ 7 - 1); }, EINVAL); +#end assertEquals(ZMQ.socketTypeNo(ZMQ_PUB), pair.s1.getsockopt(ZMQ_TYPE)); assertEquals(ZMQ.socketTypeNo(ZMQ_SUB), pair.s2.getsockopt(ZMQ_TYPE)); } catch (e:ZMQException) { @@ -102,11 +106,19 @@ class TestSocket extends BaseTest } public function testInt64SocketOptions() { - var pair:SocketPair = null; + var pair:SocketPair = null; + var v1, v2:Int; +#if (neko || cpp) var r:ZMQInt64Type = null; + +#elseif php + var r:Int = null; + var intsize = untyped __php__('PHP_INT_SIZE'); +#end try { pair = createBoundPair(ZMQ_PUB, ZMQ_SUB); +#if (neko || cpp) pair.s1.setsockopt(ZMQ_LINGER, 0); r = pair.s1.getsockopt(ZMQ_HWM); assertTrue(r.lo == 0); // Test default HWM is 0 for a new socket @@ -115,10 +127,8 @@ class TestSocket extends BaseTest var r:ZMQInt64Type = pair.s2.getsockopt(ZMQ_HWM); assertTrue(r.lo == 128); assertTrue(r.hi == 128); - r = pair.s1.getsockopt(ZMQ_AFFINITY); - assertEquals(0, r.lo); - + assertEquals(0, r.lo); r = pair.s1.getsockopt(ZMQ_SWAP); assertTrue(r.lo == 0); assertTrue(r.hi == 0); @@ -126,7 +136,24 @@ class TestSocket extends BaseTest r = pair.s1.getsockopt(ZMQ_SWAP); assertTrue(r.lo == 255); assertTrue(r.hi == 1); - +#elseif php + pair.s1.setsockopt(ZMQ_LINGER, 0); + r = pair.s1.getsockopt(ZMQ_HWM); + assertTrue(r == 0); // Test default HWM is 0 for a new socket + // If PHP int is 64bits, try a larger int value, else try a 32bit number. + v1 = { if (intsize == 8) (128 * 2 ^ 32) + 128; else 128; }; + pair.s2.setsockopt(ZMQ_HWM, v1 ); + var r:Int = pair.s2.getsockopt(ZMQ_HWM); + assertTrue(r == v1); + r = pair.s1.getsockopt(ZMQ_AFFINITY); + assertEquals(0, r); + r = pair.s1.getsockopt(ZMQ_SWAP); + assertTrue(r == 0); + v2 = { if (intsize == 8) (2 ^ 32) + 128; else 128; }; + pair.s1.setsockopt(ZMQ_SWAP, v2 ); + r = pair.s1.getsockopt(ZMQ_SWAP); + assertTrue(r == v2); +#end } catch (e:ZMQException) { trace("ZMQException #:" + e.errNo + ", str:" + e.str()); trace (Stack.toString(Stack.exceptionStack())); @@ -144,7 +171,7 @@ class TestSocket extends BaseTest // Test that you cannot retrieve a previously sefined SUBSCRIBE option value using getsockopt // See: http://api.zeromq.org/2-1-3:zmq-getsockopt - assertRaisesZMQException(function() pair.s2.getsockopt(ZMQ_SUBSCRIBE),EINVAL); + assertRaisesZMQException(function() pair.s2.getsockopt(ZMQ_SUBSCRIBE),#if php ENOTSUP #else EINVAL #end); pair.s1.setsockopt(ZMQ_IDENTITY, Bytes.ofString("Socket1")); var b:Bytes = pair.s1.getsockopt(ZMQ_IDENTITY); diff --git a/org/zeromq/test/TestVersion.hx b/org/zeromq/test/TestVersion.hx index 3ea21bd..e59e37d 100644 --- a/org/zeromq/test/TestVersion.hx +++ b/org/zeromq/test/TestVersion.hx @@ -26,6 +26,17 @@ class TestVersion extends BaseTest public function testVersionMethods() { +#if php + // version functions not supported + assertRaisesZMQException(function() ZMQ.versionMajor(), ENOTSUP); + assertRaisesZMQException(function() ZMQ.versionMinor(), ENOTSUP); + assertRaisesZMQException(function() ZMQ.versionPatch(), ENOTSUP); + + var _version = ZMQ.version_full(); + trace ("version_full:" + _version); + assertTrue(_version >= 0); + +#else var _major = ZMQ.versionMajor(); assertTrue(_major >= 2); @@ -38,12 +49,16 @@ class TestVersion extends BaseTest var _version = ZMQ.version_full(); trace ("version_full:" + _version); assertTrue(_version >= 0); - +#end } public function testMakeVersion() { +#if php + assertRaisesZMQException(function() ZMQ.makeVersion(1, 2, 3), ENOTSUP); +#else assertTrue(ZMQ.makeVersion(1, 2, 3) == 10203); +#end } public override function setup():Void { diff --git a/org/zeromq/test/TestZMQRemoting.hx b/org/zeromq/test/TestZMQRemoting.hx index 2a341f8..3c65b90 100644 --- a/org/zeromq/test/TestZMQRemoting.hx +++ b/org/zeromq/test/TestZMQRemoting.hx @@ -24,12 +24,16 @@ import haxe.remoting.Context; import haxe.io.Bytes; import haxe.remoting.Proxy; import neko.Sys; +#if !php import neko.vm.Thread; +#end import org.zeromq.remoting.ZMQConnection; import org.zeromq.ZMQ; import org.zeromq.ZMQSocket; import org.zeromq.test.helpers.HelloWorldResponderAPI; +import org.zeromq.test.BaseTest; + class TestZMQRemoting extends BaseTest { @@ -57,9 +61,11 @@ class TestZMQRemoting extends BaseTest * Also demonstrates how the ZMQ sockets could be used for remoting calls and any other message traffic. * */ - public function testRemotingSendResponse() { - + public function testThreadedRemotingSendResponse() { +#if php + assertTrue(true); +#else var responderThread:Thread = Thread.create(helloWorldResponder); var senderThread:Thread = Thread.create(helloWorldSender); @@ -80,9 +86,53 @@ class TestZMQRemoting extends BaseTest } assertEquals("Bill, "+TESTSTRING, res); } - + #end } + /** + * This method repeats the previous test but using a single thread and with tcp transport + */ + public function testSynchronousRemotingSendResponse() { + var context:ZMQContext = ZMQContext.instance(); + + var pair:SocketPair; + pair = createBoundPair(ZMQ_REQ, ZMQ_REP); + + // Socket to talk to responder + var sender:ZMQSocket = pair.s1; + // Socket to talk to sender + var responder:ZMQSocket = pair.s2; + + // Set up haXe remoting context and add remote-callable methods + var remotingContext:Context = new Context(); + remotingContext.addObject("HelloWorldResponder", new HelloWorldResponderAPI()); + var conn:ZMQConnection = ZMQConnection.create(responder, remotingContext); + + var cnx:ZMQConnection = ZMQConnection.create(sender); + // setup error handler + cnx.setErrorHandler( function(err) trace("Error : "+Std.string(err)) ); + + var me = this; + + // test 1. Use direct, untyped "call" + // Send request to responder via a ZMQConnection call + cnx.HelloWorldResponder.hello.call(["Bill"], function(s:String) { + me.assertEquals(s, "Bill, Hello World"); + }); + + // Wait for next request from client + var d = conn.getProtocol().readMessage(); + //trace ("responder received message:" + d); + conn.processMessage(d); + + // Wait for reply back + var rep:Bytes = sender.recvMsg(); + //trace ("sender received message:" + rep.toString()); + cnx.processMessage(rep.toString()); + + + } +#if (neko || cpp) static function helloWorldSender() { var context:ZMQContext = ZMQContext.instance(); @@ -178,6 +228,7 @@ class TestZMQRemoting extends BaseTest return null; } +#end } diff --git a/test/buildLinux.hxml b/test/buildLinux.hxml index 3e85ff2..d118079 100644 --- a/test/buildLinux.hxml +++ b/test/buildLinux.hxml @@ -15,3 +15,11 @@ -debug #-lib hxzmq -main org.zeromq.test.TestAll +--next +# Build PHP unit test target for Linux 32bit +-cp .. +-php out-php/Linux +-debug +--remap neko:php +#-lib hxzmq +-main org.zeromq.test.TestAll diff --git a/test/buildMac64.hxml b/test/buildMac64.hxml index 1a2e7d9..e710c28 100644 --- a/test/buildMac64.hxml +++ b/test/buildMac64.hxml @@ -16,3 +16,11 @@ -debug -lib hxzmq -main org.zeromq.test.TestAll +--next +# Build PHP unit test target for Mac64 +-cp .. +-php out-php/Mac64 +-debug +--remap neko:php +-lib hxzmq +-main org.zeromq.test.TestAll diff --git a/test/buildWindows.hxml b/test/buildWindows.hxml index 9a53b6f..5fb4773 100644 --- a/test/buildWindows.hxml +++ b/test/buildWindows.hxml @@ -13,3 +13,10 @@ -neko out-neko/Windows/TestAll.n -debug -main org.zeromq.test.TestAll +--next +# Build PHP unit test target for Windows +-cp .. +-php out-php/Windows +-debug +--remap neko:php +-main org.zeromq.test.TestAll diff --git a/zipexclude.lst b/zipexclude.lst index 377f6ef..459364f 100644 --- a/zipexclude.lst +++ b/zipexclude.lst @@ -5,12 +5,18 @@ hxzmq/guide/out-cpp/Linux/* hxzmq/guide/out-neko/Mac64/* hxzmq/guide/out-neko/Windows/* hxzmq/guide/out-neko/Linux/* +hxzmq/guide/out-php/Mac64/* +hxzmq/guide/out-php/Windows/* +hxzmq/guide/out-php/Linux/* hxzmq/test/out-cpp/Mac64/* hxzmq/test/out-cpp/Windows/* hxzmq/test/out-cpp/Linux/* hxzmq/test/out-neko/Mac64/* hxzmq/test/out-neko/Windows/* hxzmq/test/out-neko/Linux/* +hxzmq/test/out-php/Mac64/* +hxzmq/test/out-php/Windows/* +hxzmq/test/out-php/Linux/* hxzmq/lib/* hxzmq/all_objs hxzmq/hxzmq.hxproj