diff --git a/DemoUnity/Assets/Scripts/LoginGUI.cs b/DemoUnity/Assets/Scripts/LoginGUI.cs index 8a351d5..ae153f3 100644 --- a/DemoUnity/Assets/Scripts/LoginGUI.cs +++ b/DemoUnity/Assets/Scripts/LoginGUI.cs @@ -124,7 +124,7 @@ public class LoginGUI : MonoBehaviour { public void Login() { - string host = "127.0.0.1"; + string host = "bee.local"; int port = 3999; // if (pc != null) // { diff --git a/docs/cs_friend_proto.proto b/docs/cs_friend_proto.proto new file mode 100644 index 0000000..f76135c --- /dev/null +++ b/docs/cs_friend_proto.proto @@ -0,0 +1,856 @@ +package cs; + +//常量 +enum Constant_e +{ + ProtoVersion = 2020061101; //协议版本 +} + +//心跳(每60秒上报) +message CMPing +{ +} +message SMPing +{ + optional int32 param1 = 1; +} + +//string元组 +message MFStringTuple +{ + repeated string values = 1; //values +} + +//int32 pair +message MFPairInt32 +{ + optional int32 key = 1; //key + optional int32 val = 2; //val +} + +//int64 pair +message MFPairInt64 +{ + optional int64 key = 1; //key + optional int64 val = 2; //val +} + +//分页信息 +message MFPaging +{ + optional int32 curr_page = 1; //当前页(第一页是0) + optional int32 page_size = 2; //每页记录数 + optional int32 _total_page = 3; //总页数(服务器填充该字段) + optional int32 _total_count = 4; //总记录数(服务器填充该字段) +} + +//用户基础数据(可用于缓存,除下划线开头的字段会存储到db) +message MFBaseUserData +{ + optional string account_id = 1; //账号id + optional string nickname = 2; //昵称 + optional string avatar_url = 3; //头像 + optional int32 sex = 4; //性别 1:男 2:女 0:未知 + optional int32 last_login_time = 5; //最后登录时间 + optional int64 guild_id = 6; //工会id(没有公会的话为0) + optional int32 guild_job = 7; //公会职位 1:公会长 2:副公会长 3:精英成员 其他(0):普通会员 + optional int32 vip_lv = 8 [default = 0]; //性别 + optional int32 head = 9 [default = 0]; //头像框 + optional int32 contribute = 10 [default = 0]; //贡献度 + + optional int64 user_value1 = 50; //用户字段1 + optional int64 user_value2 = 51; //用户字段2 + optional int64 user_value3 = 52; //用户字段3 + optional int64 base_data_version = 100; //数据版本号 + + optional int32 _online = 101; //是否在线 +} + +//临时用户自定义数据(不会存储每次上/下线时时都重置为0) +message MFUserTempCustomData +{ + optional int64 value1 = 1 [default = 0]; //自定义字段1 + optional int64 value2 = 2 [default = 0]; //自定义字段2 + optional int64 value3 = 3 [default = 0]; //自定义字段3 +} + +//账号信息(自己) +message MFAccountInfo +{ + optional MFUserInfo user_info = 1; //用户数据 + optional string user_sign = 2; //用户签名用于接口确权 +} + +//用户信息 +message MFUserInfo +{ + optional MFBaseUserData base_data = 1; //基础数据 + optional MFUserTempCustomData temp_custom_data = 2; //临时用户自定义数据 + optional int32 is_sys_user = 3; //是否系统用户(主要在聊天时判断) +} + +//用户状态 +message MFUserStatus +{ + optional string account_id = 1; //账号id + optional int32 _online = 2; //是否在线 + optional MFUserTempCustomData temp_custom_data = 3; //临时用户自定义数据 +} + +//好友申请 +message MFFriendApply +{ + optional int64 idx = 1; //唯一索引id + optional int64 applyid = 2; //applyid + optional string target_id = 3; //target_id + optional MFBaseUserData base_data = 4; //基础数据 +} + +//公会申请 +message MFGuildApply +{ + optional int64 idx = 1; //唯一索引id + optional int64 applyid = 2; //applyid + optional int64 guild_id = 3; //guild_id + optional MFBaseUserData base_data = 4; //基础数据 +} + +//公会基本信息 +message MFGuildBasic +{ + optional int64 guild_id = 1; //公会id + optional string guild_name = 2; //公会名 + optional int32 guild_lv = 3; //公会等级 + optional double guild_exp = 4; //公会经验 + optional int32 guild_badge = 5; //公会徽章 + optional int32 member_num = 6; //公会成员数 + optional string guild_declaration = 7; //公会宣言 + optional string owner_id = 8; //公会队长id + optional string owner_name = 9; //公会队长名字 + optional string owner_avatar_url = 10; //公会队长头像 + optional int32 owner_sex = 23; //公会队长性别 + optional int32 owner_vip_lv = 12 [default = 0]; //vip等级 + optional int32 owner_head = 13 [default = 0]; //头像框 + optional int32 join_unlimited = 11; //不限制加入 + optional int32 join_cond1 = 20; //加入条件1 + optional int32 join_cond2 = 21; //加入条件2 + optional int32 applyed = 22; //是否已申请 + + optional int32 _gameid = 100; //gameid + optional int32 _channel = 101; //channel + optional int32 _createtime = 102; //createtime + optional int32 _modifytime = 103; //modifytime + optional int64 _name_ext1 = 104; //name_ext1 + optional int64 _name_ext2 = 105; //name_ext2 + optional int64 _guild_status = 106; //guild_status +} + + +//聊天消息 +message MFChatMsg +{ + /* + 消息唯一id,递增序列,客户端可以用chat_channel + msg_uuid作为主键 + !!!不同的频道msg_uuid可能重复 + */ + optional int64 msg_uuid = 1; + optional MFUserInfo sender = 2; //发送者 + optional MFUserInfo receiver = 3; //接收者 + optional int32 chat_channel = 4; //聊天频道 + optional int32 msg_type = 5; //消息类型 0:文本消息(json) 1:自定义协议 (json) 2:纯文本(但是任会做屏蔽字替换) + optional string msg_body = 6; //消息内容(json类型里的字段!开头的会做屏蔽替换) + optional int32 send_time = 7; //消息发送时间 +} + +//登录好友服 +message CMLoginCommonHead +{ + optional int32 server_id = 1; //保留 +} +message CMLoginOld +{ + optional string account_id = 3; //账号id + optional string session_id = 20; //sessionid + optional string nickname = 4; //昵称 + optional string avatar_url = 5; //头像 + optional int32 sex = 6; //性别 +} +message CMLogin +{ + optional int32 server_id = 1; //保留(定死传1) + optional string reserved2 = 2; //保留 + optional string account_id = 3; //账号id + optional string session_id = 20; //sessionid + optional string nickname = 4; //昵称 + optional int32 proto_version = 5; //协议版本号Constant_e.ProtoVersion + optional int32 sex = 6; //性别 + optional string avatar_url = 7; //头像 + optional int32 vip_lv = 8; //性别 + optional int32 head = 9; //头像框 +} + +//登录回复 +message SMLogin +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 + optional MFAccountInfo account_info = 3; //账号信息 +} + +//更新用户信息(增量更新,不需更新的字段不传即可) +message CMUpdateUserInfo +{ + optional string nickname = 2; //昵称 + optional string avatar_url = 3; //头像 + optional int32 sex = 4; //性别 1:男 2:女 0:未知 + optional int32 vip_lv = 8; //性别 + optional int32 head = 9; //头像框 + optional int32 contribute = 10; //贡献度 + + optional int64 user_value1 = 50; //用户字段1 + optional int64 user_value2 = 51; //用户字段2 + optional int64 user_value3 = 52; //用户字段3 + + optional int32 delay_time = 100; //延迟更新(单位毫秒) + optional int32 delay_flag = 101; //延迟更新标志(只能为1-16),相同的flag定时器覆盖 +} + +//屏蔽字检查 +message CMDirtyWordCheck +{ + optional string text = 2; //待检查文本 +} +//屏蔽字检查回复 +message SMDirtyWordCheck +{ + optional int32 errcode = 1; //错误消息 + optional string errmsg = 2; //错误消息 +} + +//获取自己的公会信息 +message CMGetUserGuild +{ + optional string account_id = 1; //用户id,传空或不传获取自己 +} +//获取自己 +message SMGetUserGuild +{ + optional int32 errcode = 1; //1:公会不存在 + optional string errmsg = 2; //错误消息 + optional string account_id = 3; //用户id,传空或不传获取自己 + optional int64 guild_id = 4; //工会id(没有公会的话为0) + optional int32 guild_job = 5; //公会职位 1:公会长 2:副公会长 3:精英成员 其他(0):普通会员 +} + +//获取好友列表 +message CMFriendList +{ +} +//好友列表回复 +message SMFriendList +{ + optional int32 errcode = 1; //错误消息 + optional string errmsg = 2; //错误消息 + repeated MFUserInfo friend_list = 3; //好友列表 +} + +//好友申请 +message CMFriendApply +{ + optional string friend_id = 1; //好友id + optional string msg = 2; //消息 +} +//好友申请回复 +message SMFriendApply +{ + optional int32 errcode = 1; //1:已经是好友 + optional string errmsg = 2; //消息描述 +} + +//获取好友申请列表 +message CMFriendApplyList +{ + optional MFPaging paging = 1; //分页信息 +} +//获取好友申请列表回复 +message SMFriendApplyList +{ + optional int32 errcode = 1; // + optional string errmsg = 2; //错误消息 + optional MFPaging paging = 3; //分页信息回传 + repeated MFFriendApply apply_list = 4; //申请加好友列表 +} + +//同意申请 +message CMFriendAgree +{ + optional MFFriendApply apply = 1; //申请信息 +} +//同意申请回复 +message SMFriendAgree +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误消息 +} + +//拒绝好友申请 +message CMFriendRefuse +{ + optional MFFriendApply apply = 1; //申请信息 +} +//拒绝好友申请回复 +message SMFriendRefuse +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误消息 +} + +//删除好友 +message CMFriendDelete +{ + optional string friend_id = 1; //好友id +} +//删除好友回复 +message SMFriendDelete +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误消息 + optional string friend_id = 3; //好友id +} + +//获取黑名单 +message CMFriendBlackList +{ +} +//获取黑名单回复 +message SMFriendBlackList +{ + repeated MFUserInfo black_list = 1; //黑名单 +} + +//添加黑名单 +message CMFriendAddBlack +{ + optional MFUserInfo user_info = 1; //好友信息 +} +//添加黑名单回复 +message SMFriendAddBlack +{ + optional int32 errcode = 1; // + optional string errmsg = 2; //错误消息 +} + +//删除黑名单 +message CMFriendDeleteBlack +{ + optional string account_id = 1; //好友id +} +//删除黑名单回复 +message SMFriendDeleteBlack +{ + optional int32 errcode = 1; // + optional string errmsg = 2; //错误消息 +} + +//获取好友/黑名单id列表 +message CMFriendIdList +{ +} +//获取好友/黑名单id列表回复 +message SMFriendIdList +{ + optional int32 errcode = 1; // + optional string errmsg = 2; //错误消息 + repeated string friends = 3; //好友 + repeated string blacklist = 4; //黑名单 +} + +//建群 +message CMTeamCreate +{ + optional string team_name = 1; //群名称 +} +//建群返回 +message SMTeamCreate +{ + optional int32 errcode = 1; //1:群已存在 2: 你已经有群 + optional string errmsg = 2; //错误消息 +} + +//加群 +message CMTeamJoin +{ + optional int64 team_id = 1; //群id +} +//加群返回 +message SMTeamJoin +{ + optional int32 errcode = 1; //1:群id不存在 2:群已满 + optional string errmsg = 2; //错误消息 +} + +//同意加群 +message CMTeamAgree +{ +} +message SMTeamAgree +{ + optional int32 errcode = 1; + optional string errmsg = 2; +} + +//踢人 +message CMTeamKick +{ + optional string account_id = 1; +} + +//踢人回复 +message SMTeamKick +{ + optional int32 errcode = 1; //1:群id错误 + optional string errmsg = 2; //错误消息 +} + +//退群 +message CMTeamQuit +{ +} +message SMTeamQuit +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误消息 +} + +//解散群 +message CMTeamDismiss +{ +} +message SMTeamDismiss +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 +} + +//群改名 +message CMTeamRename +{ + optional string new_team_name = 1; //新群名 +} +message SMTeamRename +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 +} + +//获取公会信息 +message CMGuildInfo +{ + optional int64 guild_id = 1; //公会id +} +//获取公会信息返回 +message SMGuildInfo +{ + optional int32 errcode = 1; //1:公会不存在 + optional string errmsg = 2; //错误消息 + optional MFGuildBasic info = 3; //公会信息 +} + +//建公会 +message CMGuildCreate +{ + optional string guild_name = 1; //公会名字 + optional int32 guild_badge = 2; //公会徽标 + optional string guild_declaration = 3; //公会徽标 + optional int32 join_unlimited = 4; //不限制加入 + optional int32 join_cond1 = 5; //加入条件1 + optional int32 join_cond2 = 6; //加入条件2 +} +//建公会返回 +message SMGuildCreate +{ + optional int32 errcode = 1; //1:公会已存在 2: 你已经有公会 + optional string errmsg = 2; //错误消息 + optional int64 guild_id = 3; //公会id +} + +//加公会 +message CMGuildJoin +{ + optional int64 guild_id = 1; //公会id +} +//加群返回 +message SMGuildJoin +{ + optional int32 errcode = 1; //1:公会id不存在 2:公会已满 + optional string errmsg = 2; //错误消息 +} + +//同意加公会 +message CMGuildAgree +{ + optional MFGuildApply apply = 1; //申请信息 + optional int32 batchid = 2; //批次号(批量的时候id相同建议用时间戳) +} +message SMGuildAgree +{ + optional int32 errcode = 1; + optional string errmsg = 2; +} + +//拒绝加公会申请 +message CMGuildRefuse +{ + optional MFGuildApply apply = 1; //申请信息 + optional int32 batchid = 2; //批次号(批量的时候id相同建议用时间戳) +} +message SMGuildRefuse +{ + optional int32 errcode = 1; + optional string errmsg = 2; +} + +//踢人 +message CMGuildKick +{ + optional string account_id = 1; +} + +//踢人回复 +message SMGuildKick +{ + optional int32 errcode = 1; //1:群id错误 + optional string errmsg = 2; //错误消息 +} + +//退公会 +message CMGuildQuit +{ +} +message SMGuildQuit +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误消息 +} + +//解散公会 +message CMGuildDismiss +{ +} +message SMGuildDismiss +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 +} + +//修改公会信息(增量更新不需要修改的字段不传) +message CMGuildChange +{ + optional string guild_name = 1; //公会名字 + optional int32 guild_badge = 2; //公会徽标 + optional string guild_declaration = 3; //公会徽标 + optional int32 join_unlimited = 4; //不限制加入 + optional int32 join_cond1 = 5; //加入条件1 + optional int32 join_cond2 = 6; //加入条件2 +} +message SMGuildChange +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 + optional MFGuildBasic info = 3; //公会信息 +} + +//查询公会 +message CMGuildSearch +{ + optional MFPaging paging = 1; //分页信息 + optional string guild_name = 2; //公会名字 +} +message SMGuildSearch +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 + optional MFPaging paging = 3; //分页信息 + repeated MFGuildBasic guild_list = 4; //公会列表 +} + +//公会排行榜 +message CMGuildRank +{ + optional MFPaging paging = 1; //分页信息 +} +message SMGuildRank +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 + optional MFPaging paging = 3; //分页信息 + repeated MFGuildBasic guild_list = 4; //公会列表 +} + +//公会成员 +message CMGuildMemberList +{ + optional MFPaging paging = 1; //分页信息 + optional string member_name = 2; //成员名字 +} +message SMGuildMemberList +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 + optional MFPaging paging = 3; //分页信息 + repeated MFUserInfo member_list = 4; //公会成员列表 + optional int32 guild_lv = 5; //公会等级 +} + +//获取公会申请列表 +message CMGuildApplyList +{ + optional MFPaging paging = 1; //分页信息 +} +//获取公会申请列表回复 +message SMGuildApplyList +{ + optional int32 errcode = 1; // + optional string errmsg = 2; //错误消息 + optional MFPaging paging = 3; //分页信息回传 + repeated MFGuildApply apply_list = 4; //申请加公会友列表 + optional int32 guild_lv = 5; //公会等级 +} + +//公会动态(日志) +message CMGuildLog +{ + optional MFPaging paging = 1; //分页信息 +} +message SMGuildLog +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 + optional MFPaging paging = 3; //分页信息 + /* + values[0]: account_id + values[1]: 角色名 + values[2]: 职位 1:队长 2:副队长 3:精英会员 其他(0):普通会员 + values[3]: 行为时间(unix时间戳) + values[4]: 行为 + */ + repeated MFStringTuple logs = 4; +} + +//设置公会成员职位 +message CMGuildMemberSetJob +{ + optional string member_id = 1; //成员id + optional int32 job = 2; //职位 +} +message SMGuildMemberSetJob +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 +} + +//同意邀请 +message CMGuildAgreeInvite +{ + optional int64 guild_id = 1; //公会id + optional string user_sign = 2; //邀请方签名 +} +message SMGuildAgreeInvite +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 +} + +//新增公会经验 +message CMGuildGainExp +{ + optional int32 exp = 1; //检验值 +} +message SMGuildGainExp +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 +} + +//查询公会成员信息 +message CMGuildSearchMember +{ + optional string target_id = 1; //账号id +} +message SMGuildSearchMember +{ + optional int32 errcode = 1; //错误码 + optional string errmsg = 2; //错误信息 + optional MFGuildBasic guild_basic = 3; //公会基本信息 + optional MFUserInfo user_info = 4; //用户信息 +} + +//发送聊天消息 +message CMSendChatMsg +{ + optional int32 chat_channel = 1; //聊天频道 1: 世界 2:好友 3:战队 4:小队(这时target表示队伍Id) 5:大喇叭 6:跑马灯(只能收不能发) + optional string target = 2; //目标 + optional int32 msg_type = 3; ////消息类型 0:文本消息(json) 1:自定义协议 (json) 2:纯文本(但是任会做屏蔽字替换) + optional string msg_body = 4; //消息内容 + repeated string members = 5; //小队成员列表(包含自己) +} + +//读取聊天消息列表并且开启聊天通知 +message CMReadMsgAndOpenChatNotify +{ + optional int32 curr_channel = 1; //当前频道 + repeated MFPairInt64 last_ids = 2; //所有频道 key:聊天频道 val:该频道最后一次收到的消息id +} + +//设置当前私聊目标 +message CMSetCurrPrivateChatTarget +{ + optional string private_target = 1; //私聊对象id, 只有当前聊频道是私聊时字段才有意义 + optional int64 last_id = 2; //最后收到想消息id +} + +//关闭聊天通知 +message CMCloseChatNotify +{ +} + +//发送自定义消息 +message CMSendCustomMsg +{ + repeated string target_list = 1; //目标列表 + optional string msg = 2; //消息内容 + optional int64 param1 = 3; //透传参数1 + optional int64 param2 = 4; //透传参数2 + optional int64 param3 = 5; //透传参数3 +} + +//更新临时自定义数据 +message CMUpdateTempCustomData +{ + /* + 更新方式 + 0: 覆盖 + 1: 用新数据和服务器数据做或运算 + 2: 用新数据和服务器数据做与运算 + + !!!注意 + MFUserRaltimeData走的是增量更新如果不需要处理的字段不传就行 + 服务器对未传的自动不做任何处理 + */ + optional int32 update_type = 1; //更新方式 + optional MFUserTempCustomData temp_custom_data = 2; //临时自定义数据 + + optional int32 delay_time = 100; //延迟更新(单位毫秒) + optional int32 delay_flag = 101; //延迟更新标志(只能为1-16),相同的flag定时器覆盖 +} + +//查询用户状态 +message CMQueryUserStatus +{ + repeated string user_list = 1; //用户列表 +} +//查询用户状态返回 +message SMQueryUserStatus +{ + repeated MFUserStatus status_list = 1; //用户状态列表 +} + +//获取推荐好友 +message CMRecommandFriend +{ +} +//获取推荐好友返回 +message SMRecommandFriend +{ + repeated MFUserInfo friend_list = 1; //好友列表 +} + +//用户上/下线通知 +message SMUserStatusNotify +{ + repeated string online_users = 1; //上线用户 + repeated string offline_users = 2; //下线用户 +} + +//聊天消息通知 +message SMChatMsgNotify +{ + repeated MFChatMsg msg_list = 1; //消息列表,客户端需要根据chat_channel和msg_uuid更新本地的last_ids +} + +//发送自定义消息 +message SMCustomMsgNotify +{ + optional string sender = 1; //发送者 + optional string msg = 2; //消息内容 + optional int64 param1 = 3; //透传参数1 + optional int64 param2 = 4; //透传参数2 + optional int64 param3 = 5; //透传参数3 +} + +//更新用户信息 +message SMUserInfoUpdate +{ + repeated MFUserInfo user_infos = 1; //用户信息列表 +} + +//删除好友通知a +message SMDeleteFriendNotify +{ + repeated string user_list = 1; //用户列表 +} + +//新增黑名单 +message SMAddBlackListNotify +{ + repeated MFUserInfo user_infos = 1; //用户信息列表 +} + +//删除黑名单通知 +message SMDeleteBlackListNotify +{ + repeated string user_list = 1; //用户列表 +} + +//更新用户临时自定义信息 +message SMUserTempCustomDataUpdate +{ + optional string account_id = 1; //账号id + optional MFUserTempCustomData temp_custom_data = 2; //用户临时自定义数据 +} + +//更新账号信息通知 +message SMUpdateAccountInfo +{ + +} + +//更新红点信息 +message SMUpdateRedPointNotify +{ + optional int32 red_point_flags = 1; //红点信息 1<<0:好友申请 1<<1:公会申请 1<<2:聊天红点 +} + +//更新聊天红点信息 +message SMUpdateChatRedPointNotify +{ + repeated int32 has_unread_msg_channels = 1; //含有未读消息的渠道id列表,不在列表里的渠道默认不含有 +} + +//更新私聊红点信息 +message SMUpdatePrivateChatRedPointNotify +{ + repeated string has_unread_msg_accounts = 1; //有未读消息的账号列表,不在列表里的好友more不含有 +} + +//更新频道最后一次收到的消息id +message SMUpdateChatChannelLastId +{ + repeated MFPairInt64 last_ids = 1; //所有频道 key:聊天频道 val:该频道最后一次收到的消息id +} + +//显示飘字 +message SMShowErrorMsg +{ + optional string msg = 1; //飘字内容 +} diff --git a/game-server/config/servers.json b/game-server/config/servers.json index 8730701..c3f580a 100644 --- a/game-server/config/servers.json +++ b/game-server/config/servers.json @@ -1,8 +1,8 @@ { "development":{ "connector": [ - {"id": "connector-server-0", "host": "127.0.0.1", "port": 3150, "clientHost": "0.0.0.0", "proxyHost": "localhost", "clientPort": 3010, "frontend": true}, - {"id": "connector-server-1", "host": "127.0.0.1", "port": 3151, "clientHost": "0.0.0.0", "proxyHost": "localhost", "clientPort": 3011, "frontend": true} + {"id": "connector-server-0", "host": "127.0.0.1", "port": 3150, "clientHost": "0.0.0.0", "proxyHost": "192.168.100.173", "clientPort": 4010, "frontend": true}, + {"id": "connector-server-1", "host": "127.0.0.1", "port": 3151, "clientHost": "0.0.0.0", "proxyHost": "192.168.100.173", "clientPort": 4011, "frontend": true} ], "guild": [ {"id": "guild-server-0", "host": "127.0.0.1", "port": 3200}, diff --git a/proxy/.vscode/launch.json b/proxy/.vscode/launch.json new file mode 100644 index 0000000..5708693 --- /dev/null +++ b/proxy/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/app.js" + } + ] +} \ No newline at end of file diff --git a/proxy/app.js b/proxy/app.js new file mode 100644 index 0000000..8afbd9f --- /dev/null +++ b/proxy/app.js @@ -0,0 +1,108 @@ +const net = require("net"); +const { PomeloClient } = require("./lib/boot"); + + +var listenPort = 4000; +var listenHost = "127.0.0.1"; + + +const proxyList = require("./config/proxy.json"); + +console.log(proxyList); + +proxyList.forEach((config) => { + proxy(config); +}); + + +function proxy(config) { + console.log(config); + + const host = config.host; + const port = config.port; + const srcHost = config.srcHost; + const srcPort = config.srcPort; + + const server = net.createServer((socket) => { + console.log("listening"); + + const pomelo = new PomeloClient(); + const connectBuffer = []; + let isReady = false; + + pomelo.init({ host: srcHost, port: srcPort, log: true }, () => { + isReady = true; + connectBuffer.forEach((data) => { + onData(data); + }); + } + ); + + socket.on("connect", () => { + console.log("connect"); + }); + + socket.on("error", (error) => { + console.log(error); + }); + + socket.on("close", () => { + console.log("close"); + pomelo.disconnect(); + }); + + socket.on("drop", () => { + console.log("drop"); + }); + + socket.on("data", (data) => { + if (isReady) { + onData(data); + } else { + connectBuffer.push(data); + } + }); + + function onData(data) { + console.log(data.toString()); + + const account = "6516_2006_0xef59f6cc4d190a0ae576c46d4583e92b61174340"; + pomelo.request("gate.gateHandler.queryEntry", { uid: account }, (data) => { + socket.write(JSON.stringify(data)); + }); + } + }); + + server.listen(port, host); +} + + + +// const testAccounts = [ +// "6516_2006_0xef59f6cc4d190a0ae576c46d4583e92b61174340", +// "6513_2006_FcZnmeGSoxGFQy1Zr6Lfr2o7dRoGcEYE", +// "6513_2006_DAmSOj6LKh1jd45DlydwUm7g8iW4KjOv", +// ]; + +// testAccounts.forEach((account) => { +// const pomelo = new PomeloClient(); + +// pomelo.init( +// { +// host: "192.168.100.173", +// port: 3999, +// log: true, +// }, +// () => { +// pomelo.request( +// "gate.gateHandler.queryEntry", +// { uid: account }, +// (data) => { +// console.log(data); +// } +// ); +// } +// ); +// }); + + diff --git a/proxy/client.js b/proxy/client.js new file mode 100644 index 0000000..a20d644 --- /dev/null +++ b/proxy/client.js @@ -0,0 +1,33 @@ +const net = require("net"); + +const port = 4999; +const host = "127.0.0.1"; + +var client = new net.Socket(); + +client.connect(port, host, function () { + console.log("Connected"); + client.write("queryEntry"); +}); + +client.on("data", function (data) { + data = JSON.parse(data); + console.log("Received: " + data); + client.destroy(); // kill client after server's response + + const game = new net.Socket(); + console.log(data.port, data.host); + game.connect(data.port, data.host, function () { + console.log("Connected"); + game.write("entry"); + }); + +}); + +client.on("error", function (error) { + console.log("Error: " + error); +}); + +client.on("close", function () { + console.log("Connection closed"); +}); diff --git a/proxy/config/proxy.json b/proxy/config/proxy.json new file mode 100644 index 0000000..850ed17 --- /dev/null +++ b/proxy/config/proxy.json @@ -0,0 +1,5 @@ +[ + { "host": "127.0.0.1", "port": 4999, "srcHost":"192.168.100.173", "srcPort": 3999 }, + { "host": "127.0.0.1", "port": 4010, "srcHost":"192.168.100.173", "srcPort": 3010 }, + { "host": "127.0.0.1", "port": 4011, "srcHost":"192.168.100.173", "srcPort": 3011 } +] \ No newline at end of file diff --git a/proxy/lib/boot.js b/proxy/lib/boot.js new file mode 100644 index 0000000..a46389c --- /dev/null +++ b/proxy/lib/boot.js @@ -0,0 +1,6 @@ +module.exports = { + EventEmitter: require('./deps/emitter'), + Protocol: require('./deps/pomelo-protocol'), + protobuf: require('./deps/pomelo-protobuf'), + PomeloClient: require('./deps/pomelo-jsclient'), +} diff --git a/proxy/lib/deps/emitter.js b/proxy/lib/deps/emitter.js new file mode 100644 index 0000000..ccfcb5b --- /dev/null +++ b/proxy/lib/deps/emitter.js @@ -0,0 +1,157 @@ +var index = require('./indexof'); + +/** + * Expose `Emitter`. + */ + +module.exports = Emitter; + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +}; + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks[event] = this._callbacks[event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + var self = this; + this._callbacks = this._callbacks || {}; + + function on() { + self.off(event, on); + fn.apply(this, arguments); + } + + fn._off = on; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks[event]; + return this; + } + + // remove specific handler + var i = index(callbacks, fn._off || fn); + if (~i) callbacks.splice(i, 1); + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks[event]; + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks[event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; diff --git a/proxy/lib/deps/indexof.js b/proxy/lib/deps/indexof.js new file mode 100644 index 0000000..4c26161 --- /dev/null +++ b/proxy/lib/deps/indexof.js @@ -0,0 +1,9 @@ +var indexOf = [].indexOf; + +module.exports = function(arr, obj){ + if (indexOf) return arr.indexOf(obj); + for (var i = 0; i < arr.length; ++i) { + if (arr[i] === obj) return i; + } + return -1; +}; diff --git a/proxy/lib/deps/pomelo-jsclient.js b/proxy/lib/deps/pomelo-jsclient.js new file mode 100644 index 0000000..a285d0a --- /dev/null +++ b/proxy/lib/deps/pomelo-jsclient.js @@ -0,0 +1,337 @@ +const net = require("net"); + +var JS_WS_CLIENT_TYPE = "js-websocket"; +var JS_WS_CLIENT_VERSION = "0.0.1"; + +var Protocol = require("./pomelo-protocol"); +var Package = Protocol.Package; +var Message = Protocol.Message; +var EventEmitter = require("./emitter"); +const protobuf = require("./pomelo-protobuf"); + +var RES_OK = 200; +var RES_FAIL = 500; +var RES_OLD_CLIENT = 501; + +class PomeloClient extends EventEmitter { + constructor() { + super(); + this.socket = null; + this.reqId = 0; + this.callbacks = {}; + this.handlers = {}; + //Map from request id to route + this.routeMap = {}; + + this.heartbeatInterval = 0; + this.heartbeatTimeout = 0; + this.nextHeartbeatTimeout = 0; + this.gapThreshold = 100; // heartbeat gap threashold + this.heartbeatId = null; + this.heartbeatTimeoutId = null; + + this.handshakeCallback = null; + + this.handshakeBuffer = { + sys: { + type: JS_WS_CLIENT_TYPE, + version: JS_WS_CLIENT_VERSION, + }, + user: {}, + }; + + this.initCallback = null; + + this.handlers[Package.TYPE_HANDSHAKE] = this.handshake.bind(this); + this.handlers[Package.TYPE_HEARTBEAT] = this.heartbeat.bind(this); + this.handlers[Package.TYPE_DATA] = this.onData.bind(this); + this.handlers[Package.TYPE_KICK] = this.onKick.bind(this); + } + + init(params, cb) { + this.initCallback = cb; + var host = params.host; + var port = params.port; + + this.handshakeBuffer.user = params.user; + this.handshakeCallback = params.handshakeCallback; + this.initWebSocket(host, port, cb); + } + + disconnect() { + if (this.socket) { + if (this.socket.disconnect) this.socket.disconnect(); + if (this.socket.close) this.socket.close(); + console.log("disconnect"); + this.socket = null; + } + + if (this.heartbeatId) { + clearTimeout(this.heartbeatId); + this.heartbeatId = null; + } + if (this.heartbeatTimeoutId) { + clearTimeout(this.heartbeatTimeoutId); + this.heartbeatTimeoutId = null; + } + } + + request(route, msg, cb) { + if (arguments.length === 2 && typeof msg === "function") { + cb = msg; + msg = {}; + } else { + msg = msg || {}; + } + route = route || msg.route; + if (!route) { + return; + } + + this.reqId++; + this.sendMessage(this.reqId, route, msg); + + this.callbacks[this.reqId] = cb; + this.routeMap[this.reqId] = route; + } + + notify(route, msg) { + msg = msg || {}; + this.sendMessage(0, route, msg); + } + + sendMessage(reqId, route, msg) { + var type = reqId ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY; + + //compress message by protobuf + var protos = !!this.data.protos ? this.data.protos.client : {}; + if (!!protos[route]) { + msg = protobuf.encode(route, msg); + } else { + msg = Protocol.strencode(JSON.stringify(msg)); + } + + var compressRoute = 0; + if (this.dict && this.dict[route]) { + route = this.dict[route]; + compressRoute = 1; + } + + msg = Message.encode(reqId, type, compressRoute, route, msg); + var packet = Package.encode(Package.TYPE_DATA, msg); + this.send(packet); + } + + initWebSocket(host, port, cb) { + console.log("connect to " + host + ":" + port); + + this.socket = net.connect(port, host, (event) => { + var obj = Package.encode( + Package.TYPE_HANDSHAKE, + Protocol.strencode(JSON.stringify(this.handshakeBuffer)) + ); + this.send(obj); + }); + this.socket.on("data", (event) => { + this.processPackage(Package.decode(event), cb); + // new package arrived, update the heartbeat timeout + if (this.heartbeatTimeout) { + this.nextHeartbeatTimeout = Date.now() + this.heartbeatTimeout; + } + }); + this.socket.on("error", (event) => { + this.emit("io-error", event); + console.error("socket error: ", event); + }); + this.socket.on("close", (event) => { + this.emit("close", event); + console.error("socket close: ", event); + }); + } + + send(packet) { + this.socket.write(packet); + } + + processPackage(msg) { + this.handlers[msg.type](msg.body); + } + + heartbeat(data) { + if (!this.heartbeatInterval) { + // no heartbeat + return; + } + + var obj = Package.encode(Package.TYPE_HEARTBEAT); + if (this.heartbeatTimeoutId) { + clearTimeout(this.heartbeatTimeoutId); + this.heartbeatTimeoutId = null; + } + + if (this.heartbeatId) { + // already in a heartbeat interval + return; + } + + this.heartbeatId = setTimeout( + function () { + this.heartbeatId = null; + this.send(obj); + + this.nextHeartbeatTimeout = Date.now() + this.heartbeatTimeout; + this.heartbeatTimeoutId = setTimeout( + this.heartbeatTimeoutCb.bind(this), + this.heartbeatTimeout + ); + }.bind(this), + this.heartbeatInterval + ); + } + + heartbeatTimeoutCb() { + var gap = this.nextHeartbeatTimeout - Date.now(); + if (gap > this.gapThreshold) { + this.heartbeatTimeoutId = setTimeout(this.heartbeatTimeoutCb, gap); + } else { + console.error("server heartbeat timeout"); + this.emit("heartbeat timeout"); + this.disconnect(); + } + } + + handshake(data) { + data = JSON.parse(Protocol.strdecode(data)); + if (data.code === RES_OLD_CLIENT) { + this.emit("error", "client version not fullfill"); + return; + } + + if (data.code !== RES_OK) { + this.emit("error", "handshake fail"); + return; + } + + this.handshakeInit(data); + + var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK); + this.send(obj); + if (this.initCallback) { + this.initCallback(this.socket); + this.initCallback = null; + } + } + + handshakeInit(data) { + if (data.sys && data.sys.heartbeat) { + this.heartbeatInterval = data.sys.heartbeat * 1000; // heartbeat interval + this.heartbeatTimeout = this.heartbeatInterval * 2; // max heartbeat timeout + } else { + this.heartbeatInterval = 0; + this.heartbeatTimeout = 0; + } + + this.initData(data); + + if (typeof this.handshakeCallback === "function") { + this.handshakeCallback(data.user); + } + } + + initData(data) { + if (!data || !data.sys) { + return; + } + this.data = this.data || {}; + var dict = data.sys.dict; + var protos = data.sys.protos; + + //Init compress dict + if (dict) { + this.data.dict = dict; + this.data.abbrs = {}; + + for (var route in dict) { + this.data.abbrs[dict[route]] = route; + } + } + + //Init protobuf protos + if (protos) { + this.data.protos = { + server: protos.server || {}, + client: protos.client || {}, + }; + if (!!protobuf) { + protobuf.init({ + encoderProtos: protos.client, + decoderProtos: protos.server, + }); + } + } + } + + onData(data) { + //probuff decode + var msg = Message.decode(data); + + if (msg.id > 0) { + msg.route = this.routeMap[msg.id]; + delete this.routeMap[msg.id]; + if (!msg.route) { + return; + } + } + + msg.body = this.deCompose(msg); + + this.processMessage(msg); + } + + deCompose(msg) { + var protos = !!this.data.protos ? this.data.protos.server : {}; + var abbrs = this.data.abbrs; + var route = msg.route; + + //Decompose route from dict + if (msg.compressRoute) { + if (!abbrs[route]) { + return {}; + } + + route = msg.route = abbrs[route]; + } + if (!!protos[route]) { + return protobuf.decode(route, msg.body); + } else { + return JSON.parse(Protocol.strdecode(msg.body)); + } + + return msg; + } + + processMessage(msg) { + if(!msg.id) { + // server push message + this.emit(msg.route, msg.body); + return; + } + + //if have a id then find the callback function with the request + var cb = this.callbacks[msg.id]; + + delete this.callbacks[msg.id]; + if(typeof cb !== 'function') { + return; + } + + cb(msg.body); + return; + }; + + onKick(data) { + this.emit("onKick"); + } +} + +module.exports = PomeloClient; diff --git a/proxy/lib/deps/pomelo-protobuf.js b/proxy/lib/deps/pomelo-protobuf.js new file mode 100644 index 0000000..b1cde5c --- /dev/null +++ b/proxy/lib/deps/pomelo-protobuf.js @@ -0,0 +1,611 @@ +/* ProtocolBuffer client 0.1.0*/ + +/** + * pomelo-protobuf + * @author + */ + +/** + * Protocol buffer root + * In browser, it will be window.protbuf + */ +(function (exports, global){ + var Protobuf = exports; + + Protobuf.init = function(opts){ + //On the serverside, use serverProtos to encode messages send to client + Protobuf.encoder.init(opts.encoderProtos); + + //On the serverside, user clientProtos to decode messages receive from clients + Protobuf.decoder.init(opts.decoderProtos); + }; + + Protobuf.encode = function(key, msg){ + return Protobuf.encoder.encode(key, msg); + }; + + Protobuf.decode = function(key, msg){ + return Protobuf.decoder.decode(key, msg); + }; + + // exports to support for components + module.exports = Protobuf; +})('object' === typeof module ? module.exports : (this.protobuf = {}), this); + +/** + * constants + */ +(function (exports, global){ + var constants = exports.constants = {}; + + constants.TYPES = { + uInt32 : 0, + sInt32 : 0, + int32 : 0, + double : 1, + string : 2, + message : 2, + float : 5 + }; + +})('undefined' !== typeof protobuf ? protobuf : module.exports, this); + +/** + * util module + */ +(function (exports, global){ + + var Util = exports.util = {}; + + Util.isSimpleType = function(type){ + return ( type === 'uInt32' || + type === 'sInt32' || + type === 'int32' || + type === 'uInt64' || + type === 'sInt64' || + type === 'float' || + type === 'double' ); + }; + +})('undefined' !== typeof protobuf ? protobuf : module.exports, this); + +/** + * codec module + */ +(function (exports, global){ + + var Codec = exports.codec = {}; + + var buffer = new ArrayBuffer(8); + var float32Array = new Float32Array(buffer); + var float64Array = new Float64Array(buffer); + var uInt8Array = new Uint8Array(buffer); + + Codec.encodeUInt32 = function(n){ + var n = parseInt(n); + if(isNaN(n) || n < 0){ + return null; + } + + var result = []; + do{ + var tmp = n % 128; + var next = Math.floor(n/128); + + if(next !== 0){ + tmp = tmp + 128; + } + result.push(tmp); + n = next; + }while(n !== 0); + + return result; + }; + + Codec.encodeSInt32 = function(n){ + var n = parseInt(n); + if(isNaN(n)){ + return null; + } + n = n<0?(Math.abs(n)*2-1):n*2; + + return Codec.encodeUInt32(n); + }; + + Codec.decodeUInt32 = function(bytes){ + var n = 0; + + for(var i = 0; i < bytes.length; i++){ + var m = parseInt(bytes[i]); + n = n + ((m & 0x7f) * Math.pow(2,(7*i))); + if(m < 128){ + return n; + } + } + + return n; + }; + + + Codec.decodeSInt32 = function(bytes){ + var n = this.decodeUInt32(bytes); + var flag = ((n%2) === 1)?-1:1; + + n = ((n%2 + n)/2)*flag; + + return n; + }; + + Codec.encodeFloat = function(float){ + float32Array[0] = float; + return uInt8Array; + }; + + Codec.decodeFloat = function(bytes, offset){ + if(!bytes || bytes.length < (offset +4)){ + return null; + } + + for(var i = 0; i < 4; i++){ + uInt8Array[i] = bytes[offset + i]; + } + + return float32Array[0]; + }; + + Codec.encodeDouble = function(double){ + float64Array[0] = double; + return uInt8Array.subarray(0, 8); + }; + + Codec.decodeDouble = function(bytes, offset){ + if(!bytes || bytes.length < (8 + offset)){ + return null; + } + + for(var i = 0; i < 8; i++){ + uInt8Array[i] = bytes[offset + i]; + } + + return float64Array[0]; + }; + + Codec.encodeStr = function(bytes, offset, str){ + for(var i = 0; i < str.length; i++){ + var code = str.charCodeAt(i); + var codes = encode2UTF8(code); + + for(var j = 0; j < codes.length; j++){ + bytes[offset] = codes[j]; + offset++; + } + } + + return offset; + }; + + /** + * Decode string from utf8 bytes + */ + Codec.decodeStr = function(bytes, offset, length){ + var array = []; + var end = offset + length; + + while(offset < end){ + var code = 0; + + if(bytes[offset] < 128){ + code = bytes[offset]; + + offset += 1; + }else if(bytes[offset] < 224){ + code = ((bytes[offset] & 0x3f)<<6) + (bytes[offset+1] & 0x3f); + offset += 2; + }else{ + code = ((bytes[offset] & 0x0f)<<12) + ((bytes[offset+1] & 0x3f)<<6) + (bytes[offset+2] & 0x3f); + offset += 3; + } + + array.push(code); + + } + + var str = ''; + for(var i = 0; i < array.length;){ + str += String.fromCharCode.apply(null, array.slice(i, i + 10000)); + i += 10000; + } + + return str; + }; + + /** + * Return the byte length of the str use utf8 + */ + Codec.byteLength = function(str){ + if(typeof(str) !== 'string'){ + return -1; + } + + var length = 0; + + for(var i = 0; i < str.length; i++){ + var code = str.charCodeAt(i); + length += codeLength(code); + } + + return length; + }; + + /** + * Encode a unicode16 char code to utf8 bytes + */ + function encode2UTF8(charCode){ + if(charCode <= 0x7f){ + return [charCode]; + }else if(charCode <= 0x7ff){ + return [0xc0|(charCode>>6), 0x80|(charCode & 0x3f)]; + }else{ + return [0xe0|(charCode>>12), 0x80|((charCode & 0xfc0)>>6), 0x80|(charCode & 0x3f)]; + } + } + + function codeLength(code){ + if(code <= 0x7f){ + return 1; + }else if(code <= 0x7ff){ + return 2; + }else{ + return 3; + } + } +})('undefined' !== typeof protobuf ? protobuf : module.exports, this); + +/** + * encoder module + */ +(function (exports, global){ + + var protobuf = exports; + var MsgEncoder = exports.encoder = {}; + + var codec = protobuf.codec; + var constant = protobuf.constants; + var util = protobuf.util; + + MsgEncoder.init = function(protos){ + this.protos = protos || {}; + }; + + MsgEncoder.encode = function(route, msg){ + //Get protos from protos map use the route as key + var protos = this.protos[route]; + + //Check msg + if(!checkMsg(msg, protos)){ + return null; + } + + //Set the length of the buffer 2 times bigger to prevent overflow + var length = codec.byteLength(JSON.stringify(msg)); + + //Init buffer and offset + var buffer = new ArrayBuffer(length); + var uInt8Array = new Uint8Array(buffer); + var offset = 0; + + if(!!protos){ + offset = encodeMsg(uInt8Array, offset, protos, msg); + if(offset > 0){ + return uInt8Array.subarray(0, offset); + } + } + + return null; + }; + + /** + * Check if the msg follow the defination in the protos + */ + function checkMsg(msg, protos){ + if(!protos){ + return false; + } + + for(var name in protos){ + var proto = protos[name]; + + //All required element must exist + switch(proto.option){ + case 'required' : + if(typeof(msg[name]) === 'undefined'){ + return false; + } + case 'optional' : + if(typeof(msg[name]) !== 'undefined'){ + if(!!protos.__messages[proto.type]){ + checkMsg(msg[name], protos.__messages[proto.type]); + } + } + break; + case 'repeated' : + //Check nest message in repeated elements + if(!!msg[name] && !!protos.__messages[proto.type]){ + for(var i = 0; i < msg[name].length; i++){ + if(!checkMsg(msg[name][i], protos.__messages[proto.type])){ + return false; + } + } + } + break; + } + } + + return true; + } + + function encodeMsg(buffer, offset, protos, msg){ + for(var name in msg){ + if(!!protos[name]){ + var proto = protos[name]; + + switch(proto.option){ + case 'required' : + case 'optional' : + offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag)); + offset = encodeProp(msg[name], proto.type, offset, buffer, protos); + break; + case 'repeated' : + if(msg[name].length > 0){ + offset = encodeArray(msg[name], proto, offset, buffer, protos); + } + break; + } + } + } + + return offset; + } + + function encodeProp(value, type, offset, buffer, protos){ + switch(type){ + case 'uInt32': + offset = writeBytes(buffer, offset, codec.encodeUInt32(value)); + break; + case 'int32' : + case 'sInt32': + offset = writeBytes(buffer, offset, codec.encodeSInt32(value)); + break; + case 'float': + writeBytes(buffer, offset, codec.encodeFloat(value)); + offset += 4; + break; + case 'double': + writeBytes(buffer, offset, codec.encodeDouble(value)); + offset += 8; + break; + case 'string': + var length = codec.byteLength(value); + + //Encode length + offset = writeBytes(buffer, offset, codec.encodeUInt32(length)); + //write string + codec.encodeStr(buffer, offset, value); + offset += length; + break; + default : + if(!!protos.__messages[type]){ + //Use a tmp buffer to build an internal msg + var tmpBuffer = new ArrayBuffer(codec.byteLength(JSON.stringify(value))); + var length = 0; + + length = encodeMsg(tmpBuffer, length, protos.__messages[type], value); + //Encode length + offset = writeBytes(buffer, offset, codec.encodeUInt32(length)); + //contact the object + for(var i = 0; i < length; i++){ + buffer[offset] = tmpBuffer[i]; + offset++; + } + } + break; + } + + return offset; + } + + /** + * Encode reapeated properties, simple msg and object are decode differented + */ + function encodeArray(array, proto, offset, buffer, protos){ + var i = 0; + + if(util.isSimpleType(proto.type)){ + offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag)); + offset = writeBytes(buffer, offset, codec.encodeUInt32(array.length)); + for(i = 0; i < array.length; i++){ + offset = encodeProp(array[i], proto.type, offset, buffer); + } + }else{ + for(i = 0; i < array.length; i++){ + offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag)); + offset = encodeProp(array[i], proto.type, offset, buffer, protos); + } + } + + return offset; + } + + function writeBytes(buffer, offset, bytes){ + for(var i = 0; i < bytes.length; i++, offset++){ + buffer[offset] = bytes[i]; + } + + return offset; + } + + function encodeTag(type, tag){ + var value = constant.TYPES[type]||2; + return codec.encodeUInt32((tag<<3)|value); + } +})('undefined' !== typeof protobuf ? protobuf : module.exports, this); + +/** + * decoder module + */ +(function (exports, global){ + var protobuf = exports; + var MsgDecoder = exports.decoder = {}; + + var codec = protobuf.codec; + var util = protobuf.util; + + var buffer; + var offset = 0; + + MsgDecoder.init = function(protos){ + this.protos = protos || {}; + }; + + MsgDecoder.setProtos = function(protos){ + if(!!protos){ + this.protos = protos; + } + }; + + MsgDecoder.decode = function(route, buf){ + var protos = this.protos[route]; + + buffer = buf; + offset = 0; + + if(!!protos){ + return decodeMsg({}, protos, buffer.length); + } + + return null; + }; + + function decodeMsg(msg, protos, length){ + while(offset>3 + }; + } + + /** + * Get tag head without move the offset + */ + function peekHead(){ + var tag = codec.decodeUInt32(peekBytes()); + + return { + type : tag&0x7, + tag : tag>>3 + }; + } + + function decodeProp(type, protos){ + switch(type){ + case 'uInt32': + return codec.decodeUInt32(getBytes()); + case 'int32' : + case 'sInt32' : + return codec.decodeSInt32(getBytes()); + case 'float' : + var float = codec.decodeFloat(buffer, offset); + offset += 4; + return float; + case 'double' : + var double = codec.decodeDouble(buffer, offset); + offset += 8; + return double; + case 'string' : + var length = codec.decodeUInt32(getBytes()); + + var str = codec.decodeStr(buffer, offset, length); + offset += length; + + return str; + default : + if(!!protos && !!protos.__messages[type]){ + var length = codec.decodeUInt32(getBytes()); + var msg = {}; + decodeMsg(msg, protos.__messages[type], offset+length); + return msg; + } + break; + } + } + + function decodeArray(array, type, protos){ + if(util.isSimpleType(type)){ + var length = codec.decodeUInt32(getBytes()); + + for(var i = 0; i < length; i++){ + array.push(decodeProp(type)); + } + }else{ + array.push(decodeProp(type, protos)); + } + } + + function getBytes(flag){ + var bytes = []; + var pos = offset; + flag = flag || false; + + var b; + + do{ + b = buffer[pos]; + bytes.push(b); + pos++; + }while(b >= 128); + + if(!flag){ + offset = pos; + } + return bytes; + } + + function peekBytes(){ + return getBytes(true); + } + +})('undefined' !== typeof protobuf ? protobuf : module.exports, this); diff --git a/proxy/lib/deps/pomelo-protocol.js b/proxy/lib/deps/pomelo-protocol.js new file mode 100644 index 0000000..29c34ca --- /dev/null +++ b/proxy/lib/deps/pomelo-protocol.js @@ -0,0 +1,341 @@ +const ByteArray = Uint8Array; +var Protocol = exports; + + +var PKG_HEAD_BYTES = 4; +var MSG_FLAG_BYTES = 1; +var MSG_ROUTE_CODE_BYTES = 2; +var MSG_ID_MAX_BYTES = 5; +var MSG_ROUTE_LEN_BYTES = 1; + +var MSG_ROUTE_CODE_MAX = 0xffff; + +var MSG_COMPRESS_ROUTE_MASK = 0x1; +var MSG_TYPE_MASK = 0x7; + +var Package = Protocol.Package = {}; +var Message = Protocol.Message = {}; + +Package.TYPE_HANDSHAKE = 1; +Package.TYPE_HANDSHAKE_ACK = 2; +Package.TYPE_HEARTBEAT = 3; +Package.TYPE_DATA = 4; +Package.TYPE_KICK = 5; + +Message.TYPE_REQUEST = 0; +Message.TYPE_NOTIFY = 1; +Message.TYPE_RESPONSE = 2; +Message.TYPE_PUSH = 3; + +/** + * pomele client encode + * id message id; + * route message route + * msg message body + * socketio current support string + */ +Protocol.strencode = function(str) { + var byteArray = new ByteArray(str.length * 3); + var offset = 0; + for(var i = 0; i < str.length; i++){ + var charCode = str.charCodeAt(i); + var codes = null; + if(charCode <= 0x7f){ + codes = [charCode]; + }else if(charCode <= 0x7ff){ + codes = [0xc0|(charCode>>6), 0x80|(charCode & 0x3f)]; + }else{ + codes = [0xe0|(charCode>>12), 0x80|((charCode & 0xfc0)>>6), 0x80|(charCode & 0x3f)]; + } + for(var j = 0; j < codes.length; j++){ + byteArray[offset] = codes[j]; + ++offset; + } + } + var _buffer = new ByteArray(offset); + copyArray(_buffer, 0, byteArray, 0, offset); + return _buffer; +}; + +/** + * client decode + * msg String data + * return Message Object + */ +Protocol.strdecode = function(buffer) { + var bytes = new ByteArray(buffer); + var array = []; + var offset = 0; + var charCode = 0; + var end = bytes.length; + while(offset < end){ + if(bytes[offset] < 128){ + charCode = bytes[offset]; + offset += 1; + }else if(bytes[offset] < 224){ + charCode = ((bytes[offset] & 0x3f)<<6) + (bytes[offset+1] & 0x3f); + offset += 2; + }else{ + charCode = ((bytes[offset] & 0x0f)<<12) + ((bytes[offset+1] & 0x3f)<<6) + (bytes[offset+2] & 0x3f); + offset += 3; + } + array.push(charCode); + } + var res = ''; + var chunk = 8 * 1024; + var i; + for (i = 0; i < array.length / chunk; i++) { + res += String.fromCharCode.apply(null, array.slice(i * chunk, (i + 1) * chunk)); + } + res += String.fromCharCode.apply(null, array.slice(i * chunk)); + return res; +}; + +/** + * Package protocol encode. + * + * Pomelo package format: + * +------+-------------+------------------+ + * | type | body length | body | + * +------+-------------+------------------+ + * + * Head: 4bytes + * 0: package type, + * 1 - handshake, + * 2 - handshake ack, + * 3 - heartbeat, + * 4 - data + * 5 - kick + * 1 - 3: big-endian body length + * Body: body length bytes + * + * @param {Number} type package type + * @param {ByteArray} body body content in bytes + * @return {ByteArray} new byte array that contains encode result + */ +Package.encode = function(type, body){ + var length = body ? body.length : 0; + var buffer = new ByteArray(PKG_HEAD_BYTES + length); + var index = 0; + buffer[index++] = type & 0xff; + buffer[index++] = (length >> 16) & 0xff; + buffer[index++] = (length >> 8) & 0xff; + buffer[index++] = length & 0xff; + if(body) { + copyArray(buffer, index, body, 0, length); + } + return buffer; +}; + +/** + * Package protocol decode. + * See encode for package format. + * + * @param {ByteArray} buffer byte array containing package content + * @return {Object} {type: package type, buffer: body byte array} + */ +Package.decode = function(buffer){ + var bytes = new ByteArray(buffer); + var type = bytes[0]; + var index = 1; + var length = ((bytes[index++]) << 16 | (bytes[index++]) << 8 | bytes[index++]) >>> 0; + var body = length ? new ByteArray(length) : null; + copyArray(body, 0, bytes, PKG_HEAD_BYTES, length); + return {'type': type, 'body': body}; +}; + +/** + * Message protocol encode. + * + * @param {Number} id message id + * @param {Number} type message type + * @param {Number} compressRoute whether compress route + * @param {Number|String} route route code or route string + * @param {Buffer} msg message body bytes + * @return {Buffer} encode result + */ +Message.encode = function(id, type, compressRoute, route, msg){ + // caculate message max length + var idBytes = msgHasId(type) ? caculateMsgIdBytes(id) : 0; + var msgLen = MSG_FLAG_BYTES + idBytes; + + if(msgHasRoute(type)) { + if(compressRoute) { + if(typeof route !== 'number'){ + throw new Error('error flag for number route!'); + } + msgLen += MSG_ROUTE_CODE_BYTES; + } else { + msgLen += MSG_ROUTE_LEN_BYTES; + if(route) { + route = Protocol.strencode(route); + if(route.length>255) { + throw new Error('route maxlength is overflow'); + } + msgLen += route.length; + } + } + } + + if(msg) { + msgLen += msg.length; + } + + var buffer = new ByteArray(msgLen); + var offset = 0; + + // add flag + offset = encodeMsgFlag(type, compressRoute, buffer, offset); + + // add message id + if(msgHasId(type)) { + offset = encodeMsgId(id, idBytes, buffer, offset); + } + + // add route + if(msgHasRoute(type)) { + offset = encodeMsgRoute(compressRoute, route, buffer, offset); + } + + // add body + if(msg) { + offset = encodeMsgBody(msg, buffer, offset); + } + + return buffer; +}; + +/** + * Message protocol decode. + * + * @param {Buffer|Uint8Array} buffer message bytes + * @return {Object} message object + */ +Message.decode = function(buffer) { + var bytes = new ByteArray(buffer); + var bytesLen = bytes.length || bytes.byteLength; + var offset = 0; + var id = 0; + var route = null; + + // parse flag + var flag = bytes[offset++]; + var compressRoute = flag & MSG_COMPRESS_ROUTE_MASK; + var type = (flag >> 1) & MSG_TYPE_MASK; + + // parse id + if(msgHasId(type)) { + var byte = bytes[offset++]; + id = byte & 0x7f; + while(byte & 0x80) { + id <<= 7; + byte = bytes[offset++]; + id |= byte & 0x7f; + } + } + + // parse route + if(msgHasRoute(type)) { + if(compressRoute) { + route = (bytes[offset++]) << 8 | bytes[offset++]; + } else { + var routeLen = bytes[offset++]; + if(routeLen) { + route = new ByteArray(routeLen); + copyArray(route, 0, bytes, offset, routeLen); + route = Protocol.strdecode(route); + } else { + route = ''; + } + offset += routeLen; + } + } + + // parse body + var bodyLen = bytesLen - offset; + var body = new ByteArray(bodyLen); + + copyArray(body, 0, bytes, offset, bodyLen); + + return {'id': id, 'type': type, 'compressRoute': compressRoute, + 'route': route, 'body': body}; +}; + +var copyArray = function(dest, doffset, src, soffset, length) { + if('function' === typeof src.copy) { + // Buffer + src.copy(dest, doffset, soffset, soffset + length); + } else { + // Uint8Array + for(var index=0; index>= 7; + } while(id > 0); + return len; +}; + +var encodeMsgFlag = function(type, compressRoute, buffer, offset) { + if(type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY && + type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) { + throw new Error('unkonw message type: ' + type); + } + + buffer[offset] = (type << 1) | (compressRoute ? 1 : 0); + + return offset + MSG_FLAG_BYTES; +}; + +var encodeMsgId = function(id, idBytes, buffer, offset) { + var index = offset + idBytes - 1; + buffer[index--] = id & 0x7f; + while(index >= offset) { + id >>= 7; + buffer[index--] = id & 0x7f | 0x80; + } + return offset + idBytes; +}; + +var encodeMsgRoute = function(compressRoute, route, buffer, offset) { + if (compressRoute) { + if(route > MSG_ROUTE_CODE_MAX){ + throw new Error('route number is overflow'); + } + + buffer[offset++] = (route >> 8) & 0xff; + buffer[offset++] = route & 0xff; + } else { + if(route) { + buffer[offset++] = route.length & 0xff; + copyArray(buffer, offset, route, 0, route.length); + offset += route.length; + } else { + buffer[offset++] = 0; + } + } + + return offset; +}; + +var encodeMsgBody = function(msg, buffer, offset) { + copyArray(buffer, offset, msg, 0, msg.length); + return offset + msg.length; +}; + +module.exports = Protocol; \ No newline at end of file diff --git a/proxy/node_modules/.package-lock.json b/proxy/node_modules/.package-lock.json new file mode 100644 index 0000000..150e538 --- /dev/null +++ b/proxy/node_modules/.package-lock.json @@ -0,0 +1,16 @@ +{ + "name": "proxy", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/bytearray": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/bytearray/-/bytearray-0.1.3.tgz", + "integrity": "sha512-oEKhhGYMfEdfnp4yViXVeauXLLYLj0hs8cQpJmu0JXbhuVX1iTeVmZ2IW4QtXhBcZitzOZ6pYNRvMDJRl5/0og==", + "engines": { + "node": ">= 0.8.0" + } + } + } +} diff --git a/proxy/node_modules/bytearray/.jshintrc b/proxy/node_modules/bytearray/.jshintrc new file mode 100644 index 0000000..2c40c44 --- /dev/null +++ b/proxy/node_modules/bytearray/.jshintrc @@ -0,0 +1,15 @@ +{ + "curly": true, + "eqeqeq": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "sub": true, + "undef": true, + "unused": true, + "boss": true, + "eqnull": true, + "node": true, + "es5": true +} diff --git a/proxy/node_modules/bytearray/.npmignore b/proxy/node_modules/bytearray/.npmignore new file mode 100644 index 0000000..205494f --- /dev/null +++ b/proxy/node_modules/bytearray/.npmignore @@ -0,0 +1,3 @@ +/node_modules/ +.DS_Store +*.swp diff --git a/proxy/node_modules/bytearray/LICENSE-MIT b/proxy/node_modules/bytearray/LICENSE-MIT new file mode 100644 index 0000000..2524e84 --- /dev/null +++ b/proxy/node_modules/bytearray/LICENSE-MIT @@ -0,0 +1,22 @@ +Copyright (c) 2013 yi + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/proxy/node_modules/bytearray/README.md b/proxy/node_modules/bytearray/README.md new file mode 100644 index 0000000..54ea7a7 --- /dev/null +++ b/proxy/node_modules/bytearray/README.md @@ -0,0 +1,31 @@ +# bytearray + +a Node.JS module for Buffer processing exposes API similar to ByteArray of ActionScript + +## Install +Install the module with: `npm install bytearray` + +```javascript +var bytearray = require('bytearray'); +``` + +## Usage + * bytearray.readBoolean(buf, [offset]):Boolean + * bytearray.readInt(buf, [offset]):int + * bytearray.readShort(buf, [offset]):int + * bytearray.readUnsignedByte(buf, [offset]):uint + * bytearray.readUnsignedInt(buf, [offset]):uint + * bytearray.readUnsignedShort(buf, [offset]):uint + * bytearray.readUTF(buf, [offset]):String + * bytearray.readUTFByte(buf, [offset]s(length:uint):String + * bytearray.writeBoolean(value:Boolean):void + * bytearray.writeByte(value:int):void + * bytearray.writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void + * bytearray.writeInt(value:int):void + * bytearray.writeShort(value:int):void + * bytearray.writeUnsignedInt(value:uint):void + * bytearray.writeUTF(value:String):void + +## License +Copyright (c) 2013 yi +Licensed under the MIT license. diff --git a/proxy/node_modules/bytearray/bin/coffee-watch.bat b/proxy/node_modules/bytearray/bin/coffee-watch.bat new file mode 100755 index 0000000..734c3d0 --- /dev/null +++ b/proxy/node_modules/bytearray/bin/coffee-watch.bat @@ -0,0 +1 @@ +coffee -o ./lib/ -cw ./src/ diff --git a/proxy/node_modules/bytearray/lib/bytearray.js b/proxy/node_modules/bytearray/lib/bytearray.js new file mode 100644 index 0000000..eacc05c --- /dev/null +++ b/proxy/node_modules/bytearray/lib/bytearray.js @@ -0,0 +1,367 @@ +// Generated by CoffeeScript 1.6.3 +/* +# a collection of utility methods for Buffer +# +# 这个工具类的设计以实现两个目地 +# 1. 读写方法,匹配 Actionscript 的 ByteArray 读写方法 +# 2. ActionScript 的默认采用 big endian,这个工具方法,对此进行封装,以是外部不用关心 endian +# +*/ + + +(function() { + module.exports = { + readUTF: function(buf, offset) { + var len; + if (!Buffer.isBuffer(buf)) { + return null; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + if (buf.length <= offset + 2) { + return null; + } + len = buf.readUInt16BE(offset); + if (buf.length < len + offset) { + return null; + } + offset += 2; + buf.position = offset + len; + return buf.toString('utf8', offset, offset + len); + }, + readUTFBytes: function(buf, length, offset) { + if (!Buffer.isBuffer(buf)) { + return null; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + if (buf.length <= offset) { + return null; + } + buf.position = offset + length; + return buf.toString('utf8', offset, offset + length); + }, + readFixLengthASCII: function(buf, offset) { + var len; + if (!Buffer.isBuffer(buf)) { + return null; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + if (buf.length <= offset + 2) { + return null; + } + len = buf.readUInt8(offset); + if (buf.length < len + offset) { + return null; + } + offset += 1; + buf.position = offset + len; + return buf.toString('utf8', offset, offset + len); + }, + readUnsignedShort: function(buf, offset) { + if (!Buffer.isBuffer(buf)) { + return 0; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.position = offset + 2; + return buf.readUInt16BE(offset); + }, + readShort: function(buf, offset) { + if (!Buffer.isBuffer(buf)) { + return 0; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.position = offset + 2; + return buf.readInt16BE(offset); + }, + readUnsignedByte: function(buf, offset) { + if (!Buffer.isBuffer(buf)) { + return 0; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.position = offset + 1; + return buf.readUInt8(offset); + }, + readByte: function(buf, offset) { + if (!Buffer.isBuffer(buf)) { + return 0; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.position = offset + 1; + return buf.readInt8(offset); + }, + readUnsignedInt: function(buf, offset) { + if (!Buffer.isBuffer(buf)) { + return 0; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.position = offset + 4; + return buf.readUInt32BE(offset); + }, + readInt: function(buf, offset) { + if (!Buffer.isBuffer(buf)) { + return 0; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.position = offset + 4; + return buf.readInt32BE(offset); + }, + readFloat: function(buf, offset) { + if (!Buffer.isBuffer(buf)) { + return 0; + } + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.position = offset + 4; + return buf.readFloatLE(offset); + }, + readUnsignedIntArray: function(buf, offset) { + var a, arr, len; + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + len = buf.readUInt16BE(offset) >>> 2; + offset += 2; + arr = []; + if (len === 0 || len > 1024) { + buf.position = offset; + return arr; + } + while (len > 0) { + a = buf.readUInt32BE(offset); + arr.push(a); + offset += 4; + len -= 1; + } + buf.position = offset; + return arr; + }, + writeUnsignedInt: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeUInt32BE(value, offset); + buf.position = offset + 4; + }, + writeInt: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeInt32BE(value, offset); + buf.position = offset + 4; + }, + writeFloat: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeFloatLE(value, offset); + buf.position = offset + 4; + }, + writeUnsignedShort: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeUInt16BE(value, offset); + buf.position = offset + 2; + }, + writeShort: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeInt16BE(value, offset); + buf.position = offset + 2; + }, + writeUnsignedByte: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeUInt8(value, offset); + buf.position = offset + 1; + }, + writeByte: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeInt8(value, offset); + buf.position = offset + 1; + }, + writeBoolean: function(buf, value, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + value = value ? 1 : 0; + buf.writeInt8(value, offset); + buf.position = offset + 1; + }, + writeFixLengthASCII: function(buf, str, maxNumOfChar, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.writeUInt8(maxNumOfChar, offset); + offset += 1; + buf.fill(0x20, offset, offset + maxNumOfChar); + buf.write(str, offset, maxNumOfChar, 'ascii'); + buf.position = offset + maxNumOfChar; + }, + writeFixLengthUTF: function(buf, str, maxNumOfChar, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + maxNumOfChar *= 6; + buf.writeUInt16BE(maxNumOfChar, offset); + offset += 2; + buf.fill(0x20, offset, offset + maxNumOfChar); + buf.write(str, offset, maxNumOfChar, 'utf8'); + buf.position = offset + maxNumOfChar; + }, + writeUTF: function(buf, str, offset) { + var byteLength; + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + byteLength = Buffer.byteLength(str); + buf.writeUInt16BE(byteLength, offset); + offset += 2; + buf.write(str, offset); + buf.position = offset + byteLength; + }, + writeUTFBytes: function(buf, str, offset) { + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + buf.write(str, offset); + buf.position = offset + Buffer.byteLength(str); + }, + writeUTFArray: function(buf, strArray, offset) { + var byteLength, str, _i, _len; + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + if (!((strArray != null) && strArray.length > 0)) { + buf.writeUInt16BE(0, offset); + buf.position = offset + 2; + return; + } + buf.writeUInt16BE(strArray.length, offset); + offset += 2; + for (_i = 0, _len = strArray.length; _i < _len; _i++) { + str = strArray[_i]; + byteLength = Buffer.byteLength(str); + buf.writeUInt16BE(byteLength, offset); + offset += 2; + buf.write(str, offset); + offset += byteLength; + } + return buf.position = offset; + }, + getByteLengthOfUTFArray: function(strArray) { + var len, str, _i, _len; + len = 2; + if (!((strArray != null) && strArray.length > 0)) { + return len; + } + for (_i = 0, _len = strArray.length; _i < _len; _i++) { + str = strArray[_i]; + len = len + 2 + Buffer.byteLength(str); + } + return len; + }, + writeUnsignedIntArray: function(buf, arr, fixedLength, offset) { + var i, n, _i, _len; + if (fixedLength == null) { + fixedLength = -1; + } + arr = arr || []; + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + n = arr.length; + if (fixedLength > 0 && fixedLength !== n) { + if (fixedLength < n) { + arr = arr.slice(0, fixedLength); + } else { + arr = arr.concat(); + arr.length = fixedLength; + } + n = fixedLength; + } + n = n << 2; + buf.writeUInt16BE(n, offset); + offset += 2; + for (_i = 0, _len = arr.length; _i < _len; _i++) { + i = arr[_i]; + buf.writeUInt32BE(parseInt(i, 10) || 0, offset); + offset += 4; + } + buf.position = offset; + }, + getByteLengthOfIntArray: function(arr) { + return (arr.length << 2) + 2; + }, + writeUnsignedShortArray: function(buf, arr, fixedLength, offset) { + var i, n, _i, _len; + if (fixedLength == null) { + fixedLength = -1; + } + arr = arr || []; + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + n = arr.length; + if (fixedLength > 0 && fixedLength !== n) { + if (fixedLength < n) { + arr = arr.slice(0, fixedLength); + } else { + arr = arr.concat(); + arr.length = fixedLength; + } + n = fixedLength; + } + n = n << 1; + buf.writeUInt16BE(n, offset); + offset += 2; + for (_i = 0, _len = arr.length; _i < _len; _i++) { + i = arr[_i]; + buf.writeUInt16BE(parseInt(i, 10) || 0, offset); + offset += 2; + } + buf.position = offset; + }, + getBytesAvailable: function(buf) { + if (buf != null) { + return buf.length - (buf.position || 0); + } else { + return 0; + } + }, + scrap: function(buf, length) { + var offset, result; + if (!((buf != null) && length > 0)) { + return null; + } + offset = buf.position || 0; + if (length + offset > buf.length) { + return null; + } + result = new Buffer(length); + buf.copy(result, 0, offset, offset + length); + buf.position = offset + length; + return result; + }, + duplicate: function(buf) { + var n, result; + n = buf.length || 0; + if (n === 0) { + return null; + } + result = new Buffer(n); + buf.copy(result, 0, 0, n); + return result; + }, + utfStringToBuf: function(str) { + var buf, n; + str = String(str || ''); + n = Buffer.byteLength(str, 'utf8'); + buf = new Buffer(n + 2); + buf.writeUInt16BE(n, 0); + buf.write(str, 2); + return buf; + }, + isAvailableBuf: function(buf) { + return Buffer.isBuffer(buf) && buf.length > 0; + }, + writeIntArray: function(buf, arr, fixedLength, offset) { + var i, n, _i, _len; + if (fixedLength == null) { + fixedLength = -1; + } + arr = arr || []; + offset = offset < 0 ? buf.length + offset : (offset === 0 ? 0 : offset || buf.position || 0); + n = arr.length; + if (fixedLength > 0 && fixedLength !== n) { + if (fixedLength < n) { + arr = arr.slice(0, fixedLength); + } else { + arr = arr.concat(); + arr.length = fixedLength; + } + n = fixedLength; + } + n = n << 2; + buf.writeUInt16BE(n, offset); + offset += 2; + for (_i = 0, _len = arr.length; _i < _len; _i++) { + i = arr[_i]; + buf.writeInt32BE(parseInt(i, 10) || 0, offset); + offset += 4; + } + buf.position = offset; + } + }; + +}).call(this); diff --git a/proxy/node_modules/bytearray/lib/test/bytearray_test.js b/proxy/node_modules/bytearray/lib/test/bytearray_test.js new file mode 100644 index 0000000..68a41db --- /dev/null +++ b/proxy/node_modules/bytearray/lib/test/bytearray_test.js @@ -0,0 +1,92 @@ +// Generated by CoffeeScript 1.6.3 +(function() { + var FIXTURE_UTF, FIXTURE_UTF_BUFF, FIXTURE_UTF_BYTE_LENGTH, FIXTURE_UTF_LENGTH, UNIT_ARR, VECTOR_UINT_1, VECTOR_UINT_STR_1, bytearray, should; + + require('mocha'); + + should = require('should'); + + bytearray = require('../byteArray'); + + FIXTURE_UTF = "这个LED花洒有意思,@陈中 可建议 @吴海 在桔子酒店引入,"; + + FIXTURE_UTF_LENGTH = FIXTURE_UTF.length; + + FIXTURE_UTF_BYTE_LENGTH = Buffer.byteLength(FIXTURE_UTF); + + FIXTURE_UTF_BUFF = new Buffer(2 + FIXTURE_UTF_BYTE_LENGTH); + + FIXTURE_UTF_BUFF.writeUInt16BE(FIXTURE_UTF_BYTE_LENGTH, 0); + + FIXTURE_UTF_BUFF.write(FIXTURE_UTF, 2); + + VECTOR_UINT_1 = [4196330, 4196812, 4198245, 4198550, 4196885, 4197941, 4197659, 4196640, 4196980, 4196368, 4196795, 4197527, 4196374, 4196672, 4197016, 4197661, 4197014, 4197449, 4197615, 4196330, 4196579, 4196714, 4196835, 4196808, 4196786, 4197947, 4196473, 4196646, 4197939, 4197928, 4196366, 4197926, 4197559, 4196333, 4198850, 4196840, 4197927, 4196511, 4197938, 4196812, 4197925, 4197526, 4196312, 4196804, 4197528, 4196682, 4196954, 4196409, 4196258, 4198177, 4196291, 4198245, 4198180, 4196216, 4198277, 4196263, 4198280, 4198276, 4198282, 4198201, 4198279, 4197004, 4198211, 4197011, 4196759, 4197097, 4196512, 4197018, 4198236, 4198304, 4196397, 4198237, 4198312, 4198198, 4198199, 4198259, 4198310, 4198305, 4197201, 4198160, 4198326, 4198189, 4197704, 4197257, 4198311, 4197475, 4198283, 4198222, 4196299, 4198250, 4198230, 4196996, 4198149, 4198315, 4197312, 4198327, 4199252, 4198181, 4198221, 4198316, 4198154, 4198244, 4196920, 4196943, 4198325, 4198320, 4196975, 4198249]; + + VECTOR_UINT_STR_1 = ["4196330", "4196812", "4198245", "4198550", "4196885", "4197941", "4197659", "4196640", "4196980", "4196368", "4196795", "4197527", "4196374", "4196672", "4197016", "4197661", "4197014", "4197449", "4197615", "4196330", "4196579", "4196714", "4196835", "4196808", "4196786", "4197947", "4196473", "4196646", "4197939", "4197928", "4196366", "4197926", "4197559", "4196333", "4198850", "4196840", "4197927", "4196511", "4197938", "4196812", "4197925", "4197526", "4196312", "4196804", "4197528", "4196682", "4196954", "4196409", "4196258", "4198177", "4196291", "4198245", "4198180", "4196216", "4198277", "4196263", "4198280", "4198276", "4198282", "4198201", "4198279", "4197004", "4198211", "4197011", "4196759", "4197097", "4196512", "4197018", "4198236", "4198304", "4196397", "4198237", "4198312", "4198198", "4198199", "4198259", "4198310", "4198305", "4197201", "4198160", "4198326", "4198189", "4197704", "4197257", "4198311", "4197475", "4198283", "4198222", "4196299", "4198250", "4198230", "4196996", "4198149", "4198315", "4197312", "4198327", "4199252", "4198181", "4198221", "4198316", "4198154", "4198244", "4196920", "4196943", "4198325", "4198320", "4196975", "4198249"]; + + UNIT_ARR = [1, 2, 3, 4, 5, 6, 0xfffffff1, 0xfffffff2]; + + describe('bytearray', function() { + it('should read/write dynamic length utf correctly', function() { + var buf; + buf = new Buffer(2 + FIXTURE_UTF_BYTE_LENGTH); + bytearray.writeUTF(buf, FIXTURE_UTF); + buf.toString('hex').should.eql(FIXTURE_UTF_BUFF.toString('hex')); + return bytearray.readUTF(buf, 0).should.eql(FIXTURE_UTF); + }); + it('should conver utf string to buffer correctly', function() { + var buf, byteLength, str; + str = "中午侧阿凡达是否违反片假名ニホンゴ,罗马音nihon go 将( المنهج الواضح لتعل&#..."; + byteLength = Buffer.byteLength(str); + buf = bytearray.utfStringToBuf(str); + bytearray.readUnsignedShort(buf, 0).should.eql(byteLength); + console.log("[bytearray_test::test utfStringToBuf] buf:" + (buf.toString('hex'))); + return buf.slice(2).toString('hex').should.eql((new Buffer(str)).toString('hex')); + }); + it('should able to write/read an uint vector', function() { + var arr, buf; + buf = new Buffer(VECTOR_UINT_1.length * 4 + 2); + bytearray.writeUnsignedIntArray(buf, VECTOR_UINT_1); + arr = bytearray.readUnsignedIntArray(buf, 0); + console.log("[bytearray_test::write/read an uint vector] arr:" + arr); + return arr.join(',').should.eql(VECTOR_UINT_1.join(',')); + }); + it('should able to write/read an string vector as an uint vector', function() { + var arr, buf; + buf = new Buffer(VECTOR_UINT_STR_1.length * 4 + 2); + bytearray.writeUnsignedIntArray(buf, VECTOR_UINT_STR_1); + arr = bytearray.readUnsignedIntArray(buf, 0); + console.log("[bytearray_test::write/read an uint vector] arr:" + arr); + return arr.join(',').should.eql(VECTOR_UINT_1.join(',')); + }); + it('should read and write UTFBytes correctly', function() { + var buf, buf2, byteLength, str; + str = "hellow, how are you"; + byteLength = Buffer.byteLength(str); + buf = new Buffer(byteLength); + bytearray.writeUTFBytes(buf, str); + buf2 = new Buffer(str); + buf.toString('hex').should.equal(buf2.toString('hex')); + buf.position.should.equal(byteLength); + return bytearray.readUTFBytes(buf, byteLength, 0).should.equal(str); + }); + return it('should read and write Float correctly', function() { + var buf, i, orgin, readback, sample, _i, _j, _ref, _ref1, _results; + sample = [321.324241, 0.323131, 4242.5435, 0.43242342]; + buf = new Buffer(sample.length * 4); + for (i = _i = 0, _ref = sample.length; _i < _ref; i = _i += 1) { + bytearray.writeFloat(buf, sample[i]); + } + buf.position = 0; + _results = []; + for (i = _j = 0, _ref1 = sample.length; _j < _ref1; i = _j += 1) { + orgin = sample[i]; + readback = bytearray.readFloat(buf); + console.log("[bytearray_test::Float test] orgin:" + orgin + ", readback:" + readback); + _results.push(Math.abs(readback - orgin).should.below(0.01)); + } + return _results; + }); + }); + +}).call(this); diff --git a/proxy/node_modules/bytearray/package.json b/proxy/node_modules/bytearray/package.json new file mode 100644 index 0000000..94aea20 --- /dev/null +++ b/proxy/node_modules/bytearray/package.json @@ -0,0 +1,36 @@ +{ + "name": "bytearray", + "description": "a Node.JS module for Buffer processing exposes API similar to ByteArray of ActionScript", + "version": "0.1.3", + "homepage": "https://github.com/yi/node-bytearray", + "author": { + "name": "yi", + "email": "yi2004@gmail.com" + }, + "repository": { + "type": "git", + "url": "git://github.com/yi/node-bytearray.git" + }, + "bugs": { + "url": "https://github.com/yi/node-bytearray/issues" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/yi/node-bytearray/blob/master/LICENSE-MIT" + } + ], + "main": "lib/bytearray", + "engines": { + "node": ">= 0.8.0" + }, + "scripts": { + "test": "mocha tests/bytearray_test.js" + }, + "devDependencies": { + "chai": ">=1.2.0", + "mocha": ">=1.3.2", + "should": ">=1.1.0" + }, + "keywords": ["buffer","buf","endian","actionscript","bytearray"] +} diff --git a/proxy/node_modules/bytearray/src/bytearray.coffee b/proxy/node_modules/bytearray/src/bytearray.coffee new file mode 100644 index 0000000..4e2fbbc --- /dev/null +++ b/proxy/node_modules/bytearray/src/bytearray.coffee @@ -0,0 +1,437 @@ +### +# a collection of utility methods for Buffer +# +# 这个工具类的设计以实现两个目地 +# 1. 读写方法,匹配 Actionscript 的 ByteArray 读写方法 +# 2. ActionScript 的默认采用 big endian,这个工具方法,对此进行封装,以是外部不用关心 endian +# +### + +module.exports = + + # Reads a UTF-8 string from the byte stream. The string is assumed to be prefixed with an unsigned short indicating the length in bytes. + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readUTF : (buf, offset)-> + return null unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + return null if buf.length <= offset + 2 + len = buf.readUInt16BE(offset) + #console.log "[readUTF] buf.position:#{buf.position}, buf.length:#{buf.length}, offset:#{offset}, len:#{len} " + return null if buf.length < len + offset + offset += 2 + buf.position = offset + len + return buf.toString 'utf8', offset, offset+len + + # Reads a sequence of UTF-8 bytes specified by the length parameter from the byte stream and returns a string. + # @param {Buff} buf + # @param {uint} length, number of bytes to read + # @param {int} [offset] optional, specify the offset where read should beging + readUTFBytes : (buf, length, offset)-> + return null unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + return null if buf.length <= offset + buf.position = offset + length + #console.log "[bytearray::readUTFBytes] buf:#{buf}, offset:#{offset}" + return buf.toString('utf8', offset, offset + length) + + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readFixLengthASCII : (buf, offset) -> + return null unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + return null if buf.length <= offset + 2 + len = buf.readUInt8(offset) + return null if buf.length < len + offset + offset += 1 + buf.position = offset + len + buf.toString 'utf8', offset, offset+len + + # Reads an unsigned 16-bit integer from the byte stream. + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readUnsignedShort : (buf, offset)-> + return 0 unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.position = offset + 2 + return buf.readUInt16BE offset + + # Reads a 16-bit integer from the byte stream. + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readShort : (buf, offset)-> + return 0 unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.position = offset + 2 + buf.readInt16BE offset + + # co-read to actionscript's ByteArray.readUnsignedByte + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readUnsignedByte : (buf, offset)-> + return 0 unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.position = offset + 1 + buf.readUInt8 offset + + # Reads a byte from the byte stream. + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readByte : (buf, offset)-> + return 0 unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.position = offset + 1 + buf.readInt8 offset + + # Reads an unsigned byte from the byte stream. + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readUnsignedInt: (buf, offset)-> + return 0 unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.position = offset + 4 + buf.readUInt32BE offset + + # Reads a signed 32-bit integer from the byte stream. + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readInt: (buf, offset)-> + return 0 unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.position = offset + 4 + buf.readInt32BE offset + + # Reads a signed 32-bit integer from the byte stream. + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readFloat : (buf, offset)-> + return 0 unless Buffer.isBuffer buf + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.position = offset + 4 + buf.readFloatLE offset + # TODO: + # this is a quick hack, should implement a proper endian swicher + # ty 2013-10-08 + + + + # @param {Buff} buf + # @param {int} [offset] optional, specify the offset where read should beging + readUnsignedIntArray:(buf, offset)-> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + len = buf.readUInt16BE(offset) >>> 2 # *4 bytes for an int + offset += 2 + arr = [] + if len is 0 or len > 1024 + buf.position = offset + return arr + while(len > 0) + a = buf.readUInt32BE(offset) + arr.push(a) + offset += 4 + len -= 1 + buf.position = offset + return arr + + # @param {Buff} buf + # @param {uint} value + # @param {int} [offset] optional, specify the offset where read should beging + writeUnsignedInt : (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + #console.log "[msg] buf.length:#{buf.length}, offset:#{offset}" + buf.writeUInt32BE value, offset + buf.position = offset + 4 + return + + # @param {Buff} buf + # @param {int} value + # @param {int} [offset] optional, specify the offset where read should beging + writeInt : (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.writeInt32BE value, offset + buf.position = offset + 4 + return + + + # @param {Buff} buf + # @param {int} value + # @param {int} [offset] optional, specify the offset where read should beging + writeFloat : (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.writeFloatLE value, offset + # TODO: + # this is a quick hack, should implement a proper endian swicher + # ty 2013-10-08 + + buf.position = offset + 4 + return + + + + + # @param {Buff} buf + # @param {ushort} value + # @param {int} [offset] optional, specify the offset where read should beging + writeUnsignedShort: (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.writeUInt16BE value, offset + buf.position = offset + 2 + return + + # @param {Buff} buf + # @param {short} value + # @param {int} [offset] optional, specify the offset where read should beging + writeShort: (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.writeInt16BE value, offset + buf.position = offset + 2 + return + + # @param {Buff} buf + # @param {ubyte} value + # @param {int} [offset] optional, specify the offset where read should beging + writeUnsignedByte: (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.writeUInt8 value, offset + buf.position = offset + 1 + return + + # @param {Buff} buf + # @param {byte} value + # @param {int} [offset] optional, specify the offset where read should beging + writeByte: (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.writeInt8 value, offset + buf.position = offset + 1 + return + + # @param {Buff} buf + # @param {Boolean} value + # @param {int} [offset] optional, specify the offset where read should beging + writeBoolean: (buf, value, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + value = if value then 1 else 0 + buf.writeInt8 value, offset + buf.position = offset + 1 + return + + # 以 ASCII 方式在定长bytes中写入给定的字符串,并且保持 position 的连续 + # buf : 需要写入的 Buffer 实例 + # str : 需要写入的字符串 + # maxNumOfChar : 最多所写入的字符长度 + # offset : 从自定义的偏移处开始写 + writeFixLengthASCII : (buf, str, maxNumOfChar, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.writeUInt8 maxNumOfChar, offset + offset += 1 #+1 因为已经写了1byte的ascii 长度 + buf.fill(0x20, offset, offset + maxNumOfChar) # 整平这个目标buf + buf.write str, offset, maxNumOfChar, 'ascii' + buf.position = offset + maxNumOfChar + return + + # 以 UTF-8 方式在定长bytes中写入给定的字符串,并且保持 position 的连续 + # buf : 需要写入的 Buffer 实例 + # str : 需要写入的字符串 + # maxNumOfChar : 最多所写入的字符长度 + # offset : 从自定义的偏移处开始写 + writeFixLengthUTF: (buf, str, maxNumOfChar, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + maxNumOfChar *= 6 # 给每个 utf-8 char 预留 6 byte 的空间 + buf.writeUInt16BE maxNumOfChar, offset + offset += 2 # +2 因为已经写了2byte的utf长度 + buf.fill(0x20, offset, offset + maxNumOfChar) # 整平这个目标buf + buf.write str, offset, maxNumOfChar, 'utf8' + buf.position = offset + maxNumOfChar + return + + # 以 UTF-8 方式在bytes中写入动态长度的字符串,并且保持 position 的连续 + # buf : 需要写入的 Buffer 实例 + # str : 需要写入的字符串 + # offset : 从自定义的偏移处开始写 + writeUTF: (buf, str, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + byteLength = Buffer.byteLength(str) + buf.writeUInt16BE(byteLength , offset) + offset += 2 # +2 因为已经写了2byte的utf长度 + buf.write(str, offset) + buf.position = offset + byteLength + return + + # 以 UTF-8 方式在bytes中写入动态长度的字符串,并且保持 position 的连续 + # buf : 需要写入的 Buffer 实例 + # str : 需要写入的字符串 + # offset : 从自定义的偏移处开始写 + writeUTFBytes: (buf, str, offset) -> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + buf.write(str, offset) + buf.position = offset + Buffer.byteLength(str) + return + + # 以 UTF-8 方式在bytes中写入动态长度的字符串,并且保持 position 的连续 + # buf : 需要写入的 Buffer 实例 + # strArray : 需要写入的字符串数组 + # offset : 从自定义的偏移处开始写 + writeUTFArray:(buf,strArray,offset)-> + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + unless strArray? and strArray.length>0 + buf.writeUInt16BE(0 , offset) + buf.position=offset+2 + return + + buf.writeUInt16BE(strArray.length , offset) + offset += 2 # +2 因为已经写了2byte的utf长度 + for str in strArray + byteLength = Buffer.byteLength(str) + buf.writeUInt16BE(byteLength , offset) + offset += 2 # +2 因为已经写了2byte的utf长度 + buf.write(str, offset) + offset += byteLength + buf.position=offset + + + getByteLengthOfUTFArray:(strArray)-> + len=2 + return len unless strArray? and strArray.length>0 + for str in strArray + len=len+2+Buffer.byteLength(str) + return len + + + # 以int 的方式写入一个数组 + # @param buf : 需要写入的 Buffer 实例 + # @param arr : 需要写入的数组 + # @param offset : 从自定义的偏移处开始写 + # @param fixedLength : 写入数组的给定长度内容 + writeUnsignedIntArray:(buf, arr, fixedLength = -1, offset)-> + arr = arr || [] # make sure argument arr is usable + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + n = arr.length + if fixedLength > 0 and fixedLength isnt n + # user require to write a fixed length of the given array + if fixedLength < n + arr = arr.slice(0, fixedLength) + # NOTE 不能用 splice 因为会改变输入的array 的内容 arr.splice(fixedLength - n) + else + arr = arr.concat() # make a copy of the given arr + arr.length = fixedLength + n = fixedLength + + n = n << 2 # *4 bytes for an int + buf.writeUInt16BE(n, offset) + offset += 2 + + for i in arr + buf.writeUInt32BE( parseInt(i,10) || 0 , offset) + offset += 4 + + buf.position = offset + return + + # 计算出给定的int数组要写入成二进制时所占的byte长度 + # @param {int[]} arr an integer array + getByteLengthOfIntArray : (arr) -> + (arr.length << 2) + 2 + + + # 以 short 的方式写入一个数组 + # @param buf : 需要写入的 Buffer 实例 + # @param arr : 需要写入的数组 + # @param offset : 从自定义的偏移处开始写 + # @param fixedLength : 写入数组的给定长度内容 + writeUnsignedShortArray:(buf, arr, fixedLength = -1, offset)-> + #console.log "[offset 1]:#{offset}" + arr = arr || [] # make sure argument arr is usable + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + #console.log "[offset 2]:#{offset}" + n = arr.length + if fixedLength > 0 and fixedLength isnt n + # user require to write a fixed length of the given array + if fixedLength < n + arr = arr.slice(0, fixedLength) + # NOTE 不能用 splice 因为会改变输入的array 的内容 arr.splice(fixedLength - n) + else + arr = arr.concat() # make a copy of the given arr + arr.length = fixedLength + n = fixedLength + + n = n << 1 # * 2 bytes for a short + #console.log "[offset]:#{offset}" + buf.writeUInt16BE(n, offset) + offset += 2 + + for i in arr + buf.writeUInt16BE( parseInt(i, 10) || 0 , offset) + offset += 2 + + buf.position = offset + return + + # 计算一个 buf 从当前的 position 开始还有多少byte 可以读取 + getBytesAvailable : (buf) -> + return if buf? then buf.length - (buf.position || 0) else 0 + + # 从给定的buf的当前position位置,复制出给定length的byte片段,并且推进buf的position属性 + scrap : (buf, length) -> + return null unless buf? and length > 0 + offset = (buf.position || 0) + return null if length + offset > buf.length + result = new Buffer(length) + buf.copy(result, 0, offset, offset + length) + buf.position = offset + length + return result + + # 复制一个和给定的 buf 完全一样的新buf + duplicate : (buf) -> + n = buf.length || 0 + return null if n is 0 + result = new Buffer(n) + buf.copy result, 0, 0, n + return result + + # convert an input str to buffer by utf8 encoding, and add byte length by a short at the begine of the buffer + utfStringToBuf : (str) -> + str = String(str || '') + n = Buffer.byteLength(str, 'utf8') + buf = new Buffer(n+2) + buf.writeUInt16BE(n,0) + buf.write(str, 2) + return buf + + #是buf并且buf length >0 + isAvailableBuf:(buf)-> + return Buffer.isBuffer(buf) and buf.length>0 + + # 以int 的方式写入一个数组 + # @param buf : 需要写入的 Buffer 实例 + # @param arr : 需要写入的数组 + # @param offset : 从自定义的偏移处开始写 + # @param fixedLength : 写入数组的给定长度内容 + writeIntArray:(buf, arr, fixedLength = -1, offset)-> + arr = arr || [] # make sure argument arr is usable + offset = if offset < 0 then buf.length + offset else (if offset is 0 then 0 else offset || buf.position || 0) + n = arr.length + if fixedLength > 0 and fixedLength isnt n + # user require to write a fixed length of the given array + if fixedLength < n + arr = arr.slice(0, fixedLength) + # NOTE 不能用 splice 因为会改变输入的array 的内容 arr.splice(fixedLength - n) + else + arr = arr.concat() # make a copy of the given arr + arr.length = fixedLength + n = fixedLength + + n = n << 2 # *4 bytes for an int + buf.writeUInt16BE(n, offset) + offset += 2 + + for i in arr + buf.writeInt32BE( parseInt(i,10) || 0 , offset) + offset += 4 + + buf.position = offset + return + + + + + diff --git a/proxy/node_modules/bytearray/src/test/bytearray_test.coffee b/proxy/node_modules/bytearray/src/test/bytearray_test.coffee new file mode 100644 index 0000000..9b1811e --- /dev/null +++ b/proxy/node_modules/bytearray/src/test/bytearray_test.coffee @@ -0,0 +1,86 @@ + +require 'mocha' +should = require 'should' + +bytearray = require '../byteArray' + +FIXTURE_UTF = "这个LED花洒有意思,@陈中 可建议 @吴海 在桔子酒店引入," +FIXTURE_UTF_LENGTH = FIXTURE_UTF.length +FIXTURE_UTF_BYTE_LENGTH = Buffer.byteLength(FIXTURE_UTF) +FIXTURE_UTF_BUFF = new Buffer(2 + FIXTURE_UTF_BYTE_LENGTH) +FIXTURE_UTF_BUFF.writeUInt16BE( FIXTURE_UTF_BYTE_LENGTH, 0) +FIXTURE_UTF_BUFF.write(FIXTURE_UTF, 2) + + +VECTOR_UINT_1 = [4196330,4196812,4198245,4198550,4196885,4197941,4197659,4196640,4196980,4196368,4196795,4197527,4196374,4196672,4197016,4197661,4197014,4197449,4197615,4196330,4196579,4196714,4196835,4196808,4196786,4197947,4196473,4196646,4197939,4197928,4196366,4197926,4197559,4196333,4198850,4196840,4197927,4196511,4197938,4196812,4197925,4197526,4196312,4196804,4197528,4196682,4196954,4196409,4196258,4198177,4196291,4198245,4198180,4196216,4198277,4196263,4198280,4198276,4198282,4198201,4198279,4197004,4198211,4197011,4196759,4197097,4196512,4197018,4198236,4198304,4196397,4198237,4198312,4198198,4198199,4198259,4198310,4198305,4197201,4198160,4198326,4198189,4197704,4197257,4198311,4197475,4198283,4198222,4196299,4198250,4198230,4196996,4198149,4198315,4197312,4198327,4199252,4198181,4198221,4198316,4198154,4198244,4196920,4196943,4198325,4198320,4196975,4198249] + +VECTOR_UINT_STR_1 = ["4196330","4196812","4198245","4198550","4196885","4197941","4197659","4196640","4196980","4196368","4196795","4197527","4196374","4196672","4197016","4197661","4197014","4197449","4197615","4196330","4196579","4196714","4196835","4196808","4196786","4197947","4196473","4196646","4197939","4197928","4196366","4197926","4197559","4196333","4198850","4196840","4197927","4196511","4197938","4196812","4197925","4197526","4196312","4196804","4197528","4196682","4196954","4196409","4196258","4198177","4196291","4198245","4198180","4196216","4198277","4196263","4198280","4198276","4198282","4198201","4198279","4197004","4198211","4197011","4196759","4197097","4196512","4197018","4198236","4198304","4196397","4198237","4198312","4198198","4198199","4198259","4198310","4198305","4197201","4198160","4198326","4198189","4197704","4197257","4198311","4197475","4198283","4198222","4196299","4198250","4198230","4196996","4198149","4198315","4197312","4198327","4199252","4198181","4198221","4198316","4198154","4198244","4196920","4196943","4198325","4198320","4196975","4198249"] + + +UNIT_ARR = [1,2,3,4,5,6,0xfffffff1, 0xfffffff2] + +describe 'bytearray', -> + + it 'should read/write dynamic length utf correctly', -> + buf = new Buffer(2 + FIXTURE_UTF_BYTE_LENGTH) + bytearray.writeUTF(buf, FIXTURE_UTF) + #console.log "[bytearray_test::] buf:#{buf.toString('hex')}" + buf.toString('hex').should.eql(FIXTURE_UTF_BUFF.toString('hex')) + #console.log "[bytearray_test::] bytearray.readUTF(buf, 0):#{bytearray.readUTF(buf, 0)}" + bytearray.readUTF(buf, 0).should.eql(FIXTURE_UTF) + + it 'should conver utf string to buffer correctly', -> + str = "中午侧阿凡达是否违反片假名ニホンゴ,罗马音nihon go 将( المنهج الواضح لتعل&#..." + byteLength = Buffer.byteLength(str) + buf = bytearray.utfStringToBuf(str) + bytearray.readUnsignedShort(buf,0).should.eql(byteLength) + console.log "[bytearray_test::test utfStringToBuf] buf:#{buf.toString('hex')}" + buf.slice(2).toString('hex').should.eql((new Buffer(str)).toString('hex')) + + it 'should able to write/read an uint vector', -> + buf = new Buffer(VECTOR_UINT_1.length * 4 + 2) + bytearray.writeUnsignedIntArray(buf, VECTOR_UINT_1) + arr = bytearray.readUnsignedIntArray(buf, 0) + console.log "[bytearray_test::write/read an uint vector] arr:#{arr}" + arr.join(',').should.eql(VECTOR_UINT_1.join(',')) + + it 'should able to write/read an string vector as an uint vector', -> + buf = new Buffer(VECTOR_UINT_STR_1.length * 4 + 2) + bytearray.writeUnsignedIntArray(buf, VECTOR_UINT_STR_1) + arr = bytearray.readUnsignedIntArray(buf, 0) + console.log "[bytearray_test::write/read an uint vector] arr:#{arr}" + arr.join(',').should.eql(VECTOR_UINT_1.join(',')) + + it 'should read and write UTFBytes correctly' , -> + str = "hellow, how are you" + byteLength = Buffer.byteLength(str) + buf = new Buffer byteLength + bytearray.writeUTFBytes buf, str + buf2 = new Buffer str + buf.toString('hex').should.equal(buf2.toString('hex')) + buf.position.should.equal(byteLength) + bytearray.readUTFBytes(buf, byteLength, 0).should.equal str + + it 'should read and write Float correctly' , -> + sample = [321.324241, 0.323131, 4242.5435, 0.43242342] + buf = new Buffer sample.length * 4 + for i in [0...sample.length] by 1 + bytearray.writeFloat buf, sample[i] + + buf.position = 0 + + for i in [0...sample.length] by 1 + orgin = sample[i] + readback = bytearray.readFloat(buf) + console.log "[bytearray_test::Float test] orgin:#{orgin}, readback:#{readback}" + Math.abs(readback - orgin).should.below(0.01) + + + + + + + + + + diff --git a/proxy/package-lock.json b/proxy/package-lock.json new file mode 100644 index 0000000..a7ad3cb --- /dev/null +++ b/proxy/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "proxy", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "proxy", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "bytearray": "^0.1.3" + } + }, + "node_modules/bytearray": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/bytearray/-/bytearray-0.1.3.tgz", + "integrity": "sha512-oEKhhGYMfEdfnp4yViXVeauXLLYLj0hs8cQpJmu0JXbhuVX1iTeVmZ2IW4QtXhBcZitzOZ6pYNRvMDJRl5/0og==", + "engines": { + "node": ">= 0.8.0" + } + } + } +} diff --git a/proxy/package.json b/proxy/package.json new file mode 100644 index 0000000..d71bf5e --- /dev/null +++ b/proxy/package.json @@ -0,0 +1,15 @@ +{ + "name": "proxy", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "bytearray": "^0.1.3" + } +}