[
  {
    "path": ".gitignore",
    "content": "*.sw[m-p]\nphpunit\nbuild\ndoc/build\n"
  },
  {
    "path": ".travis",
    "content": "#!/bin/bash\n\nphpunit\nreturn=$?\n\necho \"\"\necho \"Server error log\"\ncat build/server.err.log\n\necho \"\"\necho \"Server log\"\ncat build/server.log\n\nexit $return\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\n\nscript: ./.travis\n\nphp:\n  - 5.3\n  - 5.4\n\nbranches:\n  only:\n    - master\n    - devel\n    - 2.0\n\nnotifications:\n  email:\n    - dominic@varspool.com\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "<!-- vim: set tw=79 sw=4 ts=4 et ft=markdown : -->\n# Changelog\n\n## 2.0.0\n\n* Name change: php-websocket was renamed to Wrench, along with a top-level\n  namespace change.\n* Moved to a more traditional project layout.\n* Added composer.json: wrench/wrench is the new package name.\n* Added PHPUnit tests, and Travis CI integration\n* Everything is now much nicer to override and customize.\n* Extensive changes to the protected API, not much change to the public API\n  * Deprecated: `$server->removeClientOnClose($client)`,\n    `$server->removeClientOnError($client)` (both cases should be managed by\n    overriding the server, or hooking into `$client->onDisconnect()`)\n  * Deprecated: `StatusApplication` and `DemoApplication`, both moved to\n    examples directory.\n* Split out new classes (and in some cases hierarchies) for protocol, payload\n  frame, connection and event handling.\n* Added dependency injection patterns everywhere to split logic out into\n  loosely coupled, replacable aggregate classes.\n* Added the Configurable interface, providing a way to configure most of the\n  primary classes in detail (if you don't feel like extending them).\n* Refactored the client class to be in the same namespace as the server\n  libraries.\n* @vincentdieltiens worked on SSL configuration, and added a method to generate\n  a certificate file.\n\n## 1.0.0\n\n* Refactored methods to open up more of the protected API.\n* @lemmingzshadow switched the server to use streams instead of sockets, and\n  implemented SSL support.\n* @mazhack added support for the new WebSocket object in Firefox 11.\n* Plenty of bugfixes\n"
  },
  {
    "path": "LICENSE",
    "content": "            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n                    Version 2, December 2004\n\n Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>\n\n Everyone is permitted to copy and distribute verbatim or modified\n copies of this license document, and changing it is allowed as long\n as the name is changed.\n\n            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. You just DO WHAT THE FUCK YOU WANT TO.\n"
  },
  {
    "path": "README.md",
    "content": "<!-- vim: set tw=79 sw=4 ts=4 et ft=markdown : -->\n# Wrench\n## Simple WebSocket Client/Server for PHP\n### Formerly known as php-websocket\n\n* Version: **2.0.0**\n* Build Status: [![Build Status](https://secure.travis-ci.org/varspool/Wrench.png?branch=master)](http://travis-ci.org/varspool/Wrench)\n* Documentation: [wrench.readthedocs.org](http://wrench.readthedocs.org/en/latest/index.html)\n\nA simple websocket server and client package for PHP 5.3/5.4, using\nstreams. Protocol support is based around [RFC 6455](http://tools.ietf.org/html/rfc6455),\ntargeting the latest stable versions of Chrome and Firefox. \n(Suggest other clients [here](https://github.com/varspool/Wrench/wiki))\n\n### Backward compatibility\n\n#### Public API\n\nThe new vendor namespace is Wrench. This namespace begins in the `/lib`\ndirectory, rather than `server/lib`.\n\nApart from the new namespace, the public API of this new major version is\nfairly compatible with that of php-websocket 1.0.0.\n\n#### Protected API\n\nThe protected API has changed, a lot. Many method have been broken up into\nsimple protected methods. This makes the Server class much easier to extend. In\nfact, almost all of the classes involved in your typical daemon can now be\nreplaced or extended, including the socket handling and protocol handling.\n\n#### What happened to the `client` dir?\n\nThe client-side libraries are no longer supported: some libraries are included\nbut are packaged only as examples. You're free to use whatever client-side\nlibraries you'd like with the server. If you're still using them, see the 1.0\nbranch.\n\n## Installation\n\nThe library is PSR-0 compatible, with a vendor name of **Wrench**. An\nSplClassLoader is bundled for convenience.\n\n## Usage\n\nThis creates a server on 127.0.0.1:8000 with one Application that listens for\nWebSocket requests to `ws://localhost:8000/echo` and `ws://localhost:8000/chat`:\n\n```php\n$server = new \\Wrench\\BasicServer('ws://localhost:8000', array(\n    'allowed_origins' => array(\n        'mysite.com',\n        'mysite.dev.localdomain'\n    )\n));\n$server->registerApplication('echo', new \\Wrench\\Examples\\EchoApplication());\n$server->registerApplication('chat', new \\My\\ChatApplication());\n$server->run();\n```\n## Authors\n\nThe original maintainer and author was\n[@nicokaiser](https://github.com/nicokaiser). Plentiful improvements were\ncontributed by [@lemmingzshadow](https://github.com/lemmingzshadow) and\n[@mazhack](https://github.com/mazhack). Parts of the Socket class were written\nby Moritz Wutz. The server is licensed under the WTFPL, a free software compatible\nlicense.\n\n## Bugs/Todos/Hints\n\n- Add tests around fragmented payloads (split into many frames).\n- To report issues, see the [issue tracker](https://github.com/varspool/Wrench/issues).\n\n## Examples\n\n- See server.php in the examples directory and\n  Wrench\\Application\\EchoApplication\n- [Jitt.li](http://jitt.li), a Twitter API sample project.\n- For Symfony2, [VarspoolWebsocketBundle](https://github.com/varspool/WebsocketBundle)\n  extends this library for use with the Service Container.\n"
  },
  {
    "path": "TODO.md",
    "content": "# TODO\n\n - Unify the socket handling of `WebSocket\\Client` with that of `Websocket\\Socket`\n - Moar tests!"
  },
  {
    "path": "VERSION",
    "content": "2.0.0\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"wrench/wrench\",\n    \"type\": \"library\",\n    \"description\": \"PHP WebSocket client/server library\",\n    \"keywords\": [\"websocket\", \"websockets\", \"hybi\"],\n    \"homepage\": \"http://github.com/varspool/Wrench\",\n    \"license\": \"WTFPL\",\n    \"authors\": [\n        {\n            \"name\":     \"Dominic Scheirlinck\",\n            \"email\":    \"dominic@varspool.com\",\n            \"homepage\": \"http://www.somethingemporium.com/\"\n        },\n        {\n            \"name\":     \"Simon Samtleben\",\n            \"email\":    \"web@lemmingzshadow.net\",\n            \"homepage\": \"http://lemmingzshadow.net/\"\n        },\n        {\n            \"name\":     \"Nico Kaiser\",\n            \"email\":    \"nico@kaiser.me\",\n            \"homepage\": \"http://siriux.net/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.3\"\n    },\n    \"autoload\": {\n        \"psr-0\": {\n            \"Wrench\": \"lib/\"\n        }\n    }\n}\n"
  },
  {
    "path": "doc/Makefile",
    "content": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nPAPER         =\nBUILDDIR      = build\nSPHPDOX       = /usr/bin/env php ~/workspace/external/sphpdox/sphpdox.php\n\n# Internal variables.\nPAPEROPT_a4     = -D latex_paper_size=a4\nPAPEROPT_letter = -D latex_paper_size=letter\nALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source\n# the i18n builder cannot share the environment and doctrees with the others\nI18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source\n\n.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext\n\nhelp:\n\t@echo \"Please use \\`make <target>' where <target> is one of\"\n\t@echo \"  html       to make standalone HTML files\"\n\t@echo \"  dirhtml    to make HTML files named index.html in directories\"\n\t@echo \"  singlehtml to make a single large HTML file\"\n\t@echo \"  pickle     to make pickle files\"\n\t@echo \"  json       to make JSON files\"\n\t@echo \"  htmlhelp   to make HTML files and a HTML help project\"\n\t@echo \"  qthelp     to make HTML files and a qthelp project\"\n\t@echo \"  devhelp    to make HTML files and a Devhelp project\"\n\t@echo \"  epub       to make an epub\"\n\t@echo \"  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\"\n\t@echo \"  latexpdf   to make LaTeX files and run them through pdflatex\"\n\t@echo \"  text       to make text files\"\n\t@echo \"  man        to make manual pages\"\n\t@echo \"  texinfo    to make Texinfo files\"\n\t@echo \"  info       to make Texinfo files and run them through makeinfo\"\n\t@echo \"  gettext    to make PO message catalogs\"\n\t@echo \"  changes    to make an overview of all changed/added/deprecated items\"\n\t@echo \"  linkcheck  to check all external links for integrity\"\n\t@echo \"  doctest    to run all doctests embedded in the documentation (if enabled)\"\n\nclean:\n\t-rm -rf $(BUILDDIR)/*\n\napi: buildapi clean copyapi html singlehtml\n\nbuildapi:\n\tcd ~/workspace/external/sphpdox && ${SPHPDOX} process -t \"API Documentation\" -x \"Wrench\\Tests\" Wrench ../../wrench/lib\n\ncopyapi:\n\trm -rf ~/workspace/wrench/doc/source/api\n\tcp -r ~/workspace/external/sphpdox/build/Wrench ~/workspace/wrench/doc/source/api\n\nhtml:\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/html.\"\n\ndirhtml:\n\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/dirhtml.\"\n\nsinglehtml:\n\t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml\n\t@echo\n\t@echo \"Build finished. The HTML page is in $(BUILDDIR)/singlehtml.\"\n\npickle:\n\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle\n\t@echo\n\t@echo \"Build finished; now you can process the pickle files.\"\n\njson:\n\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json\n\t@echo\n\t@echo \"Build finished; now you can process the JSON files.\"\n\nhtmlhelp:\n\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp\n\t@echo\n\t@echo \"Build finished; now you can run HTML Help Workshop with the\" \\\n\t      \".hhp project file in $(BUILDDIR)/htmlhelp.\"\n\nqthelp:\n\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp\n\t@echo\n\t@echo \"Build finished; now you can run \"qcollectiongenerator\" with the\" \\\n\t      \".qhcp project file in $(BUILDDIR)/qthelp, like this:\"\n\t@echo \"# qcollectiongenerator $(BUILDDIR)/qthelp/Wrench.qhcp\"\n\t@echo \"To view the help file:\"\n\t@echo \"# assistant -collectionFile $(BUILDDIR)/qthelp/Wrench.qhc\"\n\ndevhelp:\n\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp\n\t@echo\n\t@echo \"Build finished.\"\n\t@echo \"To view the help file:\"\n\t@echo \"# mkdir -p $$HOME/.local/share/devhelp/Wrench\"\n\t@echo \"# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Wrench\"\n\t@echo \"# devhelp\"\n\nepub:\n\t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub\n\t@echo\n\t@echo \"Build finished. The epub file is in $(BUILDDIR)/epub.\"\n\nlatex:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo\n\t@echo \"Build finished; the LaTeX files are in $(BUILDDIR)/latex.\"\n\t@echo \"Run \\`make' in that directory to run these through (pdf)latex\" \\\n\t      \"(use \\`make latexpdf' here to do that automatically).\"\n\nlatexpdf:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through pdflatex...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\ntext:\n\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text\n\t@echo\n\t@echo \"Build finished. The text files are in $(BUILDDIR)/text.\"\n\nman:\n\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man\n\t@echo\n\t@echo \"Build finished. The manual pages are in $(BUILDDIR)/man.\"\n\ntexinfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo\n\t@echo \"Build finished. The Texinfo files are in $(BUILDDIR)/texinfo.\"\n\t@echo \"Run \\`make' in that directory to run these through makeinfo\" \\\n\t      \"(use \\`make info' here to do that automatically).\"\n\ninfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo \"Running Texinfo files through makeinfo...\"\n\tmake -C $(BUILDDIR)/texinfo info\n\t@echo \"makeinfo finished; the Info files are in $(BUILDDIR)/texinfo.\"\n\ngettext:\n\t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale\n\t@echo\n\t@echo \"Build finished. The message catalogs are in $(BUILDDIR)/locale.\"\n\nchanges:\n\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes\n\t@echo\n\t@echo \"The overview file is in $(BUILDDIR)/changes.\"\n\nlinkcheck:\n\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck\n\t@echo\n\t@echo \"Link check complete; look for any errors in the above output \" \\\n\t      \"or in $(BUILDDIR)/linkcheck/output.txt.\"\n\ndoctest:\n\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest\n\t@echo \"Testing of doctests in the sources finished, look at the \" \\\n\t      \"results in $(BUILDDIR)/doctest/output.txt.\"\n"
  },
  {
    "path": "doc/requirements.txt",
    "content": "sphinxcontrib-phpdomain\n"
  },
  {
    "path": "doc/source/api/Application/Application.rst",
    "content": "--------------------------------\nWrench\\\\Application\\\\Application\n--------------------------------\n\n.. php:namespace: Wrench\\\\Application\n\n.. php:class:: Application\n\n    Wrench Server Application\n\n    .. php:method:: onData($payload, $connection)\n\n        Handle data received from a client\n\n        :type $payload: Payload\n        :param $payload: A payload object, that supports __toString()\n        :type $connection: Connection\n        :param $connection:\n"
  },
  {
    "path": "doc/source/api/Application/EchoApplication.rst",
    "content": "------------------------------------\nWrench\\\\Application\\\\EchoApplication\n------------------------------------\n\n.. php:namespace: Wrench\\\\Application\n\n.. php:class:: EchoApplication\n\n    Example application for Wrench: echo server\n\n    .. php:method:: onData($data, $client)\n\n        :param $data:\n        :param $client:\n"
  },
  {
    "path": "doc/source/api/Application/index.rst",
    "content": ":::::::::::::::::::\nWrench\\\\Application\n:::::::::::::::::::\n\n.. php:namespace: Wrench\\\\Application\n\n.. toctree::\n\n   Application\n   EchoApplication\n"
  },
  {
    "path": "doc/source/api/BasicServer.rst",
    "content": "-------------------\nWrench\\\\BasicServer\n-------------------\n\n.. php:namespace: Wrench\n\n.. php:class:: BasicServer\n\n    .. php:const:: EVENT_SOCKET_CONNECT\n\n        Events\n\n    .. php:attr:: rateLimiter\n\n        protected\n\n    .. php:attr:: originPolicy\n\n        protected\n\n    .. php:attr:: uri\n\n        protected string\n\n        The URI of the server\n\n    .. php:attr:: options\n\n        protected array\n\n        Options\n\n    .. php:attr:: logger\n\n        protected Closure\n\n        A logging callback\n\n        The default callback simply prints to stdout. You can pass your own logger\n        in the options array. It should take a string message and string priority\n        as parameters.\n\n    .. php:attr:: listeners\n\n        protected array<string\n\n        Event listeners\n\n        Add listeners using the addListener() method.\n\n    .. php:attr:: connectionManager\n\n        protected ConnectionManager\n\n        Connection manager\n\n    .. php:attr:: applications\n\n        protected array<string\n\n        Applications\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct($uri, $options = array())\n\n        Constructor\n\n        :type $uri: string\n        :param $uri:\n        :type $options: array\n        :param $options:\n\n    .. php:method:: configure($options)\n\n        :param $options:\n\n    .. php:method:: configureRateLimiter()\n\n    .. php:method:: configureOriginPolicy()\n\n        Configures the origin policy\n\n    .. php:method:: addAllowedOrigin($origin)\n\n        Adds an allowed origin\n\n        :type $origin: array\n        :param $origin:\n\n    .. php:method:: configureLogger()\n\n        Configures the logger\n\n        :returns: void\n\n    .. php:method:: configureConnectionManager()\n\n        Configures the connection manager\n\n        :returns: void\n\n    .. php:method:: getConnectionManager()\n\n        Gets the connection manager\n\n        :returns: \\Wrench\\ConnectionManager\n\n    .. php:method:: getUri()\n\n        :returns: string\n\n    .. php:method:: setLogger($logger)\n\n        Sets a logger\n\n        :type $logger: Closure\n        :param $logger:\n        :returns: void\n\n    .. php:method:: run()\n\n        Main server loop\n\n        :returns: void This method does not return!\n\n    .. php:method:: log($message, $priority = 'info')\n\n        Logs a message to the server log\n\n        The default logger simply prints the message to stdout. You can provide a\n        logging closure. This is useful, for instance, if you've daemonized and\n        closed STDOUT.\n\n        :type $message: string\n        :param $message: Message to display.\n        :param $priority:\n        :returns: void\n\n    .. php:method:: notify($event, $arguments = array())\n\n        Notifies listeners of an event\n\n        :type $event: string\n        :param $event:\n        :type $arguments: array\n        :param $arguments: Event arguments\n        :returns: void\n\n    .. php:method:: addListener($event, $callback)\n\n        Adds a listener\n\n        Provide an event (see the Server::EVENT_* constants) and a callback\n        closure. Some arguments may be provided to your callback, such as the\n        connection the caused the event.\n\n        :type $event: string\n        :param $event:\n        :type $callback: Closure\n        :param $callback:\n        :returns: void\n\n    .. php:method:: getApplication($key)\n\n        Returns a server application.\n\n        :type $key: string\n        :param $key: Name of application.\n        :returns: Application The application object.\n\n    .. php:method:: registerApplication($key, $application)\n\n        Adds a new application object to the application storage.\n\n        :type $key: string\n        :param $key: Name of application.\n        :type $application: object\n        :param $application: The application object\n        :returns: void\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Client.rst",
    "content": "--------------\nWrench\\\\Client\n--------------\n\n.. php:namespace: Wrench\n\n.. php:class:: Client\n\n    Client class\n\n    Represents a Wrench client\n\n    .. php:const:: MAX_HANDSHAKE_RESPONSE\n\n    .. php:attr:: uri\n\n        protected\n\n    .. php:attr:: origin\n\n        protected\n\n    .. php:attr:: socket\n\n        protected\n\n    .. php:attr:: headers\n\n        protected array\n\n        Request headers\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n        Protocol instance\n\n    .. php:attr:: options\n\n        protected array\n\n        Options\n\n    .. php:attr:: connected\n\n        protected boolean\n\n        Whether the client is connected\n\n    .. php:method:: __construct($uri, $origin, $options = array())\n\n        Constructor\n\n        :type $uri: string\n        :param $uri:\n        :type $origin: string\n        :param $origin: The origin to include in the handshake (required in later versions of the protocol)\n        :param $options:\n\n    .. php:method:: configure($options)\n\n        Configure options\n\n        :type $options: array\n        :param $options:\n        :returns: void\n\n    .. php:method:: __destruct()\n\n        Destructor\n\n    .. php:method:: addRequestHeader($name, $value)\n\n        Adds a request header to be included in the initial handshake\n\n        For example, to include a Cookie header\n\n        :type $name: string\n        :param $name:\n        :type $value: string\n        :param $value:\n        :returns: void\n\n    .. php:method:: sendData($data, $type = 'text', $masked = true)\n\n        Sends data to the socket\n\n        :type $data: string\n        :param $data:\n        :type $type: string\n        :param $type: Payload type\n        :type $masked: boolean\n        :param $masked:\n        :returns: int bytes written\n\n    .. php:method:: connect()\n\n        Connect to the Wrench server\n\n        :returns: boolean Whether a new connection was made\n\n    .. php:method:: isConnected()\n\n        Whether the client is currently connected\n\n        :returns: boolean\n\n    .. php:method:: disconnect()\n"
  },
  {
    "path": "doc/source/api/Connection.rst",
    "content": "------------------\nWrench\\\\Connection\n------------------\n\n.. php:namespace: Wrench\n\n.. php:class:: Connection\n\n    Represents a client connection on the server side\n\n    i.e. the `Server` manages a bunch of `Connection`s\n\n    .. php:attr:: manager\n\n        protected Wrench\\ConnectionManager\n\n        The connection manager\n\n    .. php:attr:: socket\n\n        protected Socket\n\n        Socket object\n\n        Wraps the client connection resource\n\n    .. php:attr:: handshaked\n\n        protected boolean\n\n        Whether the connection has successfully handshaken\n\n    .. php:attr:: application\n\n        protected Application\n\n        The application this connection belongs to\n\n    .. php:attr:: ip\n\n        protected string\n\n        The IP address of the client\n\n    .. php:attr:: port\n\n        protected int\n\n        The port of the client\n\n    .. php:attr:: id\n\n        protected string|null\n\n        Connection ID\n\n    .. php:attr:: payload\n\n        protected\n\n        The current payload\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct(ConnectionManager $manager, ServerClientSocket $socket, $options = array())\n\n        Constructor\n\n        :type $manager: ConnectionManager\n        :param $manager:\n        :type $socket: ServerClientSocket\n        :param $socket:\n        :type $options: array\n        :param $options:\n\n    .. php:method:: getConnectionManager()\n\n        Gets the connection manager of this connection\n\n        :returns: \\Wrench\\ConnectionManager\n\n    .. php:method:: configure($options)\n\n        :param $options:\n\n    .. php:method:: configureClientInformation()\n\n    .. php:method:: configureClientId()\n\n        Configures the client ID\n\n        We hash the client ID to prevent leakage of information if another client\n        happens to get a hold of an ID. The secret *must* be lengthy, and must be\n        kept secret for this to work: otherwise it's trivial to search the space\n        of possible IP addresses/ports (well, if not trivial, at least very fast).\n\n    .. php:method:: onData($data)\n\n        Data receiver\n\n        Called by the connection manager when the connection has received data\n\n        :type $data: string\n        :param $data:\n\n    .. php:method:: handshake($data)\n\n        Performs a websocket handshake\n\n        :type $data: string\n        :param $data:\n\n    .. php:method:: export($data)\n\n        Returns a string export of the given binary data\n\n        :type $data: string\n        :param $data:\n        :returns: string\n\n    .. php:method:: handle($data)\n\n        Handle data received from the client\n\n        The data passed in may belong to several different frames across one or\n        more protocols. It may not even contain a single complete frame. This\n        method manages slotting the data into separate payload objects.\n\n        :type $data: string\n        :param $data:\n\n    .. php:method:: handlePayload(Payload $payload)\n\n        Handle a complete payload received from the client\n\n        :type $payload: Payload\n        :param $payload:\n\n    .. php:method:: send($data, $type = Protocol::TYPE_TEXT)\n\n        Sends the payload to the connection\n\n        :param $data:\n        :type $type: string\n        :param $type:\n        :returns: boolean\n\n    .. php:method:: process()\n\n        Processes data on the socket\n\n    .. php:method:: close($code = Protocol::CLOSE_NORMAL)\n\n        Closes the connection according to the WebSocket protocol\n\n        :param $code:\n        :returns: boolean\n\n    .. php:method:: log($message, $priority = 'info')\n\n        Logs a message\n\n        :type $message: string\n        :param $message:\n        :type $priority: string\n        :param $priority:\n\n    .. php:method:: getIp()\n\n        Gets the IP address of the connection\n\n        :returns: string Usually dotted quad notation\n\n    .. php:method:: getPort()\n\n        Gets the port of the connection\n\n        :returns: int\n\n    .. php:method:: getId()\n\n        Gets the connection ID\n\n        :returns: string\n\n    .. php:method:: getSocket()\n\n        Gets the socket object\n\n        :returns: Socket\\ServerClientSocket\n\n    .. php:method:: getClientApplication()\n\n        Gets the client application\n\n        :returns: Application\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/ConnectionManager.rst",
    "content": "-------------------------\nWrench\\\\ConnectionManager\n-------------------------\n\n.. php:namespace: Wrench\n\n.. php:class:: ConnectionManager\n\n    .. php:attr:: server\n\n        protected Server\n\n    .. php:attr:: socket\n\n        protected Socket\n\n        Master socket\n\n    .. php:attr:: connections\n\n        protected array<int\n\n        An array of client connections\n\n    .. php:attr:: resources\n\n        protected array<int\n\n        An array of raw socket resources, corresponding to connections, roughly\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct(Server $server, $options = array())\n\n        Constructor\n\n        :type $server: Server\n        :param $server:\n        :type $options: array\n        :param $options:\n\n    .. php:method:: count()\n\n    .. php:method:: configure($options)\n\n        :param $options:\n\n    .. php:method:: getApplicationForPath($path)\n\n        Gets the application associated with the given path\n\n        :type $path: string\n        :param $path:\n\n    .. php:method:: configureMasterSocket()\n\n        Configures the main server socket\n\n    .. php:method:: listen()\n\n        Listens on the main socket\n\n        :returns: void\n\n    .. php:method:: getAllResources()\n\n        Gets all resources\n\n        :returns: array<int => resource)\n\n    .. php:method:: getConnectionForClientSocket($socket)\n\n        Returns the Connection associated with the specified socket resource\n\n        :type $socket: resource\n        :param $socket:\n        :returns: Connection\n\n    .. php:method:: selectAndProcess()\n\n        Select and process an array of resources\n\n    .. php:method:: processMasterSocket()\n\n        Process events on the master socket ($this->socket)\n\n        :returns: void\n\n    .. php:method:: createConnection($resource)\n\n        Creates a connection from a socket resource\n\n        The create connection object is based on the options passed into the\n        constructor ('connection_class', 'connection_options'). This connection\n        instance and its associated socket resource are then stored in the\n        manager.\n\n        :type $resource: resource\n        :param $resource: A socket resource\n        :returns: Connection\n\n    .. php:method:: processClientSocket($socket)\n\n        Process events on a client socket\n\n        :type $socket: resource\n        :param $socket:\n\n    .. php:method:: resourceId($resource)\n\n        This server makes an explicit assumption: PHP resource types may be cast\n        to a integer. Furthermore, we assume this is bijective. Both seem to be\n        true in most circumstances, but may not be guaranteed.\n\n        This method (and $this->getResourceId()) exist to make this assumption\n        explicit.\n\n        This is needed on the connection manager as well as on resources\n\n        :type $resource: resource\n        :param $resource:\n\n    .. php:method:: getUri()\n\n        Gets the connection manager's listening URI\n\n        :returns: string\n\n    .. php:method:: log($message, $priority = 'info')\n\n        Logs a message\n\n        :type $message: string\n        :param $message:\n        :type $priority: string\n        :param $priority:\n\n    .. php:method:: getServer()\n\n        :returns: \\Wrench\\Server\n\n    .. php:method:: removeConnection(Connection $connection)\n\n        Removes a connection\n\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Exception/BadRequestException.rst",
    "content": "--------------------------------------\nWrench\\\\Exception\\\\BadRequestException\n--------------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: BadRequestException\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __construct($message = null, $code = null, $previous = null)\n\n        :param $message:\n        :param $code:\n        :type $previous: Exception\n        :param $previous:\n\n    .. php:method:: __clone()\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/CloseException.rst",
    "content": "---------------------------------\nWrench\\\\Exception\\\\CloseException\n---------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: CloseException\n\n    Close connection exception\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __construct($message = null, $code = null, $previous = null)\n\n        :param $message:\n        :param $code:\n        :type $previous: Exception\n        :param $previous:\n\n    .. php:method:: __clone()\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/ConnectionException.rst",
    "content": "--------------------------------------\nWrench\\\\Exception\\\\ConnectionException\n--------------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: ConnectionException\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __clone()\n\n    .. php:method:: __construct($message, $code, $previous)\n\n        :param $message:\n        :param $code:\n        :param $previous:\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/Exception.rst",
    "content": "----------------------------\nWrench\\\\Exception\\\\Exception\n----------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: Exception\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __clone()\n\n    .. php:method:: __construct($message, $code, $previous)\n\n        :param $message:\n        :param $code:\n        :param $previous:\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/FrameException.rst",
    "content": "---------------------------------\nWrench\\\\Exception\\\\FrameException\n---------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: FrameException\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __clone()\n\n    .. php:method:: __construct($message, $code, $previous)\n\n        :param $message:\n        :param $code:\n        :param $previous:\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/HandshakeException.rst",
    "content": "-------------------------------------\nWrench\\\\Exception\\\\HandshakeException\n-------------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: HandshakeException\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __construct($message = null, $code = null, $previous = null)\n\n        :param $message:\n        :param $code:\n        :type $previous: Exception\n        :param $previous:\n\n    .. php:method:: __clone()\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/InvalidOriginException.rst",
    "content": "-----------------------------------------\nWrench\\\\Exception\\\\InvalidOriginException\n-----------------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: InvalidOriginException\n\n    Invalid origin exception\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __construct($message = null, $code = null, $previous = null)\n\n        :param $message:\n        :param $code:\n        :type $previous: Exception\n        :param $previous:\n\n    .. php:method:: __clone()\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/PayloadException.rst",
    "content": "-----------------------------------\nWrench\\\\Exception\\\\PayloadException\n-----------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: PayloadException\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __clone()\n\n    .. php:method:: __construct($message, $code, $previous)\n\n        :param $message:\n        :param $code:\n        :param $previous:\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/RateLimiterException.rst",
    "content": "---------------------------------------\nWrench\\\\Exception\\\\RateLimiterException\n---------------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: RateLimiterException\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __construct($message = null, $code = null, $previous = null)\n\n        :param $message:\n        :param $code:\n        :type $previous: Exception\n        :param $previous:\n\n    .. php:method:: __clone()\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/SocketException.rst",
    "content": "----------------------------------\nWrench\\\\Exception\\\\SocketException\n----------------------------------\n\n.. php:namespace: Wrench\\\\Exception\n\n.. php:class:: SocketException\n\n    .. php:attr:: message\n\n        protected\n\n    .. php:attr:: code\n\n        protected\n\n    .. php:attr:: file\n\n        protected\n\n    .. php:attr:: line\n\n        protected\n\n    .. php:method:: __clone()\n\n    .. php:method:: __construct($message, $code, $previous)\n\n        :param $message:\n        :param $code:\n        :param $previous:\n\n    .. php:method:: getMessage()\n\n    .. php:method:: getCode()\n\n    .. php:method:: getFile()\n\n    .. php:method:: getLine()\n\n    .. php:method:: getTrace()\n\n    .. php:method:: getPrevious()\n\n    .. php:method:: getTraceAsString()\n\n    .. php:method:: __toString()\n"
  },
  {
    "path": "doc/source/api/Exception/index.rst",
    "content": ":::::::::::::::::\nWrench\\\\Exception\n:::::::::::::::::\n\n.. php:namespace: Wrench\\\\Exception\n\n.. toctree::\n\n   BadRequestException\n   CloseException\n   ConnectionException\n   Exception\n   FrameException\n   HandshakeException\n   InvalidOriginException\n   PayloadException\n   RateLimiterException\n   SocketException\n"
  },
  {
    "path": "doc/source/api/Frame/Frame.rst",
    "content": "--------------------\nWrench\\\\Frame\\\\Frame\n--------------------\n\n.. php:namespace: Wrench\\\\Frame\n\n.. php:class:: Frame\n\n    Represents a WebSocket frame\n\n    .. php:attr:: length\n\n        protected int\n\n        The frame data length\n\n    .. php:attr:: type\n\n        protected int\n\n        The type of this payload\n\n    .. php:attr:: buffer\n\n        protected string\n\n        The buffer\n\n        May not be a complete payload, because this frame may still be receiving\n        data. See\n\n    .. php:attr:: payload\n\n        protected string\n\n        The enclosed frame payload\n\n        May not be a complete payload, because this frame might indicate a\n        continuation frame. See isFinal() versus isComplete()\n\n    .. php:method:: getLength()\n\n        Gets the length of the payload\n\n        :returns: int\n\n    .. php:method:: encode($data, $type = Protocol::TYPE_TEXT, $masked = false)\n\n        Resets the frame and encodes the given data into it\n\n        :type $data: string\n        :param $data:\n        :type $type: int\n        :param $type:\n        :type $masked: boolean\n        :param $masked:\n        :returns: Frame\n\n    .. php:method:: isFinal()\n\n        Whether the frame is the final one in a continuation\n\n        :returns: boolean\n\n    .. php:method:: getType()\n\n        :returns: int\n\n    .. php:method:: decodeFramePayloadFromBuffer()\n\n        Decodes a frame payload from the buffer\n\n        :returns: void\n\n    .. php:method:: getExpectedBufferLength()\n\n        Gets the expected length of the buffer once all the data has been\n        receieved\n\n        :returns: int\n\n    .. php:method:: isComplete()\n\n        Whether the frame is complete\n\n        :returns: boolean\n\n    .. php:method:: receiveData($data)\n\n        Receieves data into the frame\n\n        :param $data:\n\n    .. php:method:: getRemainingData()\n\n        Gets the remaining number of bytes before this frame will be complete\n\n        :returns: number\n\n    .. php:method:: isWaitingForData()\n\n        Whether this frame is waiting for more data\n\n        :returns: boolean\n\n    .. php:method:: getFramePayload()\n\n        Gets the contents of the frame payload\n\n        The frame must be complete to call this method.\n\n        :returns: string\n\n    .. php:method:: getFrameBuffer()\n\n        Gets the contents of the frame buffer\n\n        This is the encoded value, receieved into the frame with recieveData().\n\n        :returns: string binary\n\n    .. php:method:: getBufferLength()\n\n        Gets the expected length of the frame payload\n\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Frame/HybiFrame.rst",
    "content": "------------------------\nWrench\\\\Frame\\\\HybiFrame\n------------------------\n\n.. php:namespace: Wrench\\\\Frame\n\n.. php:class:: HybiFrame\n\n    .. php:attr:: masked\n\n        protected boolean\n\n        Whether the payload is masked\n\n    .. php:attr:: mask\n\n        protected string\n\n        Masking key\n\n    .. php:attr:: offset_payload\n\n        protected int\n\n        Byte offsets\n\n    .. php:attr:: offset_mask\n\n        protected\n\n    .. php:attr:: length\n\n        protected int\n\n        The frame data length\n\n    .. php:attr:: type\n\n        protected int\n\n        The type of this payload\n\n    .. php:attr:: buffer\n\n        protected string\n\n        The buffer\n\n        May not be a complete payload, because this frame may still be receiving\n        data. See\n\n    .. php:attr:: payload\n\n        protected string\n\n        The enclosed frame payload\n\n        May not be a complete payload, because this frame might indicate a\n        continuation frame. See isFinal() versus isComplete()\n\n    .. php:method:: encode($payload, $type = Protocol::TYPE_TEXT, $masked = false)\n\n        :param $payload:\n        :param $type:\n        :param $masked:\n\n    .. php:method:: mask($payload)\n\n        Masks/Unmasks the frame\n\n        :type $payload: string\n        :param $payload:\n        :returns: string\n\n    .. php:method:: unmask($payload)\n\n        Masks a payload\n\n        :type $payload: string\n        :param $payload:\n        :returns: string\n\n    .. php:method:: receiveData($data)\n\n        :param $data:\n\n    .. php:method:: getMask()\n\n        Gets the mask\n\n        :returns: string\n\n    .. php:method:: generateMask()\n\n        Generates a suitable masking key\n\n        :returns: string\n\n    .. php:method:: isMasked()\n\n        Whether the frame is masked\n\n        :returns: boolean\n\n    .. php:method:: getExpectedBufferLength()\n\n    .. php:method:: getPayloadOffset()\n\n        Gets the offset of the payload in the frame\n\n        :returns: int\n\n    .. php:method:: getMaskOffset()\n\n        Gets the offset in the frame to the masking bytes\n\n        :returns: int\n\n    .. php:method:: getLength()\n\n    .. php:method:: getInitialLength()\n\n        Gets the inital length value, stored in the first length byte\n\n        This determines how the rest of the length value is parsed out of the\n        frame.\n\n        :returns: int\n\n    .. php:method:: getLengthSize()\n\n        Returns the byte size of the length part of the frame\n\n        Not including the initial 7 bit part\n\n        :returns: int\n\n    .. php:method:: getMaskSize()\n\n        Returns the byte size of the mask part of the frame\n\n        :returns: int\n\n    .. php:method:: decodeFramePayloadFromBuffer()\n\n    .. php:method:: isFinal()\n\n    .. php:method:: getType()\n\n    .. php:method:: isComplete()\n\n        Whether the frame is complete\n\n        :returns: boolean\n\n    .. php:method:: getRemainingData()\n\n        Gets the remaining number of bytes before this frame will be complete\n\n        :returns: number\n\n    .. php:method:: isWaitingForData()\n\n        Whether this frame is waiting for more data\n\n        :returns: boolean\n\n    .. php:method:: getFramePayload()\n\n        Gets the contents of the frame payload\n\n        The frame must be complete to call this method.\n\n        :returns: string\n\n    .. php:method:: getFrameBuffer()\n\n        Gets the contents of the frame buffer\n\n        This is the encoded value, receieved into the frame with recieveData().\n\n        :returns: string binary\n\n    .. php:method:: getBufferLength()\n\n        Gets the expected length of the frame payload\n\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Frame/index.rst",
    "content": ":::::::::::::\nWrench\\\\Frame\n:::::::::::::\n\n.. php:namespace: Wrench\\\\Frame\n\n.. toctree::\n\n   Frame\n   HybiFrame\n"
  },
  {
    "path": "doc/source/api/Listener/HandshakeRequestListener.rst",
    "content": "------------------------------------------\nWrench\\\\Listener\\\\HandshakeRequestListener\n------------------------------------------\n\n.. php:namespace: Wrench\\\\Listener\n\n.. php:class:: HandshakeRequestListener\n\n    .. php:method:: onHandshakeRequest(Connection $connection, $path, $origin, $key, $extensions)\n\n        Handshake request listener\n\n        :type $connection: Connection\n        :param $connection:\n        :type $path: string\n        :param $path:\n        :type $origin: string\n        :param $origin:\n        :type $key: string\n        :param $key:\n        :type $extensions: array\n        :param $extensions:\n"
  },
  {
    "path": "doc/source/api/Listener/Listener.rst",
    "content": "--------------------------\nWrench\\\\Listener\\\\Listener\n--------------------------\n\n.. php:namespace: Wrench\\\\Listener\n\n.. php:class:: Listener\n\n    .. php:method:: listen(Server $server)\n\n        :type $server: Server\n        :param $server:\n"
  },
  {
    "path": "doc/source/api/Listener/OriginPolicy.rst",
    "content": "------------------------------\nWrench\\\\Listener\\\\OriginPolicy\n------------------------------\n\n.. php:namespace: Wrench\\\\Listener\n\n.. php:class:: OriginPolicy\n\n    .. php:attr:: allowed\n\n        protected\n\n    .. php:method:: __construct($allowed)\n\n        :param $allowed:\n\n    .. php:method:: onHandshakeRequest(Connection $connection, $path, $origin, $key, $extensions)\n\n        Handshake request listener\n\n        Closes the connection on handshake from an origin that isn't allowed\n\n        :type $connection: Connection\n        :param $connection:\n        :type $path: string\n        :param $path:\n        :type $origin: string\n        :param $origin:\n        :type $key: string\n        :param $key:\n        :type $extensions: array\n        :param $extensions:\n\n    .. php:method:: isAllowed($origin)\n\n        Whether the specified origin is allowed under this policy\n\n        :type $origin: string\n        :param $origin:\n        :returns: boolean\n\n    .. php:method:: listen(Server $server)\n\n        :type $server: Server\n        :param $server:\n"
  },
  {
    "path": "doc/source/api/Listener/RateLimiter.rst",
    "content": "-----------------------------\nWrench\\\\Listener\\\\RateLimiter\n-----------------------------\n\n.. php:namespace: Wrench\\\\Listener\n\n.. php:class:: RateLimiter\n\n    .. php:attr:: server\n\n        protected Server\n\n        The server being limited\n\n    .. php:attr:: ips\n\n        protected array<int>\n\n        Connection counts per IP address\n\n    .. php:attr:: requests\n\n        protected array<array<int>>\n\n        Request tokens per IP address\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct($options = array())\n\n        Constructor\n\n        :type $options: array\n        :param $options:\n\n    .. php:method:: configure($options)\n\n        :type $options: array\n        :param $options:\n\n    .. php:method:: listen(Server $server)\n\n        :type $server: Server\n        :param $server:\n\n    .. php:method:: onSocketConnect($socket, $connection)\n\n        Event listener\n\n        :type $socket: resource\n        :param $socket:\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: onSocketDisconnect($socket, $connection)\n\n        Event listener\n\n        :type $socket: resource\n        :param $socket:\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: onClientData($socket, $connection)\n\n        Event listener\n\n        :type $socket: resource\n        :param $socket:\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: checkConnections($connection)\n\n        Idempotent\n\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: checkConnectionsPerIp($connection)\n\n        NOT idempotent, call once per connection\n\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: releaseConnection($connection)\n\n        NOT idempotent, call once per disconnection\n\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: checkRequestsPerMinute($connection)\n\n        NOT idempotent, call once per data\n\n        :type $connection: Connection\n        :param $connection:\n\n    .. php:method:: limit($connection, $limit)\n\n        Limits the given connection\n\n        :type $connection: Connection\n        :param $connection:\n        :type $limit: string\n        :param $limit: Reason\n\n    .. php:method:: log($message, $priority = 'info')\n\n        Logger\n\n        :type $message: string\n        :param $message:\n        :type $priority: string\n        :param $priority:\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Listener/index.rst",
    "content": "::::::::::::::::\nWrench\\\\Listener\n::::::::::::::::\n\n.. php:namespace: Wrench\\\\Listener\n\n.. toctree::\n\n   HandshakeRequestListener\n   Listener\n   OriginPolicy\n   RateLimiter\n"
  },
  {
    "path": "doc/source/api/Payload/HybiPayload.rst",
    "content": "----------------------------\nWrench\\\\Payload\\\\HybiPayload\n----------------------------\n\n.. php:namespace: Wrench\\\\Payload\n\n.. php:class:: HybiPayload\n\n    Gets a HyBi payload\n\n    .. php:attr:: frames\n\n        protected array<Frame>\n\n        A payload may consist of one or more frames\n\n    .. php:method:: getFrame()\n\n    .. php:method:: getCurrentFrame()\n\n        Gets the current frame for the payload\n\n        :returns: mixed\n\n    .. php:method:: getReceivingFrame()\n\n        Gets the frame into which data should be receieved\n\n        :returns: Frame\n\n    .. php:method:: isComplete()\n\n        Whether the payload is complete\n\n        :returns: boolean\n\n    .. php:method:: encode($data, $type = Protocol::TYPE_TEXT, $masked = false)\n\n        Encodes a payload\n\n        :type $data: string\n        :param $data:\n        :type $type: int\n        :param $type:\n        :type $masked: boolean\n        :param $masked:\n        :returns: Payload\n\n    .. php:method:: getRemainingData()\n\n        Gets the number of remaining bytes before this payload will be\n        complete\n\n        May return 0 (no more bytes required) or null (unknown number of bytes\n        required).\n\n        :returns: number|NULL\n\n    .. php:method:: isWaitingForData()\n\n        Whether this payload is waiting for more data\n\n        :returns: boolean\n\n    .. php:method:: sendToSocket(Socket $socket)\n\n        :type $socket: Socket\n        :param $socket:\n        :returns: boolean\n\n    .. php:method:: receiveData($data)\n\n        Receive raw data into the payload\n\n        :type $data: string\n        :param $data:\n        :returns: void\n\n    .. php:method:: getPayload()\n\n        :returns: string\n\n    .. php:method:: __toString()\n\n        :returns: string\n\n    .. php:method:: getType()\n\n        Gets the type of the payload\n\n        The type of a payload is taken from its first frame\n\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Payload/Payload.rst",
    "content": "------------------------\nWrench\\\\Payload\\\\Payload\n------------------------\n\n.. php:namespace: Wrench\\\\Payload\n\n.. php:class:: Payload\n\n    Payload class\n\n    Represents a WebSocket protocol payload, which may be made up of multiple frames.\n\n    .. php:attr:: frames\n\n        protected array<Frame>\n\n        A payload may consist of one or more frames\n\n    .. php:method:: getCurrentFrame()\n\n        Gets the current frame for the payload\n\n        :returns: mixed\n\n    .. php:method:: getReceivingFrame()\n\n        Gets the frame into which data should be receieved\n\n        :returns: Frame\n\n    .. php:method:: getFrame()\n\n        Get a frame object\n\n        :returns: Frame\n\n    .. php:method:: isComplete()\n\n        Whether the payload is complete\n\n        :returns: boolean\n\n    .. php:method:: encode($data, $type = Protocol::TYPE_TEXT, $masked = false)\n\n        Encodes a payload\n\n        :type $data: string\n        :param $data:\n        :type $type: int\n        :param $type:\n        :type $masked: boolean\n        :param $masked:\n        :returns: Payload\n\n    .. php:method:: getRemainingData()\n\n        Gets the number of remaining bytes before this payload will be\n        complete\n\n        May return 0 (no more bytes required) or null (unknown number of bytes\n        required).\n\n        :returns: number|NULL\n\n    .. php:method:: isWaitingForData()\n\n        Whether this payload is waiting for more data\n\n        :returns: boolean\n\n    .. php:method:: sendToSocket(Socket $socket)\n\n        :type $socket: Socket\n        :param $socket:\n        :returns: boolean\n\n    .. php:method:: receiveData($data)\n\n        Receive raw data into the payload\n\n        :type $data: string\n        :param $data:\n        :returns: void\n\n    .. php:method:: getPayload()\n\n        :returns: string\n\n    .. php:method:: __toString()\n\n        :returns: string\n\n    .. php:method:: getType()\n\n        Gets the type of the payload\n\n        The type of a payload is taken from its first frame\n\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Payload/index.rst",
    "content": ":::::::::::::::\nWrench\\\\Payload\n:::::::::::::::\n\n.. php:namespace: Wrench\\\\Payload\n\n.. toctree::\n\n   HybiPayload\n   Payload\n"
  },
  {
    "path": "doc/source/api/Protocol/Hybi10Protocol.rst",
    "content": "--------------------------------\nWrench\\\\Protocol\\\\Hybi10Protocol\n--------------------------------\n\n.. php:namespace: Wrench\\\\Protocol\n\n.. php:class:: Hybi10Protocol\n\n    http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10\n\n    .. php:const:: SCHEME_WEBSOCKET\n\n        Relevant schemes\n\n    .. php:const:: HEADER_HOST\n\n        HTTP headers\n\n    .. php:const:: HTTP_SWITCHING_PROTOCOLS\n\n        HTTP error statuses\n\n    .. php:const:: CLOSE_NORMAL\n\n        Close statuses\n\n    .. php:const:: TYPE_CONTINUATION\n\n        Frame types\n\n        %x0 denotes a continuation frame\n         %x1 denotes a text frame\n         %x2 denotes a binary frame\n         %x3-7 are reserved for further non-control frames\n         %x8 denotes a connection close\n         %x9 denotes a ping\n         %xA denotes a pong\n         %xB-F are reserved for further control frames\n\n    .. php:const:: MAGIC_GUID\n\n        Magic GUID\n\n        Used in the WebSocket accept header\n\n    .. php:const:: UPGRADE_VALUE\n\n        The request MUST contain an |Upgrade| header field whose value\n          MUST include the \"websocket\" keyword.\n\n    .. php:const:: CONNECTION_VALUE\n\n        The request MUST contain a |Connection| header field whose value\n          MUST include the \"Upgrade\" token.\n\n    .. php:const:: REQUEST_LINE_FORMAT\n\n        Request line format\n\n    .. php:const:: REQUEST_LINE_REGEX\n\n        Request line regex\n\n        Used for parsing requested path\n\n    .. php:const:: RESPONSE_LINE_FORMAT\n\n        Response line format\n\n    .. php:const:: HEADER_LINE_FORMAT\n\n        Header line format\n\n    .. php:attr:: schemes\n\n        protected array<string>\n\n        Valid schemes\n\n    .. php:attr:: closeReasons\n\n        array<int\n\n        Close status codes\n\n    .. php:attr:: frameTypes\n\n        array<string\n\n        Frame types\n\n    .. php:attr:: httpResponses\n\n        array<int\n\n        HTTP errors\n\n    .. php:method:: getVersion()\n\n    .. php:method:: acceptsVersion($version)\n\n        This is our most recent protocol class\n\n        :param $version:\n\n    .. php:method:: getPayload()\n\n    .. php:method:: generateKey()\n\n        Generates a key suitable for use in the protocol\n\n        This base implementation returns a 16-byte (128 bit) random key as a\n        binary string.\n\n        :returns: string\n\n    .. php:method:: getRequestHandshake($uri, $key, $origin, $headers = array())\n\n        Gets request handshake string\n\n        The leading line from the client follows the Request-Line format.\n        The leading line from the server follows the Status-Line format.  The\n        Request-Line and Status-Line productions are defined in [RFC2616].\n\n        An unordered set of header fields comes after the leading line in both\n        cases.  The meaning of these header fields is specified in Section 4 of\n        this document.  Additional header fields may also be present, such as\n        cookies [RFC6265].  The format and parsing of headers is as defined in\n        [RFC2616].\n\n        :type $uri: string\n        :param $uri: WebSocket URI, e.g. ws://example.org:8000/chat\n        :type $key: string\n        :param $key: 16 byte binary string key\n        :type $origin: string\n        :param $origin: Origin of the request\n        :param $headers:\n        :returns: string\n\n    .. php:method:: getResponseHandshake($key, $headers = array())\n\n        Gets a handshake response body\n\n        :type $key: string\n        :param $key:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getResponseError($e, $headers = array())\n\n        Gets a response to an error in the handshake\n\n        :type $e: int|Exception\n        :param $e: Exception or HTTP error\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getHttpResponse($status, $headers = array())\n\n        Gets an HTTP response\n\n        :type $status: int\n        :param $status:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: validateResponseHandshake($response, $key)\n\n        :type $response: unknown_type\n        :param $response:\n        :type $key: unknown_type\n        :param $key:\n        :returns: boolean\n\n    .. php:method:: getEncodedHash($key)\n\n        Gets an encoded hash for a key\n\n        :type $key: string\n        :param $key:\n        :returns: string\n\n    .. php:method:: validateRequestHandshake($request)\n\n        Validates a request handshake\n\n        :type $request: string\n        :param $request:\n\n    .. php:method:: getCloseFrame($e)\n\n        Gets a suitable WebSocket close frame\n\n        :type $e: Exception|int\n        :param $e:\n\n    .. php:method:: validateUri($uri)\n\n        Validates a WebSocket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, int $port, string $path)\n\n    .. php:method:: validateSocketUri($uri)\n\n        Validates a socket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, string $port)\n\n    .. php:method:: validateOriginUri($origin)\n\n        Validates an origin URI\n\n        :type $origin: string\n        :param $origin:\n        :returns: string\n\n    .. php:method:: validateRequestLine($line)\n\n        Validates a request line\n\n        :type $line: string\n        :param $line:\n\n    .. php:method:: getAcceptValue($encoded_key)\n\n        Gets the expected accept value for a handshake response\n\n        Note that the protocol calls for the base64 encoded value to be hashed,\n        not the original 16 byte random key.\n\n        :param $encoded_key:\n\n    .. php:method:: getHeaders($response, $request_line = null)\n\n        Gets the headers from a full response\n\n        :type $response: string\n        :param $response:\n        :param $request_line:\n        :returns: array()\n\n    .. php:method:: getRequestHeaders($response)\n\n        Gets request headers\n\n        :type $response: string\n        :param $response:\n        :returns: array<string, array<string>> The request line, and an array of headers\n\n    .. php:method:: validateScheme($scheme)\n\n        Validates a scheme\n\n        :type $scheme: string\n        :param $scheme:\n        :returns: string Underlying scheme\n\n    .. php:method:: getDefaultRequestHeaders($host, $key, $origin)\n\n        Gets the default request headers\n\n        :type $host: string\n        :param $host:\n        :type $key: string\n        :param $key:\n        :type $origin: string\n        :param $origin:\n        :returns: multitype:unknown string NULL\n\n    .. php:method:: getSuccessResponseHeaders($key)\n\n        Gets the default response headers\n\n        :type $key: string\n        :param $key:\n\n    .. php:method:: getPort($scheme)\n\n        Gets the default port for a scheme\n\n        By default, the WebSocket Protocol uses port 80 for regular WebSocket\n        connections and port 443 for WebSocket connections tunneled over Transport\n        Layer Security\n\n        :param $scheme:\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Protocol/HybiProtocol.rst",
    "content": "------------------------------\nWrench\\\\Protocol\\\\HybiProtocol\n------------------------------\n\n.. php:namespace: Wrench\\\\Protocol\n\n.. php:class:: HybiProtocol\n\n    .. php:const:: SCHEME_WEBSOCKET\n\n        Relevant schemes\n\n    .. php:const:: HEADER_HOST\n\n        HTTP headers\n\n    .. php:const:: HTTP_SWITCHING_PROTOCOLS\n\n        HTTP error statuses\n\n    .. php:const:: CLOSE_NORMAL\n\n        Close statuses\n\n    .. php:const:: TYPE_CONTINUATION\n\n        Frame types\n\n        %x0 denotes a continuation frame\n         %x1 denotes a text frame\n         %x2 denotes a binary frame\n         %x3-7 are reserved for further non-control frames\n         %x8 denotes a connection close\n         %x9 denotes a ping\n         %xA denotes a pong\n         %xB-F are reserved for further control frames\n\n    .. php:const:: MAGIC_GUID\n\n        Magic GUID\n\n        Used in the WebSocket accept header\n\n    .. php:const:: UPGRADE_VALUE\n\n        The request MUST contain an |Upgrade| header field whose value\n          MUST include the \"websocket\" keyword.\n\n    .. php:const:: CONNECTION_VALUE\n\n        The request MUST contain a |Connection| header field whose value\n          MUST include the \"Upgrade\" token.\n\n    .. php:const:: REQUEST_LINE_FORMAT\n\n        Request line format\n\n    .. php:const:: REQUEST_LINE_REGEX\n\n        Request line regex\n\n        Used for parsing requested path\n\n    .. php:const:: RESPONSE_LINE_FORMAT\n\n        Response line format\n\n    .. php:const:: HEADER_LINE_FORMAT\n\n        Header line format\n\n    .. php:attr:: schemes\n\n        protected array<string>\n\n        Valid schemes\n\n    .. php:attr:: closeReasons\n\n        array<int\n\n        Close status codes\n\n    .. php:attr:: frameTypes\n\n        array<string\n\n        Frame types\n\n    .. php:attr:: httpResponses\n\n        array<int\n\n        HTTP errors\n\n    .. php:method:: getPayload()\n\n    .. php:method:: getVersion()\n\n        Gets a version number\n\n    .. php:method:: acceptsVersion($version)\n\n        Subclasses should implement this method and return a boolean to the given\n        version string, as to whether they would like to accept requests from\n        user agents that specify that version.\n\n        :param $version:\n        :returns: boolean\n\n    .. php:method:: generateKey()\n\n        Generates a key suitable for use in the protocol\n\n        This base implementation returns a 16-byte (128 bit) random key as a\n        binary string.\n\n        :returns: string\n\n    .. php:method:: getRequestHandshake($uri, $key, $origin, $headers = array())\n\n        Gets request handshake string\n\n        The leading line from the client follows the Request-Line format.\n        The leading line from the server follows the Status-Line format.  The\n        Request-Line and Status-Line productions are defined in [RFC2616].\n\n        An unordered set of header fields comes after the leading line in both\n        cases.  The meaning of these header fields is specified in Section 4 of\n        this document.  Additional header fields may also be present, such as\n        cookies [RFC6265].  The format and parsing of headers is as defined in\n        [RFC2616].\n\n        :type $uri: string\n        :param $uri: WebSocket URI, e.g. ws://example.org:8000/chat\n        :type $key: string\n        :param $key: 16 byte binary string key\n        :type $origin: string\n        :param $origin: Origin of the request\n        :param $headers:\n        :returns: string\n\n    .. php:method:: getResponseHandshake($key, $headers = array())\n\n        Gets a handshake response body\n\n        :type $key: string\n        :param $key:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getResponseError($e, $headers = array())\n\n        Gets a response to an error in the handshake\n\n        :type $e: int|Exception\n        :param $e: Exception or HTTP error\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getHttpResponse($status, $headers = array())\n\n        Gets an HTTP response\n\n        :type $status: int\n        :param $status:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: validateResponseHandshake($response, $key)\n\n        :type $response: unknown_type\n        :param $response:\n        :type $key: unknown_type\n        :param $key:\n        :returns: boolean\n\n    .. php:method:: getEncodedHash($key)\n\n        Gets an encoded hash for a key\n\n        :type $key: string\n        :param $key:\n        :returns: string\n\n    .. php:method:: validateRequestHandshake($request)\n\n        Validates a request handshake\n\n        :type $request: string\n        :param $request:\n\n    .. php:method:: getCloseFrame($e)\n\n        Gets a suitable WebSocket close frame\n\n        :type $e: Exception|int\n        :param $e:\n\n    .. php:method:: validateUri($uri)\n\n        Validates a WebSocket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, int $port, string $path)\n\n    .. php:method:: validateSocketUri($uri)\n\n        Validates a socket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, string $port)\n\n    .. php:method:: validateOriginUri($origin)\n\n        Validates an origin URI\n\n        :type $origin: string\n        :param $origin:\n        :returns: string\n\n    .. php:method:: validateRequestLine($line)\n\n        Validates a request line\n\n        :type $line: string\n        :param $line:\n\n    .. php:method:: getAcceptValue($encoded_key)\n\n        Gets the expected accept value for a handshake response\n\n        Note that the protocol calls for the base64 encoded value to be hashed,\n        not the original 16 byte random key.\n\n        :param $encoded_key:\n\n    .. php:method:: getHeaders($response, $request_line = null)\n\n        Gets the headers from a full response\n\n        :type $response: string\n        :param $response:\n        :param $request_line:\n        :returns: array()\n\n    .. php:method:: getRequestHeaders($response)\n\n        Gets request headers\n\n        :type $response: string\n        :param $response:\n        :returns: array<string, array<string>> The request line, and an array of headers\n\n    .. php:method:: validateScheme($scheme)\n\n        Validates a scheme\n\n        :type $scheme: string\n        :param $scheme:\n        :returns: string Underlying scheme\n\n    .. php:method:: getDefaultRequestHeaders($host, $key, $origin)\n\n        Gets the default request headers\n\n        :type $host: string\n        :param $host:\n        :type $key: string\n        :param $key:\n        :type $origin: string\n        :param $origin:\n        :returns: multitype:unknown string NULL\n\n    .. php:method:: getSuccessResponseHeaders($key)\n\n        Gets the default response headers\n\n        :type $key: string\n        :param $key:\n\n    .. php:method:: getPort($scheme)\n\n        Gets the default port for a scheme\n\n        By default, the WebSocket Protocol uses port 80 for regular WebSocket\n        connections and port 443 for WebSocket connections tunneled over Transport\n        Layer Security\n\n        :param $scheme:\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Protocol/Protocol.rst",
    "content": "--------------------------\nWrench\\\\Protocol\\\\Protocol\n--------------------------\n\n.. php:namespace: Wrench\\\\Protocol\n\n.. php:class:: Protocol\n\n    Definitions and implementation helpers for the Wrenchs protocol\n\n    Based on RFC 6455: http://tools.ietf.org/html/rfc6455\n\n    .. php:const:: SCHEME_WEBSOCKET\n\n        Relevant schemes\n\n    .. php:const:: HEADER_HOST\n\n        HTTP headers\n\n    .. php:const:: HTTP_SWITCHING_PROTOCOLS\n\n        HTTP error statuses\n\n    .. php:const:: CLOSE_NORMAL\n\n        Close statuses\n\n    .. php:const:: TYPE_CONTINUATION\n\n        Frame types\n\n        %x0 denotes a continuation frame\n         %x1 denotes a text frame\n         %x2 denotes a binary frame\n         %x3-7 are reserved for further non-control frames\n         %x8 denotes a connection close\n         %x9 denotes a ping\n         %xA denotes a pong\n         %xB-F are reserved for further control frames\n\n    .. php:const:: MAGIC_GUID\n\n        Magic GUID\n\n        Used in the WebSocket accept header\n\n    .. php:const:: UPGRADE_VALUE\n\n        The request MUST contain an |Upgrade| header field whose value\n          MUST include the \"websocket\" keyword.\n\n    .. php:const:: CONNECTION_VALUE\n\n        The request MUST contain a |Connection| header field whose value\n          MUST include the \"Upgrade\" token.\n\n    .. php:const:: REQUEST_LINE_FORMAT\n\n        Request line format\n\n    .. php:const:: REQUEST_LINE_REGEX\n\n        Request line regex\n\n        Used for parsing requested path\n\n    .. php:const:: RESPONSE_LINE_FORMAT\n\n        Response line format\n\n    .. php:const:: HEADER_LINE_FORMAT\n\n        Header line format\n\n    .. php:attr:: schemes\n\n        protected array<string>\n\n        Valid schemes\n\n    .. php:attr:: closeReasons\n\n        array<int\n\n        Close status codes\n\n    .. php:attr:: frameTypes\n\n        array<string\n\n        Frame types\n\n    .. php:attr:: httpResponses\n\n        array<int\n\n        HTTP errors\n\n    .. php:method:: getVersion()\n\n        Gets a version number\n\n    .. php:method:: acceptsVersion($version)\n\n        Subclasses should implement this method and return a boolean to the given\n        version string, as to whether they would like to accept requests from\n        user agents that specify that version.\n\n        :param $version:\n        :returns: boolean\n\n    .. php:method:: getPayload()\n\n        Gets a payload instance, suitable for use in decoding/encoding protocol\n        frames\n\n        :returns: Payload\n\n    .. php:method:: generateKey()\n\n        Generates a key suitable for use in the protocol\n\n        This base implementation returns a 16-byte (128 bit) random key as a\n        binary string.\n\n        :returns: string\n\n    .. php:method:: getRequestHandshake($uri, $key, $origin, $headers = array())\n\n        Gets request handshake string\n\n        The leading line from the client follows the Request-Line format.\n        The leading line from the server follows the Status-Line format.  The\n        Request-Line and Status-Line productions are defined in [RFC2616].\n\n        An unordered set of header fields comes after the leading line in both\n        cases.  The meaning of these header fields is specified in Section 4 of\n        this document.  Additional header fields may also be present, such as\n        cookies [RFC6265].  The format and parsing of headers is as defined in\n        [RFC2616].\n\n        :type $uri: string\n        :param $uri: WebSocket URI, e.g. ws://example.org:8000/chat\n        :type $key: string\n        :param $key: 16 byte binary string key\n        :type $origin: string\n        :param $origin: Origin of the request\n        :param $headers:\n        :returns: string\n\n    .. php:method:: getResponseHandshake($key, $headers = array())\n\n        Gets a handshake response body\n\n        :type $key: string\n        :param $key:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getResponseError($e, $headers = array())\n\n        Gets a response to an error in the handshake\n\n        :type $e: int|Exception\n        :param $e: Exception or HTTP error\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getHttpResponse($status, $headers = array())\n\n        Gets an HTTP response\n\n        :type $status: int\n        :param $status:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: validateResponseHandshake($response, $key)\n\n        :type $response: unknown_type\n        :param $response:\n        :type $key: unknown_type\n        :param $key:\n        :returns: boolean\n\n    .. php:method:: getEncodedHash($key)\n\n        Gets an encoded hash for a key\n\n        :type $key: string\n        :param $key:\n        :returns: string\n\n    .. php:method:: validateRequestHandshake($request)\n\n        Validates a request handshake\n\n        :type $request: string\n        :param $request:\n\n    .. php:method:: getCloseFrame($e)\n\n        Gets a suitable WebSocket close frame\n\n        :type $e: Exception|int\n        :param $e:\n\n    .. php:method:: validateUri($uri)\n\n        Validates a WebSocket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, int $port, string $path)\n\n    .. php:method:: validateSocketUri($uri)\n\n        Validates a socket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, string $port)\n\n    .. php:method:: validateOriginUri($origin)\n\n        Validates an origin URI\n\n        :type $origin: string\n        :param $origin:\n        :returns: string\n\n    .. php:method:: validateRequestLine($line)\n\n        Validates a request line\n\n        :type $line: string\n        :param $line:\n\n    .. php:method:: getAcceptValue($encoded_key)\n\n        Gets the expected accept value for a handshake response\n\n        Note that the protocol calls for the base64 encoded value to be hashed,\n        not the original 16 byte random key.\n\n        :param $encoded_key:\n\n    .. php:method:: getHeaders($response, $request_line = null)\n\n        Gets the headers from a full response\n\n        :type $response: string\n        :param $response:\n        :param $request_line:\n        :returns: array()\n\n    .. php:method:: getRequestHeaders($response)\n\n        Gets request headers\n\n        :type $response: string\n        :param $response:\n        :returns: array<string, array<string>> The request line, and an array of headers\n\n    .. php:method:: validateScheme($scheme)\n\n        Validates a scheme\n\n        :type $scheme: string\n        :param $scheme:\n        :returns: string Underlying scheme\n\n    .. php:method:: getDefaultRequestHeaders($host, $key, $origin)\n\n        Gets the default request headers\n\n        :type $host: string\n        :param $host:\n        :type $key: string\n        :param $key:\n        :type $origin: string\n        :param $origin:\n        :returns: multitype:unknown string NULL\n\n    .. php:method:: getSuccessResponseHeaders($key)\n\n        Gets the default response headers\n\n        :type $key: string\n        :param $key:\n\n    .. php:method:: getPort($scheme)\n\n        Gets the default port for a scheme\n\n        By default, the WebSocket Protocol uses port 80 for regular WebSocket\n        connections and port 443 for WebSocket connections tunneled over Transport\n        Layer Security\n\n        :param $scheme:\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Protocol/Rfc6455Protocol.rst",
    "content": "---------------------------------\nWrench\\\\Protocol\\\\Rfc6455Protocol\n---------------------------------\n\n.. php:namespace: Wrench\\\\Protocol\n\n.. php:class:: Rfc6455Protocol\n\n    This is the version of websockets used by Chrome versions 17 through 19.\n\n    .. php:const:: SCHEME_WEBSOCKET\n\n        Relevant schemes\n\n    .. php:const:: HEADER_HOST\n\n        HTTP headers\n\n    .. php:const:: HTTP_SWITCHING_PROTOCOLS\n\n        HTTP error statuses\n\n    .. php:const:: CLOSE_NORMAL\n\n        Close statuses\n\n    .. php:const:: TYPE_CONTINUATION\n\n        Frame types\n\n        %x0 denotes a continuation frame\n         %x1 denotes a text frame\n         %x2 denotes a binary frame\n         %x3-7 are reserved for further non-control frames\n         %x8 denotes a connection close\n         %x9 denotes a ping\n         %xA denotes a pong\n         %xB-F are reserved for further control frames\n\n    .. php:const:: MAGIC_GUID\n\n        Magic GUID\n\n        Used in the WebSocket accept header\n\n    .. php:const:: UPGRADE_VALUE\n\n        The request MUST contain an |Upgrade| header field whose value\n          MUST include the \"websocket\" keyword.\n\n    .. php:const:: CONNECTION_VALUE\n\n        The request MUST contain a |Connection| header field whose value\n          MUST include the \"Upgrade\" token.\n\n    .. php:const:: REQUEST_LINE_FORMAT\n\n        Request line format\n\n    .. php:const:: REQUEST_LINE_REGEX\n\n        Request line regex\n\n        Used for parsing requested path\n\n    .. php:const:: RESPONSE_LINE_FORMAT\n\n        Response line format\n\n    .. php:const:: HEADER_LINE_FORMAT\n\n        Header line format\n\n    .. php:attr:: schemes\n\n        protected array<string>\n\n        Valid schemes\n\n    .. php:attr:: closeReasons\n\n        array<int\n\n        Close status codes\n\n    .. php:attr:: frameTypes\n\n        array<string\n\n        Frame types\n\n    .. php:attr:: httpResponses\n\n        array<int\n\n        HTTP errors\n\n    .. php:method:: getVersion()\n\n    .. php:method:: acceptsVersion($version)\n\n        This is our most recent protocol class\n\n        :param $version:\n\n    .. php:method:: getPayload()\n\n    .. php:method:: generateKey()\n\n        Generates a key suitable for use in the protocol\n\n        This base implementation returns a 16-byte (128 bit) random key as a\n        binary string.\n\n        :returns: string\n\n    .. php:method:: getRequestHandshake($uri, $key, $origin, $headers = array())\n\n        Gets request handshake string\n\n        The leading line from the client follows the Request-Line format.\n        The leading line from the server follows the Status-Line format.  The\n        Request-Line and Status-Line productions are defined in [RFC2616].\n\n        An unordered set of header fields comes after the leading line in both\n        cases.  The meaning of these header fields is specified in Section 4 of\n        this document.  Additional header fields may also be present, such as\n        cookies [RFC6265].  The format and parsing of headers is as defined in\n        [RFC2616].\n\n        :type $uri: string\n        :param $uri: WebSocket URI, e.g. ws://example.org:8000/chat\n        :type $key: string\n        :param $key: 16 byte binary string key\n        :type $origin: string\n        :param $origin: Origin of the request\n        :param $headers:\n        :returns: string\n\n    .. php:method:: getResponseHandshake($key, $headers = array())\n\n        Gets a handshake response body\n\n        :type $key: string\n        :param $key:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getResponseError($e, $headers = array())\n\n        Gets a response to an error in the handshake\n\n        :type $e: int|Exception\n        :param $e: Exception or HTTP error\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: getHttpResponse($status, $headers = array())\n\n        Gets an HTTP response\n\n        :type $status: int\n        :param $status:\n        :type $headers: array\n        :param $headers:\n\n    .. php:method:: validateResponseHandshake($response, $key)\n\n        :type $response: unknown_type\n        :param $response:\n        :type $key: unknown_type\n        :param $key:\n        :returns: boolean\n\n    .. php:method:: getEncodedHash($key)\n\n        Gets an encoded hash for a key\n\n        :type $key: string\n        :param $key:\n        :returns: string\n\n    .. php:method:: validateRequestHandshake($request)\n\n        Validates a request handshake\n\n        :type $request: string\n        :param $request:\n\n    .. php:method:: getCloseFrame($e)\n\n        Gets a suitable WebSocket close frame\n\n        :type $e: Exception|int\n        :param $e:\n\n    .. php:method:: validateUri($uri)\n\n        Validates a WebSocket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, int $port, string $path)\n\n    .. php:method:: validateSocketUri($uri)\n\n        Validates a socket URI\n\n        :type $uri: string\n        :param $uri:\n        :returns: array(string $scheme, string $host, string $port)\n\n    .. php:method:: validateOriginUri($origin)\n\n        Validates an origin URI\n\n        :type $origin: string\n        :param $origin:\n        :returns: string\n\n    .. php:method:: validateRequestLine($line)\n\n        Validates a request line\n\n        :type $line: string\n        :param $line:\n\n    .. php:method:: getAcceptValue($encoded_key)\n\n        Gets the expected accept value for a handshake response\n\n        Note that the protocol calls for the base64 encoded value to be hashed,\n        not the original 16 byte random key.\n\n        :param $encoded_key:\n\n    .. php:method:: getHeaders($response, $request_line = null)\n\n        Gets the headers from a full response\n\n        :type $response: string\n        :param $response:\n        :param $request_line:\n        :returns: array()\n\n    .. php:method:: getRequestHeaders($response)\n\n        Gets request headers\n\n        :type $response: string\n        :param $response:\n        :returns: array<string, array<string>> The request line, and an array of headers\n\n    .. php:method:: validateScheme($scheme)\n\n        Validates a scheme\n\n        :type $scheme: string\n        :param $scheme:\n        :returns: string Underlying scheme\n\n    .. php:method:: getDefaultRequestHeaders($host, $key, $origin)\n\n        Gets the default request headers\n\n        :type $host: string\n        :param $host:\n        :type $key: string\n        :param $key:\n        :type $origin: string\n        :param $origin:\n        :returns: multitype:unknown string NULL\n\n    .. php:method:: getSuccessResponseHeaders($key)\n\n        Gets the default response headers\n\n        :type $key: string\n        :param $key:\n\n    .. php:method:: getPort($scheme)\n\n        Gets the default port for a scheme\n\n        By default, the WebSocket Protocol uses port 80 for regular WebSocket\n        connections and port 443 for WebSocket connections tunneled over Transport\n        Layer Security\n\n        :param $scheme:\n        :returns: int\n"
  },
  {
    "path": "doc/source/api/Protocol/index.rst",
    "content": "::::::::::::::::\nWrench\\\\Protocol\n::::::::::::::::\n\n.. php:namespace: Wrench\\\\Protocol\n\n.. toctree::\n\n   Hybi10Protocol\n   HybiProtocol\n   Protocol\n   Rfc6455Protocol\n"
  },
  {
    "path": "doc/source/api/Resource.rst",
    "content": "----------------\nWrench\\\\Resource\n----------------\n\n.. php:namespace: Wrench\n\n.. php:class:: Resource\n\n    Resource interface\n\n    .. php:method:: getResourceId()\n\n    .. php:method:: getResource()\n"
  },
  {
    "path": "doc/source/api/Server.rst",
    "content": "--------------\nWrench\\\\Server\n--------------\n\n.. php:namespace: Wrench\n\n.. php:class:: Server\n\n    WebSocket server\n\n    The server extends socket, which provides the master socket resource. This resource is listened to, and an array of clients managed.\n\n    .. php:const:: EVENT_SOCKET_CONNECT\n\n        Events\n\n    .. php:attr:: uri\n\n        protected string\n\n        The URI of the server\n\n    .. php:attr:: options\n\n        protected array\n\n        Options\n\n    .. php:attr:: logger\n\n        protected Closure\n\n        A logging callback\n\n        The default callback simply prints to stdout. You can pass your own logger\n        in the options array. It should take a string message and string priority\n        as parameters.\n\n    .. php:attr:: listeners\n\n        protected array<string\n\n        Event listeners\n\n        Add listeners using the addListener() method.\n\n    .. php:attr:: connectionManager\n\n        protected ConnectionManager\n\n        Connection manager\n\n    .. php:attr:: applications\n\n        protected array<string\n\n        Applications\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct($uri, $options = array())\n\n        Constructor\n\n        :type $uri: string\n        :param $uri: Websocket URI, e.g. ws://localhost:8000/, path will be ignored\n        :type $options: array\n        :param $options: (optional) See configure\n\n    .. php:method:: configure($options)\n\n        Configure options\n\n        Options include\n        - socket_class      => The socket class to use, defaults to ServerSocket\n        - socket_options    => An array of socket options\n        - logger            => Closure($message, $priority = 'info'), used for\n        logging\n\n        :type $options: array\n        :param $options:\n        :returns: void\n\n    .. php:method:: configureLogger()\n\n        Configures the logger\n\n        :returns: void\n\n    .. php:method:: configureConnectionManager()\n\n        Configures the connection manager\n\n        :returns: void\n\n    .. php:method:: getConnectionManager()\n\n        Gets the connection manager\n\n        :returns: \\Wrench\\ConnectionManager\n\n    .. php:method:: getUri()\n\n        :returns: string\n\n    .. php:method:: setLogger($logger)\n\n        Sets a logger\n\n        :type $logger: Closure\n        :param $logger:\n        :returns: void\n\n    .. php:method:: run()\n\n        Main server loop\n\n        :returns: void This method does not return!\n\n    .. php:method:: log($message, $priority = 'info')\n\n        Logs a message to the server log\n\n        The default logger simply prints the message to stdout. You can provide a\n        logging closure. This is useful, for instance, if you've daemonized and\n        closed STDOUT.\n\n        :type $message: string\n        :param $message: Message to display.\n        :param $priority:\n        :returns: void\n\n    .. php:method:: notify($event, $arguments = array())\n\n        Notifies listeners of an event\n\n        :type $event: string\n        :param $event:\n        :type $arguments: array\n        :param $arguments: Event arguments\n        :returns: void\n\n    .. php:method:: addListener($event, $callback)\n\n        Adds a listener\n\n        Provide an event (see the Server::EVENT_* constants) and a callback\n        closure. Some arguments may be provided to your callback, such as the\n        connection the caused the event.\n\n        :type $event: string\n        :param $event:\n        :type $callback: Closure\n        :param $callback:\n        :returns: void\n\n    .. php:method:: getApplication($key)\n\n        Returns a server application.\n\n        :type $key: string\n        :param $key: Name of application.\n        :returns: Application The application object.\n\n    .. php:method:: registerApplication($key, $application)\n\n        Adds a new application object to the application storage.\n\n        :type $key: string\n        :param $key: Name of application.\n        :type $application: object\n        :param $application: The application object\n        :returns: void\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Socket/ClientSocket.rst",
    "content": "----------------------------\nWrench\\\\Socket\\\\ClientSocket\n----------------------------\n\n.. php:namespace: Wrench\\\\Socket\n\n.. php:class:: ClientSocket\n\n    Options:\n     - timeout_connect      => int, seconds, default 2\n\n    .. php:const:: TIMEOUT_CONNECT\n\n        Default connection timeout\n\n    .. php:const:: TIMEOUT_SOCKET\n\n        Default timeout for socket operations (reads, writes)\n\n    .. php:const:: DEFAULT_RECEIVE_LENGTH\n\n    .. php:const:: NAME_PART_IP\n\n        Socket name parts\n\n    .. php:attr:: scheme\n\n        protected\n\n    .. php:attr:: host\n\n        protected\n\n    .. php:attr:: port\n\n        protected\n\n    .. php:attr:: socket\n\n        protected resource\n\n    .. php:attr:: context\n\n        protected\n\n        Stream context\n\n    .. php:attr:: connected\n\n        protected boolean\n\n        Whether the socket is connected to a server\n\n        Note, the connection may not be ready to use, but the socket is connected\n        at least. See $handshaked, and other properties in subclasses.\n\n    .. php:attr:: firstRead\n\n        protected boolean\n\n        Whether the current read is the first one to the socket\n\n    .. php:attr:: name\n\n        protected string\n\n        The socket name according to stream_socket_get_name\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: configure($options)\n\n        :param $options:\n\n    .. php:method:: connect()\n\n        Connects to the given socket\n\n    .. php:method:: reconnect()\n\n    .. php:method:: getSocketStreamContextOptions()\n\n    .. php:method:: getSslStreamContextOptions()\n\n    .. php:method:: __construct($uri, $options = array())\n\n        URI Socket constructor\n\n        :type $uri: string\n        :param $uri: WebSocket URI, e.g. ws://example.org:8000/chat\n        :param $options:\n\n    .. php:method:: getUri()\n\n        Gets the canonical/normalized URI for this socket\n\n        :returns: string\n\n    .. php:method:: getName()\n\n    .. php:method:: getHost()\n\n        Gets the host name\n\n    .. php:method:: getPort()\n\n    .. php:method:: getStreamContext($listen = false)\n\n        Gets a stream context\n\n        :param $listen:\n\n    .. php:method:: getNamePart($name, $part)\n\n        Gets part of the name of the socket\n\n        PHP seems to return IPV6 address/port combos like this:\n        ::1:1234, where ::1 is the address and 1234 the port So, the part number\n        here is either the last : delimited section (the port)\n        or all the other sections (the whole initial part, the address).\n\n        :type $name: string\n        :param $name: (from $this->getName() usually)\n        :param $part:\n        :returns: string\n\n    .. php:method:: getIp()\n\n        Gets the IP address of the socket\n\n        :returns: string\n\n    .. php:method:: getLastError()\n\n        Get the last error that occurred on the socket\n\n        :returns: int|string\n\n    .. php:method:: isConnected()\n\n        Whether the socket is currently connected\n\n        :returns: boolean\n\n    .. php:method:: disconnect()\n\n        Disconnect the socket\n\n        :returns: void\n\n    .. php:method:: getResource()\n\n    .. php:method:: getResourceId()\n\n    .. php:method:: send($data)\n\n        :type $data: unknown_type\n        :param $data:\n        :returns: boolean|int The number of bytes sent or false on error\n\n    .. php:method:: receive($length = self::DEFAULT_RECEIVE_LENGTH)\n\n        Recieve data from the socket\n\n        :type $length: int\n        :param $length:\n        :returns: string\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Socket/ServerClientSocket.rst",
    "content": "----------------------------------\nWrench\\\\Socket\\\\ServerClientSocket\n----------------------------------\n\n.. php:namespace: Wrench\\\\Socket\n\n.. php:class:: ServerClientSocket\n\n    .. php:const:: TIMEOUT_SOCKET\n\n        Default timeout for socket operations (reads, writes)\n\n    .. php:const:: DEFAULT_RECEIVE_LENGTH\n\n    .. php:const:: NAME_PART_IP\n\n        Socket name parts\n\n    .. php:attr:: socket\n\n        protected resource\n\n    .. php:attr:: context\n\n        protected\n\n        Stream context\n\n    .. php:attr:: connected\n\n        protected boolean\n\n        Whether the socket is connected to a server\n\n        Note, the connection may not be ready to use, but the socket is connected\n        at least. See $handshaked, and other properties in subclasses.\n\n    .. php:attr:: firstRead\n\n        protected boolean\n\n        Whether the current read is the first one to the socket\n\n    .. php:attr:: name\n\n        protected string\n\n        The socket name according to stream_socket_get_name\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct($accepted_socket, $options = array())\n\n        Constructor\n\n        A server client socket is accepted from a listening socket, so there's no\n        need to call ->connect() or whatnot.\n\n        :type $accepted_socket: resource\n        :param $accepted_socket:\n        :type $options: array\n        :param $options:\n\n    .. php:method:: configure($options)\n\n        Configure options\n\n        Options include\n        - timeout_connect      => int, seconds, default 2\n        - timeout_socket       => int, seconds, default 5\n\n        :type $options: array\n        :param $options:\n        :returns: void\n\n    .. php:method:: getName()\n\n        Gets the name of the socket\n\n    .. php:method:: getNamePart($name, $part)\n\n        Gets part of the name of the socket\n\n        PHP seems to return IPV6 address/port combos like this:\n        ::1:1234, where ::1 is the address and 1234 the port So, the part number\n        here is either the last : delimited section (the port)\n        or all the other sections (the whole initial part, the address).\n\n        :type $name: string\n        :param $name: (from $this->getName() usually)\n        :param $part:\n        :returns: string\n\n    .. php:method:: getIp()\n\n        Gets the IP address of the socket\n\n        :returns: string\n\n    .. php:method:: getPort()\n\n        Gets the port of the socket\n\n        :returns: int\n\n    .. php:method:: getLastError()\n\n        Get the last error that occurred on the socket\n\n        :returns: int|string\n\n    .. php:method:: isConnected()\n\n        Whether the socket is currently connected\n\n        :returns: boolean\n\n    .. php:method:: disconnect()\n\n        Disconnect the socket\n\n        :returns: void\n\n    .. php:method:: getResource()\n\n    .. php:method:: getResourceId()\n\n    .. php:method:: send($data)\n\n        :type $data: unknown_type\n        :param $data:\n        :returns: boolean|int The number of bytes sent or false on error\n\n    .. php:method:: receive($length = self::DEFAULT_RECEIVE_LENGTH)\n\n        Recieve data from the socket\n\n        :type $length: int\n        :param $length:\n        :returns: string\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Socket/ServerSocket.rst",
    "content": "----------------------------\nWrench\\\\Socket\\\\ServerSocket\n----------------------------\n\n.. php:namespace: Wrench\\\\Socket\n\n.. php:class:: ServerSocket\n\n    Server socket\n\n    Used for a server's \"master\" socket that binds to the configured interface and listens\n\n    .. php:const:: TIMEOUT_SOCKET\n\n        Default timeout for socket operations (reads, writes)\n\n    .. php:const:: DEFAULT_RECEIVE_LENGTH\n\n    .. php:const:: NAME_PART_IP\n\n        Socket name parts\n\n    .. php:attr:: listening\n\n        protected boolean\n\n        Whether the socket is listening\n\n    .. php:attr:: scheme\n\n        protected\n\n    .. php:attr:: host\n\n        protected\n\n    .. php:attr:: port\n\n        protected\n\n    .. php:attr:: socket\n\n        protected resource\n\n    .. php:attr:: context\n\n        protected\n\n        Stream context\n\n    .. php:attr:: connected\n\n        protected boolean\n\n        Whether the socket is connected to a server\n\n        Note, the connection may not be ready to use, but the socket is connected\n        at least. See $handshaked, and other properties in subclasses.\n\n    .. php:attr:: firstRead\n\n        protected boolean\n\n        Whether the current read is the first one to the socket\n\n    .. php:attr:: name\n\n        protected string\n\n        The socket name according to stream_socket_get_name\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: configure($options)\n\n        :param $options:\n\n    .. php:method:: listen()\n\n        Listens\n\n    .. php:method:: accept()\n\n        Accepts a new connection on the socket\n\n        :returns: resource\n\n    .. php:method:: getSocketStreamContextOptions()\n\n    .. php:method:: getSslStreamContextOptions()\n\n    .. php:method:: __construct($uri, $options = array())\n\n        URI Socket constructor\n\n        :type $uri: string\n        :param $uri: WebSocket URI, e.g. ws://example.org:8000/chat\n        :param $options:\n\n    .. php:method:: getUri()\n\n        Gets the canonical/normalized URI for this socket\n\n        :returns: string\n\n    .. php:method:: getName()\n\n    .. php:method:: getHost()\n\n        Gets the host name\n\n    .. php:method:: getPort()\n\n    .. php:method:: getStreamContext($listen = false)\n\n        Gets a stream context\n\n        :param $listen:\n\n    .. php:method:: getNamePart($name, $part)\n\n        Gets part of the name of the socket\n\n        PHP seems to return IPV6 address/port combos like this:\n        ::1:1234, where ::1 is the address and 1234 the port So, the part number\n        here is either the last : delimited section (the port)\n        or all the other sections (the whole initial part, the address).\n\n        :type $name: string\n        :param $name: (from $this->getName() usually)\n        :param $part:\n        :returns: string\n\n    .. php:method:: getIp()\n\n        Gets the IP address of the socket\n\n        :returns: string\n\n    .. php:method:: getLastError()\n\n        Get the last error that occurred on the socket\n\n        :returns: int|string\n\n    .. php:method:: isConnected()\n\n        Whether the socket is currently connected\n\n        :returns: boolean\n\n    .. php:method:: disconnect()\n\n        Disconnect the socket\n\n        :returns: void\n\n    .. php:method:: getResource()\n\n    .. php:method:: getResourceId()\n\n    .. php:method:: send($data)\n\n        :type $data: unknown_type\n        :param $data:\n        :returns: boolean|int The number of bytes sent or false on error\n\n    .. php:method:: receive($length = self::DEFAULT_RECEIVE_LENGTH)\n\n        Recieve data from the socket\n\n        :type $length: int\n        :param $length:\n        :returns: string\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Socket/Socket.rst",
    "content": "----------------------\nWrench\\\\Socket\\\\Socket\n----------------------\n\n.. php:namespace: Wrench\\\\Socket\n\n.. php:class:: Socket\n\n    Socket class\n\n    Implements low level logic for connecting, serving, reading to, and writing from WebSocket connections using PHP's streams.\n\n    Unlike in previous versions of this library, a Socket instance now represents a single underlying socket resource. It's designed to be used by aggregation, rather than inheritence.\n\n    .. php:const:: TIMEOUT_SOCKET\n\n        Default timeout for socket operations (reads, writes)\n\n    .. php:const:: DEFAULT_RECEIVE_LENGTH\n\n    .. php:const:: NAME_PART_IP\n\n        Socket name parts\n\n    .. php:attr:: socket\n\n        protected resource\n\n    .. php:attr:: context\n\n        protected\n\n        Stream context\n\n    .. php:attr:: connected\n\n        protected boolean\n\n        Whether the socket is connected to a server\n\n        Note, the connection may not be ready to use, but the socket is connected\n        at least. See $handshaked, and other properties in subclasses.\n\n    .. php:attr:: firstRead\n\n        protected boolean\n\n        Whether the current read is the first one to the socket\n\n    .. php:attr:: name\n\n        protected string\n\n        The socket name according to stream_socket_get_name\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: configure($options)\n\n        Configure options\n\n        Options include\n        - timeout_connect      => int, seconds, default 2\n        - timeout_socket       => int, seconds, default 5\n\n        :type $options: array\n        :param $options:\n        :returns: void\n\n    .. php:method:: getName()\n\n        Gets the name of the socket\n\n    .. php:method:: getNamePart($name, $part)\n\n        Gets part of the name of the socket\n\n        PHP seems to return IPV6 address/port combos like this:\n        ::1:1234, where ::1 is the address and 1234 the port So, the part number\n        here is either the last : delimited section (the port)\n        or all the other sections (the whole initial part, the address).\n\n        :type $name: string\n        :param $name: (from $this->getName() usually)\n        :param $part:\n        :returns: string\n\n    .. php:method:: getIp()\n\n        Gets the IP address of the socket\n\n        :returns: string\n\n    .. php:method:: getPort()\n\n        Gets the port of the socket\n\n        :returns: int\n\n    .. php:method:: getLastError()\n\n        Get the last error that occurred on the socket\n\n        :returns: int|string\n\n    .. php:method:: isConnected()\n\n        Whether the socket is currently connected\n\n        :returns: boolean\n\n    .. php:method:: disconnect()\n\n        Disconnect the socket\n\n        :returns: void\n\n    .. php:method:: getResource()\n\n    .. php:method:: getResourceId()\n\n    .. php:method:: send($data)\n\n        :type $data: unknown_type\n        :param $data:\n        :returns: boolean|int The number of bytes sent or false on error\n\n    .. php:method:: receive($length = self::DEFAULT_RECEIVE_LENGTH)\n\n        Recieve data from the socket\n\n        :type $length: int\n        :param $length:\n        :returns: string\n\n    .. php:method:: __construct($options = array())\n\n        Configurable constructor\n\n        :param $options:\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Socket/UriSocket.rst",
    "content": "-------------------------\nWrench\\\\Socket\\\\UriSocket\n-------------------------\n\n.. php:namespace: Wrench\\\\Socket\n\n.. php:class:: UriSocket\n\n    .. php:const:: TIMEOUT_SOCKET\n\n        Default timeout for socket operations (reads, writes)\n\n    .. php:const:: DEFAULT_RECEIVE_LENGTH\n\n    .. php:const:: NAME_PART_IP\n\n        Socket name parts\n\n    .. php:attr:: scheme\n\n        protected\n\n    .. php:attr:: host\n\n        protected\n\n    .. php:attr:: port\n\n        protected\n\n    .. php:attr:: socket\n\n        protected resource\n\n    .. php:attr:: context\n\n        protected\n\n        Stream context\n\n    .. php:attr:: connected\n\n        protected boolean\n\n        Whether the socket is connected to a server\n\n        Note, the connection may not be ready to use, but the socket is connected\n        at least. See $handshaked, and other properties in subclasses.\n\n    .. php:attr:: firstRead\n\n        protected boolean\n\n        Whether the current read is the first one to the socket\n\n    .. php:attr:: name\n\n        protected string\n\n        The socket name according to stream_socket_get_name\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct($uri, $options = array())\n\n        URI Socket constructor\n\n        :type $uri: string\n        :param $uri: WebSocket URI, e.g. ws://example.org:8000/chat\n        :param $options:\n\n    .. php:method:: getUri()\n\n        Gets the canonical/normalized URI for this socket\n\n        :returns: string\n\n    .. php:method:: getName()\n\n    .. php:method:: getHost()\n\n        Gets the host name\n\n    .. php:method:: getPort()\n\n    .. php:method:: getStreamContext($listen = false)\n\n        Gets a stream context\n\n        :param $listen:\n\n    .. php:method:: getSocketStreamContextOptions()\n\n        Returns an array of socket stream context options\n\n        See http://php.net/manual/en/context.socket.php\n\n        :returns: array\n\n    .. php:method:: getSslStreamContextOptions()\n\n        Returns an array of ssl stream context options\n\n        See http://php.net/manual/en/context.ssl.php\n\n        :returns: array\n\n    .. php:method:: configure($options)\n\n        Configure options\n\n        Options include\n        - timeout_connect      => int, seconds, default 2\n        - timeout_socket       => int, seconds, default 5\n\n        :type $options: array\n        :param $options:\n        :returns: void\n\n    .. php:method:: getNamePart($name, $part)\n\n        Gets part of the name of the socket\n\n        PHP seems to return IPV6 address/port combos like this:\n        ::1:1234, where ::1 is the address and 1234 the port So, the part number\n        here is either the last : delimited section (the port)\n        or all the other sections (the whole initial part, the address).\n\n        :type $name: string\n        :param $name: (from $this->getName() usually)\n        :param $part:\n        :returns: string\n\n    .. php:method:: getIp()\n\n        Gets the IP address of the socket\n\n        :returns: string\n\n    .. php:method:: getLastError()\n\n        Get the last error that occurred on the socket\n\n        :returns: int|string\n\n    .. php:method:: isConnected()\n\n        Whether the socket is currently connected\n\n        :returns: boolean\n\n    .. php:method:: disconnect()\n\n        Disconnect the socket\n\n        :returns: void\n\n    .. php:method:: getResource()\n\n    .. php:method:: getResourceId()\n\n    .. php:method:: send($data)\n\n        :type $data: unknown_type\n        :param $data:\n        :returns: boolean|int The number of bytes sent or false on error\n\n    .. php:method:: receive($length = self::DEFAULT_RECEIVE_LENGTH)\n\n        Recieve data from the socket\n\n        :type $length: int\n        :param $length:\n        :returns: string\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Socket/index.rst",
    "content": "::::::::::::::\nWrench\\\\Socket\n::::::::::::::\n\n.. php:namespace: Wrench\\\\Socket\n\n.. toctree::\n\n   ClientSocket\n   ServerClientSocket\n   ServerSocket\n   Socket\n   UriSocket\n"
  },
  {
    "path": "doc/source/api/Util/Configurable.rst",
    "content": "--------------------------\nWrench\\\\Util\\\\Configurable\n--------------------------\n\n.. php:namespace: Wrench\\\\Util\n\n.. php:class:: Configurable\n\n    Configurable base class\n\n    .. php:attr:: options\n\n        protected array\n\n    .. php:attr:: protocol\n\n        protected Protocol\n\n    .. php:method:: __construct($options = array())\n\n        Configurable constructor\n\n        :param $options:\n\n    .. php:method:: configure($options)\n\n        Configures the options\n\n        :type $options: array\n        :param $options:\n\n    .. php:method:: configureProtocol()\n\n        Configures the protocol option\n"
  },
  {
    "path": "doc/source/api/Util/Ssl.rst",
    "content": "-----------------\nWrench\\\\Util\\\\Ssl\n-----------------\n\n.. php:namespace: Wrench\\\\Util\n\n.. php:class:: Ssl\n\n    .. php:method:: generatePemFile($pem_file, $pem_passphrase, $country_name, $state_or_province_name, $locality_name, $organization_name, $organizational_unit_name, $common_name, $email_address)\n\n        Generates a new PEM File given the informations\n\n        :type $pem_file: string\n        :param $pem_file: the path of the PEM file to create\n        :type $pem_passphrase: string\n        :param $pem_passphrase: the passphrase to protect the PEM file or if you don't want to use a passphrase\n        :type $country_name: string\n        :param $country_name: the country code of the new PEM file. e.g.: EN\n        :type $state_or_province_name: string\n        :param $state_or_province_name: the state or province name of the new PEM file\n        :type $locality_name: string\n        :param $locality_name: the name of the locality\n        :param $organization_name:\n        :param $organizational_unit_name:\n        :param $common_name:\n        :type $email_address: string\n        :param $email_address: the email address\n"
  },
  {
    "path": "doc/source/api/Util/index.rst",
    "content": "::::::::::::\nWrench\\\\Util\n::::::::::::\n\n.. php:namespace: Wrench\\\\Util\n\n.. toctree::\n\n   Configurable\n   Ssl\n"
  },
  {
    "path": "doc/source/api/index.rst",
    "content": "`````````````````\nAPI Documentation\n`````````````````\n\n.. php:namespace: Wrench\n\n.. toctree::\n\n   Application/index\n   BasicServer\n   Client\n   Connection\n   ConnectionManager\n   Exception/index\n   Frame/index\n   Listener/index\n   Payload/index\n   Protocol/index\n   Resource\n   Server\n   Socket/index\n   Util/index\n"
  },
  {
    "path": "doc/source/authors.rst",
    "content": "-------\nAuthors\n-------\n\nThe original maintainer and author was `@nicokaiser\n<https://github.com/nicokaiser>`_. Plentiful improvements were contributed by\n`@lemmingzshadow <https://github.com/lemmingzshadow>`_ and `@mazhack\n<https://github.com/mazhack>`_. Parts of the Socket class were written by\nMoritz Wutz. The server is licensed under the WTFPL, a free software compatible\nlicense.\n\n"
  },
  {
    "path": "doc/source/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Wrench documentation build configuration file, created by\n# sphinx-quickstart on Thu Jul 26 13:09:51 2012.\n#\n# This file is execfile()d with the current directory set to its containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\nimport sys, os\nimport sphinx.highlighting, pygments.lexers\n\n# Highlight PHP code without <?php\nsphinx.highlighting.lexers['php'] = pygments.lexers.PhpLexer(startinline = True)\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#sys.path.insert(0, os.path.abspath('.'))\n\n# -- General configuration -----------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be extensions\n# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.\nextensions = ['sphinxcontrib.phpdomain']\n\n# Primary domain\nprimary_domain = 'php'\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix of source filenames.\nsource_suffix = '.rst'\n\n# The encoding of source files.\n#source_encoding = 'utf-8-sig'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General information about the project.\nproject = u'Wrench'\ncopyright = u'2012, Dominic Scheirlinck and Contributors'\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nversion = '2.0'\n# The full version, including alpha/beta/rc tags.\nrelease = '2.0.0-beta'\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#language = None\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\n#today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = []\n\n# The reST default role (used for this markup: `text`) to use for all documents.\n#default_role = None\ndefault_role = 'php:class'\n\n# Default highlight language\nhighlight_language = 'php'\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = 'sphinx'\n\n# A list of ignored prefixes for module index sorting.\n#modindex_common_prefix = []\n\n\n# -- Options for HTML output ---------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\nhtml_theme = 'default'\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#html_theme_options = {}\n\n# Add any paths that contain custom themes here, relative to this directory.\n#html_theme_path = []\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n#html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n#html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\n#html_logo = None\n\n# The name of an image file (within the static path) to use as favicon of the\n# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32\n# pixels large.\n#html_favicon = None\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\n#html_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n#html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_domain_indices = True\n\n# If false, no index is generated.\n#html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n#html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\n#html_show_sourcelink = True\n\n# If true, \"Created using Sphinx\" is shown in the HTML footer. Default is True.\n#html_show_sphinx = True\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer. Default is True.\n#html_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\n#html_use_opensearch = ''\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\n#html_file_suffix = None\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'Wrench'\n\n\n# -- Options for LaTeX output --------------------------------------------------\n\nlatex_elements = {\n# The paper size ('letterpaper' or 'a4paper').\n#'papersize': 'letterpaper',\n\n# The font size ('10pt', '11pt' or '12pt').\n#'pointsize': '10pt',\n\n# Additional stuff for the LaTeX preamble.\n#'preamble': '',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title, author, documentclass [howto/manual]).\nlatex_documents = [\n  ('index', 'Wrench.tex', u'Wrench Documentation',\n   u'Dominic Scheirlinck and Contributors', 'manual'),\n]\n\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\n#latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n#latex_use_parts = False\n\n# If true, show page references after internal links.\n#latex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n#latex_show_urls = False\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\n#latex_domain_indices = True\n\n\n# -- Options for manual page output --------------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    ('index', 'wrench', u'Wrench Documentation',\n     [u'Dominic Scheirlinck and Contributors'], 1)\n]\n\n# If true, show URL addresses after external links.\n#man_show_urls = False\n\n\n# -- Options for Texinfo output ------------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n  ('index', 'Wrench', u'Wrench Documentation',\n   u'Dominic Scheirlinck and Contributors', 'Wrench', 'PHP WebSockets library.',\n   'Miscellaneous'),\n]\n\n# Documents to append as an appendix to all manuals.\n#texinfo_appendices = []\n\n# If false, no module index is generated.\n#texinfo_domain_indices = True\n\n# How to display URL addresses: 'footnote', 'no', or 'inline'.\n#texinfo_show_urls = 'footnote'\n"
  },
  {
    "path": "doc/source/getting-started.rst",
    "content": ".. vim: set tw=78 sw=4 ts=4 :\n\n***************\nGetting Started\n***************\n\n-----------------\nStarting a Server\n-----------------\n\nThe first thing you'll want to do to serve WebSockets from PHP is start a\nWebSockets server. Wrench provides a simple Server class that implements the\nmost recent version of the WebSockts protocol. Subclassing the Server class is\nencouraged: see WebSocket\\BasicServer for an example.\n\nWhen you're ready for your server to start responding to requests, call\n$server->run()::\n\n    use Wrench\\BasicServer;\n\n    $server = new BasicServer('ws://localhost:8000', array(\n        'allowed_origins' => array(\n            'mysite.com',\n            'mysite.dev.localdomain'\n        )\n    ));\n\n    // Register your applications\n\n    $server->run();\n\n--------------------------\nRegistering an Application\n--------------------------\n\nThe server on its own doesn't do anything until you write an Application for\nit. The server calls methods on your applications once they are registered::\n\n    $server->registerApplication('echo', new \\Wrench\\Examples\\EchoApplication());\n    $server->registerApplication('chat', new \\My\\ChatApplication());\n"
  },
  {
    "path": "doc/source/index.rst",
    "content": ".. vim: set tw=78 sw=2 ts=2 :\n\n======\nWrench\n======\n\nWrench is a WebSockets library for PHP 5.3+\n\n.. toctree::\n   :maxdepth: 3\n\n   introduction\n   installing\n   getting-started\n   performance\n   api/index\n   authors\n\n"
  },
  {
    "path": "doc/source/installing.rst",
    "content": ".. vim: set tw=78 sw=4 ts=4 :\n\n*****************\nInstalling Wrench\n*****************\n\nThe library is PSR-0 compatible, with a vendor name of **Wrench**. An\nSplClassLoader is bundled for convenience. The simplest possible bootstrap\nlooks like this::\n\n    require_once 'SplClassLoader.php';\n\n    $classLoader = new \\SplClassLoader('Wrench', __DIR__ . '/../path/to/wrench/lib');\n    $classLoader->register();\n\n--------\ncomposer\n--------\n\nWrench is available on Packagist as `wrench/wrench <http://packagist.org/packages/wrench/wrench>`_.\n\nHere's what it looks like in your :file:`composer.json`\n\n.. code-block:: json\n\n    {\n        ...\n        \"require\": {\n            \"wrench/wrench\": \"dev-master\"\n        }\n    }\n\n---------\ndeps file\n---------\n\nUsing Symfony2 with a traditional style deps file? You can configure Wrench\nlike this:\n\n.. code-block:: ini\n\n    [wrench]\n        git=git://github.com/varspool/Wrench.git\n        version=origin/master\n"
  },
  {
    "path": "doc/source/introduction.rst",
    "content": ".. vim: set tw=78 sw=4 ts=4 :\n\n************\nIntroduction\n************\n\nWrench is a simple websocket server and client package for PHP 5.3/5.4, using\nstreams.\n\n-------------\nphp-websocket\n-------------\n\nWrench was previously known as php-websocket. Why the name change? See\n`Frequently Asked Questions about the PHP License\n<http://php.net/license/index.php#fac-lic>`_.  Also, the namespace WebSocket\nis too generic; it denotes a common functionality, and may already be in use\nby application code. The BC break of a new `major version\n<http://semver.org/>`_ was a good time to introduce this move to best\npractices.\n\n"
  },
  {
    "path": "doc/source/performance.rst",
    "content": ".. vim: set tw=78 sw=4 ts=4 :\n\n***********\nPerformance\n***********\n\nWrench uses a single-process server, without threads, and blocks while\nprocessing data from any client. This means it has little hope of scaling in\nproduction.\n\nYou might like to use some middleware between your PHP application code and\nWebSocket clients in production. For example, you might use something like\n`RabbitMQ's STOMP + WebSockets Plugin\n<http://www.rabbitmq.com/blog/2012/05/14/introducing-rabbitmq-web-stomp/>`_. In\nany case, if you're hoping to serve large numbers of clients, you should\nprobably look into one of the evented IO based servers.\n"
  },
  {
    "path": "doc/source/setup.py",
    "content": "#!/usr/bin/env python\n\nfrom distutils.core import setup\n\nsetup(\n        name='wrench-documentation',\n        version='2.0.0',\n        requires=[\n            \"sphinxcontrib.phpdomain\"\n        ]\n     )\n"
  },
  {
    "path": "examples/StatusApplication.php",
    "content": "<?php\nnamespace Wrench\\Application;\n\n/**\n * Shiny WSS Status Application\n * Provides live server infos/messages to client/browser.\n *\n * @author Simon Samtleben <web@lemmingzshadow.net>\n */\nclass StatusApplication extends Application\n{\n    private $_clients           = array();\n    private $_serverClients     = array();\n    private $_serverInfo        = array();\n    private $_serverClientCount = 0;\n\n\n    public function onConnect($client)\n    {\n        $id = $client->getClientId();\n        $this->_clients[$id] = $client;\n        $this->_sendServerinfo($client);\n    }\n\n    public function onDisconnect($client)\n    {\n        $id = $client->getClientId();\n        unset($this->_clients[$id]);\n    }\n\n    public function onData($data, $client)\n    {\n        // currently not in use...\n    }\n\n    public function setServerInfo($serverInfo)\n    {\n        if (is_array($serverInfo)) {\n            $this->_serverInfo = $serverInfo;\n            return true;\n        }\n\n        return false;\n    }\n\n\n    public function clientConnected($ip, $port)\n    {\n        $this->_serverClients[$port] = $ip;\n        $this->_serverClientCount++;\n        $this->statusMsg('Client connected: ' . $ip . ':' . $port);\n\n        $data = array(\n            'ip' => $ip,\n            'port' => $port,\n            'clientCount' => $this->_serverClientCount,\n        );\n\n        $encodedData = $this->_encodeData('clientConnected', $data);\n\n        $this->_sendAll($encodedData);\n    }\n\n    public function clientDisconnected($ip, $port)\n    {\n        if (!isset($this->_serverClients[$port])) {\n            return false;\n        }\n\n        unset($this->_serverClients[$port]);\n\n        $this->_serverClientCount--;\n        $this->statusMsg('Client disconnected: ' . $ip . ':' . $port);\n\n        $data = array(\n            'port' => $port,\n            'clientCount' => $this->_serverClientCount,\n        );\n\n        $encodedData = $this->_encodeData('clientDisconnected', $data);\n\n        $this->_sendAll($encodedData);\n    }\n\n    public function clientActivity($port)\n    {\n        $encodedData = $this->_encodeData('clientActivity', $port);\n        $this->_sendAll($encodedData);\n    }\n\n    public function statusMsg($text, $type = 'info')\n    {\n        $data = array(\n            'type' => $type,\n            'text' => '[' . strftime('%m-%d %H:%M', time()) . '] ' . $text,\n        );\n\n        $encodedData = $this->_encodeData('statusMsg', $data);\n\n        $this->_sendAll($encodedData);\n    }\n\n    private function _sendServerinfo($client)\n    {\n        if (count($this->_clients) < 1) {\n            return false;\n        }\n\n        $currentServerInfo                = $this->_serverInfo;\n        $currentServerInfo['clientCount'] = count($this->_serverClients);\n        $currentServerInfo['clients']     = $this->_serverClients;\n        $encodedData                      = $this->_encodeData('serverInfo', $currentServerInfo);\n\n        $client->send($encodedData);\n    }\n\n    private function _sendAll($encodedData)\n    {\n        if (count($this->_clients) < 1) {\n            return false;\n        }\n\n        foreach ($this->_clients as $sendto) {\n            $sendto->send($encodedData);\n        }\n    }\n}"
  },
  {
    "path": "examples/coffeescript/coffee/client.coffee",
    "content": "$(document).ready ->\n  log = (msg) -> $('#log').append(\"#{msg}<br />\")\n  serverUrl = 'ws://127.0.0.1:8000/demo'\n  if window.MozWebSocket\n    socket = new MozWebSocket serverUrl\n  else if window.WebSocket\n    socket = new WebSocket serverUrl\n  socket.binaryType = 'blob'\n\n  socket.onopen = (msg) ->\n    $('#status').removeClass().addClass('online').html('connected')\n\n  socket.onmessage = (msg) ->\n    response = JSON.parse(msg.data)\n    log(\"Action: #{response.action}\")\n    log(\"Data: #{response.data}\")\n\n  socket.onclose = (msg) ->\n    $('#status').removeClass().addClass('offline').html('disconnected')\n\n  $('#status').click ->\n    socket.close()\n\n  $('#send').click ->\n    payload = new Object()\n    payload.action = $('#action').val()\n    payload.data = $('#data').val()\n    socket.send(JSON.stringify(payload))\n\n  $('#sendfile').click ->\n    data = document.binaryFrame.file.files[0]\n    if data\n      payload = new Object()\n      payload.action = 'setFilename'\n      payload.data = $('#file').val()\n      socket.send JSON.stringify payload\n      socket.send(data)\n    return false"
  },
  {
    "path": "examples/coffeescript/coffee/status.coffee",
    "content": "$(document).ready ->\n  log = (msg) -> $('#log').prepend(\"#{msg}<br />\")\n  serverUrl = 'ws://localhost:8000/status'\n  if window.MozWebSocket\n    socket = new MozWebSocket serverUrl\n  else if window.WebSocket\n    socket = new WebSocket serverUrl\n\n  socket.onopen = (msg) ->\n    $('#status').removeClass().addClass('online').html('connected')\n\n  socket.onmessage = (msg) ->\n    response = JSON.parse(msg.data)\n    switch response.action\n      when \"statusMsg\"      then statusMsg response.data\n      when \"clientConnected\"    then clientConnected response.data\n      when \"clientDisconnected\"  then clientDisconnected response.data\n      when \"clientActivity\"    then clientActivity response.data\n      when \"serverInfo\"      then refreshServerinfo response.data\n\n  socket.onclose = (msg) ->\n    $('#status').removeClass().addClass('offline').html('disconnected')\n\n  $('#status').click ->\n    socket.close()\n\n  statusMsg = (msgData) ->\n    switch msgData.type\n      when \"info\" then log msgData.text\n      when \"warning\" then log \"<span class=\\\"warning\\\">#{msgData.text}</span>\"\n\n  clientConnected = (data) ->\n    $('#clientListSelect').append(new Option(\"#{data.ip}:#{data.port}\", data.port))\n    $('#clientCount').text(data.clientCount)\n\n  clientDisconnected = (data) ->\n    $(\"#clientListSelect option[value='#{data.port}']\").remove()\n    $('#clientCount').text(data.clientCount)\n\n  refreshServerinfo = (serverinfo) ->\n    $('#clientCount').text(serverinfo.clientCount)\n    $('#maxClients').text(serverinfo.maxClients)\n    $('#maxConnections').text(serverinfo.maxConnectionsPerIp)\n    $('#maxRequetsPerMinute').text(serverinfo.maxRequetsPerMinute)\n    for port, ip of serverinfo.clients\n      $('#clientListSelect').append(new Option(ip + ':' + port, port));\n\n  clientActivity = (port) ->\n    $(\"#clientListSelect option[value='#{port}']\").css(\"color\", \"red\").animate({opacity: 100}, 600, ->\n      $(this).css(\"color\", \"black\")\n    )"
  },
  {
    "path": "examples/coffeescript/css/client.css",
    "content": "body {\n\tbackground: #f1f1f1;\n\tpadding-top: 65px;\n\ttext-align: center;\n\tfont-family: Arial, Helvetica, sans-serif;\n\ttext-align: center;\n\tfont-size: 16px;\n\tline-height: 25px;\n\tcolor: #444;\n}\n\na,\na:hover { \n\tcolor: #169;\n}\n\np {\n\tmargin: 0;\n\tpadding: 0 0 21px 0; \n}\n\n#container {\n\ttext-align: left;\n\twidth: 580px;\n\tbackground: #fff;\n\tposition: relative;\n\tmargin: 0 auto;\n\tpadding: 40px;\n\tborder: 1px solid #ddd;\n\tborder-radius: 10px;\n\t\t-moz-border-radius: 10px;\n}\n\nh1 {\n\tfont-size: 30px;\n\tcolor: #333;\n\tfont-weight: normal;\n\tmargin: 0 0 20px 0;\n\tpadding: 0;\n\tdisplay: inline-block;\n}\nh2 {\n\tfont-size: 16px;\n\tfont-weight: bold;\n\tmargin: 8px 0 0 0;\n}\n\n#log {\n\tmargin: 6px 0 0 0;\n\tpadding: 5px;\n\tborder: 1px solid #ccc;\n\theight: 200px;\n\toverflow: auto;\n}\n\n#send {\n\tmargin: 0 0 10px 0;\n}\n\n#status {\n\tfloat: right;\n\tpadding: 0 10px;\n\tcursor: pointer;\n\tborder-radius: 5px;\n\t\t-moz-border-radius: 5px;\n}\n.offline {\n\tbackground: #ddd;\n\tcolor: #000;\n}\n.online {\n\tbackground: #093;\n\tcolor: #fff;\n}\n.error {\n\tbackground: #930;\n\tcolor: #fff;\n}\n.connecting {\n\tbackground: #fc0;\n\tcolor: #000;\n}\n\n#action,\n#data {\n\tdisplay: inline-block;\n\twidth: 200px;\n\tmargin: 0 0 5px 0;\n}\n#file {\n\tdisplay: inline-block;\n\twidth: 410px;\n\tmargin: 0 0 5px 0;\n}\n\n.bold {\n\tfont-weight: bold;\n}"
  },
  {
    "path": "examples/coffeescript/css/status.css",
    "content": "body {\n\tbackground: #f1f1f1;\n\tpadding-top: 65px;\n\ttext-align: center;\n\tfont-family: Arial, Helvetica, sans-serif;\n\ttext-align: center;\n\tfont-size: 16px;\n\tline-height: 25px;\n\tcolor: #444;\n}\n\na,\na:hover { \n\tcolor: #169;\n}\np {\n\tmargin: 0;\n\tpadding: 0;\n}\n#container {\n\ttext-align: left;\n\twidth: 900px;\n\tbackground: #fff;\n\tposition: relative;\n\tmargin: 0 auto;\n\tpadding: 40px;\n\tborder: 1px solid #ddd;\n\tborder-radius: 10px;\n\t\t-moz-border-radius: 10px;\n}\n\nh1 {\n\tfont-size: 30px;\n\tcolor: #333;\n\tfont-weight: normal;\n\tmargin: 0 0 20px 0;\n\tpadding: 0;\n\tdisplay: inline-block;\n}\nh2 {\n\tfont-size: 16px;\n\tfont-weight: bold;\n\tmargin: 0;\n}\n#log {\n\tmargin: 6px 0 0 0;\n\tpadding: 5px;\n\tborder: 1px solid #ccc;\n\theight: 200px;\n\toverflow: auto;\n}\n\n#send {\n\tmargin: 0 0 10px 0;\n}\n\n#status {\n\tfloat: right;\n\tpadding: 0 10px;\n\tcursor: pointer;\n\tborder-radius: 5px;\n\t\t-moz-border-radius: 5px;\n}\n.offline {\n\tbackground: #ddd;\n\tcolor: #000;\n}\n.online {\n\tbackground: #093;\n\tcolor: #fff;\n}\n.error {\n\tbackground: #930;\n\tcolor: #fff;\n}\n.connecting {\n\tbackground: #fc0;\n\tcolor: #000;\n}\n\n#action,\n#data {\n\tdisplay: block;\n\twidth: 400px;\n\tmargin: 0 0 5px 0;\n}\n\n.bold {\n\tfont-weight: bold;\n}\n#clientList {\n\tfloat: left;\n\twidth: 300px;\n}\n#clientListSelect {\n\twidth: 200px;\n\theight: 120px;\n}\n\n#serverInfo {\n\tfloat: left;\n}\n\n#console {\n\tmargin-top: 20px;\n}\n#console .warning {\n\tcolor: #f00;\n}\n\n.clearer {\n\tclear: both;\n}"
  },
  {
    "path": "examples/coffeescript/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <link rel=\"stylesheet\" href=\"css/client.css\">\n\n    <script src=\"js/jquery.min.js\"></script>\n    <script src=\"js/json2.js\"></script>\n    <script src=\"lib/coffeescript/jsmaker.php?f=client.coffee\"></script>\n\n    <meta charset=utf-8/>\n\n    <title>Shiny WSS Demo Application</title>\n</head>\n<body>\n<div id=\"container\">\n    <h1>Shiny WSS Demo Application</h1>\n    <span id=\"status\" class=\"offline\">offline</span>\n\n    <h2>Send Text Frame</h2>\n    <input id=\"action\" placeholder=\"action\" type=\"text\"/>\n    <input id=\"data\" placeholder=\"data\" type=\"text\"/>\n    <button id=\"send\">Send Text</button>\n\n    <h2>Send Binary Frame</h2>\n\n    <form name=\"binaryFrame\" action=\"#\">\n        <input type=\"file\" name=\"file\" id=\"file\">\n        <button id=\"sendfile\">Send Binary</button>\n    </form>\n\n    <h2>Server-Response</h2>\n\n    <div id=\"log\"></div>\n</div>\n</body>\n</html>​"
  },
  {
    "path": "examples/coffeescript/status.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <link rel=\"stylesheet\" href=\"css/status.css\">\n\n    <script src=\"js/jquery.min.js\"></script>\n    <script src=\"js/json2.js\"></script>\n    <script src=\"lib/coffeescript/jsmaker.php?f=status.coffee\"></script>\n\n    <meta charset=utf-8/>\n\n    <title>Shiny WSS Status</title>\n</head>\n<body>\n<div id=\"container\">\n    <h1>Shiny WSS Status</h1>\n    <span id=\"status\" class=\"offline\">disconnected</span>\n\n    <div id=\"main\">\n        <div id=\"clientList\">\n            <h2>Clients:</h2>\n            <select id=\"clientListSelect\" multiple=\"multiple\"></select>\n        </div>\n\n        <div id=\"serverInfo\">\n            <h2>Server Info:</h2>\n\n            <p>Connected Clients: <span id=\"clientCount\"></span></p>\n\n            <p>Limit Clients: <span id=\"maxClients\"></span></p>\n\n            <p>Limit Connections/IP: <span id=\"maxConnections\"></span></p>\n\n            <p>Limit Requetes/Min: <span id=\"maxRequetsPerMinute\"></span></p>\n        </div>\n\n        <div class=\"clearer\"></div>\n\n        <div id=\"console\">\n            <h2>Server Messages:</h2>\n\n            <div id=\"log\"></div>\n        </div>\n    </div>\n</div>\n</body>\n</html>​"
  },
  {
    "path": "examples/server.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICsDCCAhmgAwIBAgIBADANBgkqhkiG9w0BAQQFADB1MQswCQYDVQQGEwJERTEN\nMAsGA1UECAwEbm9uZTENMAsGA1UEBwwEbm9uZTENMAsGA1UECgwEbm9uZTENMAsG\nA1UECwwEbm9uZTEPMA0GA1UEAwwGZm9vLmxoMRkwFwYJKoZIhvcNAQkBFgpiYXpA\nZm9vLmxoMB4XDTEyMDQwNzA5MzEwNVoXDTEzMDQwNzA5MzEwNVowdTELMAkGA1UE\nBhMCREUxDTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5v\nbmUxDTALBgNVBAsMBG5vbmUxDzANBgNVBAMMBmZvby5saDEZMBcGCSqGSIb3DQEJ\nARYKYmF6QGZvby5saDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7CDQtHvJ\nRE+sy2f3zKyGrMpffcf7fvbaEwT3tEpFpOJOp5qaq6JRc961O6v72++tr8iRVlfO\nMGYV5JavKBe0PLzR+tHa/+eigcvjujFsPZqTP+8zkmkOKQIsKjmtpQBKYGgqcDDR\nJv7xYASVBl3/6LuIaD1hjk+r6DH7uqmcA2cCAwEAAaNQME4wHQYDVR0OBBYEFNH0\ndPlR4RSosYd26yWaIvCeGN4kMB8GA1UdIwQYMBaAFNH0dPlR4RSosYd26yWaIvCe\nGN4kMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAGeqrcS9tZ7kTYrEe\nsT+iPtnqky8Sxu3znxkyjWKymDvELtc4gO17JaoFsQ+7PQBf22EzSgzuqlpk2gGa\npNaMwoS2o/q/Htm7KuGVP0yNEVCYAKNwutFynrn+pd87Pr/+Oq4ighvM8wEzLPl1\nOKSgTOSRdr80EdoSzgBKDD8gyuw=\n-----END CERTIFICATE-----\n-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,DE4E623117398BE5\n\n2FRyRzTeOSijgSCcvnBChbJJHMHkhAlB8Sxbo4fxeAIKyTGx9lyVZTtGN/XVWviK\nXDh/7rL5qZz0zJcHshMg1pypNsJ+dSfF3KigpXxHm3Fpb5GnCDj3UKVFxOWPwu2K\nro9RyUdEdOwou2o1TnYnimgEmF7pb1CJFtR/sN1lZ+J/XUh8wfbn2Obce9GCtXGB\nP+nVJECELVqX9KgquT49PKpIvf9gLq0Npns5P1lMenR4KGUlCGhFqgnuevPBaHaQ\nyRDQfl/qnCehiA59KpCBPyNBPn2hsfpsN+AcnTkt6zd8wWjQA4SlyI1koSxG6FE7\nOjPYsAhpQRi5qVWDyp0jkZqnU42aCGe7CqXXsdOfZv1m0wWACAvxJzV5uWljk/aD\n7+k/WcTHHsNF05FYD2eQOReQ75UnOvKF7EmDO0iSJ6NaH9kHg7bvCxPD2oQGMqU8\nISeHhnI7URcyUBJZnEBCC2eJW6R2m/mI78P1KpOoCg4YbdB/ByGCyqDl134cv243\nKnja0TV5mmTkdXWnUdSAQX0RJpohfOGomYFeeN7TqoqZxQUfFGHNgQP3oNoEzYay\nmMfvBk80TRuRD1UpEsg8f+4xw+F6L82rRnfLgNr7FKJYDSTpVsJ3L+xsmyP0hjNw\nb10iH/iOd2RprzOZ4YS+LdLLhOBJ97BciBTm71j1h0yLQuGWVLdsrisiyb22luZp\njU5mF0+wLIxCVl+k/Ibk3UYbBlvGblJzVEOnR2BOf3P3C6Skvr2JvDP/74Si/ybI\nidm+Igm+TnUQ2PIntjV0wkiJIEQY5XyDwt58TR99w2Y=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "examples/server.php",
    "content": "#!/usr/bin/env php\n<?php\n\n/* This program is free software. It comes without any warranty, to\n * the extent permitted by applicable law. You can redistribute it\n * and/or modify it under the terms of the Do What The Fuck You Want\n * To Public License, Version 2, as published by Sam Hocevar. See\n * http://sam.zoy.org/wtfpl/COPYING for more details. */\n\nini_set('display_errors', 1);\nerror_reporting(E_ALL);\n\nrequire(__DIR__ . '/../lib/SplClassLoader.php');\n\n$classLoader = new SplClassLoader('Wrench', __DIR__ . '/../lib');\n$classLoader->register();\n\n$server = new \\Wrench\\Server('ws://localhost:8000/', array(\n    'allowed_origins'            => array(\n        'mysite.localhost'\n    ),\n// Optional defaults:\n//     'check_origin'               => true,\n//     'connection_manager_class'   => 'Wrench\\ConnectionManager',\n//     'connection_manager_options' => array(\n//         'timeout_select'           => 0,\n//         'timeout_select_microsec'  => 200000,\n//         'socket_master_class'      => 'Wrench\\Socket\\ServerSocket',\n//         'socket_master_options'    => array(\n//             'backlog'                => 50,\n//             'ssl_cert_file'          => null,\n//             'ssl_passphrase'         => null,\n//             'ssl_allow_self_signed'  => false,\n//             'timeout_accept'         => 5,\n//             'timeout_socket'         => 5,\n//         ),\n//         'connection_class'         => 'Wrench\\Connection',\n//         'connection_options'       => array(\n//             'socket_class'           => 'Wrench\\Socket\\ServerClientSocket',\n//             'socket_options'         => array(),\n//             'connection_id_secret'   => 'asu5gj656h64Da(0crt8pud%^WAYWW$u76dwb',\n//             'connection_id_algo'     => 'sha512'\n//         )\n//     )\n));\n\n$server->registerApplication('echo', new \\Wrench\\Application\\EchoApplication());\n$server->run();\n"
  },
  {
    "path": "examples/server_ssl.php",
    "content": "<?php\n/* This program is free software. It comes without any warranty, to\n * the extent permitted by applicable law. You can redistribute it\n * and/or modify it under the terms of the Do What The Fuck You Want\n * To Public License, Version 2, as published by Sam Hocevar. See\n * http://sam.zoy.org/wtfpl/COPYING for more details. */\n\nini_set('display_errors', 1);\nerror_reporting(E_ALL);\n\nrequire(__DIR__ . '/../lib/SplClassLoader.php');\n\n$classLoader = new SplClassLoader('Wrench', __DIR__ . '/../lib');\n$classLoader->register();\n\n// Generate PEM file\n$pemFile                = dirname(__FILE__) . '/generated.pem';\n$pemPassphrase          = null;\n$countryName            = \"DE\";\n$stateOrProvinceName    = \"none\";\n$localityName           = \"none\";\n$organizationName       = \"none\";\n$organizationalUnitName = \"none\";\n$commonName             = \"foo.lh\";\n$emailAddress           = \"baz@foo.lh\";\n\n\\Wrench\\Socket::generatePEMFile(\n    $pemFile,\n    $pemPassphrase,\n    $countryName,\n    $stateOrProvinceName,\n    $localityName,\n    $organizationName,\n    $organizationalUnitName,\n    $commonName,\n    $emailAddress\n);\n\n// User can use tls in place of ssl\n$server = new \\Wrench\\Server('127.0.0.1', 8000, 'ssl', $pemFile, $pemPassphrase);\n\n// server settings:\n$server->setMaxClients(100);\n$server->setCheckOrigin(true);\n$server->setAllowedOrigin('foo.lh');\n$server->setMaxConnectionsPerIp(100);\n$server->setMaxRequestsPerMinute(2000);\n\n// Hint: Status application should not be removed as it displays usefull server informations:\n$server->registerApplication('status', \\Wrench\\Application\\StatusApplication::getInstance());\n$server->registerApplication('demo', \\Wrench\\Application\\DemoApplication::getInstance());\n\n$server->run();"
  },
  {
    "path": "lib/SplClassLoader.php",
    "content": "<?php\n\n/**\n * SplClassLoader implementation that implements the technical interoperability\n * standards for PHP 5.3 namespaces and class names.\n *\n * http://groups.google.com/group/php-standards/web/final-proposal\n *\n *     // Example which loads classes for the Doctrine Common package in the\n *     // Doctrine\\Common namespace.\n *     $classLoader = new SplClassLoader('Doctrine\\Common', '/path/to/doctrine');\n *     $classLoader->register();\n *\n * @author Jonathan H. Wage <jonwage@gmail.com>\n * @author Roman S. Borschel <roman@code-factory.org>\n * @author Matthew Weier O'Phinney <matthew@zend.com>\n * @author Kris Wallsmith <kris.wallsmith@gmail.com>\n * @author Fabien Potencier <fabien.potencier@symfony-project.org>\n */\nclass SplClassLoader\n{\n    private $_fileExtension = '.php';\n    private $_namespace;\n    private $_includePath;\n    private $_namespaceSeparator = '\\\\';\n\n    /**\n     * Creates a new <tt>SplClassLoader</tt> that loads classes of the\n     * specified namespace.\n     * \n     * @param string $ns The namespace to use.\n     */\n    public function __construct($ns = null, $includePath = null)\n    {\n        $this->_namespace = $ns;\n        $this->_includePath = $includePath;\n    }\n\n    /**\n     * Sets the namespace separator used by classes in the namespace of this class loader.\n     * \n     * @param string $sep The separator to use.\n     */\n    public function setNamespaceSeparator($sep)\n    {\n        $this->_namespaceSeparator = $sep;\n    }\n\n    /**\n     * Gets the namespace seperator used by classes in the namespace of this class loader.\n     *\n     * @return void\n     */\n    public function getNamespaceSeparator()\n    {\n        return $this->_namespaceSeparator;\n    }\n\n    /**\n     * Sets the base include path for all class files in the namespace of this class loader.\n     * \n     * @param string $includePath\n     */\n    public function setIncludePath($includePath)\n    {\n        $this->_includePath = $includePath;\n    }\n\n    /**\n     * Gets the base include path for all class files in the namespace of this class loader.\n     *\n     * @return string $includePath\n     */\n    public function getIncludePath()\n    {\n        return $this->_includePath;\n    }\n\n    /**\n     * Sets the file extension of class files in the namespace of this class loader.\n     * \n     * @param string $fileExtension\n     */\n    public function setFileExtension($fileExtension)\n    {\n        $this->_fileExtension = $fileExtension;\n    }\n\n    /**\n     * Gets the file extension of class files in the namespace of this class loader.\n     *\n     * @return string $fileExtension\n     */\n    public function getFileExtension()\n    {\n        return $this->_fileExtension;\n    }\n\n    /**\n     * Installs this class loader on the SPL autoload stack.\n     */\n    public function register()\n    {\n        spl_autoload_register(array($this, 'loadClass'));\n    }\n\n    /**\n     * Uninstalls this class loader from the SPL autoloader stack.\n     */\n    public function unregister()\n    {\n        spl_autoload_unregister(array($this, 'loadClass'));\n    }\n\n    /**\n     * Loads the given class or interface.\n     *\n     * @param string $className The name of the class to load.\n     * @return void\n     */\n    public function loadClass($className)\n    {\n        if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) {\n            $fileName = '';\n            $namespace = '';\n            if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) {\n                $namespace = substr($className, 0, $lastNsPos);\n                $className = substr($className, $lastNsPos + 1);\n                $fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;\n            }\n            $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension;\n\n            require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName;\n        }\n    }\n}"
  },
  {
    "path": "lib/Wrench/Application/Application.php",
    "content": "<?php\n\nnamespace Wrench\\Application;\n\n/**\n * Wrench Server Application\n */\nabstract class Application\n{\n    /**\n     * Optional: handle a connection\n     */\n    // abstract public function onConnect($connection);\n\n    /**\n     * Optional: handle a disconnection\n     *\n     * @param\n     */\n\t// abstract public function onDisconnect($connection);\n\n    /**\n     * Optional: allow the application to perform any tasks which will result in a push to clients\n     */ \n    // abstract public function onUpdate();\n\n    /**\n     * Handle data received from a client\n     *\n     * @param Payload $payload A payload object, that supports __toString()\n     * @param Connection $connection\n     */\n\tabstract public function onData($payload, $connection);\n}\n"
  },
  {
    "path": "lib/Wrench/Application/EchoApplication.php",
    "content": "<?php\n\nnamespace Wrench\\Application;\n\nuse Wrench\\Application\\Application;\nuse Wrench\\Application\\NamedApplication;\n\n/**\n * Example application for Wrench: echo server\n */\nclass EchoApplication extends Application\n{\n    /**\n     * @see Wrench\\Application.Application::onData()\n     */\n    public function onData($data, $client)\n    {\n        $client->send($data);\n    }\n}"
  },
  {
    "path": "lib/Wrench/Application/ServerTimeApplication.php",
    "content": "<?php\n\nnamespace Wrench\\Application;\n\nuse Wrench\\Application\\Application;\nuse Wrench\\Application\\NamedApplication;\n\n/**\n * Example application demonstrating how to use Application::onUpdate\n *\n * Pushes the server time to all clients every update tick.\n */\nclass ServerTimeApplication extends Application\n{\n    protected $clients = array();\n    protected $lastTimestamp = null;\n\n    /**\n     * @see Wrench\\Application.Application::onConnect()\n     */\n    public function onConnect($client)\n    {\n        $this->clients[] = $client;\n    }\n\n    /**\n     * @see Wrench\\Application.Application::onUpdate()\n     */\n    public function onUpdate()\n    {\n        // limit updates to once per second\n        if(time() > $this->lastTimestamp) {\n            $this->lastTimestamp = time();\n\n            foreach ($this->clients as $sendto) {\n                $sendto->send(date('d-m-Y H:i:s'));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/BasicServer.php",
    "content": "<?php\n\nnamespace Wrench;\n\nuse Wrench\\Server;\n\nclass BasicServer extends Server\n{\n    protected $rateLimiter;\n    protected $originPolicy;\n\n    /**\n     * Constructor\n     *\n     * @param string $uri\n     * @param array $options\n     */\n    public function __construct($uri, array $options = array())\n    {\n        parent::__construct($uri, $options);\n\n        $this->configureRateLimiter();\n        $this->configureOriginPolicy();\n    }\n\n    /**\n     * @see Wrench.Server::configure()\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'check_origin'        => true,\n            'allowed_origins'     => array(),\n            'origin_policy_class' => 'Wrench\\Listener\\OriginPolicy',\n            'rate_limiter_class'  => 'Wrench\\Listener\\RateLimiter'\n        ), $options);\n\n        parent::configure($options);\n    }\n\n    protected function configureRateLimiter()\n    {\n        $class = $this->options['rate_limiter_class'];\n        $this->rateLimiter = new $class();\n        $this->rateLimiter->listen($this);\n    }\n\n    /**\n     * Configures the origin policy\n     */\n    protected function configureOriginPolicy()\n    {\n        $class = $this->options['origin_policy_class'];\n        $this->originPolicy = new $class($this->options['allowed_origins']);\n\n        if ($this->options['check_origin']) {\n            $this->originPolicy->listen($this);\n        }\n    }\n\n    /**\n     * Adds an allowed origin\n     *\n     * @param array $origin\n     */\n    public function addAllowedOrigin($origin)\n    {\n        $this->originPolicy->addAllowedOrigin($origin);\n    }\n}"
  },
  {
    "path": "lib/Wrench/Client.php",
    "content": "<?php\n\nnamespace Wrench;\n\nuse Wrench\\Payload\\Payload;\n\nuse Wrench\\Payload\\PayloadHandler;\n\nuse Wrench\\Util\\Configurable;\n\nuse Wrench\\Socket\\ClientSocket;\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Protocol\\Rfc6455Protocol;\n\nuse \\InvalidArgumentException;\nuse \\RuntimeException;\n\n/**\n * Client class\n *\n * Represents a Wrench client\n */\nclass Client extends Configurable\n{\n    /**\n     * @var int bytes\n     */\n    const MAX_HANDSHAKE_RESPONSE = '1500';\n\n    /**\n     * @var string\n     */\n    protected $uri;\n\n    /**\n     * @var string\n     */\n    protected $origin;\n\n    /**\n     * @var ClientSocket\n     */\n    protected $socket;\n\n    /**\n     * Request headers\n     *\n     * @var array\n     */\n    protected $headers = array();\n\n    /**\n     * Whether the client is connected\n     *\n     * @var boolean\n     */\n    protected $connected = false;\n\n    /**\n     * @var PayloadHandler\n     */\n    protected $payloadHandler = null;\n\n    /**\n     * Complete received payloads\n     *\n     * @var array<Payload>\n     */\n    protected $received = array();\n\n    /**\n     * Constructor\n     *\n     * @param string $uri\n     * @param string $origin  The origin to include in the handshake (required\n     *                          in later versions of the protocol)\n     * @param array  $options (optional) Array of options\n     *                         - socket   => Socket instance (otherwise created)\n     *                         - protocol => Protocol\n     */\n    public function __construct($uri, $origin, array $options = array())\n    {\n        parent::__construct($options);\n\n        $uri = (string)$uri;\n        if (!$uri) {\n            throw new InvalidArgumentException('No URI specified');\n        }\n        $this->uri = $uri;\n\n        $origin = (string)$origin;\n        if (!$origin) {\n            throw new InvalidArgumentException('No origin specified');\n        }\n        $this->origin = $origin;\n\n        $this->protocol->validateUri($this->uri);\n        $this->protocol->validateOriginUri($this->origin);\n\n        $this->configureSocket();\n        $this->configurePayloadHandler();\n    }\n\n    /**\n     * Configure options\n     *\n     * @param array $options\n     * @return void\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'socket_class'     => 'Wrench\\\\Socket\\\\ClientSocket',\n            'on_data_callback' => null\n        ), $options);\n\n        parent::configure($options);\n    }\n\n    /**\n     * Configures the client socket\n     */\n    protected function configureSocket()\n    {\n        $class = $this->options['socket_class'];\n        $this->socket = new $class($this->uri);\n    }\n\n    /**\n     * Configures the payload handler\n     */\n    protected function configurePayloadHandler()\n    {\n        $this->payloadHandler = new PayloadHandler(array($this, 'onData'), $this->options);\n    }\n\n    /**\n     * Payload receiver\n     *\n     * Public because called from our PayloadHandler. Don't call us, we'll call\n     * you (via the on_data_callback option).\n     *\n     * @param Payload $payload\n     */\n    public function onData(Payload $payload)\n    {\n        $this->received[] = $payload;\n        if (($callback = $this->options['on_data_callback'])) {\n            call_user_func($callback, $payload);\n        }\n    }\n\n    /**\n     * Adds a request header to be included in the initial handshake\n     *\n     * For example, to include a Cookie header\n     *\n     * @param string $name\n     * @param string $value\n     * @return void\n     */\n    public function addRequestHeader($name, $value)\n    {\n        $this->headers[$name] = $value;\n    }\n\n    /**\n     * Sends data to the socket\n     *\n     * @param string $data\n     * @param string $type Payload type\n     * @param boolean $masked\n     * @return boolean Success\n     */\n    public function sendData($data, $type = Protocol::TYPE_TEXT, $masked = true)\n    {\n        if (is_string($type) && isset(Protocol::$frameTypes[$type])) {\n            $type = Protocol::$frameTypes[$type];\n        }\n\n        $payload = $this->protocol->getPayload();\n\n        $payload->encode(\n            $data,\n            $type,\n            $masked\n        );\n\n        return $payload->sendToSocket($this->socket);\n    }\n\n    /**\n     * Receives data sent by the server\n     *\n     * @param callable $callback\n     * @return array<Payload> Payload received since the last call to receive()\n     */\n    public function receive()\n    {\n        if (!$this->isConnected()) {\n            return false;\n        }\n\n        $data = $this->socket->receive();\n\n        if (!$data) {\n            return $data;\n        }\n\n        $old = $this->received;\n        $this->payloadHandler->handle($data);\n        return array_diff($this->received, $old);\n    }\n\n    /**\n     * Connect to the Wrench server\n     *\n     * @return boolean Whether a new connection was made\n     */\n    public function connect()\n    {\n        if ($this->isConnected()) {\n            return false;\n        }\n\n        $this->socket->connect();\n\n        $key       = $this->protocol->generateKey();\n        $handshake = $this->protocol->getRequestHandshake(\n            $this->uri,\n            $key,\n            $this->origin,\n            $this->headers\n        );\n\n        $this->socket->send($handshake);\n        $response = $this->socket->receive(self::MAX_HANDSHAKE_RESPONSE);\n        return ($this->connected =\n                    $this->protocol->validateResponseHandshake($response, $key));\n    }\n\n    /**\n     * Whether the client is currently connected\n     *\n     * @return boolean\n     */\n    public function isConnected()\n    {\n        return $this->connected;\n    }\n\n    /**\n     * @todo Bug: what if connect has been called twice. The first socket never\n     *        gets closed.\n     */\n    public function disconnect()\n    {\n        if ($this->socket) {\n            $this->socket->disconnect();\n        }\n        $this->connected = false;\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Connection.php",
    "content": "<?php\n\nnamespace Wrench;\n\nuse Wrench\\Payload\\PayloadHandler;\n\nuse Wrench\\Protocol\\Protocol;\n\nuse Wrench\\Payload\\Payload;\n\nuse Wrench\\Util\\Configurable;\nuse Wrench\\Socket\\ServerClientSocket;\nuse Wrench\\Server;\nuse Wrench\\Exception as WrenchException;\nuse Wrench\\Exception\\CloseException;\nuse Wrench\\Exception\\ConnectionException;\nuse Wrench\\Exception\\HandshakeException;\nuse Wrench\\Exception\\BadRequestException;\n\nuse \\Exception;\nuse \\RuntimeException;\n\n/**\n * Represents a client connection on the server side\n *\n * i.e. the `Server` manages a bunch of `Connection`s\n */\nclass Connection extends Configurable\n{\n    /**\n     * The connection manager\n     *\n     * @var Wrench\\ConnectionManager\n     */\n    protected $manager;\n\n    /**\n     * Socket object\n     *\n     * Wraps the client connection resource\n     *\n     * @var ServerClientSocket\n     */\n    protected $socket;\n\n    /**\n     * Whether the connection has successfully handshaken\n     *\n     * @var boolean\n     */\n    protected $handshaked = false;\n\n    /**\n     * The application this connection belongs to\n     *\n     * @var Application\n     */\n    protected $application = null;\n\n    /**\n     * The IP address of the client\n     *\n     * @var string\n     */\n    protected $ip;\n\n    /**\n     * The port of the client\n     *\n     * @var int\n     */\n    protected $port;\n\n    /**\n     * Connection ID\n     *\n     * @var string|null\n     */\n    protected $id = null;\n\n    /**\n     * @var PayloadHandler\n     */\n    protected $payloadHandler;\n\n    /**\n     * Constructor\n     *\n     * @param Server $server\n     * @param ServerClientSocket $socket\n     * @param array $options\n     * @throws InvalidArgumentException\n     */\n    public function __construct(\n        ConnectionManager $manager,\n        ServerClientSocket $socket,\n        array $options = array()\n    ) {\n        $this->manager = $manager;\n        $this->socket = $socket;\n\n\n        parent::__construct($options);\n\n        $this->configureClientInformation();\n        $this->configurePayloadHandler();\n\n        $this->log('Connected');\n    }\n\n    /**\n     * Gets the connection manager of this connection\n     *\n     * @return \\Wrench\\ConnectionManager\n     */\n    public function getConnectionManager()\n    {\n        return $this->manager;\n    }\n\n    /**\n     * @see Wrench\\Util.Configurable::configure()\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'connection_id_secret' => 'asu5gj656h64Da(0crt8pud%^WAYWW$u76dwb',\n            'connection_id_algo'   => 'sha512',\n        ), $options);\n\n        parent::configure($options);\n    }\n\n    protected function configurePayloadHandler()\n    {\n        $this->payloadHandler = new PayloadHandler(\n            array($this, 'handlePayload'),\n            $this->options\n        );\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    protected function configureClientInformation()\n    {\n        $this->ip = $this->socket->getIp();\n        $this->port = $this->socket->getPort();\n        $this->configureClientId();\n    }\n\n    /**\n     * Configures the client ID\n     *\n     * We hash the client ID to prevent leakage of information if another client\n     * happens to get a hold of an ID. The secret *must* be lengthy, and must\n     * be kept secret for this to work: otherwise it's trivial to search the space\n     * of possible IP addresses/ports (well, if not trivial, at least very fast).\n     */\n    protected function configureClientId()\n    {\n        $message = sprintf(\n            '%s:uri=%s&ip=%s&port=%s',\n            $this->options['connection_id_secret'],\n            rawurlencode($this->manager->getUri()),\n            rawurlencode($this->ip),\n            rawurlencode($this->port)\n        );\n\n        $algo = $this->options['connection_id_algo'];\n\n        if (extension_loaded('gmp')) {\n            $hash = hash($algo, $message, true);\n            $hash = gmp_strval(gmp_init($hash, 16), 62);\n        } else {\n            // @codeCoverageIgnoreStart\n            $hash = hash($algo, $message);\n            // @codeCoverageIgnoreEnd\n        }\n\n        $this->id = $hash;\n    }\n\n    /**\n     * Data receiver\n     *\n     * Called by the connection manager when the connection has received data\n     *\n     * @param string $data\n     */\n    public function onData($data)\n    {\n        if (!$this->handshaked) {\n            return $this->handshake($data);\n        }\n        return $this->handle($data);\n    }\n\n    /**\n     * Performs a websocket handshake\n     *\n     * @param string $data\n     * @throws BadRequestException\n     * @throws HandshakeException\n     * @throws WrenchException\n     */\n    public function handshake($data)\n    {\n        try {\n            list($path, $origin, $key, $extensions)\n                = $this->protocol->validateRequestHandshake($data);\n\n            $this->application = $this->manager->getApplicationForPath($path);\n            if (!$this->application) {\n                throw new BadRequestException('Invalid application');\n            }\n\n            $this->manager->getServer()->notify(\n                Server::EVENT_HANDSHAKE_REQUEST,\n                array($this, $path, $origin, $key, $extensions)\n            );\n\n            $response = $this->protocol->getResponseHandshake($key);\n\n            if (!$this->socket->isConnected()) {\n                throw new HandshakeException('Socket is not connected');\n            }\n\n            if ($this->socket->send($response) === false) {\n                throw new HandshakeException('Could not send handshake response');\n            }\n\n            $this->handshaked = true;\n\n            $this->log(sprintf(\n                'Handshake successful: %s:%d (%s) connected to %s',\n                $this->getIp(),\n                $this->getPort(),\n                $this->getId(),\n                $path\n            ), 'info');\n\n            $this->manager->getServer()->notify(\n                Server::EVENT_HANDSHAKE_SUCCESSFUL,\n                array($this)\n            );\n\n            if (method_exists($this->application, 'onConnect')) {\n                $this->application->onConnect($this);\n            }\n        } catch (WrenchException $e) {\n            $this->log('Handshake failed: ' . $e, 'err');\n            $this->close($e);\n        }\n    }\n\n    /**\n     * Returns a string export of the given binary data\n     *\n     * @param string $data\n     * @return string\n     */\n    protected function export($data)\n    {\n        $export = '';\n        foreach (str_split($data) as $chr) {\n            $export .= '\\\\x' . ord($chr);\n        }\n    }\n\n    /**\n     * Handle data received from the client\n     *\n     * The data passed in may belong to several different frames across one or\n     * more protocols. It may not even contain a single complete frame. This method\n     * manages slotting the data into separate payload objects.\n     *\n     * @todo An endpoint MUST be capable of handling control frames in the\n     *        middle of a fragmented message.\n     * @param string $data\n     * @return void\n     */\n    public function handle($data)\n    {\n        $this->payloadHandler->handle($data);\n    }\n\n    /**\n     * Handle a complete payload received from the client\n     *\n     * Public because called from our PayloadHandler\n     *\n     * @param string $payload\n     */\n    public function handlePayload(Payload $payload)\n    {\n        $app = $this->getClientApplication();\n\n        $this->log('Handling payload: ' . $payload->getPayload(), 'debug');\n\n        switch ($type = $payload->getType()) {\n            case Protocol::TYPE_TEXT:\n                if (method_exists($app, 'onData')) {\n                    $app->onData($payload, $this);\n                }\n                return;\n\n            case Protocol::TYPE_BINARY:\n                if(method_exists($app, 'onBinaryData')) {\n                    $app->onBinaryData($payload, $this);\n                } else {\n                    $this->close(1003);\n                }\n            break;\n\n            case Protocol::TYPE_PING:\n                $this->log('Ping received', 'notice');\n                $this->send($payload->getPayload(), Protocol::TYPE_PONG);\n                $this->log('Pong!', 'debug');\n            break;\n\n            /**\n             * A Pong frame MAY be sent unsolicited.  This serves as a\n             * unidirectional heartbeat.  A response to an unsolicited Pong\n             * frame is not expected.\n             */\n            case Protocol::TYPE_PONG:\n                $this->log('Received unsolicited pong', 'info');\n            break;\n\n            case Protocol::TYPE_CLOSE:\n                $this->log('Close frame received', 'notice');\n                $this->close();\n                $this->log('Disconnected', 'info');\n            break;\n\n            default:\n                throw new ConnectionException('Unhandled payload type');\n        }\n    }\n\n    /**\n     * Sends the payload to the connection\n     *\n     * @param string $payload\n     * @param string $type\n     * @throws HandshakeException\n     * @throws ConnectionException\n     * @return boolean\n     */\n    public function send($data, $type = Protocol::TYPE_TEXT)\n    {\n        if (!$this->handshaked) {\n            throw new HandshakeException('Connection is not handshaked');\n        }\n\n        $payload = $this->protocol->getPayload();\n\n        // Servers don't send masked payloads\n        $payload->encode($data, $type, false);\n\n        if (!$payload->sendToSocket($this->socket)) {\n            $this->log('Could not send payload to client', 'warn');\n            throw new ConnectionException('Could not send data to connection: ' . $this->socket->getLastError());\n        }\n\n        return true;\n    }\n\n    /**\n     * Processes data on the socket\n     *\n     * @throws CloseException\n     */\n    public function process()\n    {\n        $data = $this->socket->receive();\n        $bytes = strlen($data);\n\n        if ($bytes === 0 || $data === false) {\n            throw new CloseException('Error reading data from socket: ' . $this->socket->getLastError());\n        }\n\n        $this->onData($data);\n    }\n\n    /**\n     * Closes the connection according to the WebSocket protocol\n     *\n     * If an endpoint receives a Close frame and that endpoint did not\n     * previously send a Close frame, the endpoint MUST send a Close frame\n     * in response.  It SHOULD do so as soon as is practical.  An endpoint\n     * MAY delay sending a close frame until its current message is sent\n     * (for instance, if the majority of a fragmented message is already\n     * sent, an endpoint MAY send the remaining fragments before sending a\n     * Close frame).  However, there is no guarantee that the endpoint which\n     * has already sent a Close frame will continue to process data.\n\n     * After both sending and receiving a close message, an endpoint\n     * considers the WebSocket connection closed, and MUST close the\n     * underlying TCP connection.  The server MUST close the underlying TCP\n     * connection immediately; the client SHOULD wait for the server to\n     * close the connection but MAY close the connection at any time after\n     * sending and receiving a close message, e.g. if it has not received a\n     * TCP close from the server in a reasonable time period.\n     *\n     * @param int|Exception $statusCode\n     * @return boolean\n     */\n    public function close($code = Protocol::CLOSE_NORMAL)\n    {\n        try {\n            if (!$this->handshaked) {\n                $response = $this->protocol->getResponseError($code);\n                $this->socket->send($response);\n            } else {\n                $response = $this->protocol->getCloseFrame($code);\n                $this->socket->send($response);\n            }\n        } catch (Exception $e) {\n            $this->log('Unable to send close message', 'warning');\n        }\n\n        if ($this->application && method_exists($this->application, 'onDisconnect')) {\n            $this->application->onDisconnect($this);\n        }\n\n        $this->socket->disconnect();\n        $this->manager->removeConnection($this);\n    }\n\n    /**\n     * Logs a message\n     *\n     * @param string $message\n     * @param string $priority\n     */\n    public function log($message, $priority = 'info')\n    {\n        $this->manager->log(sprintf(\n            '%s: %s:%d (%s): %s',\n            __CLASS__,\n            $this->getIp(),\n            $this->getPort(),\n            $this->getId(),\n            $message\n        ), $priority);\n    }\n\n    /**\n     * Gets the IP address of the connection\n     *\n     * @return string Usually dotted quad notation\n     */\n    public function getIp()\n    {\n        return $this->ip;\n    }\n\n    /**\n     * Gets the port of the connection\n     *\n     * @return int\n     */\n    public function getPort()\n    {\n        return $this->port;\n    }\n\n    /**\n     * Gets the connection ID\n     *\n     * @return string\n     */\n    public function getId()\n    {\n        return $this->id;\n    }\n\n    /**\n     * Gets the socket object\n     *\n     * @return Socket\\ServerClientSocket\n     */\n    public function getSocket()\n    {\n        return $this->socket;\n    }\n\n    /**\n     * Gets the client application\n     *\n     * @return Application\n     */\n    public function getClientApplication()\n    {\n        return (isset($this->application)) ? $this->application : false;\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/ConnectionManager.php",
    "content": "<?php\n\nnamespace Wrench;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Resource;\nuse Wrench\\Util\\Configurable;\nuse Wrench\\Exception\\Exception as WrenchException;\nuse Wrench\\Exception\\CloseException;\nuse \\Exception;\nuse \\Countable;\n\nclass ConnectionManager extends Configurable implements Countable\n{\n    const TIMEOUT_SELECT          = 0;\n    const TIMEOUT_SELECT_MICROSEC = 200000;\n\n    /**\n     * @var Server\n     */\n    protected $server;\n\n    /**\n     * Master socket\n     *\n     * @var Socket\n     */\n    protected $socket;\n\n    /**\n     * An array of client connections\n     *\n     * @var array<int => Connection>\n     */\n    protected $connections = array();\n\n    /**\n     * An array of raw socket resources, corresponding to connections, roughly\n     *\n     * @var array<int => resource>\n     */\n    protected $resources = array();\n\n    /**\n     * Constructor\n     *\n     * @param Server $server\n     * @param array $options\n     */\n    public function __construct(Server $server, array $options = array())\n    {\n        $this->server = $server;\n\n        parent::__construct($options);\n    }\n\n    /**\n     * @see Countable::count()\n     */\n    public function count()\n    {\n        return count($this->connections);\n    }\n\n    /**\n     * @see Wrench\\Socket.Socket::configure()\n     *   Options include:\n     *     - timeout_select          => int, seconds, default 0\n     *     - timeout_select_microsec => int, microseconds (NB: not milli), default: 200000\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'socket_master_class'     => 'Wrench\\Socket\\ServerSocket',\n            'socket_master_options'   => array(),\n            'socket_client_class'     => 'Wrench\\Socket\\ServerClientSocket',\n            'socket_client_options'   => array(),\n            'connection_class'        => 'Wrench\\Connection',\n            'connection_options'      => array(),\n            'timeout_select'          => self::TIMEOUT_SELECT,\n            'timeout_select_microsec' => self::TIMEOUT_SELECT_MICROSEC\n        ), $options);\n\n        parent::configure($options);\n\n        $this->configureMasterSocket();\n    }\n\n    /**\n     * Gets the application associated with the given path\n     *\n     * @param string $path\n     */\n    public function getApplicationForPath($path)\n    {\n        $path = ltrim($path, '/');\n        return $this->server->getApplication($path);\n    }\n\n    /**\n     * Configures the main server socket\n     *\n     * @param string $uri\n     */\n    protected function configureMasterSocket()\n    {\n        $class   = $this->options['socket_master_class'];\n        $options = $this->options['socket_master_options'];\n        $this->socket = new $class($this->server->getUri(), $options);\n    }\n\n    /**\n     * Listens on the main socket\n     *\n     * @return void\n     */\n    public function listen()\n    {\n        $this->socket->listen();\n        $this->resources[$this->socket->getResourceId()] = $this->socket->getResource();\n    }\n\n    /**\n     * Gets all resources\n     *\n     * @return array<int => resource)\n     */\n    protected function getAllResources()\n    {\n        return array_merge($this->resources, array(\n            $this->socket->getResourceId() => $this->socket->getResource()\n        ));\n    }\n\n    /**\n     * Returns the Connection associated with the specified socket resource\n     *\n     * @param resource $socket\n     * @return Connection\n     */\n    protected function getConnectionForClientSocket($socket)\n    {\n        if (!isset($this->connections[$this->resourceId($socket)])) {\n            return false;\n        }\n        return $this->connections[$this->resourceId($socket)];\n    }\n\n    /**\n     * Select and process an array of resources\n     *\n     * @param array $resources\n     */\n    public function selectAndProcess()\n    {\n        $read             = $this->resources;\n        $unused_write     = null;\n        $unsued_exception = null;\n\n        stream_select(\n            $read,\n            $unused_write,\n            $unused_exception,\n            $this->options['timeout_select'],\n            $this->options['timeout_select_microsec']\n        );\n\n        foreach ($read as $socket) {\n            if ($socket == $this->socket->getResource()) {\n                $this->processMasterSocket();\n            } else {\n                $this->processClientSocket($socket);\n            }\n        }\n    }\n\n    /**\n     * Process events on the master socket ($this->socket)\n     *\n     * @return void\n     */\n    protected function processMasterSocket()\n    {\n        $new = null;\n\n        try {\n            $new = $this->socket->accept();\n        } catch (Exception $e) {\n            $this->server->log('Socket error: ' . $e, 'err');\n            return;\n        }\n\n        $connection = $this->createConnection($new);\n        $this->server->notify(Server::EVENT_SOCKET_CONNECT, array($new, $connection));\n    }\n\n    /**\n     * Creates a connection from a socket resource\n     *\n     * The create connection object is based on the options passed into the\n     * constructor ('connection_class', 'connection_options'). This connection\n     * instance and its associated socket resource are then stored in the\n     * manager.\n     *\n     * @param resource $resource A socket resource\n     * @return Connection\n     */\n    protected function createConnection($resource)\n    {\n        if (!$resource || !is_resource($resource)) {\n            throw new InvalidArgumentException('Invalid connection resource');\n        }\n\n        $socket_class = $this->options['socket_client_class'];\n        $socket_options = $this->options['socket_client_options'];\n\n        $connection_class = $this->options['connection_class'];\n        $connection_options = $this->options['connection_options'];\n\n        $socket = new $socket_class($resource, $socket_options);\n        $connection = new $connection_class($this, $socket, $connection_options);\n\n        $id = $this->resourceId($resource);\n        $this->resources[$id] = $resource;\n        $this->connections[$id] = $connection;\n\n        return $connection;\n    }\n\n    /**\n     * Process events on a client socket\n     *\n     * @param resource $socket\n     */\n    protected function processClientSocket($socket)\n    {\n        $connection = $this->getConnectionForClientSocket($socket);\n\n        if (!$connection) {\n            $this->log('No connection for client socket', 'warning');\n            return;\n        }\n\n        try {\n            $connection->process();\n        } catch (CloseException $e) {\n            $this->log('Client connection closed: ' . $e, 'notice');\n            $connection->close($e);\n        } catch (WrenchException $e) {\n            $this->log('Error on client socket: ' . $e, 'warning');\n            $connection->close($e);\n        }\n    }\n\n    /**\n     * This server makes an explicit assumption: PHP resource types may be cast\n     * to a integer. Furthermore, we assume this is bijective. Both seem to be\n     * true in most circumstances, but may not be guaranteed.\n     *\n     * This method (and $this->getResourceId()) exist to make this assumption\n     * explicit.\n     *\n     * This is needed on the connection manager as well as on resources\n     *\n     * @param resource $resource\n     */\n    protected function resourceId($resource)\n    {\n        return (int)$resource;\n    }\n\n    /**\n     * Gets the connection manager's listening URI\n     *\n     * @return string\n     */\n    public function getUri()\n    {\n        return $this->server->getUri();\n    }\n\n    /**\n     * Logs a message\n     *\n     * @param string $message\n     * @param string $priority\n     */\n    public function log($message, $priority = 'info')\n    {\n        $this->server->log(sprintf(\n            '%s: %s',\n            __CLASS__,\n            $message\n        ), $priority);\n    }\n\n    /**\n     * @return \\Wrench\\Server\n     */\n    public function getServer()\n    {\n        return $this->server;\n    }\n\n    /**\n     * Removes a connection\n     *\n     * @param Connection $connection\n     */\n    public function removeConnection(Connection $connection)\n    {\n        $socket = $connection->getSocket();\n\n        if ($socket->getResource()) {\n            $index = $socket->getResourceId();\n        } else {\n            $index = array_search($connection, $this->connections);\n        }\n\n        if (!$index) {\n            $this->log('Could not remove connection: not found', 'warning');\n        }\n\n        unset($this->connections[$index]);\n        unset($this->resources[$index]);\n\n        $this->server->notify(\n            Server::EVENT_SOCKET_DISCONNECT,\n            array($connection->getSocket(), $connection)\n        );\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Exception/BadRequestException.php",
    "content": "<?php\n\nnamespace Wrench\\Exception;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Exception\\HandshakeException;\n\nclass BadRequestException extends HandshakeException\n{\n    /**\n     * @param string    $message\n     * @param int       $code\n     * @param Exception $previous\n     */\n    public function __construct($message = null, $code = null, $previous = null)\n    {\n        if ($code == null) {\n            $code = Protocol::HTTP_BAD_REQUEST;\n        }\n        parent::__construct($message, $code, $previous);\n    }\n}"
  },
  {
    "path": "lib/Wrench/Exception/CloseException.php",
    "content": "<?php\n\nnamespace Wrench\\Exception;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Exception\\Exception as WrenchException;\n\n/**\n * Close connection exception\n */\nclass CloseException extends WrenchException\n{\n    /**\n     * @param string    $message\n     * @param int       $code\n     * @param Exception $previous\n     */\n    public function __construct($message = null, $code = null, $previous = null)\n    {\n        if ($code == null) {\n            $code = Protocol::CLOSE_UNEXPECTED;\n        }\n        parent::__construct($message, $code, $previous);\n    }\n}"
  },
  {
    "path": "lib/Wrench/Exception/ConnectionException.php",
    "content": "<?php\n\nnamespace Wrench\\Exception;\n\nclass ConnectionException extends Exception\n{\n}"
  },
  {
    "path": "lib/Wrench/Exception/Exception.php",
    "content": "<?php\n\nnamespace Wrench\\Exception;\n\nclass Exception extends \\Exception\n{\n}"
  },
  {
    "path": "lib/Wrench/Exception/FrameException.php",
    "content": "<?php\nnamespace Wrench\\Exception;\n\nuse Wrench\\Exception\\Exception as WrenchException;\n\nclass FrameException extends WrenchException\n{\n}\n"
  },
  {
    "path": "lib/Wrench/Exception/HandshakeException.php",
    "content": "<?php\n\nnamespace Wrench\\Exception;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Exception\\Exception as WrenchException;\n\nclass HandshakeException extends WrenchException\n{\n    /**\n     * @param string    $message\n     * @param int       $code\n     * @param Exception $previous\n     */\n    public function __construct($message = null, $code = null, $previous = null)\n    {\n        if ($code == null) {\n            $code = Protocol::HTTP_SERVER_ERROR;\n        }\n        parent::__construct($message, $code, $previous);\n    }\n}"
  },
  {
    "path": "lib/Wrench/Exception/InvalidOriginException.php",
    "content": "<?php\n\nnamespace Wrench\\Exception;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Exception\\HandshakeException;\n\n/**\n * Invalid origin exception\n */\nclass InvalidOriginException extends HandshakeException\n{\n    /**\n     * @param string    $message\n     * @param int       $code\n     * @param Exception $previous\n     */\n    public function __construct($message = null, $code = null, $previous = null)\n    {\n        if ($code == null) {\n            $code = Protocol::HTTP_FORBIDDEN;\n        }\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Exception/PayloadException.php",
    "content": "<?php\nnamespace Wrench\\Exception;\n\nuse Wrench\\Exception\\Exception as WrenchException;\n\nclass PayloadException extends WrenchException\n{\n}\n"
  },
  {
    "path": "lib/Wrench/Exception/RateLimiterException.php",
    "content": "<?php\nnamespace Wrench\\Exception;\n\nuse Wrench\\Exception\\Exception as WrenchException;\n\nclass RateLimiterException extends WrenchException\n{\n    /**\n     * @param string    $message\n     * @param int       $code\n     * @param Exception $previous\n     */\n    public function __construct($message = null, $code = null, $previous = null)\n    {\n        if ($code == null) {\n            $code = Protocol::CLOSE_GOING_AWAY;\n        }\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Exception/SocketException.php",
    "content": "<?php\nnamespace Wrench\\Exception;\n\nuse Wrench\\Exception\\Exception as WrenchException;\n\nclass SocketException extends WrenchException\n{\n}\n"
  },
  {
    "path": "lib/Wrench/Frame/Frame.php",
    "content": "<?php\n\nnamespace Wrench\\Frame;\n\nuse Wrench\\Payload\\Payload;\n\nuse Wrench\\Exception\\FrameException;\n\n/**\n * Represents a WebSocket frame\n */\nabstract class Frame\n{\n    /**\n     * The frame data length\n     *\n     * @var int\n     */\n    protected $length = null;\n\n    /**\n     * The type of this payload\n     *\n     * @var int\n     */\n    protected $type = null;\n\n    /**\n     * The buffer\n     *\n     * May not be a complete payload, because this frame may still be receiving\n     * data. See\n     *\n     * @var string\n     */\n    protected $buffer = '';\n\n    /**\n     * The enclosed frame payload\n     *\n     * May not be a complete payload, because this frame might indicate a continuation\n     * frame. See isFinal() versus isComplete()\n     *\n     * @var string\n     */\n    protected $payload = '';\n\n    /**\n     * Gets the length of the payload\n     *\n     * @throws FrameException\n     * @return int\n     */\n    abstract public function getLength();\n\n    /**\n     * Resets the frame and encodes the given data into it\n     *\n     * @param string $data\n     * @param int $type\n     * @param boolean $masked\n     * @return Frame\n     */\n    abstract public function encode($data, $type = Protocol::TYPE_TEXT, $masked = false);\n\n    /**\n     * Whether the frame is the final one in a continuation\n     *\n     * @return boolean\n     */\n    abstract public function isFinal();\n\n    /**\n     * @return int\n     */\n    abstract public function getType();\n\n    /**\n     * Decodes a frame payload from the buffer\n     *\n     * @return void\n     */\n    abstract protected function decodeFramePayloadFromBuffer();\n\n    /**\n     * Gets the expected length of the buffer once all the data has been\n     *  receieved\n     *\n     * @return int\n     */\n    abstract protected function getExpectedBufferLength();\n\n    /**\n     * Whether the frame is complete\n     *\n     * @return boolean\n     */\n    public function isComplete()\n    {\n        if (!$this->buffer) {\n            return false;\n        }\n\n        try {\n            return $this->getBufferLength() >= $this->getExpectedBufferLength();\n        } catch (FrameException $e) {\n            return false;\n        }\n    }\n\n    /**\n     * Receieves data into the frame\n     *\n     * @param string $buffer\n     */\n    public function receiveData($data)\n    {\n        $this->buffer .= $data;\n    }\n\n    /**\n     * Gets the remaining number of bytes before this frame will be complete\n     *\n     * @return number\n     */\n    public function getRemainingData()\n    {\n        try {\n            return $this->getExpectedBufferLength() - $this->getBufferLength();\n        } catch (FrameException $e) {\n            return null;\n        }\n    }\n\n    /**\n     * Whether this frame is waiting for more data\n     *\n     * @return boolean\n     */\n    public function isWaitingForData()\n    {\n        return $this->getRemainingData() > 0;\n    }\n\n    /**\n     * Gets the contents of the frame payload\n     *\n     * The frame must be complete to call this method.\n     *\n     * @return string\n     */\n    public function getFramePayload()\n    {\n        if (!$this->isComplete()) {\n            throw new FrameException('Cannot get payload: frame is not complete');\n        }\n\n        if (!$this->payload && $this->buffer) {\n            $this->decodeFramePayloadFromBuffer();\n        }\n\n        return $this->payload;\n    }\n\n    /**\n     * Gets the contents of the frame buffer\n     *\n     * This is the encoded value, receieved into the frame with recieveData().\n     *\n     * @throws FrameException\n     * @return string binary\n     */\n    public function getFrameBuffer()\n    {\n        if (!$this->buffer && $this->payload) {\n            throw new FrameException('Cannot get frame buffer');\n        }\n        return $this->buffer;\n    }\n\n    /**\n     * Gets the expected length of the frame payload\n     *\n     * @return int\n     */\n    protected function getBufferLength()\n    {\n        return strlen($this->buffer);\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Frame/HybiFrame.php",
    "content": "<?php\n\nnamespace Wrench\\Frame;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Exception\\FrameException;\nuse \\InvalidArgumentException;\n\nclass HybiFrame extends Frame\n{\n    // First byte\n    const BITFIELD_FINAL = 0x80;\n    const BITFIELD_RSV1  = 0x40;\n    const BITFIELD_RSV2  = 0x20;\n    const BITFIELD_RSV3  = 0x10;\n    const BITFIELD_TYPE  = 0x0f;\n\n    // Second byte\n    const BITFIELD_MASKED = 0x80;\n    const BITFIELD_INITIAL_LENGTH = 0x7f;\n\n    // The inital byte offset before\n    const BYTE_HEADER = 0;\n    const BYTE_MASKED = 1;\n    const BYTE_INITIAL_LENGTH = 1;\n\n    /**\n     * Whether the payload is masked\n     *\n     * @var boolean\n     */\n    protected $masked = null;\n\n    /**\n     * Masking key\n     *\n     * @var string\n     */\n    protected $mask = null;\n\n    /**\n     * Byte offsets\n     *\n     * @var int\n     */\n    protected $offset_payload = null;\n    protected $offset_mask = null;\n\n    /**\n     * @see Wrench\\Frame.Frame::encode()\n     *     ws-frame         = frame-fin           ; 1 bit in length\n     *                        frame-rsv1          ; 1 bit in length\n     *                        frame-rsv2          ; 1 bit in length\n     *                        frame-rsv3          ; 1 bit in length\n     *                        frame-opcode        ; 4 bits in length\n     *                        frame-masked        ; 1 bit in length\n     *                        frame-payload-length   ; either 7, 7+16,\n     *                                               ; or 7+64 bits in\n     *                                               ; length\n     *                        [ frame-masking-key ]  ; 32 bits in length\n     *                        frame-payload-data     ; n*8 bits in\n     *                                               ; length, where\n     *                                               ; n >= 0\n     */\n    public function encode($payload, $type = Protocol::TYPE_TEXT, $masked = false)\n    {\n        if (!is_int($type) || !in_array($type, Protocol::$frameTypes)) {\n            throw new InvalidArgumentException('Invalid frame type');\n        }\n\n        $this->type = $type;\n        $this->masked = $masked;\n        $this->payload = $payload;\n        $this->length = strlen($this->payload);\n        $this->offset_mask = null;\n        $this->offset_payload = null;\n\n        $this->buffer = \"\\x00\\x00\";\n\n        $this->buffer[self::BYTE_HEADER] = chr(\n            (self::BITFIELD_TYPE & $this->type)\n            | (self::BITFIELD_FINAL & PHP_INT_MAX)\n        );\n\n        $masked_bit = (self::BITFIELD_MASKED & ($this->masked ? PHP_INT_MAX : 0));\n\n        if ($this->length <= 125) {\n            $this->buffer[self::BYTE_INITIAL_LENGTH] = chr(\n                (self::BITFIELD_INITIAL_LENGTH & $this->length) | $masked_bit\n            );\n        } elseif ($this->length <= 65536) {\n            $this->buffer[self::BYTE_INITIAL_LENGTH] = chr(\n                (self::BITFIELD_INITIAL_LENGTH & 126) | $masked_bit\n            );\n            $this->buffer .= pack('n', $this->length);\n        } else {\n            $this->buffer[self::BYTE_INITIAL_LENGTH] = chr(\n                (self::BITFIELD_INITIAL_LENGTH & 127) | $masked_bit\n            );\n\n            if (PHP_INT_MAX > 2147483647) {\n                $this->buffer .= pack('NN', $this->length >> 32, $this->length);\n                // $this->buffer .= pack('I', $this->length);\n            } else {\n                $this->buffer .= pack('NN', 0, $this->length);\n            }\n        }\n\n        if ($this->masked) {\n            $this->mask = $this->generateMask();\n            $this->buffer .= $this->mask;\n            $this->buffer .= $this->mask($this->payload);\n        } else {\n            $this->buffer .= $this->payload;\n        }\n\n        $this->offset_mask = $this->getMaskOffset();\n        $this->offset_payload = $this->getPayloadOffset();\n\n        return $this;\n    }\n\n    /**\n     * Masks/Unmasks the frame\n     *\n     * @param string $payload\n     * @return string\n     */\n    protected function mask($payload)\n    {\n        $length = strlen($payload);\n        $mask = $this->getMask();\n\n        $unmasked = '';\n        for ($i = 0; $i < $length; $i++) {\n            $unmasked .= $payload[$i] ^ $mask[$i % 4];\n        }\n\n        return $unmasked;\n    }\n\n    /**\n     * Masks a payload\n     *\n     * @param string $payload\n     * @return string\n     */\n    protected function unmask($payload)\n    {\n        return $this->mask($payload);\n    }\n\n    public function receiveData($data)\n    {\n        if ($this->getBufferLength() <= self::BYTE_INITIAL_LENGTH) {\n            $this->length = null;\n            $this->offset_payload = null;\n        }\n        parent::receiveData($data);\n    }\n\n    /**\n     * Gets the mask\n     *\n     * @throws FrameException\n     * @return string\n     */\n    protected function getMask()\n    {\n        if (!isset($this->mask)) {\n            if (!$this->isMasked()) {\n                throw new FrameException('Cannot get mask: frame is not masked');\n            }\n            $this->mask = substr($this->buffer, $this->getMaskOffset(), $this->getMaskSize());\n        }\n        return $this->mask;\n    }\n\n    /**\n     * Generates a suitable masking key\n     *\n     * @return string\n     */\n    protected function generateMask()\n    {\n        if (extension_loaded('openssl')) {\n            return openssl_random_pseudo_bytes(4);\n        } else {\n            // SHA1 is 128 bit (= 16 bytes)\n            // So we pack it into 32 bits\n            return pack('N', sha1(spl_object_hash($this) . mt_rand(0, PHP_INT_MAX) . uniqid('', true), true));\n        }\n    }\n\n    /**\n     * Whether the frame is masked\n     *\n     * @return boolean\n     */\n    public function isMasked()\n    {\n        if (!isset($this->masked)) {\n            if (!isset($this->buffer[1])) {\n                throw new FrameException('Cannot tell if frame is masked: not enough frame data recieved');\n            }\n            $this->masked = (boolean)(ord($this->buffer[1]) & self::BITFIELD_MASKED);\n        }\n        return $this->masked;\n    }\n\n    /**\n     * @see Wrench\\Frame.Frame::getExpectedDataLength()\n     */\n    protected function getExpectedBufferLength()\n    {\n        return $this->getLength() + $this->getPayloadOffset();\n    }\n\n    /**\n     * Gets the offset of the payload in the frame\n     *\n     * @return int\n     */\n    protected function getPayloadOffset()\n    {\n        if (!isset($this->offset_payload)) {\n            $offset = $this->getMaskOffset();\n            $offset += $this->getMaskSize();\n\n            $this->offset_payload = $offset;\n        }\n        return $this->offset_payload;\n    }\n\n    /**\n     * Gets the offset in the frame to the masking bytes\n     *\n     * @return int\n     */\n    protected function getMaskOffset()\n    {\n        if (!isset($this->offset_mask)) {\n            $offset = self::BYTE_INITIAL_LENGTH + 1;\n            $offset += $this->getLengthSize();\n\n            $this->offset_mask = $offset;\n        }\n        return $this->offset_mask;\n    }\n\n    /**\n     * @see Wrench\\Frame.Frame::getLength()\n     */\n    public function getLength()\n    {\n        if (!$this->length) {\n            $initial = $this->getInitialLength();\n\n            if ($initial < 126) {\n                $this->length = $initial;\n            } elseif ($initial >= 126) {\n                // Extended payload length: 2 or 8 bytes\n                $start = self::BYTE_INITIAL_LENGTH + 1;\n                $end = self::BYTE_INITIAL_LENGTH + $this->getLengthSize();\n\n                if ($end > $this->getBufferLength()) {\n                    throw new FrameException('Cannot get extended length: need more data');\n                }\n\n                $length = 0;\n                for ($i = $start; $i <= $end; $i++) {\n                    $length <<= 8;\n                    $length  += ord($this->buffer[$i]);\n                }\n\n                $this->length = $length;\n            }\n        }\n        return $this->length;\n    }\n\n    /**\n     * Gets the inital length value, stored in the first length byte\n     *\n     * This determines how the rest of the length value is parsed out of the\n     * frame.\n     *\n     * @return int\n     */\n    protected function getInitialLength()\n    {\n        if (!isset($this->buffer[self::BYTE_INITIAL_LENGTH])) {\n            throw new FrameException('Cannot yet tell expected length');\n        }\n        $a = (int)(ord($this->buffer[self::BYTE_INITIAL_LENGTH]) & self::BITFIELD_INITIAL_LENGTH);\n\n        return (int)(ord($this->buffer[self::BYTE_INITIAL_LENGTH]) & self::BITFIELD_INITIAL_LENGTH);\n    }\n\n    /**\n     * Returns the byte size of the length part of the frame\n     *\n     * Not including the initial 7 bit part\n     *\n     * @return int\n     */\n    protected function getLengthSize()\n    {\n        $initial = $this->getInitialLength();\n\n        if ($initial < 126) {\n            return 0;\n        } elseif ($initial === 126) {\n            return 2;\n        } elseif ($initial === 127) {\n            return 8;\n        }\n    }\n\n    /**\n     * Returns the byte size of the mask part of the frame\n     *\n     * @return int\n     */\n    protected function getMaskSize()\n    {\n        if ($this->isMasked()) {\n            return 4;\n        }\n        return 0;\n    }\n\n    /**\n     * @see Wrench\\Frame.Frame::decodeFramePayloadFromBuffer()\n     */\n    protected function decodeFramePayloadFromBuffer()\n    {\n        $payload = substr($this->buffer, $this->getPayloadOffset());\n\n        if ($this->isMasked()) {\n            $payload = $this->unmask($payload);\n        }\n\n        $this->payload = $payload;\n    }\n\n    /**\n     * @see Wrench\\Frame.Frame::isFinal()\n     */\n    public function isFinal()\n    {\n        if (!isset($this->buffer[self::BYTE_HEADER])) {\n            throw new FrameException('Cannot yet tell if frame is final');\n        }\n        return (boolean)(ord($this->buffer[self::BYTE_HEADER]) & self::BITFIELD_FINAL);\n    }\n\n    /**\n     * @throws FrameException\n     * @see Wrench\\Frame.Frame::getType()\n     */\n    public function getType()\n    {\n        if (!isset($this->buffer[self::BYTE_HEADER])) {\n            throw new FrameException('Cannot yet tell type of frame');\n        }\n\n        $type = (int)(ord($this->buffer[self::BYTE_HEADER]) & self::BITFIELD_TYPE);\n\n        if (!in_array($type, Protocol::$frameTypes)) {\n            throw new FrameException('Invalid payload type');\n        }\n\n        return $type;\n    }\n}"
  },
  {
    "path": "lib/Wrench/Listener/HandshakeRequestListener.php",
    "content": "<?php\n\nnamespace Wrench\\Listener;\n\nuse Wrench\\Connection;\n\ninterface HandshakeRequestListener\n{\n    /**\n     * Handshake request listener\n     *\n     * @param Connection $connection\n     * @param string $path\n     * @param string $origin\n     * @param string $key\n     * @param array $extensions\n     */\n    public function onHandshakeRequest(Connection $connection, $path, $origin, $key, $extensions);\n}"
  },
  {
    "path": "lib/Wrench/Listener/Listener.php",
    "content": "<?php\n\nnamespace Wrench\\Listener;\n\nuse Wrench\\Server;\n\ninterface Listener\n{\n    public function listen(Server $server);\n}"
  },
  {
    "path": "lib/Wrench/Listener/OriginPolicy.php",
    "content": "<?php\n\nnamespace Wrench\\Listener;\n\nuse Wrench\\Connection;\nuse Wrench\\Exception\\InvalidOriginException;\nuse Wrench\\Server;\n\nclass OriginPolicy implements Listener, HandshakeRequestListener\n{\n    protected $allowed = array();\n\n    public function __construct(array $allowed)\n    {\n        $this->allowed = $allowed;\n    }\n\n    /**\n     * Handshake request listener\n     *\n     * Closes the connection on handshake from an origin that isn't allowed\n     *\n     * @param Connection $connection\n     * @param string $path\n     * @param string $origin\n     * @param string $key\n     * @param array $extensions\n     */\n    public function onHandshakeRequest(Connection $connection, $path, $origin, $key, $extensions)\n    {\n        if (!$this->isAllowed($origin)) {\n            $connection->close(new InvalidOriginException('Origin not allowed'));\n        }\n    }\n\n    /**\n     * Whether the specified origin is allowed under this policy\n     *\n     * @param string $origin\n     * @return boolean\n     */\n    public function isAllowed($origin)\n    {\n        $scheme = parse_url($origin, PHP_URL_SCHEME);\n        $host = parse_url($origin, PHP_URL_HOST) ?: $origin;\n\n        foreach ($this->allowed as $allowed) {\n            $allowed_scheme = parse_url($allowed, PHP_URL_SCHEME);\n\n            if ($allowed_scheme && $scheme != $allowed_scheme) {\n                continue;\n            }\n\n            $allowed_host = parse_url($allowed, PHP_URL_HOST) ?: $allowed;\n\n            if ($host != $allowed_host) {\n                continue;\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * @param Server $server\n     */\n    public function listen(Server $server)\n    {\n        $server->addListener(\n            Server::EVENT_HANDSHAKE_REQUEST,\n            array($this, 'onHandshakeRequest')\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Listener/RateLimiter.php",
    "content": "<?php\n\nnamespace Wrench\\Listener;\n\nuse Wrench\\Util\\Configurable;\nuse Wrench\\Server;\n\nclass RateLimiter extends Configurable implements Listener\n{\n    /**\n     * The server being limited\n     *\n     * @var Server\n     */\n    protected $server;\n\n    /**\n     * Connection counts per IP address\n     *\n     * @var array<int>\n     */\n    protected $ips = array();\n\n    /**\n     * Request tokens per IP address\n     *\n     * @var array<array<int>>\n     */\n    protected $requests = array();\n\n    /**\n     * Constructor\n     *\n     * @param array $options\n     */\n    public function __construct(array $options = array())\n    {\n        parent::__construct($options);\n    }\n\n    /**\n     * @param array $options\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'connections'         => 200, // Total\n            'connections_per_ip'  => 5,   // At once\n            'requests_per_minute' => 200  // Per connection\n        ), $options);\n\n        parent::configure($options);\n    }\n\n    /**\n     * @see Wrench\\Listener.Listener::listen()\n     */\n    public function listen(Server $server)\n    {\n        $this->server = $server;\n\n        $server->addListener(\n            Server::EVENT_SOCKET_CONNECT,\n            array($this, 'onSocketConnect')\n        );\n\n        $server->addListener(\n            Server::EVENT_SOCKET_DISCONNECT,\n            array($this, 'onSocketDisconnect')\n        );\n\n        $server->addListener(\n            Server::EVENT_CLIENT_DATA,\n            array($this, 'onClientData')\n        );\n    }\n\n    /**\n     * Event listener\n     *\n     * @param resource $socket\n     * @param Connection $connection\n     */\n    public function onSocketConnect($socket, $connection)\n    {\n        $this->checkConnections($connection);\n        $this->checkConnectionsPerIp($connection);\n    }\n\n    /**\n     * Event listener\n     *\n     * @param resource $socket\n     * @param Connection $connection\n     */\n    public function onSocketDisconnect($socket, $connection)\n    {\n        $this->releaseConnection($connection);\n    }\n\n    /**\n     * Event listener\n     *\n     * @param resource $socket\n     * @param Connection $connection\n     */\n    public function onClientData($socket, $connection)\n    {\n        $this->checkRequestsPerMinute($connection);\n    }\n\n    /**\n     * Idempotent\n     *\n     * @param Connection $connection\n     */\n    protected function checkConnections($connection)\n    {\n        $connections = $connection->getConnectionManager()->count();\n\n        if ($connections > $this->options['connections']) {\n            $this->limit($connection, 'Max connections');\n        }\n    }\n\n    /**\n     * NOT idempotent, call once per connection\n     *\n     * @param Connection $connection\n     */\n    protected function checkConnectionsPerIp($connection)\n    {\n        $ip = $connection->getIp();\n\n        if (!$ip) {\n            $this->log('Cannot check connections per IP', 'warning');\n            return;\n        }\n\n        if (!isset($this->ips[$ip])) {\n            $this->ips[$ip] = 1;\n        } else {\n            $this->ips[$ip] = min(\n                $this->options['connections_per_ip'],\n                $this->ips[$ip] + 1\n            );\n        }\n\n        if ($this->ips[$ip] > $this->options['connections_per_ip']) {\n            $this->limit($connection, 'Connections per IP');\n        }\n    }\n\n    /**\n     * NOT idempotent, call once per disconnection\n     *\n     * @param Connection $connection\n     */\n    protected function releaseConnection($connection)\n    {\n        $ip = $connection->getIp();\n\n        if (!$ip) {\n            $this->log('Cannot release connection', 'warning');\n            return;\n        }\n\n        if (!isset($this->ips[$ip])) {\n            $this->ips[$ip] = 0;\n        } else {\n            $this->ips[$ip] = max(0, $this->ips[$ip] - 1);\n        }\n\n        unset($this->requests[$connection->getId()]);\n    }\n\n    /**\n     * NOT idempotent, call once per data\n     *\n     * @param Connection $connection\n     */\n    protected function checkRequestsPerMinute($connection)\n    {\n        $id = $connection->getId();\n\n        if (!isset($this->requests[$id])) {\n            $this->requests[$id] = array();\n        }\n\n        // Add current token\n        $this->requests[$id][] = time();\n\n        // Expire old tokens\n        while (reset($this->requests[$id]) < time() - 60) {\n            array_shift($this->requests[$id]);\n        }\n\n        if (count($this->requests[$id]) > $this->options['requests_per_minute']) {\n            $this->limit($connection, 'Requests per minute');\n        }\n    }\n\n    /**\n     * Limits the given connection\n     *\n     * @param Connection $connection\n     * @param string $limit Reason\n     */\n    protected function limit($connection, $limit)\n    {\n        $this->log(sprintf(\n            'Limiting connection %s: %s',\n            $connection->getIp(),\n            $limit\n        ), 'notice');\n\n        $connection->close(new RateLimiterException($limit));\n    }\n\n    /**\n     * Logger\n     *\n     * @param string $message\n     * @param string $priority\n     */\n    public function log($message, $priority = 'info')\n    {\n        $this->server->log('RateLimiter: ' . $message, $priority);\n    }\n}"
  },
  {
    "path": "lib/Wrench/Payload/HybiPayload.php",
    "content": "<?php\n\nnamespace Wrench\\Payload;\n\nuse Wrench\\Frame\\HybiFrame;\nuse Wrench\\Exception\\PayloadException;\n\n/**\n * Gets a HyBi payload\n * @author Dominic\n *\n */\nclass HybiPayload extends Payload\n{\n    /**\n     * @see Wrench\\Payload.Payload::getFrame()\n     */\n    protected function getFrame()\n    {\n        return new HybiFrame();\n    }\n}"
  },
  {
    "path": "lib/Wrench/Payload/Payload.php",
    "content": "<?php\n\nnamespace Wrench\\Payload;\n\nuse Wrench\\Frame\\Frame;\n\nuse Wrench\\Exception\\FrameException;\n\nuse Wrench\\Socket\\Socket;\n\n/**\n * Payload class\n *\n * Represents a WebSocket protocol payload, which may be made up of multiple\n * frames.\n */\nabstract class Payload\n{\n    /**\n     * A payload may consist of one or more frames\n     *\n     * @var array<Frame>\n     */\n    protected $frames = array();\n\n    /**\n     * Gets the current frame for the payload\n     *\n     * @return mixed\n     */\n    protected function getCurrentFrame()\n    {\n        if (empty($this->frames)) {\n            array_push($this->frames, $this->getFrame());\n        }\n        return end($this->frames);\n    }\n\n    /**\n     * Gets the frame into which data should be receieved\n     *\n     * @throws PayloadException\n     * @return Frame\n     */\n    protected function getReceivingFrame()\n    {\n        $current = $this->getCurrentFrame();\n\n        if ($current->isComplete()) {\n            if ($current->isFinal()) {\n                throw new PayloadException('Payload cannot receieve data: it is already complete');\n            } else {\n                $current = array_push($this->frames, $this->getFrame());\n            }\n        }\n\n        return $current;\n    }\n\n    /**\n     * Get a frame object\n     *\n     * @return Frame\n     */\n    abstract protected function getFrame();\n\n    /**\n     * Whether the payload is complete\n     *\n     * @return boolean\n     */\n    public function isComplete()\n    {\n        return $this->getCurrentFrame()->isComplete() && $this->getCurrentFrame()->isFinal();\n    }\n\n    /**\n     * Encodes a payload\n     *\n     * @param string $data\n     * @param int $type\n     * @param boolean $masked\n     * @return Payload\n     * @todo No splitting into multiple frames just yet\n     */\n    public function encode($data, $type = Protocol::TYPE_TEXT, $masked = false)\n    {\n        $this->frames = array();\n\n        $frame = $this->getFrame();\n        array_push($this->frames, $frame);\n\n        $frame->encode($data, $type, $masked);\n\n        return $this;\n    }\n\n    /**\n     * Gets the number of remaining bytes before this payload will be\n     * complete\n     *\n     * May return 0 (no more bytes required) or null (unknown number of bytes\n     * required).\n     *\n     * @return number|NULL\n     */\n    public function getRemainingData()\n    {\n        if ($this->isComplete()) {\n            return 0;\n        }\n\n        try {\n            if ($this->getCurrentFrame()->isFinal()) {\n                return $this->getCurrentFrame()->getRemainingData();\n            }\n        } catch (FrameException $e) {\n            return null;\n        }\n\n        return null;\n    }\n\n    /**\n     * Whether this payload is waiting for more data\n     *\n     * @return boolean\n     */\n    public function isWaitingForData()\n    {\n        return $this->getRemainingData() > 0;\n    }\n\n    /**\n     * @param Socket $socket\n     * @return boolean\n     */\n    public function sendToSocket(Socket $socket)\n    {\n        $success = true;\n        foreach ($this->frames as $frame) {\n            $success = $success && ($socket->send($frame->getFrameBuffer()) !== false);\n        }\n        return $success;\n    }\n\n    /**\n     * Receive raw data into the payload\n     *\n     * @param string $data\n     * @return void\n     */\n    public function receiveData($data)\n    {\n        while ($data) {\n            $frame = $this->getReceivingFrame();\n\n            $size = strlen($data);\n            $remaining = $frame->getRemainingData();\n\n            if ($remaining === null) {\n                $chunk_size = 2;\n            } elseif ($remaining > 0) {\n                $chunk_size = $remaining;\n            }\n\n            $chunk_size = min(strlen($data), $chunk_size);\n            $chunk = substr($data, 0, $chunk_size);\n            $data = substr($data, $chunk_size);\n\n            $frame->receiveData($chunk);\n        }\n    }\n\n    /**\n     * @return string\n     */\n    public function getPayload()\n    {\n        $this->buffer = '';\n\n        foreach ($this->frames as $frame) {\n            $this->buffer .= $frame->getFramePayload();\n        }\n\n        return $this->buffer;\n    }\n\n    /**\n     * @return string\n     */\n    public function __toString()\n    {\n        try {\n            return $this->getPayload();\n        } catch (\\Exception $e) {\n            // __toString must not throw an exception\n            return '';\n        }\n    }\n\n    /**\n     * Gets the type of the payload\n     *\n     * The type of a payload is taken from its first frame\n     *\n     * @throws PayloadException\n     * @return int\n     */\n    public function getType()\n    {\n        if (!isset($this->frames[0])) {\n            throw new PayloadException('Cannot tell payload type yet');\n        }\n        return $this->frames[0]->getType();\n    }\n}"
  },
  {
    "path": "lib/Wrench/Payload/PayloadHandler.php",
    "content": "<?php\n\nnamespace Wrench\\Payload;\n\nuse Wrench\\Exception\\PayloadException;\nuse Wrench\\Exception\\ConnectionException;\nuse Wrench\\Util\\Configurable;\nuse \\InvalidArgumentException;\n\n/**\n * Handles chunking and splitting of payloads into frames\n */\nclass PayloadHandler extends Configurable\n{\n    /**\n     * A callback that will be called when a complete payload is available\n     *\n     * @var callable\n     */\n    protected $callback;\n\n    /**\n     * The current payload\n     */\n    protected $payload;\n\n    /**\n     * @param callable $callback\n     * @param array $options\n     * @throws InvalidArgumentException\n     */\n    public function __construct($callback, array $options = array())\n    {\n        parent::__construct($options);\n\n        if (!is_callable($callback)) {\n            throw new InvalidArgumentException('You must supply a callback to PayloadHandler');\n        }\n\n        $this->callback = $callback;\n    }\n\n    /**\n     * Handles the raw socket data given\n     *\n     * @param string $data\n     */\n    public function handle($data)\n    {\n        if (!$this->payload) {\n            $this->payload = $this->protocol->getPayload();\n        }\n\n        while ($data) { // Each iteration pulls off a single payload chunk\n            $size = strlen($data);\n            $remaining = $this->payload->getRemainingData();\n\n            // If we don't yet know how much data is remaining, read data into\n            // the payload in two byte chunks (the size of a WebSocket frame\n            // header to get the initial length)\n            //\n            // Then re-loop. For extended lengths, this will happen once or four\n            // times extra, as the extended length is read in.\n            if ($remaining === null) {\n                $chunk_size = 2;\n            } elseif ($remaining > 0) {\n                $chunk_size = $remaining;\n            } elseif ($remaining === 0) {\n                $chunk_size = 0;\n            }\n\n            $chunk_size = min(strlen($data), $chunk_size);\n            $chunk = substr($data, 0, $chunk_size);\n            $data = substr($data, $chunk_size);\n\n            $this->payload->receiveData($chunk);\n\n            if ($remaining !== 0 && !$this->payload->isComplete()) {\n                continue;\n            }\n\n            if ($this->payload->isComplete()) {\n                $this->emit($this->payload);\n                $this->payload = $this->protocol->getPayload();\n            } else {\n                throw new PayloadException('Payload will not complete');\n            }\n        }\n    }\n\n    /**\n     * Get the current payload\n     *\n     * @return Payload\n     */\n    public function getCurrent()\n    {\n        return $this->getPayloadHandler->getCurrent();\n    }\n\n    /**\n     * Emits a complete payload to the callback\n     *\n     * @param Payload $payload\n     */\n    protected function emit(Payload $payload)\n    {\n        call_user_func($this->callback, $payload);\n    }\n}"
  },
  {
    "path": "lib/Wrench/Protocol/Hybi10Protocol.php",
    "content": "<?php\n\nnamespace Wrench\\Protocol;\n\nuse Wrench\\Protocol\\HybiProtocol;\n\n/**\n * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10\n */\nclass Hybi10Protocol extends HybiProtocol\n{\n    const VERSION = 10;\n\n    /**\n     * @see Wrench\\Protocol.Protocol::getVersion()\n     */\n    public function getVersion()\n    {\n        return self::VERSION;\n    }\n\n    /**\n     * This is our most recent protocol class\n     *\n     * @see Wrench\\Protocol.Protocol::acceptsVersion()\n     */\n    public function acceptsVersion($version)\n    {\n        $version = (int)$version;\n\n        if ($version <= 10 && $version >= 10) {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "lib/Wrench/Protocol/HybiProtocol.php",
    "content": "<?php\n\nnamespace Wrench\\Protocol;\n\nuse Wrench\\Payload\\HybiPayload;\n\nuse Wrench\\Exception\\ConnectionException;\n\nuse Wrench\\Protocol\\Protocol;\nuse \\InvalidArgumentException;\n\n/**\n * @see http://tools.ietf.org/html/rfc6455#section-5.2\n */\nabstract class HybiProtocol extends Protocol\n{\n    /**\n     * @see Wrench\\Protocol.Protocol::getPayload()\n     */\n    public function getPayload()\n    {\n        return new HybiPayload();\n    }\n}"
  },
  {
    "path": "lib/Wrench/Protocol/Protocol.php",
    "content": "<?php\n\nnamespace Wrench\\Protocol;\n\nuse Wrench\\Payload\\Payload;\n\nuse Wrench\\Exception\\BadRequestException;\n\nuse \\Exception;\nuse \\InvalidArgumentException;\n\n/**\n * Definitions and implementation helpers for the Wrenchs protocol\n *\n * Based on RFC 6455: http://tools.ietf.org/html/rfc6455\n */\nabstract class Protocol\n{\n    /**#@+\n     * Relevant schemes\n     *\n     * @var string\n     */\n    const SCHEME_WEBSOCKET         = 'ws';\n    const SCHEME_WEBSOCKET_SECURE  = 'wss';\n    const SCHEME_UNDERLYING        = 'tcp';\n    const SCHEME_UNDERLYING_SECURE = 'tls';\n    /**#@-*/\n\n    /**#@+\n     * HTTP headers\n     *\n     * @var string\n     */\n    const HEADER_HOST       = 'Host';\n    const HEADER_KEY        = 'Sec-WebSocket-Key';\n    const HEADER_PROTOCOL   = 'Sec-WebSocket-Protocol';\n    const HEADER_VERSION    = 'Sec-WebSocket-Version';\n    const HEADER_ACCEPT     = 'Sec-WebSocket-Accept';\n    const HEADER_EXTENSIONS = 'Sec-WebSocket-Extensions';\n    const HEADER_ORIGIN     = 'Origin';\n    const HEADER_CONNECTION = 'Connection';\n    const HEADER_UPGRADE    = 'Upgrade';\n    /**#@-*/\n\n    /**#@+\n     * HTTP error statuses\n     *\n     * @var int\n     */\n    const HTTP_SWITCHING_PROTOCOLS = 101;\n    const HTTP_BAD_REQUEST         = 400;\n    const HTTP_UNAUTHORIZED        = 401;\n    const HTTP_FORBIDDEN           = 403;\n    const HTTP_NOT_FOUND           = 404;\n    const HTTP_RATE_LIMITED        = 420;\n    const HTTP_SERVER_ERROR        = 500;\n    const HTTP_NOT_IMPLEMENTED     = 501;\n    /**#@-*/\n\n    /**#@+\n     * Close statuses\n     *\n     * @see http://tools.ietf.org/html/rfc6455#section-7.4\n     * @var int\n     */\n    const CLOSE_NORMAL            = 1000;\n    const CLOSE_GOING_AWAY        = 1001;\n    const CLOSE_PROTOCOL_ERROR    = 1002;\n    const CLOSE_DATA_INVALID      = 1003;\n    const CLOSE_RESERVED          = 1004;\n    const CLOSE_RESERVED_NONE     = 1005;\n    const CLOSE_RESERVED_ABNORM   = 1006;\n    const CLOSE_DATA_INCONSISTENT = 1007;\n    const CLOSE_POLICY_VIOLATION  = 1008;\n    const CLOSE_MESSAGE_TOO_BIG   = 1009;\n    const CLOSE_EXTENSION_NEEDED  = 1010;\n    const CLOSE_UNEXPECTED        = 1011;\n    const CLOSE_RESERVED_TLS      = 1015;\n    /**#@-*/\n\n    /**#@+\n     * Frame types\n     *\n     *  %x0 denotes a continuation frame\n     *  %x1 denotes a text frame\n     *  %x2 denotes a binary frame\n     *  %x3-7 are reserved for further non-control frames\n     *  %x8 denotes a connection close\n     *  %x9 denotes a ping\n     *  %xA denotes a pong\n     *  %xB-F are reserved for further control frames\n     *\n     * @var int\n     */\n    const TYPE_CONTINUATION = 0;\n    const TYPE_TEXT         = 1;\n    const TYPE_BINARY       = 2;\n    const TYPE_RESERVED_3   = 3;\n    const TYPE_RESERVED_4   = 4;\n    const TYPE_RESERVED_5   = 5;\n    const TYPE_RESERVED_6   = 6;\n    const TYPE_RESERVED_7   = 7;\n    const TYPE_CLOSE        = 8;\n    const TYPE_PING         = 9;\n    const TYPE_PONG         = 10;\n    const TYPE_RESERVED_11  = 11;\n    const TYPE_RESERVED_12  = 12;\n    const TYPE_RESERVED_13  = 13;\n    const TYPE_RESERVED_14  = 14;\n    const TYPE_RESERVED_15  = 15;\n    /**#@-*/\n\n    /**\n     * Magic GUID\n     *\n     * Used in the WebSocket accept header\n     *\n     * @var string\n     */\n    const MAGIC_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';\n\n    /**\n     * The request MUST contain an |Upgrade| header field whose value\n     *   MUST include the \"websocket\" keyword.\n     */\n    const UPGRADE_VALUE = 'websocket';\n\n    /**\n     * The request MUST contain a |Connection| header field whose value\n     *   MUST include the \"Upgrade\" token.\n     */\n    const CONNECTION_VALUE = 'Upgrade';\n\n    /**\n     * Request line format\n     *\n     * @var string printf compatible, passed request path string\n     */\n    const REQUEST_LINE_FORMAT = 'GET %s HTTP/1.1';\n\n    /**\n     * Request line regex\n     *\n     * Used for parsing requested path\n     *\n     * @var string preg_* compatible\n     */\n    const REQUEST_LINE_REGEX = '/^GET (\\S+) HTTP\\/1.1$/';\n\n    /**\n     * Response line format\n     *\n     * @var string\n     */\n    const RESPONSE_LINE_FORMAT = 'HTTP/1.1 %d %s';\n\n    /**\n     * Header line format\n     *\n     * @var string printf compatible, passed header name and value\n     */\n    const HEADER_LINE_FORMAT = '%s: %s';\n\n    /**\n     * Valid schemes\n     *\n     * @var array<string>\n     */\n    protected static $schemes = array(\n        self::SCHEME_WEBSOCKET,\n        self::SCHEME_WEBSOCKET_SECURE,\n        self::SCHEME_UNDERLYING,\n        self::SCHEME_UNDERLYING_SECURE\n    );\n\n    /**\n     * Close status codes\n     *\n     * @var array<int => string>\n     */\n    public static $closeReasons = array(\n        self::CLOSE_NORMAL            => 'normal close',\n        self::CLOSE_GOING_AWAY        => 'going away',\n        self::CLOSE_PROTOCOL_ERROR    => 'protocol error',\n        self::CLOSE_DATA_INVALID      => 'data invalid',\n        self::CLOSE_DATA_INCONSISTENT => 'data inconsistent',\n        self::CLOSE_POLICY_VIOLATION  => 'policy violation',\n        self::CLOSE_MESSAGE_TOO_BIG   => 'message too big',\n        self::CLOSE_EXTENSION_NEEDED  => 'extension needed',\n        self::CLOSE_UNEXPECTED        => 'unexpected error',\n        self::CLOSE_RESERVED          => null, // Don't use these!\n        self::CLOSE_RESERVED_NONE     => null,\n        self::CLOSE_RESERVED_ABNORM   => null,\n        self::CLOSE_RESERVED_TLS      => null\n    );\n\n    /**\n     * Frame types\n     *\n     * @todo flip values and keys?\n     * @var array<string => int>\n     */\n    public static $frameTypes = array(\n        'continuation' => self::TYPE_CONTINUATION,\n        'text'         => self::TYPE_TEXT,\n        'binary'       => self::TYPE_BINARY,\n        'close'        => self::TYPE_CLOSE,\n        'ping'         => self::TYPE_PING,\n        'pong'         => self::TYPE_PONG\n    );\n\n    /**\n     * HTTP errors\n     *\n     * @var array<int => string>\n     */\n    public static $httpResponses = array(\n        self::HTTP_SWITCHING_PROTOCOLS => 'Switching Protocols',\n        self::HTTP_BAD_REQUEST         => 'Bad Request',\n        self::HTTP_UNAUTHORIZED        => 'Unauthorized',\n        self::HTTP_FORBIDDEN           => 'Forbidden',\n        self::HTTP_NOT_FOUND           => 'Not Found',\n        self::HTTP_NOT_IMPLEMENTED     => 'Not Implemented',\n        self::HTTP_RATE_LIMITED        => 'Enhance Your Calm'\n    );\n\n    /**\n     * Gets a version number\n     *\n     * @return\n     */\n    abstract public function getVersion();\n\n    /**\n     * Subclasses should implement this method and return a boolean to the given\n     * version string, as to whether they would like to accept requests from\n     * user agents that specify that version.\n     *\n     * @return boolean\n     */\n    abstract public function acceptsVersion($version);\n\n    /**\n     * Gets a payload instance, suitable for use in decoding/encoding protocol\n     * frames\n     *\n     * @return Payload\n     */\n    abstract public function getPayload();\n\n    /**\n     * Generates a key suitable for use in the protocol\n     *\n     * This base implementation returns a 16-byte (128 bit) random key as a\n     * binary string.\n     *\n     * @return string\n     */\n    public function generateKey()\n    {\n        if (extension_loaded('openssl')) {\n            $key = openssl_random_pseudo_bytes(16);\n        } else {\n            // SHA1 is 128 bit (= 16 bytes)\n            $key = sha1(spl_object_hash($this) . mt_rand(0, PHP_INT_MAX) . uniqid('', true), true);\n        }\n\n        return base64_encode($key);\n    }\n\n    /**\n     * Gets request handshake string\n     *\n     *   The leading line from the client follows the Request-Line format.\n     *   The leading line from the server follows the Status-Line format.  The\n     *   Request-Line and Status-Line productions are defined in [RFC2616].\n     *\n     *   An unordered set of header fields comes after the leading line in\n     *   both cases.  The meaning of these header fields is specified in\n     *   Section 4 of this document.  Additional header fields may also be\n     *   present, such as cookies [RFC6265].  The format and parsing of\n     *   headers is as defined in [RFC2616].\n     *\n     * @param string $uri    WebSocket URI, e.g. ws://example.org:8000/chat\n     * @param string $key    16 byte binary string key\n     * @param string $origin Origin of the request\n     * @return string\n     */\n    public function getRequestHandshake(\n        $uri,\n        $key,\n        $origin,\n        array $headers = array()\n    ) {\n        if (!$uri || !$key || !$origin) {\n            throw new InvalidArgumentException('You must supply a URI, key and origin');\n        }\n\n        list($scheme, $host, $port, $path) = self::validateUri($uri);\n\n        $handshake = array(\n            sprintf(self::REQUEST_LINE_FORMAT, $path)\n        );\n\n        $headers = array_merge(\n            $this->getDefaultRequestHeaders(\n                $host . ':' . $port, $key, $origin\n            ),\n            $headers\n        );\n\n        foreach ($headers as $name => $value) {\n            $handshake[] = sprintf(self::HEADER_LINE_FORMAT, $name, $value);\n        }\n        return implode($handshake, \"\\r\\n\") . \"\\r\\n\\r\\n\";\n    }\n\n    /**\n     * Gets a handshake response body\n     *\n     * @param string $key\n     * @param array $headers\n     */\n    public function getResponseHandshake($key, array $headers = array())\n    {\n        $headers = array_merge(\n            $this->getSuccessResponseHeaders(\n                $key\n            ),\n            $headers\n        );\n\n        return $this->getHttpResponse(self::HTTP_SWITCHING_PROTOCOLS, $headers);\n    }\n\n    /**\n     * Gets a response to an error in the handshake\n     *\n     * @param int|Exception $e Exception or HTTP error\n     * @param array $headers\n     */\n    public function getResponseError($e, array $headers = array())\n    {\n        $code = false;\n\n        if ($e instanceof Exception) {\n            $code = $e->getCode();\n        } elseif (is_numeric($e)) {\n            $code = (int)$e;\n        }\n\n        if (!$code || $code < 400 || $code > 599) {\n            $code = self::HTTP_SERVER_ERROR;\n        }\n\n        return $this->getHttpResponse($code, $headers);\n    }\n\n    /**\n     * Gets an HTTP response\n     *\n     * @param int $status\n     * @param array $headers\n     */\n    protected function getHttpResponse($status, array $headers = array())\n    {\n        if (array_key_exists($status, self::$httpResponses)) {\n            $response = self::$httpResponses[$status];\n        } else {\n            $response = self::$httpResponses[self::HTTP_NOT_IMPLEMENTED];\n        }\n\n        $handshake = array(\n            sprintf(self::RESPONSE_LINE_FORMAT, $status, $response)\n        );\n\n        foreach ($headers as $name => $value) {\n            $handshake[] = sprintf(self::HEADER_LINE_FORMAT, $name, $value);\n        }\n\n        return implode($handshake, \"\\r\\n\") . \"\\r\\n\\r\\n\";\n    }\n\n    /**\n     * @todo better header handling\n     * @todo throw exception\n     * @param unknown_type $response\n     * @param unknown_type $key\n     * @return boolean\n     */\n    public function validateResponseHandshake($response, $key)\n    {\n        if (!$response) {\n            return false;\n        }\n\n        $headers = $this->getHeaders($response);\n\n        if (!isset($headers[self::HEADER_ACCEPT])) {\n            throw new HandshakeException('No accept header receieved on handshake response');\n        }\n\n        $accept = $headers[self::HEADER_ACCEPT];\n\n        if (!$accept) {\n            throw new HandshakeException('Invalid accept header');\n        }\n\n        $expected = $this->getAcceptValue($key);\n\n        preg_match('#Sec-WebSocket-Accept:\\s(.*)$#mU', $response, $matches);\n        $keyAccept = trim($matches[1]);\n\n        return ($keyAccept === $this->getEncodedHash($key)) ? true : false;\n    }\n\n    /**\n     * Gets an encoded hash for a key\n     *\n     * @param string $key\n     * @return string\n     */\n    public function getEncodedHash($key)\n    {\n        return base64_encode(pack('H*', sha1($key . self::MAGIC_GUID)));\n    }\n\n    /**\n     * Validates a request handshake\n     *\n     * @param string $request\n     * @throws BadRequestException\n     */\n    public function validateRequestHandshake(\n        $request\n    ) {\n        if (!$request) {\n            return false;\n        }\n\n        list($request, $headers) = $this->getRequestHeaders($request);\n\n        $path = $this->validateRequestLine($request);\n\n        if (!isset($headers[self::HEADER_ORIGIN]) || !$headers[self::HEADER_ORIGIN]) {\n            throw new BadRequestException('No origin header');\n        }\n\n        $origin = $headers[self::HEADER_ORIGIN];\n\n        if (!isset($headers[self::HEADER_UPGRADE])\n                || strtolower($headers[self::HEADER_UPGRADE]) != self::UPGRADE_VALUE\n        ) {\n            throw new BadRequestException('Invalid upgrade header');\n        }\n\n        if (!isset($headers[self::HEADER_CONNECTION])\n                || strpos($headers[self::HEADER_CONNECTION], self::CONNECTION_VALUE) === false\n        ) {\n            throw new BadRequestException('Invalid connection header');\n        }\n\n        if (!isset($headers[self::HEADER_HOST])) {\n            // @todo Validate host == listening socket? Or would that break\n            //        TCP proxies?\n            throw new BadRequestException('No host header');\n        }\n\n        if (!isset($headers[self::HEADER_VERSION])) {\n            throw new BadRequestException('No version header received on handshake request');\n        }\n\n        if (!$this->acceptsVersion($headers[self::HEADER_VERSION])) {\n            throw new BadRequestException('Unsupported version: ' . $version);\n        }\n\n        if (!isset($headers[self::HEADER_KEY])) {\n            throw new BadRequestException('No key header received');\n        }\n\n        $key = trim($headers[self::HEADER_KEY]);\n\n        if (!$key) {\n            throw new BadRequestException('Invalid key');\n        }\n\n        // Optional\n        $protocol = isset($headers[self::HEADER_PROTOCOL]) ? $headers[self::HEADER_PROTOCOL] : null;\n\n        $extensions = array();\n        if (isset($headers[self::HEADER_EXTENSIONS]) && $headers[self::HEADER_EXTENSIONS]) {\n            $extensions = $headers[self::HEADER_EXTENSIONS];\n            if (is_scalar($extensions)) {\n                $extensions = array($extensions);\n            }\n        }\n\n        return array($path, $origin, $key, $extensions, $protocol);\n    }\n\n    /**\n     * Gets a suitable WebSocket close frame\n     *\n     * @param Exception|int $e\n     */\n    public function getCloseFrame($e)\n    {\n        $code = false;\n\n        if ($e instanceof Exception) {\n            $code = $e->getCode();\n        } elseif (is_numeric($e)) {\n            $code = (int)$e;\n        }\n\n        if (!$code || !key_exists($code, self::$closeReasons)) {\n            $code = self::CLOSE_UNEXPECTED;\n        }\n\n        $body = pack('n', $code) . self::$closeReasons[$code];\n\n        $payload = $this->getPayload();\n        return $payload->encode($body, self::TYPE_CLOSE);\n    }\n\n    /**\n     * Validates a WebSocket URI\n     *\n     * @param string $uri\n     * @return array(string $scheme, string $host, int $port, string $path)\n     */\n    public function validateUri($uri)\n    {\n        $uri = (string)$uri;\n        if (!$uri) {\n            throw new InvalidArgumentException('Invalid URI');\n        }\n\n        $scheme = parse_url($uri, PHP_URL_SCHEME);\n        $this->validateScheme($scheme);\n\n        $host = parse_url($uri, PHP_URL_HOST);\n        if (!$host) {\n            throw new InvalidArgumentException(\"Invalid host\");\n        }\n\n        $port = parse_url($uri, PHP_URL_PORT);\n        if (!$port) {\n            $port = $this->getPort($scheme);\n        }\n\n        $path = parse_url($uri, PHP_URL_PATH);\n        if (!$path) {\n            throw new InvalidArgumentException('Invalid path');\n        }\n\n        return array($scheme, $host, $port, $path);\n    }\n\n    /**\n     * Validates a socket URI\n     *\n     * @param string $uri\n     * @throws InvalidArgumentException\n     * @return array(string $scheme, string $host, string $port)\n     */\n    public function validateSocketUri($uri)\n    {\n        $uri = (string)$uri;\n        if (!$uri) {\n            throw new InvalidArgumentException('Invalid URI');\n        }\n\n        $scheme = parse_url($uri, PHP_URL_SCHEME);\n        $scheme = $this->validateScheme($scheme);\n\n        $host = parse_url($uri, PHP_URL_HOST);\n        if (!$host) {\n            throw new InvalidArgumentException(\"Invalid host\");\n        }\n\n        $port = parse_url($uri, PHP_URL_PORT);\n        if (!$port) {\n            $port = $this->getPort($scheme);\n        }\n\n        return array($scheme, $host, $port);\n    }\n\n    /**\n     * Validates an origin URI\n     *\n     * @param string $origin\n     * @throws InvalidArgumentException\n     * @return string\n     */\n    public function validateOriginUri($origin)\n    {\n        $origin = (string)$origin;\n        if (!$origin) {\n            throw new InvalidArgumentException('Invalid URI');\n        }\n\n        $scheme = parse_url($origin, PHP_URL_SCHEME);\n        if (!$scheme) {\n            throw new InvalidArgumentException('Invalid scheme');\n        }\n\n        $host = parse_url($origin, PHP_URL_HOST);\n        if (!$host) {\n            throw new InvalidArgumentException(\"Invalid host\");\n        }\n\n        return $origin;\n    }\n\n    /**\n     * Validates a request line\n     *\n     * @param string $line\n     * @throws BadRequestException\n     */\n    protected function validateRequestLine($line)\n    {\n        $matches = array(0 => null, 1 => null);\n\n        if (!preg_match(self::REQUEST_LINE_REGEX, $line, $matches) || !$matches[1]) {\n            throw new BadRequestException('Invalid request line', 400);\n        }\n\n        return $matches[1];\n    }\n\n    /**\n     * Gets the expected accept value for a handshake response\n     *\n     * Note that the protocol calls for the base64 encoded value to be hashed,\n     * not the original 16 byte random key.\n     *\n     * @see http://tools.ietf.org/html/rfc6455#section-4.2.2\n     * @param string $key\n     */\n    protected function getAcceptValue($encoded_key)\n    {\n        return base64_encode(sha1($encoded_key . self::MAGIC_GUID, true));\n    }\n\n    /**\n     * Gets the headers from a full response\n     *\n     * @param string $response\n     * @return array()\n     * @throws InvalidArgumentException\n     */\n    protected function getHeaders($response, &$request_line = null)\n    {\n        $parts = explode(\"\\r\\n\\r\\n\", $response, 2);\n\n        if (count($parts) != 2) {\n            $parts = array($parts, '');\n        }\n\n        list($headers, $body) = $parts;\n\n        $return = array();\n        foreach (explode(\"\\r\\n\", $headers) as $header) {\n            $parts = explode(': ', $header, 2);\n            if (count($parts) == 2) {\n                list($name, $value) = $parts;\n                if (!isset($return[$name])) {\n                    $return[$name] = $value;\n                } else {\n                    if (is_array($return[$name])) {\n                        $return[$name][] = $value;\n                    } else {\n                        $return[$name] = array($return[$name], $value);\n                    }\n                }\n            }\n        }\n\n        return $return;\n    }\n\n    /**\n     * Gets request headers\n     *\n     * @param string $response\n     * @return array<string, array<string>> The request line, and an array of\n     *             headers\n     * @throws InvalidArgumentException\n     */\n    protected function getRequestHeaders($response)\n    {\n        $eol = strpos($response, \"\\r\\n\");\n\n        if ($eol === false) {\n            throw new InvalidArgumentException('Invalid request line');\n        }\n\n        $request = substr($response, 0, $eol);\n        $headers = $this->getHeaders(substr($response, $eol + 2));\n\n        return array($request, $headers);\n    }\n\n    /**\n     * Validates a scheme\n     *\n     * @param string $scheme\n     * @return string Underlying scheme\n     * @throws InvalidArgumentException\n     */\n    protected function validateScheme($scheme)\n    {\n        if (!$scheme) {\n            throw new InvalidArgumentException('No scheme specified');\n        }\n        if (!in_array($scheme, self::$schemes)) {\n            throw new InvalidArgumentException(\n                'Unknown socket scheme: ' . $scheme\n            );\n        }\n\n        if ($scheme == self::SCHEME_WEBSOCKET_SECURE) {\n            return self::SCHEME_UNDERLYING_SECURE;\n        }\n        return self::SCHEME_UNDERLYING;\n    }\n\n    /**\n     * Gets the default request headers\n     *\n     * @param string $host\n     * @param string $key\n     * @param string $origin\n     * @param int $version\n     * @return multitype:unknown string NULL\n     */\n    protected function getDefaultRequestHeaders($host, $key, $origin)\n    {\n        return array(\n            self::HEADER_HOST       => $host,\n            self::HEADER_UPGRADE    => self::UPGRADE_VALUE,\n            self::HEADER_CONNECTION => self::CONNECTION_VALUE,\n            self::HEADER_KEY        => $key,\n            self::HEADER_ORIGIN     => $origin,\n            self::HEADER_VERSION    => $this->getVersion()\n        );\n    }\n\n    /**\n     * Gets the default response headers\n     *\n     * @param string $key\n     */\n    protected function getSuccessResponseHeaders($key)\n    {\n        return array(\n            self::HEADER_UPGRADE    => self::UPGRADE_VALUE,\n            self::HEADER_CONNECTION => self::CONNECTION_VALUE,\n            self::HEADER_ACCEPT     => $this->getAcceptValue($key)\n        );\n    }\n\n    /**\n     * Gets the default port for a scheme\n     *\n     * By default, the WebSocket Protocol uses port 80 for regular WebSocket\n     *  connections and port 443 for WebSocket connections tunneled over\n     *  Transport Layer Security\n     *\n     * @param string $uri\n     * @return int\n     */\n    protected function getPort($scheme)\n    {\n        if ($scheme == self::SCHEME_WEBSOCKET) {\n            return 80;\n        } elseif ($scheme == self::SCHEME_WEBSOCKET_SECURE) {\n            return 443;\n        } elseif ($scheme == self::SCHEME_UNDERLYING) {\n            return 80;\n        } elseif ($scheme == self::SCHEME_UNDERLYING_SECURE) {\n            return 443;\n        } else {\n            throw new InvalidArgumentException('Unknown websocket scheme');\n        }\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Protocol/Rfc6455Protocol.php",
    "content": "<?php\n\nnamespace Wrench\\Protocol;\n\nuse Wrench\\Protocol\\HybiProtocol;\n\n/**\n * This is the version of websockets used by Chrome versions 17 through 19.\n *\n * @see http://tools.ietf.org/html/rfc6455\n */\nclass Rfc6455Protocol extends HybiProtocol\n{\n    const VERSION = 13;\n\n    /**\n     * @see Wrench\\Protocol.Protocol::getVersion()\n     */\n    public function getVersion()\n    {\n        return self::VERSION;\n    }\n\n    /**\n     * This is our most recent protocol class\n     *\n     * @see Wrench\\Protocol.Protocol::acceptsVersion()\n     */\n    public function acceptsVersion($version)\n    {\n        if ((int)$version <= 13) {\n            return true;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "lib/Wrench/Resource.php",
    "content": "<?php\n\nnamespace Wrench;\n\n/**\n * Resource interface\n */\ninterface Resource\n{\n    public function getResourceId();\n    public function getResource();\n}\n"
  },
  {
    "path": "lib/Wrench/Server.php",
    "content": "<?php\n\nnamespace Wrench;\n\nuse Wrench\\Util\\Configurable;\n\nuse Wrench\\Socket;\nuse Wrench\\Resource;\n\nuse \\Closure;\nuse \\InvalidArgumentException;\n\n/**\n * WebSocket server\n *\n * The server extends socket, which provides the master socket resource. This\n * resource is listened to, and an array of clients managed.\n *\n * @author Nico Kaiser <nico@kaiser.me>\n * @author Simon Samtleben <web@lemmingzshadow.net>\n * @author Dominic Scheirlinck <dominic@varspool.com>\n */\nclass Server extends Configurable\n{\n    /**#@+\n     * Events\n     *\n     * @var string\n     */\n    const EVENT_SOCKET_CONNECT       = 'socket_connect';\n    const EVENT_SOCKET_DISCONNECT    = 'socket_disconnect';\n    const EVENT_HANDSHAKE_REQUEST    = 'handshake_request';\n    const EVENT_HANDSHAKE_SUCCESSFUL = 'handshake_successful';\n    const EVENT_CLIENT_DATA          = 'client_data';\n    /**#@-*/\n\n    /**\n     * The URI of the server\n     *\n     * @var string\n     */\n    protected $uri;\n\n    /**\n     * Options\n     *\n     * @var array\n     */\n    protected $options = array();\n\n    /**\n     * A logging callback\n     *\n     * The default callback simply prints to stdout. You can pass your own logger\n     * in the options array. It should take a string message and string priority\n     * as parameters.\n     *\n     * @var Closure\n     */\n    protected $logger;\n\n    /**\n     * Event listeners\n     *\n     * Add listeners using the addListener() method.\n     *\n     * @var array<string => array<Closure>>\n     */\n    protected $listeners = array();\n\n    /**\n     * Connection manager\n     *\n     * @var ConnectionManager\n     */\n    protected $connectionManager;\n\n    /**\n     * Applications\n     *\n     * @var array<string => Application>\n     */\n    protected $applications = array();\n\n    /**\n     * Constructor\n     *\n     * @param string $uri Websocket URI, e.g. ws://localhost:8000/, path will\n     *                     be ignored\n     * @param array $options (optional) See configure\n     */\n    public function __construct($uri, array $options = array())\n    {\n        $this->uri = $uri;\n\n        parent::__construct($options);\n\n        $this->log('Server initialized', 'info');\n    }\n\n    /**\n     * Configure options\n     *\n     * Options include\n     *   - socket_class      => The socket class to use, defaults to ServerSocket\n     *   - socket_options    => An array of socket options\n     *   - logger            => Closure($message, $priority = 'info'), used\n     *                                 for logging\n     *\n     * @param array $options\n     * @return void\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'connection_manager_class'   => 'Wrench\\ConnectionManager',\n            'connection_manager_options' => array()\n        ), $options);\n\n        parent::configure($options);\n\n        $this->configureConnectionManager();\n        $this->configureLogger();\n    }\n\n    /**\n     * Configures the logger\n     *\n     * @return void\n     */\n    protected function configureLogger()\n    {\n        // Default logger\n        if (!isset($this->options['logger'])) {\n            $this->options['logger'] = function ($message, $priority = 'info') {\n                printf(\"%s: %s%s\", $priority, $message, PHP_EOL);\n            };\n        }\n        $this->setLogger($this->options['logger']);\n    }\n\n    /**\n     * Configures the connection manager\n     *\n     * @return void\n     */\n    protected function configureConnectionManager()\n    {\n        $class   = $this->options['connection_manager_class'];\n        $options = $this->options['connection_manager_options'];\n        $this->connectionManager = new $class($this, $options);\n    }\n\n    /**\n     * Gets the connection manager\n     *\n     * @return \\Wrench\\ConnectionManager\n     */\n    public function getConnectionManager()\n    {\n        return $this->connectionManager;\n    }\n\n    /**\n     * @return string\n     */\n    public function getUri()\n    {\n        return $this->uri;\n    }\n\n    /**\n     * Sets a logger\n     *\n     * @param Closure $logger\n     * @return void\n     */\n    public function setLogger($logger)\n    {\n        if (!is_callable($logger)) {\n            throw new \\InvalidArgumentException('Logger must be callable');\n        }\n        $this->logger = $logger;\n    }\n\n    /**\n     * Main server loop\n     *\n     * @return void This method does not return!\n     */\n    public function run()\n    {\n        $this->connectionManager->listen();\n\n        while (true) {\n            /*\n             * If there's nothing changed on any of the sockets, the server\n             * will sleep and other processes will have a change to run. Control\n             * this behaviour with the timeout options.\n             */\n            $this->connectionManager->selectAndProcess();\n\n            /*\n             * If the application wants to perform periodic operations or queries and push updates to clients based on the result then that logic can be implemented in the 'onUpdate' method.\n             */\n            foreach($this->applications as $application) {\n                if(method_exists($application, 'onUpdate')) {\n                    $application->onUpdate();\n                }\n            }\n        }\n    }\n\n    /**\n     * Logs a message to the server log\n     *\n     * The default logger simply prints the message to stdout. You can provide\n     * a logging closure. This is useful, for instance, if you've daemonized\n     * and closed STDOUT.\n     *\n     * @param string $message Message to display.\n     * @param string $type Type of message.\n     * @return void\n     */\n    public function log($message, $priority = 'info')\n    {\n        call_user_func($this->logger, $message, $priority);\n    }\n\n    /**\n     * Notifies listeners of an event\n     *\n     * @param string $event\n     * @param array $arguments Event arguments\n     * @return void\n     */\n    public function notify($event, array $arguments = array())\n    {\n        if (!isset($this->listeners[$event])) {\n            return;\n        }\n\n        foreach ($this->listeners[$event] as $listener) {\n            call_user_func_array($listener, $arguments);\n        }\n    }\n\n    /**\n     * Adds a listener\n     *\n     * Provide an event (see the Server::EVENT_* constants) and a callback\n     * closure. Some arguments may be provided to your callback, such as the\n     * connection the caused the event.\n     *\n     * @param string $event\n     * @param Closure $callback\n     * @return void\n     * @throws InvalidArgumentException\n     */\n    public function addListener($event, $callback)\n    {\n        if (!isset($this->listeners[$event])) {\n            $this->listeners[$event] = array();\n        }\n\n        if (!is_callable($callback)) {\n            throw new InvalidArgumentException('Invalid listener');\n        }\n\n        $this->listeners[$event][] = $callback;\n    }\n\n    /**\n     * Returns a server application.\n     *\n     * @param string $key Name of application.\n     * @return Application The application object.\n     */\n    public function getApplication($key)\n    {\n        if (empty($key)) {\n            return false;\n        }\n\n        if (array_key_exists($key, $this->applications)) {\n            return $this->applications[$key];\n        }\n\n        return false;\n    }\n\n    /**\n     * Adds a new application object to the application storage.\n     *\n     * @param string $key Name of application.\n     * @param object $application The application object\n     * @return void\n     */\n    public function registerApplication($key, $application)\n    {\n        $this->applications[$key] = $application;\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Socket/ClientSocket.php",
    "content": "<?php\nnamespace Wrench\\Socket;\n\nuse Wrench\\Socket\\UriSocket;\n\n/**\n * Options:\n *  - timeout_connect      => int, seconds, default 2\n */\nclass ClientSocket extends UriSocket\n{\n    /**\n     * Default connection timeout\n     *\n     * @var int seconds\n     */\n    const TIMEOUT_CONNECT = 2;\n\n    /**\n     * @see Wrench\\Socket.Socket::configure()\n     *   Options include:\n     *     - ssl_verify_peer       => boolean, whether to perform peer verification\n     *                                 of SSL certificate used\n     *     - ssl_allow_self_signed => boolean, whether ssl_verify_peer allows\n     *                                 self-signed certs\n     *     - timeout_connect       => int, seconds, default 2\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'timeout_connect'       => self::TIMEOUT_CONNECT,\n            'ssl_verify_peer'       => false,\n            'ssl_allow_self_signed' => true\n        ), $options);\n\n        parent::configure($options);\n    }\n\n    /**\n     * Connects to the given socket\n     */\n    public function connect()\n    {\n        if ($this->isConnected()) {\n            return true;\n        }\n\n        $errno = null;\n        $errstr = null;\n\n        $this->socket = stream_socket_client(\n            $this->getUri(),\n            $errno,\n            $errstr,\n            $this->options['timeout_connect'],\n            STREAM_CLIENT_CONNECT,\n            $this->getStreamContext()\n        );\n\n        if (!$this->socket) {\n            throw new ConnectionException(sprintf(\n                'Could not connect to socket: %s (%d)',\n                $errstr,\n                $errno\n            ));\n        }\n\n        stream_set_timeout($this->socket, $this->options['timeout_socket']);\n\n        return ($this->connected = true);\n    }\n\n    public function reconnect()\n    {\n        $this->disconnect();\n        $this->connect();\n    }\n\n    /**\n     * @see Wrench\\Socket.UriSocket::getSocketStreamContextOptions()\n     */\n    protected function getSocketStreamContextOptions()\n    {\n        $options = array();\n        return $options;\n    }\n\n    /**\n     * @see Wrench\\Socket.UriSocket::getSslStreamContextOptions()\n     */\n    protected function getSslStreamContextOptions()\n    {\n        $options = array();\n\n        if ($this->options['ssl_verify_peer']) {\n            $options['verify_peer'] = true;\n        }\n\n        if ($this->options['ssl_allow_self_signed']) {\n            $options['allow_self_signed'] = true;\n        }\n\n        return $options;\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Socket/ServerClientSocket.php",
    "content": "<?php\n\nnamespace Wrench\\Socket;\n\nuse Wrench\\Socket\\Socket;\n\nclass ServerClientSocket extends Socket\n{\n    /**\n     * Constructor\n     *\n     * A server client socket is accepted from a listening socket, so there's\n     * no need to call ->connect() or whatnot.\n     *\n     * @param resource $accepted_socket\n     * @param array $options\n     */\n    public function __construct($accepted_socket, array $options = array())\n    {\n        parent::__construct($options);\n\n        $this->socket = $accepted_socket;\n        $this->connected = (boolean)$accepted_socket;\n    }\n}"
  },
  {
    "path": "lib/Wrench/Socket/ServerSocket.php",
    "content": "<?php\n\nnamespace Wrench\\Socket;\n\nuse Wrench\\Exception\\ConnectionException;\n\nuse Wrench\\Socket\\UriSocket;\n\n/**\n * Server socket\n *\n * Used for a server's \"master\" socket that binds to the configured\n * interface and listens\n */\nclass ServerSocket extends UriSocket\n{\n    const TIMEOUT_ACCEPT = 5;\n\n    /**\n     * Whether the socket is listening\n     *\n     * @var boolean\n     */\n    protected $listening = false;\n\n    /**\n     * @see Wrench\\Socket.Socket::configure()\n     *   Options include:\n     *     - backlog               => int, used to limit the number of outstanding\n     *                                 connections in the socket's listen queue\n     *     - ssl_cert_file         => string, server SSL certificate\n     *                                 file location. File should contain\n     *                                 certificate and private key\n     *     - ssl_passphrase        => string, passphrase for the key\n     *     - timeout_accept        => int, seconds, default 5\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'backlog'               => 50,\n            'ssl_cert_file'         => null,\n            'ssl_passphrase'        => null,\n            'ssl_allow_self_signed' => false,\n            'timeout_accept'        => self::TIMEOUT_ACCEPT\n        ), $options);\n\n        parent::configure($options);\n    }\n\n    /**\n     * Listens\n     *\n     * @throws ConnectionException\n     */\n    public function listen()\n    {\n        $this->socket = stream_socket_server(\n            $this->getUri(),\n            $errno,\n            $errstr,\n            STREAM_SERVER_BIND|STREAM_SERVER_LISTEN.\n            $this->getStreamContext()\n        );\n\n        if (!$this->socket) {\n            throw new ConnectionException(sprintf(\n                'Could not listen on socket: %s (%d)',\n                $errstr,\n                $errno\n            ));\n        }\n\n        $this->listening = true;\n    }\n\n    /**\n     * Accepts a new connection on the socket\n     *\n     * @throws ConnectionException\n     * @return resource\n     */\n    public function accept()\n    {\n        $new = stream_socket_accept(\n            $this->socket,\n            $this->options['timeout_accept']\n        );\n\n        if (!$new) {\n            throw new ConnectionException(socket_strerror(socket_last_error($new)));\n        }\n\n        return $new;\n    }\n\n    /**\n     * @see Wrench\\Socket.UriSocket::getSocketStreamContextOptions()\n     */\n    protected function getSocketStreamContextOptions()\n    {\n        $options = array();\n\n        if ($this->options['backlog']) {\n            $options['backlog'] = $this->options['backlog'];\n        }\n\n        return $options;\n    }\n\n    /**\n     * @see Wrench\\Socket.UriSocket::getSslStreamContextOptions()\n     */\n    protected function getSslStreamContextOptions()\n    {\n        $options = array();\n\n        if ($this->options['server_ssl_cert_file']) {\n            $options['local_cert'] = $this->options['server_ssl_cert_file'];\n            if ($this->options['server_ssl_passphrase']) {\n                $options['passphrase'] = $this->options['server_ssl_passphrase'];\n            }\n        }\n\n        return $options;\n    }\n}"
  },
  {
    "path": "lib/Wrench/Socket/Socket.php",
    "content": "<?php\n\nnamespace Wrench\\Socket;\n\nuse Wrench\\Resource;\nuse Wrench\\Exception\\ConnectionException;\nuse Wrench\\Exception\\SocketException;\nuse Wrench\\Util\\Configurable;\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Protocol\\Rfc6455Protocol;\nuse \\InvalidArgumentException;\n\n/**\n * Socket class\n *\n * Implements low level logic for connecting, serving, reading to, and\n * writing from WebSocket connections using PHP's streams.\n *\n * Unlike in previous versions of this library, a Socket instance now\n * represents a single underlying socket resource. It's designed to be used\n * by aggregation, rather than inheritence.\n */\nabstract class Socket extends Configurable implements Resource\n{\n    /**\n     * Default timeout for socket operations (reads, writes)\n     *\n     * @var int seconds\n     */\n    const TIMEOUT_SOCKET = 5;\n\n    /**\n     * @var int\n     */\n    const DEFAULT_RECEIVE_LENGTH = '1400';\n\n    /**#@+\n     * Socket name parts\n     *\n     * @var int\n     */\n    const NAME_PART_IP = 0;\n    const NAME_PART_PORT = 1;\n    /**#@-*/\n\n    /**\n     * @var resource\n     */\n    protected $socket = null;\n\n    /**\n     * Stream context\n     */\n    protected $context = null;\n\n    /**\n     * Whether the socket is connected to a server\n     *\n     * Note, the connection may not be ready to use, but the socket is\n     * connected at least. See $handshaked, and other properties in\n     * subclasses.\n     *\n     * @var boolean\n     */\n    protected $connected = false;\n\n    /**\n     * Whether the current read is the first one to the socket\n     *\n     * @var boolean\n     */\n    protected $firstRead = true;\n\n    /**\n     * The socket name according to stream_socket_get_name\n     *\n     * @var string\n     */\n    protected $name;\n\n    /**\n     * Configure options\n     *\n     * Options include\n     *   - timeout_connect      => int, seconds, default 2\n     *   - timeout_socket       => int, seconds, default 5\n     *\n     * @param array $options\n     * @return void\n     */\n    protected function configure(array $options)\n    {\n        $options = array_merge(array(\n            'timeout_socket' => self::TIMEOUT_SOCKET,\n        ), $options);\n\n        parent::configure($options);\n    }\n\n    /**\n     * Gets the name of the socket\n     */\n    protected function getName()\n    {\n        if (!isset($this->name) || !$this->name) {\n            $this->name = @stream_socket_get_name($this->socket, true);\n        }\n        return $this->name;\n    }\n\n    /**\n     * Gets part of the name of the socket\n     *\n     * PHP seems to return IPV6 address/port combos like this:\n     *   ::1:1234, where ::1 is the address and 1234 the port\n     * So, the part number here is either the last : delimited section (the port)\n     * or all the other sections (the whole initial part, the address).\n     *\n     * @param string $name (from $this->getName() usually)\n     * @param int<0, 1> $part\n     * @return string\n     * @throws SocketException\n     */\n    public static function getNamePart($name, $part)\n    {\n        if (!$name) {\n            throw new InvalidArgumentException('Invalid name');\n        }\n\n        $parts = explode(':', $name);\n\n        if (count($parts) < 2) {\n            throw new SocketException('Could not parse name parts: ' . $name);\n        }\n\n        if ($part == self::NAME_PART_PORT) {\n            return end($parts);\n        } elseif ($part == self::NAME_PART_IP) {\n            return implode(':', array_slice($parts, 0, -1));\n        } else {\n            throw new InvalidArgumentException('Invalid name part');\n        }\n\n        return null;\n    }\n\n    /**\n     * Gets the IP address of the socket\n     *\n     * @return string\n     */\n    public function getIp()\n    {\n        $name = $this->getName();\n\n        if ($name) {\n            return self::getNamePart($name, self::NAME_PART_IP);\n        } else {\n            throw new SocketException('Cannot get socket IP address');\n        }\n    }\n\n    /**\n     * Gets the port of the socket\n     *\n     * @return int\n     */\n    public function getPort()\n    {\n        $name = $this->getName();\n\n        if ($name) {\n            return self::getNamePart($name, self::NAME_PART_PORT);\n        } else {\n            throw new SocketException('Cannot get socket IP address');\n        }\n    }\n\n    /**\n     * Get the last error that occurred on the socket\n     *\n     * @return int|string\n     */\n    public function getLastError()\n    {\n        if ($this->isConnected() && $this->socket) {\n            $err = @socket_last_error($this->socket);\n            if ($err) {\n                $err = socket_strerror($err);\n            }\n            if (!$err) {\n                $err = 'Unknown error';\n            }\n            return $err;\n        } else {\n            return 'Not connected';\n        }\n    }\n\n    /**\n     * Whether the socket is currently connected\n     *\n     * @return boolean\n     */\n    public function isConnected()\n    {\n        return $this->connected;\n    }\n\n    /**\n     * Disconnect the socket\n     *\n     * @return void\n     */\n    public function disconnect()\n    {\n        if ($this->socket) {\n            stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);\n        }\n        $this->socket = null;\n        $this->connected = false;\n    }\n\n    /**\n     * @see Wrench.Resource::getResource()\n     */\n    public function getResource()\n    {\n        return $this->socket;\n    }\n\n    /**\n     * @see Wrench.Resource::getResourceId()\n     */\n    public function getResourceId()\n    {\n        return (int)$this->socket;\n    }\n\n    /**\n     * @param unknown_type $data\n     * @throws SocketException\n     * @return boolean|int The number of bytes sent or false on error\n     */\n    public function send($data)\n    {\n        if (!$this->isConnected()) {\n            throw new SocketException('Socket is not connected');\n        }\n\n        $length = strlen($data);\n\n        if ($length == 0) {\n            return 0;\n        }\n\n        for ($i = $length; $i > 0; $i -= $written) {\n            $written = @fwrite($this->socket, substr($data, -1 * $i));\n\n            if ($written === false) {\n                return false;\n            } elseif ($written === 0) {\n                return false;\n            }\n        }\n\n        return $length;\n    }\n\n    /**\n     * Recieve data from the socket\n     *\n     * @param int $length\n     * @return string\n     */\n    public function receive($length = self::DEFAULT_RECEIVE_LENGTH)\n    {\n        $remaining = $length;\n\n        $buffer = '';\n        $metadata['unread_bytes'] = 0;\n\n        do {\n            if (feof($this->socket)) {\n                return $buffer;\n            }\n\n            $result = fread($this->socket, $length);\n\n            if ($result === false) {\n                return $buffer;\n            }\n\n            $buffer .= $result;\n\n            if (feof($this->socket)) {\n                return $buffer;\n            }\n\n            $continue = false;\n\n            if ($this->firstRead == true && strlen($result) == 1) {\n                // Workaround Chrome behavior (still needed?)\n                $continue = true;\n            }\n            $this->firstRead = false;\n\n            if (strlen($result) == $length) {\n                $continue = true;\n            }\n\n            // Continue if more data to be read\n            $metadata = stream_get_meta_data($this->socket);\n            if ($metadata && isset($metadata['unread_bytes']) && $metadata['unread_bytes']) {\n                $continue = true;\n                $length = $metadata['unread_bytes'];\n            }\n        } while ($continue);\n\n        return $buffer;\n    }\n}"
  },
  {
    "path": "lib/Wrench/Socket/UriSocket.php",
    "content": "<?php\n\nnamespace Wrench\\Socket;\n\nuse Wrench\\Protocol\\Protocol;\n\nuse Wrench\\Socket\\Socket;\n\nabstract class UriSocket extends Socket\n{\n    protected $scheme;\n    protected $host;\n    protected $port;\n\n    /**\n     * URI Socket constructor\n     *\n     * @param string $uri     WebSocket URI, e.g. ws://example.org:8000/chat\n     * @param array  $options (optional)\n     *   Options:\n     *     - protocol             => Wrench\\Protocol object, latest protocol\n     *                                 version used if not specified\n     *     - timeout_socket       => int, seconds, default 5\n     *     - server_ssl_cert_file => string, server SSL certificate\n     *                                 file location. File should contain\n     *                                 certificate and private key\n     *     - server_ssl_passphrase => string, passphrase for the key\n     *     - server_ssl_allow_self_signed => boolean, whether to allows self-\n     *                                 signed certs\n     */\n    public function __construct($uri, array $options = array())\n    {\n        parent::__construct($options);\n\n        list($this->scheme, $this->host, $this->port)\n            = $this->protocol->validateSocketUri($uri);\n    }\n\n    /**\n     * Gets the canonical/normalized URI for this socket\n     *\n     * @return string\n     */\n    protected function getUri()\n    {\n        return sprintf(\n            '%s://%s:%d',\n            $this->scheme,\n            $this->host,\n            $this->port\n        );\n    }\n\n    /**\n     * @todo DNS lookup? Override getIp()?\n     * @see Wrench\\Socket.Socket::getName()\n     */\n    protected function getName()\n    {\n        return sprintf('%s:%s', $this->host, $this->port);\n    }\n\n    /**\n     * Gets the host name\n     */\n    public function getHost()\n    {\n        return $this->host;\n    }\n\n    /**\n     * @see Wrench\\Socket.Socket::getPort()\n     */\n    public function getPort()\n    {\n        return $this->port;\n    }\n\n    /**\n     * Gets a stream context\n     */\n    protected function getStreamContext($listen = false)\n    {\n        $options = array();\n\n        if ($this->scheme == Protocol::SCHEME_UNDERLYING_SECURE\n            || $this->scheme == Protocol::SCHEME_UNDERLYING) {\n            $options['socket'] = $this->getSocketStreamContextOptions();\n        }\n\n        if ($this->scheme == Protocol::SCHEME_UNDERLYING_SECURE) {\n            $options['ssl'] = $this->getSslStreamContextOptions();\n        }\n\n        return stream_context_create(\n            $options,\n            array()\n        );\n    }\n\n    /**\n     * Returns an array of socket stream context options\n     *\n     * See http://php.net/manual/en/context.socket.php\n     *\n     * @return array\n     */\n    abstract protected function getSocketStreamContextOptions();\n\n    /**\n     * Returns an array of ssl stream context options\n     *\n     * See http://php.net/manual/en/context.ssl.php\n     *\n     * @return array\n     */\n    abstract protected function getSslStreamContextOptions();\n}\n"
  },
  {
    "path": "lib/Wrench/Tests/Application/EchoApplicationTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Application;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Tests\\Test as WrenchTest;\n\nclass EchoApplicationTest extends WrenchTest\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    protected function getClass()\n    {\n        return 'Wrench\\Application\\EchoApplication';\n    }\n\n    /**\n     * Tests the constructor\n     */\n    public function testConstructor()\n    {\n        $this->assertInstanceOfClass($this->getInstance());\n    }\n\n    /**\n     * @param unknown_type $payload\n     * @dataProvider getValidPayloads\n     */\n    public function testOnData($payload)\n    {\n        $connection = $this->getMockBuilder('Wrench\\Connection')\n                     ->disableOriginalConstructor()\n                     ->getMock();\n\n        $connection\n            ->expects($this->once())\n            ->method('send')\n            ->with($this->equalTo($payload), $this->equalTo(Protocol::TYPE_TEXT))\n            ->will($this->returnValue(true));\n\n        $this->getInstance()->onData($payload, $connection);\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<array<string>>\n     */\n    public function getValidPayloads()\n    {\n        return array(\n            array('asdkllakdaowidoaw noaoinosdna nwodinado ndsnd aklndiownd'),\n            array(' ')\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/BasicServerTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests;\n\nuse Wrench\\Server;\nuse Wrench\\BasicServer;\nuse Wrench\\Tests\\ServerTest;\nuse Wrench\\Socket;\n\nuse \\InvalidArgumentException;\nuse \\PHPUnit_Framework_Error;\n\n/**\n * Tests the BasicServer class\n */\nclass BasicServerTest extends ServerTest\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    protected function getClass()\n    {\n        return 'Wrench\\BasicServer';\n    }\n\n    /**\n     * @param array $allowed\n     * @param string $origin\n     * @dataProvider getValidOrigins\n     */\n    public function testValidOriginPolicy(array $allowed, $origin)\n    {\n        $server = $this->getInstance('ws://localhost:8000', array(\n            'allowed_origins' => $allowed,\n            'logger' => array($this, 'log')\n        ));\n\n        $connection = $this->getMockBuilder('Wrench\\Connection')\n                        ->disableOriginalConstructor()\n                        ->getMock();\n\n        $connection\n            ->expects($this->never())\n            ->method('close')\n            ->will($this->returnValue(true));\n\n        $server->notify(\n            Server::EVENT_HANDSHAKE_REQUEST,\n            array($connection, '', $origin, '', array())\n        );\n    }\n\n    /**\n     * @param array $allowed\n     * @param string $origin\n     * @dataProvider getInvalidOrigins\n     */\n    public function testInvalidOriginPolicy(array $allowed, $origin)\n    {\n        $server = $this->getInstance('ws://localhost:8000', array(\n            'allowed_origins' => $allowed,\n            'logger' => array($this, 'log')\n        ));\n\n        $connection = $this->getMockBuilder('Wrench\\Connection')\n                        ->disableOriginalConstructor()\n                        ->getMock();\n\n        $connection\n            ->expects($this->once())\n            ->method('close')\n            ->will($this->returnValue(true));\n\n        $server->notify(\n            Server::EVENT_HANDSHAKE_REQUEST,\n            array($connection, '', $origin, '', array())\n        );\n    }\n\n    /**\n     * @see Wrench\\Tests.ServerTest::getValidConstructorArguments()\n     */\n    public function getValidConstructorArguments()\n    {\n        return array_merge(parent::getValidConstructorArguments(), array(\n            array(\n                'ws://localhost:8000',\n                array('logger' => function () {})\n            )\n        ));\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<array<mixed>>\n     */\n    public function getValidOrigins()\n    {\n        return array(\n            array(array('localhost'), 'localhost'),\n            array(array('somewhere.com'), 'somewhere.com'),\n        );\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<array<mixed>>\n     */\n    public function getInvalidOrigins()\n    {\n        return array(\n            array(array('localhost'), 'blah'),\n            array(array('somewhere.com'), 'somewhereelse.com'),\n            array(array('somewhere.com'), 'subdomain.somewhere.com')\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/ClientTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests;\n\nuse Wrench\\Protocol\\Protocol;\n\nuse Wrench\\Client;\nuse Wrench\\Tests\\Test;\nuse Wrench\\Socket;\n\nuse \\InvalidArgumentException;\nuse \\PHPUnit_Framework_Error;\n\n/**\n * Tests the client class\n */\nclass ClientTest extends Test\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    protected function getClass()\n    {\n        return 'Wrench\\Client';\n    }\n\n    public function testConstructor()\n    {\n        $this->assertInstanceOfClass(\n            $client = new Client(\n                'ws://localhost/test', 'http://example.org/'\n            ),\n            'ws:// scheme, default socket'\n        );\n\n        $this->assertInstanceOfClass(\n            $client = new Client(\n                'ws://localhost/test', 'http://example.org/',\n                array('socket' => $this->getMockSocket())\n            ),\n            'ws:// scheme, socket specified'\n        );\n    }\n\n    /**\n     * Gets a mock socket\n     *\n     * @return Socket\n     */\n    protected function getMockSocket()\n    {\n        return $this->getMock('Wrench\\Socket\\ClientSocket', array(), array('wss://localhost:8000'));\n    }\n\n    /**\n     * @expectedException PHPUnit_Framework_Error\n     */\n    public function testConstructorSocketUnspecified()\n    {\n        $w = new Client();\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testConstructorUriInvalid()\n    {\n        $w = new Client('invalid uri', 'http://www.example.com/');\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testConstructorUriEmpty()\n    {\n        $w = new Client(null, 'http://www.example.com/');\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testConstructorUriPathUnspecified()\n    {\n        $w = new Client('ws://localhost', 'http://www.example.com/');\n    }\n\n    /**\n     * @expectedException PHPUnit_Framework_Error\n     */\n    public function testConstructorOriginUnspecified()\n    {\n        $w = new Client('ws://localhost');\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testConstructorOriginEmpty()\n    {\n        $w = new Client('wss://localhost', null);\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testConstructorOriginInvalid()\n    {\n        $w = new Client('ws://localhost:8000', 'NOTAVALIDURI');\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testSendInvalidType()\n    {\n        $client = new Client('ws://localhost/test', 'http://example.org/');\n        $client->sendData('blah', 9999);\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testSendInvalidTypeString()\n    {\n        $client = new Client('ws://localhost/test', 'http://example.org/');\n        $client->sendData('blah', 'fooey');\n    }\n\n    public function testSend()\n    {\n        try {\n            $helper = new ServerTestHelper();\n            $helper->setUp();\n\n            /* @var $instance Wrench\\Client */\n            $instance = $this->getInstance($helper->getEchoConnectionString(), 'http://www.example.com/send');\n            $instance->addRequestHeader('X-Test', 'Custom Request Header');\n\n            $this->assertFalse($instance->receive(), 'Receive before connect');\n\n            $success = $instance->connect();\n            $this->assertTrue($success, 'Client can connect to test server');\n            $this->assertTrue($instance->isConnected());\n\n            $this->assertFalse($instance->connect(), 'Double connect');\n\n            $this->assertFalse((boolean)$instance->receive(), 'No data');\n\n            $bytes = $instance->sendData('foobar', 'text');\n            $this->assertTrue($bytes >= 6, 'sent text frame');\n            sleep(1);\n\n            $bytes = $instance->sendData('baz', Protocol::TYPE_TEXT);\n            $this->assertTrue($bytes >= 3, 'sent text frame');\n            sleep(1);\n\n            $responses = $instance->receive();\n            $this->assertTrue(is_array($responses));\n            $this->assertCount(2, $responses);\n            $this->assertInstanceOf('Wrench\\\\Payload\\\\Payload', $responses[0]);\n            $this->assertInstanceOf('Wrench\\\\Payload\\\\Payload', $responses[1]);\n\n            $instance->disconnect();\n\n            $this->assertFalse($instance->isConnected());\n        } catch (\\Exception $e) {\n            $helper->tearDown();\n            throw $e;\n        }\n\n        $helper->tearDown();\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Tests/ConnectionManagerTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests;\n\nuse Wrench\\ConnectionManager;\nuse Wrench\\Tests\\Test;\n\nuse Wrench\\Application\\EchoApplication;\n\nuse \\InvalidArgumentException;\nuse \\PHPUnit_Framework_Error;\n\n/**\n * Tests the ConnectionManager class\n */\nclass ConnectionManagerTest extends Test\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    protected function getClass()\n    {\n        return 'Wrench\\ConnectionManager';\n    }\n\n    /**\n     * Tests the constructor\n     *\n     * @dataProvider getValidConstructorArguments\n     */\n    public function testValidConstructorArguments($server, array $options)\n    {\n        $this->assertInstanceOfClass(\n            $instance = $this->getInstance(\n                $server,\n                $options\n            ),\n            'Valid constructor arguments'\n        );\n    }\n\n    /**\n     * Tests the constructor\n     */\n    public function testConstructor()\n    {\n        $this->assertInstanceOfClass(\n            $instance = $this->getInstance(\n                $this->getMockServer(),\n                array()\n            ),\n            'Constructor'\n        );\n        return $instance;\n    }\n\n    /**\n     * @depends testConstructor\n     * @param ConnectionManager $instance\n     */\n    public function testCount($instance)\n    {\n        $this->assertTrue(is_numeric($instance->count()));\n    }\n\n    /**\n     * Data provider\n     */\n    public function getValidConstructorArguments()\n    {\n        return array(\n            array($this->getMockServer(), array())\n        );\n    }\n\n    /**\n     * Gets a mock server\n     */\n    protected function getMockServer()\n    {\n        $server = $this->getMock('Wrench\\Server', array(), array(), '', false);\n\n        $server->registerApplication('/echo', $this->getMockApplication());\n\n        $server->expects($this->any())\n                ->method('getUri')\n                ->will($this->returnValue('ws://localhost:8000/'));\n\n        return $server;\n    }\n\n    /**\n     * Gets a mock application\n     *\n     * @return EchoApplication\n     */\n    protected function getMockApplication()\n    {\n        return new EchoApplication();\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/ConnectionTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests;\n\nuse Wrench\\Application\\EchoApplication;\n\nuse Wrench\\Protocol\\Protocol;\n\nuse Wrench\\Connection;\nuse Wrench\\Tests\\Test;\nuse Wrench\\Socket;\n\nuse \\InvalidArgumentException;\nuse \\PHPUnit_Framework_Error;\n\n/**\n * Tests the Connection class\n */\nclass ConnectionTest extends Test\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    protected function getClass()\n    {\n        return 'Wrench\\Connection';\n    }\n\n    /**\n     * Tests the constructor\n     *\n     * @dataProvider getValidConstructorArguments\n     */\n    public function testConstructor($manager, $socket, array $options)\n    {\n        $this->assertInstanceOfClass(\n            $instance = $this->getInstance(\n                $manager,\n                $socket,\n                $options\n            ),\n            'Valid constructor arguments'\n        );\n\n        return $instance;\n    }\n\n    /**\n     * @dataProvider getValidCloseCodes\n     */\n    public function testClose($code)\n    {\n        $socket = $this->getMockSocket();\n\n        $socket->expects($this->any())\n                ->method('getIp')\n                ->will($this->returnValue('127.0.0.1'));\n\n        $socket->expects($this->any())\n                ->method('getPort')\n                ->will($this->returnValue(mt_rand(1025, 50000)));\n\n        $manager = $this->getMockConnectionManager();\n\n        $connection = $this->getInstance($manager, $socket);\n        $connection->close($code);\n    }\n\n    /**\n     * @dataProvider getValidHandshakeData\n     */\n    public function testHandshake($path, $request)\n    {\n        $connection = $this->getConnectionForHandshake(\n            $this->getConnectedSocket(),\n            $path,\n            $request\n        );\n        $connection->handshake($request);\n        $connection->onData('somedata');\n        $this->assertTrue($connection->send('someotherdata'));\n        return $connection;\n    }\n\n    /**\n     * @dataProvider getValidHandshakeData\n     * @expectedException Wrench\\Exception\\HandshakeException\n     */\n    public function testHandshakeBadSocket($path, $request)\n    {\n        $connection = $this->getConnectionForHandshake(\n            $this->getNotConnectedSocket(),\n            $path,\n            $request\n        );\n        $connection->handshake($request);\n    }\n\n    /**\n     * Because expectation is that only $path application is available\n     *\n     * @dataProvider getWrongPathHandshakeData\n     * @expectedException PHPUnit_Framework_ExpectationFailedException\n     */\n    public function testWrongPathHandshake($path, $request)\n    {\n        $connection = $this->getConnectionForHandshake(\n            $this->getConnectedSocket(),\n            $path,\n            $request\n        );\n        $connection->handshake($request);\n    }\n\n    /**\n     * @dataProvider getValidHandleData\n     */\n    public function testHandle($path, $request_handshake, array $requests, array $counts)\n    {\n        $connection = $this->getConnectionForHandle(\n            $this->getConnectedSocket(),\n            $path,\n            $request_handshake,\n            $counts\n        );\n\n        $connection->handshake($request_handshake);\n\n        foreach ($requests as $request) {\n            $connection->handle($request);\n        }\n\n        return $connection;\n    }\n\n    /**\n     * @return Socket\n     */\n    protected function getConnectedSocket()\n    {\n        $socket = $this->getMockSocket();\n\n        $socket->expects($this->any())\n                ->method('isConnected')\n                ->will($this->returnValue(true));\n\n        return $socket;\n    }\n\n    /**\n     * @return Socket\n     */\n    protected function getNotConnectedSocket()\n    {\n        $socket = $this->getMockSocket();\n\n        $socket->expects($this->any())\n                ->method('isConnected')\n                ->will($this->returnValue(false));\n\n        return $socket;\n    }\n\n    protected function getConnectionForHandshake($socket, $path, $request)\n    {\n        $manager = $this->getMockConnectionManager();\n\n        $application = $this->getMockApplication();\n\n        $server = $this->getMock('Wrench\\Server', array(), array(), '', false);\n        $server->registerApplication($path, $application);\n\n        $manager->expects($this->any())\n                ->method('getApplicationForPath')\n                ->with($path)\n                ->will($this->returnValue($application));\n\n        $manager->expects($this->any())\n                ->method('getServer')\n                ->will($this->returnValue($server));\n\n        $connection = $this->getInstance($manager, $socket);\n\n        return $connection;\n    }\n\n    protected function getConnectionForHandle($socket, $path, $handshake, array $counts)\n    {\n        $connection = $this->getConnectionForHandshake($socket, $path, $handshake);\n\n        $manager = $this->getMockConnectionManager();\n\n        $application = $this->getMockApplication();\n\n        $application->expects($this->exactly(isset($counts['onData']) ? $counts['onData'] : 0))\n                    ->method('onData')\n                    ->will($this->returnValue(true));\n\n        $server = $this->getMock('Wrench\\Server', array(), array(), '', false);\n        $server->registerApplication($path, $application);\n\n        $manager->expects($this->any())\n                ->method('getApplicationForPath')\n                ->with($path)\n                ->will($this->returnValue($application));\n\n        $manager->expects($this->exactly(isset($counts['removeConnection']) ? $counts['removeConnection'] : 0))\n                ->method('removeConnection');\n\n        $manager->expects($this->any())\n                ->method('getServer')\n                ->will($this->returnValue($server));\n\n        $connection = $this->getInstance($manager, $socket);\n\n        return $connection;\n    }\n\n    /**\n     * @return ConnectionManager\n     */\n    protected function getMockConnectionManager()\n    {\n        return $this->getMock('Wrench\\ConnectionManager', array(), array(), '', false);\n    }\n\n    /**\n     * Gets a mock socket\n     *\n     * @return Socket\n     */\n    protected function getMockSocket()\n    {\n        return $this->getMock('Wrench\\Socket\\ServerClientSocket', array(), array(), '', false);\n    }\n\n    /**\n     * Gets a mock application\n     *\n     * @return EchoApplication\n     */\n    protected function getMockApplication()\n    {\n        return $this->getMock('Wrench\\Application\\EchoApplication');\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<array<int>>\n     */\n    public function getValidCloseCodes()\n    {\n        $arguments = array();\n        foreach (Protocol::$closeReasons as $code => $reason) {\n            $arguments[] = array($code);\n        }\n        return $arguments;\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<array<mixed>>\n     */\n    public function getValidConstructorArguments()\n    {\n        $socket = $this->getMockSocket();\n\n        $socket->expects($this->any())\n                ->method('getIp')\n                ->will($this->returnValue('127.0.0.1'));\n\n        $socket->expects($this->any())\n                ->method('getPort')\n                ->will($this->returnValue(mt_rand(1025, 50000)));\n\n        $manager = $this->getMockConnectionManager();\n\n        return array(\n            array(\n                $manager,\n                $socket,\n                array('logger' => function() {})\n            ),\n            array(\n                $manager,\n                $socket,\n                array('logger' => function () {},\n                      'connection_id_algo' => 'sha512')\n            )\n        );\n    }\n\n    /**\n     * Data provider\n     *\n     * Uses this awkward valid request array so that splitting of payloads\n     * across multiple calls to handle can be tested\n     *\n     * testHandle($path, $request_handshake, array $requests, array $counts)\n     */\n    public function getValidHandleData()\n    {\n        $valid_requests = array(\n            array(\n                'data' => array(\n                    \"\\x81\\xad\\x2e\\xab\\x82\\xac\\x6f\\xfe\\xd6\\xe4\\x14\\x8b\\xf9\\x8c\\x0c\"\n                    .\"\\xde\\xf1\\xc9\\x5c\\xc5\\xe3\\xc1\\x4b\\x89\\xb8\\x8c\\x0c\\xcd\\xed\\xc3\"\n                    .\"\\x0c\\x87\\xa2\\x8e\\x5e\\xca\\xf1\\xdf\\x59\\xc4\\xf0\\xc8\\x0c\\x91\\xa2\"\n                    .\"\\x8e\\x4c\\xca\\xf0\\x8e\\x53\\x81\\xad\\xd4\\xfd\\x81\\xfe\\x95\\xa8\\xd5\"\n                    .\"\\xb6\\xee\\xdd\\xfa\\xde\\xf6\\x88\\xf2\\x9b\\xa6\\x93\\xe0\\x93\\xb1\\xdf\"\n                    .\"\\xbb\\xde\\xf6\\x9b\\xee\\x91\\xf6\\xd1\\xa1\\xdc\\xa4\\x9c\\xf2\\x8d\\xa3\"\n                    .\"\\x92\\xf3\\x9a\\xf6\\xc7\\xa1\\xdc\\xb6\\x9c\\xf3\\xdc\\xa9\\x81\\x80\\x8e\"\n                    .\"\\x12\\xcd\\x8e\\x81\\x8c\\xf6\\x8a\\xf0\\xee\\x9a\\xeb\\x83\\x9a\\xd6\\xe7\"\n                    .\"\\x95\\x9d\\x85\\xeb\\x97\\x8b\" // Four text frames\n                ),\n                'counts' => array(\n                    'onData' => 4\n                )\n            ),\n            array(\n                'data' => array(\n                    \"\\x88\\x80\\xdc\\x8e\\xa2\\xc5\" // Close frame\n                ),\n                'counts' => array(\n                    'removeConnection' => 1\n                )\n            )\n        );\n\n        $data = array();\n\n        $handshakes = $this->getValidHandshakeData();\n\n        foreach ($handshakes as $handshake) {\n            foreach ($valid_requests as $handle_args) {\n                $arguments = $handshake;\n                $arguments[] = $handle_args['data'];\n                $arguments[] = $handle_args['counts'];\n\n                $data[] = $arguments;\n            }\n        }\n\n        return $data;\n    }\n\n    /**\n     * Data provider\n     */\n    public function getValidHandshakeData()\n    {\n        return array(\n            array(\n                '/chat',\n\"GET /chat HTTP/1.1\\r\nHost: server.example.com\\r\nUpgrade: websocket\\r\nConnection: Upgrade\\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\nOrigin: http://example.com\\r\nSec-WebSocket-Version: 13\\r\\n\\r\\n\"\n            )\n        );\n    }\n\n    /**\n     * Data provider\n     */\n    public function getWrongPathHandshakeData()\n    {\n        return array(\n            array(\n                '/foobar',\n\"GET /chat HTTP/1.1\\r\nHost: server.example.com\\r\nUpgrade: websocket\\r\nConnection: Upgrade\\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\nOrigin: http://example.com\\r\nSec-WebSocket-Version: 13\\r\\n\\r\\n\"\n            ),\n        );\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Frame;\n\nuse Wrench\\Frame\\HybiFrame;\nuse Wrench\\Tests\\Test;\n\nclass BadSubclassFrame extends HybiFrame\n{\n    protected $payload = 'asdmlasdkm';\n    protected $buffer = false;\n}\n\nclass BadSubclassFrameTest extends Test\n{\n    /**\n     * @expectedException Wrench\\Exception\\FrameException\n     */\n    public function testInvalidFrameBuffer()\n    {\n        $frame = new BadSubclassFrame();\n        $frame->getFrameBuffer();\n    }\n\n    protected function getClass()\n    {\n        return 'Wrench\\Tests\\Frame\\BadSubclassFrame';\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Tests/Frame/FrameTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Frame;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Frame\\Frame;\nuse Wrench\\Tests\\Test;\nuse \\Exception;\n\n/**\n * Frame test\n */\nabstract class FrameTest extends Test\n{\n    /**\n     * A fresh instance of the class being tested\n     *\n     * @var Frame\n     */\n    protected $frame;\n\n    /**\n     * @see PHPUnit_Framework_TestCase::setUp()\n     */\n    public function setUp()\n    {\n        parent::setUp();\n        $this->frame = $this->getNewFrame();\n    }\n\n    protected function getNewFrame()\n    {\n        $class = $this->getClass();\n        return new $class();\n    }\n\n    /**\n     * @see PHPUnit_Framework_TestCase::tearDown()\n     */\n    protected function tearDown()\n    {\n        parent::tearDown();\n        unset($this->frame);\n    }\n\n    /**\n     * @param string $payload\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testBijection($type, $payload, $masked)\n    {\n        // Encode the payload\n        $this->frame->encode($payload, $type, $masked);\n\n        // Get the resulting buffer\n        $buffer = $this->frame->getFrameBuffer();\n        $this->assertTrue((boolean)$buffer, 'Got raw frame buffer');\n\n        // And feed it back into a new frame\n        $frame = $this->getNewFrame();\n        $frame->receiveData($buffer);\n\n        // Check the properties of the new frame against the old, all match\n        $this->assertEquals(\n            $this->frame->getType(),\n            $frame->getType(),\n            'Types match after encode -> receiveData'\n        );\n\n        $this->assertEquals(\n            $this->frame->getFramePayload(),\n            $frame->getFramePayload(),\n            'Payloads match after encode -> receiveData'\n        );\n\n        // Masking key should not be different, because we read the buffer in directly\n        $this->assertEquals(\n            $this->frame->getFrameBuffer(),\n            $frame->getFrameBuffer(),\n            'Raw buffers match too'\n        );\n\n        // This time, we create a new frame and read the data in with encode\n        $frame = $this->getNewFrame();\n        $frame->encode($this->frame->getFramePayload(), $type, $masked);\n\n        // These still match\n        $this->assertEquals(\n            $this->frame->getType(),\n            $frame->getType(),\n            'Types match after encode -> receiveData -> encode'\n        );\n\n        $this->assertEquals(\n            $this->frame->getFramePayload(),\n            $frame->getFramePayload(),\n            'Payloads match after encode -> receiveData -> encode'\n        );\n\n        // But the masking key should be different, thus, so are the buffers\n        if ($masked) {\n            $this->assertNotEquals(\n                $this->frame->getFrameBuffer(),\n                $frame->getFrameBuffer(),\n                'Raw buffers don\\'t match because of masking'\n            );\n        } else {\n            $this->assertEquals(\n                $this->frame->getFramePayload(),\n                $frame->getFramePayload(),\n                'Payloads match after encode -> receiveData -> encode'\n            );\n        }\n    }\n\n    /**\n     * @param string $payload\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testEncodeTypeReflection($type, $payload, $masked)\n    {\n        $this->frame->encode($payload, $type);\n        $this->assertEquals(Protocol::TYPE_TEXT, $this->frame->getType(), 'Encode retains type information');\n    }\n\n    /**\n     * @param string $payload\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testEncodeLengthReflection($type, $payload, $masked)\n    {\n        $this->frame->encode($payload, $type);\n        $this->assertEquals(strlen($payload), $this->frame->getLength(), 'Encode does not alter payload length');\n    }\n\n    /**\n     * @param string $payload\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testEncodePayloadReflection($type, $payload, $masked)\n    {\n        $this->frame->encode($payload, $type, $masked);\n        $this->assertEquals($payload, $this->frame->getFramePayload(), 'Encode retains payload information');\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<string>\n     */\n    public function getValidEncodePayloads()\n    {\n        return array(\n            array(\n                Protocol::TYPE_TEXT,\n                \"123456\\x007890!@#$%^&*()qwe\\trtyuiopQWERTYUIOPasdfghjklASFGH\\n\n                JKLzxcvbnmZXCVBNM,./<>?;[]{}-=_+\\|'asdad0x11\\aasdassasdasasdsd\",\n                true\n            ),\n            array(\n                Protocol::TYPE_TEXT,\n                pack('CCCCCCC', 0x00, 0x01, 0x02, 0x03, 0x04, 0xff, 0xf0),\n                true\n            ),\n            array(Protocol::TYPE_TEXT, ' ', true)\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Frame/HybiFrameTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Frame;\n\nuse Wrench\\Frame\\HybiFrame;\nuse Wrench\\Tests\\Frame\\FrameTest;\n\nclass HybiFrameTest extends FrameTest\n{\n    protected function getClass()\n    {\n        return 'Wrench\\Frame\\HybiFrame';\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Listener/ListenerTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Listener;\n\nuse Wrench\\Tests\\Test;\n\n/**\n * Payload test\n */\nabstract class ListenerTest extends Test\n{\n    /**\n     * @depends testConstructor\n     */\n    public function testListen($instance)\n    {\n        $server = $this->getMock('Wrench\\Server', array(), array(), '', false);\n\n        $instance->listen($server);\n    }\n\n    abstract public function testConstructor();\n}"
  },
  {
    "path": "lib/Wrench/Tests/Listener/OriginPolicyTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Listener;\n\nuse Wrench\\Listener\\RateLimiter;\nuse Wrench\\Tests\\Listener\\ListenerTest;\n\nclass OriginPolicyTest extends ListenerTest\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    public function getClass()\n    {\n        return 'Wrench\\Listener\\OriginPolicy';\n    }\n\n    /**\n     * @see Wrench\\Tests\\Listener.ListenerTest::testConstructor()\n     */\n    public function testConstructor()\n    {\n        $instance = $this->getInstance(array());\n        $this->assertInstanceOfClass($instance, 'No constructor arguments');\n        return $instance;\n    }\n\n    /**\n     * @dataProvider getValidArguments\n     * @param array $allowed\n     * @param string $domain\n     */\n    public function testValidAllowed($allowed, $domain)\n    {\n        $instance = $this->getInstance($allowed);\n        $this->assertTrue($instance->isAllowed($domain));\n    }\n\n    /**\n     * @dataProvider getValidArguments\n     * @param array $allowed\n     * @param string $domain\n     */\n    public function testValidHandshake($allowed, $domain)\n    {\n        $instance = $this->getInstance($allowed);\n\n        $connection = $this->getMock('Wrench\\Connection', array(), array(), '', false);\n\n        $connection\n            ->expects($this->never())\n            ->method('close');\n\n        $instance->onHandshakeRequest($connection, '/', $domain, 'abc', array());\n    }\n\n    /**\n     * @dataProvider getInvalidArguments\n     * @param array $allowed\n     * @param string $bad_domain\n     */\n    public function testInvalidAllowed($allowed, $bad_domain)\n    {\n        $instance = $this->getInstance($allowed);\n        $this->assertFalse($instance->isAllowed($bad_domain));\n    }\n\n    /**\n     * @dataProvider getInvalidArguments\n     * @param array $allowed\n     * @param string $domain\n     */\n    public function testInvalidHandshake($allowed, $bad_domain)\n    {\n        $instance = $this->getInstance($allowed);\n\n        $connection = $this->getMock('Wrench\\Connection', array(), array(), '', false);\n\n        $connection\n            ->expects($this->once())\n            ->method('close');\n\n        $instance->onHandshakeRequest($connection, '/', $bad_domain, 'abc', array());\n    }\n\n    /**\n     * Data provider\n     */\n    public function getValidArguments()\n    {\n        return array(\n            array(array('localhost'), 'http://localhost'),\n            array(array('foobar.com'), 'https://foobar.com'),\n            array(array('https://foobar.com'), 'https://foobar.com')\n        );\n    }\n\n    /**\n     * Data provider\n     */\n    public function getInvalidArguments()\n    {\n        return array(\n            array(array('localhost'), 'localdomain'),\n            array(array('foobar.com'), 'foobar.org'),\n            array(array('https://foobar.com'), 'http://foobar.com'),\n            array(array('http://foobar.com'), 'foobar.com')\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Listener/RateLimiterTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Listener;\n\nuse Wrench\\Listener\\RateLimiter;\nuse Wrench\\Tests\\Listener\\ListenerTest;\n\nclass RateLimiterTest extends ListenerTest\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    public function getClass()\n    {\n        return 'Wrench\\Listener\\RateLimiter';\n    }\n\n    /**\n     * @see Wrench\\Tests\\Listener.ListenerTest::testConstructor()\n     */\n    public function testConstructor()\n    {\n        $instance = $this->getInstance();\n        $this->assertInstanceOfClass($instance, 'No constructor arguments');\n        return $instance;\n    }\n\n    public function testOnSocketConnect()\n    {\n        $this->getInstance()->onSocketConnect(null, $this->getConnection());\n    }\n\n    public function testOnSocketDisconnect()\n    {\n        $this->getInstance()->onSocketDisconnect(null, $this->getConnection());\n    }\n\n    public function testOnClientData()\n    {\n        $this->getInstance()->onClientData(null, $this->getConnection());\n    }\n\n    protected function getConnection()\n    {\n        $connection = $this->getMock('Wrench\\Connection', array(), array(), '', false);\n\n        $connection\n            ->expects($this->any())\n            ->method('getIp')\n            ->will($this->returnValue('127.0.0.1'));\n\n        $connection\n            ->expects($this->any())\n            ->method('getId')\n            ->will($this->returnValue('abcdef01234567890'));\n\n        $manager = $this->getMock('Wrench\\ConnectionManager', array(), array(), '', false);\n        $manager->expects($this->any())->method('count')->will($this->returnValue(5));\n\n        $connection\n            ->expects($this->any())\n            ->method('getConnectionManager')\n            ->will($this->returnValue($manager));\n\n        return $connection;\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Payload/HybiPayloadTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Protocol;\n\nuse Wrench\\Payload\\HybiPayload;\nuse Wrench\\Tests\\Payload\\PayloadTest;\n\nclass HybiPayloadTest extends PayloadTest\n{\n    protected function getClass()\n    {\n        return 'Wrench\\Payload\\HybiPayload';\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Payload/PayloadTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Payload;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Payload\\Payload;\nuse Wrench\\Tests\\Test;\nuse \\Exception;\n\n/**\n * Payload test\n */\nabstract class PayloadTest extends Test\n{\n    /**\n     * A fresh instance of the class being tested\n     *\n     * @var Payload\n     */\n    protected $payload;\n\n    /**\n     * @see PHPUnit_Payloadwork_TestCase::setUp()\n     */\n    public function setUp()\n    {\n        parent::setUp();\n\n        $this->payload = $this->getInstance();\n    }\n\n    /**\n     * Tests the constructor\n     */\n    public function testConstructor()\n    {\n        $this->assertInstanceOfClass($this->getInstance());\n    }\n\n    /**\n     * @param string $payload\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testBijection($type, $payload)\n    {\n        // Encode the payload\n        $this->payload->encode($payload, $type);\n\n        // Create a new payload and read the data in with encode\n        $payload = $this->getInstance();\n        $payload->encode($this->payload->getPayload(), $type);\n\n        // These still match\n        $this->assertEquals(\n            $this->payload->getType(),\n            $payload->getType(),\n            'Types match after encode -> receiveData'\n        );\n\n        $this->assertEquals(\n            $this->payload->getPayload(),\n            $payload->getPayload(),\n            'Payloads match after encode -> receiveData'\n        );\n    }\n\n    /**\n     * @param string $payload\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testEncodeTypeReflection($type, $payload)\n    {\n        $this->payload->encode($payload, Protocol::TYPE_TEXT);\n        $this->assertEquals(Protocol::TYPE_TEXT, $this->payload->getType(), 'Encode retains type information');\n    }\n\n    /**\n     * @param string $payload\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testEncodePayloadReflection($type, $payload)\n    {\n        $this->payload->encode($payload, Protocol::TYPE_TEXT);\n        $this->assertEquals($payload, $this->payload->getPayload(), 'Encode retains payload information');\n    }\n\n    /**\n     * Tests sending to a socket\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testSendToSocket($type, $payload)\n    {\n        $successfulSocket = $this->getMock('Wrench\\Socket\\ClientSocket', array(), array('wss://localhost:8000'));\n        $failedSocket = clone $successfulSocket;\n\n        $successfulSocket->expects($this->any())\n                ->method('send')\n                ->will($this->returnValue(true));\n\n        $failedSocket->expects($this->any())\n                ->method('send')\n                ->will($this->returnValue(false));\n\n        $this->payload->encode($payload, $type);\n\n        $this->assertTrue($this->payload->sendToSocket($successfulSocket));\n        $this->assertFalse($this->payload->sendToSocket($failedSocket));\n    }\n\n    /**\n     * Tests receiving data\n     * @dataProvider getValidEncodePayloads\n     */\n    public function testReceieveData($type, $payload)\n    {\n        $payload = $this->getInstance();\n        $payload->receiveData($payload);\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<string>\n     */\n    public function getValidEncodePayloads()\n    {\n        return array(\n            array(\n                Protocol::TYPE_TEXT,\n                \"123456\\x007890!@#$%^&*()qwe\\trtyuiopQWERTYUIOPasdfghjklASFGH\\n\n                JKLzxcvbnmZXCVBNM,./<>?;[]{}-=_+\\|'asdad0x11\\aasdassasdasasdsd\"\n            ),\n            array(\n                Protocol::TYPE_TEXT,\n                pack('CCCCCCC', 0x00, 0x01, 0x02, 0x03, 0x04, 0xff, 0xf0)\n            ),\n            array(Protocol::TYPE_TEXT, ' ')\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Protocol/ProtocolTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Protocol;\n\nuse Wrench\\Tests\\Test;\nuse \\Exception;\n\nabstract class ProtocolTest extends Test\n{\n    /**\n     * @see PHPUnit_Framework_TestCase::setUp()\n     */\n    public function setUp()\n    {\n        parent::setUp();\n    }\n\n    /**\n     * @dataProvider getValidHandshakeRequests\n     */\n    public function testValidatHandshakeRequestValid($request)\n    {\n        try {\n            list($path, $origin, $key, $extensions, $protocol) = $this->getInstance()->validateRequestHandshake($request);\n\n            $this->assertEquals('/chat', $path);\n            $this->assertEquals('http://example.com', $origin);\n            $this->assertEquals('dGhlIHNhbXBsZSBub25jZQ==', $key);\n            $this->assertTrue(is_array($extensions), 'Extensions returned as array');\n            $this->assertEquals(array('x-test', 'x-test2'), $extensions, 'Extensions match');\n            $this->assertEquals('chat, superchat', $protocol);\n        } catch (Exception $e) {\n            $this->fail($e);\n        }\n    }\n\n    /**\n     * @dataProvider getValidHandshakeResponses\n     */\n    public function testValidateHandshakeResponseValid($response, $key)\n    {\n        try {\n            $valid = $this->getInstance()->validateResponseHandshake($response, $key);\n            $this->assertTrue(is_bool($valid), 'Validation return value is boolean');\n            $this->assertTrue($valid, 'Handshake response validates');\n        } catch (Exception $e) {\n            $this->fail('Validated valid response handshake as invalid');\n        }\n    }\n\n    /**\n     * @dataProvider getValidHandshakeResponses\n     */\n    public function testGetResponseHandsake($unused, $key)\n    {\n        try {\n            $response = $this->getInstance()->getResponseHandshake($key);\n            $this->assertHttpResponse($response);\n        } catch (Exception $e) {\n            $this->fail('Unable to get handshake response: ' . $e);\n        }\n    }\n\n    /**\n     * Asserts the string response is an HTTP response\n     *\n     * @param string $response\n     */\n    protected function assertHttpResponse($response, $message = '')\n    {\n        $this->assertStringStartsWith('HTTP', $response, $message . ' - response starts well');\n        $this->assertStringEndsWith(\"\\r\\n\", $response, $message . ' - response ends well');\n    }\n\n    public function testGetVersion()\n    {\n        $version = $this->getInstance()->getVersion();\n        $this->assertTrue(is_int($version));\n    }\n\n    public function testGetResponseError()\n    {\n        $response = $this->getInstance()->getResponseError(400);\n        $this->assertHttpResponse($response, 'Code as int');\n\n        $response = $this->getInstance()->getResponseError(new Exception('Some message', 500));\n        $this->assertHttpResponse($response, 'Code in Exception');\n\n        $response = $this->getInstance()->getResponseError(888);\n        $this->assertHttpResponse($response, 'Invalid code produces unimplemented response');\n    }\n\n    /**\n     * @dataProvider getValidOriginUris\n     */\n    public function testValidateOriginUriValid($uri)\n    {\n        try {\n            $this->getInstance()->validateOriginUri($uri);\n        } catch (\\Exception $e) {\n            $this->fail('Valid URI validated as invalid: ' . $e);\n        }\n    }\n\n    /**\n     * @dataProvider getInvalidOriginUris\n     * @expectedException InvalidArgumentException\n     */\n    public function testValidateOriginUriInvalid($uri)\n    {\n        $this->getInstance()->validateOriginUri($uri);\n    }\n\n    public function getValidOriginUris()\n    {\n        return array(\n            array('http://www.example.org'),\n            array('http://www.example.com/some/page'),\n            array('https://localhost/')\n        );\n    }\n\n    public function getInvalidOriginUris()\n    {\n        return array(\n            array(false),\n            array(true),\n            array(''),\n            array('blah')\n        );\n    }\n\n    public function getValidHandshakeRequests()\n    {\n        $cases = array();\n\n\n        $cases[] = array(\"GET /chat HTTP/1.1\\r\nHost: server.example.com\\r\nUpgrade: websocket\\r\nConnection: Upgrade\\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\nOrigin: http://example.com\\r\nSec-WebSocket-Extensions: x-test\\r\nSec-WebSocket-Extensions: x-test2\\r\nSec-WebSocket-Protocol: chat, superchat\\r\nSec-WebSocket-Version: 13\\r\n\\r\\n\");\n\n        $cases[] = array(\"GET /chat HTTP/1.1\\r\nHost: server.example.com\\r\nUpgrade: Websocket\\r\nConnection: Upgrade\\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\nOrigin: http://example.com\\r\nSec-WebSocket-Extensions: x-test\\r\nSec-WebSocket-Extensions: x-test2\\r\nSec-WebSocket-Protocol: chat, superchat\\r\nSec-WebSocket-Version: 13\\r\n\\r\\n\");\n\n        return $cases;\n    }\n\n    public function getValidHandshakeResponses()\n    {\n       $cases = array();\n\n       for ($i = 10; $i > 0; $i--) {\n           $key = sha1(time() . uniqid('', true));\n           $response = \"Sec-WebSocket-Accept: \"\n               . base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true))\n               . \"\\r\\n\\r\\n\";\n\n           $cases[] = array($response, $key);\n       }\n\n       return $cases;\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Protocol;\n\nuse Wrench\\Protocol\\Rfc6455Protocol;\nuse Wrench\\Tests\\Protocol\\ProtocolTest;\n\nclass Rfc6455ProtocolTest extends ProtocolTest\n{\n    protected function getClass()\n    {\n        return 'Wrench\\Protocol\\Rfc6455Protocol';\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/ServerTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests;\n\nuse Wrench\\Server;\nuse Wrench\\Tests\\Test;\nuse Wrench\\Socket;\n\nuse \\InvalidArgumentException;\nuse \\PHPUnit_Framework_Error;\n\n/**\n * Tests the Server class\n */\nclass ServerTest extends Test\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    protected function getClass()\n    {\n        return 'Wrench\\Server';\n    }\n\n    /**\n     * Tests the constructor\n     *\n     * @param string $url\n     * @param array $options\n     * @dataProvider getValidConstructorArguments\n     */\n    public function testConstructor($url, array $options = array())\n    {\n        $this->assertInstanceOfClass(\n            $this->getInstance($url, $options),\n            'Valid constructor arguments'\n        );\n    }\n\n    /**\n     * Tests logging\n     */\n    public function testLogging()\n    {\n        $test = $this;\n        $logged = false;\n\n        $server = $this->getInstance('ws://localhost:8000', array(\n            'logger' => function ($message, $priority) use ($test, &$logged) {\n                $test->assertTrue(is_string($message), 'Log had a string message');\n                $test->assertTrue(is_string($priority), 'Log had a string priority');\n                $logged = true;\n            }\n        ));\n\n        $this->assertTrue($logged, 'The log callback was hit');\n    }\n\n    /**\n     * Data provider\n     *\n     * @return array<array<mixed>>\n     */\n    public function getValidConstructorArguments()\n    {\n        return array(\n            array(\n                'ws://localhost:8000',\n                array('logger' => array($this, 'log'))\n            ),\n            array(\n                'ws://localhost',\n                array('logger' => array($this, 'log'))\n            )\n        );\n    }\n\n}"
  },
  {
    "path": "lib/Wrench/Tests/ServerTestHelper.php",
    "content": "<?php\n\nnamespace Wrench\\Tests;\n\n/**\n * In conjunction with server.php, provides a listening server\n * against which tests can be run.\n */\nclass ServerTestHelper\n{\n    const TEST_SERVER_PORT_MIN = 16666;\n    const TEST_SERVER_PORT_MAX = 52222;\n\n    public static $nextPort = null;\n\n    protected $port = null;\n    protected $process = null;\n    protected $pipes = array();\n\n    /**\n     * Gets the next available port number to start a server on\n     */\n    public static function getNextPort()\n    {\n        if (self::$nextPort === null) {\n            self::$nextPort = mt_rand(self::TEST_SERVER_PORT_MIN, self::TEST_SERVER_PORT_MAX);\n        }\n        return self::$nextPort++;\n    }\n\n    /**\n     * Destructor\n     */\n    public function __destruct()\n    {\n        $this->tearDown();\n    }\n\n    /**\n     * @return string\n     */\n    public function getConnectionString()\n    {\n        return 'ws://localhost:' . $this->port;\n    }\n\n    /**\n     * @return string\n     */\n    public function getEchoConnectionString()\n    {\n        return $this->getConnectionString() . '/echo';\n    }\n\n    /**\n     * Sets up the server process and sleeps for a few seconds while\n     * it wakes up\n     */\n    public function setUp()\n    {\n        $this->port = self::getNextPort();\n\n        $this->process = proc_open(\n            $this->getCommand(),\n            array(\n                0 => array('file', '/dev/null', 'r'),\n                1 => array('file', __DIR__ . '/../../../build/server.log', 'a+'),\n                2 => array('file', __DIR__ . '/../../../build/server.err.log', 'a+')\n            ),\n            $this->pipes,\n            __DIR__ . '../'\n        );\n\n        sleep(3);\n    }\n\n    /**\n     * Tears down the server process\n     *\n     * This method *must* be called\n     */\n    public function tearDown()\n    {\n        if ($this->process) {\n            foreach ($this->pipes as &$pipe) {\n                fclose($pipe);\n            }\n            $this->pipes = null;\n\n            // Sigh\n            $status = proc_get_status($this->process);\n\n            if ($status && isset($status['pid']) && $status['pid']) {\n                // More sigh, this is the pid of the parent sh process, we want\n                //  to terminate the server directly\n                $this->log('Command: /bin/ps -ao pid,ppid | /usr/bin/col | /usr/bin/tail -n +2 | /bin/grep \\'  ' . $status['pid'] . \"'\", 'info');\n                exec('/bin/ps -ao pid,ppid | /usr/bin/col | /usr/bin/tail -n +2 | /bin/grep \\' ' . $status['pid'] . \"'\", $processes, $return);\n\n                if ($return === 0) {\n                    foreach ($processes as $process) {\n                        list($pid, $ppid) = explode(' ', str_replace('  ', ' ', $process));\n                        if ($pid) {\n                            $this->log('Killing ' . $pid, 'info');\n                            exec('/bin/kill ' . $pid . ' > /dev/null 2>&1');\n                        }\n                    }\n                } else {\n                    $this->log('Unable to find child processes', 'warning');\n                }\n\n                sleep(1);\n\n                $this->log('Killing ' . $status['pid'], 'info');\n                exec('/bin/kill ' . $status['pid'] . ' > /dev/null 2>&1');\n\n                sleep(1);\n            }\n\n            proc_close($this->process);\n            $this->process = null;\n        }\n    }\n\n    /**\n     * Gets the server command\n     *\n     * @return string\n     */\n    protected function getCommand()\n    {\n        return sprintf('/usr/bin/env php %s/server.php %d', __DIR__, $this->port);\n    }\n\n    /**\n     * Logs a message\n     *\n     * @param string $message\n     * @param string $priority\n     */\n    public function log($message, $priority = 'info')\n    {\n        //echo $message . \"\\n\";\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Socket/ClientSocketTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Socket;\n\nuse Wrench\\Protocol\\Rfc6455Protocol;\nuse Wrench\\Socket\\ClientSocket;\nuse Wrench\\Tests\\ServerTestHelper;\nuse \\Exception;\nuse \\stdClass;\n\nclass ClientSocketTest extends UriSocketTest\n{\n    /**\n     * @see Wrench\\Tests.Test::getClass()\n     */\n    public function getClass()\n    {\n        return 'Wrench\\Socket\\ClientSocket';\n    }\n\n    /**\n     * Overriden to use with the depends annotation\n     *\n     * @see Wrench\\Tests\\Socket.UriSocketTest::testConstructor()\n     */\n    public function testConstructor()\n    {\n        $instance = parent::testConstructor();\n\n        $socket = null;\n\n        $this->assertInstanceOfClass(\n            new ClientSocket('ws://localhost/'),\n            'ws:// scheme, default port'\n        );\n\n        $this->assertInstanceOfClass(\n            new ClientSocket('ws://localhost/some-arbitrary-path'),\n            'with path'\n        );\n\n        $this->assertInstanceOfClass(\n            new ClientSocket('wss://localhost/test', array()),\n            'empty options'\n        );\n\n        $this->assertInstanceOfClass(\n            new ClientSocket('ws://localhost:8000/foo'),\n            'specified port'\n        );\n\n        return $instance;\n    }\n\n    public function testOptions()\n    {\n        $socket = null;\n\n        $this->assertInstanceOfClass(\n            $socket = new ClientSocket(\n                'ws://localhost:8000/foo', array(\n                    'timeout_connect' => 10\n                )\n            ),\n            'connect timeout'\n        );\n\n        $this->assertInstanceOfClass(\n            $socket = new ClientSocket(\n                'ws://localhost:8000/foo', array(\n                    'timeout_socket' => 10\n                )\n            ),\n            'socket timeout'\n        );\n\n        $this->assertInstanceOfClass(\n            $socket = new ClientSocket(\n                'ws://localhost:8000/foo', array(\n                    'protocol' => new Rfc6455Protocol()\n                )\n            ),\n            'protocol'\n        );\n    }\n\n      /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testProtocolTypeError()\n    {\n        $socket = new ClientSocket(\n            'ws://localhost:8000/foo', array(\n                'protocol' => new stdClass()\n            )\n        );\n    }\n\n    /**\n     * @expectedException PHPUnit_Framework_Error\n     */\n    public function testConstructorUriUnspecified()\n    {\n        $w = new ClientSocket();\n    }\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testConstructorUriEmpty()\n    {\n        $w = new ClientSocket(null);\n    }\n\n\n    /**\n     * @expectedException InvalidArgumentException\n     */\n    public function testConstructorUriInvalid()\n    {\n        $w = new ClientSocket('Bad argument');\n    }\n\n\n    /**\n     * @depends testConstructor\n     * @expectedException Wrench\\Exception\\SocketException\n     */\n    public function testSendTooEarly($instance)\n    {\n        $instance->send('foo');\n    }\n\n    /**\n     * Test the connect, send, receive method\n     */\n    public function testConnect()\n    {\n        try {\n            $helper = new ServerTestHelper();\n            $helper->setUp();\n\n            $instance = $this->getInstance($helper->getConnectionString());\n            $success = $instance->connect();\n\n            $this->assertTrue($success, 'Client socket can connect to test server');\n\n            $sent = $instance->send(\"GET /echo HTTP/1.1\\r\nHost: localhost\\r\nUpgrade: websocket\\r\nConnection: Upgrade\\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\nOrigin: http://localhost\\r\nSec-WebSocket-Version: 13\\r\\n\\r\\n\");\n            $this->assertNotEquals(false, $sent, 'Client socket can send to test server');\n\n            $response = $instance->receive();\n            $this->assertStringStartsWith('HTTP', $response, 'Response looks like HTTP handshake response');\n\n        } catch (\\Exception $e) {\n            $helper->tearDown();\n            throw $e;\n        }\n\n        $helper->tearDown();\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Socket/ServerClientSocketTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Socket;\n\nuse \\Exception;\n\nclass ServerClientSocketTest extends SocketTest\n{\n    public function getClass()\n    {\n        return 'Wrench\\Socket\\ServerClientSocket';\n    }\n\n    /**\n     * By default, the socket has not required arguments\n     */\n    public function testConstructor()\n    {\n        $resource = null;\n        $instance = $this->getInstance($resource);\n        $this->assertInstanceOfClass($instance);\n        return $instance;\n    }\n\n    /**\n     * @expectedException Wrench\\Exception\\SocketException\n     * @depends testConstructor\n     */\n    public function testGetIpTooSoon($instance)\n    {\n        $instance->getIp();\n    }\n\n    /**\n     * @expectedException Wrench\\Exception\\SocketException\n     * @depends testConstructor\n     */\n    public function testGetPortTooSoon($instance)\n    {\n        $instance->getPort();\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Socket/ServerSocketTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Socket;\n\nuse \\Exception;\n\nclass ServerSocketTest extends UriSocketTest\n{\n    public function getClass()\n    {\n        return 'Wrench\\Socket\\ServerSocket';\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Socket/SocketTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Socket;\n\nuse Wrench\\Tests\\Test;\nuse \\Exception;\nuse Wrench\\Socket\\Socket;\n\nabstract class SocketTest extends Test\n{\n    /**\n     * Require constructor testing\n     */\n    abstract public function testConstructor();\n\n    /**\n     * @depends testConstructor\n     */\n    public function testIsConnected($instance)\n    {\n        $connected = $instance->isConnected();\n        $this->assertTrue(is_bool($connected), 'isConnected returns boolean');\n        $this->assertFalse($connected);\n    }\n\n    /**\n     * @dataProvider getValidNames\n     * @param string $name\n     */\n    public function testGetNamePart($name, $ip, $port)\n    {\n        $this->assertEquals($ip, Socket::getNamePart($name, Socket::NAME_PART_IP), 'splits ip correctly');\n        $this->assertEquals($port, Socket::getNamePart($name, Socket::NAME_PART_PORT), 'splits port correctly');\n    }\n\n    /**\n     * Data provider\n     */\n    public function getValidNames()\n    {\n        return array(\n            array('127.0.0.1:52339', '127.0.0.1', '52339'),\n            array('255.255.255.255:1025', '255.255.255.255', '1025'),\n            array('::1:56670', '::1', '56670')\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Socket/UriSocketTest.php",
    "content": "<?php\n\nnamespace Wrench\\Tests\\Socket;\n\nuse \\Exception;\n\nabstract class UriSocketTest extends SocketTest\n{\n    /**\n     * By default, the socket has not required arguments\n     */\n    public function testConstructor()\n    {\n        $instance = $this->getInstance('ws://localhost:8000');\n        $this->assertInstanceOfClass($instance);\n        return $instance;\n    }\n\n    /**\n     * @dataProvider getInvalidConstructorArguments\n     * @expectedException InvalidArgumentException\n     */\n    public function testInvalidConstructor($uri)\n    {\n        $this->getInstance($uri);\n    }\n\n    /**\n     * @depends testConstructor\n     */\n    public function testGetIp($instance)\n    {\n        $this->assertStringStartsWith('localhost', $instance->getIp(), 'Correct host');\n    }\n\n    /**\n     * @depends testConstructor\n     */\n    public function testGetPort($instance)\n    {\n        $this->assertEquals(8000, $instance->getPort(), 'Correct port');\n    }\n\n    /**\n     * Data provider\n     */\n    public function getInvalidConstructorArguments()\n    {\n        return array(\n            array(false),\n            array('http://www.google.com/'),\n            array('ws:///'),\n            array(':::::'),\n        );\n    }\n}"
  },
  {
    "path": "lib/Wrench/Tests/Test.php",
    "content": "<?php\n\nnamespace Wrench\\Tests;\n\nuse \\PHPUnit_Framework_TestCase;\nuse \\ReflectionClass;\n\n/**\n * Test base class\n */\nabstract class Test extends PHPUnit_Framework_TestCase\n{\n    /**\n     * Gets the class under test\n     *\n     * @return string\n     */\n    abstract protected function getClass();\n\n    /**\n     * Asserts that the given instance is of the class under test\n     *\n     * @param object $instance\n     * @param string $message Optional\n     */\n    public function assertInstanceOfClass($instance, $message = null)\n    {\n        $this->assertInstanceOf(\n            $this->getClass(),\n            $instance,\n            $message\n        );\n    }\n\n    /**\n     * Gets an instance of the class under test\n     *\n     * @param mixed Normal constructor arguments\n     * @magic This method accepts a variable number of arguments\n     * @return object Of type given by getClass()\n     */\n    public function getInstance(/* ... */)\n    {\n        $reflection = new ReflectionClass($this->getClass());\n        return $reflection->newInstanceArgs(func_get_args());\n    }\n\n    /**\n     * Logging function\n     *\n     * Passed into some classes under test as a callable\n     *\n     * @param string $message\n     * @param string $priority\n     * @return void\n     */\n    public function log($message, $priority = 'info')\n    {\n        // nothing\n    }\n}\n"
  },
  {
    "path": "lib/Wrench/Tests/bootstrap.php",
    "content": "<?php\n\n/**\n * Bootstrap file for the test suite\n */\n\n// Use SplClassLoader\nrequire_once(__DIR__ . '/../../SplClassLoader.php');\n\n$classLoader = new \\SplClassLoader('Wrench', __DIR__ . '/../..');\n$classLoader->register();"
  },
  {
    "path": "lib/Wrench/Tests/server.php",
    "content": "<?php\n\nrequire_once(__DIR__ . '/../../SplClassLoader.php');\n\nif ($argc != 2 || !$argv[1] || !is_numeric($argv[1]) || (int)$argv[1] <= 1024) {\n    throw new InvalidArgumentException('Invalid port number: supply as first argument');\n}\n\n$port = (int)$argv[1];\n\n$classLoader = new \\SplClassLoader('Wrench', __DIR__ . '/../..');\n$classLoader->register();\n\n$server = new Wrench\\Server('ws://localhost:' . $port);\n$server->registerApplication('echo', new Wrench\\Application\\EchoApplication());\n$server->run();"
  },
  {
    "path": "lib/Wrench/Util/Configurable.php",
    "content": "<?php\n\nnamespace Wrench\\Util;\n\nuse Wrench\\Protocol\\Protocol;\nuse Wrench\\Protocol\\Rfc6455Protocol;\nuse \\InvalidArgumentException;\n\n/**\n * Configurable base class\n */\nabstract class Configurable\n{\n    /**\n     * @var array\n     */\n    protected $options = array();\n\n    /**\n     * @var Protocol\n     */\n    protected $protocol;\n\n    /**\n     * Configurable constructor\n     *\n     * @param string $uri     WebSocket URI, e.g. ws://example.org:8000/chat\n     * @param array  $options (optional)\n     *   Options:\n     *     - protocol             => Wrench\\Protocol object, latest protocol\n     *                                 version used if not specified\n     */\n    public function __construct(\n        array $options = array()\n    ) {\n        $this->configure($options);\n        $this->configureProtocol();\n    }\n\n    /**\n     * Configures the options\n     *\n     * @param array $options\n     */\n    protected function configure(array $options)\n    {\n        $this->options = array_merge(array(\n            'protocol' => new Rfc6455Protocol()\n        ), $options);\n    }\n\n    /**\n     * Configures the protocol option\n     *\n     * @throws InvalidArgumentException\n     */\n    protected function configureProtocol()\n    {\n        $protocol = $this->options['protocol'];\n\n        if (!$protocol || !($protocol instanceof Protocol)) {\n            throw new InvalidArgumentException('Invalid protocol option');\n        }\n\n        $this->protocol = $protocol;\n    }\n}"
  },
  {
    "path": "lib/Wrench/Util/Ssl.php",
    "content": "<?php\n\nnamespace Wrench\\Util;\n\nclass Ssl\n{\n\t/**\n\t * Generates a new PEM File given the informations\n\t *\n\t * @param string $pem_file                 the path of the PEM file to create\n\t * @param string $pem_passphrase           the passphrase to protect the PEM\n     *                                             file or if you don't want to\n     *                                             use a passphrase\n\t * @param string $country_name             the country code of the new PEM file. e.g.: EN\n\t * @param string $state_or_province_name   the state or province name of the new PEM file\n\t * @param string $locality_name            the name of the locality\n\t * @param string $organisation_name        the name of the organisation. e.g.: MyCompany\n\t * @param string $organisational_unit_name the organisation unit name\n\t * @param string $commonName               the common name\n\t * @param string $email_address            the email address\n\t */\n\tpublic static function generatePemFile($pem_file, $pem_passphrase, $country_name, $state_or_province_name,\n\t\t$locality_name, $organization_name, $organizational_unit_name, $common_name, $email_address)\n\t{\n\t\t// Generate PEM file\n\t\t$dn = array(\n\t\t\t'countryName'            => $country_name,\n\t\t\t'stateOrProvinceName'    => $state_or_province_name,\n\t\t\t'localityName'           => $locality_name,\n\t\t\t'organizationName'       => $organization_name,\n\t\t\t'organizationalUnitName' => $organizational_unit_name,\n\t\t\t'commonName'             => $common_name,\n\t\t\t'emailAddress'           => $email_address\n\t\t);\n\n\t\t$privkey = openssl_pkey_new();\n\t\t$cert    = openssl_csr_new($dn, $privkey);\n\t\t$cert    = openssl_csr_sign($cert, null, $privkey, 365);\n\n\t\t$pem = array();\n\n\t\topenssl_x509_export($cert, $pem[0]);\n\n\t\tif ($pem_passphrase !== null) {\n\t\t\topenssl_pkey_export($privkey, $pem[1], $pem_passphrase);\n\t\t}\n\n\t\t$pem = implode($pem);\n\t\tfile_put_contents($pem_file, $pem);\n\t}\n}"
  },
  {
    "path": "phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<phpunit bootstrap=\"lib/Wrench/Tests/bootstrap.php\">\n\t<testsuites>\n\t\t<testsuite name=\"Default Testsuite\">\n\t\t\t<directory>lib/Wrench/Tests</directory>\n\t\t</testsuite>\n\t</testsuites>\n\t<filter>\n\t\t<blacklist>\n\t\t\t<file>lib/SplClassLoader.php</file>\n\t\t</blacklist>\n\t</filter>\n\t<logging>\n\t\t<log type=\"coverage-html\" target=\"build/report\" charset=\"UTF-8\"\n\t\t\tyui=\"true\" highlight=\"true\"\n\t\t\tlowUpperBound=\"35\" highLowerBound=\"70\"/>\n\t\t<log type=\"coverage-clover\" target=\"build/coverage.xml\"/>\n\t\t<log type=\"coverage-php\" target=\"build/coverage.serialized\"/>\n\t\t<log type=\"coverage-text\" target=\"php://stdout\" showUncoveredFiles=\"false\"/>\n\t\t<log type=\"junit\" target=\"build/junit.xml\" logIncompleteSkipped=\"false\"/>\n\t</logging>\n</phpunit>\n\n"
  }
]