├── .gitattributes ├── .hgignore ├── LICENSE ├── README.md ├── haxelib.json ├── protohx ├── CommonError.hx ├── Message.hx ├── MessageUtils.hx ├── Protohx.hx ├── ReadUtils.hx ├── ReadingBuffer.hx ├── WireType.hx ├── WriteUtils.hx ├── WritingBuffer.hx └── ZigZag.hx ├── run.n ├── samples ├── 01-core │ ├── assets │ │ └── plugin_proto_input │ ├── build-as3.hxml │ ├── build-cpp-pure.hxml │ ├── build-cpp.hxml │ ├── build-cs.hxml │ ├── build-flash.hxml │ ├── build-java.hxml │ ├── build-js.hxml │ ├── build-neko.hxml │ ├── build-php.hxml │ ├── build-python.hxml │ ├── js-test.html │ ├── nme-generate-sources.hxml │ ├── project.xml │ ├── proto │ │ ├── google │ │ │ └── protobuf │ │ │ │ ├── compiler │ │ │ │ └── plugin.proto │ │ │ │ └── descriptor.proto │ │ └── test.proto │ ├── protohx.json │ └── src │ │ └── Main.hx ├── 02-ipc │ ├── build-all.sh │ ├── build-java.hxml │ ├── build-neko.hxml │ ├── build-php.hxml │ ├── build.xml │ ├── proto │ │ └── calc.proto │ ├── protohx-java.json │ ├── protohx.json │ ├── src-gen-java │ │ └── calc │ │ │ └── Calc.java │ └── src │ │ ├── HaxeMain.hx │ │ └── JavaMain.java ├── 03-network │ ├── README.md │ ├── build-client-flash.hxml │ ├── build-client-nodejs-net-bot.hxml │ ├── build-server-java.hxml │ ├── build-server-neko.hxml │ ├── build-server-nodejs-multi.hxml │ ├── build-server-nodejs-net.hxml │ ├── build-server-nodejs-socket-io.hxml │ ├── index.html │ ├── package.json │ ├── project.nmml │ ├── proto │ │ └── protocol.proto │ ├── protohx.json │ └── src │ │ ├── client │ │ └── MainClient.hx │ │ ├── common │ │ ├── Base64.hx │ │ ├── Config.hx │ │ ├── MsgQueue.hx │ │ └── SocketConnection.hx │ │ └── server │ │ ├── java │ │ └── MainServer.hx │ │ ├── logic │ │ ├── BakedMsg.hx │ │ ├── Session.hx │ │ └── SessionRegistry.hx │ │ ├── native │ │ └── MainServer.hx │ │ └── nodejs │ │ ├── BotClient.hx │ │ ├── MultiServer.hx │ │ ├── NetServer.hx │ │ ├── NodeUtils.hx │ │ └── SocketIoServer.hx └── 04-metadata │ ├── build-as3.hxml │ ├── build-cpp-pure.hxml │ ├── build-cs.hxml │ ├── build-flash.hxml │ ├── build-java.hxml │ ├── build-js.hxml │ ├── build-neko.hxml │ ├── build-php.hxml │ ├── build-python.hxml │ ├── nme-generate-sources.hxml │ ├── proto │ ├── google │ │ └── protobuf │ │ │ ├── compiler │ │ │ └── plugin.proto │ │ │ └── descriptor.proto │ └── test.proto │ ├── protohx.json │ └── src │ └── Main.hx └── tools ├── plugin ├── bin │ ├── plugin │ ├── plugin.bat │ └── plugin.jar ├── build.xml ├── libs-src │ └── protobuf-java-2.5.0-sources.jar ├── libs │ └── protobuf-java-2.5.0.jar ├── plugin.iml ├── proto │ └── google │ │ └── protobuf │ │ ├── compiler │ │ └── plugin.proto │ │ └── descriptor.proto ├── src-gen │ └── google │ │ └── protobuf │ │ └── compiler │ │ └── Plugin.java └── src │ └── protohx │ └── Proto2Haxe.java └── run ├── build.hxml └── src ├── CommandLineTools.hx └── Helpers.hx /.gitattributes: -------------------------------------------------------------------------------- 1 | * -crlf 2 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | .idea 3 | **/*.iml 4 | config.json 5 | samples/01-core/out 6 | samples/02-ipc/out 7 | samples/03-network/out 8 | samples/04-metadata/out 9 | *.iml 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, NetEase.com,Inc. 2 | Copyright (c) 2011, 杨博(Yang Bo) 3 | Copyright (c) 2013, Евгений Веретенников(Eugene Veretennikov) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Protohx is crossplatform implementation of "Google's Protocol Buffers" for haxe 3. 2 | 3 | This is partial port of ActionScript3 protoc plugin "protoc-gen-as3" for haxe. 4 | Currently implemented only basic functionality: read/write messages from/to haxe.io.Bytes. 5 | 6 | haxe 3 compatible. Core functionality doesn't depend on third-party libraries. 7 | 8 | ## License 9 | BSD 10 | 11 | 12 | ## See also 13 | * https://code.google.com/p/protobuf/ - Official Google Protocol Buffers page 14 | * https://github.com/Atry/protoc-gen-haxe - another haxe implementation from original "protoc-gen-as3" author 15 | * https://code.google.com/p/protoc-gen-as3/ - ActionScript 3 protoc plugin 16 | * https://github.com/david-alexander/protobuf-haxe - another haxe implementation (GPL) 17 | 18 | 19 | ## Supported Features 20 | ### This functionality ported from "protoc-gen-as3" 21 | * All basic types (int, int64, string, bytes, bool) 22 | * Nested messages 23 | * Enumerations (as integer) 24 | * Packed and non-packed repeated fields 25 | * Extensions (converted to optional fields) 26 | 27 | 28 | ## Tested targets 29 | * flash 30 | * neko 2.0 31 | * cpp (linux32, win32, android) 32 | * js 33 | * php 34 | * java 35 | * as3 36 | 37 | 38 | ## System requirements 39 | * haxe 3.1.3 40 | * neko 2.0 41 | * protoc 2.5.0 42 | * java 1.7 43 | * ant (for build plugin from sources) 44 | 45 | 46 | ## How to install 47 | 1) install protohx 48 | $ haxelib install protohx 49 | or 50 | $ haxelib hg protohx https://bitbucket.org/nitrobin/protohx 51 | or 52 | $ haxelib git protohx https://github.com/nitrobin/protohx 53 | 2) install protoc into system PATH 54 | * Windows: 55 | Download https://protobuf.googlecode.com/files/protoc-2.5.0-win32.zip 56 | Unpack and add protoc.exe location to system %PATH% 57 | * Ubuntu: 58 | $ sudo aptitude install protobuf-compiler 59 | * Other: 60 | Download source code from https://code.google.com/p/protobuf/downloads/list 61 | Unpack and make && make install. 62 | * NOTE: 63 | You also can set custom protoc executable with "setup-protoc" 64 | $ haxelib run protohx setup-protoc PROTOC_2_5_0_PATH 65 | For example: 66 | $ haxelib run protohx setup-protoc /home/user/opt/protobuf-2.5.0/src/protoc 67 | 68 | 69 | ## How to use 70 | 1) create empty json config file in project directory with "config" 71 | $ haxelib run protohx config protohx.json 72 | Change and save protohx.json 73 | // File: samples/test-core/protohx.json 74 | { 75 | "protoPath": "proto", 76 | "protoFiles": [ 77 | "proto/test.proto", 78 | "proto/google/protobuf/compiler/plugin.proto", 79 | "proto/google/protobuf/descriptor.proto" 80 | ], 81 | "cleanOut": true, 82 | "haxeOut": "out/src-gen", 83 | "javaOut": null 84 | } 85 | Parameters: 86 | protoPath - base path for import directive in proto files; 87 | protoFiles - list of files for code generation; 88 | haxeOut/javaOut - path for generated sources (add it in project classpath); 89 | cleanOut - if 'true' clean output directories before code generation. 90 | 91 | 2) write proto files 92 | 3) genearate haxe sources: 93 | $ haxelib run protohx generate protohx.json 94 | 4) add "out/src-gen" (see param: haxeOut) directory in project classpath 95 | 96 | 97 | ## Notes 98 | Protohx project urls: 99 | * https://github.com/nitrobin/protohx 100 | * https://bitbucket.org/nitrobin/protohx 101 | 102 | This project consists from follow parts: 103 | * tools/plugin - protoc plugin for generating haxe sources; 104 | * tools/run - haxelib runner. Generate haxe and a java sources by json config in project directory; 105 | * protohx - library sources. Pure-haxe port of main parts originally ActionScrip3 code from protoc-gen-as3; 106 | * samples/01-core - unit tests; 107 | * samples/02-ipc - java-to-neko and neko-to-java intercommunication test. 108 | NOTE: Install protoc 2.5.0 via "haxelib run protohx setup-protoc PROTOC_2_5_0_PATH" before building java part of this test. 109 | * samples/03-network - complete client-server example. 110 | build/run node.js server: 111 | haxe build-server-js.hxml 112 | or neko serer: 113 | haxe build-server-neko.hxml 114 | and build/run flash client: 115 | haxe build-client-flash.hxml 116 | or 117 | nme test (flash|linux|android) -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "protohx", 3 | "url": "https://github.com/nitrobin/protohx", 4 | "license": "BSD", 5 | "tags": [ "protobuf", "serialization", "cross", "neko", "flash", "js", "cpp", "java", "php" ], 6 | "description": "Crossplatform implementation of 'Google's Protocol Buffers' for haxe.", 7 | "version": "0.4.6", 8 | "releasenote": "Enforcing class names to be Upper Case. (Thanks Bruno Santos @bmfs)", 9 | "contributors": [ "nitrobin" ], 10 | "dependencies": {} 11 | } 12 | -------------------------------------------------------------------------------- /protohx/CommonError.hx: -------------------------------------------------------------------------------- 1 | package protohx; 2 | class CommonError { 3 | public var msg:String; 4 | public function new(msg:String) { 5 | this.msg = msg; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /protohx/Message.hx: -------------------------------------------------------------------------------- 1 | // vim: tabstop=4 shiftwidth=4 2 | 3 | // Copyright (c) 2010 , NetEase.com,Inc. All rights reserved. 4 | // Copyright (c) 2012 , Yang Bo. All rights reserved. 5 | // 6 | // Author: Yang Bo (pop.atry@gmail.com) 7 | // 8 | // Use, modification and distribution are subject to the New BSD License 9 | // as listed at . 10 | 11 | package protohx; 12 | 13 | 14 | import haxe.io.Output; 15 | import haxe.io.Bytes; 16 | import protohx.Protohx; 17 | 18 | class Message { 19 | private var otherFields:IntMap; 20 | 21 | public function new():Void { 22 | 23 | } 24 | /** 25 | * Parse data as a message of this type and merge it with this. 26 | * 27 | * @param input The source where data are reading from.

After calling 28 | * this method, input.endian will be changed to 29 | * flash.utils.Endian.LITTLE_ENDIAN. If input is a 30 | * flash.utils.PT_Bytes, input.position will increase by 31 | * number of bytes being read.

32 | */ 33 | public function mergeFrom(input:Bytes):Void { 34 | readFromSlice(ReadingBuffer.fromBytes(input), 0); 35 | } 36 | /** 37 | * Like mergeFrom(), but does not read until EOF. Instead, 38 | * the size of the message (encoded as a varint) is read first, then 39 | * the message data. Use writeDelimitedTo() to write 40 | * messages in this format. 41 | * 42 | * @param input The source where data are reading from.

After calling 43 | * this method, input.endian will be changed to 44 | * flash.utils.Endian.LITTLE_ENDIAN. If input is a 45 | * flash.utils.ByteArray, input.position will increase by 46 | * number of bytes being read.

47 | * 48 | * @see #mergeFrom() 49 | * @see #writeDelimitedTo() 50 | */ 51 | public function mergeDelimitedFrom(input:Bytes):Void { 52 | ReadUtils.read__TYPE_MESSAGE(ReadingBuffer.fromBytes(input), this); 53 | } 54 | /** 55 | * Serializes the message and writes it to output. 56 | * 57 | *

58 | * NOTE: Protocol Buffers are not self-delimiting. Therefore, if you 59 | * write any more data to the stream after the message, you must 60 | * somehow ensure that the parser on the receiving end does not 61 | * interpret this as being * part of the protocol message. This can be 62 | * done e.g. by writing the size of the message before the data, then 63 | * making sure to limit the input to that size on the receiving end 64 | * (e.g. by wrapping the InputStream in one which limits the input). 65 | * Alternatively, just use writeDelimitedTo(). 66 | *

67 | * 68 | * @param output The destination where data are writing to.

If 69 | * output is a flash.utils.ByteArray, 70 | * output.position will increase by number of bytes being 71 | * written.

72 | * 73 | * @see #writeDelimitedTo() 74 | */ 75 | public function writeTo(output:Output):Void { 76 | var buffer:PT_OutputStream = new PT_OutputStream(); 77 | writeToBuffer(buffer); 78 | buffer.toNormal(output); 79 | } 80 | 81 | /** 82 | * Like writeTo(), but writes the size of the message as 83 | * a varint before writing the data. This allows more data to be 84 | * written to the stream after the message without the need to delimit 85 | * the message data yourself. Use mergeDelimitedFrom() to 86 | * parse messages written by this method. 87 | * 88 | * @param output The destination where data are writing to.

If 89 | * output is a flash.utils.ByteArray, 90 | * output.position will increase by number of bytes being 91 | * written.

92 | * 93 | * @see #writeTo() 94 | * @see #mergeDelimitedFrom() 95 | */ 96 | public function writeDelimitedTo(output:Output):Void { 97 | var buffer:PT_OutputStream = new PT_OutputStream(); 98 | WriteUtils.write__TYPE_MESSAGE(buffer, this); 99 | buffer.toNormal(output); 100 | } 101 | 102 | /** 103 | * @private 104 | */ 105 | public function readFromSlice(input:PT_InputStream, bytesAfterSlice:PT_UInt):Void { 106 | while (hasBytes(input, bytesAfterSlice)) { 107 | var tag:PT_UInt = protohx.ReadUtils.read__TYPE_UINT32(input); 108 | readUnknown(input, tag); 109 | } 110 | // throw new PT_IllegalOperationError("Not implemented!"); 111 | } 112 | 113 | public inline function hasBytes(input:PT_InputStream, bytesAfterSlice:PT_UInt):Bool { 114 | return input.bytesAvailable > cast bytesAfterSlice; 115 | } 116 | /** 117 | * @private 118 | */ 119 | public function writeToBuffer(output:PT_OutputStream):Void { 120 | writeExtensionOrUnknownFields(output); 121 | // throw new PT_IllegalOperationError("Not implemented!"); 122 | } 123 | 124 | private function writeSingleUnknown(output:PT_OutputStream, tag:PT_UInt, value:Dynamic):Void { 125 | WriteUtils.write__TYPE_UINT32(output, tag); 126 | switch (tag & 7) { 127 | case WireType.VARINT: 128 | WriteUtils.write__TYPE_UINT64(output, value); 129 | case WireType.FIXED_64_BIT: 130 | WriteUtils.write__TYPE_FIXED64(output, value); 131 | case WireType.LENGTH_DELIMITED: 132 | WriteUtils.write__TYPE_BYTES(output, value); 133 | case WireType.FIXED_32_BIT: 134 | WriteUtils.write__TYPE_FIXED32(output, value); 135 | default: 136 | throw new PT_IOError("Invalid wire type: " + (tag & 7)); 137 | } 138 | } 139 | 140 | /** 141 | * @private 142 | */ 143 | function writeUnknown(output:PT_OutputStream, 144 | tag:PT_UInt):Void { 145 | if (tag == 0) { 146 | throw new PT_ArgumentError( 147 | "Attemp to write an undefined string filed: " + 148 | tag); 149 | } 150 | WriteUtils.writeUnknownPair(output, tag, getByTag(tag)); 151 | } 152 | 153 | /** 154 | * @private 155 | */ 156 | function readUnknown(input:PT_InputStream, tag:PT_UInt):Void { 157 | var value:Dynamic; 158 | switch (tag & 7) { 159 | case WireType.VARINT: 160 | value = ReadUtils.read__TYPE_UINT64(input); 161 | case WireType.FIXED_64_BIT: 162 | value = ReadUtils.read__TYPE_FIXED64(input); 163 | case WireType.LENGTH_DELIMITED: 164 | value = ReadUtils.read__TYPE_BYTES(input); 165 | case WireType.FIXED_32_BIT: 166 | value = ReadUtils.read__TYPE_FIXED32(input); 167 | default: 168 | throw new PT_IOError("Invalid wire type: " + (tag & 7)); 169 | } 170 | var currentValue:Dynamic = this.getByTag(tag); 171 | if (currentValue == null) { 172 | this.setByTag(tag, value); 173 | } else if (Std.is(currentValue, Array)) { 174 | currentValue.push(value); 175 | } else { 176 | this.setByTag(tag, [currentValue, value]); 177 | } 178 | } 179 | 180 | public function getByTag(tag:PT_UInt):Dynamic { 181 | return otherFields != null ? otherFields.get(tag) : null; 182 | } 183 | 184 | public function setByTag(tag:PT_UInt, value:Dynamic):Void { 185 | if(otherFields == null){ 186 | otherFields = new IntMap(); 187 | } 188 | otherFields.set(tag, value); 189 | } 190 | 191 | // public function toString():String { 192 | // throw new PT_IllegalOperationError(""); 193 | // return null; 194 | //// return TextFormat.printToString(this); 195 | // } 196 | /** 197 | * @private 198 | */ 199 | public function defaultBytes():PT_Bytes { 200 | return null; 201 | } 202 | public function defaultInt64():PT_Int64 { 203 | return Protohx.newInt64(0, 0); 204 | } 205 | public function defaultUInt64():PT_UInt64 { 206 | return Protohx.newUInt64(0, 0); 207 | } 208 | 209 | public static function stringToByteArray(s:String):PT_Bytes { 210 | return Bytes.ofString(s); 211 | } 212 | 213 | function writeExtensionOrUnknownFields(output:PT_OutputStream):Void { 214 | if(otherFields != null){ 215 | for(tag in otherFields.keys()){ 216 | writeUnknown(output, tag); 217 | } 218 | } 219 | } 220 | 221 | public function forEachFields(fn:String->Dynamic->Void):Void{} 222 | } 223 | -------------------------------------------------------------------------------- /protohx/MessageUtils.hx: -------------------------------------------------------------------------------- 1 | package protohx; 2 | import haxe.Json; 3 | import haxe.Int64; 4 | using haxe.Int64; 5 | import haxe.io.Bytes; 6 | import protohx.Message; 7 | using StringTools; 8 | 9 | class MessageUtils { 10 | public static function toObject(value:Dynamic, keepNulls:Bool = false):Dynamic { 11 | if ( 12 | (value == null) 13 | || Std.is(value, String) 14 | || Std.is(value, Float) 15 | || Std.is(value, Int) 16 | || Std.is(value, Bool) 17 | ) { 18 | return value; 19 | } else if (Std.is(value, Bytes)) { 20 | return cast(value, Bytes).toHex(); 21 | #if (haxe_ver >= 3.2) 22 | } else if (Int64.is(value)) { 23 | #else 24 | } else if (Std.is(value, Int64)) { 25 | #end 26 | return Int64.toStr(cast(value)); 27 | } else if (Std.is(value, protohx.Message)) { 28 | var m:Dynamic = {}; 29 | var msg = cast(value, protohx.Message); 30 | msg.forEachFields(function (f, v) { 31 | Reflect.setField(m, f, toObject(v, keepNulls)); 32 | }); 33 | return m; 34 | } else if (Std.is(value, Array)) { 35 | var a:Array = []; 36 | for (sv in cast(value, Array)) { 37 | a.push(toObject(sv, keepNulls)); 38 | } 39 | return a; 40 | } else { 41 | return Std.string(value); 42 | } 43 | return null; 44 | } 45 | 46 | public static function toJson(msg:protohx.Message, keepNulls:Bool = false):String { 47 | var o:Dynamic = toObject(msg, keepNulls); 48 | return Json.stringify(o); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /protohx/Protohx.hx: -------------------------------------------------------------------------------- 1 | package protohx; 2 | 3 | 4 | typedef PT_Int = Int; 5 | 6 | #if (as3||cs) 7 | typedef PT_UInt = Int; 8 | #else 9 | typedef PT_UInt = UInt; 10 | #end 11 | 12 | typedef PT_Int64 = haxe.Int64; 13 | typedef PT_UInt64 = haxe.Int64; 14 | 15 | typedef PT_String = String; 16 | 17 | typedef PT_Double = Float; 18 | typedef PT_Float = Float; 19 | typedef PT_Bool = Bool; 20 | 21 | typedef PT_Bytes = haxe.io.Bytes; 22 | typedef PT_IDataInput = haxe.io.Input; 23 | typedef PT_IDataOutput = haxe.io.Output; 24 | 25 | typedef PT_OutputStream = protohx.WritingBuffer; 26 | typedef PT_InputStream = protohx.ReadingBuffer; 27 | 28 | typedef PT_ReadFunction = PT_InputStream -> T; 29 | typedef PT_WriteFunction = PT_OutputStream -> T -> Void; 30 | 31 | typedef PT_IOError = protohx.CommonError; 32 | typedef PT_ArgumentError = protohx.CommonError; 33 | typedef PT_IllegalOperationError = protohx.CommonError; 34 | 35 | typedef IntMap = haxe.ds.IntMap; 36 | 37 | class Protohx { 38 | 39 | public static inline function getLow(i:haxe.Int64):PT_Int { 40 | return cast(haxe.Int64.getLow(i), PT_Int); 41 | } 42 | 43 | public static inline function getHigh(i:haxe.Int64):PT_Int { 44 | return cast(haxe.Int64.getHigh(i), PT_Int); 45 | } 46 | 47 | public static inline function newInt64(h:PT_Int, l:PT_Int):PT_Int64 { 48 | return PT_Int64.make(h, l); 49 | } 50 | 51 | public static inline function newUInt64(h:PT_Int, l:PT_Int):PT_UInt64 { 52 | return PT_UInt64.make(h, l); 53 | } 54 | 55 | public static inline function setOutputEndian(out:haxe.io.Output):Void { 56 | out.bigEndian = false; 57 | } 58 | 59 | public static inline function setInputEndian(out:haxe.io.Input):Void { 60 | out.bigEndian = false; 61 | } 62 | } 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /protohx/ReadUtils.hx: -------------------------------------------------------------------------------- 1 | // vim: tabstop=4 shiftwidth=4 2 | 3 | // Copyright (c) 2010 , NetEase.com,Inc. All rights reserved. 4 | // Copyright (c) 2012 , Yang Bo. All rights reserved. 5 | // 6 | // Author: Yang Bo (pop.atry@gmail.com) 7 | // 8 | // Use, modification and distribution are subject to the "New BSD License" 9 | // as listed at . 10 | 11 | package protohx; 12 | 13 | import protohx.Protohx; 14 | import haxe.Int64; 15 | using haxe.Int64; 16 | 17 | class ReadUtils { 18 | public static function skip(input:PT_InputStream, wireType:PT_UInt):Void { 19 | switch (wireType) { 20 | case WireType.VARINT: 21 | while (input.readUnsignedByte() >= 0x80) {} 22 | case WireType.FIXED_64_BIT: 23 | input.readInt32(); 24 | input.readInt32(); 25 | case WireType.LENGTH_DELIMITED: 26 | var i:PT_UInt = read__TYPE_UINT32(input); 27 | while (i != 0) { 28 | input.readUnsignedByte(); 29 | i--; 30 | } 31 | case WireType.FIXED_32_BIT: 32 | input.readInt32(); 33 | default: 34 | throw new PT_IOError("Invalid wire type: " + wireType); 35 | } 36 | } 37 | public static function read__TYPE_DOUBLE(input:PT_InputStream):PT_Double { 38 | return input.readDouble(); 39 | } 40 | public static function read__TYPE_FLOAT(input:PT_InputStream):PT_Float { 41 | return input.readFloat(); 42 | } 43 | public static function read__TYPE_INT64(input:PT_InputStream):PT_Int64 { 44 | var low:PT_Int = 0; 45 | var high:PT_Int = 0; 46 | var b:PT_Int = 0; 47 | var i:PT_Int = 0; 48 | while ( true) { 49 | b = input.readUnsignedByte(); 50 | if (i == 28) { 51 | break; 52 | } else { 53 | if (b >= 0x80) { 54 | low |= ((b & 0x7f) << i); 55 | } else { 56 | low |= (b << i); 57 | return Protohx.newInt64(high, low); 58 | } 59 | } 60 | i += 7; 61 | } 62 | if (b >= 0x80) { 63 | b &= 0x7f; 64 | low |= (b << i); 65 | high = b >>> 4; 66 | } else { 67 | low |= (b << i); 68 | high = b >>> 4; 69 | return Protohx.newInt64(high, low); 70 | } 71 | i = 3; 72 | while ( true ) { 73 | b = input.readUnsignedByte(); 74 | if (i < 32) { 75 | if (b >= 0x80) { 76 | high |= ((b & 0x7f) << i); 77 | } else { 78 | high |= (b << i); 79 | break; 80 | } 81 | } 82 | i += 7; 83 | } 84 | return Protohx.newInt64(high, low); 85 | } 86 | public static function read__TYPE_UINT64(input:PT_InputStream):PT_UInt64 { 87 | var tmp = read__TYPE_INT64(input); 88 | return Protohx.newUInt64(Protohx.getHigh(tmp), Protohx.getLow(tmp)); 89 | } 90 | public static function read__TYPE_INT32(input:PT_InputStream):PT_Int { 91 | return cast read__TYPE_UINT32(input) ; 92 | } 93 | public static function read__TYPE_FIXED64(input:PT_InputStream):PT_UInt64 { 94 | var low = input.readInt32(); 95 | var high = input.readInt32(); 96 | return Protohx.newUInt64(high, low); 97 | } 98 | public static function read__TYPE_FIXED32(input:PT_InputStream):PT_UInt { 99 | return cast(input.readInt32(), PT_UInt); 100 | } 101 | public static function read__TYPE_BOOL(input:PT_InputStream):PT_Bool { 102 | return read__TYPE_UINT32(input) != 0; 103 | } 104 | public static function read__TYPE_STRING(input:PT_InputStream):PT_String { 105 | var length:PT_UInt = read__TYPE_UINT32(input); 106 | return cast input.readUTFBytes(length); 107 | } 108 | public static function read__TYPE_BYTES(input:PT_InputStream):PT_Bytes { 109 | var result:PT_Bytes = null; 110 | var length:PT_UInt = read__TYPE_UINT32(input); 111 | if (length > 0) { 112 | result = input.readBytes(length); 113 | } 114 | return result; 115 | } 116 | public static function read__TYPE_UINT32(input:PT_InputStream):PT_UInt { 117 | var result:PT_Int = 0; 118 | var i:PT_UInt = 0; 119 | while ( true ) { 120 | var b:PT_Int = input.readUnsignedByte(); 121 | if (i < 32) { 122 | if (b >= 0x80) { 123 | result |= ((b & 0x7f) << i); 124 | } else { 125 | result |= (b << i); 126 | break; 127 | } 128 | } else { 129 | while (input.readUnsignedByte() >= 0x80) {} 130 | break; 131 | } 132 | i += 7; 133 | } 134 | return result; 135 | } 136 | public static function read__TYPE_ENUM(input:PT_InputStream):PT_Int { 137 | return read__TYPE_INT32(input); 138 | } 139 | public static function read__TYPE_SFIXED32(input:PT_InputStream):PT_Int { 140 | return input.readInt32(); 141 | } 142 | public static function read__TYPE_SFIXED64(input:PT_InputStream):PT_Int64 { 143 | var low = input.readInt32(); 144 | var high = input.readInt32(); 145 | return Protohx.newInt64(high, low); 146 | } 147 | public static function read__TYPE_SINT32(input:PT_InputStream):PT_Int { 148 | return ZigZag.decode32(read__TYPE_UINT32(input)); 149 | } 150 | public static function read__TYPE_SINT64(input:PT_InputStream):PT_Int64 { 151 | var result:PT_Int64 = read__TYPE_INT64(input); 152 | var low:PT_Int = Protohx.getLow(result); 153 | var high:PT_Int = Protohx.getHigh(result); 154 | var lowNew = ZigZag.decode64low(low, high); 155 | var highNew = ZigZag.decode64high(low, high); 156 | return Protohx.newInt64(highNew, lowNew); 157 | } 158 | //TODO check types 159 | public static function read__TYPE_MESSAGE(input:PT_InputStream, message:T):T { 160 | var length:PT_UInt = read__TYPE_UINT32(input); 161 | if (input.bytesAvailable < cast length) { 162 | throw new PT_IOError("Invalid message length: " + length); 163 | } 164 | var bytesAfterSlice:PT_UInt = input.bytesAvailable - length; 165 | message.readFromSlice(input, bytesAfterSlice); 166 | if (input.bytesAvailable != cast bytesAfterSlice) { 167 | throw new PT_IOError("Invalid nested message"); 168 | } 169 | return message; 170 | } 171 | public static function readPackedRepeated(input:PT_InputStream, readFuntion:PT_ReadFunction, value:Array):Void { 172 | var length:PT_UInt = read__TYPE_UINT32(input); 173 | if (input.bytesAvailable < cast length) { 174 | throw new PT_IOError("Invalid message length: " + length); 175 | } 176 | var bytesAfterSlice:PT_UInt = input.bytesAvailable - length; 177 | while (input.bytesAvailable > cast bytesAfterSlice) { 178 | value.push(readFuntion(input)); 179 | } 180 | if (input.bytesAvailable != cast bytesAfterSlice) { 181 | throw new PT_IOError("Invalid packed repeated data"); 182 | } 183 | } 184 | } 185 | 186 | -------------------------------------------------------------------------------- /protohx/ReadingBuffer.hx: -------------------------------------------------------------------------------- 1 | package protohx; 2 | import protohx.Protohx; 3 | import haxe.io.Bytes; 4 | import haxe.io.BytesInput; 5 | 6 | class ReadingBuffer { 7 | public var length (get, null):Int; 8 | public var bytesAvailable (get, null):Int; 9 | 10 | private var buf:BytesInput; 11 | 12 | public function new(buf:BytesInput) { 13 | this.buf = buf; 14 | Protohx.setInputEndian(this.buf); 15 | } 16 | 17 | public inline static function fromBytes(bytes:Bytes, ?pos : Int, ?len : Int) { 18 | return new ReadingBuffer(new BytesInput(bytes, pos, len)); 19 | } 20 | 21 | public inline function get_length():Int { 22 | return buf.length; 23 | } 24 | 25 | public inline function get_bytesAvailable():Int { 26 | return buf.length - buf.position; 27 | } 28 | 29 | public inline function readBytes(len:Int):Bytes { 30 | var b = Bytes.alloc(len); 31 | buf.readBytes(b, 0, len); 32 | return b; 33 | } 34 | 35 | public inline function readUTFBytes(len:Int):String { 36 | return buf.readString(len); 37 | } 38 | 39 | public inline function readInt32() { 40 | return buf.readInt32(); 41 | } 42 | 43 | // public function readUnsignedInt() { 44 | // bytesAvailable -= 4; 45 | // return buf.readInt32(); 46 | // } 47 | 48 | public inline function readUnsignedByte() { 49 | return buf.readByte(); 50 | } 51 | // public function readByte() { 52 | // bytesAvailable -= 1; 53 | // return buf.readByte(); 54 | // } 55 | public inline function readDouble() { 56 | return buf.readDouble(); 57 | } 58 | public inline function readFloat() { 59 | return buf.readFloat(); 60 | } 61 | } 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /protohx/WireType.hx: -------------------------------------------------------------------------------- 1 | // vim: tabstop=4 shiftwidth=4 2 | 3 | // Copyright (c) 2010 , NetEase.com,Inc. All rights reserved. 4 | // 5 | // Author: Yang Bo (pop.atry@gmail.com) 6 | // 7 | // Use, modification and distribution are subject to the "New BSD License" 8 | // as listed at . 9 | 10 | package protohx; 11 | import protohx.Protohx; 12 | class WireType { 13 | public static inline var VARINT:PT_UInt = 0; 14 | public static inline var FIXED_64_BIT:PT_UInt = 1; 15 | public static inline var LENGTH_DELIMITED:PT_UInt = 2; 16 | public static inline var FIXED_32_BIT:PT_UInt = 5; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /protohx/WriteUtils.hx: -------------------------------------------------------------------------------- 1 | // vim: tabstop=4 shiftwidth=4 2 | 3 | // Copyright (c) 2010 , NetEase.com,Inc. All rights reserved. 4 | // Copyright (c) 2012 , Yang Bo. All rights reserved. 5 | // 6 | // Author: Yang Bo (pop.atry@gmail.com) 7 | // 8 | // Use, modification and distribution are subject to the "New BSD License" 9 | // as listed at . 10 | 11 | package protohx; 12 | import protohx.Protohx; 13 | using haxe.Int64; 14 | 15 | class WriteUtils { 16 | private static function writeSingleUnknown(output:PT_OutputStream, tag:PT_UInt, value:Dynamic):Void { 17 | WriteUtils.write__TYPE_UINT32(output, tag); 18 | switch (tag & 7) { 19 | case WireType.VARINT: 20 | WriteUtils.write__TYPE_UINT64(output, value); 21 | case WireType.FIXED_64_BIT: 22 | WriteUtils.write__TYPE_FIXED64(output, value); 23 | case WireType.LENGTH_DELIMITED: 24 | WriteUtils.write__TYPE_BYTES(output, value); 25 | case WireType.FIXED_32_BIT: 26 | WriteUtils.write__TYPE_FIXED32(output, value); 27 | default: 28 | throw new PT_IOError("Invalid wire type: " + (tag & 7)); 29 | } 30 | } 31 | 32 | public static function writeUnknownPair(output:PT_OutputStream, tag:PT_UInt, value:Dynamic):Void { 33 | //TODO check 34 | var repeated:Array = if(Std.is(value, Array)) cast (value, Array ) else null; 35 | if (repeated!=null) { 36 | for (element in repeated) { 37 | writeSingleUnknown(output, tag, element); 38 | } 39 | } else { 40 | writeSingleUnknown(output, tag, value); 41 | } 42 | } 43 | 44 | private static function writeVarint64(output:PT_OutputStream, low:PT_Int, high:PT_Int):Void { 45 | if (high == 0) { 46 | write__TYPE_UINT32(output, low); 47 | } else { 48 | for (i in 0...4) { 49 | output.writeByte((low & 0x7F) | 0x80); 50 | low >>>= 7; 51 | } 52 | if ((high & (0xffffffff << 3)) == 0) { 53 | output.writeByte((high << 4) | low); 54 | } else { 55 | output.writeByte((((high << 4) | low) & 0x7F) | 0x80); 56 | write__TYPE_UINT32(output, high >>> 3); 57 | } 58 | } 59 | } 60 | public static function writeTag(output:PT_OutputStream, wireType:PT_UInt, number:PT_UInt):Void { 61 | write__TYPE_UINT32(output, (number << 3) | wireType); 62 | } 63 | public static function write__TYPE_DOUBLE(output:PT_OutputStream, value:PT_Double):Void { 64 | output.writeDouble(value); 65 | } 66 | public static function write__TYPE_FLOAT(output:PT_OutputStream, value:PT_Float):Void { 67 | output.writeFloat(value); 68 | } 69 | public static function write__TYPE_INT64(output:PT_OutputStream, value:PT_Int64):Void { 70 | writeVarint64(output, Protohx.getLow(value), Protohx.getHigh(value)); 71 | } 72 | public static function write__TYPE_UINT64(output:PT_OutputStream, value:PT_UInt64):Void { 73 | writeVarint64(output, Protohx.getLow(value), Protohx.getHigh(value)); 74 | } 75 | public static function write__TYPE_INT32(output:PT_OutputStream, value:PT_Int):Void { 76 | if (value < 0) { 77 | writeVarint64(output, value, 0xFFFFFFFF); 78 | } else { 79 | write__TYPE_UINT32(output, value); 80 | } 81 | } 82 | public static function write__TYPE_FIXED64(output:PT_OutputStream, value:PT_UInt64):Void { 83 | output.writeInt32(Protohx.getLow(value)); 84 | output.writeInt32(Protohx.getHigh(value)); 85 | } 86 | public static function write__TYPE_FIXED32(output:PT_OutputStream, value:PT_UInt):Void { 87 | output.writeInt32(value); 88 | } 89 | public static function write__TYPE_BOOL(output:PT_OutputStream, value:PT_Bool):Void { 90 | output.writeByte(value ? 1 : 0); 91 | } 92 | public static function write__TYPE_STRING(output:PT_OutputStream, value:PT_String):Void { 93 | var i:PT_UInt = output.beginBlock(); 94 | if(value != null){//TODO check 95 | output.writeUTFBytes(value); 96 | } 97 | output.endBlock(i); 98 | } 99 | public static function write__TYPE_BYTES(output:PT_OutputStream, value:PT_Bytes):Void { 100 | if(value!=null){ 101 | write__TYPE_UINT32(output, value.length); 102 | output.writeBytes(value); 103 | }else{ 104 | write__TYPE_UINT32(output, 0); 105 | } 106 | } 107 | public static function write__TYPE_UINT32(output:PT_OutputStream, value:PT_UInt):Void { 108 | while (true) { 109 | if ((value & (0xffffffff << 7)) == 0) { 110 | output.writeByte(value); 111 | return; 112 | } else { 113 | output.writeByte((value & 0x7F) | 0x80); 114 | value >>>= 7; 115 | } 116 | } 117 | } 118 | public static function write__TYPE_ENUM(output:PT_OutputStream, value:PT_Int):Void { 119 | write__TYPE_INT32(output, value); 120 | } 121 | public static function write__TYPE_SFIXED32(output:PT_OutputStream, value:PT_Int):Void { 122 | output.writeInt32(value); 123 | } 124 | public static function write__TYPE_SFIXED64(output:PT_OutputStream, value:PT_Int64):Void { 125 | output.writeInt32(Protohx.getLow(value)); 126 | output.writeInt32(Protohx.getHigh(value)); 127 | } 128 | public static function write__TYPE_SINT32(output:PT_OutputStream, value:PT_Int):Void { 129 | write__TYPE_UINT32(output, ZigZag.encode32(value)); 130 | } 131 | public static function write__TYPE_SINT64(output:PT_OutputStream, value:PT_Int64):Void { 132 | writeVarint64(output, 133 | ZigZag.encode64low(Protohx.getLow(value), Protohx.getHigh(value)), 134 | ZigZag.encode64high(Protohx.getLow(value), Protohx.getHigh(value))); 135 | } 136 | public static function write__TYPE_MESSAGE(output:PT_OutputStream, value:Message):Void { 137 | var i:PT_UInt = output.beginBlock(); 138 | value.writeToBuffer(output); 139 | output.endBlock(i); 140 | } 141 | public static function writePackedRepeated(output:PT_OutputStream, writeFunction:PT_WriteFunction, value:Array):Void { 142 | var i:PT_UInt = output.beginBlock(); 143 | for (j in 0...value.length) { 144 | Reflect.callMethod(null, writeFunction, [output, value[j]]); 145 | } 146 | output.endBlock(i); 147 | } 148 | } 149 | 150 | -------------------------------------------------------------------------------- /protohx/WritingBuffer.hx: -------------------------------------------------------------------------------- 1 | // vim: tabstop=4 shiftwidth=4 2 | 3 | // Copyright (c) 2010 , NetEase.com,Inc. All rights reserved. 4 | // 5 | // Author: Yang Bo (pop.atry@gmail.com) 6 | // 7 | // Use, modification and distribution are subject to the "New BSD License" 8 | // as listed at . 9 | 10 | package protohx; 11 | 12 | import haxe.io.Output; 13 | import haxe.io.Bytes; 14 | import haxe.Utf8; 15 | import protohx.Protohx; 16 | import haxe.io.BytesOutput; 17 | 18 | class WritingBuffer { 19 | private var slices:Array; 20 | private var buf:BytesOutput; 21 | public var position(default, null):Int; 22 | 23 | public function new() { 24 | slices = new Array(); 25 | buf = new BytesOutput(); 26 | Protohx.setOutputEndian(buf); 27 | position = 0; 28 | } 29 | 30 | 31 | public function writeDouble(v):Void { 32 | buf.writeDouble(v); 33 | position += 8; 34 | } 35 | 36 | public function writeFloat(v):Void { 37 | buf.writeFloat(v); 38 | position += 4; 39 | } 40 | public function writeBytes(v:Bytes):Void { 41 | buf.write(v); 42 | position += v.length; 43 | } 44 | public function writeUTFBytes(v:String):Void { 45 | var b = haxe.io.Bytes.ofString(v); 46 | buf.write(b); 47 | position += b.length; 48 | } 49 | 50 | public function writeInt32(v:Int):Void { 51 | buf.writeInt32(v); 52 | position += 4; 53 | } 54 | 55 | // public function writeUnsignedInt(v:Int):Void { 56 | // buf.writeInt32(v); 57 | // position += 4; 58 | // } 59 | 60 | public function writeByte(v:Int):Void { 61 | buf.writeByte(v); 62 | position += 1; 63 | } 64 | 65 | public function beginBlock():PT_UInt { 66 | slices.push(position); 67 | var beginSliceIndex:PT_UInt = slices.length; 68 | slices.push(0);slices.push(0);//slices.length += 2; 69 | slices.push(position); 70 | return beginSliceIndex; 71 | } 72 | public function endBlock(beginSliceIndex:PT_UInt):Void { 73 | slices.push(position); 74 | var beginPosition:PT_UInt = slices[beginSliceIndex + 2]; 75 | slices[beginSliceIndex] = position; 76 | WriteUtils.write__TYPE_UINT32(this, position - beginPosition); 77 | slices[beginSliceIndex + 1] = position; 78 | slices.push(position); 79 | } 80 | public function toNormal(output:Output):Void { 81 | var i:PT_Int = 0; 82 | var begin:PT_UInt = 0; 83 | var bytes = buf.getBytes(); 84 | while (i < slices.length) { 85 | var end:PT_UInt = slices[i]; 86 | ++i; 87 | if (end > begin) { 88 | output.writeFullBytes(bytes, begin, end - begin); 89 | } else if (end < begin) { 90 | throw new PT_IllegalOperationError(""); 91 | } 92 | begin = slices[i]; 93 | ++i; 94 | } 95 | output.writeFullBytes(bytes, begin, bytes.length - begin); 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /protohx/ZigZag.hx: -------------------------------------------------------------------------------- 1 | // vim: tabstop=4 shiftwidth=4 2 | 3 | // Copyright (c) 2010 , NetEase.com,Inc. All rights reserved. 4 | // 5 | // Author: Yang Bo (pop.atry@gmail.com) 6 | // 7 | // Use, modification and distribution are subject to the "New BSD License" 8 | // as listed at . 9 | 10 | package protohx; 11 | /** 12 | * @private 13 | */ 14 | import protohx.Protohx; 15 | 16 | class ZigZag { 17 | public static function encode32(n:PT_Int):PT_Int { 18 | return (n << 1) ^ (n >> 31); 19 | } 20 | public static function decode32(n:PT_Int):PT_Int { 21 | return (n >>> 1) ^ -(n & 1); 22 | } 23 | public static function encode64low(low:PT_Int, high:PT_Int):PT_Int { 24 | return (low << 1) ^ (high >> 31); 25 | } 26 | public static function encode64high(low:PT_Int, high:PT_Int):PT_Int { 27 | return (low >>> 31) ^ (high << 1) ^ (high >> 31); 28 | } 29 | public static function decode64low(low:PT_Int, high:PT_Int):PT_Int { 30 | return (high << 31) ^ (low >>> 1) ^ -(low & 1); 31 | } 32 | public static function decode64high(low:PT_Int, high:PT_Int):PT_Int { 33 | return (high >>> 1) ^ -(low & 1); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /run.n: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nitrobin/protohx/ce7b7ac49a676fd29d08184148eefbeb4c0cba47/run.n -------------------------------------------------------------------------------- /samples/01-core/assets/plugin_proto_input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nitrobin/protohx/ce7b7ac49a676fd29d08184148eefbeb4c0cba47/samples/01-core/assets/plugin_proto_input -------------------------------------------------------------------------------- /samples/01-core/build-as3.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/as3 4 | 5 | --next 6 | 7 | -resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | 13 | -as3 out/as3 14 | 15 | --next 16 | 17 | -cmd cd out/as3 18 | -cmd /opt/haxetoolkit/tools/apache-flex-sdk-4.11.0-bin/bin/mxmlc -output as3.swf __main__.as -static-link-runtime-shared-libraries=true -debug 19 | #-swf-header 800:600:40:FFFFFF 20 | 21 | -cmd flashplayerdebugger as3.swf 22 | -------------------------------------------------------------------------------- /samples/01-core/build-cpp-pure.hxml: -------------------------------------------------------------------------------- 1 | -cmd haxelib run protohx generate protohx.json 2 | -cmd mkdir -p out/cpp 3 | 4 | --next 5 | 6 | -main Main 7 | -cp src 8 | -cp out/src-gen 9 | -lib protohx 10 | -debug 11 | -D HXCPP_STACK_TRACE 12 | -D HXCPP_STACK_LINE 13 | -D HXCPP_DEBUG_LINK 14 | -D HXCPP_CHECK_POINTER 15 | 16 | 17 | -cpp out/cpp 18 | 19 | --next 20 | 21 | -cmd cp assets/plugin_proto_input out/cpp 22 | -cmd out/cpp/Main-debug -------------------------------------------------------------------------------- /samples/01-core/build-cpp.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/cpp 4 | -cmd haxelib run openfl test linux 5 | 6 | 7 | #--next 8 | 9 | #-main Main 10 | #-cp src 11 | #-cp out/src-gen 12 | #-lib protohx 13 | #-debug 14 | #-D HXCPP_STACK_TRACE 15 | #-D HXCPP_STACK_LINE 16 | #-D HXCPP_DEBUG_LINK 17 | 18 | 19 | #-cpp out/cpp 20 | 21 | #--next 22 | 23 | #-cmd cp assets/plugin_proto_input out/cpp 24 | #-cmd out/cpp/Main-debug -------------------------------------------------------------------------------- /samples/01-core/build-cs.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/cs 4 | 5 | --next 6 | 7 | -resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | -debug 13 | 14 | -cs out/cs 15 | 16 | --next 17 | 18 | -cmd cd out/cs 19 | -cmd mono bin/Main-Debug.exe 20 | #-cmd gmcs -recurse:*.cs -main:Main -out:Tester.exe-debug 21 | -------------------------------------------------------------------------------- /samples/01-core/build-flash.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | #-cmd mkdir -p out 4 | 5 | --next 6 | 7 | -resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | 13 | -swf out/run.swf 14 | -swf-header 800:600:40:FFFFFF 15 | 16 | --next 17 | 18 | -cmd flashplayerdebugger out/run.swf 19 | -------------------------------------------------------------------------------- /samples/01-core/build-java.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/java 4 | 5 | --next 6 | 7 | #-resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | -debug 13 | 14 | -java out/java 15 | 16 | --next 17 | -cmd pwd 18 | -cmd cp assets/plugin_proto_input out/java/plugin_proto_input 19 | -cmd cd out/java/ 20 | -cmd java -jar Main-Debug.jar -cp . 21 | -------------------------------------------------------------------------------- /samples/01-core/build-js.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out 4 | 5 | --next 6 | 7 | -resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | 13 | -js out/Main.js 14 | 15 | --next 16 | 17 | #-cmd phantomjs out/Main.js 18 | -cmd nodejs out/Main.js 19 | -------------------------------------------------------------------------------- /samples/01-core/build-neko.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | #-cmd mkdir -p out 4 | 5 | --next 6 | 7 | -resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -D neko_v2 12 | -neko out/run.n 13 | -lib protohx 14 | 15 | --next 16 | 17 | -cmd neko out/run.n -------------------------------------------------------------------------------- /samples/01-core/build-php.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/php 4 | 5 | --next 6 | 7 | -resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | 13 | -php out/php 14 | 15 | --next 16 | 17 | -cmd php out/php/index.php -------------------------------------------------------------------------------- /samples/01-core/build-python.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out 4 | 5 | --next 6 | 7 | -resource assets/plugin_proto_input@plugin_proto_input 8 | -main Main 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | 13 | -python out/run.py 14 | 15 | --next 16 | 17 | -cmd python3 out/run.py -------------------------------------------------------------------------------- /samples/01-core/js-test.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/01-core/nme-generate-sources.hxml: -------------------------------------------------------------------------------- 1 | -cmd haxelib run protohx generate protohx.json 2 | -------------------------------------------------------------------------------- /samples/01-core/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /samples/01-core/proto/google/protobuf/compiler/plugin.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // http://code.google.com/p/protobuf/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // 33 | // WARNING: The plugin interface is currently EXPERIMENTAL and is subject to 34 | // change. 35 | // 36 | // protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is 37 | // just a program that reads a CodeGeneratorRequest from stdin and writes a 38 | // CodeGeneratorResponse to stdout. 39 | // 40 | // Plugins written using C++ can use google/protobuf/compiler/plugin.h instead 41 | // of dealing with the raw protocol defined here. 42 | // 43 | // A plugin executable needs only to be placed somewhere in the path. The 44 | // plugin should be named "protoc-gen-$NAME", and will then be used when the 45 | // flag "--${NAME}_out" is passed to protoc. 46 | 47 | package google.protobuf.compiler; 48 | 49 | import "google/protobuf/descriptor.proto"; 50 | 51 | // An encoded CodeGeneratorRequest is written to the plugin's stdin. 52 | message CodeGeneratorRequest { 53 | // The .proto files that were explicitly listed on the command-line. The 54 | // code generator should generate code only for these files. Each file's 55 | // descriptor will be included in proto_file, below. 56 | repeated string file_to_generate = 1; 57 | 58 | // The generator parameter passed on the command-line. 59 | optional string parameter = 2; 60 | 61 | // FileDescriptorProtos for all files in files_to_generate and everything 62 | // they import. The files will appear in topological order, so each file 63 | // appears before any file that imports it. 64 | // 65 | // protoc guarantees that all proto_files will be written after 66 | // the fields above, even though this is not technically guaranteed by the 67 | // protobuf wire format. This theoretically could allow a plugin to stream 68 | // in the FileDescriptorProtos and handle them one by one rather than read 69 | // the entire set into memory at once. However, as of this writing, this 70 | // is not similarly optimized on protoc's end -- it will store all fields in 71 | // memory at once before sending them to the plugin. 72 | repeated FileDescriptorProto proto_file = 15; 73 | } 74 | 75 | // The plugin writes an encoded CodeGeneratorResponse to stdout. 76 | message CodeGeneratorResponse { 77 | // Error message. If non-empty, code generation failed. The plugin process 78 | // should exit with status code zero even if it reports an error in this way. 79 | // 80 | // This should be used to indicate errors in .proto files which prevent the 81 | // code generator from generating correct code. Errors which indicate a 82 | // problem in protoc itself -- such as the input CodeGeneratorRequest being 83 | // unparseable -- should be reported by writing a message to stderr and 84 | // exiting with a non-zero status code. 85 | optional string error = 1; 86 | 87 | // Represents a single generated file. 88 | message File { 89 | // The file name, relative to the output directory. The name must not 90 | // contain "." or ".." components and must be relative, not be absolute (so, 91 | // the file cannot lie outside the output directory). "/" must be used as 92 | // the path separator, not "\". 93 | // 94 | // If the name is omitted, the content will be appended to the previous 95 | // file. This allows the generator to break large files into small chunks, 96 | // and allows the generated text to be streamed back to protoc so that large 97 | // files need not reside completely in memory at one time. Note that as of 98 | // this writing protoc does not optimize for this -- it will read the entire 99 | // CodeGeneratorResponse before writing files to disk. 100 | optional string name = 1; 101 | 102 | // If non-empty, indicates that the named file should already exist, and the 103 | // content here is to be inserted into that file at a defined insertion 104 | // point. This feature allows a code generator to extend the output 105 | // produced by another code generator. The original generator may provide 106 | // insertion points by placing special annotations in the file that look 107 | // like: 108 | // @@protoc_insertion_point(NAME) 109 | // The annotation can have arbitrary text before and after it on the line, 110 | // which allows it to be placed in a comment. NAME should be replaced with 111 | // an identifier naming the point -- this is what other generators will use 112 | // as the insertion_point. Code inserted at this point will be placed 113 | // immediately above the line containing the insertion point (thus multiple 114 | // insertions to the same point will come out in the order they were added). 115 | // The double-@ is intended to make it unlikely that the generated code 116 | // could contain things that look like insertion points by accident. 117 | // 118 | // For example, the C++ code generator places the following line in the 119 | // .pb.h files that it generates: 120 | // // @@protoc_insertion_point(namespace_scope) 121 | // This line appears within the scope of the file's package namespace, but 122 | // outside of any particular class. Another plugin can then specify the 123 | // insertion_point "namespace_scope" to generate additional classes or 124 | // other declarations that should be placed in this scope. 125 | // 126 | // Note that if the line containing the insertion point begins with 127 | // whitespace, the same whitespace will be added to every line of the 128 | // inserted text. This is useful for languages like Python, where 129 | // indentation matters. In these languages, the insertion point comment 130 | // should be indented the same amount as any inserted code will need to be 131 | // in order to work correctly in that context. 132 | // 133 | // The code generator that generates the initial file and the one which 134 | // inserts into it must both run as part of a single invocation of protoc. 135 | // Code generators are executed in the order in which they appear on the 136 | // command line. 137 | // 138 | // If |insertion_point| is present, |name| must also be present. 139 | optional string insertion_point = 2; 140 | 141 | // The file contents. 142 | optional string content = 15; 143 | } 144 | repeated File file = 15; 145 | } 146 | -------------------------------------------------------------------------------- /samples/01-core/proto/test.proto: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | /* 4 | // TODO check all types 5 | // https://developers.google.com/protocol-buffers/docs/proto 6 | double // double double 7 | float // float float 8 | int32 // Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32 int 9 | int64 // Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. int64 long 10 | uint32 // Uses variable-length encoding. uint32 int[1] 11 | uint64 // Uses variable-length encoding. uint64 long[1] 12 | sint32 // Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32 int 13 | sint64 // Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64 long 14 | fixed32 // Always four bytes. More efficient than uint32 if values are often greater than 228. uint32 int[1] 15 | fixed64 // Always eight bytes. More efficient than uint64 if values are often greater than 256. uint64 long[1] 16 | sfixed32 // Always four bytes. int32 int 17 | sfixed64 // Always eight bytes. int64 long 18 | bool // bool boolean 19 | string // A string must always contain UTF-8 encoded or 7-bit ASCII text. string String 20 | bytes // May contain any arbitrary sequence of bytes. string ByteString 21 | */ 22 | 23 | message ComplexMessage { 24 | enum MsgType { 25 | AAA = 100; 26 | BBB = 101; 27 | } 28 | message Point{ 29 | required int32 x = 1; 30 | required int32 y = 2; 31 | } 32 | 33 | required MsgType type = 1 [default = AAA]; 34 | required string msg = 2; 35 | required int32 id = 3; 36 | required uint32 uid = 4; 37 | required bool offline = 5; 38 | required bytes attach = 6; 39 | repeated string statuses = 7; 40 | repeated Point points = 8; 41 | required sint32 rnd = 9; 42 | required MsgType typeOpt = 10; 43 | 44 | optional string msgOpt = 11; 45 | } 46 | 47 | 48 | message IntTestMessage { 49 | optional int32 i32 = 1; 50 | optional uint32 ui32 = 2; 51 | optional int64 i64 = 3; 52 | optional uint64 ui64 = 4; 53 | optional sint32 si32 = 5; 54 | optional sint64 sui64 = 6; 55 | optional float f = 7; 56 | optional double d = 8; 57 | 58 | repeated int32 rnds = 9; 59 | repeated sint32 srnds = 10; 60 | repeated uint32 urnds = 11; 61 | repeated fixed32 frnds = 12; 62 | } 63 | 64 | message Foo { 65 | required string version = 1 [default = "1.0"]; 66 | extensions 100 to 199; 67 | } 68 | 69 | extend Foo { 70 | optional int32 bar = 126; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /samples/01-core/protohx.json: -------------------------------------------------------------------------------- 1 | { 2 | "protoPath": "proto", 3 | "protoFiles": [ 4 | "proto/test.proto", 5 | "proto/google/protobuf/compiler/plugin.proto", 6 | "proto/google/protobuf/descriptor.proto" 7 | ], 8 | "cleanOut": true, 9 | "haxeOut": "out/src-gen", 10 | "javaOut": null 11 | } -------------------------------------------------------------------------------- /samples/01-core/src/Main.hx: -------------------------------------------------------------------------------- 1 | package ; 2 | import test.Foo; 3 | import protohx.Message; 4 | import haxe.io.BytesOutput; 5 | import google.protobuf.compiler.CodeGeneratorRequest; 6 | import test.IntTestMessage; 7 | import test.complexmessage.Point; 8 | import test.complexmessage.MsgType; 9 | import protohx.Protohx; 10 | import test.ComplexMessage; 11 | import haxe.io.Bytes; 12 | import haxe.Int64; 13 | using haxe.Int64; 14 | 15 | class Main { 16 | public function new() { 17 | } 18 | 19 | public static function main():Void { 20 | #if js 21 | haxe.unit.TestRunner.print = function ( v : Dynamic ){ 22 | untyped __js__("console.log(v);"); 23 | } 24 | #end 25 | var r = new haxe.unit.TestRunner(); 26 | r.add(new TestComplex()); 27 | r.add(new TestInt()); 28 | r.add(new TestInt64()); 29 | r.add(new TestLargeData()); 30 | r.add(new TestFloat()); 31 | r.run(); 32 | } 33 | } 34 | 35 | class TestLargeData extends haxe.unit.TestCase { 36 | public function getBytes():Bytes { 37 | #if openfl 38 | return openfl.Assets.getBytes("assets/plugin_proto_input"); 39 | #elseif (java||cpp) 40 | return sys.io.File.getBytes("plugin_proto_input"); 41 | #else 42 | return haxe.Resource.getBytes("plugin_proto_input"); 43 | #end 44 | } 45 | public function testPlugin() { 46 | // try { 47 | var bytes = getBytes(); 48 | var m = new CodeGeneratorRequest(); 49 | assertTrue(bytes != null); 50 | m.mergeFrom(bytes); 51 | var b = new BytesOutput(); 52 | m.writeTo(b); 53 | var copyBytes = b.getBytes(); 54 | assertEquals(bytes.length, copyBytes.length); 55 | for (i in 0...bytes.length) { 56 | assertEquals(bytes.get(i), copyBytes.get(i)); 57 | } 58 | // } catch (e:Dynamic) {untyped __java__("((java.lang.Throwable)e).printStackTrace()");} 59 | } 60 | 61 | 62 | #if !(cpp || java || cs) //TODO 63 | public function testPluginUnknowns() { 64 | // try { 65 | var bytes = getBytes(); 66 | var m = new Message(); 67 | assertTrue(bytes != null); 68 | m.mergeFrom(bytes); 69 | var b = new BytesOutput(); 70 | m.writeTo(b); 71 | var copyBytes = b.getBytes(); 72 | assertEquals(bytes.length, copyBytes.length); 73 | for (i in 0...bytes.length) { 74 | assertEquals(bytes.get(i), copyBytes.get(i)); 75 | } 76 | // } catch (e:Dynamic) {untyped __java__("((java.lang.Throwable)e).printStackTrace()");} 77 | } 78 | #end 79 | } 80 | 81 | 82 | class TestBase extends haxe.unit.TestCase { 83 | 84 | public function copyMsg(obj:T):T { 85 | var b = new BytesOutput(); 86 | untyped obj.writeTo(b); 87 | var copy = Type.createInstance(Type.getClass(obj), []); 88 | untyped copy.mergeFrom(b.getBytes()); 89 | return copy; 90 | } 91 | } 92 | 93 | class TestInt extends TestBase { 94 | 95 | public function testInt() { 96 | function forInt(value:PT_Int) { 97 | var obj = new IntTestMessage(); 98 | obj.i32 = value; 99 | var copy = copyMsg(obj); 100 | assertEquals(obj.i32, value); 101 | assertEquals(obj.i32, copy.i32); 102 | } 103 | forInt(0x0f); 104 | forInt(0xf0); 105 | forInt(0xff); 106 | forInt(0xffff); 107 | forInt(0xffffff); 108 | forInt(-0xff); 109 | forInt(-0xffff); 110 | forInt(-0xffffff); 111 | forInt(0xffffffff); 112 | forInt(0xefffffff); 113 | forInt(-1); 114 | forInt(0); 115 | for (i in 0...32) { 116 | forInt(1 << i); 117 | } 118 | } 119 | 120 | public function testUInt() { 121 | function forInt(value:PT_UInt) { 122 | var obj = new IntTestMessage(); 123 | obj.ui32 = value; 124 | var copy = copyMsg(obj); 125 | assertEquals(obj.ui32, value); 126 | assertEquals(obj.ui32, copy.ui32); 127 | } 128 | forInt(0x0f); 129 | forInt(0xf0); 130 | forInt(0xff); 131 | forInt(0xffff); 132 | forInt(0xffffff); 133 | forInt(0xffffffff); 134 | forInt(0xefffffff); 135 | forInt(0); 136 | for (i in 0...32) { 137 | forInt(1 << i); 138 | } 139 | } 140 | 141 | public function testSInt() { 142 | function forInt(value:PT_Int) { 143 | var obj = new IntTestMessage(); 144 | obj.si32 = value; 145 | var copy = copyMsg(obj); 146 | assertEquals(obj.si32, value); 147 | assertEquals(obj.si32, copy.si32); 148 | } 149 | forInt(0xff); 150 | forInt(0xffff); 151 | forInt(0xffffff); 152 | forInt(-0xff); 153 | forInt(-0xffff); 154 | forInt(-0xffffff); 155 | forInt(0xffffffff); 156 | forInt(0xefffffff); 157 | forInt(-1); 158 | forInt(0); 159 | for (i in 0...32) { 160 | forInt(1 << i); 161 | } 162 | } 163 | 164 | public function testRepeat() { 165 | var obj = new IntTestMessage(); 166 | for( x in 0...1000 ) { 167 | obj.rnds.push(x); 168 | obj.srnds.push(x); 169 | obj.urnds.push(x); 170 | obj.frnds.push(x); 171 | } 172 | for( x in 0...1000 ) { 173 | obj.rnds.push(-x); 174 | obj.srnds.push(-x); 175 | obj.frnds.push(-x); 176 | } 177 | 178 | var copy = copyMsg(obj); 179 | for (i in 0...obj.rnds.length) { 180 | assertEquals(obj.rnds[i], copy.rnds[i]); 181 | } 182 | for (i in 0...obj.srnds.length) { 183 | assertEquals(obj.srnds[i], copy.srnds[i]); 184 | } 185 | for (i in 0...obj.urnds.length) { 186 | assertEquals(obj.urnds[i], copy.urnds[i]); 187 | } 188 | for (i in 0...obj.frnds.length) { 189 | assertEquals(obj.frnds[i], copy.frnds[i]); 190 | } 191 | } 192 | } 193 | 194 | class TestInt64 extends TestBase { 195 | 196 | public function testInt64() { 197 | function forInt64(l:PT_Int, h:PT_Int = 0) { 198 | var obj = new IntTestMessage(); 199 | obj.i64 = Protohx.newInt64(h, l); 200 | var copy = copyMsg(obj); 201 | assertTrue(copy.hasI64()); 202 | assertEquals(obj.i64.getLow(), copy.i64.getLow()); 203 | assertEquals(obj.i64.getHigh(), copy.i64.getHigh()); 204 | } 205 | forInt64(0x0); 206 | forInt64(0xff); 207 | forInt64(0xffff); 208 | forInt64(0xffffff); 209 | 210 | forInt64(0xffffffff); 211 | forInt64(0xefffffff); 212 | forInt64(0); 213 | 214 | forInt64(0, 0x1); 215 | forInt64(0, 0xff); 216 | forInt64(0, 0xffff); 217 | forInt64(0, 0xffffff); 218 | forInt64(0, 0xffffffff); 219 | forInt64(0, 0xefffffff); 220 | } 221 | } 222 | 223 | class TestFloat extends TestBase { 224 | 225 | public function testFloat() { 226 | function forFloat(v:PT_Float) { 227 | var obj = new IntTestMessage(); 228 | obj.f = v; 229 | obj.d = v; 230 | var copy = copyMsg(obj); 231 | assertEquals(obj.f, copy.f); 232 | assertEquals(obj.d, copy.d); 233 | } 234 | function forFloat2(v:PT_Float, p:PT_Float) { 235 | var obj = new IntTestMessage(); 236 | obj.f = v; 237 | obj.d = v; 238 | var copy = copyMsg(obj); 239 | assertTrue(Math.abs(obj.f - copy.f) < p); 240 | assertTrue(Math.abs(obj.d - copy.d) < p); 241 | } 242 | forFloat(0x0); 243 | forFloat(0xff); 244 | forFloat(0xffff); 245 | forFloat(0xffffff); 246 | 247 | forFloat(0xffffffff); 248 | forFloat(0.5); 249 | 250 | var p = 0.000001; 251 | for(i in 1...101){ 252 | forFloat2(1.0 / i, p); 253 | } 254 | } 255 | } 256 | 257 | class TestComplex extends TestBase { 258 | public function testBasic() { 259 | function p(x, y) { 260 | var pt = new Point(); 261 | pt.x = x; 262 | pt.y = y; 263 | return pt; 264 | } 265 | 266 | var obj = new ComplexMessage(); 267 | 268 | obj.type = MsgType.BBB; 269 | obj.msg = "msg1"; 270 | obj.id = 12345; 271 | 272 | obj.uid = 54321; 273 | obj.offline = true; 274 | 275 | obj.attach = null; 276 | obj.statuses = ["123", "456"]; 277 | obj.points = [p(1, 2), p(3, 4)]; 278 | 279 | obj.msgOpt = "msgOpt1"; 280 | 281 | obj.rnd = -1; 282 | 283 | obj.attach = Bytes.alloc(256); 284 | for (b in 0...256) { 285 | obj.attach.set(b, b); 286 | } 287 | assertEquals(obj.attach.length, 256); 288 | 289 | var b = new BytesOutput(); 290 | obj.writeTo(b); 291 | var copy = new ComplexMessage(); 292 | copy.mergeFrom(b.getBytes()); 293 | 294 | assertEquals(obj.type, copy.type); 295 | assertEquals(obj.msg, copy.msg); 296 | assertEquals(obj.id, copy.id); 297 | assertEquals(obj.uid, copy.uid); 298 | assertEquals(obj.offline, copy.offline); 299 | assertEquals(Std.string(obj.statuses), Std.string(copy.statuses)); 300 | 301 | assertEquals(obj.rnd, copy.rnd); 302 | assertEquals(copy.attach.length, 256); 303 | 304 | for (b in 0...256) { 305 | var c = copy.attach.get(b); 306 | assertEquals(c, b); 307 | } 308 | 309 | var foo = new Foo(); 310 | assertEquals("1.0", foo.version); 311 | } 312 | 313 | } 314 | -------------------------------------------------------------------------------- /samples/02-ipc/build-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ant 3 | haxe build-neko.hxml -------------------------------------------------------------------------------- /samples/02-ipc/build-java.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/java 4 | 5 | --next 6 | 7 | -main HaxeMain 8 | -cp src 9 | -cp out/src-gen-hx 10 | -lib protohx 11 | -debug 12 | 13 | -java out/java 14 | 15 | --next 16 | 17 | -cmd java -jar out/java/java.jar 18 | -------------------------------------------------------------------------------- /samples/02-ipc/build-neko.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | 4 | --next 5 | 6 | -main HaxeMain 7 | -cp src 8 | -cp out/src-gen-hx 9 | -D neko_v2 10 | -lib protohx 11 | -neko out/run.n 12 | 13 | --next 14 | 15 | -cmd neko out/run.n -------------------------------------------------------------------------------- /samples/02-ipc/build-php.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/php 4 | 5 | --next 6 | 7 | -main HaxeMain 8 | -cp src 9 | -cp out/src-gen-hx 10 | -lib protohx 11 | 12 | -php out/php 13 | 14 | --next 15 | 16 | -cmd php out/php/index.php -------------------------------------------------------------------------------- /samples/02-ipc/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /samples/02-ipc/proto/calc.proto: -------------------------------------------------------------------------------- 1 | package calc; 2 | 3 | message ValueMessage { 4 | optional float f = 1; 5 | optional double d = 2; 6 | 7 | optional int32 i32 = 3; 8 | optional sint32 si32 = 4; 9 | optional uint32 ui32 = 5; 10 | 11 | optional int64 i64 = 6; 12 | optional uint64 ui64 = 7; 13 | optional sint64 si64 = 8; 14 | 15 | 16 | optional fixed32 fi32 = 9; 17 | optional fixed64 fi64 = 10; 18 | 19 | optional sfixed32 sfi32 = 11; 20 | optional sfixed64 sfi64 = 12; 21 | } 22 | 23 | enum OpCode{ 24 | ADD = 1; 25 | SUB = 2; 26 | MUL = 3; 27 | DIV = 4; 28 | } 29 | 30 | message InputMessage { 31 | repeated ValueMessage values = 1; 32 | repeated OpCode opCodes = 2; 33 | } 34 | 35 | message OutputMessage { 36 | required bool success = 1; 37 | required string msg = 2; 38 | optional ValueMessage value = 3; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /samples/02-ipc/protohx-java.json: -------------------------------------------------------------------------------- 1 | { 2 | "protoPath": "proto", 3 | "protoFiles": [ 4 | "proto/calc.proto" 5 | ], 6 | "cleanOut": true, 7 | "javaOut": "src-gen-java" 8 | } -------------------------------------------------------------------------------- /samples/02-ipc/protohx.json: -------------------------------------------------------------------------------- 1 | { 2 | "protoPath": "proto", 3 | "protoFiles": [ 4 | "proto/calc.proto" 5 | ], 6 | "cleanOut": true, 7 | "haxeOut": "out/src-gen-hx" 8 | } -------------------------------------------------------------------------------- /samples/02-ipc/src/HaxeMain.hx: -------------------------------------------------------------------------------- 1 | package; 2 | import protohx.Protohx; 3 | import calc.OpCode; 4 | import calc.ValueMessage; 5 | import calc.OutputMessage; 6 | import calc.InputMessage; 7 | import sys.io.Process; 8 | import haxe.io.BytesOutput; 9 | import haxe.Int64; 10 | using haxe.Int64; 11 | 12 | class HaxeMain { 13 | public static function main():Void { 14 | var r = new haxe.unit.TestRunner(); 15 | r.add(new TestBasics()); 16 | r.run(); 17 | } 18 | } 19 | 20 | class TestBasics extends haxe.unit.TestCase { 21 | public function testPlugin() { 22 | function v(i:Int) { 23 | var vm = new ValueMessage(); 24 | vm.i32 = i; 25 | vm.fi32 = i; 26 | vm.ui32 = i; 27 | vm.si32 = i; 28 | vm.sfi32 = i; 29 | vm.d = i; 30 | vm.f = i; 31 | return vm; 32 | } 33 | runCalc([v(1), v(2), v(3)], [OpCode.ADD, OpCode.MUL], v(7)) ; 34 | runCalc([v(0xff00), v(0x00ff)], [OpCode.ADD], v(0xffff)) ; 35 | runCalc([v(0xfff000), v(0xfff)], [OpCode.ADD], v(0xffffff)) ; 36 | runCalc([v(0xf0f000), v(0x0f0)], [OpCode.ADD], v(0xf0f0f0)) ; 37 | runCalc([v(0xffff0000), v(0xffff)], [OpCode.ADD], v(0xffffffff)) ; 38 | runCalc([v(0xffffffff), v(0x01)], [OpCode.ADD], v(0x00)) ; 39 | runCalc([v(0xffffffff), v(0x02)], [OpCode.ADD], v(0x01)) ; 40 | } 41 | 42 | public function v(h:Int, l:Int):ValueMessage { 43 | var vm = new ValueMessage(); 44 | vm.si64 = Protohx.newInt64(h, l); 45 | vm.sfi64 = Protohx.newInt64(h, l); 46 | vm.i64 = Protohx.newInt64(h, l); 47 | vm.fi64 = Protohx.newInt64(h, l); 48 | vm.ui64 = Protohx.newUInt64(h, l); 49 | return vm; 50 | } 51 | public function testPlugin64() { 52 | runCalc([v(0, 1), v(0, 1)], [ OpCode.MUL], v(0, 1)) ; 53 | runCalc([v(0, 1), v(0, 2), v(0, 3)], [OpCode.ADD, OpCode.MUL], v(0, 7)) ; 54 | runCalc([v(0, 0xffffffff), v(0, 1), v(0, 1)], [OpCode.ADD, OpCode.MUL], v(1, 0)) ; 55 | // runCalc([v(0xff00), v(0x00ff)], [OpCode.ADD], v(0xffff)) ; 56 | // runCalc([v(0xfff000), v(0xfff)], [OpCode.ADD], v(0xffffff)) ; 57 | // runCalc([v(0xf0f000), v(0x0f0)], [OpCode.ADD], v(0xf0f0f0)) ; 58 | // runCalc([v(0xffff0000), v(0xffff)], [OpCode.ADD], v(0xffffffff)) ; 59 | // runCalc([v(0xffffffff), v(0x01)], [OpCode.ADD], v(0x00)) ; 60 | // runCalc([v(0xffffffff), v(0x02)], [OpCode.ADD], v(0x01)) ; 61 | } 62 | 63 | public function runCalc(values, opCodes, r:ValueMessage) { 64 | 65 | var p = new Process("out/calc", []); 66 | var im = new InputMessage(); 67 | im.values = values; 68 | im.opCodes = opCodes; 69 | 70 | var b = new BytesOutput(); 71 | im.writeTo(b); 72 | var bytes = b.getBytes(); 73 | p.stdin.bigEndian = true; 74 | p.stdin.writeUInt16(bytes.length); 75 | p.stdin.write(bytes); 76 | p.stdin.flush(); 77 | 78 | p.stdout.bigEndian = true; 79 | var len = p.stdout.readUInt16(); 80 | var resBytes = p.stdout.read(len); 81 | var om = new OutputMessage(); 82 | om.mergeFrom(resBytes); 83 | 84 | p.close(); 85 | // trace(protohx.MessageUtils.toJson(im)); 86 | // trace(protohx.MessageUtils.toJson(om)); 87 | 88 | assertTrue(om.success); 89 | // assertEquals("ok", om.msg); 90 | var ir:ValueMessage = om.value; 91 | if (r.hasI32()) {assertEquals(r.i32, ir.i32); } 92 | if (r.hasUi32()) {assertEquals(r.ui32, ir.ui32); } 93 | if (r.hasSi32()) {assertEquals(r.si32, ir.si32); } 94 | if (r.hasF()) {assertEquals(r.f, ir.f);} 95 | if (r.hasD()) {assertEquals(r.d, ir.d);} 96 | if (r.hasI64()) { 97 | assertEquals(Protohx.getLow(r.i64), Protohx.getLow(ir.i64)); 98 | assertEquals(Protohx.getHigh(r.i64), Protohx.getHigh(ir.i64)); 99 | } 100 | if (r.hasFi64()) { 101 | assertEquals(Protohx.getLow(r.fi64), Protohx.getLow(ir.fi64)); 102 | assertEquals(Protohx.getHigh(r.fi64), Protohx.getHigh(ir.fi64)); 103 | } 104 | if (r.hasUi64()) { 105 | assertEquals(Protohx.getLow(r.ui64), Protohx.getLow(ir.ui64)); 106 | assertEquals(Protohx.getHigh(r.ui64), Protohx.getHigh(ir.ui64)); 107 | } 108 | if (r.hasSfi64()) { 109 | assertEquals(Protohx.getLow(r.sfi64), Protohx.getLow(ir.sfi64)); 110 | assertEquals(Protohx.getHigh(r.sfi64), Protohx.getHigh(ir.sfi64)); 111 | } 112 | if (r.hasSi64()) { 113 | assertEquals(Protohx.getLow(r.si64), Protohx.getLow(ir.si64)); 114 | assertEquals(Protohx.getHigh(r.si64), Protohx.getHigh(ir.si64)); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /samples/02-ipc/src/JavaMain.java: -------------------------------------------------------------------------------- 1 | import calc.Calc; 2 | 3 | import java.io.*; 4 | 5 | public class JavaMain { 6 | 7 | public static void main(String[] args) { 8 | try { 9 | InputStream in = (args.length == 0 ? System.in : new FileInputStream(args[0])); 10 | DataInputStream dis = new DataInputStream(in); 11 | DataOutputStream dos = new DataOutputStream(System.out); 12 | 13 | final int len = dis.readUnsignedShort(); 14 | final byte[] frame = new byte[len]; 15 | dis.read(frame); 16 | final Calc.InputMessage inputMessage = Calc.InputMessage.parseFrom(frame); 17 | final Calc.OutputMessage outputMessage = process(inputMessage); 18 | final int size = outputMessage.getSerializedSize(); 19 | dos.writeShort(size); 20 | outputMessage.writeTo(dos); 21 | dos.flush(); 22 | System.out.flush(); 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | private static Calc.OutputMessage process(Calc.InputMessage inputMessage) { 29 | try { 30 | if ((inputMessage.getOpCodesCount() + 1) != inputMessage.getValuesCount()) { 31 | throw new IllegalArgumentException(); 32 | } 33 | int curOpIdx = inputMessage.getOpCodesCount() - 1; 34 | Calc.ValueMessage.Builder acc = inputMessage.getValues(inputMessage.getValuesCount() - 1).toBuilder(); 35 | for (; curOpIdx >= 0; curOpIdx--) { 36 | Calc.ValueMessage.Builder topValue = inputMessage.getValues(curOpIdx).toBuilder(); 37 | final Calc.OpCode opCode = inputMessage.getOpCodes(curOpIdx); 38 | evaluate(opCode, topValue, acc); 39 | } 40 | Calc.OutputMessage.Builder builder = Calc.OutputMessage.newBuilder(); 41 | builder.setSuccess(true); 42 | builder.setValue(acc); 43 | 44 | // builder.setMsg("ok"); 45 | 46 | builder.setMsg("ok: " + 47 | (acc.hasFi64() ? acc.getFi64() : "null") + ":" + 48 | (acc.hasSfi64() ? acc.getSfi64() : "null") + ":" + 49 | (acc.hasUi64() ? acc.getUi64() : "null") + ":" + 50 | (acc.hasSi64() ? acc.getSi64() : "null") + ":" + 51 | (acc.hasI64() ? acc.getI64() : "null")); 52 | 53 | return builder.build(); 54 | } catch (Throwable e) { 55 | Calc.OutputMessage.Builder builder = Calc.OutputMessage.newBuilder(); 56 | builder.setSuccess(false); 57 | builder.setMsg("error: " + e); 58 | return builder.build(); 59 | } 60 | } 61 | 62 | private static void evaluate(Calc.OpCode opCode, Calc.ValueMessage.Builder topValue, Calc.ValueMessage.Builder acc) { 63 | if (topValue.hasI32()) { 64 | final int a = topValue.getI32(); 65 | final int b = acc.getI32(); 66 | final int r = doInt32(opCode, a, b); 67 | acc.setI32(r); 68 | } 69 | if (topValue.hasFi32()) { 70 | final int a = topValue.getFi32(); 71 | final int b = acc.getFi32(); 72 | final int r = doInt32(opCode, a, b); 73 | acc.setFi32(r); 74 | } 75 | if (topValue.hasUi32()) { 76 | final int a = topValue.getUi32(); 77 | final int b = acc.getUi32(); 78 | final int r = doInt32(opCode, a, b); 79 | acc.setUi32(r); 80 | } 81 | if (topValue.hasSi32()) { 82 | final int a = topValue.getSi32(); 83 | final int b = acc.getSi32(); 84 | final int r = doInt32(opCode, a, b); 85 | acc.setSi32(r); 86 | } 87 | if (topValue.hasSfi32()) { 88 | final int a = topValue.getSfi32(); 89 | final int b = acc.getSfi32(); 90 | final int r = doInt32(opCode, a, b); 91 | acc.setSfi32(r); 92 | } 93 | if (topValue.hasFi64()) { 94 | final long a = topValue.getFi64(); 95 | final long b = acc.getFi64(); 96 | final long r = doInt32(opCode, a, b); 97 | acc.setFi64(r); 98 | } 99 | if (topValue.hasSfi64()) { 100 | final long a = topValue.getSfi64(); 101 | final long b = acc.getSfi64(); 102 | final long r = doInt32(opCode, a, b); 103 | acc.setSfi64(r); 104 | } 105 | if (topValue.hasI64()) { 106 | final long a = topValue.getI64(); 107 | final long b = acc.getI64(); 108 | final long r = doInt32(opCode, a, b); 109 | acc.setI64(r); 110 | } 111 | if (topValue.hasSi64()) { 112 | final long a = topValue.getSi64(); 113 | final long b = acc.getSi64(); 114 | final long r = doInt32(opCode, a, b); 115 | acc.setSi64(r); 116 | } 117 | if (topValue.hasUi64()) { 118 | final long a = topValue.getUi64(); 119 | final long b = acc.getUi64(); 120 | final long r = doInt32(opCode, a, b); 121 | acc.setUi64(r); 122 | } 123 | if (topValue.hasF()) { 124 | final float a = topValue.getF(); 125 | final float b = acc.getF(); 126 | final float r; 127 | if (opCode == Calc.OpCode.ADD) { 128 | r = (a + b); 129 | } else if (opCode == Calc.OpCode.SUB) { 130 | r = (a - b); 131 | } else if (opCode == Calc.OpCode.MUL) { 132 | r = (a * b); 133 | } else if (opCode == Calc.OpCode.DIV) { 134 | r = (a / b); 135 | } else { 136 | r = 0; 137 | } 138 | acc.setF(r); 139 | } 140 | if (topValue.hasD()) { 141 | final double a = topValue.getD(); 142 | final double b = acc.getD(); 143 | final double r; 144 | if (opCode == Calc.OpCode.ADD) { 145 | r = (a + b); 146 | } else if (opCode == Calc.OpCode.SUB) { 147 | r = (a - b); 148 | } else if (opCode == Calc.OpCode.MUL) { 149 | r = (a * b); 150 | } else if (opCode == Calc.OpCode.DIV) { 151 | r = (a / b); 152 | } else { 153 | r = 0; 154 | } 155 | acc.setD(r); 156 | } 157 | } 158 | 159 | private static long doInt32(Calc.OpCode opCode, long a, long b) { 160 | final long r; 161 | if (opCode == Calc.OpCode.ADD) { 162 | r = (a + b); 163 | } else if (opCode == Calc.OpCode.SUB) { 164 | r = (a - b); 165 | } else if (opCode == Calc.OpCode.MUL) { 166 | r = (a * b); 167 | } else if (opCode == Calc.OpCode.DIV) { 168 | r = (a / b); 169 | } else { 170 | r = 0; 171 | } 172 | return r; 173 | } 174 | 175 | private static int doInt32(Calc.OpCode opCode, int a, int b) { 176 | int r; 177 | if (opCode == Calc.OpCode.ADD) { 178 | r = (a + b); 179 | } else if (opCode == Calc.OpCode.SUB) { 180 | r = (a - b); 181 | } else if (opCode == Calc.OpCode.MUL) { 182 | r = (a * b); 183 | } else if (opCode == Calc.OpCode.DIV) { 184 | r = (a / b); 185 | } else { 186 | r = 0; 187 | } 188 | return r; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /samples/03-network/README.md: -------------------------------------------------------------------------------- 1 | Crossplatform network Protohx example. :) 2 | 3 | [Compiled demos (node.js/neko server and html5/android/flash/linux/node.js clients) ](https://bitbucket.org/nitrobin/protohx/downloads/protohx-demo.tar.gz) 4 | 5 | 6 | ## Client targets 7 | ### Client implemented for most of NME targets: 8 | * html5 (via socket.io) [live demo here](http://protohx.ap01.aws.af.cm/) 9 | * linux, android (sys.net.Socket) 10 | * flash (flash.net.Socket) 11 | 12 | 13 | ## Server targets 14 | ###neko 15 | * server.native.MainServer - simple neko socket server based on neko.net.ThreadServer. 16 | 17 | ###node.js 18 | * server.nodejs.BotClient - node.js TCP-socket bot client; 19 | * server.nodejs.NetServer - node.js server with TCP-socket clients support (flash, cpp); 20 | * server.nodejs.SocketIoServer - node.js server with socket.io clients support (html5); 21 | * server.nodejs.MultiServer - node.js server with TCP-socket and socket.io clients support (html5, flash, cpp). 22 | 23 | Server logic implemented in server.logic.SessionRegistry 24 | -------------------------------------------------------------------------------- /samples/03-network/build-client-flash.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | #-cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main client.MainClient 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -lib actuate 12 | 13 | 14 | -swf out/run.swf 15 | -swf-header 320:320:40:FFFFFF 16 | 17 | --next 18 | 19 | -cmd flashplayerdebugger out/run.swf -------------------------------------------------------------------------------- /samples/03-network/build-client-nodejs-net-bot.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main server.nodejs.BotClient 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -lib nodejs 12 | 13 | 14 | -js out/bot.js 15 | 16 | --next 17 | 18 | -cmd node out/bot.js -------------------------------------------------------------------------------- /samples/03-network/build-server-java.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/java-server 4 | -cmd wget -O out/netty.jar -c http://repo2.maven.org/maven2/io/netty/netty/3.6.5.Final/netty-3.6.5.Final.jar 5 | 6 | --next 7 | 8 | -main server.java.MainServer 9 | -cp src 10 | -cp out/src-gen 11 | -lib protohx 12 | #-lib javastd 13 | 14 | 15 | -java out/java-server 16 | -java-lib out/netty.jar 17 | 18 | --next 19 | 20 | -cmd java -jar out/java-server/java-server.jar 21 | -------------------------------------------------------------------------------- /samples/03-network/build-server-neko.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | #-cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main server.native.MainServer 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | 12 | 13 | -neko out/MainServer.n 14 | 15 | --next 16 | 17 | -cmd neko out/MainServer.n -------------------------------------------------------------------------------- /samples/03-network/build-server-nodejs-multi.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | 4 | -cmd mkdir -p out/socket-io 5 | -cmd haxelib run nme build html5 6 | 7 | -cmd mkdir -p out/socket-io/static 8 | -cmd cp index.html out/socket-io/static/ 9 | -cmd cp package.json out/socket-io/ 10 | -cmd cp out/html5/bin/protohx-samples-network-client.js out/socket-io/static/client.js 11 | 12 | --next 13 | 14 | -main server.nodejs.MultiServer 15 | -cp src 16 | -cp out/src-gen 17 | -lib protohx 18 | -lib nodejs 19 | 20 | 21 | -js out/socket-io/server.js 22 | 23 | --next 24 | 25 | -cmd cd out/socket-io 26 | -cmd pwd 27 | -cmd npm install 28 | -cmd node server.js -------------------------------------------------------------------------------- /samples/03-network/build-server-nodejs-net.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main server.nodejs.NetServer 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -lib nodejs 12 | 13 | 14 | -js out/server.js 15 | 16 | --next 17 | 18 | -cmd node out/server.js -------------------------------------------------------------------------------- /samples/03-network/build-server-nodejs-socket-io.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | 4 | -cmd mkdir -p out/socket-io 5 | -cmd haxelib run nme build html5 6 | 7 | -cmd mkdir -p out/socket-io/static 8 | -cmd cp index.html out/socket-io/static/ 9 | -cmd cp package.json out/socket-io/ 10 | -cmd cp out/html5/bin/protohx-samples-network-client.js out/socket-io/static/client.js 11 | 12 | --next 13 | 14 | -main server.nodejs.SocketIoServer 15 | -cp src 16 | -cp out/src-gen 17 | -lib protohx 18 | -lib nodejs 19 | 20 | 21 | -js out/socket-io/server.js 22 | 23 | --next 24 | 25 | -cmd cd out/socket-io 26 | -cmd pwd 27 | -cmd npm install 28 | -cmd node server.js -------------------------------------------------------------------------------- /samples/03-network/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | protohx - network test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /samples/03-network/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "protohx", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "start": "node server.js" 6 | }, 7 | "engines": { 8 | "node": "0.10.x" 9 | }, 10 | "dependencies": { 11 | "socket.io": "0.9.14", 12 | "express": "4.17.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /samples/03-network/project.nmml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/03-network/proto/protocol.proto: -------------------------------------------------------------------------------- 1 | package samples; 2 | 3 | enum ClientType { 4 | CT_UNKNOWN = 0; 5 | CT_HUMAN = 1; 6 | CT_BOT = 2; 7 | } 8 | enum ClientPlatform { 9 | CP_UNKNOWN = 0; 10 | CP_LINUX = 1; 11 | CP_FLASH = 2; 12 | CP_ANDROID = 3; 13 | CP_HTML5 = 4; 14 | CP_NODEJS = 5; 15 | CP_WINDOWS = 6; 16 | CP_IOS = 7; 17 | } 18 | 19 | message LoginReq { 20 | optional string status = 1; 21 | optional ClientType clientType = 2 [default = CT_UNKNOWN]; 22 | optional ClientPlatform clientPlatform = 3 [default = CP_UNKNOWN]; 23 | } 24 | 25 | message LoginRes { 26 | required int32 id = 1; 27 | } 28 | 29 | message PlayerData { 30 | optional int32 id = 1; 31 | optional string nick = 2; 32 | optional int32 x = 3; 33 | optional int32 y = 4; 34 | optional string status = 5; 35 | optional ClientType clientType = 6 [default = CT_UNKNOWN]; 36 | optional ClientPlatform clientPlatform = 7 [default = CP_UNKNOWN]; 37 | } 38 | 39 | message RemovePlayerRes { 40 | required int32 id = 1; 41 | } 42 | 43 | message ProtocolMessage { 44 | enum MsgType { 45 | LOGIN_REQ = 100; 46 | LOGIN_RES = 101; 47 | ADD_PLAYER_RES = 102; 48 | UPDATE_PLAYER_REQ = 103; 49 | UPDATE_PLAYER_RES = 104; 50 | REMOVE_PLAYER_RES = 105; 51 | } 52 | 53 | required MsgType type = 1; 54 | optional LoginReq loginReq = 2; 55 | optional LoginRes loginRes = 3; 56 | optional PlayerData addPlayerRes = 4; 57 | optional PlayerData updatePlayerReq = 5; 58 | optional PlayerData updatePlayerRes = 6; 59 | optional RemovePlayerRes removePlayerRes = 7; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /samples/03-network/protohx.json: -------------------------------------------------------------------------------- 1 | { 2 | "protoPath": "proto", 3 | "protoFiles": [ 4 | "proto/protocol.proto" 5 | ], 6 | "cleanOut": true, 7 | "haxeOut": "out/src-gen", 8 | "javaOut": null 9 | } -------------------------------------------------------------------------------- /samples/03-network/src/client/MainClient.hx: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import samples.ClientType; 4 | import samples.ClientPlatform; 5 | import flash.text.TextFieldType; 6 | import samples.PlayerData; 7 | import samples.LoginReq; 8 | import samples.ProtocolMessage; 9 | import samples.protocolmessage.MsgType; 10 | 11 | import common.Config; 12 | import common.MsgQueue; 13 | import common.SocketConnection; 14 | 15 | import protohx.Message; 16 | import protohx.Protohx; 17 | 18 | import haxe.io.Bytes; 19 | 20 | import flash.text.TextField; 21 | import flash.display.Sprite; 22 | import flash.events.MouseEvent; 23 | 24 | import motion.Actuate; 25 | import motion.easing.Quad; 26 | 27 | 28 | class PlayerNode extends flash.display.Sprite { 29 | public var player:PlayerData; 30 | private var tf:TextField; 31 | private var me:Bool; 32 | private var bot:Bool; 33 | 34 | public function new(player:PlayerData, myId:Int) { 35 | super(); 36 | this.player = player; 37 | // trace(protohx.MessageUtils.toJson(player)); 38 | me = (player.id == myId); 39 | bot = (player.clientType == ClientType.CT_BOT); 40 | 41 | graphics.clear(); 42 | graphics.lineStyle(me ? 3 : 1, me ? 0xff0000 : 0x000000); 43 | graphics.beginFill(bot ? 0x880000 : 0x00ff00); 44 | // graphics.drawCircle(0, 0, 20); 45 | graphics.drawRect(-15, -15, 40, 40); 46 | graphics.endFill(); 47 | 48 | tf = new TextField(); 49 | tf.x = -15 ; 50 | tf.y = -15 ; 51 | tf.selectable = false; 52 | addChild(tf); 53 | rebuild(false); 54 | } 55 | 56 | public function rebuild(animate:Bool) { 57 | tf.text = '' + player.nick + '\n[' + Config.getPlatformName(player.clientPlatform) + ']'; 58 | if (animate) { 59 | var duration:Float = 1.0; 60 | var targetX:Float = player.x; 61 | var targetY:Float = player.y; 62 | Actuate.stop(this); 63 | Actuate.tween(this, duration, { x: targetX, y: targetY }, true).ease(Quad.easeOut); 64 | 65 | } else { 66 | x = player.x; 67 | y = player.y; 68 | } 69 | 70 | } 71 | } 72 | 73 | 74 | class SimpleBtn extends flash.display.Sprite { 75 | public var btn:TextField; 76 | 77 | public function new(label:String) { 78 | super(); 79 | 80 | btn = new TextField(); 81 | btn.defaultTextFormat.size = 24; 82 | btn.text = ""+label; 83 | btn.border = true; 84 | btn.borderColor = 0xff0000; 85 | btn.backgroundColor = 0x00ff00; 86 | btn.background = true; 87 | btn.selectable = false; 88 | btn.height = 28; 89 | btn.width = 100; 90 | btn.x = 0; 91 | btn.y = 0; 92 | addChild(btn); 93 | graphics.clear(); 94 | graphics.beginFill(0x00ff00); 95 | graphics.drawRect(0, 0, 100, 28); 96 | graphics.endFill(); 97 | 98 | } 99 | } 100 | 101 | class AddressSprite extends flash.display.Sprite { 102 | public var hostTF:TextField; 103 | public var portTF:TextField; 104 | public var btn:Sprite; 105 | 106 | public function new(host:String, port:Int) { 107 | super(); 108 | hostTF = new TextField(); 109 | hostTF.type = TextFieldType.INPUT; 110 | hostTF.defaultTextFormat.size = 24; 111 | hostTF.text = host; 112 | hostTF.border = true; 113 | hostTF.borderColor = 0x000000; 114 | hostTF.height = 28; 115 | hostTF.width = 100; 116 | hostTF.x = 0; 117 | hostTF.y = 0; 118 | addChild(hostTF); 119 | 120 | portTF = new TextField(); 121 | portTF.type = TextFieldType.INPUT; 122 | portTF.defaultTextFormat.size = 24; 123 | portTF.text = Std.string(port); 124 | portTF.border = true; 125 | portTF.borderColor = 0x000000; 126 | portTF.height = 28; 127 | portTF.width = 100; 128 | portTF.x = 0; 129 | portTF.y = 30; 130 | addChild(portTF); 131 | 132 | btn = new SimpleBtn("connect"); 133 | btn.x = 0; 134 | btn.y = 60; 135 | addChild(btn); 136 | } 137 | } 138 | 139 | class MainClient extends flash.display.Sprite { 140 | 141 | var msgQueue:MsgQueue; 142 | var players:IntMap; 143 | var s:SocketConnection; 144 | var welcome:Sprite; 145 | 146 | public static function main() { 147 | flash.Lib.current.addChild(new MainClient()); 148 | } 149 | 150 | public function new() { 151 | super(); 152 | graphics.clear(); 153 | graphics.beginFill(0x888888); 154 | graphics.drawRect(0, 0, 400, 400); 155 | graphics.endFill(); 156 | welcome = new Sprite(); 157 | 158 | #if js 159 | var btn = new SimpleBtn("connect"); 160 | btn.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):Void{ 161 | connect("", 0); 162 | }); 163 | welcome.addChild(btn); 164 | #else 165 | var address = new AddressSprite(Config.DEFAULT_HOST, Config.DEFAULT_TCP_PORT); 166 | address.btn.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):Void{ 167 | var host = address.hostTF.text; 168 | var port = Std.parseInt(address.portTF.text); 169 | connect(host, port); 170 | }); 171 | welcome.addChild(address); 172 | #end 173 | 174 | start(); 175 | } 176 | 177 | private function start():Void { 178 | addChild(welcome); 179 | } 180 | 181 | private function connect(host, port):Void { 182 | removeChild(welcome); 183 | players = new IntMap(); 184 | msgQueue = new MsgQueue(); 185 | s = new SocketConnection(); 186 | s.connect(host, port, onConnect, addBytes, onClose); 187 | } 188 | 189 | private function onClick(e:MouseEvent):Void { 190 | var msg = new ProtocolMessage(); 191 | msg.type = MsgType.UPDATE_PLAYER_REQ; 192 | msg.updatePlayerReq = new PlayerData(); 193 | msg.updatePlayerReq.x = cast e.stageX; 194 | msg.updatePlayerReq.y = cast e.stageY; 195 | s.writeMsg(msg); 196 | } 197 | 198 | private function onClose():Void { 199 | trace("connection closed"); 200 | removeEventListener(MouseEvent.CLICK, onClick); 201 | while(numChildren>0){ 202 | removeChildAt(0); 203 | } 204 | graphics.clear(); 205 | graphics.beginFill(0xff8888); 206 | graphics.drawRect(0, 0, 400, 400); 207 | graphics.endFill(); 208 | } 209 | 210 | private function onConnect():Void { 211 | addEventListener(MouseEvent.CLICK, onClick); 212 | var msg = new ProtocolMessage(); 213 | msg.type = MsgType.LOGIN_REQ; 214 | msg.loginReq = new LoginReq(); 215 | msg.loginReq.status = "ok"; 216 | msg.loginReq.clientType = ClientType.CT_HUMAN; 217 | msg.loginReq.clientPlatform = Config.getPlatform(); 218 | s.writeMsg(msg); 219 | graphics.clear(); 220 | graphics.beginFill(0x88ff88); 221 | graphics.drawRect(0, 0, 400, 400); 222 | graphics.endFill(); 223 | } 224 | 225 | private var myId:Int; 226 | 227 | private function addBytes(bytes:Bytes):Void { 228 | msgQueue.addBytes(bytes); 229 | while (msgQueue.hasMsg()) { 230 | var msg:ProtocolMessage = msgQueue.popMsg(); 231 | // trace('CLIENT MSG: ' + haxe.Json.stringify(msg)); 232 | if (msg.type == MsgType.LOGIN_RES) { 233 | myId = msg.loginRes.id; 234 | } else if (msg.type == MsgType.REMOVE_PLAYER_RES) { 235 | var node = players.get(msg.removePlayerRes.id); 236 | if (node != null) { 237 | players.remove(msg.removePlayerRes.id) ; 238 | removeChild(node); 239 | } 240 | } else if (msg.type == MsgType.ADD_PLAYER_RES) { 241 | var p = msg.addPlayerRes; 242 | var node = new PlayerNode(p, myId); 243 | players.set(p.id, node); 244 | addChild(node); 245 | } else if (msg.type == MsgType.UPDATE_PLAYER_RES) { 246 | var node = players.get(msg.updatePlayerRes.id); 247 | if (node != null) { 248 | if (msg.updatePlayerRes.hasX()) { 249 | node.player.x = msg.updatePlayerRes.x; 250 | } 251 | if (msg.updatePlayerRes.hasY()) { 252 | node.player.y = msg.updatePlayerRes.y; 253 | } 254 | node.rebuild(true); 255 | } 256 | } 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /samples/03-network/src/common/Base64.hx: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | #if haxe3 4 | import haxe.crypto.BaseCode; 5 | #else 6 | import haxe.BaseCode; 7 | #end 8 | 9 | class Base64 { 10 | private inline static var BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 11 | private static var codec:BaseCode; 12 | 13 | public function new() { 14 | 15 | } 16 | 17 | static function getCodec():BaseCode { 18 | if (codec == null) { 19 | var bytes = haxe.io.Bytes.ofString(BASE64); 20 | codec = new BaseCode(bytes); 21 | } 22 | return codec; 23 | } 24 | 25 | public static function encodeBase64(content:haxe.io.Bytes):String { 26 | var suffix = switch (content.length % 3){ 27 | case 2: "="; 28 | case 1: "=="; 29 | default: ""; 30 | }; 31 | 32 | var bytes = getCodec().encodeBytes(content); 33 | return bytes.toString() + suffix; 34 | } 35 | 36 | private static function removeNullbits(s:String):String { 37 | var len = s.length; 38 | while (len > 0 && s.charAt(len - 1) == "=") { 39 | len--; 40 | if (len <= 0) { 41 | return ""; 42 | } 43 | } 44 | return s.substr(0, len); 45 | } 46 | 47 | public static function decodeBase64(content:String):haxe.io.Bytes { 48 | var bytes:haxe.io.Bytes = haxe.io.Bytes.ofString(removeNullbits(content)); 49 | return getCodec().decodeBytes(bytes); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /samples/03-network/src/common/Config.hx: -------------------------------------------------------------------------------- 1 | package common; 2 | import samples.ClientType; 3 | import samples.ClientPlatform; 4 | 5 | class Config { 6 | public static inline var DEFAULT_HOST:String = #if android "192.168.0.1" #else "127.0.0.1" #end; 7 | public static inline var DEFAULT_TCP_PORT:Int = 15000; 8 | public static inline var DEFAULT_HTTP_PORT:Int = 15001; 9 | public static inline var ADDITIONAL_POLICY_PORT:Int = 15002; 10 | 11 | public static function getTypeName(code:Int):String { 12 | return switch(code){ 13 | case ClientType.CT_BOT: "bot"; 14 | case ClientType.CT_HUMAN: "human"; 15 | //case ClientType.CT_UNKNOWN: 16 | default: "unknown"; 17 | } 18 | } 19 | public static function getPlatformName(code:Int):String { 20 | return switch(code){ 21 | case ClientPlatform.CP_ANDROID: "android"; 22 | case ClientPlatform.CP_LINUX: "linux"; 23 | case ClientPlatform.CP_HTML5: "html5"; 24 | case ClientPlatform.CP_FLASH: "flash"; 25 | case ClientPlatform.CP_WINDOWS: "win"; 26 | case ClientPlatform.CP_IOS: "ios"; 27 | case ClientPlatform.CP_NODEJS: "node.js"; 28 | //case ClientPlatform.CP_UNKNOWN: 29 | default: "unknown"; 30 | } 31 | } 32 | public static function getPlatform():Int { 33 | return 34 | #if (flash || as3) 35 | ClientPlatform.CP_FLASH; 36 | #elseif (android) 37 | ClientPlatform.CP_ANDROID; 38 | #elseif (js || html5) 39 | ClientPlatform.CP_HTML5; 40 | #elseif (linux) 41 | ClientPlatform.CP_LINUX; 42 | #elseif (windows) 43 | ClientPlatform.CP_WINDOWS; 44 | #elseif (ios) 45 | ClientPlatform.CP_IOS 46 | #else 47 | ClientPlatform.CP_UNKNOWN; 48 | #end 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /samples/03-network/src/common/MsgQueue.hx: -------------------------------------------------------------------------------- 1 | package common; 2 | import samples.ProtocolMessage; 3 | import haxe.io.BytesInput; 4 | import haxe.io.BytesBuffer; 5 | import haxe.io.Bytes; 6 | 7 | class MsgQueue { 8 | public static inline var HEADER_SIZE:Int = 2; 9 | 10 | private var bytesBuff:Bytes; 11 | private var msgs:List; 12 | 13 | public function new() { 14 | msgs = new List(); 15 | } 16 | 17 | public inline function hasMsg():Bool { 18 | return !msgs.isEmpty(); 19 | } 20 | 21 | public inline function popMsg():ProtocolMessage { 22 | return msgs.pop(); 23 | } 24 | 25 | public inline function addMsg(msg:ProtocolMessage):Void { 26 | msgs.add(msg); 27 | } 28 | 29 | public function addBytes(bytes:Bytes) { 30 | if(bytes == null){ 31 | return; 32 | } 33 | if (bytesBuff == null) { 34 | bytesBuff = bytes; 35 | } else { 36 | var buffer = new BytesBuffer(); 37 | buffer.add(bytesBuff); 38 | buffer.add(bytes); 39 | bytesBuff = buffer.getBytes(); 40 | } 41 | if (bytesBuff == null || bytesBuff.length < HEADER_SIZE) { 42 | return; 43 | } 44 | var available = bytesBuff.length; 45 | var bi = new BytesInput(bytesBuff); 46 | bi.bigEndian = false; 47 | while (available >= HEADER_SIZE) { 48 | var packetSize = bi.readUInt16(); 49 | available -= HEADER_SIZE; 50 | if (packetSize <= available) { 51 | available -= packetSize; 52 | var msgBytes = bi.read(packetSize); 53 | var msg = new ProtocolMessage(); 54 | msg.mergeFrom(msgBytes); 55 | addMsg(msg); 56 | } else { 57 | available += HEADER_SIZE; 58 | break; 59 | } 60 | } 61 | if (available == 0) { 62 | bytesBuff = null; 63 | } else if (available > 0) { 64 | if (bytesBuff.length != available) { 65 | var pos = bytesBuff.length - available; 66 | bytesBuff = bytesBuff.sub(pos, available); 67 | } 68 | } else { 69 | throw "Wrong available: " + available; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /samples/03-network/src/common/SocketConnection.hx: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | import haxe.io.BytesData; 4 | import haxe.io.BytesOutput; 5 | import haxe.io.Bytes; 6 | import haxe.io.Eof; 7 | #if flash 8 | 9 | import flash.events.Event; 10 | import flash.events.ErrorEvent; 11 | import flash.events.IOErrorEvent; 12 | import flash.events.SecurityErrorEvent; 13 | import flash.events.ProgressEvent; 14 | class SocketConnection { 15 | var socket:flash.net.Socket; 16 | 17 | public function connect(host, port, onConnect, addBytes, onClose) { 18 | socket.connect(host, port); 19 | this.onConnect = onConnect; 20 | this.onClose = onClose; 21 | this.addBytes = addBytes; 22 | } 23 | 24 | public dynamic function onConnect():Void {} 25 | public dynamic function onClose():Void {} 26 | public dynamic function addBytes(bytes:Bytes):Void {} 27 | 28 | public function new() { 29 | socket = new flash.net.Socket(); 30 | socket.addEventListener(Event.CLOSE, closeHandler); 31 | socket.addEventListener(IOErrorEvent.IO_ERROR, errorHandler); 32 | socket.addEventListener(IOErrorEvent.NETWORK_ERROR, errorHandler); 33 | socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler); 34 | socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); 35 | socket.addEventListener(Event.CONNECT, connectHandler); 36 | socket.endian = flash.utils.Endian.LITTLE_ENDIAN ; 37 | } 38 | 39 | private function closeHandler(e:Event):Void { 40 | trace("closeHandler"); 41 | detach(); 42 | onClose(); 43 | } 44 | 45 | private function errorHandler(e:ErrorEvent):Void { 46 | trace("errorHandler" + Std.string(e)); 47 | detach(); 48 | onClose(); 49 | } 50 | 51 | private function connectHandler(e:Event):Void { 52 | // trace("connectHandler"); 53 | onConnect(); 54 | } 55 | 56 | public function writeMsg(msg:protohx.Message):Void { 57 | var b = new BytesOutput(); 58 | msg.writeTo(b); 59 | var bytes = b.getBytes(); 60 | socket.writeShort(bytes.length); 61 | socket.writeBytes(cast bytes.getData()); 62 | } 63 | 64 | private function socketDataHandler(e:ProgressEvent):Void { 65 | try { 66 | // trace("socketDataHandler"); 67 | var b = new flash.utils.ByteArray(); 68 | socket.readBytes(b); 69 | var bs = Bytes.ofData(cast b); 70 | addBytes(bs); 71 | } catch (e:Dynamic) { 72 | trace('error: ' + e); 73 | } 74 | } 75 | 76 | public function detach():Void { 77 | socket.removeEventListener(Event.CLOSE, closeHandler); 78 | socket.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler); 79 | socket.removeEventListener(IOErrorEvent.NETWORK_ERROR, errorHandler); 80 | socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler); 81 | socket.removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); 82 | socket.removeEventListener(Event.CONNECT, connectHandler); 83 | } 84 | } 85 | #elseif (neko||cpp) 86 | class SocketConnection { 87 | var socket:sys.net.Socket; 88 | 89 | public function connect(host, port, onConnect, addBytes, onClose) { 90 | this.onConnect = onConnect; 91 | this.addBytes = addBytes; 92 | this.onClose = onClose; 93 | try{ 94 | socket.connect(new sys.net.Host(host), port); 95 | }catch(e:Dynamic){ 96 | trace(e); 97 | #if haxe3 98 | trace(haxe.CallStack.toString(haxe.CallStack.exceptionStack())); 99 | #else 100 | trace(haxe.Stack.toString(haxe.Stack.exceptionStack())); 101 | #end 102 | onClose(); 103 | return; 104 | } 105 | trace("connected"); 106 | onConnect(); 107 | 108 | var buffer = Bytes.alloc(1024); 109 | var socks = [socket]; 110 | var timer = new haxe.Timer(100); 111 | timer.run = function() { 112 | try { 113 | var r:Array; 114 | do { 115 | r = sys.net.Socket.select(socks, null, null, 0.001).read; 116 | for (s in r) { 117 | var size = s.input.readBytes(buffer, 0, buffer.length); 118 | addBytes(buffer.sub(0, size)); 119 | } 120 | } while (r.length > 0); 121 | } catch (e:haxe.io.Eof) { 122 | timer.stop(); 123 | onClose(); 124 | socket.close(); 125 | } catch (e:Dynamic) { 126 | trace(e); 127 | #if haxe3 128 | trace(haxe.CallStack.toString(haxe.CallStack.exceptionStack())); 129 | #else 130 | trace(haxe.Stack.toString(haxe.Stack.exceptionStack())); 131 | #end 132 | } 133 | }; 134 | } 135 | 136 | public dynamic function onConnect():Void {} 137 | public dynamic function onClose():Void {} 138 | public dynamic function addBytes(bytes:Bytes):Void {} 139 | 140 | public function new() { 141 | socket = new sys.net.Socket(); 142 | socket.input.bigEndian = false; 143 | socket.output.bigEndian = false; 144 | } 145 | 146 | public function writeMsg(msg:protohx.Message):Void { 147 | var b = new BytesOutput(); 148 | msg.writeTo(b); 149 | var bytes = b.getBytes(); 150 | socket.output.writeUInt16(bytes.length); 151 | socket.output.writeBytes(bytes, 0, bytes.length); 152 | } 153 | } 154 | #elseif js 155 | class SocketConnection { 156 | var socket:Dynamic; 157 | 158 | public dynamic function onConnect():Void {} 159 | public dynamic function onClose():Void {} 160 | public dynamic function addBytes(bytes:Bytes):Void {} 161 | 162 | public function new() { 163 | 164 | } 165 | 166 | public function handleMsg(msg:String):Void { 167 | } 168 | public function writeMsg(msg:protohx.Message):Void { 169 | socket.emit("message", Base64.encodeBase64(msgToFrameBytes(msg))); 170 | } 171 | 172 | public static function msgToFrameBytes(msg:protohx.Message):haxe.io.Bytes { 173 | var b = new BytesOutput(); 174 | msg.writeTo(b); 175 | var data = b.getBytes(); 176 | 177 | var res = new BytesOutput(); 178 | res.writeUInt16(data.length); 179 | res.write(data); 180 | return res.getBytes(); 181 | } 182 | 183 | public function connect(host, port, onConnect, addBytes, onClose) { 184 | this.onConnect = onConnect; 185 | this.addBytes = addBytes; 186 | this.onClose = onClose; 187 | var self = this; 188 | var decodeBytes = Base64.decodeBase64; 189 | untyped __js__(" 190 | //self.socket = io.connect('http://'+host+':'+port); 191 | self.socket = io.connect(); 192 | this.socket.on('connect', function () { 193 | onConnect(); 194 | self.socket.on('message', function (msg) { 195 | addBytes(decodeBytes(msg)); 196 | }); 197 | self.socket.on('disconnect', function (msg) { 198 | onClose(); 199 | self.socket.disconnect(); 200 | onConnect = function(){} 201 | onClose = function(){} 202 | addBytes = function(b){} 203 | }); 204 | }); 205 | "); 206 | } 207 | } 208 | 209 | #end 210 | -------------------------------------------------------------------------------- /samples/03-network/src/server/java/MainServer.hx: -------------------------------------------------------------------------------- 1 | package server.java; 2 | 3 | //#if java 4 | 5 | import common.Config; 6 | import server.logic.SessionRegistry; 7 | import server.logic.Session; 8 | import server.logic.BakedMsg; 9 | import haxe.io.BytesOutput; 10 | import haxe.io.Bytes; 11 | 12 | 13 | import java.net.InetSocketAddress; 14 | import java.util.concurrent.Executors; 15 | 16 | import org.jboss.netty.bootstrap.ServerBootstrap; 17 | import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; 18 | import org.jboss.netty.channel.ChannelPipeline; 19 | import org.jboss.netty.channel.ChannelPipelineFactory; 20 | import org.jboss.netty.channel.ChannelEvent; 21 | import org.jboss.netty.channel.ChannelHandlerContext; 22 | import org.jboss.netty.channel.ChannelStateEvent; 23 | import org.jboss.netty.channel.ExceptionEvent; 24 | import org.jboss.netty.channel.MessageEvent; 25 | import org.jboss.netty.channel.SimpleChannelUpstreamHandler; 26 | import org.jboss.netty.channel.ChannelStateEvent; 27 | import org.jboss.netty.channel.Channel; 28 | import org.jboss.netty.buffer.ChannelBuffer; 29 | import org.jboss.netty.buffer.ChannelBuffers; 30 | import org.jboss.netty.channel.Channels; 31 | 32 | class NettySession extends Session { 33 | 34 | public var channel:Channel; 35 | 36 | public function new(channel:Channel) { 37 | super(); 38 | this.channel = channel; 39 | } 40 | 41 | public override function close():Void { 42 | channel.close(); 43 | } 44 | 45 | public override function bakeMsg(msg:protohx.Message):BakedMsg { 46 | return new BakedMsg(msg); 47 | } 48 | 49 | public override function writeMsgBaked(msg:BakedMsg):Void { 50 | writeMsg(msg.msg); 51 | } 52 | 53 | public override function writeMsg(msg:protohx.Message):Void { 54 | try{ 55 | var bytes = msgToFrameBytes(msg); 56 | channel.write(ChannelBuffers.wrappedBuffer(bytes.getData())); 57 | }catch(e:Dynamic){ 58 | trace(e); 59 | #if haxe3 60 | trace(haxe.CallStack.toString(haxe.CallStack.exceptionStack())); 61 | #else 62 | trace(haxe.Stack.toString(haxe.Stack.exceptionStack())); 63 | #end 64 | } 65 | } 66 | public static function msgToFrameBytes(msg:protohx.Message):haxe.io.Bytes { 67 | var b = new BytesOutput(); 68 | msg.writeTo(b); 69 | var data = b.getBytes(); 70 | 71 | var res = new BytesOutput(); 72 | res.writeUInt16(data.length); 73 | res.write(data); 74 | return res.getBytes(); 75 | } 76 | 77 | } 78 | 79 | class MainServer { 80 | var sr:SessionRegistry; 81 | 82 | public function new() { 83 | sr = new SessionRegistry(); 84 | } 85 | 86 | public static function main() { 87 | var server = new MainServer(); 88 | trace("Running.."); 89 | server.run("0.0.0.0", Config.DEFAULT_TCP_PORT); 90 | } 91 | 92 | public function run(host:String, port:Int) /*throws Exception*/ { 93 | // Configure the server. 94 | var bootstrap = new ServerBootstrap( 95 | new NioServerSocketChannelFactory( 96 | Executors.newCachedThreadPool(), 97 | Executors.newCachedThreadPool())); 98 | 99 | // Set up the event pipeline factory. 100 | bootstrap.setPipelineFactory(new ServerPipelineFactory(sr)); 101 | 102 | // Bind and start to accept incoming connections. 103 | bootstrap.bind(new InetSocketAddress(port)); 104 | } 105 | } 106 | 107 | 108 | class ServerPipelineFactory implements ChannelPipelineFactory { 109 | var sr:SessionRegistry; 110 | public function new(sr:SessionRegistry) { 111 | this.sr = sr; 112 | } 113 | 114 | public function getPipeline():ChannelPipeline /*throws Exception*/ { 115 | var p:ChannelPipeline = Channels.pipeline(); 116 | p.addLast("handler", new ServerHandler(sr)); 117 | return p; 118 | } 119 | } 120 | 121 | class ServerHandler extends SimpleChannelUpstreamHandler { 122 | var sr:SessionRegistry; 123 | public function new(sr:SessionRegistry) { 124 | super(); 125 | this.sr = sr; 126 | } 127 | 128 | @:overload 129 | @:throws("java.lang.Exception") 130 | public override function handleUpstream(ctx:ChannelHandlerContext, e:ChannelEvent):Void 131 | /*throws Exception*/ { 132 | if (Std.is(e, ChannelStateEvent)) { 133 | trace(e); 134 | } 135 | super.handleUpstream(ctx, e); 136 | } 137 | @:overload 138 | @:throws("java.lang.Exception") 139 | public override function channelConnected(ctx:ChannelHandlerContext, e:ChannelStateEvent):Void 140 | /*throws Exception*/ { 141 | var c = e.getChannel(); 142 | var session = new NettySession(c); 143 | ctx.setAttachment(session); 144 | trace("client: " + session.id + " / " + c); 145 | java.Lib.lock(sr,{sr.sessionConnect(session);0;}); 146 | } 147 | 148 | @:overload 149 | @:throws("java.lang.Exception") 150 | public override function channelDisconnected(ctx:ChannelHandlerContext, 151 | e:ChannelStateEvent):Void 152 | /*throws Exception*/ { 153 | var session: NettySession = cast ctx.getAttachment(); 154 | if(session!=null){ 155 | trace("client " + Std.string(session.id) + " disconnected"); 156 | java.Lib.lock(sr,{sr.sessionDisconnect(session);0; }); 157 | } 158 | } 159 | 160 | @:overload 161 | @:throws("java.lang.Exception") 162 | public override function messageReceived(ctx:ChannelHandlerContext, e:MessageEvent ) { 163 | if(Std.is(e.getMessage(), ChannelBuffer)){ 164 | var buffer:ChannelBuffer = cast(e.getMessage(), ChannelBuffer); 165 | var bytes = haxe.io.Bytes.ofData(buffer.array()); 166 | trace("bytes: "+bytes.length); 167 | var session: NettySession = cast ctx.getAttachment(); 168 | if(session!=null){ 169 | java.Lib.lock(sr,{sr.sessionData(session, bytes);0;}); 170 | } 171 | } else { 172 | trace("WARN: "+ e.getMessage()); 173 | } 174 | } 175 | 176 | @:overload 177 | @:throws("java.lang.Exception") 178 | public override function exceptionCaught(ctx:ChannelHandlerContext, e:ExceptionEvent) { 179 | trace("Unexpected exception from downstream." + e.getCause()); 180 | e.getChannel().close(); 181 | } 182 | } 183 | 184 | //#end 185 | 186 | -------------------------------------------------------------------------------- /samples/03-network/src/server/logic/BakedMsg.hx: -------------------------------------------------------------------------------- 1 | package server.logic; 2 | class BakedMsg { 3 | public var msg:protohx.Message; 4 | public var data:Dynamic; 5 | public function new(msg:protohx.Message, ?data:Dynamic) { 6 | this.msg = msg; 7 | this.data = data; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/03-network/src/server/logic/Session.hx: -------------------------------------------------------------------------------- 1 | package server.logic; 2 | import common.MsgQueue; 3 | import samples.ProtocolMessage; 4 | import samples.PlayerData; 5 | 6 | class Session { 7 | public var id:Int; 8 | public var player:PlayerData; 9 | 10 | public var incomeMsgQueue:MsgQueue; 11 | 12 | public function new() { 13 | incomeMsgQueue = new MsgQueue(); 14 | } 15 | 16 | public function close():Void { 17 | } 18 | 19 | public function bakeMsg(msg:protohx.Message):BakedMsg { 20 | return new BakedMsg(msg); 21 | } 22 | 23 | public function writeMsgBaked(msg:BakedMsg):Void { 24 | writeMsg(msg.msg); 25 | } 26 | 27 | public function writeMsg(msg:protohx.Message):Void { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/03-network/src/server/logic/SessionRegistry.hx: -------------------------------------------------------------------------------- 1 | package server.logic; 2 | import protohx.Protohx; 3 | import samples.RemovePlayerRes; 4 | import samples.ClientType; 5 | import samples.PlayerData; 6 | import samples.LoginRes; 7 | import samples.ProtocolMessage; 8 | import samples.protocolmessage.MsgType; 9 | 10 | enum NetEvent { 11 | NEConnect; 12 | NEMsg(type:Int, msg:ProtocolMessage); 13 | NEDisconnect; 14 | } 15 | 16 | class SessionRegistry { 17 | private inline static var MAX_X:Int = 320; 18 | private inline static var MAX_Y:Int = 320; 19 | 20 | private var sessions:List; 21 | private var sessionId:Int; 22 | 23 | private var sDate:Date; 24 | private var byCT:IntMap; 25 | private var byCP:IntMap; 26 | 27 | private function log(msg):Void { 28 | trace(msg); 29 | } 30 | 31 | private function nextSessionId():Int { 32 | sessionId++; 33 | return sessionId; 34 | } 35 | 36 | public function new() { 37 | sessions = new List(); 38 | sessionId = 0; 39 | sDate = Date.now(); 40 | byCT = new IntMap(); 41 | byCP = new IntMap(); 42 | } 43 | 44 | public function scanPlayer(playerData:PlayerData):Void { 45 | var t = byCT.get(playerData.clientType); 46 | byCT.set(playerData.clientType, t == null ? 1 : t + 1); 47 | var p = byCP.get(playerData.clientPlatform); 48 | byCP.set(playerData.clientPlatform, p == null ? 1 : p + 1); 49 | } 50 | 51 | public function getStatisticsStr():String { 52 | var online = 0; 53 | forEachSessions(isAuthorized, function(s:Session):Void { 54 | online++; 55 | }); 56 | var byTypes = {}; 57 | for (key in byCT.keys()) { 58 | Reflect.setField(byTypes, common.Config.getTypeName(key), byCT.get(key)); 59 | } 60 | var byPlatforms = {}; 61 | for (key in byCP.keys()) { 62 | Reflect.setField(byPlatforms, common.Config.getPlatformName(key), byCP.get(key)); 63 | } 64 | return haxe.Json.stringify({ 65 | "sDate":sDate, 66 | "nowDate":Date.now(), 67 | "playersHandled":sessionId, 68 | "playersOnline":online, 69 | "byClientType":byTypes, 70 | "byClientPlatform":byPlatforms 71 | }); 72 | } 73 | 74 | 75 | private function registerSession(session:Session) { 76 | session.id = nextSessionId(); 77 | sessions.add(session); 78 | } 79 | 80 | private function unRegisterSession(session:Session) { 81 | sessions.remove(session); 82 | } 83 | 84 | private static function isAuthorized(session:Session):Bool { 85 | return session != null && session.player != null; 86 | } 87 | 88 | private function forEachSessions(test:Session -> Bool, body:Session -> Void):Void { 89 | for (session in sessions) { 90 | if (test(session)) { 91 | body(session); 92 | } 93 | } 94 | } 95 | 96 | public function sessionConnect(session:Session) { 97 | registerSession(session); 98 | handleMsg(session, NEConnect); 99 | } 100 | 101 | public function sessionDisconnect(session:Session) { 102 | unRegisterSession(session); 103 | handleMsg(session, NEDisconnect); 104 | } 105 | 106 | public function sessionData(session:Session, bytes:haxe.io.Bytes) { 107 | session.incomeMsgQueue.addBytes(bytes); 108 | while (session.incomeMsgQueue.hasMsg()) { 109 | var msg:ProtocolMessage = session.incomeMsgQueue.popMsg(); 110 | trace("IN: " + protohx.MessageUtils.toJson(msg)); 111 | handleMsg(session, NEMsg(msg.type, msg)); 112 | } 113 | } 114 | 115 | private function handleMsg(session:Session, event:NetEvent) { 116 | switch(event){ 117 | case NEConnect:{ /*pass*/}; 118 | case NEDisconnect:{ 119 | if (session.player == null) { 120 | return; 121 | } 122 | var removePlayer = new ProtocolMessage(); 123 | removePlayer.type = MsgType.REMOVE_PLAYER_RES; 124 | removePlayer.removePlayerRes = new RemovePlayerRes(); 125 | removePlayer.removePlayerRes.id = session.player.id; 126 | var removePlayerBaked = session.bakeMsg(removePlayer); 127 | 128 | forEachSessions(isAuthorized, function(sessionOther:Session) { 129 | sessionOther.writeMsgBaked(removePlayerBaked); 130 | }); 131 | } 132 | case NEMsg(type, msg):{ 133 | switch(type) { 134 | case MsgType.LOGIN_REQ: { 135 | if (session.player != null) { 136 | log("double login!"); 137 | session.close(); 138 | return; 139 | } 140 | var playerData = new PlayerData(); 141 | playerData.id = session.id; 142 | if(msg.loginReq.clientType == ClientType.CT_BOT){ 143 | playerData.nick = "bot" + session.id; 144 | } else { 145 | playerData.nick = "usr" + session.id; 146 | } 147 | playerData.x = Std.int(Math.random() * MAX_X); 148 | playerData.y = Std.int(Math.random() * MAX_Y); 149 | playerData.status = "hi!"; 150 | playerData.clientType = msg.loginReq.clientType; 151 | playerData.clientPlatform = msg.loginReq.clientPlatform; 152 | session.player = playerData; 153 | 154 | var respMsg = new ProtocolMessage(); 155 | respMsg.type = MsgType.LOGIN_RES; 156 | respMsg.loginRes = new LoginRes(); 157 | respMsg.loginRes.id = session.id ; 158 | session.writeMsg(respMsg); 159 | 160 | var addPlayerMsg = new ProtocolMessage(); 161 | addPlayerMsg.type = MsgType.ADD_PLAYER_RES; 162 | addPlayerMsg.addPlayerRes = session.player; 163 | var addPlayerMsgBaked = session.bakeMsg(addPlayerMsg); 164 | 165 | forEachSessions(isAuthorized, function(sessionOther:Session) { 166 | sessionOther.writeMsgBaked(addPlayerMsgBaked); 167 | if (sessionOther != session) { 168 | var addOtherPlayer = new ProtocolMessage(); 169 | addOtherPlayer.type = MsgType.ADD_PLAYER_RES; 170 | addOtherPlayer.addPlayerRes = sessionOther.player; 171 | session.writeMsg(addOtherPlayer); 172 | } 173 | }); 174 | scanPlayer(playerData); 175 | } 176 | case MsgType.UPDATE_PLAYER_REQ: { 177 | var player = session.player; 178 | if(player == null){ 179 | return; 180 | } 181 | var updateData = msg.updatePlayerReq; 182 | updateData.id = player.id; 183 | if (updateData.hasX()) { 184 | updateData.x = Std.int(Math.min(Math.max(0, updateData.x), MAX_X)); 185 | player.x = updateData.x; 186 | } 187 | if (updateData.hasY()) { 188 | updateData.y = Std.int(Math.min(Math.max(0, updateData.y), MAX_Y)); 189 | player.y = updateData.y; 190 | } 191 | if (updateData.hasStatus()) { 192 | player.status = updateData.status; 193 | } 194 | var respMsg = new ProtocolMessage(); 195 | respMsg.type = MsgType.UPDATE_PLAYER_RES; 196 | respMsg.updatePlayerRes = updateData; 197 | var respMsgBaked = session.bakeMsg(respMsg); 198 | forEachSessions(isAuthorized, function(sessionOther:Session) { 199 | sessionOther.writeMsgBaked(respMsgBaked); 200 | }); 201 | } 202 | } 203 | } 204 | } 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /samples/03-network/src/server/native/MainServer.hx: -------------------------------------------------------------------------------- 1 | package server.native; 2 | 3 | #if neko 4 | 5 | import common.Config; 6 | import server.logic.SessionRegistry; 7 | import server.logic.Session; 8 | import server.logic.BakedMsg; 9 | import haxe.io.BytesOutput; 10 | import haxe.io.Bytes; 11 | import sys.net.Socket; 12 | import neko.net.ThreadServer; 13 | import neko.Lib; 14 | 15 | class NativeSession extends Session { 16 | 17 | public var socket:Socket; 18 | 19 | public function new(socket:Socket) { 20 | super(); 21 | this.socket = socket; 22 | socket.setFastSend(true); 23 | socket.output.bigEndian = false; 24 | socket.input.bigEndian = false; 25 | } 26 | 27 | public override function close():Void { 28 | socket.close(); 29 | } 30 | 31 | public override function bakeMsg(msg:protohx.Message):BakedMsg { 32 | return new BakedMsg(msg); 33 | } 34 | 35 | public override function writeMsgBaked(msg:BakedMsg):Void { 36 | writeMsg(msg.msg); 37 | } 38 | 39 | public override function writeMsg(msg:protohx.Message):Void { 40 | try{ 41 | var bytes = msgToBytes(msg); 42 | socket.output.writeUInt16(bytes.length); 43 | socket.output.write(bytes); 44 | socket.output.flush(); 45 | }catch(e:Dynamic){ 46 | trace(e); 47 | #if haxe3 48 | trace(haxe.CallStack.toString(haxe.CallStack.exceptionStack())); 49 | #else 50 | trace(haxe.Stack.toString(haxe.Stack.exceptionStack())); 51 | #end 52 | } 53 | } 54 | 55 | public static function msgToBytes(msg:protohx.Message):haxe.io.Bytes { 56 | var b = new BytesOutput(); 57 | msg.writeTo(b); 58 | return b.getBytes(); 59 | } 60 | 61 | } 62 | 63 | class MainServer extends ThreadServer { 64 | var sr:SessionRegistry; 65 | 66 | public function new() { 67 | super(); 68 | sr = new SessionRegistry(); 69 | } 70 | 71 | // create a Client 72 | 73 | override function clientConnected(s:Socket):NativeSession { 74 | var session = new NativeSession(s); 75 | sr.sessionConnect(session); 76 | Lib.println("client: " + session.id + " / " + s.peer()); 77 | return session; 78 | } 79 | 80 | override function clientDisconnected(session:NativeSession) { 81 | Lib.println("client " + Std.string(session.id) + " disconnected"); 82 | sr.sessionDisconnect(session); 83 | } 84 | 85 | override function readClientMessage(session:NativeSession, buf:Bytes, pos:Int, len:Int) { 86 | // trace("data " + buf.length + ":" + pos + ":" + len); 87 | return {msg: buf.sub(pos, len), bytes: len}; 88 | } 89 | 90 | override function clientMessage(session:NativeSession, bytes:Bytes) { 91 | // trace("bytes: "+bytes.length); 92 | sr.sessionData(session, bytes); 93 | } 94 | 95 | public static function main() { 96 | var server = new MainServer(); 97 | trace("Running.."); 98 | server.run("0.0.0.0", Config.DEFAULT_TCP_PORT); 99 | } 100 | } 101 | #end 102 | 103 | -------------------------------------------------------------------------------- /samples/03-network/src/server/nodejs/BotClient.hx: -------------------------------------------------------------------------------- 1 | package server.nodejs; 2 | #if js 3 | import common.Config; 4 | import haxe.Timer; 5 | import samples.PlayerData; 6 | import samples.ClientType; 7 | import samples.ClientPlatform; 8 | import samples.LoginReq; 9 | import samples.ProtocolMessage; 10 | import samples.protocolmessage.MsgType; 11 | import common.MsgQueue; 12 | import server.logic.SessionRegistry; 13 | import server.logic.Session; 14 | import haxe.io.Bytes; 15 | import js.Node; 16 | import server.nodejs.NodeUtils; 17 | using server.nodejs.NodeUtils; 18 | 19 | class BotClient { 20 | private static var net:NodeNet = Node.net; 21 | private static var console:NodeConsole = Node.console; 22 | 23 | public static function main() { 24 | for(i in 0...20){ 25 | tcpClientTest(Config.DEFAULT_HOST, Config.DEFAULT_TCP_PORT); 26 | } 27 | } 28 | 29 | public static function tcpClientTest(host:String, port:Int) { 30 | var msgQueue:MsgQueue = new MsgQueue(); 31 | var client:NodeNetSocket = net.connect(port, host); 32 | var id:Int = 0; 33 | var player:PlayerData = null; 34 | var timer:Int = 0; 35 | client.on(NodeC.EVENT_STREAM_CONNECT, function() { 36 | console.log('client connected to: '+ client.addressPort()); 37 | var msg = new ProtocolMessage(); 38 | msg.type = MsgType.LOGIN_REQ; 39 | msg.loginReq = new LoginReq(); 40 | msg.loginReq.status = "ok"; 41 | msg.loginReq.clientType = ClientType.CT_BOT; 42 | msg.loginReq.clientPlatform = ClientPlatform.CP_NODEJS; 43 | client.writeMsgSafe(msg); 44 | // client.end(); 45 | // haxe.Timer.delay(function() { 46 | // client.end(); 47 | // }, 1000); 48 | }); 49 | client.on(NodeC.EVENT_STREAM_DATA, function(buffer:NodeBuffer) { 50 | var bytes = buffer.toBytes(); 51 | msgQueue.addBytes(bytes); 52 | while (msgQueue.hasMsg()) { 53 | var msg:ProtocolMessage = msgQueue.popMsg(); 54 | if (msg.type == MsgType.LOGIN_RES) { 55 | id = msg.loginRes.id; 56 | } else if (msg.type == MsgType.ADD_PLAYER_RES) { 57 | if (id == msg.addPlayerRes.id) { 58 | player = msg.addPlayerRes; 59 | timer = Node.setInterval(function() { 60 | var msg = new ProtocolMessage(); 61 | msg.type = MsgType.UPDATE_PLAYER_REQ; 62 | msg.updatePlayerReq = new PlayerData(); 63 | msg.updatePlayerReq.x = player.x + Math.floor(Math.random() * 40 - 20); 64 | msg.updatePlayerReq.y = player.y + Math.floor(Math.random() * 40 - 20); 65 | client.writeMsgSafe(msg); 66 | }, 1000 + Std.int(1000 * Math.random())); 67 | } 68 | } else if (msg.type == MsgType.UPDATE_PLAYER_RES) { 69 | if (id == msg.updatePlayerRes.id) { 70 | if (msg.updatePlayerRes.hasX()) { 71 | player.x = msg.updatePlayerRes.x; 72 | } 73 | if (msg.updatePlayerRes.hasY()) { 74 | player.y = msg.updatePlayerRes.y; 75 | } 76 | } 77 | } 78 | // trace('CLIENT MSG ${id}: ' + haxe.Json.stringify(msg)); 79 | } 80 | }); 81 | client.on(NodeC.EVENT_STREAM_CLOSE, function() { 82 | if (timer != 0) { 83 | Node.clearInterval(timer); 84 | } 85 | // console.log('server got client close: ${client.getAP()}'); 86 | }); 87 | } 88 | 89 | } 90 | #end 91 | -------------------------------------------------------------------------------- /samples/03-network/src/server/nodejs/MultiServer.hx: -------------------------------------------------------------------------------- 1 | package server.nodejs; 2 | import server.logic.SessionRegistry; 3 | import common.Config; 4 | 5 | class MultiServer { 6 | public static function main() { 7 | var sr:SessionRegistry = new SessionRegistry(); 8 | NetServer.runSocketServer(sr, Config.DEFAULT_TCP_PORT); 9 | var port = untyped (__js__("process.env.VMC_APP_PORT ") || Config.DEFAULT_HTTP_PORT); 10 | SocketIoServer.runSocketIoServer(sr, port); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/03-network/src/server/nodejs/NetServer.hx: -------------------------------------------------------------------------------- 1 | package server.nodejs; 2 | #if js 3 | import common.Config; 4 | import server.logic.BakedMsg; 5 | import server.logic.SessionRegistry; 6 | import server.logic.Session; 7 | import haxe.io.Bytes; 8 | import js.Node; 9 | import server.nodejs.NodeUtils; 10 | using server.nodejs.NodeUtils; 11 | 12 | class NodeSession extends Session { 13 | 14 | public var socket:NodeNetSocket; 15 | 16 | public function new(socket:NodeNetSocket) { 17 | super(); 18 | this.socket = socket; 19 | } 20 | 21 | public override function close():Void { 22 | socket.end(); 23 | } 24 | 25 | public override function bakeMsg(msg:protohx.Message):BakedMsg { 26 | return new BakedMsg(msg, null); 27 | } 28 | 29 | public override function writeMsgBaked(msg:BakedMsg):Void { 30 | trace("OUT: "+protohx.MessageUtils.toJson(msg.msg)); 31 | socket.writeSafe(msg.msg.toFrame()); 32 | } 33 | 34 | public override function writeMsg(msg:protohx.Message):Void { 35 | trace("OUT: "+protohx.MessageUtils.toJson(msg)); 36 | socket.writeMsgSafe(msg); 37 | } 38 | } 39 | 40 | class NetServer { 41 | 42 | private static var net:NodeNet = Node.net; 43 | private static var console:NodeConsole = Node.console; 44 | 45 | public static function main() { 46 | var sr:SessionRegistry = new SessionRegistry(); 47 | flashCrossDomain(843); 48 | // flashCrossDomain(Config.ADDITIONAL_POLICY_PORT); 49 | runSocketServer(sr, Config.DEFAULT_TCP_PORT); 50 | // haxe.Timer.delay(function(){ 51 | // for(i in 0...20){ 52 | // BotClient.tcpClientTest(Config.DEFAULT_HOST, Config.DEFAULT_TCP_PORT); 53 | // } 54 | // }, 1000); 55 | } 56 | 57 | public static function runSocketServer(sr:SessionRegistry, port:Int) { 58 | var server:NodeNetServer = net.createServer({allowHalfOpen:true}, function(client:NodeNetSocket) { 59 | // client.on(NodeC.EVENT_STREAM_CONNECT, function() { 60 | var session = new NodeSession(client); 61 | client.setSession(session); 62 | sr.sessionConnect(session); 63 | console.log('server got client connection: ${client.getAP()}'); 64 | // }); 65 | // client.on(NodeC.EVENT_STREAM_DRAIN, function() { 66 | // console.log('client drain: ${client.getAP()}'); 67 | // }); 68 | client.on(NodeC.EVENT_STREAM_ERROR, function(e) { 69 | console.log('server got client error: ${client.getAP()}:\n ${e}'); 70 | }); 71 | client.on(NodeC.EVENT_STREAM_DATA, function(buffer:NodeBuffer) { 72 | var session = client.getSession(); 73 | var bytes = buffer.toBytes(); 74 | sr.sessionData(session, bytes); 75 | }); 76 | client.on(NodeC.EVENT_STREAM_END, function(d) { 77 | // console.log('server got client end: ${client.getAP()}'); 78 | client.end(); 79 | }); 80 | client.on(NodeC.EVENT_STREAM_CLOSE, function() { 81 | console.log('server got client close: ${client.getAP()}'); 82 | sr.sessionDisconnect(client.getSession()); 83 | }); 84 | }); 85 | server.on(NodeC.EVENT_STREAM_ERROR, function(e) { 86 | console.log('server got server error: ${e}'); 87 | }); 88 | server.listen(port, /* "localhost", */ function() { 89 | console.log('server bound: ${server.serverAddressPort()}'); 90 | }); 91 | console.log('simple server started'); 92 | } 93 | 94 | public static function flashCrossDomain(port:Int) { 95 | var xml = ''; 96 | var len = NodeBuffer.byteLength(xml); 97 | var b = new NodeBuffer(len + 1); 98 | b.write(xml, 0); 99 | b.writeUInt8(0, len); 100 | var server = net.createServer({allowHalfOpen:true}, function(client:NodeNetSocket) { 101 | client.addListener(NodeC.EVENT_STREAM_CONNECT, function() { 102 | client.write(b); 103 | console.log('server cross-domain-policy'); 104 | client.end(); 105 | }); 106 | client.on(NodeC.EVENT_STREAM_ERROR, function(e) { 107 | console.log('server error:\n ${e}'); 108 | }); 109 | client.on(NodeC.EVENT_STREAM_END, function(d) { 110 | // console.log('server end'); 111 | client.end(); 112 | }); 113 | }); 114 | server.on(NodeC.EVENT_STREAM_ERROR, function(e) { 115 | console.log('server error: ${e}'); 116 | }); 117 | 118 | server.listen(port, function() { 119 | console.log('flashCrossDomain server bound: ${server.serverAddressPort()}'); 120 | }); 121 | } 122 | } 123 | 124 | #end 125 | -------------------------------------------------------------------------------- /samples/03-network/src/server/nodejs/NodeUtils.hx: -------------------------------------------------------------------------------- 1 | package server.nodejs; 2 | #if js 3 | import server.logic.Session; 4 | import haxe.io.BytesOutput; 5 | import js.Node; 6 | 7 | class NodeUtils { 8 | 9 | public static function setSession(socket:NodeNetSocket, session:Session):Void { 10 | untyped { 11 | socket.ap = addressPort(socket); 12 | socket.session = session; 13 | }; 14 | } 15 | 16 | public static function getAP(socket:NodeNetSocket):String { 17 | return cast untyped {socket.ap;}; 18 | } 19 | 20 | public static function getSession(socket:NodeNetSocket):Session { 21 | return cast untyped {socket.session;}; 22 | } 23 | 24 | public static function serverAddressPort(server:NodeNetServer):String { 25 | var a = untyped __js__('server.address()'); 26 | var address:String = a.address; 27 | var port:Int = a.port; 28 | return ""+address+":"+port; 29 | } 30 | 31 | public static function addressPort(socket:NodeNetSocket):String { 32 | return ""+socket.remoteAddress+":"+socket.remotePort; 33 | } 34 | 35 | public static function writeSafe(socket:NodeNetSocket, frame:NodeBuffer):Void { 36 | try{ 37 | socket.write(frame); 38 | } catch(e:Dynamic){ 39 | trace(e); 40 | } 41 | } 42 | 43 | public static function writeMsgSafe(socket:NodeNetSocket, msg:protohx.Message):Void { 44 | try{ 45 | writeMsg(socket, msg); 46 | } catch(e:Dynamic){ 47 | trace(e); 48 | } 49 | } 50 | 51 | public static function writeMsg(socket:NodeNetSocket, msg:protohx.Message):Void { 52 | var bytes = msgToBytes(msg); 53 | var frameSize = new NodeBuffer(common.MsgQueue.HEADER_SIZE); 54 | frameSize.writeUInt16LE(bytes.length, 0); 55 | var frameData = toNodeBuffer(bytes); 56 | socket.write(frameSize); 57 | socket.write(frameData); 58 | } 59 | 60 | public static function toFrame(msg:protohx.Message):NodeBuffer { 61 | var b = new BytesOutput(); 62 | b.writeUInt16(0); 63 | msg.writeTo(b); 64 | var bytes = b.getBytes(); 65 | var frameData = toNodeBuffer(bytes); 66 | frameData.writeUInt16LE(bytes.length - common.MsgQueue.HEADER_SIZE, 0); 67 | return frameData; 68 | } 69 | 70 | public static function toNodeBuffer(bytes:haxe.io.Bytes):NodeBuffer { 71 | return new NodeBuffer(bytes.getData()); 72 | } 73 | 74 | public static function msgToBytes(msg:protohx.Message):haxe.io.Bytes { 75 | var b = new BytesOutput(); 76 | msg.writeTo(b); 77 | return b.getBytes(); 78 | } 79 | 80 | public static function msgToFrameBytes(msg:protohx.Message):haxe.io.Bytes { 81 | var b = new BytesOutput(); 82 | msg.writeTo(b); 83 | var data = b.getBytes(); 84 | 85 | var res = new BytesOutput(); 86 | res.writeUInt16(data.length); 87 | res.write(data); 88 | return res.getBytes(); 89 | } 90 | 91 | public static function writeBytes(socket:NodeNetSocket, bytes:haxe.io.Bytes):Void { 92 | socket.write(toNodeBuffer(bytes)); 93 | } 94 | 95 | public static function toBytes(buffer:NodeBuffer):haxe.io.Bytes { 96 | return haxe.io.Bytes.ofData(cast buffer); 97 | } 98 | } 99 | 100 | #end -------------------------------------------------------------------------------- /samples/03-network/src/server/nodejs/SocketIoServer.hx: -------------------------------------------------------------------------------- 1 | package server.nodejs; 2 | #if js 3 | import common.Config; 4 | import server.logic.BakedMsg; 5 | import server.logic.SessionRegistry; 6 | import server.logic.Session; 7 | import haxe.io.Bytes; 8 | import js.Node; 9 | import server.nodejs.NodeUtils; 10 | using server.nodejs.NodeUtils; 11 | 12 | class SocketIoSession extends Session { 13 | 14 | public var socket:Dynamic; 15 | 16 | public function new(socket:Dynamic) { 17 | super(); 18 | this.socket = socket; 19 | } 20 | 21 | public function writeMsgSafe_(bytes:Bytes):Void { 22 | socket.emit("message", common.Base64.encodeBase64(bytes)); 23 | } 24 | 25 | public override function close():Void { 26 | socket.disconnect(); 27 | } 28 | 29 | public override function bakeMsg(msg:protohx.Message):BakedMsg { 30 | return new BakedMsg(msg, null); 31 | } 32 | 33 | public override function writeMsgBaked(msg:BakedMsg):Void { 34 | trace("OUT: "+protohx.MessageUtils.toJson(msg.msg)); 35 | writeMsgSafe_(msg.msg.msgToFrameBytes()); 36 | } 37 | 38 | public override function writeMsg(msg:protohx.Message):Void { 39 | trace("OUT: "+protohx.MessageUtils.toJson(msg)); 40 | writeMsgSafe_(msg.msgToFrameBytes()); 41 | } 42 | } 43 | 44 | class SocketIoServer { 45 | 46 | private static var net:NodeNet = Node.net; 47 | private static var console:NodeConsole = Node.console; 48 | 49 | public static function main() { 50 | var sr:SessionRegistry = new SessionRegistry(); 51 | // NetServer.runSocketServer(sr, Config.DEFAULT_TCP_PORT); 52 | var port = untyped (__js__("process.env.VMC_APP_PORT ") || Config.DEFAULT_HTTP_PORT); 53 | runSocketIoServer(sr, port); 54 | } 55 | 56 | public static function runSocketIoServer(sr:SessionRegistry, port:Int) { 57 | var policyXml = ''; 58 | var newSocketIoSession = function (s:Dynamic) { 59 | return new SocketIoSession(s); 60 | } 61 | var decodeBytes = common.Base64.decodeBase64; 62 | var statistics = sr.getStatisticsStr; 63 | untyped __js__(" 64 | var http = require('http') 65 | , socket_io = require('socket.io') 66 | , fs = require('fs') 67 | , console = require('console') 68 | , express = require('express') 69 | 70 | var app = express(); 71 | var httpServer = http.createServer(app) 72 | httpServer.listen(port); 73 | console.log('socket.io server on '+port+' port ') 74 | var io = socket_io.listen(httpServer); 75 | 76 | io.configure('development', function(){ 77 | io.set('transports', ['xhr-polling']); 78 | }); 79 | 80 | app.get('/stat', function(req, res){ 81 | res.setHeader('Content-Type', 'text/json'); 82 | res.send(statistics()); 83 | }); 84 | app.get('/crossdomain.xml', function(req, res){ 85 | res.setHeader('Content-Type', 'text/xml'); 86 | res.setHeader('Content-Length', policyXml.length); 87 | res.end(policyXml); 88 | }); 89 | app.use(express.static(__dirname + '/static')); 90 | 91 | io.sockets.on('connection', function (socket) { 92 | var session = newSocketIoSession(socket); 93 | sr.sessionConnect(session); 94 | socket.on('message', function (data) { 95 | var bytes = decodeBytes(data); 96 | sr.sessionData(session, bytes); 97 | }); 98 | socket.on('disconnect', function () { 99 | sr.sessionDisconnect(session); 100 | }); 101 | }); 102 | "); 103 | } 104 | } 105 | 106 | #end -------------------------------------------------------------------------------- /samples/04-metadata/build-as3.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/as3 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -debug 12 | 13 | 14 | -as3 out/as3 15 | 16 | --next 17 | 18 | -cmd cd out/as3 19 | -cmd mxmlc -output as3.swf __main__.as -static-link-runtime-shared-libraries=true -debug 20 | #-swf-header 800:600:40:FFFFFF 21 | 22 | -cmd flashplayerdebugger as3.swf 23 | -------------------------------------------------------------------------------- /samples/04-metadata/build-cpp-pure.hxml: -------------------------------------------------------------------------------- 1 | -cmd haxelib run protohx generate protohx.json 2 | -cmd mkdir -p out/cpp 3 | 4 | --next 5 | 6 | -main Main 7 | -cp src 8 | -cp out/src-gen 9 | -lib protohx 10 | -debug 11 | -D HXCPP_STACK_TRACE 12 | -D HXCPP_STACK_LINE 13 | -D HXCPP_DEBUG_LINK 14 | -D HXCPP_CHECK_POINTER 15 | 16 | 17 | -cpp out/cpp 18 | 19 | --next 20 | 21 | -cmd out/cpp/Main-debug -------------------------------------------------------------------------------- /samples/04-metadata/build-cs.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/cs 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -debug 12 | 13 | -cs out/cs 14 | 15 | --next 16 | 17 | -cmd cd out/cs 18 | -cmd mono bin/Main-Debug.exe 19 | #-cmd gmcs -recurse:*.cs -main:Main -out:Tester.exe-debug 20 | -------------------------------------------------------------------------------- /samples/04-metadata/build-flash.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | #-cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -debug 12 | 13 | -swf out/run.swf 14 | -swf-header 800:600:40:FFFFFF 15 | 16 | --next 17 | 18 | -cmd flashplayerdebugger out/run.swf 19 | -------------------------------------------------------------------------------- /samples/04-metadata/build-java.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/java 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -debug 12 | 13 | -java out/java 14 | 15 | --next 16 | -cmd pwd 17 | -cmd cd out/java/ 18 | -cmd java -jar Main-Debug.jar -cp . 19 | -------------------------------------------------------------------------------- /samples/04-metadata/build-js.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -debug 12 | 13 | -js out/Main.js 14 | 15 | --next 16 | 17 | #-cmd phantomjs out/Main.js 18 | -cmd nodejs out/Main.js 19 | -------------------------------------------------------------------------------- /samples/04-metadata/build-neko.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -neko out/run.n 11 | -lib protohx 12 | -debug 13 | 14 | 15 | --next 16 | 17 | -cmd neko out/run.n -------------------------------------------------------------------------------- /samples/04-metadata/build-php.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out/php 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | -debug 12 | 13 | -php out/php 14 | 15 | --next 16 | 17 | -cmd php out/php/index.php -------------------------------------------------------------------------------- /samples/04-metadata/build-python.hxml: -------------------------------------------------------------------------------- 1 | 2 | -cmd haxelib run protohx generate protohx.json 3 | -cmd mkdir -p out 4 | 5 | --next 6 | 7 | -main Main 8 | -cp src 9 | -cp out/src-gen 10 | -lib protohx 11 | 12 | -python out/run.py 13 | 14 | --next 15 | 16 | -cmd python3 out/run.py -------------------------------------------------------------------------------- /samples/04-metadata/nme-generate-sources.hxml: -------------------------------------------------------------------------------- 1 | -cmd haxelib run protohx generate protohx.json 2 | -------------------------------------------------------------------------------- /samples/04-metadata/proto/google/protobuf/compiler/plugin.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // http://code.google.com/p/protobuf/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // 33 | // WARNING: The plugin interface is currently EXPERIMENTAL and is subject to 34 | // change. 35 | // 36 | // protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is 37 | // just a program that reads a CodeGeneratorRequest from stdin and writes a 38 | // CodeGeneratorResponse to stdout. 39 | // 40 | // Plugins written using C++ can use google/protobuf/compiler/plugin.h instead 41 | // of dealing with the raw protocol defined here. 42 | // 43 | // A plugin executable needs only to be placed somewhere in the path. The 44 | // plugin should be named "protoc-gen-$NAME", and will then be used when the 45 | // flag "--${NAME}_out" is passed to protoc. 46 | 47 | package google.protobuf.compiler; 48 | 49 | import "google/protobuf/descriptor.proto"; 50 | 51 | // An encoded CodeGeneratorRequest is written to the plugin's stdin. 52 | message CodeGeneratorRequest { 53 | // The .proto files that were explicitly listed on the command-line. The 54 | // code generator should generate code only for these files. Each file's 55 | // descriptor will be included in proto_file, below. 56 | repeated string file_to_generate = 1; 57 | 58 | // The generator parameter passed on the command-line. 59 | optional string parameter = 2; 60 | 61 | // FileDescriptorProtos for all files in files_to_generate and everything 62 | // they import. The files will appear in topological order, so each file 63 | // appears before any file that imports it. 64 | // 65 | // protoc guarantees that all proto_files will be written after 66 | // the fields above, even though this is not technically guaranteed by the 67 | // protobuf wire format. This theoretically could allow a plugin to stream 68 | // in the FileDescriptorProtos and handle them one by one rather than read 69 | // the entire set into memory at once. However, as of this writing, this 70 | // is not similarly optimized on protoc's end -- it will store all fields in 71 | // memory at once before sending them to the plugin. 72 | repeated FileDescriptorProto proto_file = 15; 73 | } 74 | 75 | // The plugin writes an encoded CodeGeneratorResponse to stdout. 76 | message CodeGeneratorResponse { 77 | // Error message. If non-empty, code generation failed. The plugin process 78 | // should exit with status code zero even if it reports an error in this way. 79 | // 80 | // This should be used to indicate errors in .proto files which prevent the 81 | // code generator from generating correct code. Errors which indicate a 82 | // problem in protoc itself -- such as the input CodeGeneratorRequest being 83 | // unparseable -- should be reported by writing a message to stderr and 84 | // exiting with a non-zero status code. 85 | optional string error = 1; 86 | 87 | // Represents a single generated file. 88 | message File { 89 | // The file name, relative to the output directory. The name must not 90 | // contain "." or ".." components and must be relative, not be absolute (so, 91 | // the file cannot lie outside the output directory). "/" must be used as 92 | // the path separator, not "\". 93 | // 94 | // If the name is omitted, the content will be appended to the previous 95 | // file. This allows the generator to break large files into small chunks, 96 | // and allows the generated text to be streamed back to protoc so that large 97 | // files need not reside completely in memory at one time. Note that as of 98 | // this writing protoc does not optimize for this -- it will read the entire 99 | // CodeGeneratorResponse before writing files to disk. 100 | optional string name = 1; 101 | 102 | // If non-empty, indicates that the named file should already exist, and the 103 | // content here is to be inserted into that file at a defined insertion 104 | // point. This feature allows a code generator to extend the output 105 | // produced by another code generator. The original generator may provide 106 | // insertion points by placing special annotations in the file that look 107 | // like: 108 | // @@protoc_insertion_point(NAME) 109 | // The annotation can have arbitrary text before and after it on the line, 110 | // which allows it to be placed in a comment. NAME should be replaced with 111 | // an identifier naming the point -- this is what other generators will use 112 | // as the insertion_point. Code inserted at this point will be placed 113 | // immediately above the line containing the insertion point (thus multiple 114 | // insertions to the same point will come out in the order they were added). 115 | // The double-@ is intended to make it unlikely that the generated code 116 | // could contain things that look like insertion points by accident. 117 | // 118 | // For example, the C++ code generator places the following line in the 119 | // .pb.h files that it generates: 120 | // // @@protoc_insertion_point(namespace_scope) 121 | // This line appears within the scope of the file's package namespace, but 122 | // outside of any particular class. Another plugin can then specify the 123 | // insertion_point "namespace_scope" to generate additional classes or 124 | // other declarations that should be placed in this scope. 125 | // 126 | // Note that if the line containing the insertion point begins with 127 | // whitespace, the same whitespace will be added to every line of the 128 | // inserted text. This is useful for languages like Python, where 129 | // indentation matters. In these languages, the insertion point comment 130 | // should be indented the same amount as any inserted code will need to be 131 | // in order to work correctly in that context. 132 | // 133 | // The code generator that generates the initial file and the one which 134 | // inserts into it must both run as part of a single invocation of protoc. 135 | // Code generators are executed in the order in which they appear on the 136 | // command line. 137 | // 138 | // If |insertion_point| is present, |name| must also be present. 139 | optional string insertion_point = 2; 140 | 141 | // The file contents. 142 | optional string content = 15; 143 | } 144 | repeated File file = 15; 145 | } 146 | -------------------------------------------------------------------------------- /samples/04-metadata/proto/test.proto: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | /* 4 | // TODO check all types 5 | // https://developers.google.com/protocol-buffers/docs/proto 6 | double // double double 7 | float // float float 8 | int32 // Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32 int 9 | int64 // Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. int64 long 10 | uint32 // Uses variable-length encoding. uint32 int[1] 11 | uint64 // Uses variable-length encoding. uint64 long[1] 12 | sint32 // Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32 int 13 | sint64 // Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64 long 14 | fixed32 // Always four bytes. More efficient than uint32 if values are often greater than 228. uint32 int[1] 15 | fixed64 // Always eight bytes. More efficient than uint64 if values are often greater than 256. uint64 long[1] 16 | sfixed32 // Always four bytes. int32 int 17 | sfixed64 // Always eight bytes. int64 long 18 | bool // bool boolean 19 | string // A string must always contain UTF-8 encoded or 7-bit ASCII text. string String 20 | bytes // May contain any arbitrary sequence of bytes. string ByteString 21 | */ 22 | 23 | message ComplexMessage { 24 | enum MsgType { 25 | AAA = 100; 26 | BBB = 101; 27 | } 28 | message Point{ 29 | required int32 x = 1; 30 | required int32 y = 2; 31 | } 32 | 33 | required MsgType type = 1 [default = AAA]; 34 | required string msg = 2; 35 | required int32 id = 3; 36 | required uint32 uid = 4; 37 | required bool offline = 5; 38 | required bytes attach = 6; 39 | repeated string statuses = 7; 40 | repeated Point points = 8; 41 | required sint32 rnd = 9; 42 | required MsgType typeOpt = 10; 43 | 44 | optional string msgOpt = 11; 45 | repeated sint32 rnds = 12; 46 | repeated sint32 rnds2 = 13 [packed=true]; 47 | required int64 i64 = 14 [default = 0xffffffff]; 48 | } 49 | 50 | 51 | message IntTestMessage { 52 | optional int32 i32 = 1; 53 | optional uint32 ui32 = 2; 54 | optional int64 i64 = 3; 55 | optional uint64 ui64 = 4; 56 | optional sint32 si32 = 5; 57 | optional sint64 sui64 = 6; 58 | optional float f = 7; 59 | optional double d = 8; 60 | } 61 | 62 | message Foo { 63 | required string version = 1 [default = "1.0"]; 64 | extensions 100 to 199; 65 | } 66 | 67 | extend Foo { 68 | optional int32 bar = 126; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /samples/04-metadata/protohx.json: -------------------------------------------------------------------------------- 1 | { 2 | "protoPath": "proto", 3 | "protoFiles": [ 4 | "proto/test.proto", 5 | "proto/google/protobuf/compiler/plugin.proto", 6 | "proto/google/protobuf/descriptor.proto" 7 | ], 8 | "cleanOut": true, 9 | "haxeOut": "out/src-gen", 10 | "javaOut": null 11 | } -------------------------------------------------------------------------------- /samples/04-metadata/src/Main.hx: -------------------------------------------------------------------------------- 1 | package ; 2 | import protohx.Message; 3 | import protohx.Protohx; 4 | import haxe.io.BytesOutput; 5 | import haxe.io.Bytes; 6 | import google.protobuf.compiler.CodeGeneratorRequest; 7 | import test.Foo; 8 | import test.IntTestMessage; 9 | import test.complexmessage.Point; 10 | import test.complexmessage.MsgType; 11 | import test.ComplexMessage; 12 | 13 | class Main { 14 | public function new() { 15 | } 16 | 17 | public static function main():Void { 18 | #if js 19 | haxe.unit.TestRunner.print = function ( v : Dynamic ){ 20 | untyped __js__("console.log(v);"); 21 | } 22 | #end 23 | 24 | var r = new haxe.unit.TestRunner(); 25 | r.add(new TestComplex()); 26 | r.run(); 27 | } 28 | } 29 | 30 | 31 | class TestBase extends haxe.unit.TestCase { 32 | public function copyMsg(obj:T):T { 33 | var b = new BytesOutput(); 34 | untyped obj.writeTo(b); 35 | var copy = Type.createInstance(Type.getClass(obj), []); 36 | untyped copy.mergeFrom(b.getBytes()); 37 | return copy; 38 | } 39 | } 40 | 41 | class TestComplex extends TestBase { 42 | public function testBasic() { 43 | function p(x, y) { 44 | var pt = new Point(); 45 | pt.x = x; 46 | pt.y = y; 47 | return pt; 48 | } 49 | 50 | var obj = new ComplexMessage(); 51 | 52 | obj.type = MsgType.BBB; 53 | obj.msg = "msg1"; 54 | obj.id = 12345; 55 | 56 | obj.uid = 54321; 57 | obj.offline = true; 58 | 59 | obj.attach = null; 60 | obj.statuses = ["123", "456"]; 61 | obj.points = [p(1, 2), p(3, 4)]; 62 | 63 | obj.msgOpt = "msgOpt1"; 64 | 65 | obj.rnd = -1; 66 | obj.i64 = Protohx.newInt64(8, 8); 67 | 68 | obj.attach = Bytes.alloc(256); 69 | for (b in 0...256) { 70 | obj.attach.set(b, b); 71 | } 72 | assertEquals(obj.attach.length, 256); 73 | 74 | obj.setType(MsgType.BBB).setMsg("setMsg").setId(12345).setMsgOpt("setMsgOpt"); 75 | 76 | var b = new BytesOutput(); 77 | obj.writeTo(b); 78 | var copy = new ComplexMessage(); 79 | copy.mergeFrom(b.getBytes()); 80 | 81 | assertEquals(obj.type, copy.type); 82 | assertEquals(obj.msg, copy.msg); 83 | assertEquals(obj.id, copy.id); 84 | assertEquals(obj.uid, copy.uid); 85 | assertEquals(obj.offline, copy.offline); 86 | assertEquals(Std.string(obj.statuses), Std.string(copy.statuses)); 87 | 88 | assertEquals(obj.rnd, copy.rnd); 89 | assertEquals(copy.attach.length, 256); 90 | 91 | for (b in 0...256) { 92 | var c = copy.attach.get(b); 93 | assertEquals(c, b); 94 | } 95 | 96 | var foo = new Foo(); 97 | assertEquals("1.0", foo.version); 98 | 99 | trace(protohx.MessageUtils.toJson(obj)); 100 | assertEquals(protohx.MessageUtils.toJson(obj), protohx.MessageUtils.toJson(copy)); 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /tools/plugin/bin/plugin: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd "`dirname "$0"`" && java -jar plugin.jar 3 | #cd "`dirname "$0"`" && tee in.dump | java -jar plugin.jar | tee out.dump 4 | -------------------------------------------------------------------------------- /tools/plugin/bin/plugin.bat: -------------------------------------------------------------------------------- 1 | @cd %~dp0 2 | @java -jar plugin.jar 3 | -------------------------------------------------------------------------------- /tools/plugin/bin/plugin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nitrobin/protohx/ce7b7ac49a676fd29d08184148eefbeb4c0cba47/tools/plugin/bin/plugin.jar -------------------------------------------------------------------------------- /tools/plugin/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /tools/plugin/libs-src/protobuf-java-2.5.0-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nitrobin/protohx/ce7b7ac49a676fd29d08184148eefbeb4c0cba47/tools/plugin/libs-src/protobuf-java-2.5.0-sources.jar -------------------------------------------------------------------------------- /tools/plugin/libs/protobuf-java-2.5.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nitrobin/protohx/ce7b7ac49a676fd29d08184148eefbeb4c0cba47/tools/plugin/libs/protobuf-java-2.5.0.jar -------------------------------------------------------------------------------- /tools/plugin/plugin.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tools/plugin/proto/google/protobuf/compiler/plugin.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // http://code.google.com/p/protobuf/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // 33 | // WARNING: The plugin interface is currently EXPERIMENTAL and is subject to 34 | // change. 35 | // 36 | // protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is 37 | // just a program that reads a CodeGeneratorRequest from stdin and writes a 38 | // CodeGeneratorResponse to stdout. 39 | // 40 | // Plugins written using C++ can use google/protobuf/compiler/plugin.h instead 41 | // of dealing with the raw protocol defined here. 42 | // 43 | // A plugin executable needs only to be placed somewhere in the path. The 44 | // plugin should be named "protoc-gen-$NAME", and will then be used when the 45 | // flag "--${NAME}_out" is passed to protoc. 46 | 47 | package google.protobuf.compiler; 48 | 49 | import "google/protobuf/descriptor.proto"; 50 | 51 | // An encoded CodeGeneratorRequest is written to the plugin's stdin. 52 | message CodeGeneratorRequest { 53 | // The .proto files that were explicitly listed on the command-line. The 54 | // code generator should generate code only for these files. Each file's 55 | // descriptor will be included in proto_file, below. 56 | repeated string file_to_generate = 1; 57 | 58 | // The generator parameter passed on the command-line. 59 | optional string parameter = 2; 60 | 61 | // FileDescriptorProtos for all files in files_to_generate and everything 62 | // they import. The files will appear in topological order, so each file 63 | // appears before any file that imports it. 64 | // 65 | // protoc guarantees that all proto_files will be written after 66 | // the fields above, even though this is not technically guaranteed by the 67 | // protobuf wire format. This theoretically could allow a plugin to stream 68 | // in the FileDescriptorProtos and handle them one by one rather than read 69 | // the entire set into memory at once. However, as of this writing, this 70 | // is not similarly optimized on protoc's end -- it will store all fields in 71 | // memory at once before sending them to the plugin. 72 | repeated FileDescriptorProto proto_file = 15; 73 | } 74 | 75 | // The plugin writes an encoded CodeGeneratorResponse to stdout. 76 | message CodeGeneratorResponse { 77 | // Error message. If non-empty, code generation failed. The plugin process 78 | // should exit with status code zero even if it reports an error in this way. 79 | // 80 | // This should be used to indicate errors in .proto files which prevent the 81 | // code generator from generating correct code. Errors which indicate a 82 | // problem in protoc itself -- such as the input CodeGeneratorRequest being 83 | // unparseable -- should be reported by writing a message to stderr and 84 | // exiting with a non-zero status code. 85 | optional string error = 1; 86 | 87 | // Represents a single generated file. 88 | message File { 89 | // The file name, relative to the output directory. The name must not 90 | // contain "." or ".." components and must be relative, not be absolute (so, 91 | // the file cannot lie outside the output directory). "/" must be used as 92 | // the path separator, not "\". 93 | // 94 | // If the name is omitted, the content will be appended to the previous 95 | // file. This allows the generator to break large files into small chunks, 96 | // and allows the generated text to be streamed back to protoc so that large 97 | // files need not reside completely in memory at one time. Note that as of 98 | // this writing protoc does not optimize for this -- it will read the entire 99 | // CodeGeneratorResponse before writing files to disk. 100 | optional string name = 1; 101 | 102 | // If non-empty, indicates that the named file should already exist, and the 103 | // content here is to be inserted into that file at a defined insertion 104 | // point. This feature allows a code generator to extend the output 105 | // produced by another code generator. The original generator may provide 106 | // insertion points by placing special annotations in the file that look 107 | // like: 108 | // @@protoc_insertion_point(NAME) 109 | // The annotation can have arbitrary text before and after it on the line, 110 | // which allows it to be placed in a comment. NAME should be replaced with 111 | // an identifier naming the point -- this is what other generators will use 112 | // as the insertion_point. Code inserted at this point will be placed 113 | // immediately above the line containing the insertion point (thus multiple 114 | // insertions to the same point will come out in the order they were added). 115 | // The double-@ is intended to make it unlikely that the generated code 116 | // could contain things that look like insertion points by accident. 117 | // 118 | // For example, the C++ code generator places the following line in the 119 | // .pb.h files that it generates: 120 | // // @@protoc_insertion_point(namespace_scope) 121 | // This line appears within the scope of the file's package namespace, but 122 | // outside of any particular class. Another plugin can then specify the 123 | // insertion_point "namespace_scope" to generate additional classes or 124 | // other declarations that should be placed in this scope. 125 | // 126 | // Note that if the line containing the insertion point begins with 127 | // whitespace, the same whitespace will be added to every line of the 128 | // inserted text. This is useful for languages like Python, where 129 | // indentation matters. In these languages, the insertion point comment 130 | // should be indented the same amount as any inserted code will need to be 131 | // in order to work correctly in that context. 132 | // 133 | // The code generator that generates the initial file and the one which 134 | // inserts into it must both run as part of a single invocation of protoc. 135 | // Code generators are executed in the order in which they appear on the 136 | // command line. 137 | // 138 | // If |insertion_point| is present, |name| must also be present. 139 | optional string insertion_point = 2; 140 | 141 | // The file contents. 142 | optional string content = 15; 143 | } 144 | repeated File file = 15; 145 | } 146 | -------------------------------------------------------------------------------- /tools/plugin/proto/google/protobuf/descriptor.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // http://code.google.com/p/protobuf/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // Based on original Protocol Buffers design by 33 | // Sanjay Ghemawat, Jeff Dean, and others. 34 | // 35 | // The messages in this file describe the definitions found in .proto files. 36 | // A valid .proto file can be translated directly to a FileDescriptorProto 37 | // without any other information (e.g. without reading its imports). 38 | 39 | 40 | 41 | package google.protobuf; 42 | option java_package = "com.google.protobuf"; 43 | option java_outer_classname = "DescriptorProtos"; 44 | 45 | // descriptor.proto must be optimized for speed because reflection-based 46 | // algorithms don't work during bootstrapping. 47 | option optimize_for = SPEED; 48 | 49 | // The protocol compiler can output a FileDescriptorSet containing the .proto 50 | // files it parses. 51 | message FileDescriptorSet { 52 | repeated FileDescriptorProto file = 1; 53 | } 54 | 55 | // Describes a complete .proto file. 56 | message FileDescriptorProto { 57 | optional string name = 1; // file name, relative to root of source tree 58 | optional string package = 2; // e.g. "foo", "foo.bar", etc. 59 | 60 | // Names of files imported by this file. 61 | repeated string dependency = 3; 62 | // Indexes of the public imported files in the dependency list above. 63 | repeated int32 public_dependency = 10; 64 | // Indexes of the weak imported files in the dependency list. 65 | // For Google-internal migration only. Do not use. 66 | repeated int32 weak_dependency = 11; 67 | 68 | // All top-level definitions in this file. 69 | repeated DescriptorProto message_type = 4; 70 | repeated EnumDescriptorProto enum_type = 5; 71 | repeated ServiceDescriptorProto service = 6; 72 | repeated FieldDescriptorProto extension = 7; 73 | 74 | optional FileOptions options = 8; 75 | 76 | // This field contains optional information about the original source code. 77 | // You may safely remove this entire field whithout harming runtime 78 | // functionality of the descriptors -- the information is needed only by 79 | // development tools. 80 | optional SourceCodeInfo source_code_info = 9; 81 | } 82 | 83 | // Describes a message type. 84 | message DescriptorProto { 85 | optional string name = 1; 86 | 87 | repeated FieldDescriptorProto field = 2; 88 | repeated FieldDescriptorProto extension = 6; 89 | 90 | repeated DescriptorProto nested_type = 3; 91 | repeated EnumDescriptorProto enum_type = 4; 92 | 93 | message ExtensionRange { 94 | optional int32 start = 1; 95 | optional int32 end = 2; 96 | } 97 | repeated ExtensionRange extension_range = 5; 98 | 99 | optional MessageOptions options = 7; 100 | } 101 | 102 | // Describes a field within a message. 103 | message FieldDescriptorProto { 104 | enum Type { 105 | // 0 is reserved for errors. 106 | // Order is weird for historical reasons. 107 | TYPE_DOUBLE = 1; 108 | TYPE_FLOAT = 2; 109 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if 110 | // negative values are likely. 111 | TYPE_INT64 = 3; 112 | TYPE_UINT64 = 4; 113 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if 114 | // negative values are likely. 115 | TYPE_INT32 = 5; 116 | TYPE_FIXED64 = 6; 117 | TYPE_FIXED32 = 7; 118 | TYPE_BOOL = 8; 119 | TYPE_STRING = 9; 120 | TYPE_GROUP = 10; // Tag-delimited aggregate. 121 | TYPE_MESSAGE = 11; // Length-delimited aggregate. 122 | 123 | // New in version 2. 124 | TYPE_BYTES = 12; 125 | TYPE_UINT32 = 13; 126 | TYPE_ENUM = 14; 127 | TYPE_SFIXED32 = 15; 128 | TYPE_SFIXED64 = 16; 129 | TYPE_SINT32 = 17; // Uses ZigZag encoding. 130 | TYPE_SINT64 = 18; // Uses ZigZag encoding. 131 | }; 132 | 133 | enum Label { 134 | // 0 is reserved for errors 135 | LABEL_OPTIONAL = 1; 136 | LABEL_REQUIRED = 2; 137 | LABEL_REPEATED = 3; 138 | // TODO(sanjay): Should we add LABEL_MAP? 139 | }; 140 | 141 | optional string name = 1; 142 | optional int32 number = 3; 143 | optional Label label = 4; 144 | 145 | // If type_name is set, this need not be set. If both this and type_name 146 | // are set, this must be either TYPE_ENUM or TYPE_MESSAGE. 147 | optional Type type = 5; 148 | 149 | // For message and enum types, this is the name of the type. If the name 150 | // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping 151 | // rules are used to find the type (i.e. first the nested types within this 152 | // message are searched, then within the parent, on up to the root 153 | // namespace). 154 | optional string type_name = 6; 155 | 156 | // For extensions, this is the name of the type being extended. It is 157 | // resolved in the same manner as type_name. 158 | optional string extendee = 2; 159 | 160 | // For numeric types, contains the original text representation of the value. 161 | // For booleans, "true" or "false". 162 | // For strings, contains the default text contents (not escaped in any way). 163 | // For bytes, contains the C escaped value. All bytes >= 128 are escaped. 164 | // TODO(kenton): Base-64 encode? 165 | optional string default_value = 7; 166 | 167 | optional FieldOptions options = 8; 168 | } 169 | 170 | // Describes an enum type. 171 | message EnumDescriptorProto { 172 | optional string name = 1; 173 | 174 | repeated EnumValueDescriptorProto value = 2; 175 | 176 | optional EnumOptions options = 3; 177 | } 178 | 179 | // Describes a value within an enum. 180 | message EnumValueDescriptorProto { 181 | optional string name = 1; 182 | optional int32 number = 2; 183 | 184 | optional EnumValueOptions options = 3; 185 | } 186 | 187 | // Describes a service. 188 | message ServiceDescriptorProto { 189 | optional string name = 1; 190 | repeated MethodDescriptorProto method = 2; 191 | 192 | optional ServiceOptions options = 3; 193 | } 194 | 195 | // Describes a method of a service. 196 | message MethodDescriptorProto { 197 | optional string name = 1; 198 | 199 | // Input and output type names. These are resolved in the same way as 200 | // FieldDescriptorProto.type_name, but must refer to a message type. 201 | optional string input_type = 2; 202 | optional string output_type = 3; 203 | 204 | optional MethodOptions options = 4; 205 | } 206 | 207 | 208 | // =================================================================== 209 | // Options 210 | 211 | // Each of the definitions above may have "options" attached. These are 212 | // just annotations which may cause code to be generated slightly differently 213 | // or may contain hints for code that manipulates protocol messages. 214 | // 215 | // Clients may define custom options as extensions of the *Options messages. 216 | // These extensions may not yet be known at parsing time, so the parser cannot 217 | // store the values in them. Instead it stores them in a field in the *Options 218 | // message called uninterpreted_option. This field must have the same name 219 | // across all *Options messages. We then use this field to populate the 220 | // extensions when we build a descriptor, at which point all protos have been 221 | // parsed and so all extensions are known. 222 | // 223 | // Extension numbers for custom options may be chosen as follows: 224 | // * For options which will only be used within a single application or 225 | // organization, or for experimental options, use field numbers 50000 226 | // through 99999. It is up to you to ensure that you do not use the 227 | // same number for multiple options. 228 | // * For options which will be published and used publicly by multiple 229 | // independent entities, e-mail protobuf-global-extension-registry@google.com 230 | // to reserve extension numbers. Simply provide your project name (e.g. 231 | // Object-C plugin) and your porject website (if available) -- there's no need 232 | // to explain how you intend to use them. Usually you only need one extension 233 | // number. You can declare multiple options with only one extension number by 234 | // putting them in a sub-message. See the Custom Options section of the docs 235 | // for examples: 236 | // http://code.google.com/apis/protocolbuffers/docs/proto.html#options 237 | // If this turns out to be popular, a web service will be set up 238 | // to automatically assign option numbers. 239 | 240 | 241 | message FileOptions { 242 | 243 | // Sets the Java package where classes generated from this .proto will be 244 | // placed. By default, the proto package is used, but this is often 245 | // inappropriate because proto packages do not normally start with backwards 246 | // domain names. 247 | optional string java_package = 1; 248 | 249 | 250 | // If set, all the classes from the .proto file are wrapped in a single 251 | // outer class with the given name. This applies to both Proto1 252 | // (equivalent to the old "--one_java_file" option) and Proto2 (where 253 | // a .proto always translates to a single class, but you may want to 254 | // explicitly choose the class name). 255 | optional string java_outer_classname = 8; 256 | 257 | // If set true, then the Java code generator will generate a separate .java 258 | // file for each top-level message, enum, and service defined in the .proto 259 | // file. Thus, these types will *not* be nested inside the outer class 260 | // named by java_outer_classname. However, the outer class will still be 261 | // generated to contain the file's getDescriptor() method as well as any 262 | // top-level extensions defined in the file. 263 | optional bool java_multiple_files = 10 [default=false]; 264 | 265 | // If set true, then the Java code generator will generate equals() and 266 | // hashCode() methods for all messages defined in the .proto file. This is 267 | // purely a speed optimization, as the AbstractMessage base class includes 268 | // reflection-based implementations of these methods. 269 | optional bool java_generate_equals_and_hash = 20 [default=false]; 270 | 271 | // Generated classes can be optimized for speed or code size. 272 | enum OptimizeMode { 273 | SPEED = 1; // Generate complete code for parsing, serialization, 274 | // etc. 275 | CODE_SIZE = 2; // Use ReflectionOps to implement these methods. 276 | LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. 277 | } 278 | optional OptimizeMode optimize_for = 9 [default=SPEED]; 279 | 280 | // Sets the Go package where structs generated from this .proto will be 281 | // placed. There is no default. 282 | optional string go_package = 11; 283 | 284 | 285 | 286 | // Should generic services be generated in each language? "Generic" services 287 | // are not specific to any particular RPC system. They are generated by the 288 | // main code generators in each language (without additional plugins). 289 | // Generic services were the only kind of service generation supported by 290 | // early versions of proto2. 291 | // 292 | // Generic services are now considered deprecated in favor of using plugins 293 | // that generate code specific to your particular RPC system. Therefore, 294 | // these default to false. Old code which depends on generic services should 295 | // explicitly set them to true. 296 | optional bool cc_generic_services = 16 [default=false]; 297 | optional bool java_generic_services = 17 [default=false]; 298 | optional bool py_generic_services = 18 [default=false]; 299 | 300 | // The parser stores options it doesn't recognize here. See above. 301 | repeated UninterpretedOption uninterpreted_option = 999; 302 | 303 | // Clients can define custom options in extensions of this message. See above. 304 | extensions 1000 to max; 305 | } 306 | 307 | message MessageOptions { 308 | // Set true to use the old proto1 MessageSet wire format for extensions. 309 | // This is provided for backwards-compatibility with the MessageSet wire 310 | // format. You should not use this for any other reason: It's less 311 | // efficient, has fewer features, and is more complicated. 312 | // 313 | // The message must be defined exactly as follows: 314 | // message Foo { 315 | // option message_set_wire_format = true; 316 | // extensions 4 to max; 317 | // } 318 | // Note that the message cannot have any defined fields; MessageSets only 319 | // have extensions. 320 | // 321 | // All extensions of your type must be singular messages; e.g. they cannot 322 | // be int32s, enums, or repeated messages. 323 | // 324 | // Because this is an option, the above two restrictions are not enforced by 325 | // the protocol compiler. 326 | optional bool message_set_wire_format = 1 [default=false]; 327 | 328 | // Disables the generation of the standard "descriptor()" accessor, which can 329 | // conflict with a field of the same name. This is meant to make migration 330 | // from proto1 easier; new code should avoid fields named "descriptor". 331 | optional bool no_standard_descriptor_accessor = 2 [default=false]; 332 | 333 | // The parser stores options it doesn't recognize here. See above. 334 | repeated UninterpretedOption uninterpreted_option = 999; 335 | 336 | // Clients can define custom options in extensions of this message. See above. 337 | extensions 1000 to max; 338 | } 339 | 340 | message FieldOptions { 341 | // The ctype option instructs the C++ code generator to use a different 342 | // representation of the field than it normally would. See the specific 343 | // options below. This option is not yet implemented in the open source 344 | // release -- sorry, we'll try to include it in a future version! 345 | optional CType ctype = 1 [default = STRING]; 346 | enum CType { 347 | // Default mode. 348 | STRING = 0; 349 | 350 | CORD = 1; 351 | 352 | STRING_PIECE = 2; 353 | } 354 | // The packed option can be enabled for repeated primitive fields to enable 355 | // a more efficient representation on the wire. Rather than repeatedly 356 | // writing the tag and type for each element, the entire array is encoded as 357 | // a single length-delimited blob. 358 | optional bool packed = 2; 359 | 360 | 361 | 362 | // Should this field be parsed lazily? Lazy applies only to message-type 363 | // fields. It means that when the outer message is initially parsed, the 364 | // inner message's contents will not be parsed but instead stored in encoded 365 | // form. The inner message will actually be parsed when it is first accessed. 366 | // 367 | // This is only a hint. Implementations are free to choose whether to use 368 | // eager or lazy parsing regardless of the value of this option. However, 369 | // setting this option true suggests that the protocol author believes that 370 | // using lazy parsing on this field is worth the additional bookkeeping 371 | // overhead typically needed to implement it. 372 | // 373 | // This option does not affect the public interface of any generated code; 374 | // all method signatures remain the same. Furthermore, thread-safety of the 375 | // interface is not affected by this option; const methods remain safe to 376 | // call from multiple threads concurrently, while non-const methods continue 377 | // to require exclusive access. 378 | // 379 | // 380 | // Note that implementations may choose not to check required fields within 381 | // a lazy sub-message. That is, calling IsInitialized() on the outher message 382 | // may return true even if the inner message has missing required fields. 383 | // This is necessary because otherwise the inner message would have to be 384 | // parsed in order to perform the check, defeating the purpose of lazy 385 | // parsing. An implementation which chooses not to check required fields 386 | // must be consistent about it. That is, for any particular sub-message, the 387 | // implementation must either *always* check its required fields, or *never* 388 | // check its required fields, regardless of whether or not the message has 389 | // been parsed. 390 | optional bool lazy = 5 [default=false]; 391 | 392 | // Is this field deprecated? 393 | // Depending on the target platform, this can emit Deprecated annotations 394 | // for accessors, or it will be completely ignored; in the very least, this 395 | // is a formalization for deprecating fields. 396 | optional bool deprecated = 3 [default=false]; 397 | 398 | // EXPERIMENTAL. DO NOT USE. 399 | // For "map" fields, the name of the field in the enclosed type that 400 | // is the key for this map. For example, suppose we have: 401 | // message Item { 402 | // required string name = 1; 403 | // required string value = 2; 404 | // } 405 | // message Config { 406 | // repeated Item items = 1 [experimental_map_key="name"]; 407 | // } 408 | // In this situation, the map key for Item will be set to "name". 409 | // TODO: Fully-implement this, then remove the "experimental_" prefix. 410 | optional string experimental_map_key = 9; 411 | 412 | // For Google-internal migration only. Do not use. 413 | optional bool weak = 10 [default=false]; 414 | 415 | // The parser stores options it doesn't recognize here. See above. 416 | repeated UninterpretedOption uninterpreted_option = 999; 417 | 418 | // Clients can define custom options in extensions of this message. See above. 419 | extensions 1000 to max; 420 | } 421 | 422 | message EnumOptions { 423 | 424 | // Set this option to false to disallow mapping different tag names to a same 425 | // value. 426 | optional bool allow_alias = 2 [default=true]; 427 | 428 | // The parser stores options it doesn't recognize here. See above. 429 | repeated UninterpretedOption uninterpreted_option = 999; 430 | 431 | // Clients can define custom options in extensions of this message. See above. 432 | extensions 1000 to max; 433 | } 434 | 435 | message EnumValueOptions { 436 | // The parser stores options it doesn't recognize here. See above. 437 | repeated UninterpretedOption uninterpreted_option = 999; 438 | 439 | // Clients can define custom options in extensions of this message. See above. 440 | extensions 1000 to max; 441 | } 442 | 443 | message ServiceOptions { 444 | 445 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 446 | // framework. We apologize for hoarding these numbers to ourselves, but 447 | // we were already using them long before we decided to release Protocol 448 | // Buffers. 449 | 450 | // The parser stores options it doesn't recognize here. See above. 451 | repeated UninterpretedOption uninterpreted_option = 999; 452 | 453 | // Clients can define custom options in extensions of this message. See above. 454 | extensions 1000 to max; 455 | } 456 | 457 | message MethodOptions { 458 | 459 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 460 | // framework. We apologize for hoarding these numbers to ourselves, but 461 | // we were already using them long before we decided to release Protocol 462 | // Buffers. 463 | 464 | // The parser stores options it doesn't recognize here. See above. 465 | repeated UninterpretedOption uninterpreted_option = 999; 466 | 467 | // Clients can define custom options in extensions of this message. See above. 468 | extensions 1000 to max; 469 | } 470 | 471 | 472 | // A message representing a option the parser does not recognize. This only 473 | // appears in options protos created by the compiler::Parser class. 474 | // DescriptorPool resolves these when building Descriptor objects. Therefore, 475 | // options protos in descriptor objects (e.g. returned by Descriptor::options(), 476 | // or produced by Descriptor::CopyTo()) will never have UninterpretedOptions 477 | // in them. 478 | message UninterpretedOption { 479 | // The name of the uninterpreted option. Each string represents a segment in 480 | // a dot-separated name. is_extension is true iff a segment represents an 481 | // extension (denoted with parentheses in options specs in .proto files). 482 | // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents 483 | // "foo.(bar.baz).qux". 484 | message NamePart { 485 | required string name_part = 1; 486 | required bool is_extension = 2; 487 | } 488 | repeated NamePart name = 2; 489 | 490 | // The value of the uninterpreted option, in whatever type the tokenizer 491 | // identified it as during parsing. Exactly one of these should be set. 492 | optional string identifier_value = 3; 493 | optional uint64 positive_int_value = 4; 494 | optional int64 negative_int_value = 5; 495 | optional double double_value = 6; 496 | optional bytes string_value = 7; 497 | optional string aggregate_value = 8; 498 | } 499 | 500 | // =================================================================== 501 | // Optional source code info 502 | 503 | // Encapsulates information about the original source file from which a 504 | // FileDescriptorProto was generated. 505 | message SourceCodeInfo { 506 | // A Location identifies a piece of source code in a .proto file which 507 | // corresponds to a particular definition. This information is intended 508 | // to be useful to IDEs, code indexers, documentation generators, and similar 509 | // tools. 510 | // 511 | // For example, say we have a file like: 512 | // message Foo { 513 | // optional string foo = 1; 514 | // } 515 | // Let's look at just the field definition: 516 | // optional string foo = 1; 517 | // ^ ^^ ^^ ^ ^^^ 518 | // a bc de f ghi 519 | // We have the following locations: 520 | // span path represents 521 | // [a,i) [ 4, 0, 2, 0 ] The whole field definition. 522 | // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). 523 | // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). 524 | // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). 525 | // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). 526 | // 527 | // Notes: 528 | // - A location may refer to a repeated field itself (i.e. not to any 529 | // particular index within it). This is used whenever a set of elements are 530 | // logically enclosed in a single code segment. For example, an entire 531 | // extend block (possibly containing multiple extension definitions) will 532 | // have an outer location whose path refers to the "extensions" repeated 533 | // field without an index. 534 | // - Multiple locations may have the same path. This happens when a single 535 | // logical declaration is spread out across multiple places. The most 536 | // obvious example is the "extend" block again -- there may be multiple 537 | // extend blocks in the same scope, each of which will have the same path. 538 | // - A location's span is not always a subset of its parent's span. For 539 | // example, the "extendee" of an extension declaration appears at the 540 | // beginning of the "extend" block and is shared by all extensions within 541 | // the block. 542 | // - Just because a location's span is a subset of some other location's span 543 | // does not mean that it is a descendent. For example, a "group" defines 544 | // both a type and a field in a single declaration. Thus, the locations 545 | // corresponding to the type and field and their components will overlap. 546 | // - Code which tries to interpret locations should probably be designed to 547 | // ignore those that it doesn't understand, as more types of locations could 548 | // be recorded in the future. 549 | repeated Location location = 1; 550 | message Location { 551 | // Identifies which part of the FileDescriptorProto was defined at this 552 | // location. 553 | // 554 | // Each element is a field number or an index. They form a path from 555 | // the root FileDescriptorProto to the place where the definition. For 556 | // example, this path: 557 | // [ 4, 3, 2, 7, 1 ] 558 | // refers to: 559 | // file.message_type(3) // 4, 3 560 | // .field(7) // 2, 7 561 | // .name() // 1 562 | // This is because FileDescriptorProto.message_type has field number 4: 563 | // repeated DescriptorProto message_type = 4; 564 | // and DescriptorProto.field has field number 2: 565 | // repeated FieldDescriptorProto field = 2; 566 | // and FieldDescriptorProto.name has field number 1: 567 | // optional string name = 1; 568 | // 569 | // Thus, the above path gives the location of a field name. If we removed 570 | // the last element: 571 | // [ 4, 3, 2, 7 ] 572 | // this path refers to the whole field declaration (from the beginning 573 | // of the label to the terminating semicolon). 574 | repeated int32 path = 1 [packed=true]; 575 | 576 | // Always has exactly three or four elements: start line, start column, 577 | // end line (optional, otherwise assumed same as start line), end column. 578 | // These are packed into a single field for efficiency. Note that line 579 | // and column numbers are zero-based -- typically you will want to add 580 | // 1 to each before displaying to a user. 581 | repeated int32 span = 2 [packed=true]; 582 | 583 | // If this SourceCodeInfo represents a complete declaration, these are any 584 | // comments appearing before and after the declaration which appear to be 585 | // attached to the declaration. 586 | // 587 | // A series of line comments appearing on consecutive lines, with no other 588 | // tokens appearing on those lines, will be treated as a single comment. 589 | // 590 | // Only the comment content is provided; comment markers (e.g. //) are 591 | // stripped out. For block comments, leading whitespace and an asterisk 592 | // will be stripped from the beginning of each line other than the first. 593 | // Newlines are included in the output. 594 | // 595 | // Examples: 596 | // 597 | // optional int32 foo = 1; // Comment attached to foo. 598 | // // Comment attached to bar. 599 | // optional int32 bar = 2; 600 | // 601 | // optional string baz = 3; 602 | // // Comment attached to baz. 603 | // // Another line attached to baz. 604 | // 605 | // // Comment attached to qux. 606 | // // 607 | // // Another line attached to qux. 608 | // optional double qux = 4; 609 | // 610 | // optional string corge = 5; 611 | // /* Block comment attached 612 | // * to corge. Leading asterisks 613 | // * will be removed. */ 614 | // /* Block comment attached to 615 | // * grault. */ 616 | // optional int32 grault = 6; 617 | optional string leading_comments = 3; 618 | optional string trailing_comments = 4; 619 | } 620 | } 621 | -------------------------------------------------------------------------------- /tools/run/build.hxml: -------------------------------------------------------------------------------- 1 | -main CommandLineTools 2 | -neko ../../run.n 3 | -cp src 4 | -D neko_v1 5 | -------------------------------------------------------------------------------- /tools/run/src/CommandLineTools.hx: -------------------------------------------------------------------------------- 1 | package ; 2 | import haxe.Json; 3 | import haxe.Serializer; 4 | import haxe.Unserializer; 5 | import haxe.io.Path; 6 | import haxe.rtti.Meta; 7 | import sys.io.File; 8 | import sys.FileSystem; 9 | import sys.io.Process; 10 | import sys.FileSystem; 11 | import Helpers; 12 | 13 | class Context { 14 | private var protohxBaseDir:String; 15 | public static inline var DEFAULUT_PROTOC_PATH = "protoc"; 16 | 17 | public function new(protohxBaseDir) { 18 | this.protohxBaseDir = protohxBaseDir; 19 | } 20 | 21 | public function getDefaultConfigFileName():String { 22 | return "protohx.json"; 23 | } 24 | 25 | public function saveConfig(config:Dynamic):Void { 26 | var jsonData = Json.stringify(config); 27 | File.saveContent(protohxBaseDir + "/config.json", jsonData); 28 | } 29 | 30 | public function readConfigSafe():Dynamic { 31 | try { 32 | var fileContent = File.getContent(protohxBaseDir + "/config.json"); 33 | return Json.parse(fileContent); 34 | } catch (e:Dynamic) { 35 | return {}; 36 | } 37 | } 38 | 39 | public function getProtocPath():String { 40 | //TODO optimize 41 | var config:Dynamic = readConfigSafe(); 42 | var path = config.protocPath; 43 | return path != null ? path : DEFAULUT_PROTOC_PATH; 44 | } 45 | 46 | public function getProtohxBaseDir():String { 47 | return protohxBaseDir; 48 | } 49 | 50 | } 51 | 52 | 53 | class TaskDef { 54 | public var protoFiles:Array; 55 | public var protoPath:String; 56 | public var haxeOut:String; 57 | public var javaOut:String; 58 | public var cleanOut:Bool; 59 | 60 | public function new():Void { 61 | } 62 | 63 | public static function fromJson(taskJson:Dynamic):TaskDef { 64 | var result = new TaskDef(); 65 | result.protoPath = taskJson.protoPath; 66 | result.haxeOut = taskJson.haxeOut; 67 | result.javaOut = taskJson.javaOut; 68 | result.cleanOut = (taskJson.cleanOut == true); 69 | result.protoFiles = taskJson.protoFiles; 70 | return result; 71 | } 72 | } 73 | 74 | class Error { 75 | public var msg:String; 76 | 77 | public function new(msg:String = "") { 78 | this.msg = msg; 79 | } 80 | } 81 | 82 | class CommandLineTools { 83 | 84 | public static function saveDefaultConfig(fileName:String):Void { 85 | var task = new TaskDef(); 86 | task.protoPath = "."; 87 | task.haxeOut = "src-gen"; 88 | task.javaOut = null; 89 | task.cleanOut = true; 90 | task.protoFiles = ["protocol.proto"]; 91 | var jsonData = Json.stringify(task); 92 | File.saveContent(fileName, jsonData); 93 | } 94 | 95 | public static function parseConfig(fileName:String):TaskDef { 96 | var fileContent = File.getContent(fileName); 97 | var taskJson:Dynamic = Json.parse(fileContent); 98 | var result = TaskDef.fromJson(taskJson); 99 | 100 | if (result.protoPath == null) { 101 | result.protoPath = "."; 102 | } 103 | if (result.protoFiles == null || result.protoFiles.length == 0) { 104 | throw new Error("Required field 'protoFiles' is empty."); 105 | } 106 | if (result.haxeOut == null && result.javaOut == null) { 107 | throw new Error("Required fields 'haxeOut', 'javaOut' are empty."); 108 | } 109 | return result; 110 | } 111 | 112 | public static function executeTask(task:TaskDef, context:Context):Void { 113 | if (task.haxeOut != null) { 114 | Sys.println("task.haxeOut: " + task.haxeOut); 115 | if (task.cleanOut){ 116 | Sys.println("clean: " + task.haxeOut); 117 | PathHelper.removeDirectory(task.haxeOut); 118 | } 119 | PathHelper.mkdirs(task.haxeOut); 120 | task.haxeOut = FileSystem.fullPath(task.haxeOut); 121 | } 122 | if (task.javaOut != null) { 123 | if (task.cleanOut){ 124 | Sys.println("clean: " + task.javaOut); 125 | PathHelper.removeDirectory(task.javaOut); 126 | } 127 | PathHelper.mkdirs(task.javaOut); 128 | task.javaOut = FileSystem.fullPath(task.javaOut); 129 | } 130 | 131 | var oldCwd = Sys.getCwd(); 132 | var newCwd = oldCwd; 133 | var args:Array = []; 134 | if (task.haxeOut != null) { 135 | var pluginFileName = "plugin"; 136 | if (PlatformHelper.isWindows()) { 137 | pluginFileName += ".bat"; 138 | } 139 | var pluginDir = FileSystem.fullPath(context.getProtohxBaseDir() + "/tools/plugin/bin/"); 140 | var pluginPath = PathHelper.norm(pluginDir + "/" + pluginFileName); 141 | if (!PlatformHelper.isWindows()) { 142 | PlatformHelper.setExecutableBit(pluginPath); // TODO optimize 143 | } 144 | newCwd = pluginDir; 145 | args.push("--plugin=protoc-gen-haxe=" + (PlatformHelper.isWindows()?pluginFileName:pluginPath)); 146 | args.push("--haxe_out=" + PathHelper.norm(task.haxeOut)); 147 | } 148 | if (task.javaOut != null) { 149 | args.push("--java_out=" + PathHelper.norm(task.javaOut)); 150 | } 151 | args.push("--proto_path=" + PathHelper.norm(FileSystem.fullPath(task.protoPath))); 152 | for (pf in task.protoFiles){ 153 | args.push(PathHelper.norm(FileSystem.fullPath(pf))); 154 | } 155 | 156 | Sys.setCwd(newCwd); 157 | var protocPath = context.getProtocPath(); 158 | var code = PlatformHelper.command(protocPath, args); 159 | Sys.setCwd(oldCwd); 160 | Sys.println("----"); 161 | if (code != 0) { 162 | Sys.println("TIP: Check config and proto-files."); 163 | Sys.println(" Check protoc and java in system path."); 164 | Sys.println("----"); 165 | Sys.println("FAIL"); 166 | } else { 167 | if (task.haxeOut != null) {Sys.println("Haxe sources generated in '" + PathHelper.norm(task.haxeOut) + "'");} 168 | if (task.javaOut != null) {Sys.println("Java sources generated in '" + PathHelper.norm(task.javaOut) + "'");} 169 | Sys.println("----"); 170 | Sys.println("SUCCESS"); 171 | } 172 | } 173 | 174 | public static function printHelp():Void { 175 | Sys.println("For generate sources:"); 176 | Sys.println("\thaxelib run protohx generate [protohx.json]"); 177 | Sys.println("For creating deafult config:"); 178 | Sys.println("\thaxelib run protohx config [protohx.json]"); 179 | Sys.println("For setup protoc location:"); 180 | Sys.println("\thaxelib run protohx setup-protoc [protocPath]"); 181 | Sys.println("DEPENDENCIES: Require protoc and java in your system."); 182 | } 183 | 184 | public static function main():Void { 185 | try { 186 | var context:Context = new Context(Sys.getCwd()); 187 | var args = Sys.args(); 188 | 189 | var last:String = (new Path(args[args.length - 1])).dir; 190 | if (FileSystem.exists(last) && FileSystem.isDirectory(last)) { 191 | Sys.setCwd(last); 192 | } 193 | args = args.slice(0, args.length - 1); 194 | // trace(args); 195 | 196 | if (args.length > 0) { 197 | var cmd = args[0]; 198 | if (cmd == "generate" && args.length >= 1) { 199 | Sys.println("protocPath: " + context.getProtocPath()); 200 | var fileName = (args.length > 1 ? args[1] : context.getDefaultConfigFileName()); 201 | var config:TaskDef = parseConfig(fileName); 202 | if (config.haxeOut != null || config.javaOut != null) { 203 | executeTask(config, context); 204 | } 205 | } else if (cmd == "setup-protoc" && args.length >= 1) { 206 | var config = context.readConfigSafe(); 207 | if (args.length == 1) { 208 | config.protocPath = null; 209 | } else { 210 | config.protocPath = args[1]; 211 | } 212 | context.saveConfig(config); 213 | Sys.println("protocPath: " + context.getProtocPath()); 214 | } else if (cmd == "config" && args.length >= 1) { 215 | var fileName = (args.length > 1 ? args[1] : context.getDefaultConfigFileName()); 216 | saveDefaultConfig(fileName); 217 | } else { 218 | printHelp(); 219 | } 220 | } else { 221 | printHelp(); 222 | } 223 | } catch (e:Error) { 224 | Sys.println("ERROR: "); 225 | Sys.println(e.msg); 226 | } 227 | 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /tools/run/src/Helpers.hx: -------------------------------------------------------------------------------- 1 | package; 2 | import haxe.Json; 3 | import haxe.Serializer; 4 | import haxe.Unserializer; 5 | import haxe.io.Path; 6 | import haxe.rtti.Meta; 7 | import sys.io.File; 8 | import sys.io.Process; 9 | import sys.FileSystem; 10 | 11 | class Helpers { 12 | public function new() { 13 | } 14 | } 15 | 16 | 17 | enum Platform { 18 | WINDOWS; 19 | LINUX; 20 | MAC; 21 | } 22 | 23 | class PathHelper { 24 | public static function norm(path:String):String { 25 | path = StringTools.replace(path, "\\", "/"); 26 | path = StringTools.replace(path, "//", "/"); 27 | if(PlatformHelper.isWindows()){ 28 | path = StringTools.replace(path, "/", "\\"); 29 | } 30 | return path; 31 | } 32 | 33 | public static function mkdirs(directory:String):Void { 34 | directory = StringTools.replace(directory, "\\", "/"); 35 | var total = ""; 36 | if (directory.substr(0, 1) == "/") { 37 | total = "/"; 38 | } 39 | var parts = directory.split("/"); 40 | var oldPath = ""; 41 | if (parts.length > 0 && parts[0].indexOf(":") > -1) { 42 | oldPath = Sys.getCwd(); 43 | Sys.setCwd(parts[0] + "\\"); 44 | parts.shift(); 45 | } 46 | for (part in parts) { 47 | if (part != "." && part != "") { 48 | if (total != "") { 49 | total += "/"; 50 | } 51 | total += part; 52 | if (!FileSystem.exists(total)) { 53 | FileSystem.createDirectory(total); 54 | } 55 | } 56 | } 57 | if (oldPath != "") { 58 | Sys.setCwd(oldPath); 59 | } 60 | } 61 | 62 | public static function removeDirectory(directory:String):Void { 63 | if (FileSystem.exists(directory)) { 64 | for (file in FileSystem.readDirectory(directory)) { 65 | var path = directory + "/" + file; 66 | if (FileSystem.isDirectory(path)) { 67 | removeDirectory(path); 68 | } else { 69 | FileSystem.deleteFile(path); 70 | } 71 | } 72 | FileSystem.deleteDirectory(directory); 73 | } 74 | } 75 | } 76 | 77 | class PlatformHelper { 78 | private static var _hostPlatform:Platform; 79 | // from http://code.google.com/p/nekonme/source/browse/tools/helpers/PlatformHelper.hx 80 | 81 | public static function isWindows():Bool { 82 | return getHostPlatform() == Platform.WINDOWS; 83 | } 84 | 85 | public static function getHostPlatform():Platform { 86 | if (_hostPlatform == null) { 87 | if (new EReg ("window", "i").match(Sys.systemName())) { 88 | _hostPlatform = Platform.WINDOWS; 89 | } else if (new EReg ("linux", "i").match(Sys.systemName())) { 90 | _hostPlatform = Platform.LINUX; 91 | } else if (new EReg ("mac", "i").match(Sys.systemName())) { 92 | _hostPlatform = Platform.MAC; 93 | } 94 | } 95 | return _hostPlatform; 96 | } 97 | 98 | public static function command( cmd : String, ?args : Array ) : Int { 99 | Sys.println("---- PlatformHelper.command: "); 100 | Sys.println(" Sys.cwd: " + Sys.getCwd()); 101 | Sys.println(" Sys.command: '" + cmd + "' '" + args.join("' '") + "'"); 102 | return Sys.command(cmd, args); 103 | } 104 | 105 | public static function setExecutableBit(executable:String):Void { 106 | var platform = PlatformHelper.getHostPlatform(); 107 | if (platform == Platform.LINUX || platform == Platform.MAC) { 108 | PlatformHelper.command("chmod", ["a+x", PathHelper.norm(executable)]); 109 | } 110 | } 111 | } 112 | 113 | --------------------------------------------------------------------------------