├── .gitignore ├── LICENSE ├── README.md ├── client ├── Assets │ ├── Plugins.meta │ ├── Plugins │ │ ├── Debugger.dll │ │ ├── Debugger.dll.meta │ │ ├── Sproto.meta │ │ └── Sproto │ │ │ ├── Package.cs │ │ │ ├── Package.cs.meta │ │ │ ├── ProtocolBase.cs │ │ │ ├── ProtocolBase.cs.meta │ │ │ ├── ProtocolFunctionDictionary.cs │ │ │ ├── ProtocolFunctionDictionary.cs.meta │ │ │ ├── Serializer.meta │ │ │ ├── Serializer │ │ │ ├── Printer.cs │ │ │ └── Printer.cs.meta │ │ │ ├── SprotoAttribute.cs │ │ │ ├── SprotoAttribute.cs.meta │ │ │ ├── SprotoPack.cs │ │ │ ├── SprotoPack.cs.meta │ │ │ ├── SprotoRpc.cs │ │ │ ├── SprotoRpc.cs.meta │ │ │ ├── SprotoStream.cs │ │ │ ├── SprotoStream.cs.meta │ │ │ ├── SprotoTypeBase.cs │ │ │ ├── SprotoTypeBase.cs.meta │ │ │ ├── SprotoTypeDeserialize.cs │ │ │ ├── SprotoTypeDeserialize.cs.meta │ │ │ ├── SprotoTypeFieldOP.cs │ │ │ ├── SprotoTypeFieldOP.cs.meta │ │ │ ├── SprotoTypeReader.cs │ │ │ ├── SprotoTypeReader.cs.meta │ │ │ ├── SprotoTypeSerialize.cs │ │ │ ├── SprotoTypeSerialize.cs.meta │ │ │ ├── SprotoTypeSize.cs │ │ │ └── SprotoTypeSize.cs.meta │ ├── Scene.meta │ ├── Scene │ │ ├── Launch.unity │ │ └── Launch.unity.meta │ ├── Script.meta │ ├── Script │ │ ├── CodeGen.meta │ │ ├── CodeGen │ │ │ ├── backup.pbt │ │ │ ├── backup.pbt.meta │ │ │ ├── ui.pbt │ │ │ └── ui.pbt.meta │ │ ├── Constant.meta │ │ ├── Constant │ │ │ ├── Constant.cs │ │ │ └── Constant.cs.meta │ │ ├── Login.meta │ │ ├── Login │ │ │ ├── Login.cs │ │ │ └── Login.cs.meta │ │ ├── Network.meta │ │ ├── Network │ │ │ ├── ClientSocket.cs │ │ │ ├── ClientSocket.cs.meta │ │ │ ├── MessageDispatcher.cs │ │ │ ├── MessageDispatcher.cs.meta │ │ │ ├── MessageMeta.cs │ │ │ ├── MessageMeta.cs.meta │ │ │ ├── NetworkPeer.cs │ │ │ ├── NetworkPeer.cs.meta │ │ │ ├── NetworkPeerBase.cs │ │ │ ├── NetworkPeerBase.cs.meta │ │ │ ├── PeerManager.cs │ │ │ └── PeerManager.cs.meta │ │ ├── Proto.meta │ │ ├── Proto │ │ │ ├── sp.cs │ │ │ └── sp.cs.meta │ │ ├── Utility.meta │ │ └── Utility │ │ │ ├── Editor.meta │ │ │ ├── Editor │ │ │ ├── ShowSelectObjectPath.cs │ │ │ └── ShowSelectObjectPath.cs.meta │ │ │ ├── ObjectUtility.cs │ │ │ ├── ObjectUtility.cs.meta │ │ │ ├── Singleton.cs │ │ │ ├── Singleton.cs.meta │ │ │ ├── StringUtility.cs │ │ │ └── StringUtility.cs.meta │ ├── gmcs.rsp │ ├── gmcs.rsp.meta │ ├── smcs.rsp │ └── smcs.rsp.meta └── ProjectSettings │ ├── AudioManager.asset │ ├── ClusterInputManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── Physics2DSettings.asset │ ├── ProjectSettings.asset │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ └── UnityConnectSettings.asset ├── proto ├── GenerateProto.bat ├── clientnet.sp ├── login.sp └── tool │ ├── Install.bat │ └── gen_sproto.bat └── server ├── bat ├── InstallDebugAll.bat └── StartGOPATH.bat └── src ├── github.com └── davyxu │ ├── cellnet │ ├── .gitignore │ ├── .travis.yml │ ├── CHANGES.md │ ├── LICENSE │ ├── README.md │ ├── RunAllTest.bat │ ├── benchmark │ │ ├── Profile.bat │ │ ├── io │ │ │ └── io_test.go │ │ └── qpsmeter.go │ ├── codec.go │ ├── codec │ │ ├── binary │ │ │ └── binary.go │ │ ├── json │ │ │ └── json.go │ │ ├── pb │ │ │ └── pb.go │ │ └── sproto │ │ │ └── sproto.go │ ├── doc │ │ └── handler.png │ ├── event.go │ ├── example │ │ ├── classicrecv │ │ │ └── classicrecv_test.go │ │ ├── echo_pb │ │ │ └── echo_pb_test.go │ │ ├── echo_sproto │ │ │ └── echo_sproto_test.go │ │ ├── echo_websocket │ │ │ ├── echo_websocket_test.go │ │ │ └── index.html │ │ ├── gracefulexit │ │ │ ├── acceptor_test.go │ │ │ └── connector_test.go │ │ ├── rpc │ │ │ └── rpc_test.go │ │ ├── sendclose │ │ │ └── sendclose_test.go │ │ └── timer │ │ │ └── timer_test.go │ ├── extend │ │ └── sysevent.go │ ├── handler.go │ ├── handler_callback.go │ ├── handler_decode.go │ ├── handler_encode.go │ ├── handler_fixedlenframe.go │ ├── handler_matchmsgid.go │ ├── handler_msglog.go │ ├── handler_queuepost.go │ ├── handlerchain.go │ ├── handlerchainmgr.go │ ├── log.go │ ├── msgmeta.go │ ├── objprotogen │ │ ├── main.go │ │ ├── model.go │ │ ├── printer.go │ │ └── util.go │ ├── peer.go │ ├── peerprofile.go │ ├── proto │ │ ├── GenerateProto.bat │ │ ├── binary │ │ │ ├── coredef │ │ │ │ ├── binmsg.go │ │ │ │ └── objproto_gen.go │ │ │ └── gen_binary.bat │ │ ├── json │ │ │ └── gamedef │ │ │ │ └── jsonmsg.go │ │ ├── pb │ │ │ ├── gamedef.proto │ │ │ ├── gamedef │ │ │ │ ├── gamedef.pb.go │ │ │ │ └── msgid.go │ │ │ └── gen_pb.bat │ │ └── sproto │ │ │ ├── gamedef.sproto │ │ │ ├── gamedef │ │ │ └── gamedef.go │ │ │ └── gen_sproto.bat │ ├── protoc-gen-msg │ │ ├── file.go │ │ └── main.go │ ├── queue.go │ ├── rpc │ │ ├── ack_reg.go │ │ ├── handler_box.go │ │ ├── handler_reflectcall.go │ │ ├── handler_retchan.go │ │ ├── handler_unbox.go │ │ ├── log.go │ │ ├── req_async.go │ │ ├── req_sync.go │ │ ├── reqhandler.go │ │ └── util.go │ ├── sesmgr.go │ ├── socket │ │ ├── acceptor.go │ │ ├── base.go │ │ ├── connector.go │ │ ├── evtlist.go │ │ ├── handler_privatepkt.go │ │ ├── log.go │ │ ├── options.go │ │ └── session.go │ ├── timer │ │ ├── after.go │ │ └── loop.go │ ├── util │ │ ├── signaltester.go │ │ ├── strhash.go │ │ └── strhash_test.go │ └── websocket │ │ ├── acceptor.go │ │ ├── base.go │ │ ├── connector.go │ │ ├── log.go │ │ ├── session.go │ │ └── textpkt.go │ ├── golexer │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── errcatcher.go │ ├── kvpair.go │ ├── kvparser.go │ ├── kvparser_test.go │ ├── lexer.go │ ├── lexer_test.go │ ├── matcher.go │ ├── matcher_backticks.go │ ├── matcher_cstylecomment.go │ ├── matcher_identifier.go │ ├── matcher_keyword.go │ ├── matcher_lineend.go │ ├── matcher_numeral.go │ ├── matcher_sign.go │ ├── matcher_string.go │ ├── matcher_unixstylecomment.go │ ├── matcher_unknown.go │ ├── matcher_whitespace.go │ ├── parser.go │ ├── token.go │ ├── tokenizer.go │ └── tokenpos.go │ ├── golog │ ├── README.md │ ├── color.go │ ├── color_sample.json │ ├── level.go │ ├── log.go │ ├── log_test.go │ └── manager.go │ ├── goobjfmt │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── binary_reader.go │ ├── binary_size.go │ ├── binary_test.go │ ├── binary_writer.go │ ├── codec.go │ ├── lib.go │ ├── text_marshaler.go │ ├── text_marshaler_test.go │ └── text_writer.go │ └── gosproto │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── decode.go │ ├── encode.go │ ├── enum.go │ ├── example │ ├── Make.bat │ ├── addressbook.sp │ ├── addressbook_gen.cs │ ├── addressbook_gen.go │ ├── addressbook_gen.lua │ ├── addressbook_gen.sp │ ├── addressbook_gen.sproto │ ├── addressbook_test.go │ └── test.lua │ ├── meta.go │ ├── meta │ ├── commentgroup.go │ ├── commentparser.go │ ├── commentparser_test.go │ ├── field.go │ ├── fieldtype.go │ ├── file.go │ ├── fileset.go │ ├── lazyfield.go │ ├── parse_all.go │ ├── parse_enum.go │ ├── parse_enumfield.go │ ├── parse_misc.go │ ├── parse_struct.go │ ├── parse_structfield.go │ ├── parser.go │ ├── parser_test.go │ └── struct.go │ ├── pack.go │ ├── pack_test.go │ ├── pb2sproto │ ├── Make.bat │ ├── gen_proto.go │ ├── main.go │ ├── pb.proto │ └── pb.sp │ ├── sproto.go │ ├── sproto_test.go │ └── sprotogen │ ├── enumvaluegroup.go │ ├── gen_csharp.go │ ├── gen_emmylua.go │ ├── gen_go.go │ ├── gen_lua.go │ ├── gen_sp.go │ ├── gen_sproto.go │ ├── main.go │ ├── model.go │ ├── strhash.go │ └── util.go ├── proto └── msg_sp.go ├── svc ├── model.go └── setup.go ├── svcmod └── login │ ├── main.go │ └── platformverify │ └── platformverify_msg.go └── table └── log.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.pb 3 | *.suo 4 | *.user 5 | .idea 6 | /client/*.csproj 7 | /client/*.csproj 8 | /client/*.sln 9 | /client/*.userprefs 10 | /client/Assets/Lua/**/*.meta 11 | /client/Library 12 | /client/ProjectSettings/ProjectVersion.txt 13 | /client/Temp 14 | /client/obj 15 | /proto/tool/*.exe 16 | /server/bin 17 | /server/cfg/Local.pbt 18 | /server/pkg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Davy xu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cellorigin 2 | 基于cellnet和Unity3D的游戏框架 3 | 4 | 5 | # 第三方依赖 6 | 7 | https://github.com/davyxu/cellnet 8 | https://github.com/davyxu/golexer 9 | https://github.com/davyxu/golog 10 | https://github.com/davyxu/goobjfmt 11 | https://github.com/davyxu/gosproto 12 | 13 | # 文件夹功能 14 | ``` 15 | client // Unity客户端代码 16 | proto // 协议 17 | tool // 协议工具及shell 18 | server // 完整服务器代码 19 | src 20 | svc // 服务共享代码 21 | svcmod // 所有服务器 22 | login // 登录服务器 23 | ``` 24 | 25 | 26 | 27 | 28 | # 开发环境 29 | 30 | * Unity3D 5.5+ 31 | 32 | * Golang 1.8+ 33 | 34 | # 协议编译 35 | 36 | 使用sproto作为协议描述及通信格式 37 | 38 | sproto协议格式简单, 方便解析, 对lua开发较为友好 39 | 40 | 41 | - 编译sproto协议生成器 42 | 43 | 执行proto/tool/Install.bat 44 | 45 | - 根据sproto协议(*.sp)文件生成代码 46 | 47 | 执行proto/GenerateProto.bat 48 | 49 | - 生成文件位置 50 | 51 | Golang: server/src/proto/msg_sp.go 52 | 53 | C#: client/Assets/Script/Proto/sp.cs 54 | 55 | 56 | # 服务器开发指南 57 | 58 | 开发工具推荐使用Gogland(https://www.jetbrains.com/go/) 59 | 60 | ## 设置GOPATH 61 | 62 | 设置项目GOPATH为server下 63 | 64 | ## 运行 65 | 66 | 找到server/src/svcmod/login/main.go 67 | 在main前的绿箭头点击运行 68 | 69 | 70 | # 客户端开发指南 71 | 72 | ## 找到入口 73 | 74 | client/Assets/Scene/Launch.unity 75 | 76 | 运行后, 点击hello, 将连接服务器127.0.0.1:8001端口发送LoginREQ消息并接收LoginACK消息 77 | 78 | 79 | 80 | # 备注 81 | 82 | 感觉不错请star, 谢谢! 83 | 84 | 博客: http://www.cppblog.com/sunicdavy 85 | 86 | 知乎: http://www.zhihu.com/people/sunicdavy 87 | 88 | 89 | -------------------------------------------------------------------------------- /client/Assets/Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e34dc6e361156f0439e74fa578a45650 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Debugger.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davyxu/cellorigin/29ffec6fdb9c90ee816c0d0b255a4db0552e7c76/client/Assets/Plugins/Debugger.dll -------------------------------------------------------------------------------- /client/Assets/Plugins/Debugger.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c33668af923d0aa4ebd48ebe80ef943a 3 | MonoAssemblyImporter: 4 | serializedVersion: 1 5 | iconMap: {} 6 | executionOrder: {} 7 | userData: 8 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3eafcbd722a4bdf47a1c572408930b8a 3 | folderAsset: yes 4 | timeCreated: 1503384179 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/Package.cs: -------------------------------------------------------------------------------- 1 | // Generated by sprotodump. DO NOT EDIT! 2 | // source: Package.sproto 3 | 4 | using System; 5 | using Sproto; 6 | using System.Collections.Generic; 7 | 8 | namespace SprotoType { 9 | public class Package : SprotoTypeBase { 10 | private static int max_field_count = 2; 11 | 12 | 13 | private Int64 _type; // tag 0 14 | public Int64 type { 15 | get { return _type; } 16 | set { base.has_field.set_field (0, true); _type = value; } 17 | } 18 | public bool HasType { 19 | get { return base.has_field.has_field (0); } 20 | } 21 | 22 | private Int64 _session; // tag 1 23 | public Int64 session { 24 | get { return _session; } 25 | set { base.has_field.set_field (1, true); _session = value; } 26 | } 27 | public bool HasSession { 28 | get { return base.has_field.has_field (1); } 29 | } 30 | 31 | public Package () : base(max_field_count) {} 32 | 33 | public Package (byte[] buffer) : base(max_field_count, buffer) { 34 | this.decode (); 35 | } 36 | 37 | protected override void decode () { 38 | int tag = -1; 39 | while (-1 != (tag = base.deserialize.read_tag ())) { 40 | switch (tag) { 41 | case 0: 42 | this.type = base.deserialize.read_integer (); 43 | break; 44 | case 1: 45 | this.session = base.deserialize.read_integer (); 46 | break; 47 | default: 48 | base.deserialize.read_unknow_data (); 49 | break; 50 | } 51 | } 52 | } 53 | 54 | public override int encode (SprotoStream stream) { 55 | base.serialize.open (stream); 56 | 57 | if (base.has_field.has_field (0)) { 58 | base.serialize.write_integer (this.type, 0); 59 | } 60 | 61 | if (base.has_field.has_field (1)) { 62 | base.serialize.write_integer (this.session, 1); 63 | } 64 | 65 | return base.serialize.close (); 66 | } 67 | } 68 | 69 | 70 | } 71 | 72 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/Package.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f805d23edc7037747920b5bee4b7fd0b 3 | timeCreated: 1486546378 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/ProtocolBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sproto 4 | { 5 | public abstract class ProtocolBase { 6 | private ProtocolFunctionDictionary _Protocol = new ProtocolFunctionDictionary (); 7 | public ProtocolFunctionDictionary Protocol { 8 | get { return _Protocol;} 9 | } 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/ProtocolBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 688a943556559184697788ad9358230f 3 | timeCreated: 1486546377 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/ProtocolFunctionDictionary.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9344af7ea3c69c84a97fa92696283f79 3 | timeCreated: 1486546377 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/Serializer.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 98a8e385c5c878147ba81dee8e384cdd 3 | folderAsset: yes 4 | timeCreated: 1462430272 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/Serializer/Printer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef45f2d0f04c9764f9d264e87efac677 3 | timeCreated: 1462430273 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Sproto 6 | { 7 | public sealed class SprotoHasFieldAttribute : Attribute 8 | { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0d6e8509bc68784c9dc4123aa7bebb6 3 | timeCreated: 1488966474 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoPack.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed518994f9539d54383fb3ac17e07603 3 | timeCreated: 1486546378 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoRpc.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f1471430b442c984d8f13cb614f5eb53 3 | timeCreated: 1486546378 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoStream.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a5e3d8e3c44476499acd2f1a433a591 3 | timeCreated: 1486546377 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | 5 | namespace Sproto { 6 | public abstract class SprotoTypeBase { 7 | protected SprotoTypeFieldOP has_field; 8 | protected SprotoTypeSerialize serialize; 9 | protected SprotoTypeDeserialize deserialize; 10 | 11 | 12 | public SprotoTypeBase(int max_field_count) { 13 | this.has_field = new SprotoTypeFieldOP (max_field_count); 14 | this.serialize = new SprotoTypeSerialize (max_field_count); 15 | this.deserialize = new SprotoTypeDeserialize (); 16 | } 17 | 18 | public int init (byte[] buffer, int offset=0){ 19 | this.clear (); 20 | this.deserialize.init (buffer, offset); 21 | this.decode (); 22 | 23 | return this.deserialize.size (); 24 | } 25 | 26 | public long init (SprotoTypeReader reader) { 27 | this.clear (); 28 | this.deserialize.init (reader); 29 | this.decode (); 30 | 31 | return this.deserialize.size (); 32 | } 33 | 34 | public SprotoTypeBase(int max_field_count, byte[] buffer) { 35 | this.has_field = new SprotoTypeFieldOP (max_field_count); 36 | this.serialize = new SprotoTypeSerialize (max_field_count); 37 | this.deserialize = new SprotoTypeDeserialize (buffer); 38 | } 39 | 40 | public abstract int encode (SprotoStream stream); 41 | 42 | public byte[] encode () { 43 | SprotoStream stream = new SprotoStream (); 44 | this.encode (stream); 45 | int len = stream.Position; 46 | 47 | byte[] buffer = new byte[len]; 48 | stream.Seek (0, SeekOrigin.Begin); 49 | stream.Read (buffer, 0, len); 50 | 51 | return buffer; 52 | } 53 | 54 | protected abstract void decode (); 55 | 56 | public void clear(){ 57 | // clear has slot 58 | this.has_field.clear_field (); 59 | 60 | // clear deserialize 61 | this.deserialize.clear (); 62 | } 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d19ca483eb8a0e94ca92b37d9bb4b93f 3 | timeCreated: 1486546378 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeDeserialize.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d296d3824d804994784819b7a9e98805 3 | timeCreated: 1486546378 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeFieldOP.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sproto { 4 | 5 | public class SprotoTypeFieldOP { 6 | 7 | static readonly int slot_bits_size = sizeof(UInt32)*8; 8 | public UInt32[] has_bits; 9 | 10 | public SprotoTypeFieldOP (int max_field_count) { 11 | int slot_count = max_field_count / slot_bits_size; 12 | if(max_field_count % slot_bits_size >0) { 13 | slot_count++; 14 | } 15 | 16 | this.has_bits = new UInt32[slot_count]; 17 | } 18 | 19 | private int _get_array_idx(int bit_idx){ 20 | int size = has_bits.Length; 21 | int array_idx = bit_idx / slot_bits_size; 22 | 23 | return array_idx; 24 | } 25 | 26 | private int _get_slotbit_idx(int bit_idx){ 27 | int size = has_bits.Length; 28 | int slotbit_idx = bit_idx % slot_bits_size; 29 | 30 | return slotbit_idx; 31 | } 32 | 33 | 34 | public bool has_field(int field_idx){ 35 | int array_idx = this._get_array_idx(field_idx); 36 | int slotbit_idx = this._get_slotbit_idx (field_idx); 37 | 38 | UInt32 slot = this.has_bits [array_idx]; 39 | UInt32 mask = (UInt32)(1) << (slotbit_idx); 40 | 41 | return Convert.ToBoolean (slot & mask); 42 | } 43 | 44 | public void set_field(int field_idx, bool is_has){ 45 | int array_idx = this._get_array_idx(field_idx); 46 | int slotbit_idx = this._get_slotbit_idx (field_idx); 47 | 48 | UInt32 slot = this.has_bits [array_idx]; 49 | if (is_has) { 50 | UInt32 mask = (UInt32)(1) << slotbit_idx; 51 | this.has_bits [array_idx] = slot | mask; 52 | } else { 53 | UInt32 mask = ~((UInt32)(1) << slotbit_idx); 54 | this.has_bits [array_idx] = slot & mask; 55 | } 56 | } 57 | 58 | public void clear_field(){ 59 | for(int i=0; i< this.has_bits.Length; i++){ 60 | this.has_bits [i] = 0; 61 | } 62 | } 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeFieldOP.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2f752b579f9115549aeb1357678ed89d 3 | timeCreated: 1486546377 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sproto 4 | { 5 | public class SprotoTypeReader 6 | { 7 | 8 | private byte[] buffer; 9 | private int begin; 10 | private int pos; 11 | private int size; 12 | 13 | public byte[] Buffer { 14 | get { return buffer;} 15 | } 16 | 17 | public int Position { 18 | get { return this.pos - this.begin; } 19 | } 20 | 21 | public int Offset { 22 | get { return this.pos; } 23 | } 24 | 25 | public int Length { 26 | get {return this.size - this.begin;} 27 | } 28 | 29 | public SprotoTypeReader (byte[] buffer, int offset, int size) { 30 | this.Init(buffer, offset, size); 31 | } 32 | 33 | public SprotoTypeReader() { 34 | } 35 | 36 | 37 | public void Init(byte[] buffer, int offset, int size) { 38 | this.begin = offset; 39 | this.pos = offset; 40 | this.buffer = buffer; 41 | this.size = offset + size; 42 | this.check (); 43 | } 44 | 45 | 46 | private void check() { 47 | if(this.pos > this.size || this.begin > this.pos) { 48 | SprotoTypeSize.error("invalid pos."); 49 | } 50 | } 51 | 52 | public byte ReadByte () { 53 | this.check(); 54 | return this.buffer [this.pos++]; 55 | } 56 | 57 | public void Seek (int offset) { 58 | this.pos = this.begin + offset; 59 | this.check (); 60 | } 61 | 62 | public void Read(byte[] data, int offset, int size) { 63 | int cur_pos = this.pos; 64 | this.pos += size; 65 | check (); 66 | 67 | for (int i = cur_pos; i < this.pos; i++) { 68 | data [offset + i - cur_pos] = this.buffer [i]; 69 | } 70 | } 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeReader.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eff3c9e6dcd1a764aa0d78110b2f42e6 3 | timeCreated: 1486546378 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeSerialize.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfa22aca6530dd24bb5c302a27534c6c 3 | timeCreated: 1486546378 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeSize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sproto 4 | { 5 | public class SprotoTypeSize { 6 | public static readonly int sizeof_header = 2; 7 | public static readonly int sizeof_length = 4; 8 | public static readonly int sizeof_field = 2; 9 | public static readonly int encode_max_size = 0x1000000; 10 | 11 | public static void error(string info) { 12 | throw new Exception (info); 13 | } 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /client/Assets/Plugins/Sproto/SprotoTypeSize.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b4989b08b0156b4e84eb63f7ba2236f 3 | timeCreated: 1486546377 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Scene.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6957eaed32a88541bb798ddb5d011ea 3 | folderAsset: yes 4 | timeCreated: 1458284062 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Scene/Launch.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee6f6098e9a7ab4418f7aabf3c930958 3 | timeCreated: 1503385685 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /client/Assets/Script.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5484448f7bd08554790e9f638ff8b313 3 | folderAsset: yes 4 | timeCreated: 1456984688 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/CodeGen.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe1d55af01f36fb489be5b75ff7cff80 3 | folderAsset: yes 4 | timeCreated: 1462868093 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/CodeGen/backup.pbt: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeGen 4 | { 5 | Name: "Login" 6 | 7 | Peer 8 | { 9 | Name: "login" 10 | 11 | RecvMessage: "gamedef.PeerConnected" 12 | RecvMessage: "gamedef.LoginACK" 13 | 14 | } 15 | 16 | Peer 17 | { 18 | Name: "game" 19 | 20 | RecvMessage: "gamedef.PeerConnected" 21 | RecvMessage: "gamedef.VerifyGameACK" 22 | 23 | } 24 | } 25 | 26 | CodeGen 27 | { 28 | Name: "LoginServerInfo" 29 | 30 | NoGenPresenterCode: true 31 | } 32 | 33 | 34 | 35 | 36 | CodeGen 37 | { 38 | Name: "LoginCharBoard" 39 | Peer 40 | { 41 | Name: "game" 42 | 43 | RecvMessage: "gamedef.CharListACK" 44 | 45 | } 46 | } 47 | 48 | 49 | CodeGen 50 | { 51 | Name: "LoginCharInfo" 52 | ModelGen: MGT_Instance 53 | } 54 | -------------------------------------------------------------------------------- /client/Assets/Script/CodeGen/backup.pbt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99d5b3da7e15391498e9c4afe6301379 3 | timeCreated: 1463122351 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /client/Assets/Script/CodeGen/ui.pbt: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeGen 4 | { 5 | Name: "TestBoard" 6 | } 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/Assets/Script/CodeGen/ui.pbt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d20a7986483f331468d8de1d58a5fe76 3 | timeCreated: 1462868093 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /client/Assets/Script/Constant.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff39666a1adaf844e8b1290095660d12 3 | folderAsset: yes 4 | timeCreated: 1458288636 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/Constant/Constant.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | class Constant 4 | { 5 | public const string ClientVersion = "0.1.0"; 6 | public const string DevAddress = "127.0.0.1:8101"; 7 | public const string PublicAddress = "www.test.com:8101"; 8 | } 9 | -------------------------------------------------------------------------------- /client/Assets/Script/Constant/Constant.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2db780da539c1854691da92156a69003 3 | timeCreated: 1458288636 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Login.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d46444a78e0d67a45970cef8e0865830 3 | folderAsset: yes 4 | timeCreated: 1503384360 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/Login/Login.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class Login : MonoBehaviour { 6 | 7 | public NetworkPeer peer; 8 | 9 | // Use this for initialization 10 | void Start () { 11 | peer.RegisterMessage(msg => 12 | { 13 | Debug.Log("connected"); 14 | 15 | var req = new proto.LoginREQ(); 16 | req.PlatformToken = "hello"; 17 | 18 | peer.SendMessage(req); 19 | }); 20 | 21 | peer.RegisterMessage(raw => 22 | { 23 | var ack = raw as proto.LoginACK; 24 | 25 | Debug.Log(string.Format("login ok {0}", ack.Token)); 26 | }); 27 | } 28 | 29 | // Update is called once per frame 30 | void Update () { 31 | 32 | 33 | } 34 | 35 | private void OnDestroy() 36 | { 37 | peer.Stop(); 38 | } 39 | 40 | void OnGUI() 41 | { 42 | if ( GUI.Button(new Rect(10, 10, 50, 50), "hello")) 43 | { 44 | peer.Connect("127.0.0.1:8001"); 45 | UnityEngine.Debug.Log("login"); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /client/Assets/Script/Login/Login.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db78631250f52a44cba40fb1d7fda2f1 3 | timeCreated: 1503384372 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Network.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a70af8f032aa4a04db604971426fb5c9 3 | folderAsset: yes 4 | timeCreated: 1458616435 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/ClientSocket.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb820167bed6b6b4d8292776eee13453 3 | timeCreated: 1456984816 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/MessageDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | public class MessageDispatcher 5 | { 6 | Dictionary> _msgCallbacks = new Dictionary>(); 7 | 8 | public void Add(uint msgid, Action callback) 9 | { 10 | Action callbacks; 11 | if (_msgCallbacks.TryGetValue(msgid, out callbacks)) 12 | { 13 | callbacks += callback; 14 | _msgCallbacks[msgid] = callbacks; 15 | } 16 | else 17 | { 18 | callbacks += callback; 19 | 20 | _msgCallbacks.Add(msgid, callbacks); 21 | } 22 | } 23 | 24 | public void Remove(uint msgid, Action callback) 25 | { 26 | Action callbacks; 27 | if (_msgCallbacks.TryGetValue(msgid, out callbacks)) 28 | { 29 | callbacks -= callback; 30 | _msgCallbacks[msgid] = callbacks; 31 | } 32 | } 33 | 34 | public void Invoke(uint msgid, object msg) 35 | { 36 | Action callbacks; 37 | if (!_msgCallbacks.TryGetValue(msgid, out callbacks)) 38 | { 39 | return; 40 | } 41 | 42 | callbacks.Invoke(msg); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/MessageDispatcher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 988fe70aac4340b4a8281e2d357bbf80 3 | timeCreated: 1461768332 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/MessageMeta.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e206344b44937ea448fc2a34d4799d9e 3 | timeCreated: 1456986863 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/NetworkPeer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3889061bdc6cd824e8aef2cbef184707 3 | timeCreated: 1468808474 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/NetworkPeerBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 421e8f28ca2e61c41aa37ccc753fd7fb 3 | timeCreated: 1456984815 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/PeerManager.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class PeerManager : Singleton 4 | { 5 | MessageMetaSet _meta; 6 | 7 | public MessageMetaSet MsgMeta 8 | { 9 | get { return _meta; } 10 | } 11 | 12 | public PeerManager( ) 13 | { 14 | _meta = new MessageMetaSet(); 15 | _meta.Scan("proto"); 16 | } 17 | 18 | /// 19 | /// 在主摄像机上放置NetworkPeer 20 | /// 21 | /// 提前命名 22 | /// 23 | public NetworkPeer Get( string name ) 24 | { 25 | var cam = Camera.main; 26 | if (cam == null) 27 | { 28 | Debug.LogError("NetworkPeer 必须在主摄像机上"); 29 | return null; 30 | } 31 | 32 | var peers = cam.GetComponents(); 33 | for( int i = 0;i< peers.Length;i++) 34 | { 35 | if (peers[i].Name == name) 36 | return peers[i]; 37 | } 38 | 39 | // Make unity happy 40 | var com = cam.gameObject.AddComponent(); 41 | com.Name = name; 42 | return com; 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /client/Assets/Script/Network/PeerManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 317637477fab9d14d8286fb4453780ce 3 | timeCreated: 1458632276 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Proto.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f59f45a50aa2a094482d00a5f7af9f56 3 | folderAsset: yes 4 | timeCreated: 1456986229 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/Proto/sp.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 95e3f723f172894499301f5ef27f445a 3 | timeCreated: 1503383956 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56790d62bf9d6ce448f6867e97d7357c 3 | folderAsset: yes 4 | timeCreated: 1456987715 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2063b5e555e5cdc4c86c87ff07fb61ba 3 | folderAsset: yes 4 | timeCreated: 1458537791 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/Editor/ShowSelectObjectPath.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | 4 | /// 5 | /// 在日志中显示选中对象的绝对路径 6 | /// 7 | public class ShowSelectObjectPath : MonoBehaviour { 8 | 9 | [MenuItem("CellOrigin/查看GameObject路径")] 10 | public static void ShowPath( ) 11 | { 12 | foreach( Object obj in Selection.objects ) 13 | { 14 | var go = obj as GameObject; 15 | if (go == null) 16 | continue; 17 | 18 | Debug.Log(ObjectUtility.GetGameObjectPath(go)); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/Editor/ShowSelectObjectPath.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db81b75f16d8dd6469cdfb39768dde05 3 | timeCreated: 1458539937 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/ObjectUtility.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class ObjectUtility 4 | { 5 | public static string GetGameObjectPath(GameObject obj, GameObject relativeTo = null) 6 | { 7 | string path = obj.name; 8 | while (obj.transform.parent != null) 9 | { 10 | obj = obj.transform.parent.gameObject; 11 | 12 | if (obj == relativeTo) 13 | break; 14 | 15 | path = obj.name + "/" + path; 16 | } 17 | 18 | // 绝对引用加/ 19 | if ( relativeTo == null ) 20 | { 21 | path = "/" + path; 22 | } 23 | 24 | return path; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/ObjectUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 28651219854e8444bbfddbcf3fa5b47a 3 | timeCreated: 1458464006 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/Singleton.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class Singleton where T : new() 4 | { 5 | 6 | // Instead of compile time check, we provide a run time check 7 | // to make sure there is only one instance. 8 | protected Singleton() 9 | { 10 | Debug.Assert(null == _instance); 11 | } 12 | 13 | protected static T _instance = new T(); 14 | 15 | public static T Instance 16 | { 17 | get { return _instance; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/Singleton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2584f6d645be7f241b7f7eaf996a3450 3 | timeCreated: 1458615268 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/StringUtility.cs: -------------------------------------------------------------------------------- 1 |  2 | public class StringUtility 3 | { 4 | static bool _init; 5 | static uint _crcPoly = 0x04c11db7; 6 | 7 | static uint[] _crcTable = new uint[256]; 8 | 9 | static void InitCRCTable() 10 | { 11 | uint c = 0; 12 | uint j = 0; 13 | 14 | for (uint i = 0; i < _crcTable.Length; i++) 15 | { 16 | c = i << 24; 17 | 18 | for (j = 8; j != 0; j = j - 1) 19 | { 20 | if ((c & 0x80000000) != 0) 21 | { 22 | c = (c << 1) ^ _crcPoly; 23 | } 24 | else 25 | { 26 | c = c << 1; 27 | } 28 | 29 | _crcTable[i] = c; 30 | } 31 | } 32 | } 33 | 34 | public static uint Hash( string msgType ) 35 | { 36 | if (!_init) 37 | { 38 | InitCRCTable(); 39 | _init = true; 40 | } 41 | 42 | 43 | uint hash = 0; 44 | uint b = 0; 45 | 46 | for (int i = 0; i < msgType.Length; i++) 47 | { 48 | b = (uint)(msgType[i]); 49 | hash = ((hash >> 8) & 0x00FFFFFF) ^ _crcTable[(hash ^ b) & 0x000000FF]; 50 | } 51 | 52 | return hash; 53 | } 54 | 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /client/Assets/Script/Utility/StringUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a2aec62b5d7518847bbf6ce316148ddc 3 | timeCreated: 1456987715 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /client/Assets/gmcs.rsp: -------------------------------------------------------------------------------- 1 | -unsafe -------------------------------------------------------------------------------- /client/Assets/gmcs.rsp.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4847bf827666242419a7b97be6228ba8 3 | timeCreated: 1468421328 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /client/Assets/smcs.rsp: -------------------------------------------------------------------------------- 1 | -unsafe -------------------------------------------------------------------------------- /client/Assets/smcs.rsp.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d89bb12635212b44bf42a0dcac0b2cb 3 | timeCreated: 1456984866 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /client/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 0 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_DisableAudio: 0 16 | -------------------------------------------------------------------------------- /client/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /client/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_SolverIterationCount: 6 13 | m_QueriesHitTriggers: 1 14 | m_EnableAdaptiveForce: 0 15 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 16 | -------------------------------------------------------------------------------- /client/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | -------------------------------------------------------------------------------- /client/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 3 7 | m_ExternalVersionControlSupport: Hidden Meta Files 8 | m_SerializationMode: 2 9 | m_WebSecurityEmulationEnabled: 0 10 | m_WebSecurityEmulationHostUrl: http://www.mydomain.com/mygame.unity3d 11 | m_DefaultBehaviorMode: 0 12 | m_SpritePackerMode: 2 13 | m_SpritePackerPaddingPower: 1 14 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd 15 | m_ProjectGenerationRootNamespace: 16 | -------------------------------------------------------------------------------- /client/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 9 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10782, guid: 0000000000000000f000000000000000, type: 0} 38 | m_PreloadedShaders: [] 39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 40 | type: 0} 41 | m_TierSettings_Tier1: 42 | renderingPath: 1 43 | useCascadedShadowMaps: 1 44 | m_TierSettings_Tier2: 45 | renderingPath: 1 46 | useCascadedShadowMaps: 1 47 | m_TierSettings_Tier3: 48 | renderingPath: 1 49 | useCascadedShadowMaps: 1 50 | m_DefaultRenderingPath: 1 51 | m_DefaultMobileRenderingPath: 1 52 | m_TierSettings: [] 53 | m_LightmapStripping: 0 54 | m_FogStripping: 0 55 | m_LightmapKeepPlain: 1 56 | m_LightmapKeepDirCombined: 1 57 | m_LightmapKeepDirSeparate: 1 58 | m_LightmapKeepDynamicPlain: 1 59 | m_LightmapKeepDynamicDirCombined: 1 60 | m_LightmapKeepDynamicDirSeparate: 1 61 | m_FogKeepLinear: 1 62 | m_FogKeepExp: 1 63 | m_FogKeepExp2: 1 64 | -------------------------------------------------------------------------------- /client/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshAreas: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | -------------------------------------------------------------------------------- /client/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /client/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_MinPenetrationForPenalty: 0.01 17 | m_BaumgarteScale: 0.2 18 | m_BaumgarteTimeOfImpactScale: 0.75 19 | m_TimeToSleep: 0.5 20 | m_LinearSleepTolerance: 0.01 21 | m_AngularSleepTolerance: 2 22 | m_QueriesHitTriggers: 1 23 | m_QueriesStartInColliders: 1 24 | m_ChangeStopsCallbacks: 0 25 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 26 | -------------------------------------------------------------------------------- /client/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /client/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | -------------------------------------------------------------------------------- /client/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | m_Enabled: 0 7 | m_TestMode: 0 8 | m_TestEventUrl: 9 | m_TestConfigUrl: 10 | CrashReportingSettings: 11 | m_EventUrl: https://perf-events.cloud.unity3d.com/api/events/crashes 12 | m_Enabled: 0 13 | m_CaptureEditorExceptions: 1 14 | UnityPurchasingSettings: 15 | m_Enabled: 0 16 | m_TestMode: 0 17 | UnityAnalyticsSettings: 18 | m_Enabled: 0 19 | m_InitializeOnStartup: 1 20 | m_TestMode: 0 21 | m_TestEventUrl: 22 | m_TestConfigUrl: 23 | UnityAdsSettings: 24 | m_Enabled: 0 25 | m_InitializeOnStartup: 1 26 | m_TestMode: 0 27 | m_EnabledPlatforms: 4294967295 28 | m_IosGameId: 29 | m_AndroidGameId: 30 | -------------------------------------------------------------------------------- /proto/GenerateProto.bat: -------------------------------------------------------------------------------- 1 | set CURR=%cd% 2 | cd tool 3 | call gen_sproto ^ 4 | ..\login.sp ^ 5 | ..\clientnet.sp 6 | 7 | cd %CURR% -------------------------------------------------------------------------------- /proto/clientnet.sp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | message PeerConnected { 5 | 6 | } 7 | 8 | 9 | message PeerDisconnected { 10 | 11 | } 12 | 13 | 14 | message PeerConnectError { 15 | 16 | } 17 | 18 | 19 | message PeerRecvError { 20 | 21 | } 22 | 23 | 24 | message PeerSendError { 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /proto/login.sp: -------------------------------------------------------------------------------- 1 | 2 | 3 | // client -> login 4 | message LoginREQ { 5 | 6 | PlatformToken string 7 | } 8 | 9 | // login -> client 10 | message LoginACK { 11 | 12 | Result int32 13 | 14 | Token string 15 | } 16 | 17 | -------------------------------------------------------------------------------- /proto/tool/Install.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davyxu/cellorigin/29ffec6fdb9c90ee816c0d0b255a4db0552e7c76/proto/tool/Install.bat -------------------------------------------------------------------------------- /proto/tool/gen_sproto.bat: -------------------------------------------------------------------------------- 1 | sprotogen.exe ^ 2 | --go_out=..\..\server\src\proto\msg_sp.go ^ 3 | --cs_out=..\..\client\Assets\Script\Proto\sp.cs ^ 4 | --package=proto ^ 5 | --cellnet_reg=true ^ 6 | %* 7 | 8 | @IF %ERRORLEVEL% NEQ 0 pause -------------------------------------------------------------------------------- /server/bat/InstallDebugAll.bat: -------------------------------------------------------------------------------- 1 | cd .. 2 | set GOPATH=%cd% 3 | go install -gcflags "-N -l" -v svcmod/login 4 | 5 | -------------------------------------------------------------------------------- /server/bat/StartGOPATH.bat: -------------------------------------------------------------------------------- 1 | cd .. 2 | set GOPATH=%cd% 3 | cmd -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | install: 4 | - go get -v github.com/davyxu/golog 5 | - go get -v github.com/davyxu/goobjfmt 6 | - go get -v github.com/davyxu/gosproto 7 | - go get -v github.com/golang/protobuf/proto 8 | - go get -v github.com/gorilla/websocket 9 | 10 | go: 11 | - 1.8 12 | 13 | script: 14 | - go test -v github.com/davyxu/cellnet/example/classicrecv 15 | - go test -v github.com/davyxu/cellnet/example/sendclose 16 | - go test -v github.com/davyxu/cellnet/example/echo_pb 17 | - go test -v github.com/davyxu/cellnet/example/echo_sproto 18 | - go test -v github.com/davyxu/cellnet/example/echo_websocket 19 | - go test -v github.com/davyxu/cellnet/example/gracefulexit 20 | - go test -v github.com/davyxu/cellnet/example/rpc 21 | - go test -v github.com/davyxu/cellnet/example/timer 22 | 23 | after_success: 24 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/CHANGES.md: -------------------------------------------------------------------------------- 1 | # V3版本(v3分支) 2 | ## 版本特性 3 | 4 | - 全面使用Handler处理封包接收,发送, 解析, 日志, RPC等结构 5 | 6 | - 新增编码器扩展, 支持混合编码器 7 | 8 | - 新增socket的各种属性设置, 超时处理等 9 | 10 | - 新的计时器api 11 | 12 | - 新增WebSocket支持 13 | 14 | - 底层采用性能更高的纯二进制协议进行错误及rpc消息传输 15 | 16 | 17 | ## 变化及修改 18 | 19 | - 底层去除Protobuf协议依赖(依然支持Protobuf) 20 | 21 | - 大幅降低底层内存分配, GC降低后, benchmark IOPS提升 22 | 23 | - 现在使用cellnet.RegisterMessage注册消息, 回调参数统一为*Event 24 | 25 | - 去除RPC包装, 解包封包的重复代码. 封包变小 26 | 27 | - 编码解码过程放到线程中处理, 提升性能 28 | 29 | 30 | 31 | 32 | # V2版本(v2分支) 33 | 34 | ## 版本特性 35 | 36 | - 实现单线程逻辑时, 全局只有1个EventQueue. 而不是一个Peer一个Queue 37 | 38 | - EventDispatcher处理回调 39 | 40 | - 处理DB, Timer等不依赖Dispatcher(Peer)逻辑时, 在Post时, Dispatcher可以指定nil, 通过data的函数得到异步返回 41 | 42 | - 去掉MongoDB支持 43 | 44 | 45 | ## 变化及修改 46 | 47 | - 去掉V1中的EventPipe 48 | 49 | - V1中的EventQueue被拆成EventDispatcher及新的EventQueue 50 | 51 | - 新的EventQueue实现了EventPipe的一部分功能 52 | 53 | - 调整EventQueue的Post命名及DelayPost的参数 54 | 55 | - 去掉PeerEvent支持 56 | 57 | - socket.RegisterEventMessage改为socket.RegisterMessage 58 | 59 | - 例子/测试用例使用sample文件夹命名 60 | 61 | # V1版本(v1分支) -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (C) 2017 davyxu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/RunAllTest.bat: -------------------------------------------------------------------------------- 1 | set CURRDIR=%cd% 2 | cd ../../../.. 3 | set GOPATH=%cd% 4 | 5 | go test github.com/davyxu/cellnet/example/classicrecv ^ 6 | github.com/davyxu/cellnet/example/sendclose ^ 7 | github.com/davyxu/cellnet/example/echo_pb ^ 8 | github.com/davyxu/cellnet/example/echo_sproto ^ 9 | github.com/davyxu/cellnet/example/echo_websocket ^ 10 | github.com/davyxu/cellnet/example/gracefulexit ^ 11 | github.com/davyxu/cellnet/example/rpc ^ 12 | github.com/davyxu/cellnet/example/timer 13 | 14 | 15 | cd %CURRDIR% -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/benchmark/Profile.bat: -------------------------------------------------------------------------------- 1 | set CURR_DIR=%cd% 2 | cd ../../../../.. 3 | set GOPATH=%cd% 4 | go test -v -run=^$ -bench=. -cpuprofile=cpu.pprof -memprofile=mem.pprof github.com/davyxu/cellnet/benchmark/io 5 | : 需要安装Graphviz 6 | set PATH==%PATH%;"c:\Program Files (x86)\Graphviz2.38\bin" 7 | go tool pprof --pdf io.test.exe cpu.pprof > cpu.pdf 8 | go tool pprof --pdf io.test.exe mem.pprof > mem.pdf 9 | cd %CURR_DIR% -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/benchmark/io/io_test.go: -------------------------------------------------------------------------------- 1 | package benchmark 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/benchmark" 9 | _ "github.com/davyxu/cellnet/codec/pb" // 启用pb编码 10 | "github.com/davyxu/cellnet/proto/pb/gamedef" 11 | "github.com/davyxu/cellnet/socket" 12 | "github.com/davyxu/cellnet/util" 13 | "github.com/davyxu/golog" 14 | ) 15 | 16 | var log *golog.Logger = golog.New("test") 17 | 18 | var signal *util.SignalTester 19 | 20 | // 测试地址 21 | const benchmarkAddress = "127.0.0.1:7201" 22 | 23 | // 客户端并发数量 24 | const clientCount = 100 25 | 26 | // 测试时间(秒) 27 | const benchmarkSeconds = 10 28 | 29 | func server() { 30 | 31 | queue := cellnet.NewEventQueue() 32 | qpsm := benchmark.NewQPSMeter(queue, func(qps int) { 33 | 34 | log.Infof("QPS: %d", qps) 35 | 36 | }) 37 | 38 | evd := socket.NewAcceptor(queue).Start(benchmarkAddress) 39 | 40 | cellnet.RegisterMessage(evd, "gamedef.TestEchoACK", func(ev *cellnet.Event) { 41 | 42 | if qpsm.Acc() > benchmarkSeconds { 43 | signal.Done(1) 44 | log.Infof("Average QPS: %d", qpsm.Average()) 45 | } 46 | 47 | ev.Send(&gamedef.TestEchoACK{}) 48 | 49 | }) 50 | 51 | queue.StartLoop() 52 | 53 | } 54 | 55 | func client() { 56 | 57 | queue := cellnet.NewEventQueue() 58 | 59 | evd := socket.NewConnector(queue).Start(benchmarkAddress) 60 | 61 | cellnet.RegisterMessage(evd, "gamedef.TestEchoACK", func(ev *cellnet.Event) { 62 | 63 | ev.Send(&gamedef.TestEchoACK{}) 64 | 65 | }) 66 | 67 | cellnet.RegisterMessage(evd, "coredef.SessionConnected", func(ev *cellnet.Event) { 68 | 69 | ev.Send(&gamedef.TestEchoACK{}) 70 | 71 | }) 72 | 73 | queue.StartLoop() 74 | 75 | } 76 | 77 | func TestIO(t *testing.T) { 78 | 79 | // 屏蔽socket层的调试日志 80 | golog.SetLevelByString("cellnet", "error") 81 | 82 | signal = util.NewSignalTester(t) 83 | 84 | // 超时时间为测试时间延迟一会 85 | signal.SetTimeout((benchmarkSeconds + 5) * time.Second) 86 | 87 | server() 88 | 89 | for i := 0; i < clientCount; i++ { 90 | go client() 91 | } 92 | 93 | signal.WaitAndExpect("recv time out", 1) 94 | 95 | } 96 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/benchmark/qpsmeter.go: -------------------------------------------------------------------------------- 1 | package benchmark 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/timer" 9 | ) 10 | 11 | type QPSMeter struct { 12 | qpsGuard sync.Mutex 13 | qps int 14 | total int 15 | 16 | count int 17 | } 18 | 19 | func (self *QPSMeter) Acc() int { 20 | self.qpsGuard.Lock() 21 | 22 | defer self.qpsGuard.Unlock() 23 | 24 | self.qps++ 25 | 26 | return self.count 27 | } 28 | 29 | // 一轮计算 30 | func (self *QPSMeter) Turn() (ret int) { 31 | self.qpsGuard.Lock() 32 | 33 | if self.qps > 0 { 34 | ret = self.qps 35 | } 36 | 37 | self.total += self.qps 38 | 39 | self.qps = 0 40 | self.count++ 41 | 42 | self.qpsGuard.Unlock() 43 | 44 | return 45 | } 46 | 47 | // 均值 48 | func (self *QPSMeter) Average() int { 49 | 50 | self.qpsGuard.Lock() 51 | 52 | defer self.qpsGuard.Unlock() 53 | 54 | if self.count == 0 { 55 | return 0 56 | } 57 | 58 | return self.total / self.count 59 | } 60 | 61 | func NewQPSMeter(q cellnet.EventQueue, callback func(int)) *QPSMeter { 62 | 63 | self := &QPSMeter{} 64 | 65 | timer.NewLoop(q, time.Second, func(ctx *timer.Loop) { 66 | 67 | qps := self.Turn() 68 | 69 | callback(qps) 70 | 71 | }, nil).Start() 72 | 73 | return self 74 | } 75 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/codec.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | type Codec interface { 4 | Encode(interface{}) ([]byte, error) 5 | 6 | Decode([]byte, interface{}) error 7 | 8 | Name() string 9 | } 10 | 11 | var codecByName = map[string]Codec{} 12 | 13 | func RegisterCodec(name string, c Codec) { 14 | 15 | if _, ok := codecByName[name]; ok { 16 | panic("duplicate codec: " + name) 17 | } 18 | 19 | //log.Infof("registere codec '%s'!", name) 20 | 21 | codecByName[name] = c 22 | } 23 | 24 | func FetchCodec(name string) Codec { 25 | if v, ok := codecByName[name]; ok { 26 | return v 27 | } 28 | 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/codec/binary/binary.go: -------------------------------------------------------------------------------- 1 | package binary 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "github.com/davyxu/goobjfmt" 6 | ) 7 | 8 | type binaryCodec struct { 9 | } 10 | 11 | func (self *binaryCodec) Name() string { 12 | return "binary" 13 | } 14 | 15 | func (self *binaryCodec) Encode(msgObj interface{}) ([]byte, error) { 16 | 17 | return goobjfmt.BinaryWrite(msgObj) 18 | 19 | } 20 | 21 | func (self *binaryCodec) Decode(data []byte, msgObj interface{}) error { 22 | 23 | return goobjfmt.BinaryRead(data, msgObj) 24 | } 25 | 26 | func init() { 27 | 28 | cellnet.RegisterCodec("binary", new(binaryCodec)) 29 | } 30 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/codec/json/json.go: -------------------------------------------------------------------------------- 1 | package json 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/davyxu/cellnet" 6 | ) 7 | 8 | type jsonCodec struct { 9 | } 10 | 11 | func (self *jsonCodec) Name() string { 12 | return "json" 13 | } 14 | 15 | func (self *jsonCodec) Encode(msgObj interface{}) ([]byte, error) { 16 | 17 | return json.Marshal(msgObj) 18 | 19 | } 20 | 21 | func (self *jsonCodec) Decode(data []byte, msgObj interface{}) error { 22 | 23 | return json.Unmarshal(data, msgObj) 24 | } 25 | 26 | func init() { 27 | 28 | cellnet.RegisterCodec("json", new(jsonCodec)) 29 | } 30 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/codec/pb/pb.go: -------------------------------------------------------------------------------- 1 | package pbcodec 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "github.com/golang/protobuf/proto" 6 | ) 7 | 8 | type pbCodec struct { 9 | } 10 | 11 | func (self *pbCodec) Name() string { 12 | return "pb" 13 | } 14 | 15 | func (self *pbCodec) Encode(msgObj interface{}) ([]byte, error) { 16 | 17 | msg := msgObj.(proto.Message) 18 | 19 | data, err := proto.Marshal(msg) 20 | 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | return data, nil 26 | } 27 | 28 | func (self *pbCodec) Decode(data []byte, msgObj interface{}) error { 29 | 30 | err := proto.Unmarshal(data, msgObj.(proto.Message)) 31 | 32 | if err != nil { 33 | return err 34 | } 35 | 36 | return nil 37 | } 38 | 39 | func init() { 40 | 41 | cellnet.RegisterCodec("pb", new(pbCodec)) 42 | } 43 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/codec/sproto/sproto.go: -------------------------------------------------------------------------------- 1 | package sprotocodec 2 | 3 | import ( 4 | "fmt" 5 | "path" 6 | "reflect" 7 | 8 | "github.com/davyxu/cellnet" 9 | "github.com/davyxu/cellnet/util" 10 | "github.com/davyxu/gosproto" 11 | ) 12 | 13 | type sprotoCodec struct { 14 | } 15 | 16 | func (self *sprotoCodec) Name() string { 17 | return "sproto" 18 | } 19 | 20 | func (self *sprotoCodec) Encode(msgObj interface{}) ([]byte, error) { 21 | 22 | data, err := sproto.Encode(msgObj) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | return sproto.Pack(data), nil 28 | } 29 | 30 | func (self *sprotoCodec) Decode(data []byte, msgObj interface{}) error { 31 | 32 | // sproto要求必须有头, 但空包也是可以的 33 | if len(data) == 0 { 34 | return nil 35 | } 36 | 37 | raw, err := sproto.Unpack(data) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | _, err2 := sproto.Decode(raw, msgObj) 43 | 44 | return err2 45 | } 46 | 47 | func AutoRegisterMessageMeta(msgTypes []reflect.Type) { 48 | 49 | for _, tp := range msgTypes { 50 | 51 | msgName := fmt.Sprintf("%s.%s", path.Base(tp.PkgPath()), tp.Name()) 52 | 53 | cellnet.RegisterMessageMeta("sproto", msgName, tp, util.StringHash(msgName)) 54 | } 55 | 56 | } 57 | 58 | func init() { 59 | 60 | cellnet.RegisterCodec("sproto", new(sprotoCodec)) 61 | } 62 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/doc/handler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davyxu/cellorigin/29ffec6fdb9c90ee816c0d0b255a4db0552e7c76/server/src/github.com/davyxu/cellnet/doc/handler.png -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/example/echo_sproto/echo_sproto_test.go: -------------------------------------------------------------------------------- 1 | package echosproto 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/davyxu/cellnet" 7 | "github.com/davyxu/cellnet/proto/binary/coredef" 8 | "github.com/davyxu/cellnet/proto/sproto/gamedef" 9 | "github.com/davyxu/cellnet/socket" 10 | "github.com/davyxu/cellnet/util" 11 | "github.com/davyxu/golog" 12 | ) 13 | 14 | var log *golog.Logger = golog.New("test") 15 | 16 | var signal *util.SignalTester 17 | 18 | func server() { 19 | 20 | queue := cellnet.NewEventQueue() 21 | 22 | p := socket.NewAcceptor(queue).Start("127.0.0.1:7401") 23 | p.SetName("server") 24 | 25 | cellnet.RegisterMessage(p, "gamedef.TestEchoACK", func(ev *cellnet.Event) { 26 | msg := ev.Msg.(*gamedef.TestEchoACK) 27 | 28 | log.Debugln("server recv:", msg.Content) 29 | 30 | ev.Send(&gamedef.TestEchoACK{ 31 | Content: msg.Content, 32 | }) 33 | 34 | }) 35 | 36 | queue.StartLoop() 37 | 38 | } 39 | 40 | func client() { 41 | 42 | queue := cellnet.NewEventQueue() 43 | 44 | p := socket.NewConnector(queue).Start("127.0.0.1:7401") 45 | p.SetName("client") 46 | 47 | cellnet.RegisterMessage(p, "gamedef.TestEchoACK", func(ev *cellnet.Event) { 48 | msg := ev.Msg.(*gamedef.TestEchoACK) 49 | 50 | log.Debugln("client recv:", msg.Content) 51 | 52 | signal.Done(1) 53 | }) 54 | 55 | cellnet.RegisterMessage(p, "coredef.SessionConnected", func(ev *cellnet.Event) { 56 | 57 | log.Debugln("client connected") 58 | 59 | ev.Send(&gamedef.TestEchoACK{ 60 | Content: "hello", 61 | }) 62 | 63 | }) 64 | 65 | cellnet.RegisterMessage(p, "coredef.SessionConnectFailed", func(ev *cellnet.Event) { 66 | 67 | msg := ev.Msg.(*coredef.SessionConnectFailed) 68 | 69 | log.Debugln(msg.Result) 70 | 71 | }) 72 | 73 | queue.StartLoop() 74 | 75 | signal.WaitAndExpect("not recv data", 1) 76 | 77 | } 78 | 79 | func TestSprotoEcho(t *testing.T) { 80 | 81 | signal = util.NewSignalTester(t) 82 | 83 | server() 84 | 85 | client() 86 | 87 | } 88 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/example/echo_websocket/echo_websocket_test.go: -------------------------------------------------------------------------------- 1 | package echowebsocket 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | jsongamedef "github.com/davyxu/cellnet/proto/json/gamedef" // json逻辑协议 6 | "github.com/davyxu/cellnet/util" 7 | "github.com/davyxu/cellnet/websocket" 8 | "github.com/davyxu/golog" 9 | "testing" 10 | ) 11 | 12 | var log *golog.Logger = golog.New("test") 13 | 14 | var signal *util.SignalTester 15 | 16 | func server() { 17 | 18 | queue := cellnet.NewEventQueue() 19 | 20 | // 注意, 如果http代理/VPN在运行时可能会导致无法连接, 请关闭 21 | 22 | p := websocket.NewAcceptor(queue).Start("http://127.0.0.1:8801/echo") 23 | p.SetName("server") 24 | 25 | cellnet.RegisterMessage(p, "coredef.SessionAccepted", func(ev *cellnet.Event) { 26 | 27 | log.Debugln("client accepted") 28 | }) 29 | 30 | cellnet.RegisterMessage(p, "gamedef.TestEchoJsonACK", func(ev *cellnet.Event) { 31 | 32 | msg := ev.Msg.(*jsongamedef.TestEchoJsonACK) 33 | 34 | log.Debugln(msg.Content) 35 | 36 | ev.Send(&jsongamedef.TestEchoJsonACK{Content: "roger"}) 37 | }) 38 | 39 | queue.StartLoop() 40 | } 41 | 42 | func client() { 43 | 44 | queue := cellnet.NewEventQueue() 45 | 46 | p := websocket.NewConnector(queue).Start("ws://127.0.0.1:8801/echo") 47 | p.SetName("client") 48 | 49 | cellnet.RegisterMessage(p, "coredef.SessionConnected", func(ev *cellnet.Event) { 50 | 51 | log.Debugln("client connected") 52 | 53 | // 发送消息, 底层自动选择pb编码 54 | ev.Send(&jsongamedef.TestEchoJsonACK{ 55 | Content: "hello", 56 | }) 57 | 58 | signal.Done(1) 59 | 60 | }) 61 | 62 | cellnet.RegisterMessage(p, "gamedef.TestEchoJsonACK", func(ev *cellnet.Event) { 63 | msg := ev.Msg.(*jsongamedef.TestEchoJsonACK) 64 | 65 | log.Debugln("client recv:", msg.Content) 66 | 67 | signal.Done(2) 68 | }) 69 | 70 | queue.StartLoop() 71 | 72 | signal.WaitAndExpect("not recv data", 1, 2) 73 | 74 | } 75 | 76 | func TestWebsocketEcho(t *testing.T) { 77 | 78 | signal = util.NewSignalTester(t) 79 | 80 | server() 81 | 82 | client() 83 | 84 | } 85 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/example/echo_websocket/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 30 | 31 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/example/gracefulexit/acceptor_test.go: -------------------------------------------------------------------------------- 1 | package gracefulexit 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "github.com/davyxu/cellnet/socket" 6 | "github.com/davyxu/golog" 7 | "sync" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | var log *golog.Logger = golog.New("test") 13 | 14 | const clientConnectionCount = 3 15 | 16 | func TestCreateDestroyAcceptor(t *testing.T) { 17 | queue := cellnet.NewEventQueue() 18 | 19 | p := socket.NewAcceptor(queue).Start("127.0.0.1:7701") 20 | p.SetName("server") 21 | 22 | var allAccepted sync.WaitGroup 23 | cellnet.RegisterMessage(p, "coredef.SessionAccepted", func(ev *cellnet.Event) { 24 | 25 | allAccepted.Done() 26 | }) 27 | 28 | queue.StartLoop() 29 | 30 | log.Debugln("Start connecting...") 31 | allAccepted.Add(clientConnectionCount) 32 | runMultiConnection() 33 | 34 | log.Debugln("Wait all accept...") 35 | allAccepted.Wait() 36 | 37 | log.Debugln("Close acceptor...") 38 | p.Stop() 39 | 40 | // 确认所有连接已经断开 41 | time.Sleep(time.Second) 42 | 43 | log.Debugln("Session count:", p.SessionCount()) 44 | 45 | p.Start(p.Address()) 46 | log.Debugln("Start connecting...") 47 | allAccepted.Add(clientConnectionCount) 48 | runMultiConnection() 49 | 50 | log.Debugln("Wait all accept...") 51 | allAccepted.Wait() 52 | 53 | log.Debugln("All done") 54 | } 55 | 56 | func runMultiConnection() { 57 | 58 | for i := 0; i < clientConnectionCount; i++ { 59 | 60 | p := socket.NewConnector(nil).Start("127.0.0.1:7701") 61 | p.SetName("client.MultiConn") 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/example/gracefulexit/connector_test.go: -------------------------------------------------------------------------------- 1 | package gracefulexit 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/davyxu/cellnet" 7 | _ "github.com/davyxu/cellnet/codec/pb" // 启用pb编码 8 | "github.com/davyxu/cellnet/proto/pb/gamedef" 9 | "github.com/davyxu/cellnet/socket" 10 | "github.com/davyxu/cellnet/util" 11 | "time" 12 | ) 13 | 14 | var singalConnector *util.SignalTester 15 | 16 | func runEchoServer() { 17 | queue := cellnet.NewEventQueue() 18 | 19 | p := socket.NewAcceptor(queue).Start("127.0.0.1:7201") 20 | p.SetName("server") 21 | 22 | cellnet.RegisterMessage(p, "gamedef.TestEchoACK", func(ev *cellnet.Event) { 23 | msg := ev.Msg.(*gamedef.TestEchoACK) 24 | 25 | // 发包后关闭 26 | ev.Send(&gamedef.TestEchoACK{ 27 | Content: msg.Content, 28 | }) 29 | 30 | }) 31 | 32 | queue.StartLoop() 33 | 34 | } 35 | 36 | // 客户端连接上后, 主动断开连接, 确保连接正常关闭 37 | func runConnClose() { 38 | 39 | queue := cellnet.NewEventQueue() 40 | 41 | p := socket.NewConnector(queue).Start("127.0.0.1:7201") 42 | p.SetName("client.ConnClose") 43 | 44 | var times int 45 | 46 | cellnet.RegisterMessage(p, "coredef.SessionConnected", func(ev *cellnet.Event) { 47 | 48 | p.Stop() 49 | 50 | time.Sleep(time.Millisecond * 500) 51 | 52 | if times < 3 { 53 | p.Start(p.Address()) 54 | times++ 55 | } else { 56 | singalConnector.Done(1) 57 | } 58 | 59 | }) 60 | 61 | queue.StartLoop() 62 | 63 | singalConnector.WaitAndExpect("not expect times", 1) 64 | 65 | p.Stop() 66 | } 67 | 68 | func TestCreateDestroyConnector(t *testing.T) { 69 | 70 | singalConnector = util.NewSignalTester(t) 71 | singalConnector.SetTimeout(time.Second * 3) 72 | 73 | runEchoServer() 74 | 75 | runConnClose() 76 | } 77 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/example/timer/timer_test.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/timer" 9 | "github.com/davyxu/cellnet/util" 10 | "github.com/davyxu/golog" 11 | ) 12 | 13 | var log *golog.Logger = golog.New("test") 14 | 15 | func TestAfterTimer(t *testing.T) { 16 | 17 | signal := util.NewSignalTester(t) 18 | 19 | queue := cellnet.NewEventQueue() 20 | 21 | queue.StartLoop() 22 | 23 | timer.After(queue, 500*time.Millisecond, func() { 24 | log.Debugln("after 100 ms") 25 | 26 | signal.Done(1) 27 | }) 28 | 29 | timer.After(queue, 800*time.Millisecond, func() { 30 | log.Debugln("after 200 ms") 31 | 32 | signal.Done(2) 33 | }) 34 | 35 | signal.WaitAndExpect("1 sec after not done", 1) 36 | 37 | signal.WaitAndExpect("2 sec after not done", 2) 38 | } 39 | 40 | func TestLoopTimer(t *testing.T) { 41 | 42 | signal := util.NewSignalTester(t) 43 | signal.SetTimeout(60 * time.Second) 44 | 45 | queue := cellnet.NewEventQueue() 46 | 47 | // 启动消息循环 48 | queue.StartLoop() 49 | 50 | var count int 51 | 52 | // 启动计时循环 53 | timer.NewLoop(queue, time.Millisecond*100, func(ctx *timer.Loop) { 54 | 55 | log.Debugln("tick 100 ms", count) 56 | 57 | count++ 58 | 59 | if count >= 10 { 60 | signal.Done(1) 61 | ctx.Stop() 62 | } 63 | }, nil).Start() 64 | 65 | signal.WaitAndExpect("100ms * 10 times ticker not done", 1) 66 | } 67 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/extend/sysevent.go: -------------------------------------------------------------------------------- 1 | package extend 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "github.com/davyxu/cellnet/proto/binary/coredef" 6 | ) 7 | 8 | var ( 9 | metaSessionConnected = cellnet.MessageMetaByName("coredef.SessionConnected") 10 | metaSessionAccepted = cellnet.MessageMetaByName("coredef.SessionAccepted") 11 | ) 12 | 13 | func PostSystemEvent(ses cellnet.Session, t cellnet.EventType, chain cellnet.HandlerChainList, r cellnet.Result) { 14 | 15 | ev := cellnet.NewEvent(t, ses) 16 | 17 | // 直接放在这里, decoder里遇到系统事件不会进行decode操作 18 | switch t { 19 | case cellnet.Event_Closed: 20 | ev.FromMessage(&coredef.SessionClosed{Result: r}) 21 | case cellnet.Event_AcceptFailed: 22 | ev.FromMessage(&coredef.SessionAcceptFailed{Result: r}) 23 | case cellnet.Event_ConnectFailed: 24 | ev.FromMessage(&coredef.SessionConnectFailed{Result: r}) 25 | case cellnet.Event_Accepted: 26 | ev.MsgID = metaSessionAccepted.ID 27 | case cellnet.Event_Connected: 28 | ev.MsgID = metaSessionConnected.ID 29 | default: 30 | panic("unknown system error") 31 | } 32 | 33 | cellnet.MsgLog(ev) 34 | 35 | chain.Call(ev) 36 | } 37 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type EventHandler interface { 9 | Call(*Event) 10 | } 11 | 12 | var EnableHandlerLog bool 13 | 14 | // 显示handler的名称 15 | func HandlerName(h EventHandler) string { 16 | if h == nil { 17 | return "nil" 18 | } 19 | 20 | return reflect.TypeOf(h).Elem().Name() 21 | } 22 | 23 | func HandlerString(h EventHandler) string { 24 | 25 | if sg, ok := h.(fmt.Stringer); ok { 26 | return sg.String() 27 | } else { 28 | return HandlerName(h) 29 | } 30 | } 31 | 32 | func HandlerLog(h EventHandler, ev *Event) { 33 | 34 | if EnableHandlerLog { 35 | log.Debugf("evid: %d #%s [%s] chain: %d <%s> SesID: %d Result: %d MsgID: %d(%s) {%s} Tag: %v TransmitTag: %v Raw: (%d)%v", 36 | ev.UID, 37 | ev.Type.String(), 38 | ev.PeerName(), 39 | ev.chainid, 40 | HandlerString(h), 41 | ev.SessionID(), 42 | ev.Result(), 43 | ev.MsgID, 44 | ev.MsgName(), 45 | ev.MsgString(), 46 | ev.Tag, 47 | ev.TransmitTag, 48 | ev.MsgSize(), 49 | ev.Data, 50 | ) 51 | } 52 | } 53 | 54 | func HandlerChainCall(hlist []EventHandler, ev *Event) { 55 | 56 | for _, h := range hlist { 57 | 58 | HandlerLog(h, ev) 59 | 60 | h.Call(ev) 61 | 62 | if ev.Result() != Result_OK { 63 | break 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler_callback.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type CallbackHandler struct { 8 | userCallback func(*Event) 9 | } 10 | 11 | func (self *CallbackHandler) Call(ev *Event) { 12 | 13 | self.userCallback(ev) 14 | 15 | } 16 | 17 | func NewCallbackHandler(userCallback func(*Event)) EventHandler { 18 | 19 | return &CallbackHandler{ 20 | userCallback: userCallback, 21 | } 22 | } 23 | 24 | type RegisterMessageContext struct { 25 | *MessageMeta 26 | } 27 | 28 | // 注册消息处理回调 29 | func RegisterMessage(p Peer, msgName string, userCallback func(*Event)) *RegisterMessageContext { 30 | 31 | return RegisterHandler(p, msgName, NewCallbackHandler(userCallback)) 32 | } 33 | 34 | // 注册消息处理的一系列Handler, 当有队列时, 投放到队列 35 | func RegisterHandler(p Peer, msgName string, handlers ...EventHandler) *RegisterMessageContext { 36 | 37 | if p == nil { 38 | return nil 39 | } 40 | 41 | meta := MessageMetaByName(msgName) 42 | 43 | if meta == nil { 44 | panic(fmt.Sprintf("message register failed, name not found: %s", msgName)) 45 | } 46 | 47 | if p.Queue() != nil { 48 | 49 | p.AddChainRecv(NewHandlerChain( 50 | NewMatchMsgIDHandler(meta.ID), 51 | StaticDecodePacketHandler(), 52 | NewQueuePostHandler(p.Queue(), handlers...), 53 | )) 54 | } else { 55 | 56 | p.AddChainRecv(NewHandlerChain( 57 | NewMatchMsgIDHandler(meta.ID), 58 | StaticDecodePacketHandler(), 59 | handlers, 60 | )) 61 | } 62 | 63 | return &RegisterMessageContext{MessageMeta: meta} 64 | } 65 | 66 | // 直接注册回调 67 | func RegisterRawHandler(p Peer, msgName string, handlers ...EventHandler) *RegisterMessageContext { 68 | 69 | if p == nil { 70 | return nil 71 | } 72 | 73 | meta := MessageMetaByName(msgName) 74 | 75 | if meta == nil { 76 | panic(fmt.Sprintf("message register failed, %s", msgName)) 77 | } 78 | 79 | p.AddChainRecv(NewHandlerChain( 80 | NewMatchMsgIDHandler(meta.ID), 81 | StaticDecodePacketHandler(), 82 | handlers, 83 | )) 84 | 85 | return &RegisterMessageContext{MessageMeta: meta} 86 | } 87 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler_decode.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | ) 7 | 8 | type DecodePacketHandler struct { 9 | } 10 | 11 | func (self *DecodePacketHandler) Call(ev *Event) { 12 | 13 | var err error 14 | ev.Msg, err = DecodeMessage(ev.MsgID, ev.Data) 15 | 16 | r := errToResult(err) 17 | if r != Result_OK { 18 | ev.Msg, _ = DecodeMessage(ev.MsgID, ev.Data) 19 | 20 | ev.SetResult(r) 21 | } 22 | 23 | } 24 | 25 | var defaultDecodePacketHandler = new(DecodePacketHandler) 26 | 27 | func StaticDecodePacketHandler() EventHandler { 28 | return defaultDecodePacketHandler 29 | } 30 | 31 | var ErrCodecNotFound = errors.New("codec not found") 32 | 33 | func DecodeMessage(msgid uint32, data []byte) (interface{}, error) { 34 | meta := MessageMetaByID(msgid) 35 | 36 | if meta == nil { 37 | return nil, ErrMessageNotFound 38 | } 39 | if meta.Codec == nil { 40 | return nil, ErrCodecNotFound 41 | } 42 | 43 | // 创建消息 44 | msg := reflect.New(meta.Type).Interface() 45 | 46 | // 解析消息 47 | err := meta.Codec.Decode(data, msg) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | return msg, nil 53 | } 54 | 55 | func errToResult(err error) Result { 56 | 57 | if err == nil { 58 | return Result_OK 59 | } 60 | 61 | return Result_CodecError 62 | } 63 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler_encode.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import "reflect" 4 | 5 | type EncodePacketHandler struct { 6 | } 7 | 8 | func (self *EncodePacketHandler) Call(ev *Event) { 9 | 10 | var err error 11 | ev.Data, ev.MsgID, err = EncodeMessage(ev.Msg) 12 | 13 | r := errToResult(err) 14 | if r != Result_OK { 15 | ev.SetResult(r) 16 | } 17 | } 18 | 19 | var defaultEncodePacketHandler EventHandler = new(EncodePacketHandler) 20 | 21 | func StaticEncodePacketHandler() EventHandler { 22 | return defaultEncodePacketHandler 23 | } 24 | 25 | func EncodeMessage(msg interface{}) (data []byte, msgid uint32, err error) { 26 | 27 | meta := MessageMetaByType(reflect.TypeOf(msg)) 28 | if meta != nil { 29 | msgid = meta.ID 30 | } else { 31 | return nil, 0, ErrMessageNotFound 32 | } 33 | 34 | if meta.Codec == nil { 35 | return nil, 0, ErrCodecNotFound 36 | } 37 | 38 | data, err = meta.Codec.Encode(msg) 39 | 40 | return data, msgid, err 41 | } 42 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler_fixedlenframe.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "io" 5 | "sync" 6 | ) 7 | 8 | type FixedLengthFrameReader struct { 9 | headerBuffer []byte 10 | } 11 | 12 | func (self *FixedLengthFrameReader) Call(ev *Event) { 13 | 14 | reader := ev.Ses.(interface { 15 | DataSource() io.ReadWriter 16 | }).DataSource() 17 | 18 | _, err := io.ReadFull(reader, self.headerBuffer) 19 | 20 | if err != nil { 21 | ev.SetResult(Result_SocketError) 22 | return 23 | } 24 | 25 | ev.Data = self.headerBuffer 26 | } 27 | 28 | func NewFixedLengthFrameReader(size int) EventHandler { 29 | return &FixedLengthFrameReader{ 30 | headerBuffer: make([]byte, size), 31 | } 32 | } 33 | 34 | type FixedLengthFrameWriter struct { 35 | sendser uint16 36 | sendtagGuard sync.RWMutex 37 | } 38 | 39 | func (self *FixedLengthFrameWriter) Call(ev *Event) { 40 | 41 | writer := ev.Ses.(interface { 42 | DataSource() io.ReadWriter 43 | }).DataSource() 44 | 45 | err := writeFull(writer, ev.Data) 46 | 47 | if err != nil { 48 | ev.SetResult(Result_PackageCrack) 49 | return 50 | } 51 | 52 | } 53 | 54 | // 完整发送所有封包 55 | func writeFull(writer io.ReadWriter, p []byte) error { 56 | 57 | sizeToWrite := len(p) 58 | 59 | for { 60 | 61 | n, err := writer.Write(p) 62 | 63 | if err != nil { 64 | return err 65 | } 66 | 67 | if n >= sizeToWrite { 68 | break 69 | } 70 | 71 | copy(p[0:sizeToWrite-n], p[n:sizeToWrite]) 72 | sizeToWrite -= n 73 | } 74 | 75 | return nil 76 | 77 | } 78 | 79 | func NewFixedLengthFrameWriter() EventHandler { 80 | return &FixedLengthFrameWriter{} 81 | } 82 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler_matchmsgid.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import "fmt" 4 | 5 | type MatchMsgIDHandler struct { 6 | msgid uint32 7 | } 8 | 9 | func (self *MatchMsgIDHandler) String() string { 10 | return fmt.Sprintf("MatchMsgIDHandler(msgid:%d %s)", self.msgid, MessageNameByID(self.msgid)) 11 | } 12 | 13 | func (self *MatchMsgIDHandler) Call(ev *Event) { 14 | 15 | if ev.MsgID != self.msgid { 16 | ev.SetResult(Result_NextChain) 17 | } 18 | 19 | } 20 | 21 | func NewMatchMsgIDHandler(msgid uint32) EventHandler { 22 | return &MatchMsgIDHandler{ 23 | msgid: msgid, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler_msglog.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | ) 7 | 8 | type MsgLogHandler struct { 9 | } 10 | 11 | func (self *MsgLogHandler) Call(ev *Event) { 12 | 13 | MsgLog(ev) 14 | } 15 | 16 | var defaultmsgLogHandler = new(MsgLogHandler) 17 | 18 | func StaticMsgLogHandler() EventHandler { 19 | return defaultmsgLogHandler 20 | } 21 | 22 | // Msg 23 | // Data, MsgID 24 | 25 | func MsgLog(ev *Event) { 26 | 27 | if !log.IsDebugEnabled() { 28 | return 29 | } 30 | 31 | ev.Parse() 32 | 33 | if IsBlockedMessageByID(ev.MsgID) { 34 | return 35 | } 36 | 37 | // 需要在收到消息, 不经过decoder时, 就要打印出来, 所以手动解开消息, 有少许耗费 38 | 39 | log.Debugf("#%s(%s) sid: %d %s(%d) size: %d | %s", ev.Type.String(), ev.PeerName(), ev.SessionID(), ev.MsgName(), ev.MsgID, ev.MsgSize(), ev.MsgString()) 40 | 41 | } 42 | 43 | var ( 44 | msgMetaByID = map[uint32]*MessageMeta{} 45 | msgMetaByIDGuard sync.RWMutex 46 | ) 47 | 48 | func IsBlockedMessageByID(msgid uint32) bool { 49 | msgMetaByIDGuard.RLock() 50 | defer msgMetaByIDGuard.RUnlock() 51 | 52 | if _, ok := msgMetaByID[msgid]; ok { 53 | return true 54 | } 55 | 56 | return false 57 | } 58 | 59 | var ( 60 | ErrMessageNotFound = errors.New("msg not exists") 61 | ) 62 | 63 | func BlockMessageLog(msgName string) error { 64 | meta := MessageMetaByName(msgName) 65 | 66 | if meta == nil { 67 | return ErrMessageNotFound 68 | } 69 | 70 | msgMetaByIDGuard.Lock() 71 | msgMetaByID[meta.ID] = meta 72 | msgMetaByIDGuard.Unlock() 73 | 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/handler_queuepost.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | type QueuePostHandler struct { 4 | q EventQueue 5 | hlist []EventHandler 6 | } 7 | 8 | func (self *QueuePostHandler) Call(ev *Event) { 9 | 10 | self.q.Post(func() { 11 | HandlerChainCall(self.hlist, ev) 12 | }) 13 | 14 | } 15 | 16 | func NewQueuePostHandler(q EventQueue, hlist ...EventHandler) EventHandler { 17 | 18 | return &QueuePostHandler{ 19 | q: q, 20 | hlist: hlist, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/log.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log *golog.Logger = golog.New("cellnet") 8 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/objprotogen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "go/parser" 7 | "go/token" 8 | "os" 9 | ) 10 | 11 | var paramOut = flag.String("out", "", "output file name") 12 | 13 | func main() { 14 | 15 | flag.Parse() 16 | 17 | files := flag.Args() 18 | if len(files) == 0 { 19 | fmt.Println("Require go source file list") 20 | os.Exit(1) 21 | } 22 | 23 | fs := token.NewFileSet() 24 | 25 | p := &Package{} 26 | 27 | for _, filename := range files { 28 | 29 | file, err := parser.ParseFile(fs, filename, nil, parser.ParseComments) 30 | 31 | if err != nil { 32 | fmt.Println(err) 33 | os.Exit(1) 34 | } 35 | 36 | err = p.Parse(file) 37 | if err != nil { 38 | fmt.Println(err) 39 | os.Exit(1) 40 | } 41 | } 42 | 43 | genCode(*paramOut, p) 44 | 45 | } 46 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/objprotogen/model.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/davyxu/cellnet/util" 5 | "go/ast" 6 | ) 7 | 8 | type Package struct { 9 | PackageName string 10 | 11 | Structs []*Struct 12 | } 13 | 14 | func (self *Package) Parse(fileNode *ast.File) error { 15 | 16 | self.PackageName = fileNode.Name.Name 17 | 18 | ast.Inspect(fileNode, func(n ast.Node) bool { 19 | 20 | switch typeSpec := n.(type) { 21 | case *ast.TypeSpec: 22 | 23 | switch typeSpecType := typeSpec.Type.(type) { 24 | case *ast.StructType: 25 | 26 | st := &Struct{ 27 | Name: typeSpec.Name.Name, 28 | } 29 | 30 | st.Parse(typeSpecType) 31 | 32 | self.Structs = append(self.Structs, st) 33 | } 34 | } 35 | 36 | return true 37 | }) 38 | 39 | return nil 40 | } 41 | 42 | func newFile() *Package { 43 | return &Package{} 44 | } 45 | 46 | type Struct struct { 47 | Name string 48 | 49 | Fields []*Field 50 | } 51 | 52 | func (self *Struct) MsgID() uint32 { 53 | return util.StringHash(self.Name) 54 | } 55 | 56 | func (self *Struct) Parse(n *ast.StructType) { 57 | 58 | for _, fd := range n.Fields.List { 59 | 60 | f := &Field{} 61 | f.Parse(fd) 62 | 63 | self.Fields = append(self.Fields, f) 64 | } 65 | } 66 | 67 | type Field struct { 68 | Name string 69 | Type string 70 | } 71 | 72 | func (self *Field) Parse(n *ast.Field) { 73 | 74 | self.Name = n.Names[0].Name 75 | 76 | switch x := n.Type.(type) { 77 | case *ast.Ident: 78 | self.Type = x.Name 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/objprotogen/printer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const codeTemplate = `// Generated by github.com/davyxu/cellnet/objprotogen 4 | // DO NOT EDIT! 5 | package {{.PackageName}} 6 | 7 | {{if gt (.Structs|len) 0}} 8 | import ( 9 | "github.com/davyxu/cellnet" 10 | "github.com/davyxu/goobjfmt" 11 | "reflect" 12 | ) 13 | {{end}} 14 | 15 | {{range .Structs}} 16 | func (self *{{.Name}}) String() string { return goobjfmt.CompactTextString(self) } {{end}} 17 | 18 | func init() { 19 | {{range .Structs}} 20 | cellnet.RegisterMessageMeta("binary","{{$.PackageName}}.{{.Name}}", reflect.TypeOf((*{{.Name}})(nil)).Elem(), {{.MsgID}}) {{end}} 21 | } 22 | 23 | ` 24 | 25 | func genCode(output string, f *Package) { 26 | 27 | generateCode("objprotogen", codeTemplate, output, f, &generateOption{formatGoCode: true}) 28 | } 29 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/objprotogen/util.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/parser" 7 | "go/printer" 8 | "go/token" 9 | "io/ioutil" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | "text/template" 14 | ) 15 | 16 | type generateOption struct { 17 | formatGoCode bool 18 | 19 | outputData []byte 20 | } 21 | 22 | // 字段首字母大写 23 | func publicFieldName(name string) string { 24 | return strings.ToUpper(string(name[0])) + name[1:] 25 | } 26 | 27 | func generateCode(templateName, templateStr, output string, model interface{}, opt *generateOption) { 28 | 29 | var err error 30 | 31 | if opt == nil { 32 | opt = &generateOption{} 33 | } 34 | 35 | var bf bytes.Buffer 36 | 37 | tpl, err := template.New(templateName).Parse(templateStr) 38 | if err != nil { 39 | goto OnError 40 | } 41 | 42 | err = tpl.Execute(&bf, model) 43 | if err != nil { 44 | goto OnError 45 | } 46 | 47 | if opt.formatGoCode { 48 | if err = formatCode(&bf); err != nil { 49 | fmt.Println("format golang code err", err) 50 | } 51 | } 52 | 53 | opt.outputData = bf.Bytes() 54 | 55 | if output != "" { 56 | 57 | os.MkdirAll(filepath.Dir(output), 666) 58 | 59 | err = ioutil.WriteFile(output, bf.Bytes(), 0666) 60 | 61 | if err != nil { 62 | goto OnError 63 | } 64 | } 65 | return 66 | 67 | OnError: 68 | fmt.Println(err) 69 | os.Exit(1) 70 | } 71 | 72 | func formatCode(bf *bytes.Buffer) error { 73 | 74 | fset := token.NewFileSet() 75 | 76 | ast, err := parser.ParseFile(fset, "", bf, parser.ParseComments) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | bf.Reset() 82 | 83 | err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(bf, fset, ast) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | return nil 89 | } 90 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/peer.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | // 会话 4 | type Session interface { 5 | 6 | // 发包 7 | Send(interface{}) 8 | 9 | // 直接发送封包 10 | RawSend(*Event) 11 | 12 | // 断开 13 | Close() 14 | 15 | // 标示ID 16 | ID() int64 17 | 18 | // 归属端 19 | FromPeer() Peer 20 | 21 | SetTag(tag interface{}) 22 | 23 | Tag() interface{} 24 | } 25 | 26 | // 端, Connector或Acceptor 27 | type Peer interface { 28 | 29 | // 开启/关闭 30 | Start(address string) Peer 31 | 32 | Stop() 33 | 34 | Queue() EventQueue 35 | 36 | // 基础信息 37 | PeerProfile 38 | 39 | // 定制处理链 40 | HandlerChainManager 41 | 42 | // 会话管理 43 | SessionAccessor 44 | } 45 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/peerprofile.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type PeerProfile interface { 8 | // 名字 9 | SetName(string) 10 | Name() string 11 | 12 | // 地址 13 | SetAddress(string) 14 | Address() string 15 | 16 | // Tag 17 | SetTag(interface{}) 18 | Tag() interface{} 19 | } 20 | 21 | // Peer间的共享数据 22 | type PeerProfileImplement struct { 23 | // 基本信息 24 | name string 25 | address string 26 | tag interface{} 27 | 28 | // 运行状态 29 | running bool 30 | runningGuard sync.RWMutex 31 | } 32 | 33 | func (self *PeerProfileImplement) IsRunning() bool { 34 | 35 | self.runningGuard.RLock() 36 | defer self.runningGuard.RUnlock() 37 | 38 | return self.running 39 | } 40 | 41 | func (self *PeerProfileImplement) SetRunning(v bool) { 42 | self.runningGuard.Lock() 43 | self.running = v 44 | self.runningGuard.Unlock() 45 | } 46 | 47 | func (self *PeerProfileImplement) NameOrAddress() string { 48 | if self.name != "" { 49 | return self.name 50 | } 51 | 52 | return self.address 53 | } 54 | 55 | func (self *PeerProfileImplement) Tag() interface{} { 56 | return self.tag 57 | } 58 | 59 | func (self *PeerProfileImplement) SetTag(tag interface{}) { 60 | self.tag = tag 61 | } 62 | 63 | func (self *PeerProfileImplement) Address() string { 64 | return self.address 65 | } 66 | 67 | func (self *PeerProfileImplement) SetAddress(address string) { 68 | self.address = address 69 | } 70 | 71 | func (self *PeerProfileImplement) SetName(name string) { 72 | self.name = name 73 | } 74 | 75 | func (self *PeerProfileImplement) Name() string { 76 | return self.name 77 | } 78 | 79 | func NewPeerProfile() *PeerProfileImplement { 80 | 81 | return &PeerProfileImplement{} 82 | } 83 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/GenerateProto.bat: -------------------------------------------------------------------------------- 1 | cd pb 2 | set PKGNAME=gamedef 3 | call gen_pb.bat gamedef.proto 4 | 5 | cd ..\sproto 6 | call gen_sproto.bat gamedef.sproto 7 | cd .. 8 | 9 | cd binary 10 | call gen_binary 11 | cd .. 12 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/binary/coredef/binmsg.go: -------------------------------------------------------------------------------- 1 | package coredef 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | _ "github.com/davyxu/cellnet/codec/binary" 6 | ) 7 | 8 | // Acceptor的会话被允许接入时 9 | type SessionAccepted struct { 10 | } 11 | 12 | // Connector的连接创建时 13 | type SessionConnected struct { 14 | } 15 | 16 | // Acceptor的会话接受错误 17 | type SessionAcceptFailed struct { 18 | Result cellnet.Result 19 | } 20 | 21 | // Connector连接失败时 22 | type SessionConnectFailed struct { 23 | Result cellnet.Result 24 | } 25 | 26 | // Session连接断开时 27 | type SessionClosed struct { 28 | Result cellnet.Result 29 | } 30 | 31 | // 内部消息,勿使用及注册响应 32 | type RemoteCallACK struct { 33 | MsgID uint32 34 | Data []byte 35 | CallID int64 36 | } 37 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/binary/coredef/objproto_gen.go: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/cellnet/objprotogen 2 | // DO NOT EDIT! 3 | package coredef 4 | 5 | import ( 6 | "github.com/davyxu/cellnet" 7 | "github.com/davyxu/goobjfmt" 8 | "reflect" 9 | ) 10 | 11 | func (self *SessionAccepted) String() string { return goobjfmt.CompactTextString(self) } 12 | func (self *SessionConnected) String() string { return goobjfmt.CompactTextString(self) } 13 | func (self *SessionAcceptFailed) String() string { return goobjfmt.CompactTextString(self) } 14 | func (self *SessionConnectFailed) String() string { return goobjfmt.CompactTextString(self) } 15 | func (self *SessionClosed) String() string { return goobjfmt.CompactTextString(self) } 16 | func (self *RemoteCallACK) String() string { return goobjfmt.CompactTextString(self) } 17 | 18 | func init() { 19 | 20 | cellnet.RegisterMessageMeta("binary", "coredef.SessionAccepted", reflect.TypeOf((*SessionAccepted)(nil)).Elem(), 2087448307) 21 | cellnet.RegisterMessageMeta("binary", "coredef.SessionConnected", reflect.TypeOf((*SessionConnected)(nil)).Elem(), 3159799620) 22 | cellnet.RegisterMessageMeta("binary", "coredef.SessionAcceptFailed", reflect.TypeOf((*SessionAcceptFailed)(nil)).Elem(), 3257237101) 23 | cellnet.RegisterMessageMeta("binary", "coredef.SessionConnectFailed", reflect.TypeOf((*SessionConnectFailed)(nil)).Elem(), 290677256) 24 | cellnet.RegisterMessageMeta("binary", "coredef.SessionClosed", reflect.TypeOf((*SessionClosed)(nil)).Elem(), 1747213404) 25 | cellnet.RegisterMessageMeta("binary", "coredef.RemoteCallACK", reflect.TypeOf((*RemoteCallACK)(nil)).Elem(), 14297662) 26 | } 27 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/binary/gen_binary.bat: -------------------------------------------------------------------------------- 1 | set CURR=%cd% 2 | cd ..\..\..\..\..\.. 3 | set GOPATH=%cd% 4 | cd %CURR% 5 | 6 | go build -o objprotogen.exe github.com/davyxu/cellnet/objprotogen 7 | @IF %ERRORLEVEL% NEQ 0 pause 8 | 9 | 10 | objprotogen.exe --out coredef/objproto_gen.go coredef/binmsg.go 11 | @IF %ERRORLEVEL% NEQ 0 pause 12 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/json/gamedef/jsonmsg.go: -------------------------------------------------------------------------------- 1 | package gamedef 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | _ "github.com/davyxu/cellnet/codec/json" 6 | "github.com/davyxu/cellnet/util" 7 | "github.com/davyxu/goobjfmt" 8 | "reflect" 9 | ) 10 | 11 | type TestEchoJsonACK struct { 12 | Content string 13 | } 14 | 15 | func (m *TestEchoJsonACK) String() string { return goobjfmt.CompactTextString(m) } 16 | 17 | func init() { 18 | 19 | // coredef.proto 20 | cellnet.RegisterMessageMeta("json", "gamedef.TestEchoJsonACK", reflect.TypeOf((*TestEchoJsonACK)(nil)).Elem(), util.StringHash("gamedef.TestEchoJsonACK")) 21 | } 22 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/pb/gamedef.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package gamedef; 4 | 5 | // 游戏消息是单独处理的一个协议文件, 与coredef区分开 6 | 7 | // ========================================================== 8 | // 测试用消息 9 | // ========================================================== 10 | message TestEchoACK 11 | { 12 | string Content = 1; 13 | } 14 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/pb/gamedef/gamedef.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: gamedef.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package gamedef is a generated protocol buffer package. 7 | 8 | It is generated from these files: 9 | gamedef.proto 10 | 11 | It has these top-level messages: 12 | TestEchoACK 13 | */ 14 | package gamedef 15 | 16 | import proto "github.com/golang/protobuf/proto" 17 | import fmt "fmt" 18 | import math "math" 19 | 20 | // Reference imports to suppress errors if they are not otherwise used. 21 | var _ = proto.Marshal 22 | var _ = fmt.Errorf 23 | var _ = math.Inf 24 | 25 | // This is a compile-time assertion to ensure that this generated file 26 | // is compatible with the proto package it is being compiled against. 27 | // A compilation error at this line likely means your copy of the 28 | // proto package needs to be updated. 29 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 30 | 31 | // ========================================================== 32 | // 测试用消息 33 | // ========================================================== 34 | type TestEchoACK struct { 35 | Content string `protobuf:"bytes,1,opt,name=Content,json=content" json:"Content,omitempty"` 36 | } 37 | 38 | func (m *TestEchoACK) Reset() { *m = TestEchoACK{} } 39 | func (m *TestEchoACK) String() string { return proto.CompactTextString(m) } 40 | func (*TestEchoACK) ProtoMessage() {} 41 | func (*TestEchoACK) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 42 | 43 | func init() { 44 | proto.RegisterType((*TestEchoACK)(nil), "gamedef.TestEchoACK") 45 | } 46 | 47 | func init() { proto.RegisterFile("gamedef.proto", fileDescriptor0) } 48 | 49 | var fileDescriptor0 = []byte{ 50 | // 85 bytes of a gzipped FileDescriptorProto 51 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x4f, 0xcc, 0x4d, 52 | 0x4d, 0x49, 0x4d, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x72, 0x95, 0xd4, 0xb9, 53 | 0xb8, 0x43, 0x52, 0x8b, 0x4b, 0x5c, 0x93, 0x33, 0xf2, 0x1d, 0x9d, 0xbd, 0x85, 0x24, 0xb8, 0xd8, 54 | 0x9d, 0xf3, 0xf3, 0x4a, 0x52, 0xf3, 0x4a, 0x24, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xd8, 0x93, 55 | 0x21, 0xdc, 0x24, 0x36, 0xb0, 0x46, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1a, 0xc1, 0x9b, 56 | 0xa0, 0x49, 0x00, 0x00, 0x00, 57 | } 58 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/pb/gamedef/msgid.go: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/cellnet/protoc-gen-msg 2 | // DO NOT EDIT! 3 | // Source: gamedef.proto 4 | 5 | package gamedef 6 | 7 | import ( 8 | "github.com/davyxu/cellnet" 9 | "reflect" 10 | _ "github.com/davyxu/cellnet/codec/pb" 11 | ) 12 | 13 | func init() { 14 | 15 | // gamedef.proto 16 | cellnet.RegisterMessageMeta("pb", "gamedef.TestEchoACK", reflect.TypeOf((*TestEchoACK)(nil)).Elem(), 1899977859) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/pb/gen_pb.bat: -------------------------------------------------------------------------------- 1 | set CURR_DIR=%cd% 2 | 3 | : Build generator 4 | cd ..\..\..\..\..\.. 5 | set GOPATH=%cd% 6 | go build -o %CURR_DIR%\protoc-gen-msg.exe github.com/davyxu/cellnet/protoc-gen-msg 7 | cd %CURR_DIR% 8 | 9 | set OUTDIR=%PKGNAME% 10 | set plugindir=..\..\..\..\..\..\bin 11 | mkdir %OUTDIR% 12 | protoc.exe --plugin=protoc-gen-go=%plugindir%\protoc-gen-go.exe --go_out %OUTDIR% --proto_path "." %* 13 | protoc.exe --plugin=protoc-gen-msg=protoc-gen-msg.exe --msg_out=msgid.go:%OUTDIR% --proto_path "." %* -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/sproto/gamedef.sproto: -------------------------------------------------------------------------------- 1 | 2 | .TestEchoACK { 3 | Content 0: string 4 | } 5 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/sproto/gamedef/gamedef.go: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/gosproto/sprotogen 2 | // DO NOT EDIT! 3 | 4 | package gamedef 5 | 6 | import ( 7 | "reflect" 8 | 9 | "github.com/davyxu/goobjfmt" 10 | "github.com/davyxu/cellnet/codec/sproto" 11 | ) 12 | 13 | type TestEchoACK struct { 14 | Content string `sproto:"string,0,name=Content"` 15 | } 16 | 17 | func (self *TestEchoACK) String() string { return goobjfmt.CompactTextString(self) } 18 | 19 | var SProtoStructs = []reflect.Type{ 20 | 21 | reflect.TypeOf((*TestEchoACK)(nil)).Elem(), // 1899977859 22 | } 23 | 24 | var SProtoEnumValue = map[string]map[int32]string{} 25 | 26 | func init() { 27 | sprotocodec.AutoRegisterMessageMeta(SProtoStructs) 28 | } 29 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/proto/sproto/gen_sproto.bat: -------------------------------------------------------------------------------- 1 | set CURR_DIR=%cd% 2 | 3 | : Build generator 4 | cd ..\..\..\..\..\.. 5 | set GOPATH=%cd% 6 | go build -o %CURR_DIR%\sprotogen.exe github.com/davyxu/gosproto/sprotogen 7 | cd %CURR_DIR% 8 | 9 | : Generate go source file by sproto 10 | sprotogen --go_out=.\gamedef\gamedef.go --package=gamedef --cellnet_reg=true %* -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/protoc-gen-msg/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path" 7 | 8 | "github.com/davyxu/golog" 9 | "github.com/davyxu/pbmeta" 10 | pbprotos "github.com/davyxu/pbmeta/proto" 11 | plugin "github.com/davyxu/pbmeta/proto/compiler" 12 | "github.com/golang/protobuf/proto" 13 | ) 14 | 15 | var log *golog.Logger = golog.New("main") 16 | 17 | func main() { 18 | 19 | // 读取protoc请求 20 | data, err := ioutil.ReadAll(os.Stdin) 21 | if err != nil { 22 | log.Errorln("reading input") 23 | } 24 | 25 | var Request plugin.CodeGeneratorRequest // The input. 26 | var Response plugin.CodeGeneratorResponse // The output. 27 | 28 | // 解析请求 29 | if err := proto.Unmarshal(data, &Request); err != nil { 30 | log.Errorln("parsing input proto") 31 | } 32 | 33 | if len(Request.FileToGenerate) == 0 { 34 | log.Errorln("no files to generate") 35 | } 36 | 37 | // 建立解析池 38 | pool := pbmeta.NewDescriptorPool(&pbprotos.FileDescriptorSet{ 39 | File: Request.ProtoFile, 40 | }) 41 | 42 | Response.File = make([]*plugin.CodeGeneratorResponse_File, 0) 43 | 44 | contenxt, ok := printFile(pool) 45 | 46 | if !ok { 47 | os.Exit(1) 48 | } 49 | 50 | Response.File = append(Response.File, &plugin.CodeGeneratorResponse_File{ 51 | Name: proto.String(Request.GetParameter()), 52 | Content: proto.String(contenxt), 53 | }) 54 | 55 | // 发回处理结果 56 | data, err = proto.Marshal(&Response) 57 | if err != nil { 58 | log.Errorln("failed to marshal output proto") 59 | } 60 | _, err = os.Stdout.Write(data) 61 | if err != nil { 62 | log.Errorln("failed to write output proto") 63 | } 64 | 65 | } 66 | 67 | func changeExt(name string) string { 68 | ext := path.Ext(name) 69 | if ext == ".proto" { 70 | name = name[0 : len(name)-len(ext)] 71 | } 72 | return name + ".msg.go" 73 | } 74 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/queue.go: -------------------------------------------------------------------------------- 1 | package cellnet 2 | 3 | import ( 4 | "runtime/debug" 5 | ) 6 | 7 | type EventQueue interface { 8 | StartLoop() 9 | 10 | StopLoop(result int) 11 | 12 | // 等待退出 13 | Wait() int 14 | 15 | // 投递事件, 通过队列到达消费者端 16 | Post(callback func()) 17 | } 18 | 19 | type evQueue struct { 20 | queue chan func() 21 | 22 | exitSignal chan int 23 | 24 | capturePanic bool 25 | } 26 | 27 | // 派发到队列 28 | func (self *evQueue) Post(callback func()) { 29 | 30 | if callback == nil { 31 | return 32 | } 33 | 34 | self.queue <- callback 35 | } 36 | 37 | func (self *evQueue) protectedCall(callback func()) { 38 | 39 | if callback == nil { 40 | return 41 | } 42 | 43 | if self.capturePanic { 44 | defer func() { 45 | 46 | if err := recover(); err != nil { 47 | 48 | debug.PrintStack() 49 | } 50 | 51 | }() 52 | } 53 | 54 | callback() 55 | } 56 | 57 | func (self *evQueue) StartLoop() { 58 | 59 | go func() { 60 | for callback := range self.queue { 61 | self.protectedCall(callback) 62 | } 63 | }() 64 | } 65 | 66 | func (self *evQueue) StopLoop(result int) { 67 | self.exitSignal <- result 68 | } 69 | 70 | func (self *evQueue) Wait() int { 71 | return <-self.exitSignal 72 | } 73 | 74 | const DefaultQueueSize = 100 75 | 76 | func NewEventQueue() EventQueue { 77 | 78 | return NewEventQueueByLen(DefaultQueueSize) 79 | } 80 | 81 | func NewEventQueueByLen(l int) EventQueue { 82 | self := &evQueue{ 83 | queue: make(chan func(), l), 84 | exitSignal: make(chan int), 85 | } 86 | 87 | return self 88 | } 89 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/ack_reg.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | ) 6 | 7 | func ChainSend() *cellnet.HandlerChain { 8 | 9 | return cellnet.NewHandlerChain( 10 | cellnet.StaticEncodePacketHandler(), 11 | NewBoxHandler(), 12 | ) 13 | } 14 | 15 | // 服务器端响应RPC消息 16 | func RegisterMessage(p cellnet.Peer, msgName string, userCallback func(ev *cellnet.Event)) { 17 | 18 | if p == nil { 19 | return 20 | } 21 | 22 | msgMeta := cellnet.MessageMetaByName(msgName) 23 | 24 | p.AddChainRecv(cellnet.NewHandlerChain( 25 | cellnet.NewMatchMsgIDHandler(MetaCall.ID), 26 | cellnet.StaticDecodePacketHandler(), 27 | NewUnboxHandler(ChainSend()), 28 | cellnet.NewMatchMsgIDHandler(msgMeta.ID), 29 | cellnet.StaticDecodePacketHandler(), 30 | cellnet.NewQueuePostHandler(p.Queue(), cellnet.NewCallbackHandler(userCallback)), 31 | )) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/handler_box.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "github.com/davyxu/cellnet/proto/binary/coredef" 6 | ) 7 | 8 | type BoxHandler struct { 9 | } 10 | 11 | func (self *BoxHandler) Call(ev *cellnet.Event) { 12 | 13 | // 来自encode之后的消息 14 | ev.FromMessage(&coredef.RemoteCallACK{ 15 | MsgID: ev.MsgID, 16 | Data: ev.Data, 17 | CallID: ev.TransmitTag.(int64), 18 | }) 19 | 20 | } 21 | 22 | func NewBoxHandler() cellnet.EventHandler { 23 | 24 | return &BoxHandler{} 25 | 26 | } 27 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/handler_reflectcall.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/davyxu/cellnet" 7 | ) 8 | 9 | type ReflectCallHandler struct { 10 | entry reflect.Value 11 | } 12 | 13 | func (self *ReflectCallHandler) Call(ev *cellnet.Event) { 14 | 15 | // 这里的反射, 会影响非常少的效率, 但因为外部写法简单, 就算了 16 | self.entry.Call([]reflect.Value{reflect.ValueOf(ev.Msg)}) 17 | 18 | } 19 | 20 | func NewReflectCallHandler(userCallback interface{}) cellnet.EventHandler { 21 | 22 | return &ReflectCallHandler{ 23 | entry: reflect.ValueOf(userCallback), 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/handler_retchan.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import "github.com/davyxu/cellnet" 4 | 5 | type RetChanHandler struct { 6 | ret chan interface{} 7 | } 8 | 9 | func (self *RetChanHandler) Call(ev *cellnet.Event) { 10 | 11 | self.ret <- ev.Msg 12 | } 13 | 14 | func NewRetChanHandler(ret chan interface{}) cellnet.EventHandler { 15 | return &RetChanHandler{ 16 | ret: ret, 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/handler_unbox.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "github.com/davyxu/cellnet/proto/binary/coredef" 6 | ) 7 | 8 | type UnboxHandler struct { 9 | feedbackChain *cellnet.HandlerChain 10 | } 11 | 12 | func (self *UnboxHandler) Call(ev *cellnet.Event) { 13 | 14 | wrapper := ev.Msg.(*coredef.RemoteCallACK) 15 | 16 | ev.MsgID = wrapper.MsgID 17 | ev.Data = wrapper.Data 18 | 19 | // 服务器接收后, 发送时, 需要使用CallID 20 | ev.TransmitTag = wrapper.CallID 21 | 22 | ev.ChainSend = self.feedbackChain 23 | 24 | } 25 | 26 | func NewUnboxHandler(chain *cellnet.HandlerChain) cellnet.EventHandler { 27 | return &UnboxHandler{ 28 | feedbackChain: chain, 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/log.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log *golog.Logger = golog.New("rpc") 8 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/req_async.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "time" 6 | ) 7 | 8 | // ud: peer/session, reqMsg:请求用的消息, userCallback: 返回消息类型回调 func( ackMsg *ackMsgType) 9 | func Call(sesOrPeer interface{}, reqMsg interface{}, ackMsgName string, timeout time.Duration, userCallback func(ev *cellnet.Event)) error { 10 | 11 | ses, p, err := getPeerSession(sesOrPeer) 12 | 13 | if err != nil { 14 | return err 15 | } 16 | 17 | rpcid, err := buildRecvHandler(p, ackMsgName, cellnet.NewCallbackHandler(userCallback)) 18 | 19 | if err != nil { 20 | return err 21 | } 22 | 23 | time.AfterFunc(timeout, func() { 24 | p.RemoveChainRecv(rpcid) 25 | }) 26 | 27 | // 发送RPC请求 28 | ev := cellnet.NewEvent(cellnet.Event_Send, ses) 29 | ev.TransmitTag = rpcid 30 | ev.Msg = reqMsg 31 | ev.ChainSend = ChainSend() 32 | ses.RawSend(ev) 33 | 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/req_sync.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "errors" 5 | "github.com/davyxu/cellnet" 6 | "time" 7 | ) 8 | 9 | var ErrTimeout = errors.New("time out") 10 | 11 | // 发出请求, 接收到服务器返回后才返回, ud: peer/session, reqMsg:请求用的消息, ackMsgName: 返回消息类型名, 返回消息为返回值 12 | func CallSync(ud interface{}, reqMsg interface{}, ackMsgName string, timeout time.Duration) (interface{}, error) { 13 | 14 | ses, p, err := getPeerSession(ud) 15 | 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | ret := make(chan interface{}) 21 | 22 | rpcid, err := buildRecvHandler(p, ackMsgName, NewRetChanHandler(ret)) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | // 发送RPC请求 28 | ev := cellnet.NewEvent(cellnet.Event_Send, ses) 29 | ev.TransmitTag = rpcid 30 | ev.Msg = reqMsg 31 | ev.ChainSend = ChainSend() 32 | ses.RawSend(ev) 33 | 34 | // 等待RPC回复 35 | select { 36 | case v := <-ret: 37 | return v, nil 38 | case <-time.After(timeout): 39 | return nil, ErrTimeout 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/reqhandler.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import "github.com/davyxu/cellnet" 4 | 5 | // 请求方接收消息 6 | func buildRecvHandler(p cellnet.Peer, msgName string, tailHandler cellnet.EventHandler) (rpcID int64, err error) { 7 | 8 | msgMeta := cellnet.MessageMetaByName(msgName) 9 | if msgMeta == nil { 10 | return -1, ErrReplayMessageNotFound 11 | } 12 | 13 | rpcID = p.AddChainRecv(cellnet.NewHandlerChain( 14 | cellnet.NewMatchMsgIDHandler(MetaCall.ID), 15 | cellnet.StaticDecodePacketHandler(), 16 | NewUnboxHandler(ChainSend()), 17 | cellnet.NewMatchMsgIDHandler(msgMeta.ID), 18 | cellnet.StaticDecodePacketHandler(), 19 | cellnet.NewQueuePostHandler(p.Queue(), tailHandler, cellnet.NewCallbackHandler(func(ev *cellnet.Event) { 20 | 21 | p.RemoveChainRecv(rpcID) 22 | 23 | })), 24 | )) 25 | 26 | return rpcID, nil 27 | 28 | } 29 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/rpc/util.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/davyxu/cellnet" 7 | ) 8 | 9 | var ( 10 | ErrInvalidPeerSession error = errors.New("rpc: Invalid peer type, require cellnet.RPCSessionGetter or cellnet.Session") 11 | ErrReplayMessageNotFound = errors.New("rpc: Reply message name not found") 12 | 13 | MetaCall = cellnet.MessageMetaByName("coredef.RemoteCallACK") 14 | ) 15 | 16 | type RPCSessionGetter interface { 17 | RPCSession() cellnet.Session 18 | } 19 | 20 | // 从peer获取rpc使用的session 21 | func getPeerSession(ud interface{}) (cellnet.Session, cellnet.Peer, error) { 22 | 23 | if ud == nil { 24 | return nil, nil, ErrInvalidPeerSession 25 | } 26 | 27 | switch i := ud.(type) { 28 | case RPCSessionGetter: 29 | return i.RPCSession(), i.RPCSession().FromPeer(), nil 30 | case cellnet.Session: 31 | return i, i.FromPeer(), nil 32 | default: 33 | return nil, nil, ErrInvalidPeerSession 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/socket/base.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "net" 6 | ) 7 | 8 | // Peer间的共享数据 9 | type socketPeer struct { 10 | cellnet.EventQueue 11 | // 会话管理器 12 | cellnet.SessionManager 13 | 14 | // 共享配置 15 | *cellnet.PeerProfileImplement 16 | 17 | // 处理链管理 18 | *cellnet.HandlerChainManagerImplement 19 | 20 | // socket配置 21 | *socketOptions 22 | 23 | // 停止过程同步 24 | stopping chan bool 25 | } 26 | 27 | func (self *socketPeer) waitStopFinished() { 28 | // 如果正在停止时, 等待停止完成 29 | if self.stopping != nil { 30 | <-self.stopping 31 | self.stopping = nil 32 | } 33 | } 34 | 35 | func (self *socketPeer) isStopping() bool { 36 | return self.stopping != nil 37 | } 38 | 39 | func (self *socketPeer) startStopping() { 40 | self.stopping = make(chan bool) 41 | } 42 | 43 | func (self *socketPeer) endStopping() { 44 | select { 45 | case self.stopping <- true: 46 | 47 | default: 48 | self.stopping = nil 49 | } 50 | } 51 | 52 | func (self *socketPeer) Queue() cellnet.EventQueue { 53 | return self.EventQueue 54 | } 55 | 56 | func newSocketPeer(queue cellnet.EventQueue, sm cellnet.SessionManager) *socketPeer { 57 | 58 | self := &socketPeer{ 59 | EventQueue: queue, 60 | SessionManager: sm, 61 | socketOptions: newSocketOptions(), 62 | PeerProfileImplement: cellnet.NewPeerProfile(), 63 | HandlerChainManagerImplement: cellnet.NewHandlerChainManager(), 64 | } 65 | 66 | // 设置默认发送链 67 | self.SetChainSend( 68 | cellnet.NewHandlerChain( 69 | cellnet.StaticEncodePacketHandler(), 70 | ), 71 | ) 72 | 73 | // 设置默认读写链 74 | self.SetReadWriteChain(func() *cellnet.HandlerChain { 75 | return cellnet.NewHandlerChain( 76 | cellnet.NewFixedLengthFrameReader(10), 77 | NewPrivatePacketReader(), 78 | ) 79 | }, func() *cellnet.HandlerChain { 80 | return cellnet.NewHandlerChain(NewPrivatePacketWriter(), 81 | cellnet.NewFixedLengthFrameWriter(), 82 | ) 83 | }) 84 | 85 | return self 86 | } 87 | 88 | func errToResult(err error) cellnet.Result { 89 | 90 | if err == nil { 91 | return cellnet.Result_OK 92 | } 93 | 94 | switch n := err.(type) { 95 | case net.Error: 96 | if n.Timeout() { 97 | return cellnet.Result_SocketTimeout 98 | } 99 | } 100 | 101 | return cellnet.Result_SocketError 102 | } 103 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/socket/evtlist.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/davyxu/cellnet" 7 | ) 8 | 9 | type eventList struct { 10 | list []*cellnet.Event 11 | listGuard sync.Mutex 12 | listCond *sync.Cond 13 | } 14 | 15 | func (self *eventList) Add(ev *cellnet.Event) { 16 | self.listGuard.Lock() 17 | self.list = append(self.list, ev) 18 | self.listGuard.Unlock() 19 | 20 | self.listCond.Signal() 21 | } 22 | 23 | func (self *eventList) Reset() { 24 | self.list = self.list[0:0] 25 | } 26 | 27 | func (self *eventList) Pick() (ret []*cellnet.Event, exit bool) { 28 | 29 | self.listGuard.Lock() 30 | 31 | for len(self.list) == 0 { 32 | self.listCond.Wait() 33 | } 34 | 35 | self.listGuard.Unlock() 36 | 37 | self.listGuard.Lock() 38 | 39 | // 复制出队列 40 | 41 | for _, ev := range self.list { 42 | 43 | if ev == nil { 44 | exit = true 45 | break 46 | } else { 47 | ret = append(ret, ev) 48 | } 49 | } 50 | 51 | self.Reset() 52 | self.listGuard.Unlock() 53 | 54 | return 55 | } 56 | 57 | func NewPacketList() *eventList { 58 | self := &eventList{} 59 | self.listCond = sync.NewCond(&self.listGuard) 60 | 61 | return self 62 | } 63 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/socket/log.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log *golog.Logger = golog.New("socket") 8 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/socket/options.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "net" 5 | "time" 6 | ) 7 | 8 | type SocketOptions interface { 9 | // Session最大包大小, 超过这个数字, 接收视为错误, 断开连接 10 | SetMaxPacketSize(size int) 11 | 12 | MaxPacketSize() int 13 | 14 | // 设置socket选项, 如果不修改,请设置-1 15 | SetSocketOption(readBufferSize, writeBufferSize int, nodelay bool) 16 | 17 | // 设置socket超时间隔, 0表示不作用 18 | SetSocketDeadline(read, write time.Duration) 19 | SocketDeadline() (read, write time.Duration) 20 | } 21 | 22 | type socketOptions struct { 23 | // socket参数 24 | maxPacketSize int 25 | connReadBuffer int 26 | connWriteBuffer int 27 | connNoDelay bool 28 | connReadTimeout time.Duration 29 | connWriteTimeout time.Duration 30 | } 31 | 32 | // socket配置 33 | func (self *socketOptions) SetMaxPacketSize(size int) { 34 | self.maxPacketSize = size 35 | } 36 | 37 | func (self *socketOptions) MaxPacketSize() int { 38 | return self.maxPacketSize 39 | } 40 | 41 | func (self *socketOptions) SetSocketDeadline(read, write time.Duration) { 42 | self.connReadTimeout = read 43 | self.connWriteTimeout = write 44 | } 45 | 46 | func (self *socketOptions) SocketDeadline() (read, write time.Duration) { 47 | return self.connReadTimeout, self.connWriteTimeout 48 | } 49 | 50 | func (self *socketOptions) SetSocketOption(readBufferSize, writeBufferSize int, nodelay bool) { 51 | 52 | self.connReadBuffer = readBufferSize 53 | self.connWriteBuffer = writeBufferSize 54 | self.connNoDelay = nodelay 55 | } 56 | 57 | func (self *socketOptions) Apply(conn net.Conn) { 58 | 59 | if cc, ok := conn.(*net.TCPConn); ok { 60 | 61 | if self.connReadBuffer >= 0 { 62 | cc.SetReadBuffer(self.connReadBuffer) 63 | } 64 | 65 | if self.connWriteBuffer >= 0 { 66 | cc.SetWriteBuffer(self.connWriteBuffer) 67 | } 68 | 69 | cc.SetNoDelay(self.connNoDelay) 70 | } 71 | 72 | } 73 | 74 | func newSocketOptions() *socketOptions { 75 | return &socketOptions{ 76 | connWriteBuffer: -1, 77 | connReadBuffer: -1, 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/timer/after.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "time" 6 | ) 7 | 8 | type AfterStopper interface { 9 | Stop() bool 10 | } 11 | 12 | func After(q cellnet.EventQueue, duration time.Duration, callback func()) AfterStopper { 13 | 14 | if q == nil { 15 | return nil 16 | } 17 | 18 | afterTimer := time.NewTimer(duration) 19 | 20 | go func() { 21 | 22 | <-afterTimer.C 23 | 24 | q.Post(callback) 25 | 26 | }() 27 | 28 | return afterTimer 29 | 30 | } 31 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/timer/loop.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "time" 6 | ) 7 | 8 | type Loop struct { 9 | Context interface{} 10 | Duration time.Duration 11 | userCallback func(*Loop) 12 | 13 | running bool 14 | 15 | Queue cellnet.EventQueue 16 | } 17 | 18 | func (self *Loop) Running() bool { 19 | return self.running 20 | } 21 | 22 | func (self *Loop) Start() bool { 23 | 24 | if self.running { 25 | return false 26 | } 27 | 28 | self.running = true 29 | 30 | self.rawPost() 31 | 32 | return true 33 | } 34 | 35 | func (self *Loop) rawPost() { 36 | 37 | if self.Duration == 0 { 38 | panic("seconds can be zero in loop") 39 | } 40 | 41 | After(self.Queue, self.Duration, func() { 42 | tick(self, false) 43 | }) 44 | } 45 | 46 | func (self *Loop) NextLoop() { 47 | 48 | self.Queue.Post(func() { 49 | tick(self, true) 50 | }) 51 | } 52 | 53 | func (self *Loop) Stop() { 54 | 55 | self.running = false 56 | } 57 | 58 | func (self *Loop) Notify() { 59 | self.userCallback(self) 60 | } 61 | 62 | func tick(ctx interface{}, nextLoop bool) { 63 | 64 | loop := ctx.(*Loop) 65 | 66 | loop.Notify() 67 | 68 | if !loop.running { 69 | return 70 | } 71 | 72 | // 不等待, 直接跳到下一个循环 73 | 74 | if !nextLoop { 75 | loop.rawPost() 76 | } 77 | 78 | } 79 | 80 | func NewLoop(q cellnet.EventQueue, duration time.Duration, callback func(*Loop), context interface{}) *Loop { 81 | 82 | self := &Loop{ 83 | Context: context, 84 | Duration: duration, 85 | userCallback: callback, 86 | Queue: q, 87 | } 88 | 89 | return self 90 | } 91 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/util/signaltester.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | type SignalTester struct { 9 | *testing.T 10 | 11 | signal chan interface{} 12 | 13 | timeout time.Duration 14 | } 15 | 16 | func (self *SignalTester) SetTimeout(du time.Duration) { 17 | self.timeout = du 18 | } 19 | 20 | func (self *SignalTester) WaitAndExpect(msg string, values ...interface{}) bool { 21 | 22 | var recvValues = map[interface{}]bool{} 23 | 24 | for _, value := range values { 25 | select { 26 | case v := <-self.signal: 27 | recvValues[v] = true 28 | 29 | case <-time.After(self.timeout): 30 | self.Errorf("signal timeout: %d %s", value, msg) 31 | self.Fail() 32 | return false 33 | } 34 | } 35 | 36 | for _, value := range values { 37 | 38 | if _, ok := recvValues[value]; !ok { 39 | self.FailNow() 40 | self.Errorf("%s\n", msg) 41 | 42 | } 43 | 44 | } 45 | 46 | return true 47 | } 48 | 49 | func (self *SignalTester) Done(value interface{}) { 50 | self.signal <- value 51 | } 52 | 53 | func NewSignalTester(t *testing.T) *SignalTester { 54 | 55 | return &SignalTester{ 56 | T: t, 57 | timeout: 2 * time.Second, 58 | signal: make(chan interface{}), 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/util/strhash.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | var crcTable []uint32 = make([]uint32, 256) 4 | 5 | const crcPOLY uint32 = 0x04c11db7 6 | 7 | var crcTableInitialized bool = false 8 | 9 | func initCRCTable() { 10 | 11 | if crcTableInitialized { 12 | return 13 | } 14 | 15 | var i uint32 16 | var c uint32 17 | var j uint32 18 | 19 | for i = 0; i < 256; i++ { 20 | 21 | c = (i << 24) 22 | 23 | for j = 8; j != 0; j = j - 1 { 24 | 25 | if (c & 0x80000000) != 0 { 26 | c = (c << 1) ^ crcPOLY 27 | } else { 28 | c = (c << 1) 29 | } 30 | 31 | crcTable[i] = c 32 | } 33 | } 34 | 35 | crcTableInitialized = true 36 | } 37 | 38 | // 字符串转为32位整形值 39 | func StringHash(s string) uint32 { 40 | initCRCTable() 41 | 42 | var hash uint32 43 | var b uint32 44 | 45 | for _, c := range s { 46 | 47 | b = uint32(c) 48 | 49 | hash = ((hash >> 8) & 0x00FFFFFF) ^ crcTable[(hash^b)&0x000000FF] 50 | } 51 | 52 | return hash 53 | } 54 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/util/strhash_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestStrHash(t *testing.T) { 8 | if v := StringHash("gamedef.EnterGameREQ"); v != 0x28c2f4fb { 9 | t.Errorf("expect 0x28c2f4fb, got %x", v) 10 | } 11 | 12 | if v := StringHash("gamedef.EnterGameACK"); v != 0x43980899 { 13 | t.Errorf("expect 0x43980899, got %x", v) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/websocket/acceptor.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/extend" 9 | "github.com/gorilla/websocket" 10 | ) 11 | 12 | type wsAcceptor struct { 13 | *wsPeer 14 | } 15 | 16 | var upgrader = websocket.Upgrader{ 17 | CheckOrigin: func(r *http.Request) bool { 18 | return true 19 | }, 20 | } // use default options 21 | 22 | func (self *wsAcceptor) Start(address string) cellnet.Peer { 23 | 24 | if self.IsRunning() { 25 | return self 26 | } 27 | 28 | self.SetRunning(true) 29 | 30 | url, err := url.Parse(address) 31 | 32 | if err != nil { 33 | log.Errorln(err, address) 34 | return self 35 | } 36 | 37 | if url.Path == "" { 38 | log.Errorln("websocket: expect path in url to listen", address) 39 | return self 40 | } 41 | 42 | self.SetAddress(address) 43 | 44 | http.HandleFunc(url.Path, func(w http.ResponseWriter, r *http.Request) { 45 | 46 | c, err := upgrader.Upgrade(w, r, nil) 47 | if err != nil { 48 | return 49 | } 50 | 51 | ses := newSession(c, self) 52 | 53 | // 添加到管理器 54 | self.Add(ses) 55 | 56 | // 断开后从管理器移除 57 | ses.OnClose = func() { 58 | self.Remove(ses) 59 | } 60 | 61 | ses.run() 62 | 63 | // 通知逻辑 64 | extend.PostSystemEvent(ses, cellnet.Event_Accepted, self.ChainListRecv(), cellnet.Result_OK) 65 | 66 | }) 67 | 68 | go func() { 69 | 70 | err = http.ListenAndServe(url.Host, nil) 71 | 72 | if err != nil { 73 | log.Errorln(err) 74 | } 75 | 76 | self.SetRunning(false) 77 | 78 | }() 79 | 80 | return self 81 | } 82 | 83 | func (self *wsAcceptor) Stop() { 84 | if !self.IsRunning() { 85 | return 86 | } 87 | 88 | } 89 | 90 | func NewAcceptor(q cellnet.EventQueue) cellnet.Peer { 91 | 92 | self := &wsAcceptor{ 93 | wsPeer: newPeer(q, cellnet.NewSessionManager()), 94 | } 95 | 96 | return self 97 | } 98 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/websocket/base.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | ) 6 | 7 | // Peer间的共享数据 8 | type wsPeer struct { 9 | cellnet.EventQueue 10 | 11 | cellnet.SessionManager 12 | 13 | *cellnet.PeerProfileImplement 14 | 15 | *cellnet.HandlerChainManagerImplement 16 | } 17 | 18 | func (self *wsPeer) Queue() cellnet.EventQueue { 19 | return self.EventQueue 20 | } 21 | 22 | func newPeer(queue cellnet.EventQueue, sm cellnet.SessionManager) *wsPeer { 23 | 24 | self := &wsPeer{ 25 | EventQueue: queue, 26 | SessionManager: sm, 27 | PeerProfileImplement: cellnet.NewPeerProfile(), 28 | HandlerChainManagerImplement: cellnet.NewHandlerChainManager(), 29 | } 30 | 31 | self.SetChainSend( 32 | cellnet.NewHandlerChain( 33 | cellnet.StaticEncodePacketHandler(), 34 | ), 35 | ) 36 | 37 | return self 38 | } 39 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/websocket/log.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log *golog.Logger = golog.New("websocket") 8 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/cellnet/websocket/textpkt.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import "bytes" 4 | 5 | // 格式: 消息名\n+json文本 6 | 7 | func parsePacket(pkt []byte) (msgName string, data []byte) { 8 | 9 | for index, d := range pkt { 10 | 11 | if d == '\n' { 12 | msgName = string(pkt[:index]) 13 | data = pkt[index+1:] 14 | return 15 | } 16 | } 17 | 18 | return 19 | } 20 | 21 | func composePacket(msgName string, data []byte) []byte { 22 | 23 | var b bytes.Buffer 24 | b.WriteString(msgName) 25 | b.WriteString("\n") 26 | b.Write(data) 27 | 28 | return b.Bytes() 29 | } 30 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (C) 2016 davyxu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/README.md: -------------------------------------------------------------------------------- 1 | # golexer 2 | 3 | 可自定义的词法解析器 4 | 5 | C#版参考https://github.com/davyxu/SharpLexer 6 | 7 | # 特性 8 | 9 | * 支持数值,字符串,注释,标识符等的内建匹配 10 | 11 | * 可自定义匹配器来拾取需要的token 12 | 13 | * 高性能并发匹配 14 | 15 | ```golang 16 | 17 | // 自定义的token id 18 | const ( 19 | Token_Unknown = iota 20 | Token_Numeral 21 | Token_String 22 | Token_WhiteSpace 23 | Token_LineEnd 24 | Token_UnixStyleComment 25 | Token_Identifier 26 | Token_Go 27 | Token_Semicolon 28 | ) 29 | 30 | // 使用lexer 31 | 32 | l := NewLexer() 33 | l.AddMatcher(NewNumeralMatcher(Token_Numeral)) 34 | l.AddMatcher(NewStringMatcher(Token_String)) 35 | 36 | l.AddIgnoreMatcher(NewWhiteSpaceMatcher(Token_WhiteSpace)) 37 | l.AddIgnoreMatcher(NewLineEndMatcher(Token_LineEnd)) 38 | l.AddIgnoreMatcher(NewUnixStyleCommentMatcher(Token_UnixStyleComment)) 39 | 40 | l.AddMatcher(NewSignMatcher(Token_Semicolon, ";")) 41 | l.AddMatcher(NewSignMatcher(Token_Go, "go")) 42 | 43 | l.AddMatcher(NewIdentifierMatcher(Token_Identifier)) 44 | 45 | l.AddMatcher(NewUnknownMatcher(Token_Unknown)) 46 | 47 | // 解析原文 48 | l.Start(`"a" 49 | 123.3; 50 | go 51 | _id # comment 52 | ; 53 | 'b' 54 | 55 | 56 | `) 57 | 58 | // 解析过程 59 | for { 60 | 61 | tk, err := l.Read() 62 | 63 | if err != nil { 64 | t.Error(err) 65 | break 66 | } 67 | 68 | if tk == nil { 69 | break 70 | } 71 | 72 | t.Log(tk.String()) 73 | } 74 | ``` 75 | 76 | 77 | # 备注 78 | 79 | 感觉不错请star, 谢谢! 80 | 81 | 博客: http://www.cppblog.com/sunicdavy 82 | 83 | 知乎: http://www.zhihu.com/people/sunicdavy 84 | 85 | 邮箱: sunicdavy@qq.com 86 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/errcatcher.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | func ErrorCatcher(errFunc func(error)) { 4 | 5 | err := recover() 6 | 7 | switch err.(type) { 8 | // 运行时错误 9 | case interface { 10 | RuntimeError() 11 | }: 12 | 13 | // 继续外抛, 方便调试 14 | panic(err) 15 | 16 | case error: 17 | errFunc(err.(error)) 18 | case nil: 19 | default: 20 | panic(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/kvparser.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // 自定义的token id 8 | const ( 9 | pbtToken_EOF = iota 10 | pbtToken_WhiteSpace 11 | pbtToken_Identifier 12 | pbtToken_Numeral 13 | pbtToken_String 14 | pbtToken_Comma 15 | pbtToken_Colon 16 | pbtToken_LBrace 17 | pbtToken_RBrace 18 | pbtToken_Unknown 19 | ) 20 | 21 | // k:v 与pbt格式互换,详见kvparser_test.go 22 | 23 | func ParseKV(str string, callback func(string, interface{}) bool) (errRet error) { 24 | 25 | l := NewLexer() 26 | 27 | l.AddMatcher(NewNumeralMatcher(pbtToken_Numeral)) 28 | l.AddMatcher(NewStringMatcher(pbtToken_String)) 29 | 30 | l.AddIgnoreMatcher(NewWhiteSpaceMatcher(pbtToken_WhiteSpace)) 31 | l.AddMatcher(NewSignMatcher(pbtToken_Comma, ",")) 32 | l.AddMatcher(NewSignMatcher(pbtToken_Colon, ":")) 33 | l.AddMatcher(NewSignMatcher(pbtToken_LBrace, "[")) 34 | l.AddMatcher(NewSignMatcher(pbtToken_RBrace, "]")) 35 | l.AddMatcher(NewIdentifierMatcher(pbtToken_Identifier)) 36 | l.AddMatcher(NewUnknownMatcher(pbtToken_Unknown)) 37 | 38 | l.Start(str) 39 | 40 | p := NewParser(l, str) 41 | 42 | defer ErrorCatcher(func(err error) { 43 | 44 | errRet = err 45 | 46 | }) 47 | 48 | p.NextToken() 49 | 50 | for p.TokenID() != pbtToken_EOF { 51 | 52 | if p.TokenID() != pbtToken_Identifier { 53 | panic(errors.New("expect identifier: " + p.TokenValue())) 54 | } 55 | 56 | key := p.TokenValue() 57 | 58 | p.NextToken() 59 | 60 | if p.TokenID() != pbtToken_Colon { 61 | panic(errors.New("expect comma: " + p.TokenValue())) 62 | } 63 | 64 | p.NextToken() 65 | 66 | var value interface{} 67 | 68 | if p.TokenID() == pbtToken_LBrace { 69 | p.NextToken() 70 | 71 | strArray := make([]string, 0) 72 | 73 | for p.TokenID() != pbtToken_RBrace && 74 | p.TokenID() != pbtToken_EOF { 75 | 76 | value := p.TokenValue() 77 | 78 | strArray = append(strArray, value) 79 | 80 | p.NextToken() 81 | 82 | // 逗号分割值 83 | if p.TokenID() == pbtToken_Comma { 84 | p.NextToken() 85 | } 86 | 87 | } 88 | 89 | value = strArray 90 | 91 | } else { 92 | value = p.TokenValue() 93 | } 94 | 95 | if !callback(key, value) { 96 | return nil 97 | } 98 | 99 | p.NextToken() 100 | 101 | } 102 | 103 | return nil 104 | } 105 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/kvparser_test.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestKVParser(t *testing.T) { 8 | 9 | ParseKV(`TableName: "Service" Package: "gamedef" OutputTag:[".go", ".json"]"`, func(key string, value interface{}) bool { 10 | 11 | switch v := value.(type) { 12 | case string: 13 | t.Logf("'%s' = '%s'", key, value) 14 | case []string: 15 | t.Logf("'%s' = '%s' len: %d", key, value, len(v)) 16 | } 17 | 18 | return true 19 | }) 20 | 21 | kvp := NewKVPair() 22 | if err := kvp.Parse(`protobuf:"varint,1,opt,name=AutoID,json=autoID" json:"AutoID,omitempty" my:[1, 2]`); err != nil { 23 | t.Error(err) 24 | } 25 | 26 | t.Log(kvp.GetString("json")) 27 | 28 | t.Log(kvp.String()) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/lexer.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | type Lexer struct { 4 | matchers []matcherMeta 5 | 6 | running bool 7 | 8 | tz *Tokenizer 9 | 10 | pos TokenPos 11 | } 12 | 13 | type matcherMeta struct { 14 | m TokenMatcher 15 | ignore bool 16 | } 17 | 18 | var eofToken = NewToken(nil, nil, "EOF", "") 19 | 20 | func (self *Lexer) VisitMatcher(callback func(TokenMatcher) bool) { 21 | 22 | for _, m := range self.matchers { 23 | if !callback(m.m) { 24 | return 25 | } 26 | } 27 | } 28 | 29 | func (self *Lexer) MatcherString(id int) string { 30 | m := self.MatcherByID(id) 31 | if m != nil { 32 | return m.String() 33 | } 34 | 35 | return "" 36 | } 37 | 38 | func (self *Lexer) MatcherByID(id int) TokenMatcher { 39 | for _, m := range self.matchers { 40 | if m.m.ID() == id { 41 | return m.m 42 | } 43 | } 44 | 45 | return nil 46 | } 47 | 48 | // 添加一个匹配器,如果结果匹配,返回token 49 | func (self *Lexer) AddMatcher(m TokenMatcher) { 50 | self.matchers = append(self.matchers, matcherMeta{ 51 | m: m, 52 | ignore: false, 53 | }) 54 | } 55 | 56 | // 添加一个匹配器,如果结果匹配,直接忽略匹配内容 57 | func (self *Lexer) AddIgnoreMatcher(m TokenMatcher) { 58 | self.matchers = append(self.matchers, matcherMeta{ 59 | m: m, 60 | ignore: true, 61 | }) 62 | } 63 | 64 | func (self *Lexer) Start(src string) { 65 | 66 | self.running = true 67 | 68 | self.tz = NewTokenizer(src, self) 69 | } 70 | 71 | func (self *Lexer) Read() (Token, error) { 72 | 73 | if !self.running { 74 | return eofToken, nil 75 | } 76 | 77 | tk, err := self.readToken() 78 | 79 | if err != nil || tk.MatcherID() == 0 { 80 | self.running = false 81 | } 82 | 83 | return tk, err 84 | } 85 | 86 | func (self *Lexer) readToken() (Token, error) { 87 | 88 | if len(self.matchers) == 0 { 89 | return eofToken, nil 90 | } 91 | 92 | for !self.tz.EOF() { 93 | 94 | for _, mm := range self.matchers { 95 | 96 | token, err := mm.m.Match(self.tz) 97 | 98 | if err != nil { 99 | return NewToken(nil, self.tz, err.Error(), ""), err 100 | } 101 | 102 | if token == EmptyToken { 103 | continue 104 | } 105 | 106 | if mm.ignore { 107 | break 108 | } 109 | 110 | return token, nil 111 | } 112 | } 113 | 114 | return eofToken, nil 115 | } 116 | 117 | func NewLexer() *Lexer { 118 | 119 | return &Lexer{ 120 | pos: DefaultTokenPos, 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | type TokenMatcher interface { 4 | Match(*Tokenizer) (Token, error) 5 | ID() int 6 | String() string 7 | } 8 | 9 | type baseMatcher struct { 10 | id int 11 | } 12 | 13 | func (self *baseMatcher) ID() int { 14 | return self.id 15 | } 16 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_backticks.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "bytes" 5 | "reflect" 6 | ) 7 | 8 | // 字符串 9 | type BackTicksMatcher struct { 10 | baseMatcher 11 | builder bytes.Buffer 12 | } 13 | 14 | func (self *BackTicksMatcher) String() string { 15 | return reflect.TypeOf(self).Elem().Name() 16 | } 17 | 18 | func (self *BackTicksMatcher) Match(tz *Tokenizer) (Token, error) { 19 | 20 | if tz.Current() != '`' { 21 | return EmptyToken, nil 22 | } 23 | 24 | tz.ConsumeOne() 25 | 26 | begin := tz.Index() 27 | 28 | for { 29 | 30 | if tz.Current() == '`' { 31 | tz.ConsumeOne() 32 | break 33 | } 34 | 35 | if tz.Current() == 0 { 36 | break 37 | } 38 | 39 | tz.ConsumeOne() 40 | 41 | } 42 | 43 | return NewToken(self, tz, tz.StringRange(begin, tz.index-1), ""), nil 44 | } 45 | 46 | func NewBackTicksMatcher(id int) TokenMatcher { 47 | return &BackTicksMatcher{ 48 | baseMatcher: baseMatcher{id}, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_cstylecomment.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import "reflect" 4 | 5 | // #开头的行注释 6 | type CStyleCommentMatcher struct { 7 | baseMatcher 8 | } 9 | 10 | func (self *CStyleCommentMatcher) String() string { 11 | return reflect.TypeOf(self).Elem().Name() 12 | } 13 | 14 | func (self *CStyleCommentMatcher) Match(tz *Tokenizer) (Token, error) { 15 | if tz.Current() != '/' || tz.Peek(1) != '/' { 16 | return EmptyToken, nil 17 | } 18 | 19 | tz.ConsumeOne() 20 | 21 | begin := tz.Index() 22 | 23 | for { 24 | 25 | tz.ConsumeOne() 26 | 27 | if tz.Current() == '\n' || tz.Current() == 0 { 28 | break 29 | } 30 | 31 | } 32 | 33 | return NewToken(self, tz, tz.StringRange(begin, tz.index), ""), nil 34 | } 35 | 36 | func NewCStyleCommentMatcher(id int) TokenMatcher { 37 | return &CStyleCommentMatcher{ 38 | baseMatcher{id}, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_identifier.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "reflect" 5 | "unicode" 6 | ) 7 | 8 | // 标识符 9 | type IdentifierMatcher struct { 10 | baseMatcher 11 | } 12 | 13 | func (self *IdentifierMatcher) String() string { 14 | return reflect.TypeOf(self).Elem().Name() 15 | } 16 | 17 | func (self *IdentifierMatcher) Match(tz *Tokenizer) (Token, error) { 18 | 19 | if !unicode.IsLetter(tz.Current()) && tz.Current() != '_' { 20 | return EmptyToken, nil 21 | } 22 | 23 | begin := tz.Index() 24 | 25 | for { 26 | 27 | tz.ConsumeOne() 28 | 29 | if !(unicode.IsLetter(tz.Current()) || unicode.IsDigit(tz.Current())) && tz.Current() != '_' { 30 | break 31 | } 32 | 33 | } 34 | 35 | return NewToken(self, tz, tz.StringRange(begin, tz.index), ""), nil 36 | } 37 | 38 | func NewIdentifierMatcher(id int) TokenMatcher { 39 | return &IdentifierMatcher{ 40 | baseMatcher{id}, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_keyword.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unicode" 7 | ) 8 | 9 | // 下划线和字母(中文)+数字=关键字 10 | type KeywordMatcher struct { 11 | baseMatcher 12 | word []rune 13 | } 14 | 15 | func isKeyword(r rune, index int) bool { 16 | basic := unicode.IsLetter(r) || r == '_' 17 | if index == 0 { 18 | return basic 19 | } 20 | 21 | return basic || unicode.IsDigit(r) 22 | } 23 | 24 | func (self *KeywordMatcher) String() string { 25 | return fmt.Sprintf("%s('%s')", reflect.TypeOf(self).Elem().Name(), string(self.word)) 26 | } 27 | 28 | func (self *KeywordMatcher) Match(tz *Tokenizer) (Token, error) { 29 | 30 | if (tz.Count() - tz.Index()) < len(self.word) { 31 | return EmptyToken, nil 32 | } 33 | 34 | var index int 35 | 36 | for _, c := range self.word { 37 | 38 | if !isKeyword(c, index) { 39 | return EmptyToken, nil 40 | } 41 | 42 | if tz.Peek(index) != c { 43 | return EmptyToken, nil 44 | } 45 | 46 | index++ 47 | 48 | } 49 | 50 | tz.ConsumeMulti(len(self.word)) 51 | 52 | return NewToken(self, tz, string(self.word), ""), nil 53 | } 54 | 55 | func NewKeywordMatcher(id int, word string) TokenMatcher { 56 | 57 | if len(word) == 0 { 58 | panic("empty string") 59 | } 60 | 61 | self := &KeywordMatcher{ 62 | baseMatcher: baseMatcher{id}, 63 | word: []rune(word), 64 | } 65 | 66 | for i, c := range self.word { 67 | if !isKeyword(c, i) { 68 | panic("not keyword") 69 | } 70 | } 71 | 72 | return self 73 | } 74 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_lineend.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import "reflect" 4 | 5 | // 行结束 6 | type LineEndMatcher struct { 7 | baseMatcher 8 | } 9 | 10 | func (self *LineEndMatcher) String() string { 11 | return reflect.TypeOf(self).Elem().Name() 12 | } 13 | 14 | func (self *LineEndMatcher) Match(tz *Tokenizer) (Token, error) { 15 | 16 | var count int 17 | for { 18 | 19 | c := tz.Peek(count) 20 | 21 | if c == '\n' { 22 | tz.increaseLine() 23 | } else if c == '\r' { 24 | 25 | } else { 26 | break 27 | } 28 | 29 | count++ 30 | 31 | } 32 | 33 | if count == 0 { 34 | return EmptyToken, nil 35 | } 36 | 37 | tz.ConsumeMulti(count) 38 | 39 | return NewToken(self, tz, "\r", ""), nil 40 | } 41 | 42 | func NewLineEndMatcher(id int) TokenMatcher { 43 | return &LineEndMatcher{ 44 | baseMatcher{id}, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_numeral.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | "unicode" 7 | ) 8 | 9 | // 整形,浮点数 10 | type NumeralMatcher struct { 11 | baseMatcher 12 | includeNagtive bool 13 | } 14 | 15 | func (self *NumeralMatcher) String() string { 16 | return reflect.TypeOf(self).Elem().Name() 17 | } 18 | 19 | func (self *NumeralMatcher) Match(tz *Tokenizer) (Token, error) { 20 | 21 | if !(unicode.IsDigit(tz.Current()) || (self.includeNagtive && tz.Current() == '-')) { 22 | 23 | return EmptyToken, nil 24 | } 25 | 26 | begin := tz.Index() 27 | 28 | var maybeFloat bool 29 | 30 | for { 31 | 32 | tz.ConsumeOne() 33 | 34 | if !unicode.IsDigit(tz.Current()) { 35 | 36 | if tz.Current() == '.' { 37 | maybeFloat = true 38 | } 39 | 40 | break 41 | } 42 | 43 | } 44 | 45 | if maybeFloat { 46 | for i := 0; ; i++ { 47 | 48 | tz.ConsumeOne() 49 | 50 | if !unicode.IsDigit(tz.Current()) { 51 | 52 | // .之后的第一个字符居然不是数字 53 | if i == 0 { 54 | return EmptyToken, errors.New("invalid numeral") 55 | } 56 | 57 | break 58 | 59 | } 60 | 61 | } 62 | } 63 | 64 | return NewToken(self, tz, tz.StringRange(begin, tz.Index()), ""), nil 65 | } 66 | 67 | func NewNumeralMatcher(id int) TokenMatcher { 68 | return &NumeralMatcher{ 69 | baseMatcher: baseMatcher{id}, 70 | includeNagtive: true, 71 | } 72 | } 73 | 74 | func NewPositiveNumeralMatcher(id int) TokenMatcher { 75 | return &NumeralMatcher{ 76 | baseMatcher: baseMatcher{id}, 77 | includeNagtive: false, 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_sign.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unicode" 7 | ) 8 | 9 | // 操作符,分隔符 10 | type SignMatcher struct { 11 | baseMatcher 12 | word []rune 13 | } 14 | 15 | func isSign(r rune) bool { 16 | return !unicode.IsLetter(r) && 17 | !unicode.IsDigit(r) && 18 | r != ' ' && 19 | r != '\r' && 20 | r != '\n' 21 | } 22 | func (self *SignMatcher) String() string { 23 | return fmt.Sprintf("%s('%s')", reflect.TypeOf(self).Elem().Name(), string(self.word)) 24 | } 25 | 26 | func (self *SignMatcher) Match(tz *Tokenizer) (Token, error) { 27 | 28 | if (tz.Count() - tz.Index()) < len(self.word) { 29 | return EmptyToken, nil 30 | } 31 | 32 | for i, c := range self.word { 33 | 34 | if !isSign(c) { 35 | return EmptyToken, nil 36 | } 37 | 38 | if tz.Peek(i) != c { 39 | return EmptyToken, nil 40 | } 41 | 42 | } 43 | 44 | tz.ConsumeMulti(len(self.word)) 45 | 46 | return NewToken(self, tz, string(self.word), ""), nil 47 | } 48 | 49 | func NewSignMatcher(id int, word string) TokenMatcher { 50 | self := &SignMatcher{ 51 | baseMatcher: baseMatcher{id}, 52 | word: []rune(word), 53 | } 54 | 55 | for _, c := range self.word { 56 | if !isSign(c) { 57 | panic("not sign") 58 | } 59 | } 60 | 61 | return self 62 | } 63 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_string.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "bytes" 5 | "reflect" 6 | ) 7 | 8 | // 字符串 9 | type StringMatcher struct { 10 | baseMatcher 11 | builder bytes.Buffer 12 | } 13 | 14 | func (self *StringMatcher) String() string { 15 | return reflect.TypeOf(self).Elem().Name() 16 | } 17 | 18 | func (self *StringMatcher) Match(tz *Tokenizer) (Token, error) { 19 | 20 | if tz.Current() != '"' && tz.Current() != '\'' { 21 | return EmptyToken, nil 22 | } 23 | 24 | beginChar := tz.Current() 25 | 26 | begin := tz.Index() 27 | 28 | tz.ConsumeOne() 29 | 30 | var escaping bool 31 | 32 | self.builder.Reset() 33 | 34 | for { 35 | 36 | if escaping { 37 | switch tz.Current() { 38 | case 'n': 39 | self.builder.WriteRune('\n') 40 | case 'r': 41 | self.builder.WriteRune('\r') 42 | case '"', '\'': 43 | self.builder.WriteRune(tz.Current()) 44 | default: 45 | self.builder.WriteRune('\\') 46 | self.builder.WriteRune(tz.Current()) 47 | } 48 | 49 | escaping = false 50 | } else if tz.Current() != beginChar { 51 | if tz.Current() == '\\' { 52 | escaping = true 53 | } else { 54 | self.builder.WriteRune(tz.Current()) 55 | } 56 | } else { 57 | break 58 | } 59 | 60 | tz.ConsumeOne() 61 | 62 | if tz.Current() == '\n' || 63 | tz.Current() == 0 { 64 | break 65 | } 66 | 67 | } 68 | 69 | tz.ConsumeOne() 70 | 71 | return NewToken(self, tz, self.builder.String(), tz.StringRange(begin, tz.Index())), nil 72 | } 73 | 74 | func NewStringMatcher(id int) TokenMatcher { 75 | return &StringMatcher{ 76 | baseMatcher: baseMatcher{id}, 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_unixstylecomment.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import "reflect" 4 | 5 | // #开头的行注释 6 | type UnixStyleCommentMatcher struct { 7 | baseMatcher 8 | } 9 | 10 | func (self *UnixStyleCommentMatcher) String() string { 11 | return reflect.TypeOf(self).Elem().Name() 12 | } 13 | 14 | func (self *UnixStyleCommentMatcher) Match(tz *Tokenizer) (Token, error) { 15 | if tz.Current() != '#' { 16 | return EmptyToken, nil 17 | } 18 | 19 | tz.ConsumeOne() 20 | 21 | begin := tz.Index() 22 | 23 | for { 24 | 25 | tz.ConsumeOne() 26 | 27 | if tz.Current() == '\n' || tz.Current() == 0 { 28 | break 29 | } 30 | 31 | } 32 | 33 | return NewToken(self, tz, tz.StringRange(begin, tz.index), ""), nil 34 | } 35 | 36 | func NewUnixStyleCommentMatcher(id int) TokenMatcher { 37 | return &UnixStyleCommentMatcher{ 38 | baseMatcher{id}, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_unknown.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import "reflect" 4 | 5 | // 未知字符 6 | type UnknownMatcher struct { 7 | baseMatcher 8 | } 9 | 10 | func (self *UnknownMatcher) String() string { 11 | return reflect.TypeOf(self).Elem().Name() 12 | } 13 | 14 | func (self *UnknownMatcher) Match(tz *Tokenizer) (Token, error) { 15 | 16 | if tz.Current() == 0 { 17 | return EmptyToken, nil 18 | } 19 | 20 | begin := tz.Index() 21 | 22 | tz.ConsumeOne() 23 | 24 | return NewToken(self, tz, tz.StringRange(begin, tz.Index()), ""), nil 25 | } 26 | 27 | func NewUnknownMatcher(id int) TokenMatcher { 28 | return &UnknownMatcher{ 29 | baseMatcher{id}, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/matcher_whitespace.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import "reflect" 4 | 5 | // 空白字符 6 | type WhiteSpaceMatcher struct { 7 | baseMatcher 8 | } 9 | 10 | func (self *WhiteSpaceMatcher) String() string { 11 | return reflect.TypeOf(self).Elem().Name() 12 | } 13 | 14 | func isWhiteSpace(c rune) bool { 15 | return c == ' ' || c == '\t' 16 | } 17 | 18 | func (self *WhiteSpaceMatcher) Match(tz *Tokenizer) (Token, error) { 19 | 20 | var count int 21 | 22 | var ret rune 23 | for { 24 | 25 | c := tz.Peek(count) 26 | 27 | if !isWhiteSpace(c) { 28 | break 29 | } 30 | 31 | count++ 32 | ret += c 33 | } 34 | 35 | if count == 0 { 36 | return EmptyToken, nil 37 | } 38 | 39 | tz.ConsumeMulti(count) 40 | 41 | return NewToken(self, tz, string(ret), ""), nil 42 | } 43 | 44 | func NewWhiteSpaceMatcher(id int) TokenMatcher { 45 | return &WhiteSpaceMatcher{ 46 | baseMatcher{id}, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/parser.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import "errors" 4 | 5 | type Parser struct { 6 | lexer *Lexer 7 | 8 | curr Token 9 | 10 | errFunc func(error) 11 | 12 | prePos TokenPos 13 | } 14 | 15 | func (self *Parser) Lexer() *Lexer { 16 | return self.lexer 17 | } 18 | 19 | func (self *Parser) TokenPos() TokenPos { 20 | return self.lexer.pos 21 | } 22 | func (self *Parser) PreTokenPos() TokenPos { 23 | return self.prePos 24 | } 25 | 26 | func (self *Parser) Expect(id int) Token { 27 | 28 | if self.TokenID() != id { 29 | panic(errors.New("Expect " + self.lexer.MatcherString(id))) 30 | } 31 | 32 | t := self.curr 33 | 34 | self.NextToken() 35 | 36 | return t 37 | } 38 | 39 | func (self *Parser) NextToken() { 40 | 41 | self.prePos = self.lexer.pos 42 | 43 | token, err := self.lexer.Read() 44 | 45 | if err != nil { 46 | panic(err) 47 | } 48 | 49 | self.curr = token 50 | } 51 | 52 | func (self *Parser) RawToken() Token { 53 | return self.curr 54 | } 55 | 56 | func (self *Parser) TokenID() int { 57 | return self.curr.MatcherID() 58 | } 59 | 60 | func (self *Parser) TokenValue() string { 61 | return self.curr.Value() 62 | } 63 | 64 | func (self *Parser) MatcherName() string { 65 | return self.curr.MatcherName() 66 | } 67 | 68 | func (self *Parser) MatcherString() string { 69 | return self.curr.MatcherString() 70 | } 71 | 72 | func (self *Parser) TokenRaw() string { 73 | 74 | return self.curr.Raw() 75 | } 76 | 77 | func NewParser(l *Lexer, srcName string) *Parser { 78 | 79 | self := &Parser{ 80 | lexer: l, 81 | } 82 | 83 | self.lexer.pos.SourceName = srcName 84 | 85 | return self 86 | 87 | } 88 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/tokenizer.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | type Tokenizer struct { 4 | src []rune 5 | index int 6 | lex *Lexer 7 | } 8 | 9 | func (self *Tokenizer) Current() rune { 10 | 11 | if self.EOF() { 12 | return 0 13 | } 14 | 15 | return self.src[self.index] 16 | } 17 | 18 | func (self *Tokenizer) Index() int { 19 | return self.index 20 | } 21 | 22 | func (self *Tokenizer) Count() int { 23 | return len(self.src) 24 | } 25 | 26 | func (self *Tokenizer) Line() int { 27 | return self.lex.pos.Line 28 | } 29 | 30 | func (self *Tokenizer) Peek(offset int) rune { 31 | 32 | if self.index+offset >= len(self.src) { 33 | return 0 34 | } 35 | 36 | return self.src[self.index+offset] 37 | } 38 | 39 | func (self *Tokenizer) ConsumeOne() { 40 | 41 | self.index++ 42 | self.lex.pos.Col++ 43 | } 44 | 45 | func (self *Tokenizer) ConsumeMulti(count int) { 46 | 47 | self.index += count 48 | self.lex.pos.Col += count 49 | } 50 | 51 | func (self *Tokenizer) EOF() bool { 52 | return self.index >= len(self.src) 53 | } 54 | 55 | func (self *Tokenizer) increaseLine() { 56 | self.lex.pos.Line++ 57 | self.lex.pos.Col = 1 58 | } 59 | 60 | func (self *Tokenizer) StringRange(begin, end int) string { 61 | 62 | if begin < 0 { 63 | begin = 0 64 | } 65 | 66 | if end > len(self.src) { 67 | end = len(self.src) 68 | } 69 | 70 | return string(self.src[begin:end]) 71 | } 72 | 73 | func NewTokenizer(s string, l *Lexer) *Tokenizer { 74 | 75 | return &Tokenizer{ 76 | src: []rune(s), 77 | lex: l, 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golexer/tokenpos.go: -------------------------------------------------------------------------------- 1 | package golexer 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var DefaultTokenPos = TokenPos{Line: 1, Col: 1} 8 | 9 | type TokenPos struct { 10 | Line int 11 | Col int 12 | SourceName string 13 | } 14 | 15 | func (self TokenPos) String() string { 16 | return fmt.Sprintf("%s(%d:%d)", self.SourceName, self.Line, self.Col) 17 | } 18 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golog/README.md: -------------------------------------------------------------------------------- 1 | # golog 2 | 本日志库初期为本人的golang提供日志支持 3 | 4 | 基础代码基于golang的官方日志库修改 5 | 6 | # 主要功能 7 | 8 | * 增加了log级别设置 9 | 10 | * 去掉默认全局日志接口,使用日志需要实例化给出模块名方便跟踪 11 | 12 | * 可根据模块名设定所有模块日志的层级方便切换想看到的日志 13 | 14 | * 根据内容标记日志颜色 15 | 16 | 17 | # 安装方法 18 | 19 | go get github.com/davyxu/golog 20 | 21 | # 使用方法 22 | 23 | * 基本使用 24 | 25 | var log *golog.Logger = golog.New("test") 26 | 27 | log.Debugln("hello world") 28 | 29 | * 层级设置 30 | 31 | golog.SetLevelByString( "test", "info") 32 | 33 | 34 | # 备注 35 | 36 | 感觉不错请star, 谢谢! 37 | 38 | 博客: http://www.cppblog.com/sunicdavy 39 | 40 | 知乎: http://www.zhihu.com/people/sunicdavy 41 | 42 | 邮箱: sunicdavy@qq.com 43 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golog/color.go: -------------------------------------------------------------------------------- 1 | package golog 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | type Color int 10 | 11 | const ( 12 | Color_None Color = iota 13 | Color_Black 14 | Color_Red 15 | Color_Green 16 | Color_Yellow 17 | Color_Blue 18 | Color_Purple 19 | Color_DarkGreen 20 | Color_White 21 | ) 22 | 23 | var logColorPrefix = []string{ 24 | "", 25 | "\x1b[030m", 26 | "\x1b[031m", 27 | "\x1b[032m", 28 | "\x1b[033m", 29 | "\x1b[034m", 30 | "\x1b[035m", 31 | "\x1b[036m", 32 | "\x1b[037m", 33 | } 34 | 35 | var colorByName = map[string]Color{ 36 | "none": Color_None, 37 | "black": Color_Black, 38 | "red": Color_Red, 39 | "green": Color_Green, 40 | "yellow": Color_Yellow, 41 | "blue": Color_Blue, 42 | "purple": Color_Purple, 43 | "darkgreen": Color_DarkGreen, 44 | "white": Color_White, 45 | } 46 | 47 | func matchColor(name string) Color { 48 | 49 | lower := strings.ToLower(name) 50 | 51 | for cname, c := range colorByName { 52 | 53 | if cname == lower { 54 | return c 55 | } 56 | } 57 | 58 | return Color_None 59 | } 60 | 61 | func ColorFromLevel(l Level) Color { 62 | switch l { 63 | case Level_Warn: 64 | return Color_Yellow 65 | case Level_Error, Level_Fatal: 66 | return Color_Red 67 | } 68 | 69 | return Color_None 70 | } 71 | 72 | var logColorSuffix = "\x1b[0m" 73 | 74 | type ColorMatch struct { 75 | Text string 76 | Color string 77 | 78 | c Color 79 | } 80 | 81 | type ColorFile struct { 82 | Rule []*ColorMatch 83 | } 84 | 85 | func (self *ColorFile) ColorFromText(text string) Color { 86 | 87 | for _, rule := range self.Rule { 88 | if strings.Contains(text, rule.Text) { 89 | return rule.c 90 | } 91 | } 92 | 93 | return Color_None 94 | } 95 | 96 | func (self *ColorFile) Load(data string) error { 97 | 98 | err := json.Unmarshal([]byte(data), self) 99 | if err != nil { 100 | return err 101 | } 102 | 103 | for _, rule := range self.Rule { 104 | 105 | rule.c = matchColor(rule.Color) 106 | 107 | if rule.c == Color_None { 108 | return fmt.Errorf("color name not exists: %s", rule.Text) 109 | } 110 | 111 | } 112 | 113 | return nil 114 | } 115 | 116 | func NewColorFile() *ColorFile { 117 | return &ColorFile{} 118 | } 119 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golog/color_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "Rule":[ 3 | {"Text":"panic:","Color":"Red"}, 4 | {"Text":"[DB]","Color":"Green"}, 5 | {"Text":"#recv","Color":"Blue"}, 6 | {"Text":"#send","Color":"Purple"}, 7 | {"Text":"#connected","Color":"Blue"}, 8 | {"Text":"#listen","Color":"Blue"}, 9 | {"Text":"#accepted","Color":"Blue"}, 10 | {"Text":"#closed","Color":"Blue"}, 11 | {"Text":"agent->backend","Color":"White"}, 12 | {"Text":"backend->agent","Color":"White"}, 13 | {"Text":"client->backend","Color":"White"}, 14 | {"Text":"backend->client","Color":"White"} 15 | ] 16 | } -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golog/level.go: -------------------------------------------------------------------------------- 1 | package golog 2 | 3 | type Level int 4 | 5 | const ( 6 | Level_Debug Level = iota 7 | Level_Info 8 | Level_Warn 9 | Level_Error 10 | Level_Fatal 11 | ) 12 | 13 | var levelString = [...]string{ 14 | "[DEBUG]", 15 | "[INFO]", 16 | "[WARN]", 17 | "[ERROR]", 18 | "[FATAL]", 19 | } 20 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/golog/log_test.go: -------------------------------------------------------------------------------- 1 | package golog 2 | 3 | import ( 4 | "log" 5 | "testing" 6 | ) 7 | 8 | func TestLevel(t *testing.T) { 9 | 10 | logex := New("test") 11 | logex.Debugf("%d %s %v", 1, "hello") 12 | 13 | logex.Errorln("hello1") 14 | 15 | logex.Errorln("2") 16 | 17 | logex.Infoln("no") 18 | 19 | } 20 | 21 | func TestMyLog(t *testing.T) { 22 | 23 | logex := New("test") 24 | logex.Debugln("hello1") 25 | logex.DebugColorln("blue", "hello2") 26 | logex.Debugln("hello3") 27 | 28 | } 29 | 30 | func TestSystemLog(t *testing.T) { 31 | 32 | log.Println("hello1") 33 | log.Println("hello2") 34 | log.Println("hello3") 35 | 36 | } 37 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/.gitignore: -------------------------------------------------------------------------------- 1 | debug.test 2 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Davy xu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/README.md: -------------------------------------------------------------------------------- 1 | # goobjfmt 2 | 3 | Marshal struct input text format( protobuf text ) 4 | 5 | like 6 | key : value 7 | 8 | key has no "" 9 | 10 | string value should have "" 11 | 12 | # Example 13 | 14 | ```golang 15 | input := &MyData{ 16 | Name: "genji", 17 | Type: MyCar_Pig, 18 | Uint32: math.MaxUint32, 19 | Int64: math.MaxInt64, 20 | Uint64: math.MaxUint64, 21 | } 22 | 23 | t.Log(MarshalTextString(input)) 24 | ``` 25 | 26 | # Feedback 27 | 28 | Star me if you like or use, thanks 29 | 30 | blog(Chinese): [http://www.cppblog.com/sunicdavy](http://www.cppblog.com/sunicdavy) 31 | 32 | zhihu(Chinese): [http://www.zhihu.com/people/sunicdavy](http://www.zhihu.com/people/sunicdavy) 33 | 34 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/binary_reader.go: -------------------------------------------------------------------------------- 1 | package goobjfmt 2 | 3 | import ( 4 | "encoding/binary" 5 | "reflect" 6 | ) 7 | 8 | func BinaryRead(data []byte, obj interface{}) error { 9 | 10 | if len(data) == 0 { 11 | return nil 12 | } 13 | 14 | v := reflect.ValueOf(obj) 15 | 16 | switch v.Kind() { 17 | case reflect.Ptr: 18 | v = v.Elem() 19 | } 20 | 21 | size := dataSize(v, nil) 22 | if size < 0 { 23 | return ErrInvalidType 24 | } 25 | 26 | if len(data) < size { 27 | return ErrOutOfData 28 | } 29 | 30 | d := &decoder{order: binary.LittleEndian, buf: data} 31 | d.value(v) 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/binary_size.go: -------------------------------------------------------------------------------- 1 | package goobjfmt 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func dataSize(v reflect.Value, sf *reflect.StructField) int { 8 | 9 | switch v.Kind() { 10 | case reflect.Array: 11 | if s := dataSize(v.Elem(), nil); s >= 0 { 12 | return s*v.Type().Len() + 4 13 | } 14 | case reflect.Slice: 15 | l := v.Len() 16 | elemSize := int(v.Type().Elem().Size()) 17 | return l*elemSize + 4 18 | 19 | case reflect.String: 20 | t := v.Len() 21 | return t + 4 22 | case reflect.Bool, 23 | reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 24 | reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 25 | reflect.Float32, reflect.Float64: 26 | return int(v.Type().Size()) 27 | case reflect.Struct: 28 | sum := 0 29 | 30 | st := v.Type() 31 | 32 | for i := 0; i < v.NumField(); i++ { 33 | 34 | fv := v.Field(i) 35 | 36 | sf := st.Field(i) 37 | 38 | s := dataSize(fv, &sf) 39 | if s < 0 { 40 | return -1 41 | } 42 | sum += s 43 | } 44 | return sum 45 | 46 | case reflect.Int: 47 | panic("do not support int, use int32/int64 instead") 48 | //case reflect.Ptr: 49 | // ev := v.Elem() 50 | // 51 | // return dataSize(ev, sf) 52 | //case reflect.Invalid: 53 | // return 0 54 | //case reflect.Interface: 55 | return 0 56 | default: 57 | 58 | if sf != nil && sf.Tag.Get("binary") == "-" { 59 | return 0 60 | } else { 61 | panic("size: unsupport kind: " + v.Kind().String()) 62 | } 63 | 64 | } 65 | 66 | return -1 67 | } 68 | 69 | func BinarySize(obj interface{}) int { 70 | v := reflect.Indirect(reflect.ValueOf(obj)) 71 | return dataSize(v, nil) 72 | } 73 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/binary_test.go: -------------------------------------------------------------------------------- 1 | package goobjfmt 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | type P struct { 9 | X, Y, Z int32 10 | 11 | Name string 12 | } 13 | 14 | //func TestPtr(t *testing.T) { 15 | // 16 | // var v int32 = 100 17 | // 18 | // data, err := BinaryWrite(&struct { 19 | // Ignore *int32 20 | // }{ 21 | // &v, 22 | // }) 23 | // 24 | // if err != nil { 25 | // fmt.Println(err) 26 | // } else { 27 | // fmt.Println(data) 28 | // } 29 | // 30 | // var out struct { 31 | // Ignore *int32 32 | // } 33 | // 34 | // err = BinaryRead(data, &out) 35 | // 36 | // if err != nil { 37 | // fmt.Println(err) 38 | // } else { 39 | // fmt.Println(*out.Ignore) 40 | // } 41 | // 42 | // if *out.Ignore != v { 43 | // t.FailNow() 44 | // } 45 | // 46 | //} 47 | 48 | func TestBinaryIgnore(t *testing.T) { 49 | 50 | data, err := BinaryWrite(&struct { 51 | Ignore int32 `binary:"-"` 52 | }{ 53 | 100, 54 | }) 55 | 56 | if err != nil { 57 | fmt.Println(err) 58 | } else { 59 | fmt.Println(data) 60 | } 61 | } 62 | 63 | func TestWrite(t *testing.T) { 64 | 65 | var input P 66 | input.Name = "hello" 67 | input.X = 4 68 | 69 | data, err := BinaryWrite(&input) 70 | 71 | if err != nil { 72 | fmt.Println(err) 73 | } else { 74 | fmt.Println(data) 75 | } 76 | 77 | var p2 P 78 | err = BinaryRead(data, &p2) 79 | 80 | if err != nil { 81 | fmt.Println(err) 82 | } else { 83 | fmt.Println(p2) 84 | } 85 | } 86 | 87 | type RemoteCallACK struct { 88 | MsgID uint32 89 | Data []byte 90 | CallID int32 91 | } 92 | 93 | func TestWrite2(t *testing.T) { 94 | 95 | input := &RemoteCallACK{123, []byte{1, 34}, 34} 96 | 97 | data, err := BinaryWrite(input) 98 | 99 | if err != nil { 100 | fmt.Println(err) 101 | } else { 102 | fmt.Println(data) 103 | } 104 | 105 | inputsize := BinarySize(input) 106 | 107 | if len(data) != inputsize { 108 | t.Failed() 109 | } 110 | 111 | var p2 RemoteCallACK 112 | err = BinaryRead(data, &p2) 113 | 114 | if err != nil { 115 | fmt.Println(err) 116 | } else { 117 | fmt.Println(p2) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/binary_writer.go: -------------------------------------------------------------------------------- 1 | package goobjfmt 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "reflect" 7 | ) 8 | 9 | var ( 10 | ErrInvalidType = errors.New("invalid type") 11 | ErrOutOfData = errors.New("out of data") 12 | ) 13 | 14 | func BinaryWrite(obj interface{}) ([]byte, error) { 15 | 16 | // Fallback to reflect-based encoding. 17 | v := reflect.Indirect(reflect.ValueOf(obj)) 18 | size := dataSize(v, nil) 19 | if size < 0 { 20 | return nil, ErrInvalidType 21 | } 22 | 23 | buf := make([]byte, size) 24 | 25 | e := &encoder{order: binary.LittleEndian, buf: buf} 26 | e.value(v) 27 | 28 | return buf, nil 29 | } 30 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/lib.go: -------------------------------------------------------------------------------- 1 | package goobjfmt 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "sort" 7 | ) 8 | 9 | type mapKeySorter struct { 10 | vs []reflect.Value 11 | less func(a, b reflect.Value) bool 12 | } 13 | 14 | func (s mapKeySorter) Len() int { return len(s.vs) } 15 | func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } 16 | func (s mapKeySorter) Less(i, j int) bool { 17 | return s.less(s.vs[i], s.vs[j]) 18 | } 19 | 20 | // Map fields may have key types of non-float scalars, strings and enums. 21 | // The easiest way to sort them in some deterministic order is to use fmt. 22 | // If this turns out to be inefficient we can always consider other options, 23 | // such as doing a Schwartzian transform. 24 | 25 | func mapKeys(vs []reflect.Value) sort.Interface { 26 | s := mapKeySorter{ 27 | vs: vs, 28 | // default Less function: textual comparison 29 | less: func(a, b reflect.Value) bool { 30 | return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) 31 | }, 32 | } 33 | 34 | // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; 35 | // numeric keys are sorted numerically. 36 | if len(vs) == 0 { 37 | return s 38 | } 39 | switch vs[0].Kind() { 40 | case reflect.Int32, reflect.Int64: 41 | s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } 42 | case reflect.Uint32, reflect.Uint64: 43 | s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } 44 | } 45 | 46 | return s 47 | } 48 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/goobjfmt/text_marshaler_test.go: -------------------------------------------------------------------------------- 1 | package goobjfmt 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | type MyCar int32 9 | 10 | const ( 11 | MyCar_Monkey MyCar = 1 12 | MyCar_Monk MyCar = 2 13 | MyCar_Pig MyCar = 3 14 | ) 15 | 16 | type MyData struct { 17 | Stream []byte 18 | 19 | Name string 20 | 21 | Type MyCar 22 | 23 | Int32 int32 24 | 25 | Uint32 uint32 26 | 27 | Int64 int64 28 | 29 | Uint64 uint64 30 | } 31 | 32 | type PhoneNumber struct { 33 | Number string 34 | 35 | Type int32 36 | } 37 | 38 | type Person struct { 39 | Name string 40 | 41 | Id int32 42 | 43 | Email string 44 | 45 | Phone []*PhoneNumber 46 | } 47 | 48 | type AddressBook struct { 49 | Person []*Person 50 | 51 | PersonByName map[string]*Person 52 | } 53 | 54 | func TestNumber(t *testing.T) { 55 | 56 | input := &MyData{ 57 | Stream: []byte{1, 2, 3, 4}, 58 | Name: "genji", 59 | Type: MyCar_Pig, 60 | Uint32: math.MaxUint32, 61 | Int64: math.MaxInt64, 62 | Uint64: math.MaxUint64, 63 | } 64 | 65 | t.Log(CompactTextString(input)) 66 | } 67 | 68 | func TestString(t *testing.T) { 69 | t.Log(CompactTextString(&MyData{Name: "源氏"})) 70 | } 71 | 72 | func TestPhone(t *testing.T) { 73 | input := &AddressBook{ 74 | Person: []*Person{ 75 | { 76 | Name: "Alice", 77 | Id: int32(10000), 78 | Phone: []*PhoneNumber{ 79 | { 80 | Number: "123456789", 81 | Type: 1, 82 | }, 83 | { 84 | Number: "87654321", 85 | Type: 2, 86 | }, 87 | }, 88 | }, 89 | { 90 | Name: "Bob", 91 | Id: int32(20000), 92 | Phone: []*PhoneNumber{ 93 | { 94 | Number: "01234567890", 95 | Type: int32(3), 96 | }, 97 | }, 98 | }, 99 | }, 100 | } 101 | 102 | input.PersonByName = make(map[string]*Person) 103 | 104 | for _, v := range input.Person { 105 | 106 | input.PersonByName[v.Name] = v 107 | } 108 | 109 | t.Log(CompactTextString(input)) 110 | 111 | t.Log(MarshalTextString(input)) 112 | 113 | } 114 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | pb2sproto/meta.pb 3 | 4 | example/luadll.dll 5 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Davy xu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/enum.go: -------------------------------------------------------------------------------- 1 | package sproto 2 | 3 | import "strconv" 4 | 5 | func EnumName(m map[int32]string, v int32) string { 6 | s, ok := m[v] 7 | if ok { 8 | return s 9 | } 10 | return strconv.Itoa(int(v)) 11 | } 12 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/example/Make.bat: -------------------------------------------------------------------------------- 1 | set CURR_DIR=%cd% 2 | 3 | : Build generator 4 | cd ..\..\..\..\.. 5 | set GOPATH=%cd% 6 | go build -o %CURR_DIR%\sprotogen.exe github.com/davyxu/gosproto/sprotogen 7 | @IF %ERRORLEVEL% NEQ 0 pause 8 | cd %CURR_DIR% 9 | 10 | : Generate go source file by sproto 11 | sprotogen --go_out=addressbook_gen.go --package=example --cellnet_reg=true addressbook.sp 12 | @IF %ERRORLEVEL% NEQ 0 pause 13 | 14 | : Convert to standard sproto file 15 | : sprotogen --type=sproto --out=addressbook_gen.sproto addressbook.sp 16 | @IF %ERRORLEVEL% NEQ 0 pause 17 | 18 | : Format sp file 19 | : sprotogen --type=sp --out=addressbook_gen.sp addressbook.sp 20 | : @IF %ERRORLEVEL% NEQ 0 pause 21 | 22 | : Generate c# source file by sproto 23 | : sprotogen --type=cs --out=addressbook_gen.cs --package=example addressbook.sp 24 | @IF %ERRORLEVEL% NEQ 0 pause 25 | 26 | : Generate lua source file by sproto 27 | : sprotogen --type=lua --out=addressbook_gen.lua --package=example addressbook.sp 28 | @IF %ERRORLEVEL% NEQ 0 pause -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/example/addressbook.sp: -------------------------------------------------------------------------------- 1 | // extend standard 2 | 3 | 4 | message PhoneNumber { 5 | 6 | // 头注释 7 | number string // 尾注释 8 | 9 | // 整形 10 | type int32 11 | 12 | } 13 | 14 | 15 | message Person { 16 | 17 | name string 18 | 19 | id int32 20 | 21 | email string 22 | 23 | phone []PhoneNumber 24 | 25 | } 26 | 27 | 28 | message AddressBook { 29 | 30 | person []Person 31 | 32 | } 33 | 34 | 35 | enum MyCar { 36 | 37 | Monkey 38 | 39 | Monk 40 | 41 | Pig 42 | 43 | } 44 | 45 | 46 | message MyData { 47 | 48 | name string 49 | 50 | Type MyCar 51 | 52 | Int32 int32 // extend standard 53 | 54 | Uint32 uint32 55 | 56 | Int64 int64 57 | 58 | Uint64 uint64 59 | 60 | Bool bool 61 | 62 | Float32 float32 // [ExtendPrecision]100 # 手动设置精度, 默认1000 63 | 64 | Float64 float64 65 | 66 | Stream bytes 67 | 68 | } 69 | 70 | 71 | message MyProfile { 72 | 73 | nameField MyData 74 | 75 | nameArray []MyData 76 | 77 | nameMap []MyData(Type) 78 | 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/example/addressbook_gen.lua: -------------------------------------------------------------------------------- 1 | -- Generated by github.com/davyxu/gosproto/sprotogen 2 | -- DO NOT EDIT! 3 | 4 | Enum = { 5 | 6 | MyCar = { 7 | ["Monkey"] = 0, 8 | ["Monk"] = 1, 9 | ["Pig"] = 2, 10 | }, 11 | 12 | } 13 | 14 | local sproto = { 15 | Schema = [[ 16 | 17 | .PhoneNumber { 18 | number 0 : string 19 | type 1 : integer 20 | } 21 | 22 | .Person { 23 | name 0 : string 24 | id 1 : integer 25 | email 2 : string 26 | phone 3 : *PhoneNumber 27 | } 28 | 29 | .AddressBook { 30 | person 0 : *Person 31 | } 32 | 33 | .MyData { 34 | name 0 : string 35 | Type 1 : integer 36 | Int32 2 : integer 37 | Uint32 3 : integer 38 | Int64 4 : integer 39 | Uint64 5 : integer 40 | Bool 6 : boolean 41 | Float32 7 : integer 42 | Float64 8 : integer 43 | Stream 9 : string 44 | } 45 | 46 | .MyProfile { 47 | nameField 0 : MyData 48 | nameArray 1 : *MyData 49 | nameMap 2 : *MyData(Type) 50 | } 51 | 52 | ]], 53 | 54 | NameByID = { 55 | [4271979557] = "PhoneNumber", 56 | [1498745430] = "Person", 57 | [2618161298] = "AddressBook", 58 | [2244887298] = "MyData", 59 | [438153711] = "MyProfile", 60 | }, 61 | 62 | IDByName = {}, 63 | 64 | ResetByID = { 65 | [4271979557] = function( obj ) -- PhoneNumber 66 | if obj == nil then return end 67 | obj.number = "" 68 | obj.type = 0 69 | end, 70 | [1498745430] = function( obj ) -- Person 71 | if obj == nil then return end 72 | obj.name = "" 73 | obj.id = 0 74 | obj.email = "" 75 | obj.phone = nil 76 | end, 77 | [2618161298] = function( obj ) -- AddressBook 78 | if obj == nil then return end 79 | obj.person = nil 80 | end, 81 | [2244887298] = function( obj ) -- MyData 82 | if obj == nil then return end 83 | obj.name = "" 84 | obj.Type = 0 85 | obj.Int32 = 0 86 | obj.Uint32 = 0 87 | obj.Int64 = 0 88 | obj.Uint64 = 0 89 | obj.Bool = false 90 | obj.Float32 = 0 91 | obj.Float64 = 0 92 | obj.Stream = nil 93 | end, 94 | [438153711] = function( obj ) -- MyProfile 95 | if obj == nil then return end 96 | obj.nameField = nil 97 | obj.nameArray = nil 98 | obj.nameMap = nil 99 | end, 100 | }, 101 | } 102 | 103 | local t = sproto.IDByName 104 | for k, v in pairs(sproto.NameByID) do 105 | t[v] = k 106 | end 107 | 108 | return sproto 109 | 110 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/example/addressbook_gen.sp: -------------------------------------------------------------------------------- 1 | # Generated by github.com/davyxu/gosproto/sprotogen 2 | # DO NOT EDIT! 3 | 4 | 5 | enum MyCar { 6 | 7 | Monkey = 1 8 | Monk = 2 9 | Pig = 3 10 | } 11 | 12 | 13 | 14 | # [agent] client -> battle # comment 15 | .PhoneNumber { 16 | 17 | # 头 18 | number 0 : string # 哈哈 19 | # 哈哈 20 | # 头 21 | type 1 : int32 22 | } 23 | 24 | 25 | .Person { 26 | 27 | 28 | name 0 : string 29 | 30 | id 1 : int32 31 | 32 | email 2 : string 33 | 34 | phone 3 : *PhoneNumber 35 | } 36 | 37 | 38 | .AddressBook { 39 | 40 | 41 | person 0 : *Person 42 | } 43 | 44 | 45 | .MyData { 46 | 47 | 48 | name 0 string 49 | 50 | type 1 MyCar 51 | 52 | int32 2 int32 // extend standard 53 | # extend standard 54 | uint32 4 uint32 55 | 56 | int64 5 : int64 57 | 58 | uint64 6 : uint64 59 | } 60 | 61 | 62 | .MyProfile { 63 | 64 | 65 | nameField 1 : MyData 66 | 67 | nameArray 2 : *MyData 68 | 69 | nameMap 3 : *MyData(type) 70 | } 71 | 72 | 73 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/example/addressbook_gen.sproto: -------------------------------------------------------------------------------- 1 | # Generated by github.com/davyxu/gosproto/sprotogen 2 | # DO NOT EDIT! 3 | 4 | 5 | .PhoneNumber { 6 | 7 | number 0 : string 8 | 9 | type 1 : integer 10 | 11 | } 12 | 13 | .Person { 14 | 15 | name 0 : string 16 | 17 | id 1 : integer 18 | 19 | email 2 : string 20 | 21 | phone 3 : *PhoneNumber 22 | 23 | } 24 | 25 | .AddressBook { 26 | 27 | person 0 : *Person 28 | 29 | } 30 | 31 | .MyData { 32 | 33 | name 0 : string 34 | 35 | Type 1 : integer 36 | 37 | Int32 2 : integer 38 | 39 | Uint32 3 : integer 40 | 41 | Int64 4 : integer 42 | 43 | Uint64 5 : integer 44 | 45 | Bool 6 : boolean 46 | 47 | Float32 7 : integer 48 | 49 | Float64 8 : integer 50 | 51 | Stream 9 : string 52 | 53 | } 54 | 55 | .MyProfile { 56 | 57 | nameField 0 : MyData 58 | 59 | nameArray 1 : *MyData 60 | 61 | nameMap 2 : *MyData(Type) 62 | 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/example/test.lua: -------------------------------------------------------------------------------- 1 | local a= require "addressbook" 2 | 3 | for k, v in pairs( a.NameByID) do 4 | print(k, v) 5 | end 6 | 7 | for k, v in pairs( a.IDByName) do 8 | print(k, v) 9 | end 10 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/commentgroup.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/davyxu/golexer" 7 | ) 8 | 9 | type TaggedComment struct { 10 | Name string 11 | Value string 12 | } 13 | 14 | type CommentGroup struct { 15 | Pos golexer.TokenPos 16 | 17 | Leading string 18 | Trailing string 19 | 20 | taggedComments []TaggedComment 21 | } 22 | 23 | func (self *CommentGroup) addLineComment(text string) { 24 | 25 | if text == "" { 26 | return 27 | } 28 | 29 | if v, err := parseComment(text); err == nil && v.Name != "" { 30 | self.taggedComments = append(self.taggedComments, v) 31 | } 32 | } 33 | 34 | func (self *CommentGroup) MatchTag(tag string) (string, bool) { 35 | 36 | for _, c := range self.taggedComments { 37 | if c.Name == tag { 38 | return c.Value, true 39 | } 40 | } 41 | 42 | return "", false 43 | 44 | } 45 | 46 | func (self *CommentGroup) String() string { 47 | return fmt.Sprintf("Leading: %s Trailing: %s", self.Leading, self.Trailing) 48 | } 49 | 50 | func newCommentGroup() *CommentGroup { 51 | return &CommentGroup{} 52 | } 53 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/commentparser.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import "github.com/davyxu/golexer" 4 | 5 | // 自定义的token id 6 | const ( 7 | CommentToken_EOF = iota 8 | CommentToken_LeftBrace 9 | CommentToken_RightBrace 10 | CommentToken_WhiteSpace 11 | CommentToken_LineEnd 12 | CommentToken_UnixStyleComment 13 | CommentToken_Identifier 14 | CommentToken_Unknown 15 | ) 16 | 17 | type CommentParser struct { 18 | *golexer.Parser 19 | } 20 | 21 | func parseComment(src string) (ret TaggedComment, retErr error) { 22 | 23 | p := NewCommentParser(src) 24 | 25 | // defer golexer.ErrorCatcher(func(err error) { 26 | 27 | // fmt.Printf("%s %s\n", p.PreTokenPos().String(), err.Error()) 28 | 29 | // retErr = err 30 | 31 | // }) 32 | 33 | p.Lexer().Start(src) 34 | 35 | p.NextToken() 36 | 37 | for p.TokenID() != CommentToken_EOF { 38 | 39 | //log.Debugln("#", self.TokenID(), self.TokenValue()) 40 | 41 | if p.TokenID() == CommentToken_WhiteSpace { 42 | p.NextToken() 43 | continue 44 | } 45 | 46 | // 读取标头 47 | if p.TokenID() == CommentToken_LeftBrace { 48 | 49 | p.NextToken() 50 | 51 | tagNameToken := p.Expect(CommentToken_Identifier) 52 | 53 | p.Expect(CommentToken_RightBrace) 54 | 55 | ret.Name = tagNameToken.Value() 56 | 57 | for { 58 | 59 | ret.Value += p.TokenValue() 60 | 61 | p.NextToken() 62 | 63 | if p.TokenID() == CommentToken_LineEnd || p.TokenID() == CommentToken_EOF { 64 | break 65 | } 66 | } 67 | 68 | } 69 | 70 | p.NextToken() 71 | 72 | } 73 | 74 | return 75 | } 76 | 77 | func NewCommentParser(src string) *CommentParser { 78 | 79 | l := golexer.NewLexer() 80 | 81 | // 匹配顺序从高到低 82 | 83 | l.AddMatcher(golexer.NewSignMatcher(CommentToken_LeftBrace, "[")) 84 | l.AddMatcher(golexer.NewSignMatcher(CommentToken_RightBrace, "]")) 85 | 86 | l.AddMatcher(golexer.NewWhiteSpaceMatcher(CommentToken_WhiteSpace)) 87 | l.AddIgnoreMatcher(golexer.NewLineEndMatcher(CommentToken_LineEnd)) 88 | l.AddIgnoreMatcher(golexer.NewUnixStyleCommentMatcher(CommentToken_UnixStyleComment)) 89 | 90 | l.AddMatcher(golexer.NewIdentifierMatcher(CommentToken_Identifier)) 91 | 92 | l.AddMatcher(golexer.NewUnknownMatcher(CommentToken_Unknown)) 93 | 94 | return &CommentParser{ 95 | Parser: golexer.NewParser(l, src), 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/commentparser_test.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import "testing" 4 | 5 | func TestCommentParser(t *testing.T) { 6 | 7 | v, err := parseComment("[agent] client -> battle # comment") 8 | if err != nil{ 9 | t.Error(err) 10 | t.FailNow() 11 | } 12 | 13 | t.Log(v) 14 | } 15 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/fieldtype.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type FieldType int 8 | 9 | const ( 10 | FieldType_None FieldType = iota 11 | FieldType_Integer 12 | FieldType_Int32 13 | FieldType_Int64 14 | FieldType_UInt32 15 | FieldType_UInt64 16 | FieldType_Bool 17 | FieldType_String 18 | FieldType_Struct 19 | FieldType_Enum 20 | FieldType_Float32 21 | FieldType_Float64 22 | FieldType_Bytes 23 | ) 24 | 25 | var fieldtypeByStr = map[string]FieldType{ 26 | "boolean": FieldType_Bool, 27 | "integer": FieldType_Integer, 28 | "int32": FieldType_Int32, 29 | "int64": FieldType_Int64, 30 | "uint32": FieldType_UInt32, 31 | "uint64": FieldType_UInt64, 32 | "string": FieldType_String, 33 | "struct": FieldType_Struct, 34 | "enum": FieldType_Enum, 35 | "float32": FieldType_Float32, 36 | "float64": FieldType_Float64, 37 | "bytes": FieldType_Bytes, 38 | } 39 | 40 | var strByFieldtype = map[FieldType]string{} 41 | 42 | func init() { 43 | for k, v := range fieldtypeByStr { 44 | strByFieldtype[v] = k 45 | } 46 | } 47 | 48 | func ParseFieldType(str string) FieldType { 49 | 50 | if t, ok := fieldtypeByStr[str]; ok { 51 | return t 52 | } 53 | 54 | if str == "bool" { 55 | return FieldType_Bool 56 | } 57 | 58 | return FieldType_None 59 | } 60 | 61 | func (self FieldType) String() string { 62 | 63 | if v, ok := strByFieldtype[self]; ok { 64 | return v 65 | } 66 | 67 | return fmt.Sprintf("none(%d)", self) 68 | } 69 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/fileset.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | type FileDescriptorSet struct { 4 | Files []*FileDescriptor 5 | 6 | unknownFields []*lazyField 7 | } 8 | 9 | func (self *FileDescriptorSet) resolveAll() error { 10 | 11 | for _, v := range self.unknownFields { 12 | if _, err := v.resolve(2); err != nil { 13 | return err 14 | } 15 | } 16 | 17 | return nil 18 | } 19 | 20 | func (self *FileDescriptorSet) addFile(file *FileDescriptor) { 21 | file.FileSet = self 22 | self.Files = append(self.Files, file) 23 | } 24 | 25 | func (self *FileDescriptorSet) parseType(name string) (ft FieldType, structType *Descriptor) { 26 | 27 | for _, file := range self.Files { 28 | 29 | if ft, structType = file.rawParseType(name); ft != FieldType_None { 30 | return ft, structType 31 | } 32 | } 33 | 34 | return FieldType_None, nil 35 | } 36 | 37 | func NewFileDescriptorSet() *FileDescriptorSet { 38 | return &FileDescriptorSet{} 39 | } 40 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/lazyfield.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/davyxu/golexer" 7 | ) 8 | 9 | type lazyField struct { 10 | typeName string 11 | mainIndexName string 12 | 13 | fd *FieldDescriptor 14 | 15 | d *Descriptor 16 | 17 | tp golexer.TokenPos 18 | 19 | miss bool 20 | } 21 | 22 | func newLazyField(typeName string, fd *FieldDescriptor, d *Descriptor, tp golexer.TokenPos) *lazyField { 23 | return &lazyField{typeName: typeName, 24 | fd: fd, 25 | d: d, 26 | tp: tp} 27 | } 28 | 29 | func (self *lazyField) resolve(pass int) (bool, error) { 30 | 31 | self.fd.Type, self.fd.Complex = self.fd.parseType(self.typeName) 32 | 33 | if self.fd.Type == FieldType_None { 34 | if pass > 1 { 35 | 36 | fmt.Println(self.tp.String()) 37 | 38 | return true, errors.New("type not found: " + self.typeName) 39 | } else { 40 | 41 | self.miss = true 42 | return true, nil 43 | } 44 | } 45 | 46 | if self.mainIndexName != "" { 47 | if indexFd, ok := self.fd.Complex.FieldByName[self.mainIndexName]; ok { 48 | self.fd.MainIndex = indexFd 49 | } else { 50 | if pass > 1 { 51 | return true, errors.New("Main index not found:" + self.mainIndexName) 52 | } else { 53 | return true, nil 54 | } 55 | 56 | } 57 | } 58 | 59 | return false, nil 60 | } 61 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/parse_all.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/davyxu/golexer" 7 | "io/ioutil" 8 | ) 9 | 10 | func ParseFile(fileName string) (*FileDescriptorSet, error) { 11 | 12 | fileset := NewFileDescriptorSet() 13 | 14 | fileD := NewFileDescriptor() 15 | fileD.FileName = fileName 16 | 17 | err := rawPaseFile(fileD, fileName) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | fileset.addFile(fileD) 23 | 24 | return fileset, fileset.resolveAll() 25 | } 26 | 27 | func ParseFileList(fileset *FileDescriptorSet, filelist []string) (string, error) { 28 | 29 | for _, filename := range filelist { 30 | 31 | fileD := NewFileDescriptor() 32 | fileD.FileName = filename 33 | fileset.addFile(fileD) 34 | 35 | if err := rawPaseFile(fileD, filename); err != nil { 36 | return filename, err 37 | } 38 | 39 | } 40 | 41 | return "", fileset.resolveAll() 42 | 43 | } 44 | 45 | // 从文件解析 46 | func rawPaseFile(fileD *FileDescriptor, fileName string) error { 47 | 48 | data, err := ioutil.ReadFile(fileName) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | return rawParse(fileD, string(data), fileName) 54 | } 55 | 56 | // 解析字符串 57 | func rawParse(fileD *FileDescriptor, data string, srcName string) (retErr error) { 58 | 59 | p := newSProtoParser(srcName) 60 | 61 | defer golexer.ErrorCatcher(func(err error) { 62 | 63 | retErr = fmt.Errorf("%s %s", p.PreTokenPos().String(), err.Error()) 64 | 65 | }) 66 | 67 | p.Lexer().Start(data) 68 | 69 | p.NextToken() 70 | 71 | for p.TokenID() != Token_EOF { 72 | 73 | switch p.TokenID() { 74 | case Token_Dot, Token_Message: 75 | parseStruct(p, fileD, srcName) 76 | case Token_Enum: 77 | parseEnum(p, fileD, srcName) 78 | case Token_FileTag: 79 | parseFileTag(p, fileD, srcName) 80 | default: 81 | panic(errors.New("Unknown token: " + p.TokenValue())) 82 | } 83 | 84 | } 85 | 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/parse_enum.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | func parseEnum(p *sprotoParser, fileD *FileDescriptor, srcName string) { 8 | 9 | // enum 10 | enumToken := p.Expect(Token_Enum) 11 | 12 | d := newDescriptor(fileD) 13 | d.Type = DescriptorType_Enum 14 | 15 | // 名字 16 | d.Name = p.Expect(Token_Identifier).Value() 17 | 18 | d.CommentGroup = p.CommentGroupByLine(enumToken.Line()) 19 | 20 | // { 21 | p.Expect(Token_CurlyBraceL) 22 | 23 | for p.TokenID() != Token_CurlyBraceR { 24 | 25 | // 字段 26 | parseEnumField(p, d) 27 | 28 | } 29 | 30 | p.Expect(Token_CurlyBraceR) 31 | 32 | // } 33 | 34 | // 名字重复检查 35 | 36 | if fileD.NameExists(d.Name) { 37 | panic(errors.New("Duplicate name: " + d.Name)) 38 | } 39 | 40 | fileD.addObject(d, srcName) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/parse_enumfield.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import "errors" 4 | 5 | func parseEnumField(p *sprotoParser, d *Descriptor) { 6 | 7 | fd := newFieldDescriptor(d) 8 | 9 | nameToken := p.RawToken() 10 | 11 | // 字段名 12 | fd.Name = p.Expect(Token_Identifier).Value() 13 | 14 | if _, ok := d.FieldByName[fd.Name]; ok { 15 | panic(errors.New("Duplicate field name: " + d.Name)) 16 | } 17 | 18 | // 有等号 19 | if p.TokenID() == Token_Assign { 20 | p.NextToken() 21 | 22 | // tag 23 | fd.Tag = p.Expect(Token_Numeral).ToInt() 24 | 25 | } else { 26 | 27 | if len(d.Fields) == 0 { 28 | fd.AutoTag = 0 29 | } else { 30 | fd.AutoTag = d.MaxTag() + 1 31 | } 32 | 33 | } 34 | 35 | fd.Type = FieldType_Int32 36 | 37 | fd.CommentGroup = p.CommentGroupByLine(nameToken.Line()) 38 | 39 | checkField(d, fd) 40 | 41 | d.addField(fd) 42 | 43 | return 44 | } 45 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/parse_misc.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import "strings" 4 | 5 | func parseFileTag(p *sprotoParser, fileD *FileDescriptor, srcName string) { 6 | 7 | p.Expect(Token_FileTag) 8 | 9 | rawTagStr := p.Expect(Token_String).Value() 10 | for _, tagStr := range strings.Split(rawTagStr, " ") { 11 | fileD.fileTag = append(fileD.fileTag, strings.TrimSpace(tagStr)) 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/parse_struct.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | func parseStruct(p *sprotoParser, fileD *FileDescriptor, srcName string) { 8 | 9 | dotToken := p.RawToken() 10 | 11 | p.NextToken() 12 | 13 | d := newDescriptor(fileD) 14 | d.Type = DescriptorType_Struct 15 | 16 | // 名字 17 | d.Name = p.Expect(Token_Identifier).Value() 18 | 19 | d.CommentGroup = p.CommentGroupByLine(dotToken.Line()) 20 | 21 | // { 22 | p.Expect(Token_CurlyBraceL) 23 | 24 | for p.TokenID() != Token_CurlyBraceR { 25 | 26 | // 字段 27 | parseStructField(p, d) 28 | 29 | } 30 | 31 | p.Expect(Token_CurlyBraceR) 32 | 33 | // } 34 | 35 | // 名字重复检查 36 | 37 | if fileD.NameExists(d.Name) { 38 | panic(errors.New("Duplicate name: " + d.Name)) 39 | } 40 | 41 | fileD.addObject(d, srcName) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/parse_structfield.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func parseStructField(p *sprotoParser, d *Descriptor) { 9 | 10 | fd := newFieldDescriptor(d) 11 | 12 | nameToken := p.RawToken() 13 | // 字段名 14 | fd.Name = p.Expect(Token_Identifier).Value() 15 | 16 | if _, ok := d.FieldByName[fd.Name]; ok { 17 | panic(errors.New("Duplicate field name: " + d.Name)) 18 | } 19 | 20 | if p.TokenID() == Token_Numeral { 21 | // tag 22 | fd.Tag = p.Expect(Token_Numeral).ToInt() 23 | } else { // 没写就自动生成 24 | 25 | if len(d.Fields) == 0 { 26 | fd.AutoTag = 0 27 | } else { 28 | fd.AutoTag = d.MaxTag() + 1 29 | } 30 | 31 | } 32 | 33 | if p.TokenID() == Token_Colon { 34 | p.NextToken() 35 | } 36 | 37 | tp := p.TokenPos() 38 | 39 | var typeName string 40 | 41 | switch p.TokenID() { 42 | // 数组 43 | case Token_Star: 44 | p.NextToken() 45 | 46 | fd.Repeatd = true 47 | 48 | typeName = p.Expect(Token_Identifier).Value() 49 | case Token_BracketL: 50 | p.NextToken() 51 | p.Expect(Token_BracketR) 52 | fd.Repeatd = true 53 | 54 | typeName = p.Expect(Token_Identifier).Value() 55 | 56 | case Token_Identifier: 57 | // 普通字段 58 | typeName = p.TokenValue() 59 | p.NextToken() 60 | break 61 | default: 62 | } 63 | 64 | // 根据类型名查找类型及结构体类型 65 | 66 | pf := newLazyField(typeName, fd, d, tp) 67 | 68 | // map的索引解析 ( 69 | if p.TokenID() == Token_ParenL { 70 | p.NextToken() 71 | 72 | // 索引的字段 73 | pf.mainIndexName = p.Expect(Token_Identifier).Value() 74 | 75 | p.Expect(Token_ParenR) 76 | 77 | } 78 | // ) 79 | 80 | fd.CommentGroup = p.CommentGroupByLine(nameToken.Line()) 81 | 82 | // 尝试首次解析 83 | if need2Pass, _ := pf.resolve(1); need2Pass { 84 | d.File.FileSet.unknownFields = append(d.File.FileSet.unknownFields, pf) 85 | } 86 | 87 | checkField(d, fd) 88 | 89 | d.addField(fd) 90 | 91 | return 92 | } 93 | 94 | func checkField(d *Descriptor, fd *FieldDescriptor) { 95 | 96 | if _, ok := d.FieldByName[fd.Name]; ok { 97 | panic(errors.New(fmt.Sprintf("Duplicate field name: %s in %s", fd.Name, d.Name))) 98 | } 99 | 100 | if _, ok := d.FieldByTag[fd.TagNumber()]; ok { 101 | panic(errors.New(fmt.Sprintf("Duplicate field tag: %d in %s", fd.TagNumber(), d.Name))) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/parser_test.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestParser(t *testing.T) { 9 | 10 | fileD, err := ParseFile("../example/addressbook.sp") 11 | 12 | if err != nil { 13 | t.Log(err) 14 | t.FailNow() 15 | } 16 | 17 | v, _ := fileD.StructByName["PhoneNumber"] 18 | //f, _ := v.FieldByName["number"] 19 | 20 | tag, _ := v.MatchTag("agent") 21 | fmt.Println("tag: ", tag) 22 | 23 | fmt.Println(fileD.String()) 24 | } 25 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/meta/struct.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | ) 7 | 8 | type DescriptorType int 9 | 10 | const ( 11 | DescriptorType_None DescriptorType = iota 12 | DescriptorType_Enum 13 | DescriptorType_Struct 14 | ) 15 | 16 | type Descriptor struct { 17 | *CommentGroup 18 | Name string 19 | SrcName string 20 | Type DescriptorType 21 | 22 | Fields []*FieldDescriptor 23 | FieldByName map[string]*FieldDescriptor 24 | FieldByTag map[int]*FieldDescriptor 25 | 26 | File *FileDescriptor 27 | 28 | TagBase int 29 | 30 | EnumValueIgnoreType bool 31 | } 32 | 33 | func (self *Descriptor) MaxTag() (ret int) { 34 | 35 | for _, fd := range self.Fields { 36 | if fd.TagNumber() > ret { 37 | ret = fd.TagNumber() 38 | } 39 | 40 | } 41 | 42 | return 43 | } 44 | 45 | func (self *Descriptor) TypeName() string { 46 | switch self.Type { 47 | case DescriptorType_Enum: 48 | return "enum" 49 | case DescriptorType_Struct: 50 | return "struct" 51 | } 52 | 53 | return "none" 54 | } 55 | 56 | // c# 要使用的fieldcount 57 | func (self *Descriptor) MaxFieldCount() int { 58 | maxn := len(self.Fields) 59 | lastTag := -1 60 | 61 | for _, fd := range self.Fields { 62 | if fd.TagNumber() < lastTag { 63 | panic(errors.New("tag must in ascending order")) 64 | } 65 | 66 | if fd.TagNumber() > lastTag+1 { 67 | maxn++ 68 | } 69 | 70 | lastTag = fd.TagNumber() 71 | } 72 | 73 | return maxn 74 | } 75 | 76 | func (self *Descriptor) String() string { 77 | 78 | var bf bytes.Buffer 79 | 80 | bf.WriteString(self.Name) 81 | 82 | bf.WriteString(":") 83 | bf.WriteString("\n") 84 | 85 | for _, fd := range self.Fields { 86 | bf.WriteString(" ") 87 | bf.WriteString(fd.String()) 88 | bf.WriteString("\n") 89 | } 90 | 91 | bf.WriteString("\n") 92 | 93 | return bf.String() 94 | } 95 | 96 | func (self *Descriptor) addField(fd *FieldDescriptor) { 97 | self.Fields = append(self.Fields, fd) 98 | self.FieldByName[fd.Name] = fd 99 | self.FieldByTag[fd.Tag] = fd 100 | } 101 | 102 | func newDescriptor(f *FileDescriptor) *Descriptor { 103 | return &Descriptor{ 104 | CommentGroup: newCommentGroup(), 105 | File: f, 106 | FieldByName: make(map[string]*FieldDescriptor), 107 | FieldByTag: make(map[int]*FieldDescriptor), 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/pack_test.go: -------------------------------------------------------------------------------- 1 | package sproto_test 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/davyxu/gosproto" 8 | ) 9 | 10 | type PackTestCase struct { 11 | Name string 12 | Unpacked []byte 13 | Packed []byte 14 | } 15 | 16 | var packTestCases []*PackTestCase = []*PackTestCase{ 17 | &PackTestCase{ 18 | Name: "SimplePack", 19 | Unpacked: []byte{0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x19, 0x00, 0x00, 0x00, 0xaa, 0x01, 0x00, 0x00}, 20 | Packed: []byte{0x51, 0x08, 0x03, 0x02, 0x31, 0x19, 0xaa, 0x01}, 21 | }, 22 | &PackTestCase{ 23 | Name: "FFPack", 24 | Unpacked: bytes.Join([][]byte{ 25 | bytes.Repeat([]byte{0x8a}, 30), 26 | []byte{0x00, 0x00}, 27 | }, nil), 28 | Packed: bytes.Join([][]byte{ 29 | []byte{0xff, 0x03}, 30 | bytes.Repeat([]byte{0x8a}, 30), 31 | []byte{0x00, 0x00}, 32 | }, nil), 33 | }, 34 | } 35 | 36 | func TestPack(t *testing.T) { 37 | var allUnpacked, allPacked []byte 38 | for _, tc := range packTestCases { 39 | packed := sproto.Pack(tc.Unpacked) 40 | if !bytes.Equal(packed, tc.Packed) { 41 | t.Log("packed:", packed) 42 | t.Log("expected:", tc.Packed) 43 | t.Fatalf("test case *%s* failed", tc.Name) 44 | } 45 | allUnpacked = sproto.Append(allUnpacked, tc.Unpacked) 46 | allPacked = sproto.Append(allPacked, packed) 47 | } 48 | 49 | packed := sproto.Pack(allUnpacked) 50 | if !bytes.Equal(packed, allPacked) { 51 | t.Log("packed:", packed) 52 | t.Log("expected:", allPacked) 53 | t.Fatal("test case *total* failed") 54 | } 55 | } 56 | 57 | func TestUnpack(t *testing.T) { 58 | var allUnpacked, allPacked []byte 59 | for _, tc := range packTestCases { 60 | unpacked, err := sproto.Unpack(tc.Packed) 61 | if err != nil { 62 | t.Fatalf("test case *%s* failed with error:%s", tc.Name, err) 63 | } 64 | if !bytes.Equal(unpacked, tc.Unpacked) { 65 | t.Log("unpacked:", unpacked) 66 | t.Log("expected:", tc.Unpacked) 67 | t.Fatalf("test case *%s* failed", tc.Name) 68 | } 69 | allUnpacked = sproto.Append(allUnpacked, tc.Unpacked) 70 | allPacked = sproto.Append(allPacked, tc.Packed) 71 | } 72 | unpacked, err := sproto.Unpack(allPacked) 73 | if err != nil { 74 | t.Fatalf("test case *total* failed with error:%s", err) 75 | } 76 | if !bytes.Equal(unpacked, allUnpacked) { 77 | t.Log("unpacked:", unpacked) 78 | t.Log("expected:", allUnpacked) 79 | t.Fatal("test case *total* failed") 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/pb2sproto/Make.bat: -------------------------------------------------------------------------------- 1 | set CURR_DIR=%cd% 2 | 3 | : Build generator 4 | cd ..\..\..\..\.. 5 | set GOPATH=%cd% 6 | go build -o %CURR_DIR%\protoc-gen-meta.exe github.com/davyxu/pbmeta/protoc-gen-meta 7 | cd %CURR_DIR% 8 | 9 | protoc.exe --plugin=protoc-gen-meta=protoc-gen-meta.exe --meta_out=meta.pb:. --proto_path "." pb.proto 10 | :@IF %ERRORLEVEL% NEQ 0 pause 11 | 12 | go build -o pb2sproto.exe gen_proto.go main.go 13 | 14 | pb2sproto --pbmeta=meta.pb --outdir=. -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/pb2sproto/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/davyxu/pbmeta" 9 | ) 10 | 11 | var paramOut = flag.String("outdir", "", "output directory") 12 | 13 | var paramPBMeta = flag.String("pbmeta", "", "Input Google Protobuf Descripte Binary file format, use protoc generated!") 14 | 15 | func getPbMeta(filename string) (*pbmeta.DescriptorPool, error) { 16 | 17 | // 请先运行ExportPluginMeta导出test.pb 18 | fds, err := pbmeta.LoadFileDescriptorSet(filename) 19 | 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | // 描述池 25 | return pbmeta.NewDescriptorPool(fds), nil 26 | 27 | } 28 | 29 | func main() { 30 | 31 | flag.Parse() 32 | 33 | pool, err := getPbMeta(*paramPBMeta) 34 | if err != nil { 35 | fmt.Println(err) 36 | os.Exit(1) 37 | } 38 | 39 | for fileIndex := 0; fileIndex < pool.FileCount(); fileIndex++ { 40 | 41 | gen_proto(pool.File(fileIndex), *paramOut) 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/pb2sproto/pb.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package gamedef; 4 | 5 | 6 | enum MyCar { 7 | Monkey = 0; 8 | Monk = 1; 9 | Pig = 2; 10 | } 11 | 12 | 13 | // This is phone number 14 | message PhoneNumber { 15 | 16 | string Number = 1; // mobile phone number 17 | 18 | int32 Type = 2; // phone type 19 | } 20 | 21 | // Person 22 | message Person { 23 | 24 | string Name = 1; 25 | 26 | int32 Id = 2; 27 | 28 | string Email = 3; 29 | 30 | repeated PhoneNumber phone = 4; 31 | 32 | bool Staff = 5; 33 | 34 | } 35 | 36 | // All person list 37 | message AddressBook { 38 | 39 | repeated Person person = 1; 40 | 41 | } 42 | 43 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/pb2sproto/pb.sp: -------------------------------------------------------------------------------- 1 | # Generated by github.com/davyxu/gosproto/pb2sproto 2 | # Source: pb.proto 3 | 4 | 5 | 6 | .MyCar { 7 | 8 | Monkey 0 9 | 10 | Monk 1 11 | 12 | Pig 2 13 | 14 | } 15 | 16 | 17 | 18 | # This is phone number 19 | .PhoneNumber { 20 | 21 | Number 1 : string # mobile phone number 22 | 23 | Type 2 : int32 # phone type 24 | 25 | } 26 | 27 | # Person 28 | .Person { 29 | 30 | Name 1 : string 31 | 32 | Id 2 : int32 33 | 34 | Email 3 : string 35 | 36 | phone 4 : *PhoneNumber 37 | 38 | Staff 5 : boolean 39 | 40 | } 41 | 42 | # All person list 43 | .AddressBook { 44 | 45 | person 1 : *Person 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/sproto.go: -------------------------------------------------------------------------------- 1 | package sproto 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | ErrNonPtr = errors.New("sproto: called with Non-Ptr type") 9 | ErrNonStruct = errors.New("sproto: Encode called with Non-Ptr") 10 | ErrNil = errors.New("sproto: Encode called with nil") 11 | ErrDecode = errors.New("sproto: Decode msg failed") 12 | ErrUnpack = errors.New("sproto: Unpack data failed") 13 | ) 14 | 15 | func Append(dst, src []byte) []byte { 16 | l := len(dst) 17 | if l+len(src) > cap(dst) { 18 | // allocate double what's needed, for future growth 19 | buf := make([]byte, (l+len(src))*2) 20 | copy(buf, dst) 21 | dst = buf 22 | } 23 | dst = dst[0 : l+len(src)] 24 | copy(dst[l:], src) 25 | return dst 26 | } 27 | 28 | // encode && pack 29 | func EncodePacked(sp interface{}) ([]byte, error) { 30 | unpacked, err := Encode(sp) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return Pack(unpacked), nil 35 | } 36 | 37 | // unpack && decode 38 | func DecodePacked(data []byte, sp interface{}) error { 39 | unpacked, err := Unpack(data) 40 | if err != nil { 41 | return err 42 | } 43 | _, err = Decode(unpacked, sp) 44 | return err 45 | } 46 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/sprotogen/enumvaluegroup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/gosproto/meta" 6 | "os" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // 本文件内功能仅做项目内部功能使用, 不做通用功能 12 | 13 | func enumValueGroup(fm *fileModel) { 14 | 15 | fileset := fm.FileDescriptorSet 16 | 17 | var maxGroup int64 18 | 19 | var allTagNumbers = map[int]*meta.FieldDescriptor{} 20 | 21 | for _, file := range fileset.Files { 22 | 23 | for _, e := range file.Enums { 24 | 25 | if rawValue, ok := e.MatchTag("EnumValueOffset"); ok { 26 | 27 | if offset, err := strconv.ParseInt(strings.TrimSpace(rawValue), 10, 32); err == nil { 28 | 29 | e.TagBase = int(offset) 30 | 31 | if offset > maxGroup { 32 | maxGroup = offset 33 | } 34 | } 35 | 36 | } 37 | 38 | if strings.HasSuffix(e.Name, "Result") { 39 | 40 | e.EnumValueIgnoreType = true 41 | 42 | //fmt.Printf("%s (%s)\n", e.Name, e.File.FileName) 43 | 44 | for _, fd := range e.Fields { 45 | 46 | //fmt.Printf(" %s = %d\n", fd.Name, fd.TagNumber()) 47 | 48 | if fd.TagNumber() == 0 { 49 | continue 50 | } 51 | 52 | if prev, ok := allTagNumbers[fd.TagNumber()]; ok { 53 | 54 | fmt.Printf("Duplicated enum value: %d %s.%s(%s) prev: %s.%s(%s)\n", fd.TagNumber(), fd.Struct.Name, fd.Name, fd.Struct.File.FileName, prev.Struct.Name, prev.Name, prev.Struct.File.FileName) 55 | os.Exit(1) 56 | } 57 | 58 | allTagNumbers[fd.TagNumber()] = fd 59 | } 60 | 61 | } 62 | 63 | } 64 | 65 | } 66 | 67 | fmt.Printf("max group: %d\n", maxGroup) 68 | 69 | } 70 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/sprotogen/gen_emmylua.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const emmyluaCodeTemplate = `-- Generated by github.com/davyxu/gosproto/sprotogen 4 | -- DO NOT EDIT! 5 | 6 | {{range .Structs}} 7 | ---@class {{.Name}} {{range .StFields}} 8 | ---@field public {{.Name}} {{.CSTypeName}} {{end}} 9 | local {{.Name}} = {} 10 | {{end}} 11 | 12 | ` 13 | 14 | func gen_emmylua(fm *fileModel, filename string) { 15 | 16 | addData(fm, "lua") 17 | 18 | generateCode("sp->emmylua", emmyluaCodeTemplate, filename, fm, nil) 19 | 20 | } 21 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/sprotogen/gen_sproto.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const sprotoCodeTemplate = `# Generated by github.com/davyxu/gosproto/sprotogen 4 | # DO NOT EDIT! 5 | 6 | {{range .Structs}} 7 | .{{.Name}} { 8 | {{range .StFields}} 9 | {{.Name}} {{.TagNumber}} : {{.CompatibleTypeString}} 10 | {{end}} 11 | } 12 | {{end}} 13 | 14 | ` 15 | 16 | func gen_sproto(fm *fileModel, filename string) { 17 | 18 | addData(fm, "sproto") 19 | 20 | generateCode("sp->sproto", sprotoCodeTemplate, filename, fm, nil) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/sprotogen/strhash.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var crcTable []uint32 = make([]uint32, 256) 4 | 5 | const crcPOLY uint32 = 0x04c11db7 6 | 7 | var crcTableInitialized bool = false 8 | 9 | func initCRCTable() { 10 | 11 | if crcTableInitialized { 12 | return 13 | } 14 | 15 | var i uint32 16 | var c uint32 17 | var j uint32 18 | 19 | for i = 0; i < 256; i++ { 20 | 21 | c = (i << 24) 22 | 23 | for j = 8; j != 0; j = j - 1 { 24 | 25 | if (c & 0x80000000) != 0 { 26 | c = (c << 1) ^ crcPOLY 27 | } else { 28 | c = (c << 1) 29 | } 30 | 31 | crcTable[i] = c 32 | } 33 | } 34 | 35 | crcTableInitialized = true 36 | } 37 | 38 | // 字符串转为32位整形值 39 | func StringHash(s string) uint32 { 40 | initCRCTable() 41 | 42 | var hash uint32 43 | var b uint32 44 | 45 | for _, c := range s { 46 | 47 | b = uint32(c) 48 | 49 | hash = ((hash >> 8) & 0x00FFFFFF) ^ crcTable[(hash^b)&0x000000FF] 50 | } 51 | 52 | return hash 53 | } 54 | -------------------------------------------------------------------------------- /server/src/github.com/davyxu/gosproto/sprotogen/util.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/parser" 7 | "go/printer" 8 | "go/token" 9 | "io/ioutil" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | "text/template" 14 | ) 15 | 16 | type generateOption struct { 17 | formatGoCode bool 18 | 19 | outputData []byte 20 | } 21 | 22 | // 字段首字母大写 23 | func publicFieldName(name string) string { 24 | return strings.ToUpper(string(name[0])) + name[1:] 25 | } 26 | 27 | func generateCode(templateName, templateStr, output string, model interface{}, opt *generateOption) { 28 | 29 | var err error 30 | 31 | if opt == nil { 32 | opt = &generateOption{} 33 | } 34 | 35 | var bf bytes.Buffer 36 | 37 | tpl, err := template.New(templateName).Parse(templateStr) 38 | if err != nil { 39 | goto OnError 40 | } 41 | 42 | err = tpl.Execute(&bf, model) 43 | if err != nil { 44 | goto OnError 45 | } 46 | 47 | if opt.formatGoCode { 48 | if err = formatCode(&bf); err != nil { 49 | fmt.Println("format golang code err", err) 50 | } 51 | } 52 | 53 | opt.outputData = bf.Bytes() 54 | 55 | if output != "" { 56 | 57 | os.MkdirAll(filepath.Dir(output), 666) 58 | 59 | err = ioutil.WriteFile(output, bf.Bytes(), 0666) 60 | 61 | if err != nil { 62 | goto OnError 63 | } 64 | } 65 | return 66 | 67 | OnError: 68 | fmt.Println(err) 69 | os.Exit(1) 70 | } 71 | 72 | func formatCode(bf *bytes.Buffer) error { 73 | 74 | fset := token.NewFileSet() 75 | 76 | ast, err := parser.ParseFile(fset, "", bf, parser.ParseComments) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | bf.Reset() 82 | 83 | err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(bf, fset, ast) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | return nil 89 | } 90 | -------------------------------------------------------------------------------- /server/src/proto/msg_sp.go: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/gosproto/sprotogen 2 | // DO NOT EDIT! 3 | 4 | package proto 5 | 6 | import ( 7 | "reflect" 8 | 9 | "github.com/davyxu/goobjfmt" 10 | "github.com/davyxu/cellnet/codec/sproto" 11 | ) 12 | 13 | type LoginREQ struct { 14 | PlatformToken string `sproto:"string,0,name=PlatformToken"` 15 | } 16 | 17 | func (self *LoginREQ) String() string { return goobjfmt.CompactTextString(self) } 18 | 19 | type LoginACK struct { 20 | Result int32 `sproto:"integer,0,name=Result"` 21 | 22 | Token string `sproto:"string,1,name=Token"` 23 | } 24 | 25 | func (self *LoginACK) String() string { return goobjfmt.CompactTextString(self) } 26 | 27 | type PeerConnected struct { 28 | } 29 | 30 | func (self *PeerConnected) String() string { return goobjfmt.CompactTextString(self) } 31 | 32 | type PeerDisconnected struct { 33 | } 34 | 35 | func (self *PeerDisconnected) String() string { return goobjfmt.CompactTextString(self) } 36 | 37 | type PeerConnectError struct { 38 | } 39 | 40 | func (self *PeerConnectError) String() string { return goobjfmt.CompactTextString(self) } 41 | 42 | type PeerRecvError struct { 43 | } 44 | 45 | func (self *PeerRecvError) String() string { return goobjfmt.CompactTextString(self) } 46 | 47 | type PeerSendError struct { 48 | } 49 | 50 | func (self *PeerSendError) String() string { return goobjfmt.CompactTextString(self) } 51 | 52 | var SProtoStructs = []reflect.Type{ 53 | 54 | reflect.TypeOf((*LoginREQ)(nil)).Elem(), // 2266274450 55 | reflect.TypeOf((*LoginACK)(nil)).Elem(), // 3964561136 56 | reflect.TypeOf((*PeerConnected)(nil)).Elem(), // 1162626543 57 | reflect.TypeOf((*PeerDisconnected)(nil)).Elem(), // 3629069126 58 | reflect.TypeOf((*PeerConnectError)(nil)).Elem(), // 780565736 59 | reflect.TypeOf((*PeerRecvError)(nil)).Elem(), // 3264497882 60 | reflect.TypeOf((*PeerSendError)(nil)).Elem(), // 4009711215 61 | } 62 | 63 | var SProtoEnumValue = map[string]map[int32]string{} 64 | 65 | func init() { 66 | sprotocodec.AutoRegisterMessageMeta(SProtoStructs) 67 | } 68 | -------------------------------------------------------------------------------- /server/src/svc/model.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import "github.com/davyxu/cellnet" 4 | 5 | var Queue cellnet.EventQueue 6 | -------------------------------------------------------------------------------- /server/src/svc/setup.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import "github.com/davyxu/cellnet" 4 | 5 | func Init(svcName string) { 6 | 7 | Queue = cellnet.NewEventQueue() 8 | 9 | } 10 | 11 | func Run() { 12 | 13 | Queue.StartLoop() 14 | 15 | Queue.Wait() 16 | } 17 | -------------------------------------------------------------------------------- /server/src/svcmod/login/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/davyxu/cellnet/socket" 5 | "svcmod/login/platformverify" 6 | "github.com/davyxu/golog" 7 | "svc" 8 | ) 9 | 10 | var log *golog.Logger = golog.New("main") 11 | 12 | func main() { 13 | 14 | svc.Init("login") 15 | 16 | peer := socket.NewAcceptor(svc.Queue) 17 | 18 | platformverify.Start(peer) 19 | 20 | peer.Start("127.0.0.1:8001") 21 | 22 | svc.Run() 23 | } 24 | -------------------------------------------------------------------------------- /server/src/svcmod/login/platformverify/platformverify_msg.go: -------------------------------------------------------------------------------- 1 | package platformverify 2 | 3 | import ( 4 | "proto" 5 | 6 | "github.com/davyxu/cellnet" 7 | "github.com/davyxu/golog" 8 | ) 9 | 10 | var log *golog.Logger = golog.New("platformverify") 11 | 12 | func Start(peer cellnet.Peer) { 13 | 14 | cellnet.RegisterMessage(peer, "proto.LoginREQ", func(ev *cellnet.Event) { 15 | 16 | msg := ev.Msg.(*proto.LoginREQ) 17 | 18 | log.Debugln("platform token:", msg.PlatformToken) 19 | 20 | ev.Send(&proto.LoginACK{ 21 | Token: "pass", 22 | }) 23 | 24 | }) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /server/src/table/log.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log *golog.Logger = golog.New("table") 8 | --------------------------------------------------------------------------------