Page MenuHomePhabricator

D11143.diff
No OneTemporary

D11143.diff

diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,6 @@
# User extensions
/src/extensions/*
+
+# NPM local packages
+/support/aphlict/server/node_modules/
diff --git a/externals/vegas/LICENSE b/externals/vegas/LICENSE
deleted file mode 100644
--- a/externals/vegas/LICENSE
+++ /dev/null
@@ -1,581 +0,0 @@
-Mozilla Public License 1.1 (MPL 1.1)
-
-1. Definitions.
-
- 1.0.1. "Commercial Use" means distribution or
- otherwise making the Covered Code available to a third
- party.
-
- 1.1. ''Contributor'' means each entity that creates or
- contributes to the creation of Modifications.
-
- 1.2. ''Contributor Version'' means the combination of
- the Original Code, prior Modifications used by
- a Contributor, and the Modifications made by that
- particular Contributor.
-
- 1.3. ''Covered Code'' means the Original Code or
- Modifications or the combination of the Original Code
- and Modifications, in each case including portions
- thereof.
-
- 1.4. ''Electronic Distribution Mechanism'' means a
- mechanism generally accepted in the software
- development community for the electronic transfer of
- data.
-
- 1.5. ''Executable'' means Covered Code in any form
- other than Source Code.
-
- 1.6. ''Initial Developer'' means the individual or
- entity identified as the Initial Developer in the
- Source Code notice required by Exhibit A.
-
- 1.7. ''Larger Work'' means a work which combines
- Covered Code or portions thereof with code not
- governed by the terms of this License.
-
- 1.8. ''License'' means this document.
-
- 1.8.1. "Licensable" means having the right to grant,
- to the maximum extent possible, whether at the time of
- the initial grant or subsequently acquired, any and
- all of the rights conveyed herein.
-
- 1.9. ''Modifications'' means any addition to or
- deletion from the substance or structure of either the
- Original Code or any previous Modifications. When
- Covered Code is released as a series of files, a
- Modification is:
-
- A. Any addition to or deletion from the contents
- of a file containing Original Code or previous
- Modifications.
-
- B. Any new file that contains any part of the
- Original Code or previous Modifications.
-
- 1.10. ''Original Code'' means Source Code of computer
- software code which is described in the Source Code
- notice required by Exhibit A as Original Code, and
- which, at the time of its release under this License
- is not already Covered Code governed by this License.
-
- 1.10.1. "Patent Claims" means any patent claim(s), now
- owned or hereafter acquired, including without
- limitation, method, process, and apparatus claims, in
- any patent Licensable by grantor.
-
- 1.11. ''Source Code'' means the preferred form of the
- Covered Code for making modifications to it, including
- all modules it contains, plus any associated interface
- definition files, scripts used to control compilation
- and installation of an Executable, or source code
- differential comparisons against either the Original
- Code or another well known, available Covered Code of
- the Contributor's choice. The Source Code can be in a
- compressed or archival form, provided the appropriate
- decompression or de-archiving software is widely
- available for no charge.
-
- 1.12. "You'' (or "Your") means an individual or a
- legal entity exercising rights under, and complying
- with all of the terms of, this License or a future
- version of this License issued under Section 6.1. For
- legal entities, "You'' includes any entity which
- controls, is controlled by, or is under common control
- with You. For purposes of this definition, "control''
- means (a) the power, direct or indirect, to cause the
- direction or management of such entity, whether by
- contract or otherwise, or (b) ownership of more than
- fifty percent (50%) of the outstanding shares or
- beneficial ownership of such entity.
-
-
-2. Source Code License.
-
- 2.1. The Initial Developer Grant.
- The Initial Developer hereby grants You a world-wide,
- royalty-free, non-exclusive license, subject to third
- party intellectual property claims:
- (a) under intellectual property rights (other
- than patent or trademark) Licensable by Initial
- Developer to use, reproduce, modify, display,
- perform, sublicense and distribute the Original
- Code (or portions thereof) with or without
- Modifications, and/or as part of a Larger Work;
- and
-
- (b) under Patents Claims infringed by the making,
- using or selling of Original Code, to make, have
- made, use, practice, sell, and offer for sale,
- and/or otherwise dispose of the Original Code (or
- portions thereof).
-
- (c) the licenses granted in this Section 2.1(a)
- and (b) are effective on the date Initial
- Developer first distributes Original Code under
- the terms of this License.
-
- (d) Notwithstanding Section 2.1(b) above, no
- patent license is granted: 1) for code that You
- delete from the Original Code; 2) separate from
- the Original Code; or 3) for infringements
- caused by: i) the modification of the Original
- Code or ii) the combination of the Original Code
- with other software or devices.
-
- 2.2. Contributor Grant.
- Subject to third party intellectual property claims,
- each Contributor hereby grants You a world-wide,
- royalty-free, non-exclusive license
-
- (a) under intellectual property rights (other
- than patent or trademark) Licensable by
- Contributor, to use, reproduce, modify, display,
- perform, sublicense and distribute the
- Modifications created by such Contributor (or
- portions thereof) either on an unmodified basis,
- with other Modifications, as Covered Code and/or
- as part of a Larger Work;
- and
-
- (b) under Patent Claims infringed by the making,
- using, or selling of Modifications made by that
- Contributor either alone and/or in combination
- with its Contributor Version (or portions of such
- combination), to make, use, sell, offer for sale,
- have made, and/or otherwise dispose of: 1)
- Modifications made by that Contributor (or
- portions thereof); and 2) the combination of
- Modifications made by that Contributor with its
- Contributor Version (or portions of such
- combination).
-
- (c) the licenses granted in Sections 2.2(a) and
- 2.2(b) are effective on the date Contributor
- first makes Commercial Use of the Covered Code.
-
- (d) Notwithstanding Section 2.2(b) above, no
- patent license is granted: 1) for any code that
- Contributor has deleted from the Contributor
- Version; 2) separate from the Contributor
- Version; 3) for infringements caused by: i)
- third party modifications of Contributor Version
- or ii) the combination of Modifications made by
- that Contributor with other software (except as
- part of the Contributor Version) or other
- devices; or 4) under Patent Claims infringed by
- Covered Code in the absence of Modifications made
- by that Contributor.
-
-
-3. Distribution Obligations.
-
- 3.1. Application of License.
- The Modifications which You create or to which You
- contribute are governed by the terms of this License,
- including without limitation Section 2.2. The Source
- Code version of Covered Code may be distributed only
- under the terms of this License or a future version of
- this License released under Section 6.1, and You must
- include a copy of this License with every copy of the
- Source Code You distribute. You may not offer or
- impose any terms on any Source Code version that
- alters or restricts the applicable version of this
- License or the recipients' rights hereunder. However,
- You may include an additional document offering the
- additional rights described in Section 3.5.
-
- 3.2. Availability of Source Code.
- Any Modification which You create or to which You
- contribute must be made available in Source Code form
- under the terms of this License either on the same
- media as an Executable version or via an accepted
- Electronic Distribution Mechanism to anyone to whom
- you made an Executable version available; and if made
- available via Electronic Distribution Mechanism, must
- remain available for at least twelve (12) months after
- the date it initially became available, or at least
- six (6) months after a subsequent version of that
- particular Modification has been made available to
- such recipients. You are responsible for ensuring that
- the Source Code version remains available even if the
- Electronic Distribution Mechanism is maintained by a
- third party.
-
- 3.3. Description of Modifications.
- You must cause all Covered Code to which You
- contribute to contain a file documenting the changes
- You made to create that Covered Code and the date of
- any change. You must include a prominent statement
- that the Modification is derived, directly or
- indirectly, from Original Code provided by the Initial
- Developer and including the name of the Initial
- Developer in (a) the Source Code, and (b) in any
- notice in an Executable version or related
- documentation in which You describe the origin or
- ownership of the Covered Code.
-
- 3.4. Intellectual Property Matters
- (a) Third Party Claims.
- If Contributor has knowledge that a license under
- a third party's intellectual property rights is
- required to exercise the rights granted by such
- Contributor under Sections 2.1 or 2.2,
- Contributor must include a text file with the
- Source Code distribution titled "LEGAL'' which
- describes the claim and the party making the
- claim in sufficient detail that a recipient will
- know whom to contact. If Contributor obtains such
- knowledge after the Modification is made
- available as described in Section 3.2,
- Contributor shall promptly modify the LEGAL file
- in all copies Contributor makes available
- thereafter and shall take other steps (such as
- notifying appropriate mailing lists or
- newsgroups) reasonably calculated to inform those
- who received the Covered Code that new knowledge
- has been obtained.
-
- (b) Contributor APIs.
- If Contributor's Modifications include an
- application programming interface and Contributor
- has knowledge of patent licenses which are
- reasonably necessary to implement that API,
- Contributor must also include this information in
- the LEGAL file.
-
- (c) Representations.
- Contributor represents that, except as disclosed
- pursuant to Section 3.4(a) above, Contributor
- believes that Contributor's Modifications are
- Contributor's original creation(s) and/or
- Contributor has sufficient rights to grant the
- rights conveyed by this License.
-
- 3.5. Required Notices.
- You must duplicate the notice in Exhibit A in each
- file of the Source Code. If it is not possible to put
- such notice in a particular Source Code file due to
- its structure, then You must include such notice in a
- location (such as a relevant directory) where a user
- would be likely to look for such a notice. If You
- created one or more Modification(s) You may add your
- name as a Contributor to the notice described in
- Exhibit A. You must also duplicate this License in
- any documentation for the Source Code where You
- describe recipients' rights or ownership rights
- relating to Covered Code. You may choose to offer,
- and to charge a fee for, warranty, support, indemnity
- or liability obligations to one or more recipients of
- Covered Code. However, You may do so only on Your own
- behalf, and not on behalf of the Initial Developer or
- any Contributor. You must make it absolutely clear
- than any such warranty, support, indemnity or
- liability obligation is offered by You alone, and You
- hereby agree to indemnify the Initial Developer and
- every Contributor for any liability incurred by the
- Initial Developer or such Contributor as a result of
- warranty, support, indemnity or liability terms You
- offer.
-
- 3.6. Distribution of Executable Versions.
- You may distribute Covered Code in Executable form
- only if the requirements of Section 3.1-3.5 have been
- met for that Covered Code, and if You include a notice
- stating that the Source Code version of the Covered
- Code is available under the terms of this License,
- including a description of how and where You have
- fulfilled the obligations of Section 3.2. The notice
- must be conspicuously included in any notice in an
- Executable version, related documentation or
- collateral in which You describe recipients' rights
- relating to the Covered Code. You may distribute the
- Executable version of Covered Code or ownership rights
- under a license of Your choice, which may contain
- terms different from this License, provided that You
- are in compliance with the terms of this License and
- that the license for the Executable version does not
- attempt to limit or alter the recipient's rights in
- the Source Code version from the rights set forth in
- this License. If You distribute the Executable version
- under a different license You must make it absolutely
- clear that any terms which differ from this License
- are offered by You alone, not by the Initial Developer
- or any Contributor. You hereby agree to indemnify the
- Initial Developer and every Contributor for any
- liability incurred by the Initial Developer or such
- Contributor as a result of any such terms You offer.
-
- 3.7. Larger Works.
- You may create a Larger Work by combining Covered Code
- with other code not governed by the terms of this
- License and distribute the Larger Work as a single
- product. In such a case, You must make sure the
- requirements of this License are fulfilled for the
- Covered Code.
-
-
-4. Inability to Comply Due to Statute or Regulation.
-
- If it is impossible for You to comply with any of the
- terms of this License with respect to some or all of
- the Covered Code due to statute, judicial order, or
- regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b)
- describe the limitations and the code they affect.
- Such description must be included in the LEGAL file
- described in Section 3.4 and must be included with all
- distributions of the Source Code. Except to the extent
- prohibited by statute or regulation, such description
- must be sufficiently detailed for a recipient of
- ordinary skill to be able to understand it.
-
-
-5. Application of this License.
-
- This License applies to code to which the Initial
- Developer has attached the notice in Exhibit A and to
- related Covered Code.
-
-
-6. Versions of the License.
-
- 6.1. New Versions.
- Netscape Communications Corporation (''Netscape'') may
- publish revised and/or new versions of the License
- from time to time. Each version will be given a
- distinguishing version number.
-
- 6.2. Effect of New Versions.
- Once Covered Code has been published under a
- particular version of the License, You may always
- continue to use it under the terms of that version.
- You may also choose to use such Covered Code under the
- terms of any subsequent version of the License
- published by Netscape. No one other than Netscape has
- the right to modify the terms applicable to Covered
- Code created under this License.
-
- 6.3. Derivative Works.
- If You create or use a modified version of this
- License (which you may only do in order to apply it to
- code which is not already Covered Code governed by
- this License), You must (a) rename Your license so
- that the phrases ''Mozilla'', ''MOZILLAPL'',
- ''MOZPL'', ''Netscape'', "MPL", ''NPL'' or any
- confusingly similar phrase do not appear in your
- license (except to note that your license differs from
- this License) and (b) otherwise make it clear that
- Your version of the license contains terms which
- differ from the Mozilla Public License and Netscape
- Public License. (Filling in the name of the Initial
- Developer, Original Code or Contributor in the notice
- described in Exhibit A shall not of themselves be
- deemed to be modifications of this License.)
-
-
-7. DISCLAIMER OF WARRANTY.
-
- COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS
- IS'' BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER
- EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
- WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS,
- MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-
- INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
- PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD
- ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU
- (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR)
- ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR
- CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
- ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED
- CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
- DISCLAIMER.
-
-
-8. TERMINATION.
-
- 8.1. This License and the rights granted hereunder
- will terminate automatically if You fail to comply
- with terms herein and fail to cure such breach within
- 30 days of becoming aware of the breach. All
- sublicenses to the Covered Code which are properly
- granted shall survive any termination of this License.
- Provisions which, by their nature, must remain in
- effect beyond the termination of this License shall
- survive.
-
- 8.2. If You initiate litigation by asserting a patent
- infringement claim (excluding declatory judgment
- actions) against Initial Developer or a Contributor
- (the Initial Developer or Contributor against whom You
- file such action is referred to as "Participant")
- alleging that:
-
- (a) such Participant's Contributor Version directly
- or indirectly infringes any patent, then any and all
- rights granted by such Participant to You under
- Sections 2.1 and/or 2.2 of this License shall, upon 60
- days notice from Participant terminate prospectively,
- unless if within 60 days after receipt of notice You
- either: (i) agree in writing to pay Participant a
- mutually agreeable reasonable royalty for Your past
- and future use of Modifications made by such
- Participant, or (ii) withdraw Your litigation claim
- with respect to the Contributor Version against such
- Participant. If within 60 days of notice, a
- reasonable royalty and payment arrangement are not
- mutually agreed upon in writing by the parties or the
- litigation claim is not withdrawn, the rights granted
- by Participant to You under Sections 2.1 and/or 2.2
- automatically terminate at the expiration of the 60
- day notice period specified above.
-
- (b) any software, hardware, or device, other than
- such Participant's Contributor Version, directly or
- indirectly infringes any patent, then any rights
- granted to You by such Participant under Sections 2.1
- (b) and 2.2(b) are revoked effective as of the date
- You first made, used, sold, distributed, or had made,
- Modifications made by that Participant.
-
- 8.3. If You assert a patent infringement claim
- against Participant alleging that such Participant's
- Contributor Version directly or indirectly infringes
- any patent where such claim is resolved (such as by
- license or settlement) prior to the initiation of
- patent infringement litigation, then the reasonable
- value of the licenses granted by such Participant
- under Sections 2.1 or 2.2 shall be taken into account
- in determining the amount or value of any payment or
- license.
-
- 8.4. In the event of termination under Sections 8.1
- or 8.2 above, all end user license agreements
- (excluding distributors and resellers) which have been
- validly granted by You or any distributor hereunder
- prior to termination shall survive termination.
-
-
-9. LIMITATION OF LIABILITY.
-
- UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
- WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR
- OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER
- CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR
- ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY
- PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
- CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING,
- WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
- STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND
- ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH
- PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF
- SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT
- APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
- RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
- APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME
- JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION
- OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS
- EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-
-10. U.S. GOVERNMENT END USERS.
-
- The Covered Code is a ''commercial item,'' as that
- term is defined in 48 C.F.R. 2.101 (Oct. 1995),
- consisting of ''commercial computer software'' and
- ''commercial computer software documentation,'' as
- such terms are used in 48 C.F.R. 12.212 (Sept. 1995).
- Consistent with 48 C.F.R. 12.212 and 48 C.F.R.
- 227.7202-1 through 227.7202-4 (June 1995), all U.S.
- Government End Users acquire Covered Code with only
- those rights set forth herein.
-
-
-11. MISCELLANEOUS.
-
- This License represents the complete agreement
- concerning subject matter hereof. If any provision of
- this License is held to be unenforceable, such
- provision shall be reformed only to the extent
- necessary to make it enforceable. This License shall
- be governed by California law provisions (except to
- the extent applicable law, if any, provides
- otherwise), excluding its conflict-of-law provisions.
- With respect to disputes in which at least one party
- is a citizen of, or an entity chartered or registered
- to do business in the United States of America, any
- litigation relating to this License shall be subject
- to the jurisdiction of the Federal Courts of the
- Northern District of California, with venue lying in
- Santa Clara County, California, with the losing party
- responsible for costs, including without limitation,
- court costs and reasonable attorneys' fees and
- expenses. The application of the United Nations
- Convention on Contracts for the International Sale of
- Goods is expressly excluded. Any law or regulation
- which provides that the language of a contract shall
- be construed against the drafter shall not apply to
- this License.
-
-
-12. RESPONSIBILITY FOR CLAIMS.
-
- As between Initial Developer and the Contributors,
- each party is responsible for claims and damages
- arising, directly or indirectly, out of its
- utilization of rights under this License and You agree
- to work with Initial Developer and Contributors to
- distribute such responsibility on an equitable basis.
- Nothing herein is intended or shall be deemed to
- constitute any admission of liability.
-
-
-13. MULTIPLE-LICENSED CODE.
-
- Initial Developer may designate portions of the
- Covered Code as Multiple-Licensed. Multiple-Licensed
- means that the Initial Developer permits you to
- utilize portions of the Covered Code under Your choice
- of the NPL or the alternative licenses, if any,
- specified by the Initial Developer in the file
- described in Exhibit A.
-
-
-
-EXHIBIT A - Mozilla Public License.
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the License.
-
- The Original Code is ______________________________________.
-
- The Initial Developer of the Original Code is
- ________________________.
- Portions created by ______________________ are Copyright (C) ______
- _______________________. All Rights Reserved.
-
- Contributor(s): ______________________________________.
-
- Alternatively, the contents of this file may be used under the terms of
- the _____ license (the [___] License), in which case the provisions of
- [______] License are applicable instead of those above. If you wish to
- allow use of your version of this file only under the terms of the [____]
- License and not to allow others to use your version of this file under
- the MPL, indicate your decision by deleting the provisions above and
- replace them with the notice and other provisions required by the [___]
- License. If you do not delete the provisions above, a recipient may use
- your version of this file under either the MPL or the [___] License.
-
- [NOTE: The text of this Exhibit A may differ slightly from the text of
- the notices in the Source Code files of the Original Code. You should use
- the text of this Exhibit A rather than the text found in the Original Code
- Source Code for Your Modifications.]
-
diff --git a/externals/vegas/README b/externals/vegas/README
deleted file mode 100644
--- a/externals/vegas/README
+++ /dev/null
@@ -1,29 +0,0 @@
-VEGAS AS3 - version 1.8.5.2228
-
-The "vegas.swc" library contains all the AS3 source code of the VEGAS project with all this extensions.
-
-LICENCE
-
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
-PROJECT PAGES
-
- * http://code.google.com/p/vegas/
-
-DOCUMENTATION & CO
-
- * http://code.google.com/p/vegas/ (tutorials and install)
- * http://code.google.com/p/vegas/issues/list (issues)
- * http://www.ekameleon.net/vegas/docs
-
- * http://www.ekameleon.net/blog/ (french blog)
-
-ABOUT AUTHOR
-
- * Author : ALCARAZ Marc (eKameleon)
- * Link : http://www.ekameleon.net/blog
- * Mail : ekameleon@gmail.com
-
-NOTES
-
-The vegas.swc file target now the FlashPlayer 10.2 and build with the Flex SDK 4.5.0.19786.
\ No newline at end of file
diff --git a/externals/vegas/src/system/Serializer.as b/externals/vegas/src/system/Serializer.as
deleted file mode 100644
--- a/externals/vegas/src/system/Serializer.as
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is [maashaack framework].
-
- The Initial Developers of the Original Code are
- Zwetan Kjukov <zwetan@gmail.com> and Marc Alcaraz <ekameleon@gmail.com>.
- Portions created by the Initial Developers are Copyright (C) 2006-2011
- the Initial Developers. All Rights Reserved.
-
- Contributor(s):
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-*/
-
-package system
-{
-
- /**
- * Defines what a Serializer have to implements to be integrated in the framework.
- * <p><b>Note :</b> Every serializers (eden, json, wddx, etc.) should implement it.</p>
- */
- public interface Serializer
- {
- /**
- * The prettyIndent value of the serializer.
- */
- function get prettyIndent():int;
-
- /**
- * @private
- */
- function set prettyIndent( value:int ):void;
-
- /**
- * The prettyPrinting value of the serializer.
- */
- function get prettyPrinting():Boolean;
-
- /**
- * @private
- */
- function set prettyPrinting( value:Boolean ):void;
-
- /**
- * The identor String value of the serializer.
- */
- function get indentor():String;
-
- /**
- * @private
- */
- function set indentor( value:String ):void;
-
- /**
- * Deserialize the specified String source representation.
- */
- function deserialize( source:String ):*;
-
- /**
- * Serialize the specified object.
- */
- function serialize( value:* ):String;
- }
-}
-
diff --git a/externals/vegas/src/vegas/strings/JSON.as b/externals/vegas/src/vegas/strings/JSON.as
deleted file mode 100644
--- a/externals/vegas/src/vegas/strings/JSON.as
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the License.
-
- The Original Code is VEGAS Framework.
-
- The Initial Developer of the Original Code is
- ALCARAZ Marc (aka eKameleon) <ekameleon@gmail.com>.
- Portions created by the Initial Developer are Copyright (C) 2004-2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s) :
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
-*/
-package vegas.strings
-{
- import vegas.strings.json.JSONSerializer;
-
- /**
- * <code class="prettyprint">JSON</code> (JavaScript object Notation) is a lightweight data-interchange format.
- * <p>More information in the official site : <a href="http://www.JSON.org/">http://www.JSON.org</a></p>
- * <p>Add Hexa Digits tool in deserialize method - <a href="http://code.google.com/p/edenrr/">eden inspiration</a></p>
- *
- * @example Example
- * <listing version="3.0">
- * <code class="prettyprint">
- * import core.getClassName ;
- *
- * import vegas.strings.JSON;
- * import vegas.strings.errors.JSONError;
- *
- * // --- Init
- *
- * var a:Array = [2, true, "hello"] ;
- * var o:Object = { prop1 : 1 , prop2 : 2 } ;
- * var s:String = "hello world" ;
- * var n:Number = 4 ;
- * var b:Boolean = true ;
- *
- * trace("# Serialize \r") ;
- *
- * trace("- a : " + JSON.serialize( a ) ) ;
- * trace("- o : " + JSON.serialize( o ) ) ;
- * trace("- s : " + JSON.serialize( s ) ) ;
- * trace("- n : " + JSON.serialize( n ) ) ;
- * trace("- b : " + JSON.serialize( b ) ) ;
- *
- * trace ("\r# Deserialize \r") ;
- *
- * var source:String = '[ { "prop1" : 0xFF0000 , prop2:2, prop3:"hello", prop4:true} , 2, true, 3, [3, 2] ]' ;
- *
- * o = JSON.deserialize(source) ;
- *
- * var l:uint = o.length ;
- * for (var i:uint = 0 ; i &lt; l ; i++)
- * {
- * trace("> " + i + " : " + o[i] + " -> typeof :: " + typeof(o[i])) ;
- * if (typeof(o[i]) == "object")
- * {
- * for (var each:String in o[i])
- * {
- * trace(" > " + each + " : " + o[i][each] + " :: " + getClassName(o[i][each]) ) ;
- * }
- * }
- * }
- *
- * trace ("\r# JSONError \r") ;
- *
- * source = "[3, 2," ; // test1
- *
- * // var source:String = '{"prop1":coucou"}' ; // test2
- *
- * try
- * {
- * var errorObj:Object = JSON.deserialize(source) ;
- * }
- * catch( e:JSONError )
- * {
- * trace( e.toString() ) ;
- * }
- * </code>
- * </listing>
- */
- public var JSON:JSONSerializer = new JSONSerializer() ;
-}
\ No newline at end of file
diff --git a/externals/vegas/src/vegas/strings/json/JSONError.as b/externals/vegas/src/vegas/strings/json/JSONError.as
deleted file mode 100644
--- a/externals/vegas/src/vegas/strings/json/JSONError.as
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the License.
-
- The Original Code is VEGAS Framework.
-
- The Initial Developer of the Original Code is
- ALCARAZ Marc (aka eKameleon) <ekameleon@gmail.com>.
- Portions created by the Initial Developer are Copyright (C) 2004-2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s) :
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
-*/
-
-package vegas.strings.json
-{
- /**
- * This JSONError is throw in the JSON static methods.
- */
- public class JSONError extends Error
- {
- /**
- * Creates a new JSONError instance.
- */
- public function JSONError( message:String, at:uint, source:String , id:int=0 )
- {
- super( message , id );
- name = "JSONError" ;
- this.at = at ;
- this.source = source ;
- }
-
- /**
- * The position of char with an error parsing in the JSON String representation.
- */
- public var at:uint ;
-
- /**
- * The source ot the bad parsing.
- */
- public var source:String ;
-
- /**
- * Returns a String representation of the object.
- * @return a String representation of the object.
- */
- public function toString():String
- {
- var msg:String = "## " + name + " : " + message + " ##" ;
- if (!isNaN(at))
- {
- msg += ", at:" + at ;
- }
- if ( source != null )
- {
- msg += " in \"" + source + "\"";
- }
- return msg ;
- }
- }
-}
\ No newline at end of file
diff --git a/externals/vegas/src/vegas/strings/json/JSONSerializer.as b/externals/vegas/src/vegas/strings/json/JSONSerializer.as
deleted file mode 100644
--- a/externals/vegas/src/vegas/strings/json/JSONSerializer.as
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
-
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the License.
-
- The Original Code is VEGAS Framework.
-
- The Initial Developer of the Original Code is
- ALCARAZ Marc (aka eKameleon) <ekameleon@gmail.com>.
- Portions created by the Initial Developer are Copyright (C) 2004-2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s) :
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
-*/
-
-package vegas.strings.json
-{
- import system.Serializer;
-
- /**
- * This class is the concrete class of the JSON singleton.
- * <code class="prettyprint">JSON</code> (JavaScript object Notation) is a lightweight data-interchange format.
- * <p>More information in the official site : <a href="http://www.JSON.org/">http://www.JSON.org</a></p>
- * <p>Add Hexa Digits tool in deserialize method - <a href="http://code.google.com/p/edenrr/">eden inspiration</a></p>
- * <p><b>Example :</b></p>
- * <pre class="prettyprint">
- * import core.getClassName ;
- *
- * import vegas.strings.JSON;
- * import vegas.strings.JSONError;
- *
- * // --- Init
- *
- * var a:Array = [2, true, "hello"] ;
- * var o:Object = { prop1 : 1 , prop2 : 2 } ;
- * var s:String = "hello world" ;
- * var n:Number = 4 ;
- * var b:Boolean = true ;
- *
- * trace("Serialize") ;
- *
- * trace("- a : " + JSON.serialize( a ) ) ;
- * trace("- o : " + JSON.serialize( o ) ) ;
- * trace("- s : " + JSON.serialize( s ) ) ;
- * trace("- n : " + JSON.serialize( n ) ) ;
- * trace("- b : " + JSON.serialize( b ) ) ;
- *
- * trace ("Deserialize") ;
- *
- * var source:String = '[ { "prop1" : 0xFF0000 , prop2:2, prop3:"hello", prop4:true} , 2, true, 3, [3, 2] ]' ;
- *
- * o = JSON.deserialize(source) ;
- *
- * var l:uint = o.length ;
- * for (var i:uint = 0 ; i &lt; l ; i++)
- * {
- * trace("- " + i + " : " + o[i] + " , typeof :: " + typeof(o[i])) ;
- * if (typeof(o[i]) == "object")
- * {
- * for (var each:String in o[i])
- * {
- * trace(" + " + each + " : " + o[i][each] + " :: " + getClassName(o[i][each]) ) ;
- * }
- * }
- * }
- *
- * trace ("JSONError") ;
- *
- * source = "[3, 2," ; // test1
- *
- * // var source:String = '{"prop1":coucou"}' ; // test2
- *
- * try
- * {
- * var errorObj:Object = JSON.deserialize(source) ;
- * }
- * catch( e:JSONError )
- * {
- * trace( e.toString() ) ;
- * }
- * </pre>
- */
- public class JSONSerializer implements Serializer
- {
- /**
- * Creates a new JSONSerializer instance.
- */
- public function JSONSerializer()
- {
- //
- }
-
- /**
- * The source to evaluate.
- */
- public var source:String ;
-
- /**
- * Indicates the indentor string representation.
- */
- public function get indentor():String
- {
- return _indentor;
- }
-
- /**
- * @private
- */
- public function set indentor(value:String):void
- {
- _indentor = value;
- }
-
- /**
- * Indicates the pretty indent value.
- */
- public function get prettyIndent():int
- {
- return _prettyIndent;
- }
-
- /**
- * @private
- */
- public function set prettyIndent(value:int):void
- {
- _prettyIndent = value ;
- }
-
- /**
- * Indicates the pretty printing flag value.
- */
- public function get prettyPrinting():Boolean
- {
- return _prettyPrinting ;
- }
-
- /**
- * @private
- */
- public function set prettyPrinting(value:Boolean):void
- {
- _prettyPrinting = value;
- }
-
- /**
- * Parse a string and interpret the source code to the correct object construct.
- * <p><b>Example :</b></p>
- * <pre class="prettyprint">
- * "hello world" --> "hello world"
- * "0xFF" --> 255
- * "{a:1,"b":2}" --> {a:1,b:2}
- * </pre>
- * @return a string representing the data.
- */
- public function deserialize( source:String ):*
- {
- this.source = source ;
- at = 0 ;
- ch = ' ' ;
- return value() ;
- }
-
- /**
- * Serialize the specified value object passed-in argument.
- */
- public function serialize( value:* ):String
- {
- var c:String ; // char
- var i:int ;
- var l:int ;
- var s:String = '' ;
- var v:* ;
- var tof:String = typeof(value) ;
- switch (tof)
- {
- case 'object' :
- {
- if (value)
- {
- if (value is Array)
- {
- l = (value as Array).length ;
- for (i = 0 ; i < l ; ++i)
- {
- v = serialize(value[i]);
- if (s) s += ',' ;
- s += v ;
- }
- return '[' + s + ']';
- }
- else if ( typeof( value.toString ) != 'undefined')
- {
- for (var prop:String in value)
- {
- v = value[prop];
- if ( (typeof(v) != 'undefined') && (typeof(v) != 'function') )
- {
- v = serialize(v);
- if (s)
- {
- s += ',' ;
- }
- s += serialize(prop) + ':' + v ;
- }
- }
- return "{" + s + "}";
- }
- }
- return 'null';
- }
- case 'number':
- {
- return isFinite(value) ? String(value) : 'null' ;
- }
- case 'string' :
- {
- l = (value as String).length ;
- s = '"' ;
- for (i = 0 ; i < l ; i += 1)
- {
- c = (value as String).charAt(i) ;
- if (c >= ' ')
- {
- if (c == '\\' || c == '"')
- {
- s += '\\';
- }
- s += c;
- }
- else
- {
- switch (c)
- {
- case '\b':
- {
- s += '\\b';
- break ;
- }
- case '\f' :
- {
- s += '\\f' ;
- break ;
- }
- case '\n' :
- {
- s += '\\n' ;
- break ;
- }
- case '\r':
- {
- s += '\\r' ;
- break ;
- }
- case '\t':
- {
- s += '\\t' ;
- break ;
- }
- default:
- {
- var code:Number = c.charCodeAt() ;
- s += '\\u00' + String(Math.floor(code / 16).toString(16)) + ((code % 16).toString(16)) ;
- }
- }
- }
- }
- return s + '"' ;
- }
- case 'boolean' :
- {
- return String(value);
- }
- default :
- {
- return 'null';
- }
- }
- }
-
- /**
- * The current position of the iterator in the source.
- */
- protected var at:Number = 0 ;
-
- /**
- * The current character of the iterator in the source.
- */
- protected var ch:String = ' ' ;
-
- /**
- * Check the Array objects in the source expression.
- */
- protected function array():Array
- {
- var a:Array = [];
- if ( ch == '[' )
- {
- next() ;
- white() ;
- if (ch == ']')
- {
- next();
- return a;
- }
- while (ch)
- {
- a.push( value() ) ;
- white();
- if (ch == ']')
- {
- next();
- return a;
- }
- else if (ch != ',')
- {
- break;
- }
- next();
- white();
- }
- }
- error( JSONStrings.badArray );
- return null ;
- }
-
- /**
- * Throws a JSONError with the passed-in message.
- */
- protected function error( m:String ):void
- {
- throw new JSONError( m, at - 1 , source) ;
- }
-
- /**
- * Indicates if the passed-in character is a digit.
- */
- protected function isDigit( c:String ):Boolean
- {
- return( ("0" <= c) && (c <= "9") );
- }
-
- /**
- * Indicates if the passed-in character is a hexadecimal digit.
- */
- protected function isHexDigit( c:String ):Boolean
- {
- return( isDigit( c ) || (("A" <= c) && (c <= "F")) || (("a" <= c) && (c <= "f")) );
- }
-
- /**
- * Indicates if the current character is a key.
- */
- protected function key():*
- {
- var s:String = ch ;
- var semiColon:int = source.indexOf( ':' , at ) ;
- var quoteIndex:int = source.indexOf( '"' , at ) ;
- var squoteIndex:int = source.indexOf( "'" , at ) ;
- if( (quoteIndex <= semiColon && quoteIndex > -1) || (squoteIndex <= semiColon && squoteIndex > -1))
- {
- s = string() ;
- white() ;
- if(ch == ':')
- {
- return s;
- }
- else
- {
- error(JSONStrings.badKey);
- }
- }
- while ( next() ) // Use key handling
- {
- if (ch == ':')
- {
- return s;
- }
- if(ch <= ' ')
- {
- //
- }
- else
- {
- s += ch;
- }
- }
- error( JSONStrings.badKey ) ;
- }
-
- /**
- * Returns the next character in the source String representation.
- * @return the next character in the source String representation.
- */
- protected function next():String
- {
- ch = source.charAt(at);
- at += 1;
- return ch;
- }
-
- /**
- * Check the Number values in the source expression.
- */
- protected function number():*
- {
-
- var n:* = '' ;
- var v:* ;
- var hex:String = '' ;
- var sign:String = '' ;
- if (ch == '-')
- {
- n = '-';
- sign = n ;
- next();
- }
- if( ch == "0" )
- {
- next() ;
- if( ( ch == "x") || ( ch == "X") )
- {
- next();
- while( isHexDigit( ch ) )
- {
- hex += ch ;
- next();
- }
- if( hex == "" )
- {
- error(JSONStrings.malFormedHexadecimal) ;
- }
- else
- {
- return Number( sign + "0x" + hex ) ;
- }
- }
- else
- {
- n += "0" ;
- }
- }
- while ( isDigit(ch) )
- {
- n += ch ;
- next() ;
- }
- if (ch == '.')
- {
- n += '.';
- while (next() && ch >= '0' && ch <= '9')
- {
- n += ch ;
- }
- }
- v = 1 * n ;
- if (!isFinite(v))
- {
- error( JSONStrings.badNumber );
- }
- else
- {
- return v ;
- }
- return NaN ;
- }
-
- /**
- * Check the Object values in the source expression.
- */
- protected function object():*
- {
- var k:* = {} ;
- var o:* = {} ;
- if (ch == '{')
- {
- next();
- white();
- if (ch == '}')
- {
- next() ;
- return o ;
- }
- while (ch)
- {
- k = key() ;
- white();
- if (ch != ':')
- {
- break;
- }
- next();
- o[k] = value() ;
- white();
- if (ch == '}')
- {
- next();
- return o;
- }
- else if (ch != ',')
- {
- break;
- }
- next();
- white();
- }
- }
- error( JSONStrings.badObject ) ;
- }
-
- /**
- * Check the string objects in the source expression.
- */
- protected function string():*
- {
- var i:* = '' ;
- var s:* = '' ;
- var t:* ;
- var u:* ;
- var outer:Boolean ;
- if (ch == '"' || ch == "'" )
- {
- var outerChar:String = ch ;
- while ( next() )
- {
- if (ch == outerChar)
- {
- next() ;
- return s ;
- }
- else if (ch == '\\')
- {
- switch ( next() )
- {
- case 'b':
- {
- s += '\b' ;
- break ;
- }
- case 'f' :
- {
- s += '\f';
- break ;
- }
- case 'n':
- {
- s += '\n';
- break ;
- }
- case 'r' :
- {
- s += '\r';
- break ;
- }
- case 't' :
- {
- s += '\t' ;
- break ;
- }
- case 'u' :
- {
- u = 0;
- for (i = 0; i < 4; i += 1)
- {
- t = parseInt( next() , 16 ) ;
- if (!isFinite(t))
- {
- outer = true;
- break;
- }
- u = u * 16 + t;
- }
- if(outer)
- {
- outer = false;
- break;
- }
- s += String.fromCharCode(u);
- break;
- }
- default :
- {
- s += ch;
- }
- }
- }
- else
- {
- s += ch;
- }
- }
- }
- error( JSONStrings.badString );
- return null ;
- }
-
- /**
- * Evaluates the values in the source expression.
- */
- protected function value():*
- {
- white() ;
- if (ch == '{' )
- {
- return object();
- }
- else if ( ch == '[' )
- {
- return array();
- }
- else if ( ch == '"' || ch == "'" )
- {
- return string();
- }
- else if ( ch == '-' )
- {
- return number();
- }
- else
- {
- return ( ch >= '0' && ch <= '9' ) ? number() : word() ;
- }
- }
-
- /**
- * Check all white spaces.
- */
- protected function white():void
- {
- while (ch)
- {
- if (ch <= ' ')
- {
- next();
- }
- else if (ch == '/')
- {
- switch ( next() )
- {
- case '/' :
- {
- while ( next() && ch != '\n' && ch != '\r')
- {
- }
- break;
- }
- case '*' :
- {
- next();
- for (;;)
- {
- if (ch)
- {
- if (ch == '*')
- {
- if ( next() == '/' )
- {
- next();
- break;
- }
- }
- else
- {
- next();
- }
- }
- else
- {
- error( JSONStrings.unterminatedComment );
- }
- }
- break ;
- }
- default :
- {
- error( JSONStrings.syntaxError );
- }
- }
- }
- else
- {
- break ;
- }
- }
- }
-
- /**
- * Check all special words in the source to evaluate.
- */
- protected function word():*
- {
- if (ch == 't')
- {
- if (next() == 'r' && next() == 'u' && next() == 'e')
- {
- next() ;
- return true ;
- }
- }
- else if ( ch == 'f' )
- {
- if (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e')
- {
- next() ;
- return false ;
- }
- }
- else if ( ch == 'n' )
- {
- if (next() == 'u' && next() == 'l' && next() == 'l')
- {
- next() ;
- return null ;
- }
- }
- error( JSONStrings.syntaxError );
- return null ;
- }
-
- /**
- * @private
- */
- private var _prettyIndent:int = 0 ;
-
- /**
- * @private
- */
- private var _prettyPrinting:Boolean ;
-
- /**
- * @private
- */
- private var _indentor:String = " " ;
- }
-}
diff --git a/externals/vegas/src/vegas/strings/json/JSONStrings.as b/externals/vegas/src/vegas/strings/json/JSONStrings.as
deleted file mode 100644
--- a/externals/vegas/src/vegas/strings/json/JSONStrings.as
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
-
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the License.
-
- The Original Code is VEGAS Framework.
-
- The Initial Developer of the Original Code is
- ALCARAZ Marc (aka eKameleon) <ekameleon@gmail.com>.
- Portions created by the Initial Developer are Copyright (C) 2004-2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s) :
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
-*/
-
-package vegas.strings.json
-{
- /**
- * The string messages used in the JSON class.
- */
- public class JSONStrings
- {
- /**
- * The bad Array error message.
- */
- public static var badArray:String = "Bad Array" ;
-
- /**
- * The bad key error message.
- */
- public static var badKey:String = "Bad key" ;
-
- /**
- * The bad Number error message.
- */
- public static var badNumber:String = "Bad Number" ;
-
- /**
- * The bad Object error message.
- */
- public static var badObject:String = "Bad Object" ;
-
- /**
- * The bad String error message.
- */
- public static var badString:String = "Bad String" ;
-
- /**
- * The mal formed Hexadecimal error message.
- */
- public static var malFormedHexadecimal:String = "Mal formed Hexadecimal" ;
-
- /**
- * The syntax error message.
- */
- public static var syntaxError:String = "Syntax Error" ;
-
- /**
- * The unterminated comment error message.
- */
- public static var unterminatedComment:String = "Unterminated Comment" ;
- }
-}
\ No newline at end of file
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,8 +7,8 @@
*/
return array(
'names' => array(
- 'core.pkg.css' => '63e782fb',
- 'core.pkg.js' => '44aac665',
+ 'core.pkg.css' => '8fc8031a',
+ 'core.pkg.js' => '21041609',
'darkconsole.pkg.js' => '8ab24e01',
'differential.pkg.css' => '8af45893',
'differential.pkg.js' => 'dad3622f',
@@ -342,9 +342,9 @@
'rsrc/image/texture/table_header.png' => '5c433037',
'rsrc/image/texture/table_header_hover.png' => '038ec3b9',
'rsrc/image/texture/table_header_tall.png' => 'd56b434f',
- 'rsrc/js/application/aphlict/Aphlict.js' => '4a07e8e3',
+ 'rsrc/js/application/aphlict/Aphlict.js' => '464d333a',
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'f6bc26f0',
- 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'a826c925',
+ 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '1162a152',
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '58f7803f',
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de',
@@ -489,7 +489,6 @@
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '6e8cefa4',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
- 'rsrc/swf/aphlict.swf' => 'f19daffb',
),
'symbols' => array(
'almanac-css' => 'dbb9b3af',
@@ -536,10 +535,10 @@
'herald-rule-editor' => '335fd41f',
'herald-test-css' => '778b008e',
'inline-comment-summary-css' => '8cfd34e8',
- 'javelin-aphlict' => '4a07e8e3',
+ 'javelin-aphlict' => '464d333a',
'javelin-behavior' => '61cbc29a',
'javelin-behavior-aphlict-dropdown' => 'f6bc26f0',
- 'javelin-behavior-aphlict-listen' => 'a826c925',
+ 'javelin-behavior-aphlict-listen' => '1162a152',
'javelin-behavior-aphlict-status' => '58f7803f',
'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884',
'javelin-behavior-aphront-crop' => 'fa0f4fc2',
@@ -909,6 +908,18 @@
'javelin-uri',
'javelin-install',
),
+ '1162a152' => array(
+ 'javelin-behavior',
+ 'javelin-aphlict',
+ 'javelin-stratcom',
+ 'javelin-request',
+ 'javelin-uri',
+ 'javelin-dom',
+ 'javelin-json',
+ 'javelin-router',
+ 'javelin-util',
+ 'phabricator-notification',
+ ),
'13c739ea' => array(
'javelin-behavior',
'javelin-stratcom',
@@ -1079,6 +1090,13 @@
'javelin-behavior',
'javelin-dom',
),
+ '464d333a' => array(
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-websocket',
+ 'javelin-leader',
+ 'javelin-json',
+ ),
'469c0d9e' => array(
'javelin-behavior',
'javelin-dom',
@@ -1100,10 +1118,6 @@
'javelin-request',
'javelin-util',
),
- '4a07e8e3' => array(
- 'javelin-install',
- 'javelin-util',
- ),
'4d94d9c3' => array(
'javelin-behavior',
'javelin-stratcom',
@@ -1489,18 +1503,6 @@
'javelin-stratcom',
'javelin-dom',
),
- 'a826c925' => array(
- 'javelin-behavior',
- 'javelin-aphlict',
- 'javelin-stratcom',
- 'javelin-request',
- 'javelin-uri',
- 'javelin-dom',
- 'javelin-json',
- 'javelin-router',
- 'javelin-util',
- 'phabricator-notification',
- ),
'a8d8459d' => array(
'javelin-behavior',
'javelin-dom',
@@ -2024,6 +2026,11 @@
'sprite-tokens-css',
'tokens-css',
'phui-status-list-view-css',
+ 'phui-feed-story-css',
+ 'phabricator-feed-css',
+ 'phabricator-dashboard-css',
+ 'aphront-multi-column-view-css',
+ 'phui-action-header-view-css',
),
'core.pkg.js' => array(
'javelin-util',
@@ -2093,6 +2100,11 @@
'javelin-behavior-phabricator-show-older-transactions',
'javelin-behavior-phui-timeline-dropdown-menu',
'javelin-behavior-doorkeeper-tag',
+ 'phabricator-title',
+ 'javelin-leader',
+ 'javelin-websocket',
+ 'javelin-behavior-dashboard-async-panel',
+ 'javelin-behavior-dashboard-tab-panel',
),
'darkconsole.pkg.js' => array(
'javelin-behavior-dark-console',
diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php
--- a/resources/celerity/packages.php
+++ b/resources/celerity/packages.php
@@ -69,6 +69,11 @@
'javelin-behavior-phabricator-show-older-transactions',
'javelin-behavior-phui-timeline-dropdown-menu',
'javelin-behavior-doorkeeper-tag',
+ 'phabricator-title',
+ 'javelin-leader',
+ 'javelin-websocket',
+ 'javelin-behavior-dashboard-async-panel',
+ 'javelin-behavior-dashboard-tab-panel',
),
'core.pkg.css' => array(
'phabricator-core-css',
@@ -126,6 +131,12 @@
'sprite-tokens-css',
'tokens-css',
'phui-status-list-view-css',
+
+ 'phui-feed-story-css',
+ 'phabricator-feed-css',
+ 'phabricator-dashboard-css',
+ 'aphront-multi-column-view-css',
+ 'phui-action-header-view-css',
),
'differential.pkg.css' => array(
'differential-core-view-css',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1239,7 +1239,6 @@
'PhabricatorAlmanacApplication' => 'applications/almanac/application/PhabricatorAlmanacApplication.php',
'PhabricatorAmazonAuthProvider' => 'applications/auth/provider/PhabricatorAmazonAuthProvider.php',
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
- 'PhabricatorAphlictManagementBuildWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php',
'PhabricatorAphlictManagementDebugWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php',
'PhabricatorAphlictManagementRestartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php',
'PhabricatorAphlictManagementStartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php',
@@ -4393,7 +4392,6 @@
'PhabricatorAlmanacApplication' => 'PhabricatorApplication',
'PhabricatorAmazonAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorAnchorView' => 'AphrontView',
- 'PhabricatorAphlictManagementBuildWorkflow' => 'PhabricatorAphlictManagementWorkflow',
'PhabricatorAphlictManagementDebugWorkflow' => 'PhabricatorAphlictManagementWorkflow',
'PhabricatorAphlictManagementRestartWorkflow' => 'PhabricatorAphlictManagementWorkflow',
'PhabricatorAphlictManagementStartWorkflow' => 'PhabricatorAphlictManagementWorkflow',
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php
deleted file mode 100644
--- a/src/applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-
-final class PhabricatorAphlictManagementBuildWorkflow
- extends PhabricatorAphlictManagementWorkflow {
-
- public function didConstruct() {
- $this
- ->setName('build')
- ->setSynopsis(pht('Build the Aphlict client.'))
- ->setArguments(
- array(
- array(
- 'name' => 'debug',
- 'help' => 'Enable a debug build.',
- ),
- ));
- }
-
- public function execute(PhutilArgumentParser $args) {
- $console = PhutilConsole::getConsole();
- $root = dirname(__FILE__).'/../../../..';
-
- if (!Filesystem::binaryExists('mxmlc')) {
- throw new PhutilArgumentUsageException(
- pht(
- "The `mxmlc` binary was not found in PATH. This compiler binary ".
- "is required to rebuild the Aphlict client.\n\n".
- "Adjust your PATH, or install the Flex SDK from:\n\n".
- " http://flex.apache.org\n\n".
- "You may also be able to install it with `npm`:\n\n".
- " $ npm install flex-sdk\n\n".
- "(Note: you should only need to rebuild Aphlict if you are ".
- "developing Phabricator.)"));
- }
-
- $argv = array(
- "-source-path=$root/externals/vegas/src",
- '-static-link-runtime-shared-libraries=true',
- '-warnings=true',
- '-strict=true',
- );
-
- if ($args->getArg('debug')) {
- $argv[] = '-debug=true';
- }
-
- list ($err, $stdout, $stderr) = exec_manual('mxmlc %Ls -output=%s %s',
- $argv,
- $root.'/webroot/rsrc/swf/aphlict.swf',
- $root.'/support/aphlict/client/src/AphlictClient.as');
-
- if ($err) {
- $console->writeErr($stderr);
- return 1;
- }
-
- $console->writeOut("Done.\n");
- return 0;
- }
-
-}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php
--- a/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php
@@ -14,7 +14,7 @@
}
public function execute(PhutilArgumentParser $args) {
- $this->willLaunch();
+ $this->willLaunch(true);
return $this->launch(true);
}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
--- a/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
@@ -50,7 +50,7 @@
}
}
- final protected function willLaunch() {
+ final protected function willLaunch($debug = false) {
$console = PhutilConsole::getConsole();
$pid = $this->getPID();
@@ -61,25 +61,35 @@
'running. Use `aphlict restart` to restart it.'));
}
- if (posix_getuid() != 0) {
+ if (posix_getuid() == 0) {
throw new PhutilArgumentUsageException(
pht(
- 'You must run this script as root; the Aphlict server needs to bind '.
- 'to privileged ports.'));
+ // TODO: Update this message after a while.
+ 'The notification server should not be run as root. It no '.
+ 'longer requires access to privileged ports.'));
}
- // This will throw if we can't find an appropriate `node`.
- $this->getNodeBinary();
- }
+ // Make sure we can write to the PID file.
+ if (!$debug) {
+ Filesystem::writeFile($this->getPIDPath(), '');
+ }
- final protected function launch($debug = false) {
- $console = PhutilConsole::getConsole();
+ // First, start the server in configuration test mode with --test. This
+ // will let us error explicitly if there are missing modules, before we
+ // fork and lose access to the console.
+ $test_argv = $this->getServerArgv($debug);
+ $test_argv[] = '--test=true';
- if ($debug) {
- $console->writeOut(pht("Starting Aphlict server in foreground...\n"));
- } else {
- Filesystem::writeFile($this->getPIDPath(), getmypid());
- }
+ execx(
+ '%s %s %Ls',
+ $this->getNodeBinary(),
+ $this->getAphlictScriptPath(),
+ $test_argv);
+ }
+
+ private function getServerArgv($debug) {
+ $ssl_key = PhabricatorEnv::getEnvConfig('notification.ssl-key');
+ $ssl_cert = PhabricatorEnv::getEnvConfig('notification.ssl-cert');
$server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
$server_uri = new PhutilURI($server_uri);
@@ -87,27 +97,46 @@
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
$client_uri = new PhutilURI($client_uri);
- $user = PhabricatorEnv::getEnvConfig('notification.user');
- $log = PhabricatorEnv::getEnvConfig('notification.log');
+ $log = PhabricatorEnv::getEnvConfig('notification.log');
$server_argv = array();
- $server_argv[] = csprintf('--port=%s', $client_uri->getPort());
- $server_argv[] = csprintf('--admin=%s', $server_uri->getPort());
- $server_argv[] = csprintf('--host=%s', $server_uri->getDomain());
+ $server_argv[] = '--port='.$client_uri->getPort();
+ $server_argv[] = '--admin='.$server_uri->getPort();
+
+ if ($ssl_key) {
+ $server_argv[] = '--ssl-key='.$ssl_key;
+ }
- if ($user) {
- $server_argv[] = csprintf('--user=%s', $user);
+ if ($ssl_cert) {
+ $server_argv[] = '--ssl-cert='.$ssl_cert;
}
if (!$debug) {
- $server_argv[] = csprintf('--log=%s', $log);
+ $server_argv[] = '--log='.$log;
+ }
+
+ return $server_argv;
+ }
+
+ private function getAphlictScriptPath() {
+ $root = dirname(phutil_get_library_root('phabricator'));
+ return $root.'/support/aphlict/server/aphlict_server.js';
+ }
+
+ final protected function launch($debug = false) {
+ $console = PhutilConsole::getConsole();
+
+ if ($debug) {
+ $console->writeOut(pht("Starting Aphlict server in foreground...\n"));
+ } else {
+ Filesystem::writeFile($this->getPIDPath(), getmypid());
}
$command = csprintf(
- '%s %s %C',
+ '%s %s %Ls',
$this->getNodeBinary(),
- dirname(__FILE__).'/../../../../support/aphlict/server/aphlict_server.js',
- implode(' ', $server_argv));
+ $this->getAphlictScriptPath(),
+ $this->getServerArgv($debug));
if (!$debug) {
declare(ticks = 1);
@@ -159,6 +188,7 @@
fclose(STDOUT);
fclose(STDERR);
+
$this->launch();
return 0;
}
diff --git a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
--- a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
+++ b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
@@ -194,6 +194,11 @@
'This option has been renamed to `phabricator.show-prototypes` '.
'to emphasize the unfinished nature of many prototype applications. '.
'Your existing setting has been migrated.'),
+ 'notification.user' => pht(
+ 'The notification server no longer requires root permissions. Start '.
+ 'the server as the user you want it to run under.'),
+ 'notification.debug' => pht(
+ 'Notifications no longer have a dedicated debugging mode.'),
);
return $ancient_config;
diff --git a/src/applications/config/option/PhabricatorNotificationConfigOptions.php b/src/applications/config/option/PhabricatorNotificationConfigOptions.php
--- a/src/applications/config/option/PhabricatorNotificationConfigOptions.php
+++ b/src/applications/config/option/PhabricatorNotificationConfigOptions.php
@@ -36,23 +36,21 @@
'string',
'http://localhost:22281/')
->setDescription(pht('Location of the notification receiver server.')),
- $this->newOption('notification.user', 'string', null)
- ->setSummary(pht('Drop permissions to a less-privileged user.'))
- ->setDescription(
- pht(
- 'The notifcation server must be started as root so it can bind '.
- 'to privileged ports, but if you specify a system user here it '.
- 'will drop permissions to that user after binding to the ports '.
- 'it needs.')),
$this->newOption('notification.log', 'string', '/var/log/aphlict.log')
->setDescription(pht('Location of the server log file.')),
+ $this->newOption('notification.ssl-key', 'string', null)
+ ->setLocked(true)
+ ->setDescription(
+ pht('Path to SSL key to use for secure WebSockets.')),
+ $this->newOption('notification.ssl-cert', 'string', null)
+ ->setLocked(true)
+ ->setDescription(
+ pht('Path to SSL certificate to use for secure WebSockets.')),
$this->newOption(
'notification.pidfile',
'string',
- '/var/run/aphlict.pid')
+ '/var/tmp/aphlict/pid/aphlict.pid')
->setDescription(pht('Location of the server PID file.')),
- $this->newOption('notification.debug', 'bool', false)
- ->setDescription(pht('Enable debug output in the browser.')),
);
}
diff --git a/src/applications/notification/controller/PhabricatorNotificationTestController.php b/src/applications/notification/controller/PhabricatorNotificationTestController.php
--- a/src/applications/notification/controller/PhabricatorNotificationTestController.php
+++ b/src/applications/notification/controller/PhabricatorNotificationTestController.php
@@ -16,6 +16,11 @@
$viewer_phid = $viewer->getPHID();
+ // NOTE: Because we don't currently show you your own notifications, make
+ // sure this comes from a different PHID.
+ $application_phid = id(new PhabricatorNotificationsApplication())
+ ->getPHID();
+
// TODO: When it's easier to get these buttons to render as forms, this
// would be slightly nicer as a more standard isFormPost() check.
@@ -24,7 +29,7 @@
->setStoryType($story_type)
->setStoryData($story_data)
->setStoryTime(time())
- ->setStoryAuthorPHID($viewer_phid)
+ ->setStoryAuthorPHID($application_phid)
->setRelatedPHIDs(array($viewer_phid))
->setPrimaryObjectPHID($viewer_phid)
->setSubscribedPHIDs(array($viewer_phid))
diff --git a/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php b/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php
--- a/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php
+++ b/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php
@@ -38,7 +38,7 @@
->addCommand(
pht(
"(To start the server, run this command.)\n".
- "phabricator/ $ sudo ./bin/aphlict start"));
+ "phabricator/ $ ./bin/aphlict start"));
return;
}
@@ -57,7 +57,7 @@
->setShortName(pht('Notification Server Version'))
->setName(pht('Notification Server Out of Date'))
->setMessage($message)
- ->addCommand('phabricator/ $ sudo ./bin/aphlict restart');
+ ->addCommand('phabricator/ $ ./bin/aphlict restart');
}
}
diff --git a/src/applications/notification/view/PhabricatorNotificationStatusView.php b/src/applications/notification/view/PhabricatorNotificationStatusView.php
--- a/src/applications/notification/view/PhabricatorNotificationStatusView.php
+++ b/src/applications/notification/view/PhabricatorNotificationStatusView.php
@@ -13,18 +13,8 @@
'nodeID' => $this->getID(),
'pht' => array(
'setup' => pht('Setting Up Client'),
- 'start' => pht('Starting Client'),
- 'ready' => pht('Ready to Connect'),
- 'connecting' => pht('Connecting...'),
- 'connected' => pht('Connected'),
- 'error' => pht('Connection Error'),
- 'client' => pht('Connected Locally'),
-
- 'error.flash.xdomain' => pht(
- 'Unable to connect to Flash Policy Server. Check that the '.
- 'notification server is running and port 843 is not firewalled.'),
- 'error.flash.disconnected' => pht(
- 'Disconnected from notification server.'),
+ 'open' => pht('Connected'),
+ 'closed' => pht('Disconnected'),
),
));
diff --git a/src/docs/user/configuration/notifications.diviner b/src/docs/user/configuration/notifications.diviner
--- a/src/docs/user/configuration/notifications.diviner
+++ b/src/docs/user/configuration/notifications.diviner
@@ -3,7 +3,8 @@
Guide to setting up notifications.
-= Overview =
+Overview
+========
By default, Phabricator delivers information about events (like users creating
tasks or commenting on code reviews) through email and in-application
@@ -20,61 +21,95 @@
This document describes the process in detail.
-= Running the Aphlict Server =
-Phabricator implements realtime notifications using a Node.js server called
-"Aphlict". To run it:
+Supported Browsers
+==================
- - Install node.js.
- - Run `bin/aphlict start` (this script must be run as root).
+Notifications are supported for browsers which support WebSockets. This covers
+most modern browsers (like Chrome, Firefox, Safari, and recent versions of
+Internet Explorer) and many mobile browsers.
-The server must be able to listen on port **843** and port **22280** for Aphlict
-to work. You can change the latter port in the `notification.client-uri` config,
-but port 843 is used by Flash and can not be changed. In particular, if you're
-running in EC2, you need to unblock both of these ports in the server's security
-group configuration.
+IE8 and IE9 do not support WebSockets, so real-time notifications won't work in
+those browsers.
-You may want to adjust these settings:
+
+Installing Node and Modules
+===========================
+
+The notification server uses Node.js, so you'll need to install it first.
+
+To install Node.js, follow the instructions on
+[[ http://nodejs.org | nodejs.org ]].
+
+You will also need to install the `ws` module for Node. After installing
+Node, run `npm install -g ws` to install it.
+
+ name="(Option 1, Recommended) Install 'ws' Module Globally"
+ $ npm install -g ws # Global Install
+
+If you prefer, you can also install it locally in the `support/aphlict/server/`
+directory:
+
+ name="(Option 2) Install 'ws' Module Locally"
+ phabricator/support/aphlict/server/ $ npm install ws
+
+Once Node.js and the `ws` module are installed, you're ready to start the
+server.
+
+
+Running the Aphlict Server
+==========================
+
+After installing Node.js, you can control the notification server with the
+`bin/aphlict` command. To start the server:
+
+ phabricator/ $ bin/aphlict start
+
+The server must be able to listen on port **22280** for Aphlict to work. In
+particular, if you're running in EC2, you need to unblock this port in the
+server's security group configuration. You can change this port in the
+`notification.client-uri` config.
+
+You may need to adjust these settings:
+
+ - `notification.ssl-cert` Point this at an SSL certificate for secure
+ WebSockets.
+ - `notification.ssl-key` Point this at an SSL keyfile for secure WebSockets.
+
+In particular, if your server uses HTTPS, you **must** configure these options.
+Browsers will not allow you to use non-SSL websockets from an SSL web page.
+
+You may also want to adjust these settings:
- `notification.client-uri` Externally-facing host and port that browsers will
connect to in order to listen for notifications.
- `notification.server-uri` Internally-facing host and port that Phabricator
will connect to in order to publish notifications.
- `notification.log` Log file location for the server.
- - `notification.user` Non-root user to drop permissions to after binding to
- privileged ports.
- `notification.pid` Pidfile location used to stop any running server when
aphlict is restarted.
-In most cases, the defaults are appropriate, except that you should set
-`notification.user` to some valid system user so Aphlict isn't running as root.
-== Verifying Server Status ==
+Verifying Server Status
+=======================
Access `/notification/status/` to verify the server is operational. You should
see a table showing stats like "uptime" and connection/message counts if the
server is working. If it isn't working, you should see an error.
-== Testing the Server ==
+You can also send a test notification by clicking the button in the upper right
+corner of this screen.
-The easiest way to test the server is to have two users login and comment on
-the same Maniphest Task or Differential Revision. They should receive in-browser
-notifications about the other user's activity.
-NOTE: This is cumbersome. There will be better testing tools at some point.
-
-== Debugging Server Problems ==
+Troubleshooting
+===============
You can run `aphlict` in the foreground to get output to your console:
- phabricator/ $ sudo ./bin/aphlict debug
-
-You can run `support/aphlict/client/aphlict_test_client.php` to connect to the
-Aphlict server from the command line. Messages the client receives will be
-printed to stdout.
+ phabricator/ $ ./bin/aphlict debug
-You can set `notification.debug` in your configuration to get additional
-output in your browser.
+Because the notification server uses WebSockets, your browser error console
+may also have information that is useful in figuring out what's wrong.
The server also generates a log, by default in `/var/log/aphlict.log`. You can
change this location by changing `notification.log` in your configuration. The
diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php
--- a/src/view/page/PhabricatorStandardPageView.php
+++ b/src/view/page/PhabricatorStandardPageView.php
@@ -371,9 +371,6 @@
if (PhabricatorEnv::getEnvConfig('notification.enabled')) {
if ($user && $user->isLoggedIn()) {
- $aphlict_object_id = celerity_generate_unique_node_id();
- $aphlict_container_id = celerity_generate_unique_node_id();
-
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
$client_uri = new PhutilURI($client_uri);
if ($client_uri->getDomain() == 'localhost') {
@@ -382,37 +379,24 @@
$client_uri->setDomain($this_host->getDomain());
}
- $map = CelerityResourceMap::getNamedInstance('phabricator');
- $swf_uri = $response->getURI($map, 'rsrc/swf/aphlict.swf', true);
-
- $enable_debug = PhabricatorEnv::getEnvConfig('notification.debug');
-
$subscriptions = $this->pageObjects;
if ($user) {
$subscriptions[] = $user->getPHID();
}
+ if ($request->isHTTPS()) {
+ $client_uri->setProtocol('wss');
+ } else {
+ $client_uri->setProtocol('ws');
+ }
+
Javelin::initBehavior(
'aphlict-listen',
array(
- 'id' => $aphlict_object_id,
- 'containerID' => $aphlict_container_id,
- 'server' => $client_uri->getDomain(),
- 'port' => $client_uri->getPort(),
- 'debug' => $enable_debug,
- 'swfURI' => $swf_uri,
+ 'websocketURI' => (string)$client_uri,
'pageObjects' => array_fill_keys($this->pageObjects, true),
'subscriptions' => $subscriptions,
));
-
- $tail[] = phutil_tag(
- 'div',
- array(
- 'id' => $aphlict_container_id,
- 'style' =>
- 'position: absolute; width: 0; height: 0; overflow: hidden;',
- ),
- '');
}
}
diff --git a/support/aphlict/client/aphlict_test_client.php b/support/aphlict/client/aphlict_test_client.php
deleted file mode 100755
--- a/support/aphlict/client/aphlict_test_client.php
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-$root = dirname(dirname(dirname(dirname(__FILE__))));
-require_once $root.'/scripts/__init_script__.php';
-
-$args = new PhutilArgumentParser($argv);
-$args->setTagline('test client for Aphlict server');
-$args->setSynopsis(<<<EOHELP
-**aphlict_test_client.php** [__options__]
- Connect to the Aphlict server configured in the Phabricator config.
-
-EOHELP
-);
-$args->parseStandardArguments();
-$args->parse(
- array(
- array(
- 'name' => 'server',
- 'param' => 'uri',
- 'default' => PhabricatorEnv::getEnvConfig('notification.client-uri'),
- 'help' => 'Connect to __uri__ instead of the default server.',
- ),
- ));
-$console = PhutilConsole::getConsole();
-
-$errno = null;
-$errstr = null;
-
-$uri = $args->getArg('server');
-$uri = new PhutilURI($uri);
-$uri->setProtocol('tcp');
-
-$console->writeErr("Connecting...\n");
-$socket = stream_socket_client(
- $uri,
- $errno,
- $errstr);
-
-if (!$socket) {
- $console->writeErr(
- "Unable to connect to Aphlict (at '$uri'). Error #{$errno}: {$errstr}");
- exit(1);
-} else {
- $console->writeErr("Connected.\n");
-}
-
-$io_channel = new PhutilSocketChannel($socket);
-$proto_channel = new PhutilJSONProtocolChannel($io_channel);
-
-$json = new PhutilJSON();
-while (true) {
- $message = $proto_channel->waitForMessage();
- $console->writeOut($json->encodeFormatted($message));
-}
diff --git a/support/aphlict/client/src/Aphlict.as b/support/aphlict/client/src/Aphlict.as
deleted file mode 100644
--- a/support/aphlict/client/src/Aphlict.as
+++ /dev/null
@@ -1,47 +0,0 @@
-package {
-
- import flash.display.Sprite;
- import flash.external.ExternalInterface;
- import flash.net.LocalConnection;
-
-
- public class Aphlict extends Sprite {
-
- /**
- * A transport channel used to receive data.
- */
- protected var recv:LocalConnection;
-
- /**
- * A transport channel used to send data.
- */
- protected var send:LocalConnection;
-
-
- public function Aphlict() {
- super();
-
- this.recv = new LocalConnection();
- this.recv.client = this;
-
- this.send = new LocalConnection();
- }
-
- final protected function externalInvoke(
- type:String,
- object:Object = null):void {
-
- ExternalInterface.call('JX.Aphlict.didReceiveEvent', type, object);
- }
-
- final protected function error(error:Object):void {
- this.externalInvoke('error', error.toString());
- }
-
- final protected function log(message:String):void {
- this.externalInvoke('log', message);
- }
-
- }
-
-}
diff --git a/support/aphlict/client/src/AphlictClient.as b/support/aphlict/client/src/AphlictClient.as
deleted file mode 100644
--- a/support/aphlict/client/src/AphlictClient.as
+++ /dev/null
@@ -1,160 +0,0 @@
-package {
-
- import flash.events.TimerEvent;
- import flash.external.ExternalInterface;
- import flash.utils.Dictionary;
- import flash.utils.Timer;
- import flash.events.UncaughtErrorEvent;
-
- final public class AphlictClient extends Aphlict {
-
- /**
- * The connection name for this client. This will be used for the
- * @{class:LocalConnection} object.
- */
- private var client:String;
-
- /**
- * The expiry timestamp for the @{class:AphlictMaster}. If this time is
- * elapsed then the master will be assumed to be dead and another
- * @{class:AphlictClient} will create a master.
- */
- private var expiry:Number = 0;
-
- /**
- * The interval at which to ping the @{class:AphlictMaster}.
- */
- public static const INTERVAL:Number = 3000;
-
- private var master:AphlictMaster;
- private var timer:Timer;
-
- private var remoteServer:String;
- private var remotePort:Number;
- private var subscriptions:Array;
-
-
- public function AphlictClient() {
- super();
-
- loaderInfo.uncaughtErrorEvents.addEventListener(
- UncaughtErrorEvent.UNCAUGHT_ERROR,
- this.uncaughtErrorHandler);
-
- ExternalInterface.marshallExceptions = true;
- ExternalInterface.addCallback('connect', this.externalConnect);
-
- this.setStatus('ready');
- }
-
- private function uncaughtErrorHandler(event:UncaughtErrorEvent):void {
- this.error(event.error.toString());
- }
-
- public function externalConnect(
- server:String,
- port:Number,
- subscriptions:Array):void {
-
- this.remoteServer = server;
- this.remotePort = port;
- this.subscriptions = subscriptions;
-
- this.client = AphlictClient.generateClientId();
- this.recv.connect(this.client);
-
- this.timer = new Timer(AphlictClient.INTERVAL);
- this.timer.addEventListener(TimerEvent.TIMER, this.keepalive);
-
- this.connectToMaster();
- }
-
- /**
- * Generate a unique identifier that will be used to communicate with the
- * @{class:AphlictMaster}.
- */
- private static function generateClientId():String {
- return 'aphlict_client_' + Math.round(Math.random() * 100000);
- }
-
- /**
- * Create a new connection to the @{class:AphlictMaster}.
- *
- * If there is no current @{class:AphlictMaster} instance, then a new master
- * will be created.
- */
- private function connectToMaster():void {
- this.timer.stop();
-
- // Try to become the master.
- try {
- this.log('Attempting to become the master...');
- this.master = new AphlictMaster(this.remoteServer, this.remotePort);
- this.log('I am the master.');
- } catch (err:ArgumentError) {
- this.log('Cannot become the master... probably one already exists');
- } catch (err:Error) {
- this.error(err);
- }
-
- this.registerWithMaster();
- this.timer.start();
- }
-
- /**
- * Register our client ID with the @{class:AphlictMaster} and send our
- * subscriptions.
- */
- private function registerWithMaster():void {
- this.send.send('aphlict_master', 'register', this.client);
- this.expiry = new Date().getTime() + (5 * AphlictClient.INTERVAL);
- this.log('Registered client ' + this.client);
-
- // Send subscriptions to master.
- this.log('Sending subscriptions to master.');
- this.send.send(
- 'aphlict_master',
- 'subscribe',
- this.client,
- this.subscriptions);
- }
-
- /**
- * Send a keepalive signal to the @{class:AphlictMaster}.
- *
- * If the connection to the master has expired (because the master has not
- * sent a heartbeat signal), then a new connection to master will be
- * created.
- */
- private function keepalive(event:TimerEvent):void {
- if (new Date().getTime() > this.expiry) {
- this.connectToMaster();
- }
-
- this.send.send('aphlict_master', 'ping', this.client);
- }
-
- /**
- * This function is used to receive the heartbeat signal from the
- * @{class:AphlictMaster}.
- */
- public function pong():void {
- this.expiry = new Date().getTime() + (2 * AphlictClient.INTERVAL);
- }
-
- /**
- * Receive a message from the Aphlict Server, via the
- * @{class:AphlictMaster}.
- */
- public function receiveMessage(msg:Object):void {
- this.log('Received message.');
- this.externalInvoke('receive', msg);
- }
-
- public function setStatus(status:String, code:String = null):void {
- this.externalInvoke('status', {type: status, code: code});
- }
-
- }
-
-}
diff --git a/support/aphlict/client/src/AphlictMaster.as b/support/aphlict/client/src/AphlictMaster.as
deleted file mode 100644
--- a/support/aphlict/client/src/AphlictMaster.as
+++ /dev/null
@@ -1,312 +0,0 @@
-package {
-
- import flash.events.Event;
- import flash.events.IOErrorEvent;
- import flash.events.ProgressEvent;
- import flash.events.SecurityErrorEvent;
- import flash.events.TimerEvent;
- import flash.net.Socket;
- import flash.utils.ByteArray;
- import flash.utils.Dictionary;
- import flash.utils.Timer;
- import vegas.strings.JSON;
-
-
- final public class AphlictMaster extends Aphlict {
-
- /**
- * The pool of connected clients.
- */
- private var clients:Dictionary;
-
- /**
- * A timer used to trigger periodic events.
- */
- private var timer:Timer;
-
- /**
- * The interval after which clients will be considered dead and removed
- * from the pool.
- */
- public static const PURGE_INTERVAL:Number = 3 * AphlictClient.INTERVAL;
-
- /**
- * The hostname for the Aphlict Server.
- */
- private var remoteServer:String;
-
- /**
- * The port number for the Aphlict Server.
- */
- private var remotePort:Number;
-
- /**
- * A dictionary mapping PHID to subscribed clients.
- */
- private var subscriptions:Dictionary;
-
- private var socket:Socket;
- private var readBuffer:ByteArray;
-
- private var status:String;
- private var statusCode:String;
-
-
- public function AphlictMaster(server:String, port:Number) {
- super();
-
- this.remoteServer = server;
- this.remotePort = port;
-
- this.clients = new Dictionary();
- this.subscriptions = new Dictionary();
-
- // Connect to the Aphlict Server.
- this.recv.connect('aphlict_master');
- this.connectToServer();
-
- // Start a timer and regularly purge dead clients.
- this.timer = new Timer(AphlictMaster.PURGE_INTERVAL);
- this.timer.addEventListener(TimerEvent.TIMER, this.purgeClients);
- this.timer.start();
- }
-
- /**
- * Register a @{class:AphlictClient}.
- */
- public function register(client:String):void {
- if (!this.clients[client]) {
- this.log('Registering client: ' + client);
- this.clients[client] = new Date().getTime();
-
- this.send.send(client, 'setStatus', this.status, this.statusCode);
- }
- }
-
- /**
- * Purge stale client connections from the client pool.
- */
- private function purgeClients(event:TimerEvent):void {
- for (var client:String in this.clients) {
- var checkin:Number = this.clients[client];
-
- if (new Date().getTime() - checkin > AphlictMaster.PURGE_INTERVAL) {
- this.log('Purging client: ' + client);
- delete this.clients[client];
-
- this.log('Removing client subscriptions: ' + client);
- this.unsubscribeAll(client);
- }
- }
- }
-
- /**
- * Clients will regularly "ping" the master to let us know that they are
- * still alive. We will "pong" them back to let the client know that the
- * master is still alive.
- */
- public function ping(client:String):void {
- this.clients[client] = new Date().getTime();
- this.send.send(client, 'pong');
- }
-
- private function connectToServer():void {
- this.setStatusOnClients('connecting');
-
- var socket:Socket = new Socket();
-
- socket.addEventListener(Event.CONNECT, didConnectSocket);
- socket.addEventListener(Event.CLOSE, didCloseSocket);
- socket.addEventListener(ProgressEvent.SOCKET_DATA, didReceiveSocket);
-
- socket.addEventListener(IOErrorEvent.IO_ERROR, didIOErrorSocket);
- socket.addEventListener(
- SecurityErrorEvent.SECURITY_ERROR,
- didSecurityErrorSocket);
-
- socket.connect(this.remoteServer, this.remotePort);
-
- this.readBuffer = new ByteArray();
- this.socket = socket;
- }
-
- private function didConnectSocket(event:Event):void {
- this.setStatusOnClients('connected');
-
- // Send subscriptions
- var phids = new Array();
- for (var phid:String in this.subscriptions) {
- phids.push(phid);
- }
-
- if (phids.length) {
- this.sendSubscribeCommand(phids);
- }
- }
-
- private function didCloseSocket(event:Event):void {
- this.setStatusOnClients('error', 'error.flash.disconnected');
- }
-
- private function didIOErrorSocket(event:IOErrorEvent):void {
- this.externalInvoke('error', event.text);
- }
-
- private function didSecurityErrorSocket(event:SecurityErrorEvent):void {
- var text = event.text;
-
- // This is really gross but there doesn't seem to be anything else
- // on the object which gives us an error code.
- if (text.match(/^Error #2048/)) {
- this.setStatusOnClients('error', 'error.flash.xdomain');
- }
-
- this.error(text);
- }
-
- public function subscribe(client:String, phids:Array):void {
- var newPHIDs = new Array();
-
- for (var i:String in phids) {
- var phid = phids[i];
- if (!this.subscriptions[phid]) {
- this.subscriptions[phid] = new Dictionary();
- newPHIDs.push(phid);
- }
- this.subscriptions[phid][client] = true;
- }
-
- if (newPHIDs.length) {
- this.sendSubscribeCommand(newPHIDs);
- }
- }
-
- private function getSubscriptions(client:String):Array {
- var subscriptions = new Array();
-
- for (var phid:String in this.subscriptions) {
- var clients = this.subscriptions[phid];
- if (clients[client]) {
- subscriptions.push(phid);
- }
- }
-
- return subscriptions;
- }
-
- public function unsubscribeAll(client:String):void {
- this.unsubscribe(client, this.getSubscriptions(client));
- }
-
- public function unsubscribe(client:String, phids:Array):void {
- var oldPHIDs = new Array();
-
- for (var i:String in phids) {
- var phid = phids[i];
-
- if (!this.subscriptions[phid]) {
- continue;
- }
-
- delete this.subscriptions[phid][client];
-
- var empty = true;
- for (var key:String in this.subscriptions[phid]) {
- empty = false;
- }
-
- if (empty) {
- delete this.subscriptions[phid];
- oldPHIDs.push(phid);
- }
- }
-
- if (oldPHIDs.length) {
- this.sendUnsubscribeCommand(oldPHIDs);
- }
- }
-
- private function sendSubscribeCommand(phids:Array):void {
- var msg:Dictionary = new Dictionary();
- msg['command'] = 'subscribe';
- msg['data'] = phids;
-
- this.log('Sending subscribe command to server.');
- this.socket.writeUTF(vegas.strings.JSON.serialize(msg));
- this.socket.flush();
- }
-
- private function sendUnsubscribeCommand(phids:Array):void {
- var msg:Dictionary = new Dictionary();
- msg['command'] = 'unsubscribe';
- msg['data'] = phids;
-
- this.log('Sending subscribe command to server.');
- this.socket.writeUTF(vegas.strings.JSON.serialize(msg));
- this.socket.flush();
- }
-
- private function didReceiveSocket(event:Event):void {
- try {
- var b:ByteArray = this.readBuffer;
- this.socket.readBytes(b, b.length);
-
- do {
- b = this.readBuffer;
- b.position = 0;
-
- if (b.length <= 8) {
- break;
- }
-
- var msg_len:Number = parseInt(b.readUTFBytes(8), 10);
- if (b.length >= msg_len + 8) {
- var bytes:String = b.readUTFBytes(msg_len);
- var data:Object = vegas.strings.JSON.deserialize(bytes);
- var t:ByteArray = new ByteArray();
- t.writeBytes(b, msg_len + 8);
- this.readBuffer = t;
-
- // Send the message to all clients.
- for (var client:String in this.clients) {
- var subscribed = false;
-
- for (var i:String in data.subscribers) {
- var phid = data.subscribers[i];
-
- if (this.subscriptions[phid] &&
- this.subscriptions[phid][client]) {
- subscribed = true;
- break;
- }
- }
-
- if (subscribed) {
- this.log('Sending message to client: ' + client);
- this.send.send(client, 'receiveMessage', data);
- }
- }
- } else {
- break;
- }
- } while (true);
- } catch (err:Error) {
- this.error(err);
- }
- }
-
- private function setStatusOnClients(
- status:String,
- code:String = null):void {
-
- this.status = status;
- this.statusCode = code;
-
- for (var client:String in this.clients) {
- this.send.send(client, 'setStatus', status, code);
- }
- }
-
- }
-
-}
diff --git a/support/aphlict/server/aphlict_server.js b/support/aphlict/server/aphlict_server.js
--- a/support/aphlict/server/aphlict_server.js
+++ b/support/aphlict/server/aphlict_server.js
@@ -1,14 +1,9 @@
-/**
- * Notification server. Launch with:
- *
- * sudo node aphlict_server.js --user=aphlict
- *
- * You can also specify `port`, `admin`, `host` and `log`.
- */
-
var JX = require('./lib/javelin').JX;
+var http = require('http');
+var https = require('https');
+var util = require('util');
+var fs = require('fs');
-JX.require('lib/AphlictFlashPolicyServer', __dirname);
JX.require('lib/AphlictListenerList', __dirname);
JX.require('lib/AphlictLog', __dirname);
@@ -17,8 +12,10 @@
port: 22280,
admin: 22281,
host: '127.0.0.1',
- user: null,
- log: '/var/log/aphlict.log'
+ log: '/var/log/aphlict.log',
+ 'ssl-key': null,
+ 'ssl-certificate': null,
+ test: false
};
for (var ii = 2; ii < argv.length; ii++) {
@@ -42,124 +39,120 @@
var debug = new JX.AphlictLog()
.addConsole(console);
-var clients = new JX.AphlictListenerList();
-
var config = parse_command_line_arguments(process.argv);
+process.on('uncaughtException', function(err) {
+ debug.log('\n<<< UNCAUGHT EXCEPTION! >>>\n' + err.stack);
+ process.exit(1);
+});
+
+var WebSocket;
+try {
+ WebSocket = require('ws');
+} catch (ex) {
+ throw new Error(
+ 'You need to install the Node.js "ws" module for websocket support. ' +
+ 'Usually, you can do this with `npm install -g ws`. ' + ex.toString());
+}
+
+var ssl_config = {
+ enabled: (config['ssl-key'] || config['ssl-cert'])
+};
+
+// Load the SSL certificates (if any were provided) now, so that runs with
+// `--test` will see any errors.
+if (ssl_config.enabled) {
+ ssl_config.key = fs.readFileSync(config['ssl-key']);
+ ssl_config.cert = fs.readFileSync(config['ssl-cert']);
+}
+
+// Add the logfile so we'll fail if we can't write to it.
if (config.logfile) {
debug.addLogfile(config.logfile);
}
-if (process.getuid() !== 0) {
- console.log(
- "ERROR: " +
- "This server must be run as root because it needs to bind to privileged " +
- "port 843 to start a Flash policy server. It will downgrade to run as a " +
- "less-privileged user after binding if you pass a user in the command " +
- "line arguments with '--user=alincoln'.");
- process.exit(1);
+// If we're just doing a configuration test, exit here before starting any
+// servers.
+if (config.test) {
+ debug.log('Configuration test OK.');
+ process.exit(0);
}
-var net = require('net');
-var http = require('http');
+var start_time = new Date().getTime();
+var messages_out = 0;
+var messages_in = 0;
-process.on('uncaughtException', function(err) {
- debug.log('\n<<< UNCAUGHT EXCEPTION! >>>\n' + err.stack);
+var clients = new JX.AphlictListenerList();
- process.exit(1);
-});
+function https_discard_handler(req, res) {
+ res.writeHead(501);
+ res.end('HTTP/501 Use Websockets\n');
+}
-new JX.AphlictFlashPolicyServer()
- .setDebugLog(debug)
- .setAccessPort(config.port)
- .start();
-
-
-net.createServer(function(socket) {
- var listener = clients.addListener(socket);
-
- debug.log('<%s> Connected from %s',
- listener.getDescription(),
- socket.remoteAddress);
-
- var buffer = new Buffer([]);
- var length = 0;
-
- socket.on('data', function(data) {
- buffer = Buffer.concat([buffer, new Buffer(data)]);
-
- while (buffer.length) {
- if (!length) {
- length = buffer.readUInt16BE(0);
- buffer = buffer.slice(2);
- }
-
- if (buffer.length < length) {
- // We need to wait for the rest of the data.
- return;
- }
-
- var message;
- try {
- message = JSON.parse(buffer.toString('utf8', 0, length));
- } catch (err) {
- debug.log('<%s> Received invalid data.', listener.getDescription());
- continue;
- } finally {
- buffer = buffer.slice(length);
- length = 0;
- }
-
- debug.log('<%s> Received data: %s',
- listener.getDescription(),
- JSON.stringify(message));
-
- switch (message.command) {
- case 'subscribe':
- debug.log(
- '<%s> Subscribed to: %s',
- listener.getDescription(),
- JSON.stringify(message.data));
- listener.subscribe(message.data);
- break;
+var ws;
+if (ssl_config.enabled) {
+ var https_server = https.createServer({
+ key: ssl_config.key,
+ cert: ssl_config.cert
+ }, https_discard_handler).listen(config.port);
- case 'unsubscribe':
- debug.log(
- '<%s> Unsubscribed from: %s',
- listener.getDescription(),
- JSON.stringify(message.data));
- listener.unsubscribe(message.data);
- break;
-
- default:
- debug.log('<s> Unrecognized command.', listener.getDescription());
- }
- }
- });
+ ws = new WebSocket.Server({server: https_server});
+} else {
+ ws = new WebSocket.Server({port: config.port});
+}
- socket.on('close', function() {
- clients.removeListener(listener);
- debug.log('<%s> Disconnected', listener.getDescription());
- });
+ws.on('connection', function(ws) {
+ var listener = clients.addListener(ws);
- socket.on('timeout', function() {
- debug.log('<%s> Timed Out', listener.getDescription());
- });
+ function log() {
+ debug.log(
+ util.format('<%s>', listener.getDescription()) +
+ ' ' +
+ util.format.apply(null, arguments));
+ }
- socket.on('end', function() {
- debug.log('<%s> Ended Connection', listener.getDescription());
- });
+ log('Connected from %s.', ws._socket.remoteAddress);
- socket.on('error', function(e) {
- debug.log('<%s> Error: %s', listener.getDescription(), e);
- });
+ ws.on('message', function(data) {
+ log('Received message: %s', data);
-}).listen(config.port);
+ var message;
+ try {
+ message = JSON.parse(data);
+ } catch (err) {
+ log('Message is invalid: %s', err.message);
+ return;
+ }
+ switch (message.command) {
+ case 'subscribe':
+ log(
+ 'Subscribed to: %s',
+ JSON.stringify(message.data));
+ listener.subscribe(message.data);
+ break;
+
+ case 'unsubscribe':
+ log(
+ 'Unsubscribed from: %s',
+ JSON.stringify(message.data));
+ listener.unsubscribe(message.data);
+ break;
+
+ default:
+ log('Unrecognized command "%s".', message.command || '<undefined>');
+ }
+ });
-var messages_out = 0;
-var messages_in = 0;
-var start_time = new Date().getTime();
+ ws.on('close', function() {
+ clients.removeListener(listener);
+ log('Disconnected.');
+ });
+
+ ws.on('error', function(err) {
+ log('Error: %s', err.message);
+ });
+});
function transmit(msg) {
var listeners = clients.getListeners().filter(function(client) {
@@ -195,7 +188,7 @@
try {
var msg = JSON.parse(body);
- debug.log('notification: ' + JSON.stringify(msg));
+ debug.log('Received notification: ' + JSON.stringify(msg));
++messages_in;
try {
@@ -242,10 +235,4 @@
}
}).listen(config.admin, config.host);
-// If we're configured to drop permissions, get rid of them now that we've
-// bound to the ports we need and opened logfiles.
-if (config.user) {
- process.setuid(config.user);
-}
-
debug.log('Started Server (PID %d)', process.pid);
diff --git a/support/aphlict/server/lib/AphlictFlashPolicyServer.js b/support/aphlict/server/lib/AphlictFlashPolicyServer.js
deleted file mode 100644
--- a/support/aphlict/server/lib/AphlictFlashPolicyServer.js
+++ /dev/null
@@ -1,68 +0,0 @@
-var JX = require('javelin').JX;
-
-var net = require('net');
-
-/**
- * Server which handles cross-domain policy requests for Flash.
- *
- * var server = new AphlictFlashPolicyServer()
- * .setAccessPort(9999)
- * .start();
- */
-JX.install('AphlictFlashPolicyServer', {
-
- members: {
- _server: null,
- _port: 843,
- _accessPort: null,
- _debug: null,
-
- setDebugLog: function(log) {
- this._debug = log;
- return this;
- },
-
- setAccessPort: function(port) {
- this._accessPort = port;
- return this;
- },
-
- start: function() {
- this._server = net.createServer(JX.bind(this, this._didConnect));
- this._server.listen(this._port);
- return this;
- },
-
- _didConnect: function(socket) {
- this._log('<FlashPolicy> Policy Request From %s', socket.remoteAddress);
-
- socket.on('error', JX.bind(this, this._didSocketError, socket));
-
- socket.write(this._getFlashPolicyResponse());
- socket.end();
- },
-
- _didSocketError: function(socket, error) {
- this._log('<FlashPolicy> Socket Error: %s', error);
- },
-
- _log: function() {
- this._debug && this._debug.log.apply(this._debug, arguments);
- },
-
- _getFlashPolicyResponse: function() {
- var policy = [
- '<?xml version="1.0"?>',
- '<!DOCTYPE cross-domain-policy SYSTEM ' +
- '"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">',
- '<cross-domain-policy>',
- '<allow-access-from domain="*" to-ports="' + this._accessPort + '"/>',
- '</cross-domain-policy>'
- ];
-
- return policy.join('\n') + '\0';
- }
-
- }
-
-});
diff --git a/support/aphlict/server/lib/AphlictListener.js b/support/aphlict/server/lib/AphlictListener.js
--- a/support/aphlict/server/lib/AphlictListener.js
+++ b/support/aphlict/server/lib/AphlictListener.js
@@ -49,15 +49,7 @@
},
writeMessage: function(message) {
- var serial = JSON.stringify(message);
-
- var length = Buffer.byteLength(serial, 'utf8');
- length = length.toString();
- while (length.length < 8) {
- length = '0' + length;
- }
-
- this._socket.write(length + serial);
+ this._socket.send(JSON.stringify(message));
}
}
diff --git a/webroot/rsrc/js/application/aphlict/Aphlict.js b/webroot/rsrc/js/application/aphlict/Aphlict.js
--- a/webroot/rsrc/js/application/aphlict/Aphlict.js
+++ b/webroot/rsrc/js/application/aphlict/Aphlict.js
@@ -2,39 +2,31 @@
* @provides javelin-aphlict
* @requires javelin-install
* javelin-util
+ * javelin-websocket
+ * javelin-leader
+ * javelin-json
*/
/**
- * Simple JS API for the Flash Aphlict client. Example usage:
+ * Client for the notification server. Example usage:
*
- * var aphlict = new JX.Aphlict('aphlict_swf', '127.0.0.1', 22280)
- * .setHandler(function(type, message) {
- * JX.log("Got " + type + " event!")
+ * var aphlict = new JX.Aphlict('ws://localhost:22280', subscriptions)
+ * .setHandler(function(message) {
+ * // ...
* })
* .start();
*
- * Your handler will receive these events:
- *
- * - `connect` The client initiated a connection to the server.
- * - `connected` The client completed a connection to the server.
- * - `close` The client disconnected from the server.
- * - `error` There was an error.
- * - `receive` Received a message from the server.
- *
- * You do not have to handle any of them in any specific way.
*/
JX.install('Aphlict', {
- construct: function(id, server, port, subscriptions) {
+ construct: function(uri, subscriptions) {
if (__DEV__) {
if (JX.Aphlict._instance) {
JX.$E('Aphlict object is a singleton.');
}
}
- this._id = id;
- this._server = server;
- this._port = port;
+ this._uri = uri;
this._subscriptions = subscriptions;
this._setStatus('setup');
@@ -44,7 +36,6 @@
events: ['didChangeStatus'],
members: {
- _id: null,
_server: null,
_port: null,
_subscriptions: null,
@@ -52,47 +43,92 @@
_statusCode: null,
start: function(node, uri) {
- this._setStatus('start');
-
- // NOTE: This is grotesque, but seems to work everywhere.
- node.innerHTML =
- '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000">' +
- '<param name="movie" value="' + uri + '" />' +
- '<param name="allowScriptAccess" value="always" />' +
- '<param name="wmode" value="opaque" />' +
- '<embed src="' + uri + '" wmode="opaque"' +
- 'width="0" height="0" id="' + this._id + '">' +
- '</embed>' +
- '</object>';
+ JX.Leader.listen('onBecomeLeader', JX.bind(this, this._lead));
+ JX.Leader.listen('onReceiveBroadcast', JX.bind(this, this._receive));
+ JX.Leader.start();
+
+ JX.Leader.call(JX.bind(this, this._begin));
+ },
+
+ getStatus: function() {
+ return this._status;
},
- _didStartFlash: function() {
- var id = this._id;
+ _begin: function() {
+ JX.Leader.broadcast(
+ null,
+ {type: 'aphlict.getstatus'});
+ JX.Leader.broadcast(
+ null,
+ {type: 'aphlict.subscribe', data: this._subscriptions});
+ },
+
+ _lead: function() {
+ var socket = new JX.WebSocket(this._uri);
+ socket.setOpenHandler(JX.bind(this, this._open));
+ socket.setMessageHandler(JX.bind(this, this._message));
+ socket.setCloseHandler(JX.bind(this, this._close));
- // Flash puts its "objects" into global scope in an inconsistent way,
- // because it was written in like 1816 when globals were awesome and IE4
- // didn't support other scopes since global scope is the best anyway.
- var container = document[id] || window[id];
+ this._socket = socket;
- this._flashContainer = container;
- this._flashContainer.connect(
- this._server,
- this._port,
- this._subscriptions);
+ socket.open();
},
- getStatus: function() {
- return this._status;
+ _open: function() {
+ this._broadcastStatus('open');
+ JX.Leader.broadcast(null, {type: 'aphlict.getsubscribers'});
+ },
+
+ _close: function() {
+ this._broadcastStatus('closed');
+ },
+
+ _broadcastStatus: function(status) {
+ JX.Leader.broadcast(null, {type: 'aphlict.status', data: status});
+ },
+
+ _message: function(raw) {
+ var message = JX.JSON.parse(raw);
+ JX.Leader.broadcast(null, {type: 'aphlict.server', data: message});
},
- getStatusCode: function() {
- return this._statusCode;
+ _receive: function(message, is_leader) {
+ switch (message.type) {
+ case 'aphlict.status':
+ this._setStatus(message.data);
+ break;
+ case 'aphlict.getstatus':
+ if (is_leader) {
+ this._broadcastStatus(this.getStatus());
+ }
+ break;
+ case 'aphlict.getsubscribers':
+ JX.Leader.broadcast(
+ null,
+ {type: 'aphlict.subscribe', data: this._subscriptions});
+ break;
+ case 'aphlict.subscribe':
+ if (is_leader) {
+ this._write({
+ command: 'subscribe',
+ data: message.data
+ });
+ }
+ break;
+ case 'aphlict.server':
+ var handler = this.getHandler();
+ handler && handler(message.data);
+ break;
+ }
},
- _setStatus: function(status, code) {
+ _setStatus: function(status) {
this._status = status;
- this._statusCode = code || null;
this.invoke('didChangeStatus');
+ },
+
+ _write: function(message) {
+ this._socket.send(JX.JSON.stringify(message));
}
},
@@ -110,28 +146,8 @@
return null;
}
return self._instance;
- },
-
- didReceiveEvent: function(type, message) {
- var client = JX.Aphlict.getInstance();
- if (!client) {
- return;
- }
-
- if (type == 'status') {
- client._setStatus(message.type, message.code);
- switch (message.type) {
- case 'ready':
- client._didStartFlash();
- break;
- }
- }
-
- var handler = client.getHandler();
- if (handler) {
- handler(type, message);
- }
}
+
}
});
diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js
--- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js
+++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js
@@ -41,22 +41,8 @@
// Respond to a notification from the Aphlict notification server. We send
// a request to Phabricator to get notification details.
- function onaphlictmessage(type, message) {
- switch (type) {
- case 'receive':
- JX.Stratcom.invoke('aphlict-receive-message', null, message);
- break;
-
- default:
- case 'error':
- case 'log':
- case 'status':
- if (config.debug) {
- var details = message ? JX.JSON.stringify(message) : '';
- JX.log('(Aphlict) [' + type + '] ' + details);
- }
- break;
- }
+ function onaphlictmessage(message) {
+ JX.Stratcom.invoke('aphlict-receive-message', null, message);
}
@@ -89,13 +75,11 @@
}
var client = new JX.Aphlict(
- config.id,
- config.server,
- config.port,
+ config.websocketURI,
config.subscriptions);
client
.setHandler(onaphlictmessage)
- .start(JX.$(config.containerID), config.swfURI);
+ .start();
});
diff --git a/webroot/rsrc/swf/aphlict.swf b/webroot/rsrc/swf/aphlict.swf
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001

File Metadata

Mime Type
text/plain
Expires
May 18 2024, 5:39 AM (4 w, 2 d ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/nb/xm/gram3wax7qw6bhq3
Default Alt Text
D11143.diff (125 KB)

Event Timeline