├── LICENSE ├── README.md ├── dest ├── RongIMClient.js └── RongIMClient.js.map ├── external ├── WebSocketMain.zip ├── protobuf.js ├── swfobject.js └── xhrpolling.js ├── index.html ├── modules ├── Embedded.js ├── emoji-0.9.2.js ├── indexedDB.js ├── loadImage.js └── voice-0.9.1.js ├── package.json ├── src ├── IMClient │ ├── IMEnum.js │ ├── RongIMClient.js │ ├── affiliatedMessage.js │ ├── coustomMessage.js │ ├── entry.js │ └── shim.js ├── binary.js ├── core │ ├── bridge.js │ ├── channel.js │ ├── client.js │ ├── messageCallback.js │ ├── messageHandler.js │ └── messageParser.js ├── enum.js ├── io │ ├── base.js │ ├── factory.js │ ├── polling.js │ └── websocket.js ├── mapping.js ├── md5.js ├── message │ ├── Message.js │ ├── MessageEntity.js │ ├── msgEnum.js │ └── throttleStream.js ├── ready.js └── tool.js ├── test └── Junit.js ├── web_SDK_文件结构说明.txt └── webpack.config.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 融云 RongCloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rongcloud-web-im-sdk v1 [已废弃] 2 | 3 | 请移步 Web IM SDK 2.0 [https://github.com/rongcloud/rongcloud-web-im-sdk-v2](https://github.com/rongcloud/rongcloud-web-im-sdk-v2) 4 | 5 | 官方不再对 v1 版本提供技术支持。 6 | 7 | 8 | ----------------------------------------------------------- 9 | 10 | ## 融云 Web SDK 0.9.x 版本 Demo 如何使用 11 | 12 | [文档参考](http://docs.rongcloud.cn/api/js/index.html " SDK 文档") 13 | 14 | [使用说明请见](https://github.com/rongcloud/demo-web-sdk/blob/master/README.md " 说明文档") 15 | 16 | #### 安装 `webpack` 17 | ``` 18 | $ npm install webpack -g 19 | ``` 20 | 21 | #### 执行 `webpack` 22 | 23 | ``` 24 | $ webpack 25 | ``` 26 | 27 | #### 具体配置请见 `webpack.config.js` 28 | 29 | 测试前请修改index.html中的token,因为token可能不可用.
30 |
31 | *注意:为了更好的展现模块化,此次更新demo使用webpack来组织代码.*
32 | *本事例进攻参考,更多请关注rongcloud-web-im-sdk v2* 33 | -------------------------------------------------------------------------------- /external/WebSocketMain.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rongcloud/rongcloud-web-im-sdk/e1eaa23c30ad553adba537537ccf3b3c420b7904/external/WebSocketMain.zip -------------------------------------------------------------------------------- /external/xhrpolling.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yataozhang on 15/1/23. 3 | */ 4 | (function (d) { 5 | if (!('now' in Date)) { 6 | Date.now = function () { 7 | var d = new Date(); 8 | return d.getTime(); 9 | } 10 | } 11 | var e = { 12 | NotifyMsg: function () { 13 | var a = {}; 14 | this.setType = function (b) { 15 | a.type = b 16 | }; 17 | this.setTime = function (b) { 18 | a.time = b; 19 | }; 20 | this.toArrayBuffer = function () { 21 | return a; 22 | } 23 | }, 24 | SyncRequestMsg: function () { 25 | var a = {}; 26 | this.setSyncTime = function (b) { 27 | a.syncTime = b || 0; 28 | }; 29 | this.setIspolling = function (b) { 30 | a.ispolling = !!b 31 | }; 32 | this.toArrayBuffer = function () { 33 | return a 34 | } 35 | }, 36 | UpStreamMessage: function () { 37 | var a = {}; 38 | this.setSessionId = function (b) { 39 | a.sessionId = b 40 | }; 41 | this.setClassname = function (b) { 42 | a.classname = b 43 | }; 44 | this.setContent = function (b) { 45 | if (b) a.content = b; 46 | }; 47 | this.setPushText = function (b) { 48 | a.pushText = b 49 | }; 50 | this.toArrayBuffer = function () { 51 | return a 52 | } 53 | }, 54 | DownStreamMessages: function () { 55 | var a = {}; 56 | this.setList = function (b) { 57 | a.list = b 58 | }; 59 | this.setSyncTime = function (b) { 60 | a.syncTime = b; 61 | }; 62 | this.toArrayBuffer = function () { 63 | return a 64 | } 65 | }, 66 | DownStreamMessage: function () { 67 | var a = {}; 68 | this.setFromUserId = function (b) { 69 | a.fromUserId = b 70 | }; 71 | this.setType = function (b) { 72 | a.type = b 73 | }; 74 | this.setGroupId = function (b) { 75 | a.groupId = b 76 | }; 77 | this.setClassname = function (b) { 78 | a.classname = b 79 | }; 80 | this.setContent = function (b) { 81 | if (b) 82 | a.content = b 83 | }; 84 | this.setDataTime = function (b) { 85 | a.dataTime = b 86 | }; 87 | this.setStatus = function (b) { 88 | a.status = b 89 | }; 90 | this.toArrayBuffer = function () { 91 | return a 92 | } 93 | }, 94 | CreateDiscussionInput: function () { 95 | var a = {}; 96 | this.setName = function (b) { 97 | a.name = b 98 | }; 99 | this.toArrayBuffer = function () { 100 | return a 101 | } 102 | }, 103 | CreateDiscussionOutput: function () { 104 | var a = {}; 105 | this.setId = function (b) { 106 | a.id = b 107 | }; 108 | this.toArrayBuffer = function () { 109 | return a 110 | } 111 | }, 112 | ChannelInvitationInput: function () { 113 | var a = {}; 114 | this.setUsers = function (b) { 115 | a.users = b 116 | }; 117 | this.toArrayBuffer = function () { 118 | return a 119 | } 120 | }, 121 | LeaveChannelInput: function () { 122 | var a = {}; 123 | this.setNothing = function (b) { 124 | a.nothing = b 125 | }; 126 | this.toArrayBuffer = function () { 127 | return a 128 | } 129 | }, 130 | ChannelEvictionInput: function () { 131 | var a = {}; 132 | this.setUser = function (b) { 133 | a.user = b 134 | }; 135 | this.toArrayBuffer = function () { 136 | return a 137 | } 138 | }, 139 | RenameChannelInput: function () { 140 | var a = {}; 141 | this.setName = function (b) { 142 | a.name = b 143 | }; 144 | this.toArrayBuffer = function () { 145 | return a 146 | } 147 | }, 148 | ChannelInfoInput: function () { 149 | var a = {}; 150 | this.setNothing = function (b) { 151 | a.nothing = b 152 | }; 153 | this.toArrayBuffer = function () { 154 | return a 155 | } 156 | }, 157 | ChannelInfoOutput: function () { 158 | var a = {}; 159 | this.setType = function (b) { 160 | a.type = b 161 | }; 162 | this.setChannelId = function (b) { 163 | a.channelId = b 164 | }; 165 | this.setChannelName = function (b) { 166 | a.channelName = b 167 | }; 168 | this.setAdminUserId = function (b) { 169 | a.adminUserId = b 170 | }; 171 | this.setFirstTenUserIds = function (b) { 172 | a.firstTenUserIds = b 173 | }; 174 | this.setOpenStatus = function (b) { 175 | a.openStatus = b 176 | }; 177 | this.toArrayBuffer = function () { 178 | return a 179 | } 180 | }, 181 | ChannelInfosInput: function () { 182 | var a = {}; 183 | this.setPage = function (b) { 184 | a.page = b 185 | }; 186 | this.setNumber = function (b) { 187 | a.number = b 188 | }; 189 | this.toArrayBuffer = function () { 190 | return a 191 | } 192 | }, 193 | ChannelInfosOutput: function () { 194 | var a = {}; 195 | this.setChannels = function (b) { 196 | a.channels = b 197 | }; 198 | this.setTotal = function (b) { 199 | a.total = b 200 | }; 201 | this.toArrayBuffer = function () { 202 | return a 203 | } 204 | }, 205 | MemberInfo: function () { 206 | var a = {}; 207 | this.setUserId = function (b) { 208 | a.userId = b 209 | }; 210 | this.setUserName = function (b) { 211 | a.userName = b 212 | }; 213 | this.setUserPortrait = function (b) { 214 | a.userPortrait = b 215 | }; 216 | this.setExtension = function (b) { 217 | a.extension = b 218 | }; 219 | this.toArrayBuffer = function () { 220 | return a 221 | } 222 | }, 223 | GroupMembersInput: function () { 224 | var a = {}; 225 | this.setPage = function (b) { 226 | a.page = b 227 | }; 228 | this.setNumber = function (b) { 229 | a.number = b 230 | }; 231 | this.toArrayBuffer = function () { 232 | return a 233 | } 234 | }, 235 | GroupMembersOutput: function () { 236 | var a = {}; 237 | this.setMembers = function (b) { 238 | a.members = b 239 | }; 240 | this.setTotal = function (b) { 241 | a.total = b 242 | }; 243 | this.toArrayBuffer = function () { 244 | return a 245 | } 246 | }, 247 | GetUserInfoInput: function () { 248 | var a = {}; 249 | this.setNothing = function (b) { 250 | a.nothing = b 251 | }; 252 | this.toArrayBuffer = function () { 253 | return a 254 | } 255 | }, 256 | GetUserInfoOutput: function () { 257 | var a = {}; 258 | this.setUserId = function (b) { 259 | a.userId = b 260 | }; 261 | this.setUserName = function (b) { 262 | a.userName = b 263 | }; 264 | this.setUserPortrait = function (b) { 265 | a.userPortrait = b 266 | }; 267 | this.toArrayBuffer = function () { 268 | return a 269 | } 270 | }, 271 | GetSessionIdInput: function () { 272 | var a = {}; 273 | this.setNothing = function (b) { 274 | a.nothing = b 275 | }; 276 | this.toArrayBuffer = function () { 277 | return a 278 | } 279 | }, 280 | GetSessionIdOutput: function () { 281 | var a = {}; 282 | this.setSessionId = function (b) { 283 | a.sessionId = b 284 | }; 285 | this.toArrayBuffer = function () { 286 | return a 287 | } 288 | }, 289 | GetQNupTokenInput: function () { 290 | var a = {}; 291 | this.setType = function (b) { 292 | a.type = b; 293 | } 294 | this.toArrayBuffer = function () { 295 | return a 296 | } 297 | }, 298 | GetQNupTokenOutput: function () { 299 | var a = {}; 300 | this.setDeadline = function (b) { 301 | a.deadline = b 302 | }; 303 | this.setToken = function (b) { 304 | a.token = b; 305 | }; 306 | this.toArrayBuffer = function () { 307 | return a 308 | } 309 | }, 310 | GetQNdownloadUrlInput: function () { 311 | var a = {}; 312 | this.setType = function (b) { 313 | a.type = b; 314 | }; 315 | this.setKey = function (b) { 316 | a.key = b; 317 | }; 318 | this.toArrayBuffer = function () { 319 | return a 320 | } 321 | }, 322 | GetQNdownloadUrlOutput: function () { 323 | var a = {}; 324 | this.setDownloadUrl = function (b) { 325 | a.downloadUrl = b; 326 | }; 327 | this.toArrayBuffer = function () { 328 | return a 329 | } 330 | }, 331 | Add2BlackListInput: function () { 332 | var a = {}; 333 | this.setUserId = function (b) { 334 | a.userId = b; 335 | }; 336 | this.toArrayBuffer = function () { 337 | return a 338 | } 339 | }, 340 | RemoveFromBlackListInput: function () { 341 | var a = {}; 342 | this.setUserId = function (b) { 343 | a.userId = b; 344 | }; 345 | this.toArrayBuffer = function () { 346 | return a 347 | } 348 | }, 349 | QueryBlackListInput: function () { 350 | var a = {}; 351 | this.setNothing = function (b) { 352 | a.nothing = b; 353 | }; 354 | this.toArrayBuffer = function () { 355 | return a 356 | } 357 | }, 358 | QueryBlackListOutput: function () { 359 | var a = {}; 360 | this.setUserIds = function (b) { 361 | a.userIds = b; 362 | }; 363 | this.toArrayBuffer = function () { 364 | return a 365 | } 366 | }, 367 | BlackListStatusInput: function () { 368 | var a = {}; 369 | this.setUserId = function (b) { 370 | a.userId = b; 371 | }; 372 | this.toArrayBuffer = function () { 373 | return a 374 | } 375 | }, 376 | BlockPushInput: function () { 377 | var a = {}; 378 | this.setBlockeeId = function (b) { 379 | a.blockeeId = b; 380 | }; 381 | this.toArrayBuffer = function () { 382 | return a 383 | } 384 | }, 385 | ModifyPermissionInput: function () { 386 | var a = {}; 387 | this.setOpenStatus = function (b) { 388 | a.openStatus = b; 389 | }; 390 | this.toArrayBuffer = function () { 391 | return a 392 | } 393 | }, 394 | GroupInput: function () { 395 | var a = {}; 396 | this.setGroupInfo = function (b) { 397 | for (var i = 0, arr = []; i < b.length; i++) { 398 | arr.push({id: b[i].getContent().id, name: b[i].getContent().name}) 399 | } 400 | a.groupInfo = arr; 401 | }; 402 | this.toArrayBuffer = function () { 403 | return a 404 | } 405 | }, 406 | GroupOutput: function () { 407 | var a = {}; 408 | this.setNothing = function (b) { 409 | a.nothing = b; 410 | }; 411 | this.toArrayBuffer = function () { 412 | return a 413 | } 414 | }, 415 | GroupInfo: function () { 416 | var a = {}; 417 | this.setId = function (b) { 418 | a.id = b; 419 | }; 420 | this.setName = function (b) { 421 | a.name = b; 422 | }; 423 | this.getContent = function () { 424 | return a; 425 | }; 426 | this.toArrayBuffer = function () { 427 | return a 428 | } 429 | }, 430 | GroupHashInput: function () { 431 | var a = {}; 432 | this.setUserId = function (b) { 433 | a.userId = b; 434 | }; 435 | this.setGroupHashCode = function (b) { 436 | a.groupHashCode = b; 437 | }; 438 | this.toArrayBuffer = function () { 439 | return a 440 | } 441 | }, 442 | GroupHashOutput: function () { 443 | var a = {}; 444 | this.setResult = function (b) { 445 | a.result = b; 446 | }; 447 | this.toArrayBuffer = function () { 448 | return a 449 | } 450 | }, 451 | ChrmInput: function () { 452 | var a = {}; 453 | this.setNothing = function (b) { 454 | a.nothing = b; 455 | }; 456 | this.toArrayBuffer = function () { 457 | return a 458 | } 459 | }, 460 | ChrmOutput: function () { 461 | var a = {}; 462 | this.setNothing = function (b) { 463 | a.nothing = b; 464 | }; 465 | this.toArrayBuffer = function () { 466 | return a 467 | } 468 | }, 469 | ChrmPullMsg: function () { 470 | var a = {}; 471 | this.setSyncTime = function (b) { 472 | a.syncTime = b 473 | }; 474 | this.setCount = function (b) { 475 | a.count = b; 476 | }; 477 | this.toArrayBuffer = function () { 478 | return a 479 | } 480 | }, 481 | RelationsInput: function () { 482 | var a = {}; 483 | this.setType = function (b) { 484 | a.type = b; 485 | }; 486 | this.toArrayBuffer = function () { 487 | return a 488 | } 489 | }, 490 | RelationsOutput: function () { 491 | var a = {}; 492 | this.setInfo = function (b) { 493 | a.info = b; 494 | }; 495 | this.toArrayBuffer = function () { 496 | return a 497 | } 498 | }, 499 | RelationInfo: function () { 500 | var a = {}; 501 | this.setType = function (b) { 502 | a.type = b; 503 | }; 504 | this.setUserId = function (b) { 505 | a.userId = b; 506 | }; 507 | this.toArrayBuffer = function () { 508 | return a 509 | } 510 | }, 511 | HistoryMessageInput: function () { 512 | var a={}; 513 | this.setTargetId=function(b){ 514 | a.targetId=b; 515 | }; 516 | this.setDataTime=function(b){ 517 | a.dataTime=b; 518 | }; 519 | this.setSize=function(b){ 520 | a.size=b; 521 | }; 522 | this.toArrayBuffer = function () { 523 | return a 524 | } 525 | }, 526 | HistoryMessagesOuput: function () { 527 | var a={}; 528 | this.setList=function(b){ 529 | a.list=b; 530 | }; 531 | this.setSyncTime=function(b){ 532 | a.syncTime=b; 533 | }; 534 | this.setHasMsg=function(b){ 535 | a.hasMsg=b; 536 | }; 537 | this.toArrayBuffer = function () { 538 | return a 539 | } 540 | } 541 | }; 542 | for (var f in e) { 543 | e[f].decode = function (b) { 544 | var back = {}, val = JSON.parse(b) || eval("(" + b + ")"); 545 | for (var i in val) { 546 | back[i]=val[i]; 547 | back["get"+ i.charAt(0).toUpperCase()+i.slice(1)]=function(){ 548 | return val[i]; 549 | } 550 | } 551 | return back; 552 | } 553 | } 554 | d.Modules = e; 555 | })(window); 556 | (function (g) { 557 | if (g.RongIMClient) { 558 | if (RongIMClient.connect.token) { 559 | RongIMClient.getInstance().connect(RongIMClient.connect.token, RongIMClient.connect.callback); 560 | } 561 | } else { 562 | require(['../bin/RongIMClient'], function (r) { 563 | if (r.connect.token) { 564 | r.getInstance().connect(r.connect.token, r.connect.callback); 565 | } 566 | }) 567 | } 568 | })(this); 569 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 221 | 222 | 223 | 224 | 用户id 225 | 233 | 接受的内容: 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 |
243 |
244 | 245 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /modules/emoji-0.9.2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 表情帮助库 3 | * 具体参考文档 https://github.com/rongcloud/demo-web-sdk#表情帮助库如何使用 4 | * */ 5 | 6 | (function (b) { 7 | if (b.RongIMClient) { 8 | var c = {u1F600: {en: "grinning", zh: "\u72de\u7b11", tag: "\ud83d\ude00", "bp": "-1539px 0"}, u1F601: {en: "grin", zh: "\u9732\u9f7f\u800c\u7b11", tag: "\ud83d\ude01", "bp": "-1566px 0"}, u1F602: {en: "joy", zh: "\u6b22\u4e50", tag: "\ud83d\ude02", "bp": "-1593px 0"}, u1F603: {en: "smile", zh: "\u5fae\u7b11", tag: "\ud83d\ude03", "bp": "-1620px 0"}, u1F605: {en: "sweat_smile", zh: "\u8d54\u7b11", tag: "\ud83d\ude05", "bp": "-1647px 0"}, u1F606: {en: "satisfied", 9 | zh: "\u6ee1\u610f", tag: "\ud83d\ude06", "bp": "-1674px 0"}, u1F607: {en: "innocent", zh: "\u65e0\u8f9c", tag: "\ud83d\ude07", "bp": "-1701px 0"}, u1F608: {en: "smiling_imp", zh: "\u574f\u7b11", tag: "\ud83d\ude08", "bp": "-1728px 0"}, u1F609: {en: "wink", zh: "\u7728\u773c", tag: "\ud83d\ude09", "bp": "-1755px 0"}, u1F611: {en: "expressionless", zh: "\u9762\u65e0\u8868\u60c5", tag: "\ud83d\ude11", "bp": "-1944px 0"}, u1F612: {en: "unamused", zh: "\u4e00\u8138\u4e0d\u5feb", 10 | tag: "\ud83d\ude12", "bp": "-1971px 0"}, u1F613: {en: "sweat", zh: "\u6c57", tag: "\ud83d\ude13", "bp": "0 -27px"}, u1F614: {en: "pensive", zh: "\u54c0\u601d", tag: "\ud83d\ude14", "bp": "-27px -27px"}, u1F615: {en: "confused", zh: "\u8ff7\u832b", tag: "\ud83d\ude15", "bp": "-54px -27px"}, u1F616: {en: "confounded", zh: "\u56f0\u60d1\u7684", tag: "\ud83d\ude16", "bp": "-81px -27px"}, u1F618: {en: "kissing_heart", zh: "\u4eb2\u4e00\u4e2a", tag: "\ud83d\ude18", 11 | "bp": "-108px -27px"}, u1F621: {en: "rage", zh: "\u6124\u6012", tag: "\ud83d\ude21", "bp": "-270px -27px"}, u1F622: {en: "cry", zh: "\u54ed", tag: "\ud83d\ude22", "bp": "-297px -27px"}, u1F623: {en: "persevere", zh: "\u4f7f\u52b2", tag: "\ud83d\ude23", "bp": "-324px -27px"}, u1F624: {en: "triumph", zh: "\u751f\u6c14", tag: "\ud83d\ude24", "bp": "-351px -27px"}, u1F628: {en: "fearful", zh: "\u53ef\u6015", tag: "\ud83d\ude28", "bp": "-378px -27px"}, 12 | u1F629: {en: "weary", zh: "\u538c\u5026", tag: "\ud83d\ude29", "bp": "-405px -27px"}, u1F630: {en: "cold_sweat", zh: "\u51b7\u6c57", tag: "\ud83d\ude30", "bp": "-567px -27px"}, u1F631: {en: "scream", zh: "\u60ca\u53eb", tag: "\ud83d\ude31", "bp": "-594px -27px"}, u1F632: {en: "astonished", zh: "\u60ca\u8bb6", tag: "\ud83d\ude32", "bp": "-621px -27px"}, u1F633: {en: "flushed", zh: "\u5446\u4f4f", tag: "\ud83d\ude33", "bp": "-648px -27px"}, u1F634: {en: "sleeping", 13 | zh: "\u7761\u7720", tag: "\ud83d\ude34", "bp": "-675px -27px"}, u1F635: {en: "dizzy_face", zh: "\u65ad\u7535\u4e86", tag: "\ud83d\ude35", "bp": "-702px -27px"}, u1F636: {en: "no_mouth", zh: "\u65e0\u53e3", tag: "\ud83d\ude36", "bp": "-729px -27px"}, u1F637: {en: "mask", zh: "\u75c5\u4e86", tag: "\ud83d\ude37", "bp": "-756px -27px"}, u1F3A4: {en: "microphone", zh: "KTV", tag: "\ud83c\udfa4", "bp": "-486px 0"}, u1F3B2: {en: "game_die", zh: "\u8272\u5b50", tag: "\ud83c\udfb2", 14 | "bp": "-513px 0"}, u1F3B5: {en: "musical_note", zh: "\u97f3\u4e50", tag: "\ud83c\udfb5", "bp": "-540px 0"}, u1F3C0: {en: "basketball", zh: "\u7bee\u7403", tag: "\ud83c\udfc0", "bp": "-567px 0"}, u1F3C2: {en: "snowboarder", zh: "\u5355\u677f\u6ed1\u96ea", tag: "\ud83c\udfc2", "bp": "-594px 0"}, u1F3E1: {en: "house_with_garden", zh: "\u623f\u5b50", tag: "\ud83c\udfe1", "bp": "-621px 0"}, u1F004: {en: "mahjong", zh: "\u9ebb\u5c06", tag: "\ud83c\udc04", "bp": "0 0"}, 15 | u1F4A1: {en: "bulb", zh: "\u706f\u6ce1", tag: "\ud83d\udca1", "bp": "-1188px 0"}, u1F4A2: {en: "anger", zh: "\u6124\u6012", tag: "\ud83d\udca2", "bp": "-1215px 0"}, u1F4A3: {en: "bomb", zh: "\u70b8\u5f39", tag: "\ud83d\udca3", "bp": "-1242px 0"}, u1F4A4: {en: "zzz", zh: "ZZZ", tag: "\ud83d\udca4", "bp": "-1269px 0"}, u1F4A9: {en: "shit", zh: "\u72d7\u5c41", tag: "\ud83d\udca9", "bp": "-1296px 0"}, u1F4AA: {en: "muscle", zh: "\u808c\u8089", tag: "\ud83d\udcaa", "bp": "-1323px 0"}, 16 | u1F4B0: {en: "moneybag", zh: "\u94b1\u888b", tag: "\ud83d\udcb0", "bp": "-1350px 0"}, u1F4DA: {en: "books", zh: "\u4e66\u7c4d", tag: "\ud83d\udcda", "bp": "-1377px 0"}, u1F4DE: {en: "telephone_receiver", zh: "\u7535\u8bdd", tag: "\ud83d\udcde", "bp": "-1404px 0"}, u1F4E2: {en: "loudspeaker", zh: "\u6269\u97f3\u5668", tag: "\ud83d\udce2", "bp": "-1431px 0"}, u1F6AB: {en: "stop", zh: "\u505c\u6b62", tag: "\ud83d\udeab", "bp": "-918px -27px"}, u1F6BF: {en: "shower", 17 | zh: "\u6dcb\u6d74", tag: "\ud83d\udebf", "bp": "-945px -27px"}, u1F30F: {en: "earth_asia", zh: "\u571f", tag: "\ud83c\udf0f", "bp": "-27px 0"}, u1F33B: {en: "sunflower", zh: "\u5411\u65e5\u8475", tag: "\ud83c\udf3b", "bp": "-135px 0"}, u1F35A: {en: "rice", zh: "\u996d", tag: "\ud83c\udf5a", "bp": "-216px 0"}, u1F36B: {en: "chocolate_bar", zh: "\u5de7\u514b\u529b", tag: "\ud83c\udf6b", "bp": "-270px 0"}, u1F37B: {en: "beers", zh: "\u5564\u9152", tag: "\ud83c\udf7b", 18 | "bp": "-324px 0"}, u1F44A: {en: "punch", zh: "\u62f3", tag: "\ud83d\udc4a", "bp": "-729px 0"}, u1F44C: {en: "ok_hand", zh: "\u6ca1\u95ee\u9898", tag: "\ud83d\udc4c", "bp": "-756px 0"}, u1F44D: {en: "1", zh: "1", tag: "\ud83d\udc4d", "bp": "-783px 0"}, u1F44E: {en: "-1", zh: "-1", tag: "\ud83d\udc4e", "bp": "-810px 0"}, u1F44F: {en: "clap", zh: "\u62cd", tag: "\ud83d\udc4f", "bp": "-837px 0"}, u1F46A: {en: "family", zh: "\u5bb6\u5ead", tag: "\ud83d\udc6a", 19 | "bp": "-891px 0"}, u1F46B: {en: "couple", zh: "\u60c5\u4fa3", tag: "\ud83d\udc6b", "bp": "-918px 0"}, u1F47B: {en: "ghost", zh: "\u9b3c", tag: "\ud83d\udc7b", "bp": "-945px 0"}, u1F47C: {en: "angel", zh: "\u5929\u4f7f", tag: "\ud83d\udc7c", "bp": "-972px 0"}, u1F47D: {en: "alien", zh: "\u5916\u661f\u4eba", tag: "\ud83d\udc7d", "bp": "-999px 0"}, u1F47F: {en: "imp", zh: "\u6076\u9b54", tag: "\ud83d\udc7f", "bp": "-1026px 0"}, u1F48A: {en: "pill", 20 | zh: "\u836f", tag: "\ud83d\udc8a", "bp": "-1080px 0"}, u1F48B: {en: "kiss", zh: "\u543b", tag: "\ud83d\udc8b", "bp": "-1107px 0"}, u1F48D: {en: "ring", zh: "\u6212\u6307", tag: "\ud83d\udc8d", "bp": "-1134px 0"}, u1F52B: {en: "gun", zh: "\u67aa", tag: "\ud83d\udd2b", "bp": "-1485px 0"}, u1F60A: {en: "blush", zh: "\u8138\u7ea2", tag: "\ud83d\ude0a", "bp": "-1782px 0"}, u1F60B: {en: "yum", zh: "\u998b", tag: "\ud83d\ude0b", "bp": "-1809px 0"}, u1F60C: {en: "relieved", 21 | zh: "\u5b89\u5fc3", tag: "\ud83d\ude0c", "bp": "-1836px 0"}, u1F60D: {en: "heart_eyes", zh: "\u8272\u8272", tag: "\ud83d\ude0d", "bp": "-1863px 0"}, u1F60E: {en: "sunglasses", zh: "\u58a8\u955c", tag: "\ud83d\ude0e", "bp": "-1890px 0"}, u1F60F: {en: "smirk", zh: "\u50bb\u7b11", tag: "\ud83d\ude0f", "bp": "-1917px 0"}, u1F61A: {en: "kissing_closed_eyes", zh: "\u63a5\u543b", tag: "\ud83d\ude1a", "bp": "-135px -27px"}, u1F61C: {en: "stuck_out_tongue_winking_eye", 22 | zh: "\u641e\u602a", tag: "\ud83d\ude1c", "bp": "-162px -27px"}, u1F61D: {en: "stuck_out_tongue_closed_eyes", zh: "\u6076\u4f5c\u5267", tag: "\ud83d\ude1d", "bp": "-189px -27px"}, u1F61E: {en: "disappointed", zh: "\u5931\u671b\u7684", tag: "\ud83d\ude1e", "bp": "-216px -27px"}, u1F61F: {en: "anguished", zh: "\u82e6\u6da9", tag: "\ud83d\ude1f", "bp": "-243px -27px"}, u1F62A: {en: "sleepy", zh: "\u56f0", tag: "\ud83d\ude2a", "bp": "-432px -27px"}, u1F62B: {en: "tired_face", 23 | zh: "\u6293\u72c2", tag: "\ud83d\ude2b", "bp": "-459px -27px"}, u1F62C: {en: "grimacing", zh: "\u9b3c\u8138", tag: "\ud83d\ude2c", "bp": "-486px -27px"}, u1F62D: {en: "sob", zh: "\u54ed\u6ce3", tag: "\ud83d\ude2d", "bp": "-513px -27px"}, u1F62F: {en: "hushed", zh: "\u5bc2\u9759", tag: "\ud83d\ude2f", "bp": "-540px -27px"}, u1F64A: {en: "speak_no_evil", zh: "\u4e0d\u8bf4\u8bdd", tag: "\ud83d\ude4a", "bp": "-837px -27px"}, u1F64F: {en: "pray", zh: "\u7948\u7977", 24 | tag: "\ud83d\ude4f", "bp": "-864px -27px"}, u1F319: {en: "moon", zh: "\u6708\u4eae", tag: "\ud83c\udf19", "bp": "-54px 0"}, u1F332: {en: "evergreen_tree", zh: "\u6811", tag: "\ud83c\udf32", "bp": "-81px 0"}, u1F339: {en: "rose", zh: "\u73ab\u7470", tag: "\ud83c\udf39", "bp": "-108px 0"}, u1F349: {en: "watermelon", zh: "\u897f\u74dc", tag: "\ud83c\udf49", "bp": "-162px 0"}, u1F356: {en: "meat_on_bone", zh: "\u8089", tag: "\ud83c\udf56", "bp": "-189px 0"}, 25 | u1F366: {en: "icecream", zh: "\u51b0\u6dc7\u6dcb", tag: "\ud83c\udf66", "bp": "-243px 0"}, u1F377: {en: "wine_glass", zh: "\u9152", tag: "\ud83c\udf77", "bp": "-297px 0"}, u1F381: {en: "gift", zh: "\u793c\u7269", tag: "\ud83c\udf81", "bp": "-351px 0"}, u1F382: {en: "birthday", zh: "\u751f\u65e5", tag: "\ud83c\udf82", "bp": "-378px 0"}, u1F384: {en: "christmas_tree", zh: "\u5723\u8bde", tag: "\ud83c\udf84", "bp": "-405px 0"}, u1F389: {en: "tada", zh: "\u793c\u82b1", 26 | tag: "\ud83c\udf89", "bp": "-432px 0"}, u1F393: {en: "mortar_board", zh: "\u6bd5\u4e1a", tag: "\ud83c\udf93", "bp": "-459px 0"}, u1F434: {en: "horse", zh: "\u9a6c", tag: "\ud83d\udc34", "bp": "-648px 0"}, u1F436: {en: "dog", zh: "\u72d7", tag: "\ud83d\udc36", "bp": "-675px 0"}, u1F437: {en: "pig", zh: "\u732a", tag: "\ud83d\udc37", "bp": "-702px 0"}, u1F451: {en: "crown", zh: "\u738b\u51a0", tag: "\ud83d\udc51", "bp": "-864px 0"}, u1F484: {en: "lipstick", 27 | zh: "\u53e3\u7ea2", tag: "\ud83d\udc84", "bp": "-1053px 0"}, u1F494: {en: "broken_heart", zh: "\u4f24\u5fc3", tag: "\ud83d\udc94", "bp": "-1161px 0"}, u1F525: {en: "fire", zh: "\u706b\u4e86", tag: "\ud83d\udd25", "bp": "-1458px 0"}, u1F556: {en: "time", zh: "\u65f6\u95f4", tag: "\ud83d\udd56", "bp": "-1512px 0"}, u1F648: {en: "see_no_evil", zh: "\u4e0d\u770b", tag: "\ud83d\ude48", "bp": "-783px -27px"}, u1F649: {en: "hear_no_evil", zh: "\u4e0d\u542c", tag: "\ud83d\ude49", 28 | "bp": "-810px -27px"}, u1F680: {en: "rocket", zh: "\u706b\u7bad", tag: "\ud83d\ude80", "bp": "-891px -27px"}, u2B50: {en: "star", zh: "\u661f\u661f", tag: "\u2b50", "bp": "-1431px -27px"}, u23F0: {en: "alarm_clock", zh: "\u949f\u8868", tag: "\u23f0", "bp": "-972px -27px"}, u23F3: {en: "hourglass_flowing_sand", zh: "\u6c99\u6f0f", tag: "\u23f3", "bp": "-999px -27px"}, u26A1: {en: "zap", zh: "\u95ea\u7535", tag: "\u26a1", "bp": "-1188px -27px"}, 29 | u26BD: {en: "soccer", zh: "\u8db3\u7403", tag: "\u26bd", "bp": "-1215px -27px"}, u26C4: {en: "snowman", zh: "\u96ea\u4eba", tag: "\u26c4", "bp": "-1242px -27px"}, u26C5: {en: "partly_sunny", zh: "\u591a\u4e91", tag: "\u26c5", "bp": "-1269px -27px"}, u261D: {en: "point_up", zh: "\u7b2c\u4e00", tag: "\u261d", "bp": "-1134px -27px"}, u263A: {en: "relaxed", zh: "\u8f7b\u677e", tag: "\u263a", "bp": "-1161px -27px"}, u270A: {en: "fist", zh: "\u62f3\u5934", tag: "\u270a", 30 | "bp": "-1296px -27px"}, u270B: {en: "hand", zh: "\u624b", tag: "\u270b", "bp": "-1323px -27px"}, u270C: {en: "v", zh: "v ", tag: "\u270c", "bp": "-1350px -27px"}, u270F: {en: "pencil2", zh: "\u7b14", tag: "\u270f", "bp": "-1377px -27px"}, u2600: {en: "sunny", zh: "\u6674\u6717", tag: "\u2600", "bp": "-1026px -27px"}, u2601: {en: "cloud", zh: "\u4e91", tag: "\u2601", "bp": "-1053px -27px"}, u2614: {en: "umbrella", zh: "\u4f1e", tag: "\u2614", "bp": "-1080px -27px"}, 31 | u2615: {en: "coffee", zh: "\u5496\u5561", tag: "\u2615", "bp": "-1107px -27px"}, u2744: {en: "snowflake", zh: "\u96ea\u82b1", tag: "\u2744", "bp": "-1404px -27px"}}; 32 | //根据浏览器初始化css 33 | function initCss() { 34 | var head = document.getElementsByTagName("head")[0] || document.createElement("head"); 35 | if (document.createStyleSheet) { 36 | initBtag = function (position) { 37 | var e = document.createElement("b"); 38 | e.style.width = '22px'; 39 | e.style.height = '22px'; 40 | e.style.backgroundImage = 'url(http://res.websdk.rongcloud.cn/css-sprite_bg.png)'; 41 | e.style.display = 'inline'; 42 | e.style.display = 'inline-block'; 43 | e.style.zoom = '1'; 44 | e.style.backgroundPosition = position; 45 | return e; 46 | }; 47 | } else { 48 | var _style = document.createElement("style"); 49 | _style.type = "text/css"; 50 | _style.innerHTML = ".RC_Expression {width:22px;height:22px;background-image:url(http://res.websdk.rongcloud.cn/css-sprite_bg.png);display:inline-block}"; 51 | head.appendChild(_style); 52 | } 53 | } 54 | 55 | var initBtag = function (position) { 56 | var e = document.createElement("b"); 57 | e.className = "RC_Expression"; 58 | e.style.backgroundPosition = position; 59 | return e; 60 | }; 61 | b.RongIMClient.Expression = new function () { 62 | initCss(); 63 | var e = this; 64 | //得到所有表情对象 0-127 65 | this.getAllExpression = function (a, b) { 66 | if (0 < a && -1 < b && 127 > a + b) { 67 | var h = [], d = 0, f; 68 | for (f in c) { 69 | if (d >= b + a)break; 70 | if (d >= b) { 71 | var e = initBtag(c[f]["bp"]); 72 | h.push({englishName: c[f].en, chineseName: c[f].zh, img: e, tag: c[f].tag}); 73 | } 74 | d++; 75 | } 76 | return h; 77 | } 78 | throw Error("Wrong parameter"); 79 | }; 80 | //根据c的key得到表情对象 81 | this.getEmojiByContent = function (a) { 82 | if (a in c) { 83 | var b = initBtag(c[a]["bp"]); 84 | return{englishName: c[a].en, chineseName: c[a].zh, img: b, tag: c[a].tag}; 85 | } 86 | }; 87 | //计算utf 88 | this.calcUTF = function (d) { 89 | if (61440 < d.charCodeAt(0)) { 90 | var b = c[escape(d).replace("%u", "u1")]; 91 | if (b)return b.tag; 92 | } 93 | return d; 94 | }; 95 | //根据英文名称或中文名称得到表情对象 96 | this.getEmojiObjByEnglishNameOrChineseName = function (a) { 97 | for (var b in c) { 98 | if (c[b].en == a || c[b].zh == a) { 99 | var e = initBtag(c[b]["bp"]); 100 | return {img: e, englishName: c[b].en, chineseName: c[b].zh, tag: c[b].tag}; 101 | } 102 | } 103 | return{}; 104 | }; 105 | var k = /(\ud83d\ude00|\ud83d\ude01|\ud83d\ude02|\ud83d\ude03|\ud83d\ude05|\ud83d\ude06|\ud83d\ude07|\ud83d\ude08|\ud83d\ude09|\ud83d\ude11|\ud83d\ude12|\ud83d\ude13|\ud83d\ude14|\ud83d\ude15|\ud83d\ude16|\ud83d\ude18|\ud83d\ude21|\ud83d\ude22|\ud83d\ude23|\ud83d\ude24|\ud83d\ude28|\ud83d\ude29|\ud83d\ude30|\ud83d\ude31|\ud83d\ude32|\ud83d\ude33|\ud83d\ude34|\ud83d\ude35|\ud83d\ude36|\ud83d\ude37|\ud83c\udfa4|\ud83c\udfb2|\ud83c\udfb5|\ud83c\udfc0|\ud83c\udfc2|\ud83c\udfe1|\ud83c\udc04|\ud83d\udca1|\ud83d\udca2|\ud83d\udca3|\ud83d\udca4|\ud83d\udca9|\ud83d\udcaa|\ud83d\udcb0|\ud83d\udcda|\ud83d\udcde|\ud83d\udce2|\ud83d\udeab|\ud83d\udebf|\ud83c\udf0f|\ud83c\udf3b|\ud83c\udf5a|\ud83c\udf6b|\ud83c\udf7b|\ud83d\udc4a|\ud83d\udc4c|\ud83d\udc4d|\ud83d\udc4e|\ud83d\udc4f|\ud83d\udc6a|\ud83d\udc6b|\ud83d\udc7b|\ud83d\udc7c|\ud83d\udc7d|\ud83d\udc7f|\ud83d\udc8a|\ud83d\udc8b|\ud83d\udc8d|\ud83d\udd2b|\ud83d\ude0a|\ud83d\ude0b|\ud83d\ude0c|\ud83d\ude0d|\ud83d\ude0e|\ud83d\ude0f|\ud83d\ude1a|\ud83d\ude1c|\ud83d\ude1d|\ud83d\ude1e|\ud83d\ude1f|\ud83d\ude2a|\ud83d\ude2b|\ud83d\ude2c|\ud83d\ude2d|\ud83d\ude2f|\ud83d\ude4a|\ud83d\ude4f|\ud83c\udf19|\ud83c\udf32|\ud83c\udf39|\ud83c\udf49|\ud83c\udf56|\ud83c\udf66|\ud83c\udf77|\ud83c\udf81|\ud83c\udf82|\ud83c\udf84|\ud83c\udf89|\ud83c\udf93|\ud83d\udc34|\ud83d\udc36|\ud83d\udc37|\ud83d\udc51|\ud83d\udc84|\ud83d\udc94|\ud83d\udd25|\ud83d\udd56|\ud83d\ude48|\ud83d\ude49|\ud83d\ude80|\u2b50|\u23f0|\u23f3|\u26a1|\u26bd|\u26c4|\u26c5|\u261d|\u263a|\u270a|\u270b|\u270c|\u270f|\u2600|\u2601|\u2614|\u2615|\u2744)/g; 106 | //解析一段字符串得到表情 107 | this.retrievalEmoji = function (a, b) { 108 | return a.replace(k, function (a) { 109 | var d; 110 | a:{ 111 | for (d in c)if (c[d].tag == a)break a; 112 | d = a 113 | } 114 | return d != a ? b(e.getEmojiByContent(d)) : a; 115 | }) 116 | } 117 | }; 118 | } else { 119 | throw new Error("Please load RongIMClient.min.js,http://res.websdk.rong.io/RongIMClient.min.js") 120 | } 121 | })(window); -------------------------------------------------------------------------------- /modules/indexedDB.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yataozhang on 15/4/13. 3 | * 内部存储帮助库 4 | * 文档地址 https://github.com/rongcloud/demo-web-sdk#web-端本地存储帮助库如何使用 5 | */ 6 | (function (global, rong) { 7 | var db; 8 | 9 | global.indexedDB = global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB; 10 | 11 | if (!global.indexedDB) 12 | throw new Error("The browser does not support this function"); 13 | if (!rong) 14 | throw new Error("Please load RongIMClient.min.js,http://res.websdk.rongcloud.cn/RongIMClient.min.js") 15 | 16 | var DBOpenRequest = global.indexedDB.open('rongcloud', 1); 17 | 18 | DBOpenRequest.onsuccess = function (event) { 19 | db = event.target.result; 20 | }; 21 | 22 | DBOpenRequest.onupgradeneeded = function (event) { 23 | var db = event.currentTarget.result; 24 | 25 | db.onerror = function (event) { 26 | throw new Error(event); 27 | }; 28 | 29 | var objectStore = db.createObjectStore('messageObject', { keyPath: 'messageId' }); 30 | objectStore.createIndex('ConversationType', 'ConversationType', { unique: true }); 31 | }; 32 | 33 | function getDB(mode) { 34 | var transaction = db.transaction(['messageObject'], mode); 35 | var objectStore = transaction.objectStore('messageObject'); 36 | return { 37 | transaction: transaction, 38 | objectStore: objectStore 39 | } 40 | } 41 | 42 | function displayData(f) { 43 | var obj = getDB('readonly'), arr = []; 44 | obj.objectStore.openCursor(null, "prev").onsuccess = function (event) { 45 | var cursor = event.target.result; 46 | if (cursor) { 47 | arr.push(cursor.value); 48 | cursor.continue(); 49 | } 50 | }; 51 | obj.transaction.oncomplete = function () { 52 | f(arr); 53 | } 54 | } 55 | 56 | function getCount(func) { 57 | var obj = getDB('readwrite'); 58 | var num = obj.objectStore.count(); 59 | obj.transaction.oncomplete = function () { 60 | func(num.result); 61 | }; 62 | } 63 | 64 | function addMessageObject(msg,func) { 65 | function add() { 66 | var obj = getDB("readwrite"); 67 | obj.objectStore.put(msg); 68 | obj.transaction.oncomplete = function () { 69 | func(); 70 | }; 71 | } 72 | 73 | getCount(function (count) { 74 | if (count <= 20) { 75 | add(); 76 | } else { 77 | deleteResult(null, function (err) { 78 | if (!err) { 79 | add(); 80 | } 81 | }); 82 | } 83 | }) 84 | } 85 | 86 | function deleteResult(k, f) { 87 | var obj = getDB('readwrite'); 88 | var request = {}; 89 | obj.objectStore.openCursor().onsuccess = function (event) { 90 | var cursor = event.target.result; 91 | if (cursor) { 92 | if (k) { 93 | if (k && cursor.value.messageId == k) { 94 | request = cursor.delete(); 95 | } 96 | cursor.continue(); 97 | } else { 98 | request = cursor.delete(); 99 | } 100 | request.onsuccess = function () { 101 | f(null); 102 | }; 103 | request.onerror = function () { 104 | f(new Error("delete fail")); 105 | } 106 | } 107 | }; 108 | } 109 | rong.indexedDB = { 110 | getMessageListFromIndexedDB: function (func) { 111 | displayData(func); 112 | }, 113 | addMessageToIndexedDB: function (message, func) { 114 | if(message instanceof RongIMClient.RongIMMessage){ 115 | addMessageObject(JSON.parse(message.toJSONString()), func) 116 | } 117 | }, deleteMessageFromIndexedDB: function (messageid, func) { 118 | deleteResult(messageid, func) 119 | }, getMessageListCountFromIndexedDB: function (func) { 120 | getCount(func) 121 | } 122 | } 123 | })(window, RongIMClient); -------------------------------------------------------------------------------- /modules/loadImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yataozhang on 14/11/3. 3 | */ 4 | (function (win) { 5 | if (win.RongIMClient) { 6 | var token = "", isinit = false,xdomain = null; 7 | function getToken() { 8 | RongIMClient.getInstance().getUploadToken({ 9 | onSuccess: function (data) { 10 | token = data.token; 11 | isinit = true; 12 | }, onError: function () { 13 | throw new Error("Get token failure"); 14 | } 15 | }) 16 | } 17 | 18 | win.RongIMClient.loadPicture = new function () { 19 | function create(con, callback) { 20 | if(!window.FormData){ 21 | return; 22 | } 23 | if (XMLHttpRequest) { 24 | xdomain = new XMLHttpRequest(); 25 | xdomain.onreadystatechange = function () { 26 | if (xdomain.readyState == 4 && xdomain.status == 200) { 27 | var resu = io.util.JSONParse(xdomain.responseText); 28 | if (resu) 29 | callback(resu); 30 | } 31 | }; 32 | } 33 | else if (XDomainRequest) { 34 | xdomain = new XDomainRequest(); 35 | xdomain.onerror = function () { 36 | }; 37 | xdomain.onload = function () { 38 | var resu = io.util.JSONParse(xdr.responseText) 39 | if (resu) 40 | callback(resu); 41 | }; 42 | } else { 43 | throw new Error("The browser version is not supported"); 44 | } 45 | xdomain.setRequestHeader("content-type","application/json"); 46 | xdomain.open("post", 'http://localhost:8080/qwer',true); 47 | xdomain.send({token:token,data:con,userId:RongIMClient.getInstance().getCurrentUserInfo().getUserId()}); 48 | } 49 | 50 | this.load = function (DataURL, callback) { 51 | if (isinit) { 52 | create(DataURL, callback); 53 | } 54 | else 55 | throw new Error("please init") 56 | }; 57 | this.showImage = function (url, callback) { 58 | var img = new Image(); 59 | img.url = url; 60 | callback(img); 61 | }; 62 | }; 63 | 64 | win.RongIMClient.loadPicture.init = function () { 65 | getToken(); 66 | } 67 | } 68 | else { 69 | throw new Error("Please load RongIMClient.min.js,http://res.websdk.rong.io/RongIMClient.min.js"); 70 | } 71 | }) 72 | (window) -------------------------------------------------------------------------------- /modules/voice-0.9.1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yataozhang on 14/11/3. 3 | * 音频帮助库 4 | * 文档地址 https://github.com/rongcloud/demo-web-sdk#音频播放帮助库如何使用 5 | */ 6 | (function (win) { 7 | if (win.RongIMClient) { 8 | win.RongIMClient.voice = new function () { 9 | var isinit = false; 10 | this.init = function () { 11 | if (/IE/.test(navigator.userAgent) || isinit)//ie内核版本不支持此功能 12 | return; 13 | for (var list = ["http://res.websdk.rongcloud.cn/libamr.js", "http://res.websdk.rongcloud.cn/pcmdata.min.js", "http://res.websdk.rongcloud.cn/amr.js"], i = 0; i < list.length; i++) { 14 | var script = document.createElement("script"); 15 | script.src = list[i]; 16 | document.head.appendChild(script); 17 | } 18 | return (isinit = true); 19 | }; 20 | this.play = function (DataURL, duration) { 21 | if (isinit&&+duration==duration) { 22 | if (window.handleFileSelect) 23 | window.handleFileSelect(DataURL); 24 | else 25 | throw new Error("Has not been initialized, please wait"); 26 | if(!duration) 27 | return; 28 | duration=Math.ceil(duration); 29 | this.onprogress(0); 30 | var self = this, c = 1, timer = setInterval(function () { 31 | self.onprogress(c / duration); 32 | c++; 33 | if (c >= duration) { 34 | clearInterval(timer); 35 | } 36 | }, 1000); 37 | } else { 38 | throw new Error("the voice is not init,please init;WARNING:IE core is not supported This feature "); 39 | } 40 | }; 41 | this.onprogress = function () { 42 | 43 | }; 44 | }; 45 | } else { 46 | throw new Error("Please load RongIMClient.min.js,http://res.websdk.rong.io/RongIMClient.min.js"); 47 | } 48 | })(window); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rongcloud-web-im-sdk", 3 | "version": "0.9.10", 4 | "description": "RongCloud web sdk resource code", 5 | "main": "RongIMClient.js", 6 | "contributors": [ 7 | "yataozhang " 8 | ], 9 | "bin": { 10 | "rongcloud_web_SDK": "RongIMClient.js" 11 | }, 12 | "directories": { 13 | "test": "test" 14 | }, 15 | "scripts": { 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/rongcloud/demo-web-sdk.git" 21 | }, 22 | "keywords": [ 23 | "im", 24 | "rongcloud", 25 | "websdk", 26 | "sdk" 27 | ], 28 | "author": "zhangyatao", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/rongcloud/rongcloud-web-im-sdk/issues" 32 | }, 33 | "homepage": "https://github.com/rongcloud/rongcloud-web-im-sdk" 34 | } 35 | -------------------------------------------------------------------------------- /src/IMClient/IMEnum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyatao on 16/1/11. 3 | */ 4 | var RongIMClient = require('./RongIMClient'); 5 | var tool = require('../tool'); 6 | var msgEnum = require('../message/msgEnum'); 7 | var en = require('../enum'); 8 | var ConnectionState = msgEnum.ConnectionState; 9 | //create enum object 枚举对象,详情可参考API文档 10 | var _enum = { 11 | 'MessageTag': { 12 | 'ISPERSISTED': 'ISPERSISTED', 13 | 'ISCOUNTED': 'ISCOUNTED', 14 | 'NONE': 'NONE', 15 | 'ISDISPLAYED': "ISDISPLAYED" 16 | }, 17 | 'ConversationNotificationStatus': ['DO_NOT_DISTURB', 'NOTIFY'], 18 | 'ConversationType': ['CHATROOM', 'CUSTOMER_SERVICE', 'DISCUSSION', 'GROUP', 'PRIVATE', 'SYSTEM'], 19 | 'SentStatus': ['DESTROYED', 'FAILED', 'READ', 'RECEIVED', 'SENDING', 'SENT'], 20 | 'DiscussionInviteStatus': ['CLOSED', 'OPENED'], 21 | 'MediaType': ['AUDIO', 'FILE', 'IMAGE', 'VIDEO'], 22 | 'MessageDirection': ['RECEIVE', 'SEND'], 23 | 'MessageType': ['DiscussionNotificationMessage', 'TextMessage', 'ImageMessage', 'VoiceMessage', 'RichContentMessage', 'HandshakeMessage', 'UnknownMessage', 'SuspendMessage', 'LocationMessage', 'InformationNotificationMessage', 'ContactNotificationMessage', 'ProfileNotificationMessage', 'CommandNotificationMessage'], 24 | 'SendErrorStatus': { 25 | 'REJECTED_BY_BLACKLIST': 405, 26 | 'NOT_IN_DISCUSSION': 21406, 27 | 'NOT_IN_GROUP': 22406, 28 | 'NOT_IN_CHATROOM': 23406 29 | }, 30 | 'BlacklistStatus': ['EXIT_BLACK_LIST', 'NOT_EXIT_BLACK_LIST'], 31 | 'ConnectionStatus': ['CONNECTED', 'CONNECTING', 'RECONNECT', 'OTHER_DEVICE_LOGIN', 'CLOSURE', 'UNKNOWN_ERROR', 'LOGOUT', 'BLOCK'] 32 | }; 33 | //生产枚举对象 34 | tool.each(_enum, function (_name, option) { 35 | var val = {}; 36 | if (tool.isArray(option)) { 37 | tool.forEach(option, function (x, i) { 38 | val[x] = i; 39 | }) 40 | } else { 41 | val = option; 42 | } 43 | RongIMClient[_name] = en(val); 44 | }); 45 | RongIMClient.ConnectErrorStatus = ConnectionState; 46 | //回调基类 47 | RongIMClient.callback = function (d, a) { 48 | this.onError = a; 49 | this.onSuccess = d 50 | }; 51 | //回调错误枚举值 52 | RongIMClient.callback.ErrorCode = en({ 53 | TIMEOUT: -1, 54 | UNKNOWN_ERROR: -2 55 | }); -------------------------------------------------------------------------------- /src/IMClient/affiliatedMessage.js: -------------------------------------------------------------------------------- 1 | var RongIMClient=require('./RongIMClient'); 2 | var tool=require('../tool'); 3 | //把具体的消息类型转化为protobuf格式的类 4 | RongIMClient.MessageContent = function (f) { 5 | if (!(f instanceof RongIMClient.RongIMMessage)) { 6 | throw new Error("wrong parameter") 7 | } 8 | }; 9 | RongIMClient.MessageContent.prototype.getMessage = function () { 10 | return f 11 | }; 12 | RongIMClient.MessageContent.prototype.encode = function () { 13 | var c = new Modules.UpStreamMessage(); 14 | c.setSessionId(0); 15 | c.setClassname(f.getObjectName()); 16 | c.setContent(tool.JSON.stringify(f.getDetail())); 17 | var val = c.toArrayBuffer(); 18 | if (Object.prototype.toString.call(val) == "[object ArrayBuffer]") { 19 | return [].slice.call(new Int8Array(val)) 20 | } 21 | return val 22 | }; 23 | //发送中处理消息的类,sendMessage方法的第三个参数就是这个对象 24 | RongIMClient.MessageHandler = function (a) { 25 | if (typeof a == "function") { 26 | this.process = a; 27 | } else { 28 | throw new Error("MessageHandler:arguments type is error") 29 | } 30 | }; 31 | //接收状态 32 | RongIMClient.ReceivedStatus = function (d) { 33 | var a = d || 1; 34 | this.getFlag = function () { 35 | return a 36 | }; 37 | this.isDownload = function () { 38 | return a == 1 39 | }; 40 | this.isListened = function () { 41 | return a == 2 42 | }; 43 | this.isRead = function () { 44 | return a == 3 45 | }; 46 | this.setDownload = function () { 47 | a = 1 48 | }; 49 | this.setListened = function () { 50 | a = 2 51 | }; 52 | this.setRead = function () { 53 | a = 3 54 | }; 55 | }; 56 | //用户信息 57 | RongIMClient.UserInfo = function (h, l, a) { 58 | var k = h, 59 | j = l, 60 | i = a; 61 | this.getUserName = function () { 62 | return j 63 | }; 64 | this.getPortraitUri = function () { 65 | return i 66 | }; 67 | this.getUserId = function () { 68 | return k 69 | }; 70 | this.setUserName = function (c) { 71 | j = c 72 | }; 73 | this.setPortraitUri = function (c) { 74 | i = c 75 | }; 76 | this.setUserId = function (c) { 77 | k = c 78 | } 79 | }; 80 | //会话信息 81 | RongIMClient.Conversation = function () { 82 | var s = this, 83 | a = (new Date).getTime(), 84 | D, v, B, w, E, G, t, F, y, C, A, H, x, u = 0, por, 85 | z = RongIMClient.ConversationNotificationStatus.NOTIFY; 86 | this.getConversationTitle = function () { 87 | return G 88 | }; 89 | this.toJSON = function () { 90 | var c = { 91 | "senderUserName": E, 92 | lastTime: a, 93 | "objectName": D, 94 | "senderUserId": v, 95 | "receivedTime": B, 96 | "conversationTitle": G, 97 | "conversationType": t, 98 | "latestMessageId": C, 99 | "sentTime": H, 100 | "targetId": x, 101 | "notificationStatus": z 102 | }; 103 | return tool.JSON.stringify(c) 104 | }; 105 | this.setReceivedStatus = function (c) { 106 | w = c 107 | }; 108 | this.getReceivedStatus = function () { 109 | return w 110 | }; 111 | this.getConversationType = function () { 112 | return t 113 | }; 114 | this.getDraft = function () { 115 | return F 116 | }; 117 | this.getLatestMessage = function () { 118 | return y 119 | }; 120 | this.getLatestMessageId = function () { 121 | return C 122 | }; 123 | this.getNotificationStatus = function () { 124 | return z 125 | }; 126 | this.getObjectName = function () { 127 | return D 128 | }; 129 | this.getReceivedTime = function () { 130 | return B 131 | }; 132 | this.getSenderUserId = function () { 133 | return v 134 | }; 135 | this.getSentStatus = function () { 136 | return A 137 | }; 138 | this.getSentTime = function () { 139 | return H 140 | }; 141 | this.getTargetId = function () { 142 | return x 143 | }; 144 | this.getUnreadMessageCount = function () { 145 | return u 146 | }; 147 | this.isTop = function () { 148 | var e = RongIMClient.getInstance().getConversationList(); 149 | return e[0] != undefined && e[0].getTargetId() == this.getTargetId() && e[0].getConversationType() == this.getConversationType(); 150 | }; 151 | this.setConversationTitle = function (c) { 152 | G = c 153 | }; 154 | this.getConversationPortrait = function () { 155 | return por; 156 | }; 157 | this.setConversationPortrait = function (p) { 158 | por = p; 159 | }; 160 | this.setConversationType = function (c) { 161 | t = c 162 | }; 163 | this.setDraft = function (c) { 164 | F = c 165 | }; 166 | this.setSenderUserName = function (c) { 167 | E = c 168 | }; 169 | this.setLatestMessage = function (c) { 170 | y = c 171 | }; 172 | this.setLatestMessageId = function (c) { 173 | C = c 174 | }; 175 | this.setNotificationStatus = function (c) { 176 | z = c instanceof RongIMClient.ConversationNotificationStatus ? c : RongIMClient.ConversationNotificationStatus.setValue(c); 177 | }; 178 | this.setObjectName = function (c) { 179 | D = c 180 | }; 181 | this.setReceivedTime = function (c) { 182 | a = B = c 183 | }; 184 | this.setSenderUserId = function (c) { 185 | v = c 186 | }; 187 | this.getLatestTime = function () { 188 | return a 189 | }; 190 | this.setSentStatus = function (c) { 191 | return !!(A = c) 192 | }; 193 | this.setSentTime = function (c) { 194 | a = H = c 195 | }; 196 | this.setTargetId = function (c) { 197 | x = c 198 | }; 199 | this.setTop = function () { 200 | if (s.getTargetId() == undefined || this.isTop()) { 201 | return 202 | } 203 | RongIMClient.getInstance().getConversationList().add(this); 204 | }; 205 | this.setUnreadMessageCount = function (c) { 206 | u = c 207 | } 208 | }; 209 | //讨论组信息 210 | RongIMClient.Discussion = function (m, l, a, q, p) { 211 | var s = m, 212 | t = l, 213 | r = a, 214 | o = q, 215 | n = p; 216 | this.getCreatorId = function () { 217 | return r 218 | }; 219 | this.getId = function () { 220 | return s 221 | }; 222 | this.getMemberIdList = function () { 223 | return n 224 | }; 225 | this.getName = function () { 226 | return t 227 | }; 228 | this.isOpen = function () { 229 | return o 230 | }; 231 | this.setCreatorId = function (c) { 232 | r = c 233 | }; 234 | this.setId = function (c) { 235 | s = c 236 | }; 237 | this.setMemberIdList = function (c) { 238 | n = c 239 | }; 240 | this.setName = function (c) { 241 | t = c 242 | }; 243 | this.setOpen = function (c) { 244 | o = !!c 245 | } 246 | }; 247 | //群信息 248 | RongIMClient.Group = function (j, l, a) { 249 | var h = j, 250 | k = l, 251 | i = a; 252 | this.getId = function () { 253 | return h 254 | }; 255 | this.getName = function () { 256 | return k 257 | }; 258 | this.getPortraitUri = function () { 259 | return i 260 | }; 261 | this.setId = function (c) { 262 | h = c 263 | }; 264 | this.setName = function (c) { 265 | k = c 266 | }; 267 | this.setPortraitUri = function (c) { 268 | i = c 269 | } 270 | }; 271 | -------------------------------------------------------------------------------- /src/IMClient/coustomMessage.js: -------------------------------------------------------------------------------- 1 | var RongIMClient=require('./RongIMClient'); 2 | var tool=require('../tool'); 3 | //消息基类,此类是对安卓消息基类的重新实现 4 | RongIMClient.RongIMMessage = function (content) { 5 | var x = "unknown", 6 | u, z = content || {}, 7 | o, q, t, y, a, p, s, v, r; 8 | this.getDetail = function () { 9 | return z; 10 | }; 11 | this.getMessageTag = function () { 12 | return [RongIMClient.MessageTag.ISPERSISTED, RongIMClient.MessageTag.ISCOUNTED, RongIMClient.MessageTag.ISDISPLAYED]; 13 | }; 14 | this.getContent = function () { 15 | return z.content 16 | }; 17 | this.getConversationType = function () { 18 | return o 19 | }; 20 | this.getExtra = function () { 21 | return z.extra; 22 | }; 23 | this.getMessageDirection = function () { 24 | return q 25 | }; 26 | this.getMessageId = function () { 27 | return t 28 | }; 29 | this.getObjectName = function () { 30 | return y 31 | }; 32 | this.getReceivedStatus = function () { 33 | return a 34 | }; 35 | this.getReceivedTime = function () { 36 | return u 37 | }; 38 | this.getSenderUserId = function () { 39 | return p 40 | }; 41 | this.getSentStatus = function () { 42 | return s 43 | }; 44 | this.getTargetId = function () { 45 | return r 46 | }; 47 | this.setContent = function (c, d) { 48 | z[d || "content"] = c 49 | }; 50 | this.setConversationType = function (c) { 51 | o = c 52 | }; 53 | this.setExtra = function (c) { 54 | z.extra = c; 55 | }; 56 | this.setMessageDirection = function (c) { 57 | q = c 58 | }; 59 | this.setMessageId = function (c) { 60 | t = c 61 | }; 62 | this.setObjectName = function (c) { 63 | y = c 64 | }; 65 | this.setReceivedStatus = function (c) { 66 | a = c 67 | }; 68 | this.setSenderUserId = function (c) { 69 | p = c 70 | }; 71 | this.setSentStatus = function (c) { 72 | return !!(s = c) 73 | }; 74 | this.setSentTime = function (c) { 75 | v = tool.int64ToTimestamp(c); 76 | }; 77 | this.getSentTime = function () { 78 | return v; 79 | }; 80 | this.setTargetId = function (c) { 81 | r = c 82 | }; 83 | this.setReceivedTime = function (c) { 84 | u = c 85 | }; 86 | this.toJSON = function () { 87 | var c = { 88 | "receivedTime": u, 89 | "messageType": x, 90 | "details": z, 91 | "conversationType": o, 92 | "direction": q, 93 | "messageId": t, 94 | "objectName": y, 95 | "senderUserId": p, 96 | "sendTime": v, 97 | "targetId": r 98 | }; 99 | return tool.JSON.stringify(c) 100 | }; 101 | this.getMessageType = function () { 102 | return x 103 | }; 104 | this.setMessageType = function (c) { 105 | x = c 106 | } 107 | }; 108 | //通知类型消息基类,继承自RongIMMessage 109 | RongIMClient.NotificationMessage = function (c) { 110 | RongIMClient.RongIMMessage.call(this, c); 111 | this.getMessageTag = function () { 112 | return [RongIMClient.MessageTag.ISPERSISTED, RongIMClient.MessageTag.ISDISPLAYED]; 113 | }; 114 | }; 115 | tool.inherit(RongIMClient.NotificationMessage, RongIMClient.RongIMMessage, true); 116 | //状态类型消息基类,继承自RongIMMessage 117 | RongIMClient.StatusMessage = function (c) { 118 | RongIMClient.RongIMMessage.call(this, c); 119 | this.getMessageTag = function () { 120 | return ['NONE']; 121 | }; 122 | }; 123 | tool.inherit(RongIMClient.StatusMessage, RongIMClient.RongIMMessage, true); 124 | //文本消息 125 | RongIMClient.TextMessage = function (c) { 126 | RongIMClient.RongIMMessage.call(this, c); 127 | this.setMessageType(RongIMClient.MessageType.TextMessage); 128 | this.setObjectName("RC:TxtMsg"); 129 | }; 130 | RongIMClient.TextMessage.obtain = function (text) { 131 | return new RongIMClient.TextMessage({ 132 | content: text, 133 | extra: "" 134 | }) 135 | }; 136 | tool.inherit(RongIMClient.TextMessage, RongIMClient.RongIMMessage, true); 137 | //图片消息 138 | RongIMClient.ImageMessage = function (c) { 139 | RongIMClient.RongIMMessage.call(this, c); 140 | this.setMessageType(RongIMClient.MessageType.ImageMessage); 141 | this.setObjectName("RC:ImgMsg"); 142 | this.setImageUri = function (a) { 143 | this.setContent(a, "imageUri") 144 | }; 145 | this.getImageUri = function () { 146 | return this.getDetail().imageUri 147 | }; 148 | }; 149 | RongIMClient.ImageMessage.obtain = function (content, imageUri) { 150 | return new RongIMClient.ImageMessage({ 151 | content: content, 152 | imageUri: imageUri, 153 | extra: "" 154 | }); 155 | }; 156 | tool.inherit(RongIMClient.ImageMessage, RongIMClient.RongIMMessage, true); 157 | //图文消息 158 | RongIMClient.RichContentMessage = function (c) { 159 | RongIMClient.RongIMMessage.call(this, c); 160 | this.setMessageType(RongIMClient.MessageType.RichContentMessage); 161 | this.setObjectName("RC:ImgTextMsg"); 162 | this.setTitle = function (a) { 163 | this.setContent(a, "title") 164 | }; 165 | this.getTitle = function () { 166 | return this.getDetail().title; 167 | }; 168 | this.setImageUri = function (a) { 169 | this.setContent(a, "imageUri") 170 | }; 171 | this.getImageUri = function () { 172 | return this.getDetail().imageUri; 173 | }; 174 | }; 175 | RongIMClient.RichContentMessage.obtain = function (title, content, imageUri) { 176 | return new RongIMClient.RichContentMessage({ 177 | title: title, 178 | content: content, 179 | imageUri: imageUri, 180 | extra: "" 181 | }) 182 | }; 183 | tool.inherit(RongIMClient.RichContentMessage, RongIMClient.RongIMMessage, true); 184 | //音频消息 185 | RongIMClient.VoiceMessage = function (c) { 186 | RongIMClient.RongIMMessage.call(this, c); 187 | this.setObjectName("RC:VcMsg"); 188 | this.setMessageType(RongIMClient.MessageType.VoiceMessage); 189 | this.setDuration = function (a) { 190 | this.setContent(a, "duration") 191 | }; 192 | this.getDuration = function () { 193 | return this.getDetail().duration; 194 | }; 195 | }; 196 | RongIMClient.VoiceMessage.obtain = function (content, duration) { 197 | return new RongIMClient.VoiceMessage({ 198 | content: content, 199 | duration: duration, 200 | extra: "" 201 | }) 202 | }; 203 | tool.inherit(RongIMClient.VoiceMessage, RongIMClient.RongIMMessage, true); 204 | //客服握手消息 205 | RongIMClient.HandshakeMessage = function () { 206 | RongIMClient.RongIMMessage.call(this); 207 | this.setMessageType(RongIMClient.MessageType.HandshakeMessage); 208 | this.setObjectName("RC:HsMsg"); 209 | }; 210 | tool.inherit(RongIMClient.HandshakeMessage, RongIMClient.RongIMMessage, true); 211 | //中断客服消息 212 | RongIMClient.SuspendMessage = function () { 213 | RongIMClient.RongIMMessage.call(this); 214 | this.setMessageType(RongIMClient.MessageType.SuspendMessage); 215 | this.setObjectName("RC:SpMsg"); 216 | }; 217 | tool.inherit(RongIMClient.SuspendMessage, RongIMClient.RongIMMessage, true); 218 | //未知消息 219 | RongIMClient.UnknownMessage = function (c, o) { 220 | RongIMClient.RongIMMessage.call(this, c); 221 | this.setMessageType(RongIMClient.MessageType.UnknownMessage); 222 | this.setObjectName(o); 223 | }; 224 | tool.inherit(RongIMClient.UnknownMessage, RongIMClient.RongIMMessage, true); 225 | //地理位置消息 226 | RongIMClient.LocationMessage = function (c) { 227 | RongIMClient.RongIMMessage.call(this, c); 228 | this.setMessageType(RongIMClient.MessageType.LocationMessage); 229 | this.setObjectName("RC:LBSMsg"); 230 | this.setLatitude = function (a) { 231 | this.setContent(a, "latitude") 232 | }; 233 | this.getLatitude = function () { 234 | return this.getDetail().latitude; 235 | }; 236 | this.setLongitude = function (a) { 237 | this.setContent(a, "longitude") 238 | }; 239 | this.getLongitude = function () { 240 | return this.getDetail().longitude; 241 | }; 242 | this.setPoi = function (a) { 243 | this.setContent(a, "poi") 244 | }; 245 | this.getPoi = function () { 246 | return this.getDetail().poi; 247 | }; 248 | }; 249 | RongIMClient.LocationMessage.obtain = function (content, latitude, longitude, poi) { 250 | return new RongIMClient.LocationMessage({ 251 | content: content, 252 | latitude: latitude, 253 | longitude: longitude, 254 | poi: poi, 255 | extra: "" 256 | }) 257 | }; 258 | tool.inherit(RongIMClient.LocationMessage, RongIMClient.RongIMMessage, true); 259 | //讨论组通知消息 260 | RongIMClient.DiscussionNotificationMessage = function (c) { 261 | RongIMClient.NotificationMessage.call(this, c); 262 | this.setMessageType(RongIMClient.MessageType.DiscussionNotificationMessage); 263 | this.setObjectName("RC:DizNtf"); 264 | var isReceived = false; 265 | this.getExtension = function () { 266 | return this.getDetail().extension; 267 | }; 268 | this.getOperator = function () { 269 | return this.getDetail().operator; 270 | }; 271 | this.getType = function () { 272 | return this.getDetail().type; 273 | }; 274 | this.isHasReceived = function () { 275 | return isReceived; 276 | }; 277 | this.setExtension = function (a) { 278 | this.setContent(a, "extension") 279 | }; 280 | this.setHasReceived = function (x) { 281 | isReceived = !!x; 282 | }; 283 | this.setOperator = function (a) { 284 | this.setContent(a, "operator") 285 | }; 286 | this.setType = function (a) { 287 | this.setContent(a, "type"); 288 | //1:加入讨论组 2:退出讨论组 3:讨论组改名 4:讨论组群主T人 289 | }; 290 | }; 291 | tool.inherit(RongIMClient.DiscussionNotificationMessage, RongIMClient.NotificationMessage, true); 292 | //信息通知消息,继承自NotificationMessage 293 | RongIMClient.InformationNotificationMessage = function (c) { 294 | RongIMClient.NotificationMessage.call(this, c); 295 | this.setMessageType(RongIMClient.MessageType.InformationNotificationMessage); 296 | this.setObjectName("RC:InfoNtf"); 297 | }; 298 | RongIMClient.InformationNotificationMessage.obtain = function (content) { 299 | return new RongIMClient.InformationNotificationMessage({ 300 | content: content, 301 | extra: "" 302 | }) 303 | }; 304 | tool.inherit(RongIMClient.InformationNotificationMessage, RongIMClient.NotificationMessage, true); 305 | //加删好友消息 306 | RongIMClient.ContactNotificationMessage = function (c) { 307 | RongIMClient.NotificationMessage.call(this, c); 308 | this.setMessageType(RongIMClient.MessageType.ContactNotificationMessage); 309 | this.setObjectName("RC:ContactNtf"); 310 | this.getOperation = function () { 311 | return this.getDetail().operation; 312 | }; 313 | this.setOperation = function (o) { 314 | this.setContent(o, 'operation'); 315 | }; 316 | this.setMessage = function (m) { 317 | this.setContent(m, 'message'); 318 | }; 319 | this.getMessage = function () { 320 | return this.getDetail().message; 321 | }; 322 | this.getSourceUserId = function () { 323 | return this.getDetail().sourceUserId; 324 | }; 325 | this.setSourceUserId = function (m) { 326 | this.setContent(m, 'sourceUserId'); 327 | }; 328 | this.getTargetUserId = function () { 329 | return this.getDetail().targetUserId; 330 | }; 331 | this.setTargetUserId = function (m) { 332 | this.setContent(m, 'targetUserId'); 333 | }; 334 | }; 335 | RongIMClient.ContactNotificationMessage.obtain = function (operation, sourceUserId, targetUserId, message) { 336 | return new RongIMClient.ContactNotificationMessage({ 337 | operation: operation, 338 | sourceUserId: sourceUserId, 339 | targetUserId: targetUserId, 340 | message: message, 341 | extra: "" 342 | }); 343 | }; 344 | //允许加好友 345 | RongIMClient.ContactNotificationMessage.CONTACT_OPERATION_ACCEPT_RESPONSE = 'ContactOperationAcceptResponse'; 346 | //拒绝加好友 347 | RongIMClient.ContactNotificationMessage.CONTACT_OPERATION_REJECT_RESPONSE = 'ContactOperationRejectResponse'; 348 | //发起加好友请求 349 | RongIMClient.ContactNotificationMessage.CONTACT_OPERATION_REQUEST = 'ContactOperationRequest'; 350 | tool.inherit(RongIMClient.ContactNotificationMessage, RongIMClient.NotificationMessage, true); 351 | //个人信息通知消息 352 | RongIMClient.ProfileNotificationMessage = function (c) { 353 | RongIMClient.NotificationMessage.call(this, c); 354 | this.setMessageType(RongIMClient.MessageType.ProfileNotificationMessage); 355 | this.setObjectName("RC:ProfileNtf"); 356 | this.getOperation = function () { 357 | return this.getDetail().operation; 358 | }; 359 | this.setOperation = function (o) { 360 | this.setContent(o, 'operation'); 361 | }; 362 | this.getData = function () { 363 | return this.getDetail().data; 364 | }; 365 | this.setData = function (o) { 366 | this.setContent(o, 'data'); 367 | }; 368 | }; 369 | RongIMClient.ProfileNotificationMessage.obtain = function (operation, data) { 370 | return new RongIMClient.ProfileNotificationMessage({ 371 | operation: operation, 372 | data: data, 373 | extra: "" 374 | }); 375 | }; 376 | tool.inherit(RongIMClient.ProfileNotificationMessage, RongIMClient.NotificationMessage, true); 377 | //命令通知消息 378 | RongIMClient.CommandNotificationMessage = function (c) { 379 | RongIMClient.NotificationMessage.call(this, c); 380 | this.setMessageType(RongIMClient.MessageType.CommandNotificationMessage); 381 | this.setObjectName("RC:CmdNtf"); 382 | this.getData = function () { 383 | return this.getDetail().data; 384 | }; 385 | this.setData = function (o) { 386 | this.setContent(o, "data"); 387 | }; 388 | this.getName = function () { 389 | return this.getDetail().name; 390 | }; 391 | this.setName = function (o) { 392 | this.setContent(o, 'name'); 393 | }; 394 | }; 395 | RongIMClient.CommandNotificationMessage.obtain = function (x, data) { 396 | return new RongIMClient.CommandNotificationMessage({ 397 | name: x, 398 | data: data, 399 | extra: "" 400 | }); 401 | }; 402 | tool.inherit(RongIMClient.CommandNotificationMessage, RongIMClient.NotificationMessage, true); -------------------------------------------------------------------------------- /src/IMClient/entry.js: -------------------------------------------------------------------------------- 1 | var RongIMClient = require('./RongIMClient'); 2 | var tool = require('../tool'); 3 | var mapping = require('../mapping'); 4 | require('../ready'); 5 | require('./affiliatedMessage'); 6 | require('./coustomMessage'); 7 | require('./IMEnum'); 8 | //版本号 9 | RongIMClient.version = "0.9.10"; 10 | // RongIMClient.connect静态方法,执行连接操作 11 | RongIMClient.connect = function (d, a) { 12 | if (!RongIMClient.getInstance) { 13 | throw new Error("please init") 14 | } 15 | //判断protobuf文件加载是否完成 16 | if (global.Modules) { 17 | //完成执行connect方法 18 | RongIMClient.getInstance().connect(d, a); 19 | } else { 20 | //把token、回调函数赋值给RongIMClient.connect,让protobuf文件自己来触发连接操作 21 | RongIMClient.connect.token = d; 22 | RongIMClient.connect.callback = a 23 | } 24 | }; 25 | //是否有未接收的消息,jsonp方法 26 | RongIMClient.hasUnreadMessages = function (appkey, token, callback) { 27 | tool.jsonp("http://api.cn.rong.io/message/exist.js?appKey=" + 28 | encodeURIComponent(appkey) + "&token=" + encodeURIComponent(token), 29 | "callBack", function (x) { 30 | callback.onSuccess(!!+x.status); 31 | }, function () { 32 | callback.onError(RongIMClient.callback.ErrorCode.UNKNOWN_ERROR); 33 | }); 34 | }; 35 | //初始化。生成一个RongIMClient单例 36 | RongIMClient.init = function (d, conf) { 37 | 38 | mapping.WEB_SOCKET_FORCE_FLASH = !!conf.WEB_SOCKET_FORCE_FLASH; 39 | mapping.WEB_XHR_POLLING = !!conf.WEB_XHR_POLLING; 40 | mapping.FORCE_LOCAL_STORAGE = !!conf.FORCE_LOCAL_STORAGE; 41 | 42 | var instance = null; 43 | RongIMClient.getInstance === undefined && (RongIMClient.getInstance = function () { 44 | if (instance == null) { 45 | instance = new RongIMClient(d); 46 | } 47 | return instance; 48 | }); 49 | }; 50 | //注册自定义消息 51 | RongIMClient.registerMessageType = function (regMsg) { 52 | if (!RongIMClient.getInstance) { 53 | throw new Error("unInitException") 54 | } 55 | if ("messageType" in regMsg && "objectName" in regMsg && "fieldName" in regMsg) { 56 | mapping.registerMessageTypeMapping[regMsg.objectName] = regMsg.messageType; 57 | var temp = RongIMClient[regMsg.messageType] = function (c) { 58 | RongIMClient.RongIMMessage.call(this, c); 59 | RongIMClient.MessageType[regMsg.messageType] = regMsg.messageType; 60 | this.setMessageType(regMsg.messageType); 61 | this.setObjectName(regMsg.objectName); 62 | for (var i = 0; i < regMsg.fieldName.length; i++) { 63 | var item = regMsg.fieldName[i]; 64 | this["set" + item] = (function (na) { 65 | return function (a) { 66 | this.setContent(a, na); 67 | } 68 | })(item); 69 | this["get" + item] = (function (na) { 70 | return function () { 71 | return this.getDetail()[na]; 72 | } 73 | })(item); 74 | } 75 | }; 76 | tool.inherit(temp, RongIMClient.RongIMMessage, true); 77 | } else 78 | throw new Error("registerMessageType:arguments type is error"); 79 | }; 80 | //设置连接状态监听器 81 | RongIMClient.setConnectionStatusListener = function (a) { 82 | if (!RongIMClient.getInstance) { 83 | throw new Error("unInitException") 84 | } 85 | RongIMClient.getInstance().setConnectionStatusListener(a) 86 | }; 87 | window.RongIMClient = RongIMClient; -------------------------------------------------------------------------------- /src/IMClient/shim.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyatao on 16/1/11. 3 | */ 4 | //存储会话列表的类 5 | var _func = function () { 6 | //添加会话,当前列表没有该会话则将该会话加到队列最后,有的话将该会话放到队列最开始 7 | this.add = function (x) { 8 | for (var i = 0; i < this.length; i++) { 9 | if (this[i].getTargetId() === x.getTargetId() && i != 0 && this[i].getConversationType() == x.getConversationType()) { 10 | this.unshift(this.splice(i, 1)[0]); 11 | return; 12 | } 13 | } 14 | this.unshift(x); 15 | }; 16 | //根据会话类型和tagetid从列表中得到会话 17 | this.get = function (conver, tarid) { 18 | for (var i = 0; i < this.length; i++) { 19 | if (this[i].getTargetId() == tarid && this[i].getConversationType() == conver) { 20 | return this[i] 21 | } 22 | } 23 | return null; 24 | } 25 | }; 26 | _func.prototype = []; 27 | //本地会话类型和服务器端会话类型映射关系 28 | var C2S = { 29 | "4": 1, 30 | "2": 2, 31 | "3": 3, 32 | "1": 5 33 | }; 34 | var sessionStore = global.sessionStorage || new function () { 35 | var c = {}; 36 | this.length = 0; 37 | this.clear = function () { 38 | c = {}; 39 | this.length = 0 40 | }; 41 | this.setItem = function (e, f) { 42 | !c[e] && this.length++; 43 | c[e] = f; 44 | return e in c 45 | }; 46 | this.getItem = function (e) { 47 | return c[e] 48 | }; 49 | this.removeItem = function (f) { 50 | if (f in c) { 51 | delete c[f]; 52 | this.length--; 53 | return true; 54 | } 55 | return false; 56 | } 57 | }; 58 | var LimitableMap = function (limit) { 59 | this.limit = limit || 10; 60 | this.map = {}; 61 | this.keys = []; 62 | }; 63 | LimitableMap.prototype.set = function (key, value) { 64 | var map = this.map; 65 | var keys = this.keys; 66 | if (!map.hasOwnProperty(key)) { 67 | if (keys.length === this.limit) { 68 | var firstKey = keys.shift(); 69 | delete map[firstKey]; 70 | } 71 | keys.push(key) 72 | } 73 | map[key] = value; 74 | }; 75 | LimitableMap.prototype.get = function (key) { 76 | return this.map[key] || 0; 77 | }; 78 | module.exports = { 79 | list: _func, 80 | C2S: C2S, 81 | sessionStore: sessionStore, 82 | LimitableMap: LimitableMap 83 | }; -------------------------------------------------------------------------------- /src/binary.js: -------------------------------------------------------------------------------- 1 | var global = window; 2 | var binaryPot = global.RongBinaryHelper = { 3 | /** 4 | * 初始化字节流,把-128至128的区间改为0-256的区间.便于计算 5 | * @param {Array} array 字节流数组 6 | * @return {Array} 转化好的字节流数组 7 | */ 8 | init: function (array) { 9 | for (var i = 0; i < array.length; i++) { 10 | array[i] *= 1; 11 | if (array[i] < 0) { 12 | array[i] += 256 13 | } 14 | if (array[i] > 255) { 15 | throw new Error('不合法字节流') 16 | } 17 | } 18 | return array; 19 | }, 20 | /** 21 | * 把一段字符串按照utf8编码写到缓冲区中 22 | * @param {String} str 将要写入缓冲区的字符串 23 | * @param {Boolean} isGetBytes 是否只得到内容字节(不包括最开始的两位占位字节) 24 | * @returns {Array} 字节流 25 | */ 26 | writeUTF: function (str, isGetBytes) { 27 | var back = [], 28 | byteSize = 0; 29 | for (var i = 0; i < str.length; i++) { 30 | var code = str.charCodeAt(i); 31 | if (code >= 0 && code <= 127) { 32 | byteSize += 1; 33 | back.push(code); 34 | } else if (code >= 128 && code <= 2047) { 35 | byteSize += 2; 36 | back.push((192 | (31 & (code >> 6)))); 37 | back.push((128 | (63 & code))) 38 | } else if (code >= 2048 && code <= 65535) { 39 | byteSize += 3; 40 | back.push((224 | (15 & (code >> 12)))); 41 | back.push((128 | (63 & (code >> 6)))); 42 | back.push((128 | (63 & code))) 43 | } 44 | } 45 | for (i = 0; i < back.length; i++) { 46 | if (back[i] > 255) { 47 | back[i] &= 255 48 | } 49 | } 50 | if (isGetBytes) { 51 | return back 52 | } 53 | if (byteSize <= 255) { 54 | return [0, byteSize].concat(back); 55 | } else { 56 | return [byteSize >> 8, byteSize & 255].concat(back); 57 | } 58 | }, 59 | /** 60 | * 把一串字节流按照utf8编码读取出来 61 | * @param arr 字节流 62 | * @returns {String} 读取出来的字符串 63 | */ 64 | readUTF: function (arr) { 65 | if (Object.prototype.toString.call(arr) == "[object String]") { 66 | return arr; 67 | } 68 | var UTF = "", 69 | _arr = this.init(arr); 70 | for (var i = 0; i < _arr.length; i++) { 71 | var one = _arr[i].toString(2), 72 | v = one.match(/^1+?(?=0)/); 73 | if (v && one.length == 8) { 74 | var bytesLength = v[0].length, 75 | store = _arr[i].toString(2).slice(7 - bytesLength); 76 | for (var st = 1; st < bytesLength; st++) { 77 | store += _arr[st + i].toString(2).slice(2) 78 | } 79 | UTF += String.fromCharCode(parseInt(store, 2)); 80 | i += bytesLength - 1 81 | } else { 82 | UTF += String.fromCharCode(_arr[i]) 83 | } 84 | } 85 | return UTF 86 | }, 87 | /** 88 | * 转换成Stream对象 89 | * @param x 90 | * @returns {TinyStream} 91 | */ 92 | convertStream: function (x) { 93 | if (x instanceof TinyStream) { 94 | return x 95 | } else { 96 | return new TinyStream(x) 97 | } 98 | }, 99 | /** 100 | * 把一段字符串转为mqtt格式 101 | * @param str 102 | * @returns {*|Array} 103 | */ 104 | toMQttString: function (str) { 105 | return this.writeUTF(str) 106 | } 107 | }; 108 | /** 109 | * 读取指定长度的字节流到指定数组中 110 | * @param {TinyStream} m Stream实例 111 | * @param {number} i 读取的长度 112 | * @param {Array} a 存入的数组 113 | * @returns {Array} 存入的数组 114 | */ 115 | function baseRead(m, i, a) { 116 | var t = a ? a : []; 117 | for (var start = 0; start < i; start++) { 118 | t[start] = m.pool[m.position++] 119 | } 120 | return t 121 | } 122 | /** 123 | * 判断浏览器是否支持ArrayBuffer 124 | */ 125 | var supportArrayBuffer = (function () { 126 | return !!window.ArrayBuffer; 127 | })(); 128 | /** 129 | * 字节流处理实体类 130 | * @param {String|Array} array 初始化字节流,如果是字符串则按照UTF8的格式写入缓冲区 131 | * @constructor 132 | */ 133 | function TinyStream(array) { 134 | if (!(this instanceof TinyStream)) { 135 | return new TinyStream(array); 136 | } 137 | /** 138 | * 字节流缓冲区 139 | * @type {Array} 140 | */ 141 | this.pool = []; 142 | if (Object.prototype.toString.call(array) === '[object Array]') { 143 | this.pool = binaryPot.init(array); 144 | } else if (Object.prototype.toString.call(array) == "[object ArrayBuffer]") { 145 | var arr = new Int8Array(array); 146 | this.pool = binaryPot.init([].slice.call(arr)); 147 | } else if (typeof array === 'string') { 148 | this.pool = binaryPot.writeUTF(array); 149 | } 150 | var self = this; 151 | //当前流执行的起始位置 152 | this.position = 0; 153 | //当前流写入的多少字节 154 | this.writen = 0; 155 | //返回当前流执行的起始位置是否已经大于整个流的长度 156 | this.check = function () { 157 | return self.position >= self.pool.length 158 | }; 159 | } 160 | /** 161 | * 强制转换为Stream对象 162 | * @param x 163 | * @returns {*|TinyStream} 164 | */ 165 | TinyStream.parse = function (x) { 166 | return binaryPot.convertStream(x); 167 | }; 168 | TinyStream.toMQTString = function (x) { 169 | return binaryPot.toMQttString(x); 170 | }; 171 | TinyStream.prototype = { 172 | /** 173 | * 从缓冲区读取4个字节的长度并转换为int值,position往后移4位 174 | * @returns {Number} 读取到的数字 175 | * @description 如果position大于等于缓冲区的长度则返回-1 176 | */ 177 | readInt: function () { 178 | if (this.check()) { 179 | return -1 180 | } 181 | var end = ""; 182 | for (var i = 0; i < 4; i++) { 183 | end += this.pool[this.position++].toString(16) 184 | } 185 | return parseInt(end, 16); 186 | }, 187 | /** 188 | * 从缓冲区读取1个字节,position往后移1位 189 | * @returns {Number} 190 | * @description 如果position大于等于缓冲区的长度则返回-1 191 | */ 192 | readByte: function () { 193 | if (this.check()) { 194 | return -1 195 | } 196 | var val = this.pool[this.position++]; 197 | if (val > 255) { 198 | val &= 255; 199 | } 200 | return val; 201 | }, 202 | /** 203 | * 从缓冲区读取1个字节,或读取指定长度的字节到传入的数组中,position往后移1或bytesArray.length位 204 | * @param {Array|undefined} bytesArray 205 | * @returns {Array|Number} 206 | */ 207 | read: function (bytesArray) { 208 | if (this.check()) { 209 | return -1 210 | } 211 | if (bytesArray) { 212 | return baseRead(this, bytesArray.length | 0, bytesArray) 213 | } else { 214 | return this.readByte(); 215 | } 216 | }, 217 | /** 218 | * 从缓冲区的position位置按UTF8的格式读取字符串,position往后移指定的长度 219 | * @returns {String} 读取的字符串 220 | */ 221 | readUTF: function () { 222 | var big = (this.readByte() << 8) | this.readByte(); 223 | return binaryPot.readUTF(this.pool.slice(this.position, this.position += big)); 224 | }, 225 | /** 226 | * 把字节流写入缓冲区,writen往后移指定的位 227 | * @param {Number|Array} _byte 写入缓冲区的字节(流) 228 | * @returns {Array} 写入的字节流 229 | */ 230 | write: function (_byte) { 231 | var b = _byte; 232 | if (Object.prototype.toString.call(b).toLowerCase() == "[object array]") { 233 | [].push.apply(this.pool, b); 234 | this.writen += b.length; 235 | } else { 236 | if (+b == b) { 237 | if (b > 255) { 238 | b &= 255; 239 | } 240 | this.pool.push(b); 241 | this.writen++ 242 | } 243 | } 244 | return b 245 | }, 246 | /** 247 | * 把参数当成char类型写入缓冲区,writen往后移2位 248 | * @param {Number} v 写入缓冲区的字节 249 | */ 250 | writeChar: function (v) { 251 | if (+v != v) { 252 | throw new Error("writeChar:arguments type is error") 253 | } 254 | this.write((v >> 8) & 255); 255 | this.write(v & 255); 256 | this.writen += 2 257 | }, 258 | /** 259 | * 把字符串按照UTF8的格式写入缓冲区,writen往后移指定的位 260 | * @param {String} str 字符串 261 | * @return {Array} 缓冲区 262 | */ 263 | writeUTF: function (str) { 264 | var val = binaryPot.writeUTF(str); 265 | [].push.apply(this.pool, val); 266 | this.writen += val.length; 267 | }, 268 | /** 269 | * 把缓冲区字节流的格式从0至256的区间改为-128至128的区间 270 | * @returns {Array} 转换后的字节流 271 | */ 272 | toComplements: function () { 273 | var _tPool = this.pool; 274 | for (var i = 0; i < _tPool.length; i++) { 275 | if (_tPool[i] > 128) { 276 | _tPool[i] -= 256 277 | } 278 | } 279 | return _tPool 280 | }, 281 | /** 282 | * 获取整个缓冲区的字节 283 | * @param {Boolean} isCom 是否转换字节流区间 284 | * @returns {Array} 转换后的缓冲区 285 | */ 286 | getBytesArray: function (isCom) { 287 | if (isCom) { 288 | return this.toComplements() 289 | } 290 | return this.pool 291 | }, 292 | /** 293 | * 把缓冲区的字节流转换为ArrayBuffer 294 | * @returns {ArrayBuffer} 295 | * @throw {Error} 不支持ArrayBuffer 296 | */ 297 | toArrayBuffer: function () { 298 | if (supportArrayBuffer) { 299 | return new ArrayBuffer(this.getBytesArray()); 300 | } else { 301 | throw new Error('not support arraybuffer'); 302 | } 303 | }, 304 | clear: function () { 305 | this.pool = []; 306 | this.writen = this.position = 0; 307 | } 308 | }; 309 | module.exports = TinyStream; -------------------------------------------------------------------------------- /src/core/bridge.js: -------------------------------------------------------------------------------- 1 | var mapping = require('../mapping'); 2 | var client = require('./client'); 3 | var e = require('../message/msgEnum'); 4 | var Qos = e.Qos; 5 | 6 | var Bridge = function (_appkey, _token, _callback) { 7 | this.context = client.connect(_appkey, _token, _callback); 8 | Bridge.getInstance = function () { 9 | return this; 10 | } 11 | }; 12 | Bridge.prototype.setListener = function (_changer) { 13 | if (typeof _changer == "object") { 14 | if (typeof _changer.onChanged == 'function') { 15 | mapping._ConnectionStatusListener = _changer; 16 | } else if (typeof _changer.onReceived == 'function') { 17 | mapping._ReceiveMessageListener = _changer; 18 | } 19 | } 20 | }; 21 | //重连 22 | Bridge.prototype.reConnect = function (callback) { 23 | this.context.channel.reconnect(callback) 24 | }; 25 | //断连 26 | Bridge.prototype.disConnect = function () { 27 | this.context.clearHeartbeat(); 28 | this.context.channel.disconnect() 29 | }; 30 | //执行queryMessage请求 31 | Bridge.prototype.queryMsg = function (topic, content, targetId, callback, pbname) { 32 | if (typeof topic != "string") { 33 | topic = mapping.topic[topic] 34 | } 35 | this.context.queryMessage(topic, content, targetId, Qos.AT_MOST_ONCE, callback, pbname) 36 | }; 37 | //执行publishMessage请求 38 | Bridge.prototype.pubMsg = function (topic, content, targetId, callback, msg) { 39 | this.context.publishMessage(mapping.topic[10][topic], content, targetId, callback, msg) 40 | }; 41 | module.exports = Bridge; 42 | -------------------------------------------------------------------------------- /src/core/channel.js: -------------------------------------------------------------------------------- 1 | var mapping = require('../mapping'); 2 | var msgEnum = require('../message/msgEnum'); 3 | var factory = require('../io/factory'); 4 | var tool = require('../tool'); 5 | function Channel(address, cb, self) { 6 | //连接服务器 7 | this.context = self; 8 | this.socket = factory(address.host + 9 | "/websocket?appId=" + this.context.appId + 10 | "&token=" + encodeURIComponent(this.context.token) + 11 | "&sdkVer=" + this.context.sdkVer + 12 | "&apiVer=" + this.context.apiVer, 13 | cb); 14 | //注册状态改变观察者 15 | if ("onChanged" in mapping._ConnectionStatusListener) { 16 | this.socket.on("StatusChanged", function (code) { 17 | //如果参数为DisconnectionStatus,就停止心跳,其他的不停止心跳。每3min连接一次服务器 18 | if (code instanceof msgEnum.DisconnectionStatus) { 19 | mapping._ConnectionStatusListener.onChanged(RongIMClient.ConnectionStatus.setValue(code + 2)); 20 | self.clearHeartbeat(); 21 | return; 22 | } 23 | mapping._ConnectionStatusListener.onChanged(RongIMClient.ConnectionStatus.setValue(code)) 24 | }) 25 | } else { 26 | throw new Error("setConnectStatusListener:Parameter format is incorrect") 27 | } 28 | //注册message观察者 29 | this.socket.on("message", this.context.handler.handleMessage); 30 | //注册断开连接观察者 31 | var that = this; 32 | this.socket.on("disconnect", function () { 33 | that.socket.fire("StatusChanged", 4); 34 | }); 35 | } 36 | //发送,如果通道可写就发送,不可写就重连服务器 37 | Channel.prototype.writeAndFlush = function (val) { 38 | var that = this; 39 | if (this.isWritable()) { 40 | this.socket.send(val); 41 | } else { 42 | this.reconnect({ 43 | onSuccess: function () { 44 | that.socket.send(val); 45 | }, 46 | onError: function () { 47 | throw new Error("reconnect fail") 48 | } 49 | }) 50 | } 51 | }; 52 | //重连并清空messageid 53 | Channel.prototype.reconnect = function (callback) { 54 | tool.messageIdHandler.clearMessageId(); 55 | this.socket = this.socket.reconnect(); 56 | if (callback) { 57 | mapping.reconnectSet = callback; 58 | } 59 | }; 60 | Channel.prototype.disconnect = function (x) { 61 | this.socket.disconnect(x); 62 | }; 63 | //通道是否可写 64 | Channel.prototype.isWritable = function () { 65 | return this.socket.connected || this.socket.connecting; 66 | }; 67 | module.exports = Channel; -------------------------------------------------------------------------------- /src/core/client.js: -------------------------------------------------------------------------------- 1 | var entity = require('../message/MessageEntity'); 2 | var handler = require('./messageHandler'); 3 | var channel = require('./channel'); 4 | var ack = require('./messageCallback'); 5 | var mapping = require('../mapping'); 6 | var md5 = require('../md5'); 7 | var tool = require('../tool'); 8 | var en = require('../message/msgEnum'); 9 | var Qos = en.Qos; 10 | var global = window; 11 | //初始化通道对象 12 | ack.ConnectAck.redirect = function (callback) { 13 | Client.getInstance().channel = new channel(Client.Endpoint, callback, Client.getInstance()); 14 | }; 15 | //连接端类,逻辑处理全在此类中 16 | function Client(_to, _ap) { 17 | this.timeoutMillis = 100000; 18 | this.timeout_ = 0; 19 | this.appId = _ap; 20 | this.token = _to; 21 | this.sdkVer = "1.0.0"; 22 | this.apiVer = "1.0.0"; 23 | this.channel = null; 24 | this.handler = null; 25 | this.userId = ""; 26 | this.heartbeat = 0; 27 | this.chatroomId = ''; 28 | //用于心跳启动定时器 29 | } 30 | Client.prototype.resumeTimer = function () { 31 | var self = this; 32 | if (!this.timeout_) { 33 | this.timeout_ = setTimeout(function () { 34 | if (!self.timeout_) { 35 | return; 36 | } 37 | try { 38 | self.channel.disconnect() 39 | } catch (e) { 40 | } 41 | clearTimeout(self.timeout_); 42 | self.timeout_ = 0; 43 | self.channel.reconnect(); 44 | self.channel.socket.fire("StatusChanged", 5); 45 | }, self.timeoutMillis) 46 | } 47 | }; 48 | //销毁心跳定时器 49 | Client.prototype.pauseTimer = function () { 50 | if (this.timeout_) { 51 | clearTimeout(this.timeout_); 52 | this.timeout_ = 0; 53 | } 54 | }; 55 | //连接服务器 56 | Client.prototype.connect = function (_callback) { 57 | var self = this; 58 | //判断navi是否已经返回地址 59 | if (mapping.Endpoint.host) { 60 | if (tool.getTransportType() == "websocket") { 61 | if (!global.WebSocket) { 62 | _callback.onError(RongIMClient.ConnectErrorStatus.setValue(1)); 63 | return; 64 | } 65 | //判断是否是flashsocket 是的话就加载代理文件 66 | 'loadFlashPolicyFile' in WebSocket && WebSocket.loadFlashPolicyFile(); 67 | } 68 | //实例消息处理类 69 | this.handler = new handler(this); 70 | //设置连接回调 71 | this.handler.setConnectCallback(_callback); 72 | //实例通道类型 73 | this.channel = new channel(mapping.Endpoint, function () { 74 | tool.getTransportType() == "websocket" && self.keepLive() 75 | }, this); 76 | //触发状态改变观察者 77 | this.channel.socket.fire("StatusChanged", 1) 78 | } else { 79 | //没有返回地址就手动抛出错误 80 | _callback.onError(RongIMClient.ConnectErrorStatus.setValue(5)); 81 | } 82 | }; 83 | //心跳启动方法 84 | Client.prototype.keepLive = function () { 85 | var self = this; 86 | if (this.heartbeat > 0) { 87 | clearInterval(this.heartbeat); 88 | } 89 | this.heartbeat = setInterval(function () { 90 | self.resumeTimer(); 91 | self.channel.writeAndFlush(new entity.PingReqMessage()); 92 | console.log("keep live pingReqMessage sending appId " + self.appId); 93 | }, 180000); 94 | }; 95 | //心跳停止方法 96 | Client.prototype.clearHeartbeat = function () { 97 | clearInterval(this.heartbeat); 98 | this.heartbeat = 0; 99 | this.pauseTimer(); 100 | }; 101 | //发送publishMessage消息 102 | Client.prototype.publishMessage = function (_topic, _data, _targetId, _callback, _msg) { 103 | var msgId = tool.messageIdHandler.messageIdPlus(this.channel.reconnect); 104 | if (!msgId) { 105 | return; 106 | } 107 | var msg = new entity.PublishMessage(_topic, _data, _targetId); 108 | msg.setMessageId(msgId); 109 | if (_callback) { 110 | msg.setQos(Qos.AT_LEAST_ONCE); 111 | this.handler.putCallback(new ack.PublishCallback(_callback.onSuccess, _callback.onError), msg.getMessageId(), _msg) 112 | } else { 113 | msg.setQos(Qos.AT_MOST_ONCE); 114 | } 115 | this.channel.writeAndFlush(msg); 116 | }; 117 | //发送queryMessage消息 118 | Client.prototype.queryMessage = function (_topic, _data, _targetId, _qos, _callback, pbtype) { 119 | //如果topic是userinfo,就去userinfo缓存对象里拿,没有的话再去请求服务器拉取userinfo 120 | if (_topic == "userInf") { 121 | if (mapping.userInfoMapping[_targetId]) { 122 | _callback.onSuccess(mapping.userInfoMapping[_targetId]); 123 | return; 124 | } 125 | } 126 | var msgId = tool.messageIdHandler.messageIdPlus(this.channel.reconnect); 127 | if (!msgId) { 128 | return; 129 | } 130 | var msg = new entity.QueryMessage(_topic, _data, _targetId); 131 | msg.setMessageId(msgId); 132 | msg.setQos(_qos); 133 | this.handler.putCallback(new ack.QueryCallback(_callback.onSuccess, _callback.onError), msg.getMessageId(), pbtype); 134 | this.channel.writeAndFlush(msg) 135 | }; 136 | //同步消息 137 | Client.prototype.syncTime = function (_type, pullTime) { 138 | SyncTimeQueue.push({type: _type, pulltime: pullTime}); 139 | //如果队列中只有一个成员并且状态已经完成就执行invoke方法 140 | if (SyncTimeQueue.length == 1 && SyncTimeQueue.state == "complete") { 141 | invoke() 142 | } 143 | }; 144 | //声明Client.connect静态方法,返回Client实例 145 | Client.connect = function (appId, token, callback) { 146 | //如果appid和本地存储的不一样,清空所有本地存储数据 147 | var oldAppId = tool.cookieHelper.getItem("appId"); 148 | if (oldAppId && oldAppId != appId) { 149 | tool.cookieHelper.clear(); 150 | tool.cookieHelper.setItem("appId", appId); 151 | } 152 | var client = new Client(token, appId); 153 | Client.getInstance = function () { 154 | return client; 155 | }; 156 | //请求navi导航 157 | Client.getServerEndpoint(token, appId, callback, true); 158 | return client; 159 | }; 160 | Client.getServerEndpoint = function (_token, _appId, callback, unignore) { 161 | if (unignore) { 162 | //根据token生成MD5截取8-16下标的数据与本地存储的导航信息进行比对 163 | //如果信息和上次的通道类型都一样,不执行navi请求,用本地存储的导航信息连接服务器 164 | var naviStr = md5(_token).slice(8, 16), 165 | _old = tool.cookieHelper.getItem("navi\\w+?"), 166 | _new = tool.cookieHelper.getItem("navi" + naviStr); 167 | if (_old == _new && _new !== null && tool.cookieHelper.getItem("rongSDK") == tool.getTransportType()) { 168 | var obj = unescape(_old).split(","); 169 | setTimeout(function () { 170 | RongBinaryHelper.__host = mapping.Endpoint.host = obj[0]; 171 | mapping.Endpoint.userId = obj[1]; 172 | Client.getInstance().connect(callback); 173 | }, 500); 174 | return; 175 | } 176 | } 177 | //导航信息,切换Url对象的key进行线上线下测试操作 178 | var Url = { 179 | //测试环境 180 | "navUrl-Debug": "http://nav.sunquan.rongcloud.net:9001/", 181 | //线上环境 182 | "navUrl-Release": "http://nav.cn.rong.io/" 183 | }; 184 | tool.jsonp(Url["navUrl-Release"] + 185 | (tool.getTransportType() == "xhr-polling" ? "cometnavi.js" : "navi.js") + 186 | "?appId=" + _appId + "&token=" + encodeURIComponent(_token), 187 | "callBack", 188 | function (data) { 189 | Client.getInstance().connect(callback); 190 | //把导航返回的server字段赋值给RongBinaryHelper.__host,因为flash widget需要使用 191 | RongBinaryHelper.__host = mapping.Endpoint.host = data["server"]; 192 | mapping.Endpoint.userId = data.userId; 193 | //替换本地存储的导航信息 194 | var temp = document.cookie.match(new RegExp("(^| )navi\\w+?=([^;]*)(;|$)")); 195 | temp !== null && tool.cookieHelper.removeItem(temp[0].split("=")[0].replace(/^\s/, "")); 196 | tool.cookieHelper.setItem("navi" + md5(Client.getInstance().token).slice(8, 16), data["server"] + "," + (data.userId || "")); 197 | }, function () { 198 | callback.onError(RongIMClient.ConnectErrorStatus.setValue(4)); 199 | }); 200 | }; 201 | //同步消息队列 202 | var SyncTimeQueue = []; 203 | //队列的执行状态 204 | SyncTimeQueue.state = "complete"; 205 | function invoke() { 206 | var time, modules, str, target; 207 | //从队列开头取出一个赋值给temp变量 208 | var temp = SyncTimeQueue.shift(); 209 | var self = Client.getInstance(); 210 | if (!temp) { 211 | return; 212 | } 213 | //改变状态为pending 214 | SyncTimeQueue.state = "pending"; 215 | if (temp.type != 2) { 216 | //普通消息 217 | time = tool.cookieHelper.getItem(self.userId) || 0; 218 | modules = new Modules.SyncRequestMsg(); 219 | modules.setIspolling(false); 220 | str = 'pullMsg'; 221 | target = self.userId; 222 | } else { 223 | //聊天室消息 224 | time = tool.cookieHelper.getItem(self.userId + "CST") || 0; 225 | modules = new Modules.ChrmPullMsg(); 226 | modules.setCount(0); 227 | str = 'chrmPull'; 228 | if (self.chatroomId === '') { 229 | //受到聊天室消息,但是本地没有加入聊天室就手动抛出一个错误 230 | throw new Error("syncTime:Received messages of chatroom but was not init"); 231 | } 232 | target = self.chatroomId; 233 | } 234 | //判断服务器给的时间是否消息本地存储的时间,小于的话不执行拉取操作,进行一下步队列操作 235 | if (temp.pulltime <= time) { 236 | SyncTimeQueue.state = "complete"; 237 | invoke(); 238 | return; 239 | } 240 | modules.setSyncTime(time); 241 | //发送queryMessage请求 242 | self.queryMessage(str, tool.arrayFrom(modules.toArrayBuffer()), target, Qos.AT_LEAST_ONCE, { 243 | onSuccess: function (collection) { 244 | var sync = tool.int64ToTimestamp(collection.syncTime), 245 | symbol = self.userId; 246 | if (str == "chrmPull") { 247 | symbol += 'CST'; 248 | } 249 | //把返回时间戳存入本地,普通消息key为userid,聊天室消息key为userid+'CST';value都为服务器返回的时间戳 250 | tool.cookieHelper.setItem(symbol, sync); 251 | //把拉取到的消息逐条传给消息监听器 252 | var list = collection.list; 253 | for (var i = 0; i < list.length; i++) { 254 | Client.getInstance().handler.onReceived(list[i]) 255 | } 256 | SyncTimeQueue.state = "complete"; 257 | invoke(); 258 | }, 259 | onError: function () { 260 | SyncTimeQueue.state = "complete"; 261 | invoke(); 262 | } 263 | }, "DownStreamMessages"); 264 | } 265 | module.exports = Client; -------------------------------------------------------------------------------- /src/core/messageCallback.js: -------------------------------------------------------------------------------- 1 | var tool = require('../tool'); 2 | var mapping = require('../mapping'); 3 | var factory = require('../io/factory'); 4 | //protobuf映射 5 | function callbackMapping(entity, tag) { 6 | switch (tag) { 7 | case "GetUserInfoOutput": 8 | var userInfo = new RongIMClient.UserInfo(); 9 | userInfo.setUserId(entity.userId); 10 | userInfo.setUserName(entity.userName); 11 | userInfo.setPortraitUri(entity.userPortrait); 12 | return userInfo; 13 | case "GetQNupTokenOutput": 14 | return { 15 | deadline: util.int64ToTimestamp(entity.deadline), 16 | token: entity.token 17 | }; 18 | case "GetQNdownloadUrlOutput": 19 | return { 20 | downloadUrl: entity.downloadUrl 21 | }; 22 | case "CreateDiscussionOutput": 23 | return entity.id; 24 | case "ChannelInfoOutput": 25 | var disInfo = new RongIMClient.Discussion(); 26 | disInfo.setCreatorId(entity.adminUserId); 27 | disInfo.setId(entity.channelId); 28 | disInfo.setMemberIdList(entity.firstTenUserIds); 29 | disInfo.setName(entity.channelName); 30 | disInfo.setOpen(RongIMClient.DiscussionInviteStatus.setValue(entity.openStatus)); 31 | return disInfo; 32 | case "GroupHashOutput": 33 | return entity.result; 34 | case "QueryBlackListOutput": 35 | return entity.userIds; 36 | default: 37 | return entity; 38 | } 39 | } 40 | function MessageCallback(error) { 41 | var timeoutMillis, me = this; 42 | this.timeout = null; 43 | this.onError = null; 44 | if (error && typeof error == "number") { 45 | timeoutMillis = error 46 | } else { 47 | timeoutMillis = 6000; 48 | this.onError = error; 49 | } 50 | this.resumeTimer = function () { 51 | if (timeoutMillis > 0 && !this.timeout) { 52 | this.timeout = setTimeout(function () { 53 | me.readTimeOut(true); 54 | }, timeoutMillis) 55 | } 56 | } 57 | } 58 | MessageCallback.prototype = { 59 | pauseTimer: function () { 60 | if (this.timeout) { 61 | clearTimeout(this.timeout); 62 | this.timeout = null 63 | } 64 | }, readTimeOut: function (isTimeout) { 65 | if (isTimeout && this.onError) { 66 | this.onError(RongIMClient.callback.ErrorCode.TIMEOUT) 67 | } else { 68 | this.pauseTimer() 69 | } 70 | } 71 | }; 72 | //发送PublishMessage消息回调类 73 | function PublishCallback(cb, _timeout) { 74 | MessageCallback.call(this, _timeout); 75 | this.done = cb || function () { 76 | }; 77 | this.fail = _timeout || function () { 78 | }; 79 | } 80 | tool.inherit(PublishCallback, MessageCallback); 81 | PublishCallback.prototype.process = function (_staus, _serverTime, _msg) { 82 | this.readTimeOut(); 83 | if (_staus == 0) { 84 | if (_msg) { 85 | //把发送的消息发送状态改为已接收 86 | _msg.setSentStatus(RongIMClient.SentStatus.RECEIVED) 87 | } 88 | this.done(); 89 | } else { 90 | this.fail(RongIMClient.SendErrorStatus.setValue(_staus)); 91 | } 92 | }; 93 | PublishCallback.prototype.readTimeOut = function (x) { 94 | PublishCallback.super_.prototype.readTimeOut.call(this, x) 95 | }; 96 | 97 | //发送QueryMessage消息回调类 98 | function QueryCallback(cb, _timeout) { 99 | MessageCallback.call(this, _timeout); 100 | this.done = cb || function () { 101 | }; 102 | this.fail = _timeout || function () { 103 | }; 104 | } 105 | tool.inherit(QueryCallback, MessageCallback); 106 | QueryCallback.prototype.process = function (status, data, serverTime, pbtype) { 107 | this.readTimeOut(); 108 | if (pbtype && data && status == 0) { 109 | try { 110 | data = callbackMapping(Modules[pbtype].decode(data), pbtype); 111 | } catch (e) { 112 | this.fail(RongIMClient.callback.ErrorCode.UNKNOWN_ERROR); 113 | return; 114 | } 115 | if ("GetUserInfoOutput" == pbtype) { 116 | //pb类型为GetUserInfoOutput的话就把data放入userinfo缓存队列 117 | mapping.userInfoMapping[data.getUserId()] = data; 118 | } 119 | this.done(data); 120 | } else { 121 | status > 0 ? this.fail(status) : this.done(status) 122 | } 123 | }; 124 | QueryCallback.prototype.readTimeOut = function (x) { 125 | QueryCallback.super_.prototype.readTimeOut.call(this, x) 126 | }; 127 | 128 | //连接回调类 129 | function ConnectAck(cb, _timeout, context) { 130 | MessageCallback.call(this, _timeout); 131 | this.context = context; 132 | this.done = cb || function () { 133 | }; 134 | this.fail = _timeout || function () { 135 | }; 136 | } 137 | tool.inherit(ConnectAck, MessageCallback); 138 | ConnectAck.prototype.process = function (status, userId) { 139 | this.readTimeOut(); 140 | if (status == 0) { 141 | mapping.userId = this.context.userId = userId; 142 | if (!RongIMClient.isNotPullMsg) { 143 | this.context.syncTime(); 144 | } 145 | if (mapping.reconnectSet.onSuccess) { 146 | mapping.reconnectSet.onSuccess(userId); 147 | try { 148 | delete mapping.reconnectSet.onSuccess; 149 | } catch (e) { 150 | } 151 | } else { 152 | this.done(userId); 153 | } 154 | factory.getInstance().fire("StatusChanged", 0); 155 | factory.getInstance()._doQueue() 156 | } else if (status == 6) { 157 | var that = this; 158 | ConnectAck.redirect(this.context.token, this.context.appId, function () { 159 | that.context.clearHeartbeat(); 160 | ConnectAck.redirect(); 161 | that.context.channel.socket.fire("StatusChanged", 2); 162 | }, function () { 163 | that.fail(); 164 | }, false); 165 | } else { 166 | if (mapping.reconnectSet.onError) { 167 | mapping.reconnectSet.onError(RongIMClient.ConnectErrorStatus.setValue(status)); 168 | delete mapping.reconnectSet.onError; 169 | } else { 170 | this.fail(RongIMClient.ConnectErrorStatus.setValue(status)) 171 | } 172 | } 173 | }; 174 | ConnectAck.prototype.readTimeOut = function (x) { 175 | ConnectAck.super_.prototype.readTimeOut.call(this, x) 176 | }; 177 | ConnectAck.redirect = function () { 178 | }; 179 | 180 | module.exports = { 181 | MessageCallback: MessageCallback, 182 | PublishCallback: PublishCallback, 183 | QueryCallback: QueryCallback, 184 | ConnectAck: ConnectAck 185 | }; -------------------------------------------------------------------------------- /src/core/messageHandler.js: -------------------------------------------------------------------------------- 1 | var parser = require('./messageParser'); 2 | var mapping = require('../mapping'); 3 | var ack = require('./messageCallback'); 4 | var tool = require('../tool'); 5 | var entity=require('../message/MessageEntity'); 6 | var self = null; 7 | function MessageHandler(client) { 8 | if (!mapping._ReceiveMessageListener) { 9 | throw new Error("please set onReceiveMessageListener"); 10 | } 11 | self = this; 12 | this.context = client; 13 | this._map = {}; 14 | this._onReceived = mapping._ReceiveMessageListener.onReceived; 15 | this.connectCallback = null; 16 | } 17 | MessageHandler.prototype.putCallback = function (callbackObj, _publishMessageId, _msg) { 18 | var item = { 19 | Callback: callbackObj, 20 | Message: _msg 21 | }; 22 | item.Callback.resumeTimer(); 23 | this._map[_publishMessageId] = item; 24 | }; 25 | //设置连接回调对象,启动定时器 26 | MessageHandler.prototype.setConnectCallback = function (_connectCallback) { 27 | if (_connectCallback) { 28 | this.connectCallback = new ack.ConnectAck(_connectCallback.onSuccess, _connectCallback.onError, this.context); 29 | this.connectCallback.resumeTimer(); 30 | } 31 | }; 32 | //处理具体的消息对象 33 | MessageHandler.prototype.onReceived = function (msg) { 34 | //实体对象 35 | var entity; 36 | if (msg.constructor._name != "PublishMessage") { 37 | //如果msg不是一个内置消息对象,直接赋值给实体,进行下一步处理 38 | entity = msg; 39 | tool.cookieHelper.setItem(this.context.userId, tool.int64ToTimestamp(entity.dataTime)); 40 | } else { 41 | if (msg.getTopic() == "s_ntf") { 42 | entity = Modules.NotifyMsg.decode(msg.getData()); 43 | this.context.syncTime(entity.type, tool.int64ToTimestamp(entity.time)); 44 | return; 45 | } else if (msg.getTopic() == "s_msg") { 46 | entity = Modules.DownStreamMessage.decode(msg.getData()); 47 | tool.cookieHelper.setItem(this.context.userId, tool.int64ToTimestamp(entity.dataTime)); 48 | } else { 49 | return; 50 | } 51 | } 52 | //解析实体对象为消息对象。 53 | var message = parser(entity); 54 | if (message.getObjectName() in mapping.sysNtf) { 55 | this._onReceived(message); 56 | return; 57 | } 58 | //创建会话对象 59 | var con = RongIMClient.getInstance().getConversationList().get(message.getConversationType(), message.getTargetId()); 60 | if (!con) { 61 | con = RongIMClient.getInstance().createConversation(message.getConversationType(), message.getTargetId(), ""); 62 | } 63 | //根据messageTag判断是否进行消息数累加 64 | if (/ISCOUNTED/.test(message.getMessageTag())) { 65 | con.getConversationType() != 0 && con.setUnreadMessageCount(con.getUnreadMessageCount() + 1); 66 | } 67 | con.setReceivedTime((new Date).getTime()); 68 | con.setReceivedStatus(new RongIMClient.ReceivedStatus()); 69 | con.setSenderUserId(message.getSenderUserId()); 70 | con.setObjectName(message.getObjectName()); 71 | con.setNotificationStatus(RongIMClient.ConversationNotificationStatus.DO_NOT_DISTURB); 72 | con.setLatestMessageId(message.getMessageId()); 73 | con.setLatestMessage(message); 74 | con.setTop(); 75 | //把消息传递给消息监听器 76 | this._onReceived(message); 77 | }; 78 | //处理通道对象传送过来的内置消息对象 79 | MessageHandler.prototype.handleMessage = function (msg) { 80 | if (!msg) { 81 | return 82 | } 83 | switch (msg.constructor._name) { 84 | case "ConnAckMessage": 85 | self.connectCallback.process(msg.getStatus(), msg.getUserId()); 86 | break; 87 | case "PublishMessage": 88 | if (msg.getQos() != 0) { 89 | self.context.channel.writeAndFlush(new entity.PubAckMessage(msg.getMessageId())); 90 | } 91 | //如果是PublishMessage就把该对象给onReceived方法执行处理 92 | self.onReceived(msg); 93 | break; 94 | case "QueryAckMessage": 95 | if (msg.getQos() != 0) { 96 | self.context.channel.writeAndFlush(new entity.QueryConMessage(msg.getMessageId())) 97 | } 98 | var temp = self._map[msg.getMessageId()]; 99 | if (temp) { 100 | //执行回调操作 101 | temp.Callback.process(msg.getStatus(), msg.getData(), msg.getDate(), temp.Message); 102 | delete self._map[msg.getMessageId()]; 103 | } 104 | break; 105 | case "PubAckMessage": 106 | var item = self._map[msg.getMessageId()]; 107 | if (item) { 108 | //执行回调操作 109 | item.Callback.process(msg.getStatus() || 0, msg.getDate(), item.Message); 110 | delete self._map[msg.getMessageId()]; 111 | } 112 | break; 113 | case "PingRespMessage": 114 | self.context.pauseTimer(); 115 | break; 116 | case "DisconnectMessage": 117 | self.context.channel.disconnect(msg.getStatus()); 118 | break; 119 | default: 120 | } 121 | }; 122 | module.exports = MessageHandler; -------------------------------------------------------------------------------- /src/core/messageParser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyatao on 16/1/7. 3 | */ 4 | 5 | var com = require('../mapping'); 6 | var tool=require('../tool'); 7 | //消息转换方法 8 | function messageParser(entity) { 9 | var message, content = entity.content; 10 | var result, objectName = entity.classname; 11 | 12 | try { 13 | result = JSON.parse(RongBinaryHelper.readUTF(content.offset ? tool.arrayFrom(content.buffer).slice(content.offset, content.limit) : content)) 14 | } catch (ex) { 15 | return null; 16 | } 17 | 18 | //处理表情 19 | if ("Expression" in RongIMClient && "RC:TxtMsg" == objectName && result.content) { 20 | result.content = result.content.replace(/[\uf000-\uf700]/g, function (x) { 21 | return RongIMClient.Expression.calcUTF(x) || x; 22 | }) 23 | } 24 | 25 | //映射为具体消息对象 26 | if (objectName in com.typeMapping) { 27 | message = new RongIMClient[com.typeMapping[objectName]](result); 28 | } else if (objectName in com.sysNtf) { 29 | message = new RongIMClient[com.sysNtf[objectName]](result); 30 | } else if (objectName in com.registerMessageTypeMapping) { 31 | //自定义消息 32 | message = new RongIMClient[com.registerMessageTypeMapping[objectName]](result); 33 | } else { 34 | //未知消息 35 | message = new RongIMClient.UnknownMessage(result, objectName); 36 | } 37 | 38 | //根据实体对象设置message对象 39 | message.setSentTime(tool.int64ToTimestamp(entity.dataTime)); 40 | message.setSenderUserId(entity.fromUserId); 41 | message.setConversationType(RongIMClient.ConversationType.setValue(com.mapping[entity.type])); 42 | message.setTargetId(/^[234]$/.test(entity.type || entity.getType()) ? entity.groupId : message.getSenderUserId()); 43 | if (entity.fromUserId == com.userId) { 44 | message.setMessageDirection(RongIMClient.MessageDirection.SEND); 45 | } else { 46 | message.setMessageDirection(RongIMClient.MessageDirection.RECEIVE); 47 | } 48 | message.setReceivedTime((new Date).getTime()); 49 | message.setMessageId(message.getConversationType() + "_" + ~~(Math.random() * 0xffffff)); 50 | message.setReceivedStatus(new RongIMClient.ReceivedStatus()); 51 | return message; 52 | } 53 | module.exports = messageParser; -------------------------------------------------------------------------------- /src/enum.js: -------------------------------------------------------------------------------- 1 | function inherit(superCtor) { 2 | var f = function () { 3 | }; 4 | f.prototype = superCtor; 5 | return new f; 6 | } 7 | var Enum = function (namesToValues) { 8 | var enumeration = function () { 9 | throw "can't Instantiate Enumerations"; 10 | }; 11 | enumeration.setValue = function (x) { 12 | var val = null; 13 | enumeration.foreach(function (i) { 14 | if (i.value == x || i.name == x) { 15 | val = enumeration[i.name]; 16 | } 17 | }, null); 18 | return val; 19 | }; 20 | 21 | 22 | var proto = enumeration.prototype = { 23 | constructor: enumeration, 24 | toString: function () { 25 | return this.name; 26 | }, 27 | valueOf: function () { 28 | return this.value; 29 | }, 30 | toJSON: function () { 31 | return this.name; 32 | } 33 | }; 34 | enumeration.values = []; 35 | for (var _name in namesToValues) { 36 | var e = inherit(proto); 37 | e.name = _name; 38 | e.value = namesToValues[_name]; 39 | enumeration[_name] = e; 40 | enumeration.values.push(e); 41 | } 42 | enumeration.foreach = function (f, c) { 43 | for (var i = 0; i < this.values.length; i++) { 44 | f.call(c, this.values[i]); 45 | } 46 | }; 47 | return enumeration; 48 | }; 49 | module.exports = Enum; -------------------------------------------------------------------------------- /src/io/base.js: -------------------------------------------------------------------------------- 1 | var util = require('../tool'); 2 | var IOstream = require('../Message/throttleStream'); 3 | var mapping=require('../mapping'); 4 | var global = window; 5 | //获取消息id标识符对象,如果是comet消息通道就将messageid放入本地存储(localstorage或cookie)中。其他消息通道则放入内存中。 6 | 7 | var Transport = function (base, options) { 8 | this.base = base; 9 | this.options = { 10 | timeout: 30000 11 | }; 12 | util.merge(this.options, options) 13 | }; 14 | Transport.prototype.send = function () { 15 | throw new Error("No rewrite send() method") 16 | }; 17 | Transport.prototype.connect = function () { 18 | throw new Error("No rewrite connect() method") 19 | }; 20 | Transport.prototype.disconnect = function () { 21 | throw new Error("No rewrite disconnect() method") 22 | }; 23 | //此方法只有comet用到 24 | Transport.prototype._encode = function (x) { 25 | var str = "?messageid=" + x.getMessageId() + "&header=" + x.getHeaderFlag() + "&sessionid=" + util.cookieHelper.getItem(mapping.Endpoint.userId + "sId"); 26 | if (!/(PubAckMessage|QueryConMessage)/.test(x.constructor._name)) { 27 | str += "&topic=" + x.getTopic() + "&targetid=" + (x.getTargetId() || ""); 28 | } 29 | return { 30 | url: str, 31 | data: "getData" in x ? x.getData() : "" 32 | }; 33 | }; 34 | //转化服务器返回的二进制数组为一个具体的消息对象 35 | Transport.prototype._decode = function (data) { 36 | if (!data) { 37 | return; 38 | } 39 | if (util.isArray(data)) { 40 | this._onMessage(new IOstream.MessageInputStream(data).readMessage()); 41 | } else if (util.getType(data) === "ArrayBuffer") { 42 | this._onMessage(new IOstream.MessageInputStream(util.arrayFrom(data)).readMessage()); 43 | } 44 | }; 45 | //此方法只有comet用到。接收服务器返回的json对象 46 | Transport.prototype._onData = function (data, header) { 47 | if (!data || data == "lost params") { 48 | return; 49 | } 50 | if (header) { 51 | util.cookieHelper.getItem(mapping.Endpoint.userId + "sId") || util.cookieHelper.setItem(mapping.Endpoint.userId + "sId", header); 52 | } 53 | var self = this, val = util.JSON.parse(data); 54 | if (!util.isArray(val)) { 55 | val = [val]; 56 | } 57 | util.forEach(val, function (x) { 58 | self._onMessage(new IOstream.MessageInputStream(x, true).readMessage()); 59 | }); 60 | }; 61 | Transport.prototype._onMessage = function (message) { 62 | this.base._onMessage(message) 63 | }; 64 | Transport.prototype._onConnect = function () { 65 | this.connected = true; 66 | this.connecting = false; 67 | this.base._onConnect() 68 | }; 69 | Transport.prototype._onDisconnect = function () { 70 | this.connecting = false; 71 | this.connected = false; 72 | this.base._onDisconnect() 73 | }; 74 | Transport.prototype._baseConnect = function () { 75 | this.base.connect(null, null); 76 | }; 77 | 78 | module.exports = Transport; -------------------------------------------------------------------------------- /src/io/factory.js: -------------------------------------------------------------------------------- 1 | //var io = require('./base'); 2 | var util = require('../tool'); 3 | var WS = require('./websocket'); 4 | var XHR = require('./polling'); 5 | var _Transport = { 6 | 'websocket': WS, 7 | 'xhr-polling': XHR 8 | }; 9 | var Socket = function () { 10 | this.options = { 11 | token: "", 12 | transports: ["websocket", "xhr-polling"]//主要有两种(websocket,flashsocket)、comet 13 | }; 14 | this.connected = false; 15 | this.connecting = false; 16 | this._events = {}; 17 | this.currentURL = ""; 18 | this.transport = this.getTransport(util.getTransportType()); 19 | if (this.transport === null) { 20 | throw new Error("the channel was not supported") 21 | } 22 | }; 23 | //此方法用于生产通道对象 24 | Socket.prototype.getTransport = function (override) { 25 | var i = 0, 26 | transport = override || this.options.transports[i]; 27 | if (_Transport[transport] && _Transport[transport].check() && _Transport[transport].XDomainCheck()) { 28 | return new _Transport[transport](this, {}) 29 | } 30 | return null; 31 | }; 32 | //连接服务器 33 | Socket.prototype.connect = function (url, cb) { 34 | if (this.transport && arguments.length == 2) { 35 | if (url) { 36 | this.on("connect", cb || function () { 37 | }) 38 | } 39 | if (this.connecting || this.connected) { 40 | this.disconnect() 41 | } 42 | this.connecting = true; 43 | if (url) { 44 | this.currentURL = url 45 | } 46 | this.transport.connect(this.currentURL); //是否重连 47 | } 48 | return this 49 | }; 50 | Socket.prototype.send = function (data) { 51 | if (!this.transport || !this.connected) { 52 | //如果通道不可用,把消息压入队列中,等到通道可用时处理 53 | return this._queue(data) 54 | } 55 | this.transport.send(data) 56 | }; 57 | Socket.prototype.disconnect = function (callback) { 58 | if (callback) { 59 | //出发状态改变观察者 60 | this.fire("StatusChanged", callback) 61 | } 62 | this.transport.disconnect(); 63 | return this; 64 | }; 65 | Socket.prototype.reconnect = function () { 66 | if (this.currentURL) { 67 | return this.connect(null, null); 68 | } else { 69 | throw new Error("reconnect:no have URL"); 70 | } 71 | }; 72 | Socket.prototype.fire = function (x, args) { 73 | if (x in this._events) { 74 | for (var i = 0, ii = this._events[x].length; i < ii; i++) { 75 | this._events[x][i](args); 76 | } 77 | } 78 | return this 79 | }; 80 | Socket.prototype.removeEvent = function (x, fn) { 81 | if (x in this._events) { 82 | for (var a = 0, l = this._events[x].length; a < l; a++) { 83 | if (this._events[x][a] == fn) { 84 | this._events[x].splice(a, 1) 85 | } 86 | } 87 | } 88 | return this 89 | }; 90 | Socket.prototype._queue = function (message) { 91 | if (!("_queueStack" in this)) { 92 | this._queueStack = [] 93 | } 94 | this._queueStack.push(message); 95 | return this 96 | }; 97 | Socket.prototype._doQueue = function () { 98 | if (!("_queueStack" in this) || !this._queueStack.length) { 99 | return this 100 | } 101 | for (var i = 0; i < this._queueStack.length; i++) { 102 | this.transport.send(this._queueStack[i]) 103 | } 104 | this._queueStack = []; 105 | return this 106 | }; 107 | Socket.prototype._onConnect = function () { 108 | this.connected = true; 109 | this.connecting = false; 110 | util.cookieHelper.setItem("rongSDK",util.getTransportType()); 111 | this.fire("connect"); 112 | }; 113 | Socket.prototype._onMessage = function (data) { 114 | this.fire("message", data) 115 | }; 116 | Socket.prototype._onDisconnect = function () { 117 | var wasConnected = this.connected; 118 | this.connected = false; 119 | this.connecting = false; 120 | this._queueStack = []; 121 | if (wasConnected) { 122 | this.fire("disconnect") 123 | } 124 | }; 125 | //注册观察者 126 | Socket.prototype.on = function (x, func) { 127 | if (!(typeof func == "function" && x)) { 128 | return this 129 | } 130 | if (x in this._events) { 131 | util.indexOf(this._events, func) == -1 && this._events[x].push(func) 132 | } else { 133 | this._events[x] = [func]; 134 | } 135 | return this 136 | }; 137 | 138 | var connect = function (token, args) { 139 | var instance = new Socket(); 140 | connect.getInstance = function () { 141 | return instance 142 | }; 143 | instance.connect(token, args); 144 | return instance; 145 | }; 146 | 147 | module.exports = connect; -------------------------------------------------------------------------------- /src/io/polling.js: -------------------------------------------------------------------------------- 1 | var Transport = require('./base'); 2 | var util = require('../tool'); 3 | var mapping=require('../mapping'); 4 | var global = window; 5 | var empty = new Function; 6 | //利用withCredentials判断是否支持跨域操作 7 | var XMLHttpRequestCORS = (function () { 8 | if (!('XMLHttpRequest' in global)) 9 | return false; 10 | var a = new XMLHttpRequest(); 11 | return a.withCredentials !== undefined; 12 | })(); 13 | //生成跨域传输对象 14 | var request = function () { 15 | if ('XDomainRequest' in global) 16 | return new global["XDomainRequest"](); 17 | if ('XMLHttpRequest' in global && XMLHttpRequestCORS) 18 | return new XMLHttpRequest(); 19 | return false; 20 | }; 21 | var XHR = Transport.XHR = function () { 22 | Transport.apply(this, arguments); 23 | }; 24 | util.inherit(XHR, Transport); 25 | //comet链接服务器,先从本地存储对象里是否存有当前登陆人员的sessionid,如果有的话就不再从服务器申请sessionid,直接用本地存储的sessionid链接服务器。 26 | XHR.prototype.connect = function (url) { 27 | var sid = util.cookieHelper.getItem(mapping.Endpoint.userId + "sId"), 28 | _that = this; 29 | if (sid) { 30 | //io.getInstance().currentURL = url; 31 | setTimeout(function () { 32 | _that.onopen("{\"status\":0,\"userId\":\"" + mapping.Endpoint.userId + "\",\"headerCode\":32,\"messageId\":0,\"sessionid\":\"" + sid + "\"}"); 33 | _that._onConnect(); 34 | }, 500); 35 | return this; 36 | } 37 | this._get(url); 38 | return this; 39 | }; 40 | XHR.prototype._checkSend = function (data) { 41 | //格式化数据为comet指定的数据格式,然后发送 42 | var encoded = this._encode(data); 43 | this._send(encoded); 44 | }; 45 | XHR.prototype.send = function (data) { 46 | this._checkSend(data); 47 | return this; 48 | }; 49 | //利用post方法发送数据,有数据返回就执行_onData(responseText)方法 50 | XHR.prototype._send = function (data) { 51 | var self = this; 52 | this._sendXhr = this._request(mapping.Endpoint.host + "/websocket" + data.url, 'POST'); 53 | if ("onload" in this._sendXhr) { 54 | this._sendXhr.onload = function () { 55 | this.onload = empty; 56 | self._onData(this.responseText); 57 | }; 58 | this._sendXhr.onerror = function () { 59 | this.onerror = empty; 60 | }; 61 | } else { 62 | this._sendXhr.onreadystatechange = function () { 63 | if (this.readyState == 4) { 64 | this.onreadystatechange = empty; 65 | if (/^(202|200)$/.test(this.status)) { 66 | self._onData(this.responseText); 67 | } 68 | } 69 | }; 70 | } 71 | this._sendXhr.send(util.JSON.stringify(data.data)); 72 | }; 73 | XHR.prototype.disconnect = function () { 74 | this._onDisconnect(); 75 | return this; 76 | }; 77 | //断开连接,强制中止所有正在连接的http请求 78 | XHR.prototype._onDisconnect = function (isrecon) { 79 | if (this._xhr) { 80 | this._xhr.onreadystatechange = this._xhr.onload = empty; 81 | this._xhr.abort(); 82 | this._xhr = null; 83 | } 84 | if (this._sendXhr) { 85 | this._sendXhr.onreadystatechange = this._sendXhr.onload = empty; 86 | this._sendXhr.abort(); 87 | this._sendXhr = null; 88 | } 89 | if (isrecon === undefined) { 90 | Transport.prototype._onDisconnect.call(this); 91 | } 92 | }; 93 | //打开跨域请求对象 94 | XHR.prototype._request = function (url, method, multipart) { 95 | var req = request(); 96 | if (multipart) 97 | req.multipart = true; 98 | req.open(method || 'GET', "http://" + url); 99 | if (method == 'POST' && 'setRequestHeader' in req) { 100 | req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=utf-8'); 101 | } 102 | return req; 103 | }; 104 | XHR.check = function () { 105 | try { 106 | if (request()) 107 | return true; 108 | } catch (e) { 109 | } 110 | return false; 111 | }; 112 | XHR.XDomainCheck = function () { 113 | return XHR.check(); 114 | }; 115 | XHR.request = request; 116 | var XHRPolling = Transport['xhr-polling'] = function () { 117 | Transport.XHR.apply(this, arguments); 118 | }; 119 | util.inherit(XHRPolling, Transport.XHR); 120 | XHRPolling.prototype.type = 'xhr-polling'; 121 | //链接服务器,如果是ios和安卓就等10毫秒执行。 122 | XHRPolling.prototype.connect = function (x) { 123 | if (util.ios || util.android) { 124 | var self = this; 125 | util.load(function () { 126 | setTimeout(function () { 127 | Transport.XHR.prototype.connect.call(self, x); 128 | }, 10); 129 | }); 130 | } else { 131 | Transport.XHR.prototype.connect.call(this, x); 132 | } 133 | }; 134 | //发送pullmsg.js请求,这里是一个死循环调用。用于保持pullmsg.js请求 135 | XHRPolling.prototype.onopen = function (a, b) { 136 | this._onData(a, b); 137 | if (/"headerCode":-32,/.test(a)) { 138 | return; 139 | } 140 | this._get(mapping.Endpoint.host + "/pullmsg.js?sessionid=" + util.cookieHelper.getItem(mapping.Endpoint.userId + "sId"), true); 141 | }; 142 | //http状态码对应执行对象 143 | var status = { 144 | //arg参数有值说明是链接服务器请求,直接_onConnect方法 145 | 200: function (self, text, arg) { 146 | var txt = text.match(/"sessionid":"\S+?(?=")/); 147 | self.onopen(text, txt ? txt[0].slice(13) : void 0); 148 | arg || self._onConnect(); 149 | }, 150 | //http状态码为400,断开连接 151 | 400: function (self) { 152 | util.cookieHelper.removeItem(mapping.Endpoint.userId + "sId"); 153 | self._onDisconnect(true); 154 | self._baseConnect(); 155 | } 156 | }; 157 | //用于接收pullmsg.js请求中服务器返回的消息数据 158 | XHRPolling.prototype._get = function (symbol, arg) { 159 | var self = this; 160 | this._xhr = this._request(symbol, 'GET'); 161 | if ("onload" in this._xhr) { 162 | this._xhr.onload = function () { 163 | this.onload = empty; 164 | if (this.responseText == 'lost params') { 165 | status['400'](self); 166 | } else { 167 | status['200'](self, this.responseText, arg); 168 | } 169 | }; 170 | this._xhr.onerror = function () { 171 | self._onDisconnect(); 172 | } 173 | } else { 174 | this._xhr.onreadystatechange = function () { 175 | if (this.readyState == 4) { 176 | this.onreadystatechange = empty; 177 | if (/^(200|202)$/.test(this.status)) { 178 | status['200'](self, this.responseText, arg); 179 | } else if (/^(400|403)$/.test(this.status)) { 180 | status['400'](self); 181 | } else { 182 | self._onDisconnect(); 183 | } 184 | } 185 | }; 186 | } 187 | this._xhr.send(); 188 | }; 189 | XHRPolling.check = function () { 190 | return Transport.XHR.check(); 191 | }; 192 | XHRPolling.XDomainCheck = function () { 193 | return Transport.XHR.XDomainCheck(); 194 | }; 195 | module.exports = XHRPolling; -------------------------------------------------------------------------------- /src/io/websocket.js: -------------------------------------------------------------------------------- 1 | var Transport = require('./base'); 2 | var util = require('../tool'); 3 | var tinyStream = require('../binary'); 4 | var IOStream = require('../message/throttleStream'); 5 | var mapping = require('../mapping'); 6 | var WS = Transport.websocket = function () { 7 | Transport.apply(this, arguments) 8 | }; 9 | util.inherit(WS, Transport); 10 | WS.prototype.type = "websocket"; 11 | WS.prototype.connect = function (url) { 12 | var self = this; 13 | //操作html5 websocket API 14 | this.socket = new WebSocket("ws://" + url); 15 | this.socket.binaryType = "arraybuffer"; 16 | this.socket.onopen = function () { 17 | self._onConnect(); 18 | }; 19 | this.socket.onmessage = function (ev) { 20 | //判断数据是不是字符串,如果是字符串那么就是flash传过来的。 21 | if (typeof ev.data == "string") { 22 | self._decode(ev.data.split(",")) 23 | } else { 24 | self._decode(ev.data) 25 | } 26 | }; 27 | this.socket.onclose = function () { 28 | self._onClose() 29 | }; 30 | this.socket.onerror = function () { 31 | //当websocket执行出错的时候,判断是否已经注册了重连对象。有的话就执行重连对象的onError,没有的话主动抛出一个错误 32 | if (mapping.reconnectSet.onError) { 33 | mapping.reconnectSet.onError(RongIMClient.ConnectErrorStatus.setValue(2)); 34 | delete mapping.reconnectSet.onError; 35 | } else { 36 | throw new Error("network is unavailable or unknown error"); 37 | } 38 | }; 39 | return this 40 | }; 41 | //发送数据到服务器 42 | WS.prototype.send = function (data) { 43 | var stream = new tinyStream([]), 44 | msg = new IOStream.MessageOutputStream(stream); 45 | msg.writeMessage(data); 46 | var val = stream.getBytesArray(true); 47 | if (this.socket.readyState == 1) { 48 | if (util.getType(global.Int8Array) === 'Function' && !mapping.globalConf.WEB_SOCKET_FORCE_FLASH) { 49 | //Int8Array为html5 API 50 | var binary = new Int8Array(val); 51 | this.socket.send(binary.buffer) 52 | } else { 53 | this.socket.send(val + "") 54 | } 55 | } 56 | return this 57 | }; 58 | WS.prototype.disconnect = function () { 59 | if (this.socket) { 60 | this.socket.close() 61 | } 62 | return this 63 | }; 64 | WS.prototype._onClose = function () { 65 | this._onDisconnect(); 66 | return this 67 | }; 68 | WS.check = function () { 69 | return "WebSocket" in global && WebSocket.prototype && WebSocket.prototype.send && typeof WebSocket !== "undefined" 70 | }; 71 | WS.XDomainCheck = function () { 72 | return true; 73 | }; 74 | module.exports = WS; -------------------------------------------------------------------------------- /src/mapping.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyatao on 16/1/7. 3 | */ 4 | module.exports = { 5 | mapping: { 6 | "1": 4, 7 | "2": 2, 8 | "3": 3, 9 | "4": 0, 10 | "5": 1, 11 | "6": 5 12 | }, 13 | //objectname映射 14 | typeMapping: { 15 | "RC:TxtMsg": "TextMessage", 16 | "RC:ImgMsg": "ImageMessage", 17 | "RC:VcMsg": "VoiceMessage", 18 | "RC:ImgTextMsg": "RichContentMessage", 19 | "RC:LBSMsg": "LocationMessage" 20 | }, 21 | //通知类型映射 22 | sysNtf: { 23 | "RC:InfoNtf": "InformationNotificationMessage", 24 | "RC:ContactNtf": "ContactNotificationMessage", 25 | "RC:ProfileNtf": "ProfileNotificationMessage", 26 | "RC:CmdNtf": "CommandNotificationMessage", 27 | "RC:DizNtf": "DiscussionNotificationMessage" 28 | }, 29 | //消息监听器 30 | _ReceiveMessageListener: null, 31 | //连接状态监听器 32 | _ConnectionStatusListener: null, 33 | registerMessageTypeMapping: {}, 34 | userInfoMapping: {}, 35 | topic: ["invtDiz", "crDiz", "qnUrl", "userInf", "dizInf", "userInf", "joinGrp", "quitDiz", "exitGrp", "evctDiz", ["chatMsg", "pcMsgP", "pdMsgP", "pgMsgP", "ppMsgP"], "pdOpen", "rename", "uGcmpr", "qnTkn", 'destroyChrm', 'createChrm', 'exitChrm', 'queryChrm', 'joinChrm', "pGrps", "addBlack", "rmBlack", "getBlack", "blackStat", "addRelation", 'qryRelation', 'delRelation'], 36 | globalConf: { 37 | WEB_SOCKET_FORCE_FLASH: null, 38 | WEB_XHR_POLLING: null, 39 | FORCE_LOCAL_STORAGE: null 40 | }, 41 | Endpoint:{}, 42 | userId:'', 43 | reconnectSet:{ 44 | 45 | }, 46 | chatroomId:'' 47 | }; -------------------------------------------------------------------------------- /src/md5.js: -------------------------------------------------------------------------------- 1 | var MD5 = function (e) { 2 | function n(d) { 3 | for (var a = 0, b = ""; 3 >= a; a++)b += "0123456789abcdef".charAt(d >> 8 * a + 4 & 15) + "0123456789abcdef".charAt(d >> 8 * a & 15); 4 | return b 5 | } 6 | 7 | function m(a, b) { 8 | var d = (a & 65535) + (b & 65535); 9 | return (a >> 16) + (b >> 16) + (d >> 16) << 16 | d & 65535 10 | } 11 | 12 | function h(a, b, d, c, e, f) { 13 | a = m(m(b, a), m(c, f)); 14 | return m(a << e | a >>> 32 - e, d) 15 | } 16 | 17 | function g(a, b, d, c, e, f, g) { 18 | return h(b & d | ~b & c, a, b, e, f, g) 19 | } 20 | 21 | function k(a, b, d, c, e, f, g) { 22 | return h(b & c | d & ~c, a, b, e, f, g) 23 | } 24 | 25 | function l(a, b, d, c, e, f, g) { 26 | return h(d ^ (b | ~c), a, b, e, f, g) 27 | } 28 | 29 | e = function (a) { 30 | for (var b = 31 | (a.length + 8 >> 6) + 1, d = Array(16 * b), c = 0; c < 16 * b; c++)d[c] = 0; 32 | for (c = 0; c < a.length; c++)d[c >> 2] |= a.charCodeAt(c) << c % 4 * 8; 33 | d[c >> 2] |= 128 << c % 4 * 8; 34 | d[16 * b - 2] = 8 * a.length; 35 | return d 36 | }(e); 37 | for (var d = 1732584193, a = -271733879, b = -1732584194, c = 271733878, f = 0; f < e.length; f += 16)var p = d, q = a, r = b, t = c, d = g(d, a, b, c, e[f + 0], 7, -680876936), c = g(c, d, a, b, e[f + 1], 12, -389564586), b = g(b, c, d, a, e[f + 2], 17, 606105819), a = g(a, b, c, d, e[f + 3], 22, -1044525330), d = g(d, a, b, c, e[f + 4], 7, -176418897), c = g(c, d, a, b, e[f + 5], 12, 1200080426), b = g(b, c, d, a, e[f + 6], 17, -1473231341), 38 | a = g(a, b, c, d, e[f + 7], 22, -45705983), d = g(d, a, b, c, e[f + 8], 7, 1770035416), c = g(c, d, a, b, e[f + 9], 12, -1958414417), b = g(b, c, d, a, e[f + 10], 17, -42063), a = g(a, b, c, d, e[f + 11], 22, -1990404162), d = g(d, a, b, c, e[f + 12], 7, 1804603682), c = g(c, d, a, b, e[f + 13], 12, -40341101), b = g(b, c, d, a, e[f + 14], 17, -1502002290), a = g(a, b, c, d, e[f + 15], 22, 1236535329), d = k(d, a, b, c, e[f + 1], 5, -165796510), c = k(c, d, a, b, e[f + 6], 9, -1069501632), b = k(b, c, d, a, e[f + 11], 14, 643717713), a = k(a, b, c, d, e[f + 0], 20, -373897302), d = k(d, a, b, c, e[f + 5], 5, -701558691), c = k(c, d, a, b, e[f + 10], 9, 38016083), 39 | b = k(b, c, d, a, e[f + 15], 14, -660478335), a = k(a, b, c, d, e[f + 4], 20, -405537848), d = k(d, a, b, c, e[f + 9], 5, 568446438), c = k(c, d, a, b, e[f + 14], 9, -1019803690), b = k(b, c, d, a, e[f + 3], 14, -187363961), a = k(a, b, c, d, e[f + 8], 20, 1163531501), d = k(d, a, b, c, e[f + 13], 5, -1444681467), c = k(c, d, a, b, e[f + 2], 9, -51403784), b = k(b, c, d, a, e[f + 7], 14, 1735328473), a = k(a, b, c, d, e[f + 12], 20, -1926607734), d = h(a ^ b ^ c, d, a, e[f + 5], 4, -378558), c = h(d ^ a ^ b, c, d, e[f + 8], 11, -2022574463), b = h(c ^ d ^ a, b, c, e[f + 11], 16, 1839030562), a = h(b ^ c ^ d, a, b, e[f + 14], 23, -35309556), d = h(a ^ b ^ c, d, a, e[f + 40 | 1], 4, -1530992060), c = h(d ^ a ^ b, c, d, e[f + 4], 11, 1272893353), b = h(c ^ d ^ a, b, c, e[f + 7], 16, -155497632), a = h(b ^ c ^ d, a, b, e[f + 10], 23, -1094730640), d = h(a ^ b ^ c, d, a, e[f + 13], 4, 681279174), c = h(d ^ a ^ b, c, d, e[f + 0], 11, -358537222), b = h(c ^ d ^ a, b, c, e[f + 3], 16, -722521979), a = h(b ^ c ^ d, a, b, e[f + 6], 23, 76029189), d = h(a ^ b ^ c, d, a, e[f + 9], 4, -640364487), c = h(d ^ a ^ b, c, d, e[f + 12], 11, -421815835), b = h(c ^ d ^ a, b, c, e[f + 15], 16, 530742520), a = h(b ^ c ^ d, a, b, e[f + 2], 23, -995338651), d = l(d, a, b, c, e[f + 0], 6, -198630844), c = l(c, d, a, b, e[f + 7], 10, 1126891415), b = l(b, c, d, a, e[f + 14], 15, 41 | -1416354905), a = l(a, b, c, d, e[f + 5], 21, -57434055), d = l(d, a, b, c, e[f + 12], 6, 1700485571), c = l(c, d, a, b, e[f + 3], 10, -1894986606), b = l(b, c, d, a, e[f + 10], 15, -1051523), a = l(a, b, c, d, e[f + 1], 21, -2054922799), d = l(d, a, b, c, e[f + 8], 6, 1873313359), c = l(c, d, a, b, e[f + 15], 10, -30611744), b = l(b, c, d, a, e[f + 6], 15, -1560198380), a = l(a, b, c, d, e[f + 13], 21, 1309151649), d = l(d, a, b, c, e[f + 4], 6, -145523070), c = l(c, d, a, b, e[f + 11], 10, -1120210379), b = l(b, c, d, a, e[f + 2], 15, 718787259), a = l(a, b, c, d, e[f + 9], 21, -343485551), d = m(d, p), a = m(a, q), b = m(b, r), c = m(c, t); 42 | return n(d) + 43 | n(a) + n(b) + n(c) 44 | }; 45 | module.exports = MD5; -------------------------------------------------------------------------------- /src/message/Message.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 消息类,对java逻辑的重新实现 3 | * */ 4 | var e = require('./msgEnum'); 5 | var TinyStream = require('../binary'); 6 | var Qos = e.Qos; 7 | var Type = e.Type; 8 | function Message(argu) { 9 | var _header, _headerCode, lengthSize = 0; 10 | if (argu instanceof Header) { 11 | _header = argu 12 | } else { 13 | _header = new Header(argu, false, Qos.AT_MOST_ONCE, false) 14 | } 15 | this.write = function (Out) { 16 | var out = TinyStream.parse(Out); 17 | _headerCode = this.getHeaderFlag(); 18 | out.write(_headerCode); 19 | this.writeMessage(out); 20 | return out 21 | }; 22 | this.getHeaderFlag = function () { 23 | return _header.encode(); 24 | }; 25 | this.getLengthSize = function () { 26 | return lengthSize 27 | }; 28 | this.setRetained = function (retain) { 29 | _header.retain = retain 30 | }; 31 | this.isRetained = function () { 32 | return _header.retain 33 | }; 34 | this.setQos = function (qos) { 35 | _header.qos = qos instanceof Qos ? qos : Qos.setValue(qos); 36 | }; 37 | this.getQos = function () { 38 | return _header.qos 39 | }; 40 | this.setDup = function (dup) { 41 | _header.dup = dup 42 | }; 43 | this.isDup = function () { 44 | return _header.dup 45 | }; 46 | this.getType = function () { 47 | return _header.type 48 | }; 49 | } 50 | Message._name = "Message"; 51 | Message.prototype = { 52 | read: function (In, length) { 53 | this.readMessage(In, length) 54 | }, 55 | toBytes: function () { 56 | return this.write([]).getBytesArray() 57 | }, messageLength: function () { 58 | return 0 59 | }, writeMessage: function (out) { 60 | }, readMessage: function (In) { 61 | }, init: function (args) { 62 | var valName, nana; 63 | for (nana in args) { 64 | if (!args.hasOwnProperty(nana)) 65 | continue; 66 | valName = nana.replace(/^\w/, function (x) { 67 | var tt = x.charCodeAt(0); 68 | return 'set' + (tt >= 0x61 ? String.fromCharCode(tt & ~32) : x) 69 | }); 70 | if (valName in this) { 71 | this[valName](args[nana]) 72 | } 73 | } 74 | } 75 | }; 76 | function Header(_type, _retain, _qos, _dup) { 77 | this.type = null; 78 | this.retain = false; 79 | this.qos = Qos.AT_LEAST_ONCE; 80 | this.dup = false; 81 | if (_type && +_type == _type && arguments.length == 1) { 82 | this.retain = (_type & 1) > 0; 83 | this.qos = Qos.setValue((_type & 6) >> 1); 84 | this.dup = (_type & 8) > 0; 85 | this.type = Type.setValue((_type >> 4) & 15); 86 | } else { 87 | this.type = Type.setValue(_type); 88 | this.retain = _retain; 89 | this.qos = Qos.setValue(_qos); 90 | this.dup = _dup; 91 | } 92 | } 93 | Header.prototype = { 94 | getType: function () { 95 | return this.type 96 | }, encode: function () { 97 | var _byte = (this.type << 4); 98 | _byte |= this.retain ? 1 : 0; 99 | _byte |= this.qos << 1; 100 | _byte |= this.dup ? 8 : 0; 101 | return _byte 102 | }, toString: function () { 103 | return "Header [type=" + this.type + ",retain=" + this.retain + ",qos=" + this.qos + ",dup=" + this.dup + "]" 104 | } 105 | }; 106 | module.exports = { 107 | Message: Message, 108 | Header: Header 109 | }; -------------------------------------------------------------------------------- /src/message/MessageEntity.js: -------------------------------------------------------------------------------- 1 | var msg = require('./Message'); 2 | var TinyStream = require('../binary'); 3 | var e = require('./msgEnum'); 4 | var util = require('../tool'); 5 | var Message = msg.Message; 6 | var Header = msg.Header; 7 | var Type = e.Type; 8 | var ConnectionState = e.ConnectionState; 9 | var DisconnectionStatus = e.DisconnectionStatus; 10 | function ConnectMessage() { 11 | var CONNECT_HEADER_SIZE = 12, 12 | protocolId = "RCloud", 13 | protocolVersion = 3, 14 | clientId, keepAlive, appId, token, cleanSession, willTopic, will, willQos, retainWill, hasAppId, hasToken, hasWill; 15 | switch (arguments.length) { 16 | case 0: 17 | Message.call(this, Type.CONNECT); 18 | break; 19 | case 1: 20 | Message.call(this, arguments[0]); 21 | break; 22 | case 3: 23 | Message.call(this, Type.CONNECT); 24 | if (!arguments[0] || arguments[0].length > 64) { 25 | throw new Error("ConnectMessage:Client Id cannot be null and must be at most 64 characters long: " + arguments[0]) 26 | } 27 | clientId = arguments[0]; 28 | cleanSession = arguments[1]; 29 | keepAlive = arguments[2]; 30 | break 31 | } 32 | this.messageLength = function () { 33 | var payloadSize = TinyStream.toMQTString(clientId).length; 34 | payloadSize += TinyStream.toMQTString(willTopic).length; 35 | payloadSize += TinyStream.toMQTString(will).length; 36 | payloadSize += TinyStream.toMQTString(appId).length; 37 | payloadSize += TinyStream.toMQTString(token).length; 38 | return payloadSize + CONNECT_HEADER_SIZE 39 | }; 40 | this.readMessage = function (In) { 41 | var stream = TinyStream.parse(In); 42 | protocolId = stream.readUTF(); 43 | protocolVersion = stream.readByte(); 44 | var cFlags = stream.readByte(); 45 | hasAppId = (cFlags & 128) > 0; 46 | hasToken = (cFlags & 64) > 0; 47 | retainWill = (cFlags & 32) > 0; 48 | willQos = cFlags >> 3 & 3; 49 | hasWill = (cFlags & 4) > 0; 50 | cleanSession = (cFlags & 32) > 0; 51 | keepAlive = stream.read() * 256 + stream.read(); 52 | clientId = stream.readUTF(); 53 | if (hasWill) { 54 | willTopic = stream.readUTF(); 55 | will = stream.readUTF() 56 | } 57 | if (hasAppId) { 58 | try { 59 | appId = stream.readUTF() 60 | } catch (ex) { 61 | } 62 | } 63 | if (hasToken) { 64 | try { 65 | token = stream.readUTF() 66 | } catch (ex) { 67 | } 68 | } 69 | return stream 70 | }; 71 | this.writeMessage = function (out) { 72 | var stream = TinyStream.parse(out); 73 | stream.writeUTF(protocolId); 74 | stream.write(protocolVersion); 75 | var flags = cleanSession ? 2 : 0; 76 | flags |= hasWill ? 4 : 0; 77 | flags |= willQos ? willQos >> 3 : 0; 78 | flags |= retainWill ? 32 : 0; 79 | flags |= hasToken ? 64 : 0; 80 | flags |= hasAppId ? 128 : 0; 81 | stream.write(flags); 82 | stream.writeChar(keepAlive); 83 | stream.writeUTF(clientId); 84 | if (hasWill) { 85 | stream.writeUTF(willTopic); 86 | stream.writeUTF(will) 87 | } 88 | if (hasAppId) { 89 | stream.writeUTF(appId) 90 | } 91 | if (hasToken) { 92 | stream.writeUTF(token) 93 | } 94 | return stream 95 | }; 96 | } 97 | ConnectMessage._name = "ConnectMessage"; 98 | util.inherit(ConnectMessage, Message, true); 99 | function ConnAckMessage() { 100 | var status, userId, MESSAGE_LENGTH = 2; 101 | switch (arguments.length) { 102 | case 0: 103 | Message.call(this, Type.CONNACK); 104 | break; 105 | case 1: 106 | if (arguments[0] instanceof Header) { 107 | Message.call(this, arguments[0]) 108 | } else { 109 | if (arguments[0] instanceof ConnectionState) { 110 | Message.call(this, Type.CONNACK); 111 | if (arguments[0] == null) { 112 | throw new Error("ConnAckMessage:The status of ConnAskMessage can't be null") 113 | } 114 | status = arguments[0] 115 | } 116 | } 117 | } 118 | this.messageLength = function () { 119 | var length = MESSAGE_LENGTH; 120 | if (userId) { 121 | length += TinyStream.toMQTString(userId).length 122 | } 123 | return length 124 | }; 125 | this.readMessage = function (In, msglength) { 126 | var stream = TinyStream.parse(In); 127 | stream.read(); 128 | var result = +stream.read(); 129 | if (result >= 0 && result <= 9) { 130 | this.setStatus(result); 131 | } else { 132 | throw new Error("Unsupported CONNACK code:" + result) 133 | } 134 | if (msglength > MESSAGE_LENGTH) { 135 | this.setUserId(stream.readUTF()) 136 | } 137 | }; 138 | this.writeMessage = function (out) { 139 | var stream = TinyStream.parse(out); 140 | stream.write(128); 141 | switch (+status) { 142 | case 0: 143 | case 1: 144 | case 2: 145 | case 5: 146 | case 6: 147 | stream.write(+status); 148 | break; 149 | case 3: 150 | case 4: 151 | stream.write(3); 152 | break; 153 | default: 154 | throw new Error("Unsupported CONNACK code:" + status); 155 | } 156 | if (userId) { 157 | stream.writeUTF(userId) 158 | } 159 | return stream 160 | }; 161 | this.getStatus = function () { 162 | return status 163 | }; 164 | this.setStatus = function (x) { 165 | status = x instanceof ConnectionState ? x : ConnectionState.setValue(x); 166 | }; 167 | this.setUserId = function (_userId) { 168 | userId = _userId 169 | }; 170 | this.getUserId = function () { 171 | return userId 172 | }; 173 | } 174 | ConnAckMessage._name = "ConnAckMessage"; 175 | util.inherit(ConnAckMessage, Message, true); 176 | function DisconnectMessage(one) { 177 | var status; 178 | this.MESSAGE_LENGTH = 2; 179 | if (one instanceof Header) { 180 | Message.call(this, one) 181 | } else { 182 | Message.call(this, Type.DISCONNECT); 183 | if (one instanceof DisconnectionStatus) { 184 | status = one 185 | } 186 | } 187 | this.messageLength = function () { 188 | return this.MESSAGE_LENGTH 189 | }; 190 | this.readMessage = function (In) { 191 | var _in = TinyStream.parse(In); 192 | _in.read(); 193 | var result = +_in.read(); 194 | if (result >= 0 && result <= 5) { 195 | this.setStatus(result); 196 | } else { 197 | throw new Error("Unsupported CONNACK code:" + result) 198 | } 199 | }; 200 | this.writeMessage = function (Out) { 201 | var out = TinyStream.parse(Out); 202 | out.write(0); 203 | if (+status >= 1 && +status <= 3) { 204 | out.write((+status) - 1); 205 | } else { 206 | throw new Error("Unsupported CONNACK code:" + status) 207 | } 208 | }; 209 | this.setStatus = function (x) { 210 | status = x instanceof DisconnectionStatus ? x : DisconnectionStatus.setValue(x); 211 | }; 212 | this.getStatus = function () { 213 | return status 214 | }; 215 | } 216 | DisconnectMessage._name = "DisconnectMessage"; 217 | util.inherit(DisconnectMessage, Message, true); 218 | function PingReqMessage(header) { 219 | if (header && header instanceof Header) { 220 | Message.call(this, header) 221 | } else { 222 | Message.call(this, Type.PINGREQ) 223 | } 224 | } 225 | PingReqMessage._name = "PingReqMessage"; 226 | util.inherit(PingReqMessage, Message, true); 227 | function PingRespMessage(header) { 228 | if (header && header instanceof Header) { 229 | Message.call(this, header) 230 | } else { 231 | Message.call(this, Type.PINGRESP) 232 | } 233 | } 234 | PingRespMessage._name = "PingRespMessage"; 235 | util.inherit(PingRespMessage, Message, true); 236 | function RetryableMessage(argu) { 237 | var messageId; 238 | Message.call(this, argu); 239 | this.messageLength = function () { 240 | return 2 241 | }; 242 | this.writeMessage = function (Out) { 243 | var out = TinyStream.parse(Out), 244 | Id = this.getMessageId(), 245 | lsb = Id & 255, 246 | msb = (Id & 65280) >> 8; 247 | out.write(msb); 248 | out.write(lsb); 249 | return out 250 | }; 251 | this.readMessage = function (In) { 252 | var _in = TinyStream.parse(In), 253 | msgId = _in.read() * 256 + _in.read(); 254 | this.setMessageId(parseInt(msgId, 10)); 255 | }; 256 | this.setMessageId = function (_messageId) { 257 | messageId = _messageId 258 | }; 259 | this.getMessageId = function () { 260 | return messageId 261 | } 262 | } 263 | RetryableMessage._name = "RetryableMessage"; 264 | util.inherit(RetryableMessage, Message, true); 265 | function PubAckMessage(args) { 266 | var status, msgLen = 2, 267 | date = 0; 268 | if (args instanceof Header) { 269 | RetryableMessage.call(this, args) 270 | } else { 271 | RetryableMessage.call(this, Type.PUBACK); 272 | this.setMessageId(args) 273 | } 274 | this.messageLength = function () { 275 | return msgLen 276 | }; 277 | this.writeMessage = function (Out) { 278 | var out = TinyStream.parse(Out); 279 | PubAckMessage.prototype.writeMessage.call(this, out) 280 | }; 281 | this.readMessage = function (In) { 282 | var _in = TinyStream.parse(In); 283 | PubAckMessage.prototype.readMessage.call(this, _in); 284 | date = _in.readInt(); 285 | status = _in.read() * 256 + _in.read() 286 | }; 287 | this.setStatus = function (x) { 288 | status = x; 289 | }; 290 | this.getStatus = function () { 291 | return status 292 | }; 293 | this.getDate = function () { 294 | return date 295 | }; 296 | } 297 | PubAckMessage._name = "PubAckMessage"; 298 | util.inherit(PubAckMessage, RetryableMessage, true); 299 | function PublishMessage(one, two, three) { 300 | var topic, data, targetId, date; 301 | if (arguments.length == 1 && one instanceof Header) { 302 | RetryableMessage.call(this, one) 303 | } else { 304 | if (arguments.length == 3) { 305 | RetryableMessage.call(this, Type.PUBLISH); 306 | topic = one; 307 | targetId = three; 308 | data = typeof two == "string" ? TinyStream.toMQTString(two) : two; 309 | } 310 | } 311 | this.messageLength = function () { 312 | var length = 10; 313 | length += TinyStream.toMQTString(topic).length; 314 | length += TinyStream.toMQTString(targetId).length; 315 | length += data.length; 316 | return length 317 | }; 318 | this.writeMessage = function (Out) { 319 | var out = TinyStream.parse(Out); 320 | out.writeUTF(topic); 321 | out.writeUTF(targetId); 322 | PublishMessage.prototype.writeMessage.apply(this, arguments); 323 | out.write(data) 324 | }; 325 | this.readMessage = function (In, msgLength) { 326 | var pos = 6, 327 | _in = TinyStream.parse(In); 328 | date = _in.readInt(); 329 | topic = _in.readUTF(); 330 | pos += TinyStream.toMQTString(topic).length; 331 | PublishMessage.prototype.readMessage.apply(this, arguments); 332 | data = new Array(msgLength - pos); 333 | _in.read(data) 334 | }; 335 | this.setTopic = function (x) { 336 | topic = x; 337 | }; 338 | this.setData = function (x) { 339 | data = x; 340 | }; 341 | this.setTargetId = function (x) { 342 | targetId = x; 343 | }; 344 | this.setDate = function (x) { 345 | date = x; 346 | }; 347 | this.setData = function (x) { 348 | data = x; 349 | }; 350 | this.getTopic = function () { 351 | return topic 352 | }; 353 | this.getData = function () { 354 | return data 355 | }; 356 | this.getTargetId = function () { 357 | return targetId 358 | }; 359 | this.getDate = function () { 360 | return date 361 | } 362 | } 363 | PublishMessage._name = "PublishMessage"; 364 | util.inherit(PublishMessage, RetryableMessage, true); 365 | function QueryMessage(one, two, three) { 366 | var topic, data, targetId; 367 | if (one instanceof Header) { 368 | RetryableMessage.call(this, one) 369 | } else { 370 | if (arguments.length == 3) { 371 | RetryableMessage.call(this, Type.QUERY); 372 | data = typeof two == "string" ? TinyStream.toMQTString(two) : two; 373 | topic = one; 374 | targetId = three; 375 | } 376 | } 377 | this.messageLength = function () { 378 | var length = 0; 379 | length += TinyStream.toMQTString(topic).length; 380 | length += TinyStream.toMQTString(targetId).length; 381 | length += 2; 382 | length += data.length; 383 | return length 384 | }; 385 | this.writeMessage = function (Out) { 386 | var out = TinyStream.parse(Out); 387 | out.writeUTF(topic); 388 | out.writeUTF(targetId); 389 | this.constructor.prototype.writeMessage.call(this, out); 390 | out.write(data) 391 | }; 392 | this.readMessage = function (In, msgLength) { 393 | var pos = 0, 394 | _in = TinyStream.parse(In); 395 | topic = _in.readUTF(); 396 | targetId = _in.readUTF(); 397 | pos += TinyStream.toMQTString(topic).length; 398 | pos += TinyStream.toMQTString(targetId).length; 399 | this.constructor.prototype.readMessage.apply(this, arguments); 400 | pos += 2; 401 | data = new Array(msgLength - pos); 402 | _in.read(data) 403 | }; 404 | this.setTopic = function (x) { 405 | topic = x; 406 | }; 407 | this.setData = function (x) { 408 | data = x; 409 | }; 410 | this.setTargetId = function (x) { 411 | targetId = x; 412 | }; 413 | this.getTopic = function () { 414 | return topic 415 | }; 416 | this.getData = function () { 417 | return data 418 | }; 419 | this.getTargetId = function () { 420 | return targetId 421 | }; 422 | } 423 | QueryMessage._name = "QueryMessage"; 424 | util.inherit(QueryMessage, RetryableMessage, true); 425 | function QueryConMessage(messageId) { 426 | if (messageId instanceof Header) { 427 | RetryableMessage.call(this, messageId) 428 | } else { 429 | RetryableMessage.call(this, Type.QUERYCON); 430 | this.setMessageId(messageId) 431 | } 432 | } 433 | QueryConMessage._name = "QueryConMessage"; 434 | util.inherit(QueryConMessage, RetryableMessage, true); 435 | function QueryAckMessage(header) { 436 | var data, status, date; 437 | RetryableMessage.call(this, header); 438 | this.readMessage = function (In, msgLength) { 439 | var _in = TinyStream.parse(In); 440 | QueryAckMessage.prototype.readMessage.call(this, _in); 441 | date = _in.readInt(); 442 | status = _in.read() * 256 + _in.read(); 443 | if (msgLength > 0) { 444 | data = new Array(msgLength - 8); 445 | _in.read(data) 446 | } 447 | }; 448 | this.getStatus = function () { 449 | return status 450 | }; 451 | this.getDate = function () { 452 | return date 453 | }; 454 | this.setDate = function (x) { 455 | date = x; 456 | }; 457 | this.setStatus = function (x) { 458 | status = x; 459 | }; 460 | this.setData = function (x) { 461 | data = x; 462 | }; 463 | this.getData = function () { 464 | return data 465 | }; 466 | } 467 | QueryAckMessage._name = "QueryAckMessage"; 468 | util.inherit(QueryAckMessage, RetryableMessage, true); 469 | module.exports = { 470 | ConnectMessage: ConnectMessage, 471 | ConnAckMessage: ConnAckMessage, 472 | DisconnectMessage: DisconnectMessage, 473 | PingReqMessage: PingReqMessage, 474 | PingRespMessage: PingRespMessage, 475 | RetryableMessage: RetryableMessage, 476 | PubAckMessage: PubAckMessage, 477 | PublishMessage: PublishMessage, 478 | QueryMessage: QueryMessage, 479 | QueryConMessage: QueryConMessage, 480 | QueryAckMessage: QueryAckMessage 481 | }; 482 | 483 | -------------------------------------------------------------------------------- /src/message/msgEnum.js: -------------------------------------------------------------------------------- 1 | var myEnum = require('../enum'); 2 | var Qos = myEnum({AT_MOST_ONCE: 0, AT_LEAST_ONCE: 1, EXACTLY_ONCE: 2, DEFAULT: 3}), 3 | Type = myEnum({ 4 | CONNECT: 1, 5 | CONNACK: 2, 6 | PUBLISH: 3, 7 | PUBACK: 4, 8 | QUERY: 5, 9 | QUERYACK: 6, 10 | QUERYCON: 7, 11 | SUBSCRIBE: 8, 12 | SUBACK: 9, 13 | UNSUBSCRIBE: 10, 14 | UNSUBACK: 11, 15 | PINGREQ: 12, 16 | PINGRESP: 13, 17 | DISCONNECT: 14 18 | }), 19 | DisconnectionStatus = myEnum({ 20 | RECONNECT: 0, 21 | OTHER_DEVICE_LOGIN: 1, 22 | CLOSURE: 2, 23 | UNKNOWN_ERROR: 3, 24 | LOGOUT: 4, 25 | BLOCK: 5 26 | }), 27 | ConnectionState = myEnum({ 28 | ACCEPTED: 0, 29 | UNACCEPTABLE_PROTOCOL_VERSION: 1, 30 | IDENTIFIER_REJECTED: 2, 31 | SERVER_UNAVAILABLE: 3, 32 | TOKEN_INCORRECT: 4, 33 | NOT_AUTHORIZED: 5, 34 | REDIRECT: 6, 35 | PACKAGE_ERROR: 7, 36 | APP_BLOCK_OR_DELETE: 8, 37 | BLOCK: 9, 38 | TOKEN_EXPIRE: 10, 39 | DEVICE_ERROR: 11 40 | }); 41 | module.exports = { 42 | Qos: Qos, 43 | Type: Type, 44 | DisconnectionStatus: DisconnectionStatus, 45 | ConnectionState: ConnectionState 46 | }; 47 | -------------------------------------------------------------------------------- /src/message/throttleStream.js: -------------------------------------------------------------------------------- 1 | var TinyStream = require('../binary'); 2 | var Message = require('./Message'); 3 | var eneity = require('./MessageEntity'); 4 | 5 | function output(_out) { 6 | var out = TinyStream.parse(_out); 7 | this.writeMessage = function (msg) { 8 | if (msg instanceof Message.Message) { 9 | msg.write(out) 10 | } 11 | } 12 | } 13 | //converted input stream to message object ,that was server send to client,把服务器返回的二进制流生成具体的消息对象 14 | function input(In, isPolling) { 15 | var flags, header, msg = null; 16 | if (!isPolling) { 17 | var _in = TinyStream.parse(In); 18 | flags = _in.readByte(); 19 | } else { 20 | flags = In["headerCode"]; 21 | } 22 | header = new Message.Header(flags); 23 | this.readMessage = function () { 24 | switch (+header.getType()) { 25 | case 2: 26 | msg = new eneity.ConnAckMessage(header); 27 | break; 28 | case 3: 29 | msg = new eneity.PublishMessage(header); 30 | break; 31 | case 4: 32 | msg = new eneity.PubAckMessage(header); 33 | break; 34 | case 5: 35 | msg = new eneity.QueryMessage(header); 36 | break; 37 | case 6: 38 | msg = new eneity.QueryAckMessage(header); 39 | break; 40 | case 7: 41 | msg = new eneity.QueryConMessage(header); 42 | break; 43 | case 9: 44 | case 11: 45 | case 13: 46 | msg = new eneity.PingRespMessage(header); 47 | break; 48 | case 1: 49 | msg = new eneity.ConnectMessage(header); 50 | break; 51 | case 8: 52 | case 10: 53 | case 12: 54 | msg = new eneity.PingReqMessage(header); 55 | break; 56 | case 14: 57 | msg = new eneity.DisconnectMessage(header); 58 | break; 59 | default: 60 | throw new Error("No support for deserializing " + header.getType() + " messages") 61 | } 62 | if (isPolling) { 63 | msg.init(In); 64 | } else { 65 | msg.read(_in, In.length - 1); 66 | } 67 | return msg 68 | } 69 | } 70 | module.exports = { 71 | MessageOutputStream: output, 72 | MessageInputStream: input 73 | }; -------------------------------------------------------------------------------- /src/ready.js: -------------------------------------------------------------------------------- 1 | var global = window; 2 | var tool = require('./tool'); 3 | var mappding = require('./mapping'); 4 | var config = { 5 | canFlashWidget: (function () { 6 | if ('navigator' in global && 'plugins' in navigator && navigator.plugins['Shockwave Flash']) { 7 | return !!navigator.plugins['Shockwave Flash'].description; 8 | } 9 | if ('ActiveXObject' in global) { 10 | try { 11 | return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); 12 | } catch (e) { 13 | } 14 | } 15 | return false; 16 | })(), 17 | supportedWebSocket: function () { 18 | return "WebSocket" in global && "ArrayBuffer" in global && WebSocket.prototype.CLOSED === 3 && !mappding.globalConf.WEB_SOCKET_FORCE_FLASH && !mappding.globalConf.WEB_XHR_POLLING; 19 | }, 20 | supportedFlash: function () { 21 | return !/opera/i.test(navigator.userAgent) && !mappding.globalConf.WEB_XHR_POLLING && this.canFlashWidget 22 | } 23 | }; 24 | // 程序入口 25 | tool.ready(function () { 26 | var src = ''; 27 | //此属性为通道标识。根据这个标识生产通道对象,默认为websocket 28 | tool.setTransportType('websocket'); 29 | //当前浏览器是否支持webSocket,并且window.WEB_SOCKET_FORCE_FLASH 和 !window.WEB_XHR_POLLING都是false 30 | if (config.supportedWebSocket()) { 31 | //加载protobuf 32 | src = "http://res.websdk.rongcloud.cn/protobuf-0.2.min.js"; 33 | //是否支持flash widget 34 | } else if (config.supportedFlash()) { 35 | //加载flash widget帮助库 36 | src = "http://res.websdk.rongcloud.cn/swfobject-0.2.min.js"; 37 | } else { 38 | //如果上述条件都不支持则执行comet逻辑 39 | tool.setTransportType('xhr-polling'); 40 | //加载comet帮助库 41 | src = "http://res.websdk.rongcloud.cn/xhrpolling-0.2.min.js"; 42 | } 43 | tool.loadScript(src); 44 | }); -------------------------------------------------------------------------------- /src/tool.js: -------------------------------------------------------------------------------- 1 | var mapping = require('./mapping'); 2 | var doc = document; 3 | var global = window; 4 | var transportType = ''; 5 | var tool = { 6 | //注册页面加载事件 7 | load: function (fn) { 8 | if (doc.readyState == "complete" || this._pageLoaded) { 9 | return fn() 10 | } 11 | if (global.attachEvent) { 12 | global.attachEvent("onload", fn) 13 | } else { 14 | global.addEventListener("load", fn, false) 15 | } 16 | }, 17 | //继承 18 | inherit: function (ctor, superCtor,isClassExt) { 19 | var f = function () { 20 | }; 21 | if(isClassExt){ 22 | f.prototype = new superCtor; 23 | }else{ 24 | f.prototype = superCtor.prototype; 25 | } 26 | ctor.super_ = superCtor; 27 | ctor.prototype = new f(); 28 | ctor.prototype.constructor = ctor; 29 | }, 30 | //查找数组中位于指定下标的元素 31 | indexOf: function (arr, item, from) { 32 | for (var l = arr.length, i = (from < 0) ? Math.max(0, +from) : from || 0; i < l; i++) { 33 | if (arr[i] == item) { 34 | return i 35 | } 36 | } 37 | return -1 38 | }, 39 | //判断是否为数组 40 | isArray: function (obj) { 41 | return Object.prototype.toString.call(obj) == "[object Array]"; 42 | }, 43 | //遍历,只能遍历数组 44 | forEach: (function () { 45 | if ([].forEach) { 46 | return function (arr, func) { 47 | [].forEach.call(arr, func) 48 | } 49 | } else { 50 | return function (arr, func) { 51 | for (var i = 0; i < arr.length; i++) { 52 | func.call(arr, arr[i], i, arr) 53 | } 54 | } 55 | } 56 | })(), 57 | //遍历,可遍历对象也可遍历数组 58 | each: function (obj, callback) { 59 | if (this.isArray(obj)) { 60 | this.forEach(x, callback); 61 | } else { 62 | for (var _name in obj) { 63 | if (obj.hasOwnProperty(_name)) { 64 | callback.call(obj, _name, obj[_name]); 65 | } 66 | } 67 | } 68 | }, 69 | //合并 70 | merge: function (target, additional) { 71 | for (var i in additional) { 72 | if (additional.hasOwnProperty(i)) { 73 | target[i] = additional[i] 74 | } 75 | } 76 | }, 77 | //把类数组转换为数组 78 | arrayFrom: function (typedarray) { 79 | if (Object.prototype.toString.call(typedarray) == "[object ArrayBuffer]") { 80 | var arr = new Int8Array(typedarray); 81 | return [].slice.call(arr) 82 | } 83 | return typedarray; 84 | }, 85 | //删除数组指定项 86 | remove: function (array, func) { 87 | for (var i = 0; i < array.length; i++) { 88 | if (func(array[i])) { 89 | return array.splice(i, 1)[0] 90 | } 91 | } 92 | return null 93 | }, 94 | //把int64的时间对象转为时间戳 95 | int64ToTimestamp: function (obj, isDate) { 96 | if (obj.low === undefined) { 97 | return obj; 98 | } 99 | var low = obj.low; 100 | if (low < 0) { 101 | low += 0xffffffff + 1; 102 | } 103 | low = low.toString(16); 104 | var timestamp = parseInt(obj.high.toString(16) + "00000000".replace(new RegExp('0{' + low.length + '}$'), low), 16); 105 | if (isDate) { 106 | return new Date(timestamp) 107 | } 108 | return timestamp; 109 | }, 110 | getType: function (obj) { 111 | return Object.prototype.toString.call(obj).slice(8, -1); 112 | }, 113 | ready: function (callback) { 114 | if (doc.readyState == "interactive" || doc.readyState == "complete") { 115 | callback(); 116 | } else if (doc.addEventListener) { 117 | doc.addEventListener("DOMContentLoaded", function () { 118 | doc.removeEventListener("DOMContentLoaded", arguments.callee, false); 119 | callback(); 120 | }, false) 121 | } else if (doc.attachEvent) { 122 | doc.attachEvent("onreadystatechange", function () { 123 | if (doc.readyState === "interactive" || doc.readyState === "complete") { 124 | doc.detachEvent("onreadystatechange", arguments.callee); 125 | callback() 126 | } 127 | }) 128 | } 129 | }, 130 | loadScript: function (src, callback) { 131 | var script = doc.createElement("script"); 132 | var body = doc.body || doc.getElementsByTagName("body")[0]; 133 | script.src = src; 134 | body.appendChild(script); 135 | if ('onload' in script) { 136 | script.onload = function () { 137 | callback && callback(); 138 | } 139 | } else { 140 | script.onreadystatechange = function () { 141 | if (script.readyState === 'complete') { 142 | callback && callback(); 143 | } 144 | } 145 | } 146 | }, 147 | jsonp: function (src, jsonpCallback, callback, onFail) { 148 | var cbName = 'cb' + jsonpCount++; 149 | var cbAck = 'window.RongIMClient.jsonpPool.' + cbName; 150 | if (global.RongIMClient.jsonpPool === void 0) { 151 | global.RongIMClient.jsonpPool = {}; 152 | } 153 | global.RongIMClient.jsonpPool[cbName] = function (data) { 154 | try { 155 | callback(data); 156 | } finally { 157 | delete global.RongIMClient.jsonpPool[cbName]; 158 | script.parentNode.removeChild(script); 159 | } 160 | }; 161 | var script = doc.createElement('script'); 162 | script.src = src + '&' + jsonpCallback + '=' + cbAck; 163 | script.onerror = function () { 164 | onFail(); 165 | }; 166 | doc.body.appendChild(script); 167 | }, 168 | getTransportType: function () { 169 | return transportType; 170 | }, 171 | setTransportType: function (t) { 172 | transportType = t; 173 | }, 174 | //是否为ios 175 | ios: /iphone|ipad/i.test(navigator.userAgent), 176 | //是否为安卓 177 | android: /android/i.test(navigator.userAgent), 178 | _pageLoaded: false 179 | }; 180 | var jsonpCount = 1; 181 | //此方法判断是否设置FORCE_LOCAL_STORAGE为true,如果是true则在localstorage中存储。否则在cookie中存储。 182 | tool.cookieHelper = (function () { 183 | var obj, old; 184 | if (mapping.globalConf.FORCE_LOCAL_STORAGE === true) { 185 | old = localStorage.setItem; 186 | localStorage.setItem = function (x, value) { 187 | if (localStorage.length == 15) { 188 | localStorage.removeItem(localStorage.key(0)); 189 | } 190 | old.call(localStorage, x, value); 191 | }; 192 | obj = localStorage; 193 | } else { 194 | obj = { 195 | getItem: function (x) { 196 | var arr = doc.cookie.match(new RegExp("(^| )" + x + "=([^;]*)(;|$)")); 197 | if (arr != null) { 198 | return (arr[2]); 199 | } 200 | return null; 201 | }, 202 | setItem: function (x, value) { 203 | var exp = new Date(); 204 | exp.setTime(exp.getTime() + 15 * 24 * 3600 * 1000); 205 | doc.cookie = x + "=" + escape(value) + ";path=/;expires=" + exp.toGMTString(); 206 | }, 207 | removeItem: function (x) { 208 | if (this.getItem(x)) { 209 | doc.cookie = x + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT"; 210 | } 211 | }, 212 | clear: function () { 213 | var keys = doc.cookie.match(/[^ =;]+(?=\=)/g); 214 | if (keys) { 215 | for (var i = keys.length; i--;) 216 | doc.cookie = keys[i] + '=0;path=/;expires=' + new Date(0).toUTCString(); 217 | } 218 | } 219 | } 220 | } 221 | return obj; 222 | })(); 223 | tool.load(function () { 224 | tool._pageLoaded = true; 225 | if (!global.JSON) { 226 | tool.JSON = { 227 | parse: function (sJSON) { 228 | return eval('(' + sJSON + ')'); 229 | }, 230 | stringify: (function () { 231 | var toString = Object.prototype.toString; 232 | var isArray = Array.isArray || function (a) { 233 | return toString.call(a) === '[object Array]'; 234 | }; 235 | var escMap = { 236 | '"': '\\"', 237 | '\\': '\\\\', 238 | '\b': '\\b', 239 | '\f': '\\f', 240 | '\n': '\\n', 241 | '\r': '\\r', 242 | '\t': '\\t' 243 | }; 244 | var escFunc = function (m) { 245 | return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); 246 | }; 247 | var escRE = new RegExp('[\\"' + unescape("%00-%1F%u2028%u2029") + ']', 'g'); 248 | return function stringify(value) { 249 | if (value == null) { 250 | return 'null'; 251 | } else if (typeof value === 'number') { 252 | return isFinite(value) ? value.toString() : 'null'; 253 | } else if (typeof value === 'boolean') { 254 | return value.toString(); 255 | } else if (typeof value === 'object') { 256 | if (typeof value.toJSON === 'function') { 257 | return stringify(value.toJSON()); 258 | } else if (isArray(value)) { 259 | var res = '['; 260 | for (var i = 0; i < value.length; i++) 261 | res += (i ? ', ' : '') + stringify(value[i]); 262 | return res + ']'; 263 | } else if (toString.call(value) === '[object Object]') { 264 | var tmp = []; 265 | for (var k in value) { 266 | if (value.hasOwnProperty(k)) 267 | tmp.push(stringify(k) + ': ' + stringify(value[k])); 268 | } 269 | return '{' + tmp.join(', ') + '}'; 270 | } 271 | } 272 | return '"' + value.toString().replace(escRE, escFunc) + '"'; 273 | }; 274 | })() 275 | }; 276 | } else { 277 | tool.JSON = global.JSON; 278 | } 279 | tool.messageIdHandler = (function () { 280 | var messageId = 0, 281 | isXHR = tool.getTransportType() === "xhr-polling", 282 | init = function () { 283 | messageId = +(tool.cookieHelper.getItem("msgId") || tool.cookieHelper.setItem("msgId", 0) || 0); 284 | }; 285 | isXHR && init(); 286 | return { 287 | //messageid 加一并返回 288 | messageIdPlus: function (method) { 289 | isXHR && init(); 290 | if (messageId >= 0xffff) { 291 | method(); 292 | return false; 293 | } 294 | messageId++; 295 | isXHR && tool.cookieHelper.setItem("msgId", messageId); 296 | return messageId; 297 | }, 298 | //清空messageid 299 | clearMessageId: function () { 300 | messageId = 0; 301 | isXHR && tool.cookieHelper.setItem("msgId", messageId); 302 | }, 303 | //返回当前messageid 304 | getMessageId: function () { 305 | isXHR && init(); 306 | return messageId; 307 | } 308 | } 309 | })() 310 | }); 311 | module.exports = tool; -------------------------------------------------------------------------------- /test/Junit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yataozhang on 15/4/8. 3 | * 单元测试 4 | */ 5 | (function (rong) { 6 | //promise模块 7 | var _promise = function (affair) { 8 | this.state = "waiting"; 9 | this.affair = affair || function (o) { 10 | return o 11 | }; 12 | this.handles = []; 13 | }; 14 | _promise.prototype.then = function (nextaffair) { 15 | var p = new _promise(); 16 | if (this.state != "waiting") { 17 | this._fire(p, nextaffair); 18 | } else { 19 | this._push(p, nextaffair); 20 | } 21 | return p; 22 | }; 23 | _promise.prototype.delay = function (time) { 24 | return this.then(function (data) { 25 | var p = new _promise(); 26 | setTimeout(function () { 27 | p.resolve(data); 28 | }, time); 29 | return p; 30 | }); 31 | }; 32 | _promise.prototype.resolve = function (obj) { 33 | if (this.state != "waiting") { 34 | throw new Error("all done"); 35 | } 36 | this.state = "done"; 37 | this.result = this.affair(obj); 38 | for (var i = 0; i < this.handles.length; i++) { 39 | var tmp = this.handles[i]; 40 | this._fire(tmp.nextPromise, tmp.nextAffair); 41 | } 42 | return this; 43 | }; 44 | _promise.prototype._push = function (nextPromise, nextAffair) { 45 | this.handles.push({ 46 | nextPromise: nextPromise, 47 | nextAffair: nextAffair 48 | }); 49 | }; 50 | _promise.prototype._fire = function (nextPromise, nextAffair) { 51 | if (this.result == false) { 52 | console.warn("终止操作"); 53 | return; 54 | } 55 | 56 | var nextVal = nextAffair(this.result); 57 | if (nextVal instanceof _promise) { 58 | nextVal.then(function (obj) { 59 | nextPromise.resolve(obj); 60 | }) 61 | } else { 62 | nextPromise.resolve(nextVal); 63 | } 64 | }; 65 | 66 | 67 | var log = function (x) { 68 | console.log(x); 69 | } , error = function (x) { 70 | console.error("fail", x); 71 | return false; 72 | } , info = function (x) { 73 | console.info("done"); 74 | if (x) { 75 | console.info(x); 76 | } 77 | return true; 78 | }; 79 | var Junit = window.Junit = {}, instance, _default = { 80 | ConversationType: RongIMClient.ConversationType.setValue(4), 81 | targetId: "2189", 82 | content: "开始测试了", 83 | discussId: "ee23c0d6-4d38-4aaf-97a7-8155f0b93518", 84 | chatroomId: "tr002", 85 | groupId: "group001" 86 | }; 87 | Junit.init = function () { 88 | instance = rong.getInstance(); 89 | }; 90 | Junit.config = function (obj) { 91 | for (var s in obj) { 92 | _default[s] = obj[s]; 93 | } 94 | }; 95 | Junit.baseFuncTest = function () { 96 | var pro = new _promise(function (data) { 97 | log(data); 98 | log("保存草稿,输入内容为:123456789"); 99 | instance.saveTextMessageDraft(_default.ConversationType, _default.targetId, "123456789") 100 | return info(); 101 | }); 102 | pro.then(function () { 103 | log("得到草稿,预期值为123456789"); 104 | if (instance.getTextMessageDraft(_default.ConversationType, _default.targetId) == "123456789") { 105 | return info(); 106 | } else { 107 | return error("getTextMessageDraft"); 108 | } 109 | }).then(function () { 110 | log("删除草稿,预期值为null"); 111 | instance.clearTextMessageDraft(_default.ConversationType, _default.targetId); 112 | if (instance.getTextMessageDraft(_default.ConversationType, _default.targetId)) { 113 | return error("clearTextMessageDraft"); 114 | } else { 115 | return info(); 116 | } 117 | }).then(function () { 118 | log("得到会话列表"); 119 | log(instance.getConversationList()); 120 | return true; 121 | }) 122 | // .then(function () { 123 | // log("同步会话列表"); 124 | // instance.getConversationList().length = 0; 125 | // instance.syncConversationList(); 126 | // }).delay(5000) 127 | .then(function () { 128 | // if (instance.getConversationList().length == 0 && instance.getIO()._TransportType != "xhr-polling") { 129 | // return error("syncConversationList"); 130 | // } 131 | log("创建会话列表"); 132 | if (instance.createConversation(_default.ConversationType, _default.targetId, "test")) { 133 | return info(); 134 | } else { 135 | return error("createConversation"); 136 | } 137 | }).then(function () { 138 | log("得到会话列表"); 139 | if (instance.getConversation(_default.ConversationType, _default.targetId)) { 140 | return info(); 141 | } else { 142 | return error("getConversation"); 143 | } 144 | }).then(function () { 145 | log("得到会话通知类型"); 146 | instance.getConversationNotificationStatus(_default.ConversationType, _default.targetId, { 147 | onSuccess: function (x) { 148 | log(x) 149 | }, onError: function (x) { 150 | error(x); 151 | error("getConversationNotificationStatus") 152 | } 153 | }); 154 | return true; 155 | }).then(function () { 156 | log("清除某类型会话"); 157 | instance.clearConversations([_default.ConversationType]); 158 | if (instance.getConversation(_default.ConversationType, _default.targetId) == null) { 159 | return info(); 160 | } else { 161 | return error("clearConversations"); 162 | } 163 | }).then(function () { 164 | log("得到群类型会话列表"); 165 | instance.createConversation(RongIMClient.ConversationType.GROUP, _default.groupId, "群一"); 166 | if (instance.getGroupConversationList().length != 0) { 167 | return info(); 168 | } else { 169 | return error("getGroupConversationList"); 170 | } 171 | }).then(function () { 172 | log("删除指定会话"); 173 | instance.removeConversation(RongIMClient.ConversationType.GROUP, _default.groupId); 174 | if (instance.getConversation(RongIMClient.ConversationType.GROUP, _default.groupId)) { 175 | return error("removeConversation") 176 | } else { 177 | return info(); 178 | } 179 | }).then(function () { 180 | log("设置会话通知类型"); 181 | instance.createConversation(_default.ConversationType, _default.targetId, "test"); 182 | instance.setConversationNotificationStatus(_default.ConversationType, _default.targetId, RongIMClient.ConversationNotificationStatus.NOTIFY, { 183 | onSuccess: function (x) { 184 | console.info(x); 185 | }, onError: function (x) { 186 | error(x) 187 | } 188 | }); 189 | return true; 190 | }).then(function () { 191 | log("会话置顶"); 192 | instance.createConversation(RongIMClient.ConversationType.GROUP, _default.groupId, "群一"); 193 | instance.setConversationToTop(_default.ConversationType, _default.targetId); 194 | var val = instance.getConversationList()[0]; 195 | if (val.getTargetId() == _default.targetId && val.getConversationType() == _default.ConversationType) { 196 | return info(); 197 | } else { 198 | return error("setConversationToTop"); 199 | } 200 | }).then(function () { 201 | log("设置会话名称"); 202 | instance.setConversationName(_default.ConversationType, _default.targetId, "修改名称"); 203 | if (instance.getConversation(_default.ConversationType, _default.targetId).getConversationTitle() == "修改名称") { 204 | return info(); 205 | } else { 206 | return error("setConversationName"); 207 | } 208 | }).then(function () { 209 | log("得到登陆人员信息"); 210 | instance.getCurrentUserInfo({ 211 | onSuccess: function (x) { 212 | info(x); 213 | }, onError: function (x) { 214 | error(x); 215 | error("getCurrentUserInfo"); 216 | } 217 | }); 218 | return true; 219 | }).then(function () { 220 | log("发送消息"); 221 | instance.sendMessage(_default.ConversationType, _default.targetId, RongIMClient.TextMessage.obtain(_default.content), new RongIMClient.MessageHandler(function () { 222 | console.log("发送消息中") 223 | }), { 224 | onSuccess: function () { 225 | info("发送消息成功") 226 | }, onError: function (x) { 227 | error(x); 228 | error("sendMessage") 229 | } 230 | }); 231 | return true; 232 | }).then(function () { 233 | log("得到所有未读消息数量"); 234 | info("未读消息数量:", instance.getTotalUnreadCount()); 235 | return true; 236 | }).then(function () { 237 | log("得到指定会话未读消息数量"); 238 | info("指定会话未读消息数量:", instance.getUnreadCount(_default.ConversationType, _default.targetId)); 239 | return true; 240 | }).then(function () { 241 | log("清空未读消息数量"); 242 | if (instance.clearMessagesUnreadStatus(_default.ConversationType, _default.targetId)) { 243 | return info("~~~~~基础功能测试完成~~~~~~\n以下开始高级功能测试"); 244 | } else { 245 | return error("clearMessagesUnreadStatus"); 246 | } 247 | }).then(function () { 248 | log("加入聊天室"); 249 | instance.joinChatRoom(_default.chatroomId, 10, { 250 | onSuccess: function () { 251 | info() 252 | }, onError: function (x) { 253 | error(x); 254 | error("joinChatRoom"); 255 | } 256 | }); 257 | return true; 258 | }).delay(2000).then(function () { 259 | log("退出聊天室"); 260 | instance.quitChatRoom(_default.chatroomId, { 261 | onSuccess: function () { 262 | info(); 263 | }, onError: function (x) { 264 | error(x); 265 | error("quitChatRoom"); 266 | } 267 | }); 268 | return true; 269 | }).delay(2000).then(function () { 270 | log("发送通知类型消息"); 271 | instance.sendNotification(RongIMClient.ConversationType.PRIVATE, _default.targetId, RongIMClient.InformationNotificationMessage.obtain(_default.content), { 272 | onSuccess: function () { 273 | info() 274 | }, onError: function (x) { 275 | error(x); 276 | error("sendNotification") 277 | } 278 | }); 279 | return true; 280 | }).then(function () { 281 | log("发送状态类型消息"); 282 | return true; 283 | }).delay(2000).then(function () { 284 | log("创建讨论组"); 285 | instance.createDiscussion("单元测试", ["2180"], { 286 | onSuccess: function (id) { 287 | _default.discussId = id; 288 | info(); 289 | }, onError: function (x) { 290 | error(x); 291 | error("createDiscussion") 292 | } 293 | }); 294 | return true; 295 | }).delay(2000).then(function () { 296 | log("得到指定讨论组信息"); 297 | instance.getDiscussion(_default.discussId, { 298 | onSuccess: function (x) { 299 | console.warn("讨论组Id", x.getId()); 300 | console.warn("讨论组名称", x.getName()); 301 | console.warn("讨论组邀请状态", x.isOpen()); 302 | console.warn("讨论组人员", x.getMemberIdList()); 303 | console.warn("讨论组管理员", x.getCreatorId()); 304 | info() 305 | }, onError: function (x) { 306 | error(x); 307 | error("getDiscussion") 308 | } 309 | }); 310 | return true; 311 | }).delay(2000).then(function () { 312 | log("设置讨论组名称"); 313 | instance.setDiscussionName(_default.discussId, "修改讨论组名称——", { 314 | onSuccess: function () { 315 | info() 316 | }, onError: function (x) { 317 | error(x); 318 | error("setDiscussionName") 319 | } 320 | }); 321 | return true; 322 | }).delay(2000).then(function () { 323 | log("设置讨论组邀请状态"); 324 | instance.setDiscussionInviteStatus(_default.discussId, RongIMClient.DiscussionInviteStatus.OPENED, { 325 | onSuccess: function () { 326 | info() 327 | }, onError: function (x) { 328 | error(x); 329 | error("setDiscussionInviteStatus") 330 | } 331 | }); 332 | return true; 333 | }).delay(2000).then(function () { 334 | 335 | log("指定人员加入讨论组")//2315 336 | instance.addMemberToDiscussion(_default.discussId, ["2315"], { 337 | onSuccess: function () { 338 | info() 339 | }, onError: function (x) { 340 | error(x); 341 | error("addMemberToDiscussion") 342 | } 343 | }); 344 | return true; 345 | }).delay(2000).then(function () { 346 | log("将指定人员移出讨论组"); 347 | instance.removeMemberFromDiscussion(_default.discussId, "2315", { 348 | onSuccess: function () { 349 | info() 350 | }, onError: function (x) { 351 | error(x); 352 | error("removeMemberFromDiscussion") 353 | } 354 | }); 355 | return true; 356 | }).delay(2000).then(function () { 357 | log("退出讨论组"); 358 | instance.quitDiscussion(_default.discussId, { 359 | onSuccess: function () { 360 | info(); 361 | }, onError: function (x) { 362 | error(x); 363 | error("quitDiscussion") 364 | } 365 | }); 366 | return true; 367 | }).delay(2000).then(function () { 368 | //flash bug 369 | log("加入群"); 370 | instance.joinGroup(_default.groupId, "群组一", { 371 | onSuccess: function () { 372 | info(); 373 | }, onError: function (x) { 374 | error(x); 375 | error("joinGroup") 376 | } 377 | }); 378 | return true; 379 | }).delay(2000).then(function () { 380 | log("退出群"); 381 | instance.quitGroup(_default.groupId, { 382 | onSuccess: function () { 383 | info(); 384 | }, onError: function (x) { 385 | error(x); 386 | error("quitGroup") 387 | } 388 | }); 389 | return true; 390 | }).delay(2000).then(function () { 391 | log("同步群"); 392 | var group1 = new RongIMClient.Group(); 393 | group1.setId("group001"); 394 | group1.setName("群组一"); 395 | var group2 = new RongIMClient.Group(); 396 | group2.setId("group002"); 397 | group2.setName("群组二"); 398 | var group3 = new RongIMClient.Group(); 399 | group3.setId("group003"); 400 | group3.setName("群组三"); 401 | instance.syncGroup([group1, group3, group2, group2, group3], { 402 | onSuccess: function () { 403 | info(); 404 | }, onError: function (x) { 405 | error(x); 406 | error("syncGroup") 407 | } 408 | }); 409 | return true; 410 | }).delay(2000).then(function () { 411 | log("得到黑名单信息"); 412 | instance.getBlacklist({ 413 | onSuccess: function (x) { 414 | info(x); 415 | }, onError: function (x) { 416 | error(x); 417 | error("getBlacklistStatus") 418 | } 419 | }); 420 | return true; 421 | }).delay(2000).then(function () { 422 | log("将指定人员加入到黑名单"); 423 | instance.addToBlacklist("2315", { 424 | onSuccess: function () { 425 | info(); 426 | }, onError: function (x) { 427 | error(x); 428 | error("addToBlacklist") 429 | } 430 | }); 431 | return true; 432 | }).delay(2000).then(function () { 433 | log("得到指定人员在黑名单中的状态"); 434 | instance.getBlacklistStatus("2315", { 435 | onSuccess: function (x) { 436 | info(x); 437 | }, onError: function (x) { 438 | error(x); 439 | error("getBlacklistStatus") 440 | } 441 | }); 442 | return true; 443 | }).delay(2000).then(function () { 444 | log("将指定人员移出黑名单"); 445 | instance.removeFromBlacklist("2315", { 446 | onSuccess: function () { 447 | instance.getBlacklist({ 448 | onSuccess: function (x) { 449 | x.indexOf("2315") == -1 ? info(x) : error("removeFromBlacklist"); 450 | }, onError: function (x) { 451 | } 452 | }) 453 | }, onError: function (x) { 454 | error(x); 455 | error("removeFromBlacklist") 456 | } 457 | }); 458 | return true; 459 | }).then(function () { 460 | log("得到未读消息状态"); 461 | RongIMClient.hasUnreadMessages(RongBrIdge._client.appId, RongBrIdge._client.token, { 462 | onSuccess: function (x) { 463 | info(x); 464 | }, onError: function (x) { 465 | error(x); 466 | error("hasUnreadMessages") 467 | } 468 | }); 469 | return true; 470 | }).delay(2000).then(function () { 471 | log("注册自定义消息"); 472 | RongIMClient.registerMessageType({messageType: "_MessageType", "objectName": "RC:selfMsg", "fieldName": ["name", "id", "age"]}); 473 | 474 | if (RongIMClient._MessageType) { 475 | var val = new RongIMClient._MessageType(); 476 | if (val.getObjectName() == "RC:selfMsg" && val.setname && val.setid && val.setage) { 477 | info(); 478 | return true; 479 | } 480 | } 481 | error("registerMessageType"); 482 | return false; 483 | }).then(function () { 484 | log("断开链接测试"); 485 | instance.disconnect(); 486 | return true; 487 | }).delay(5000).then(function () { 488 | if (instance.getIO().getInstance().connected != false) { 489 | return error("disconnect"); 490 | } 491 | log("重连"); 492 | instance.reconnect({ 493 | onSuccess: function () { 494 | 495 | }, onError: function () { 496 | 497 | } 498 | }); 499 | return true; 500 | }).delay(10000).then(function () { 501 | console.log("~~~~~~~~~~~~测试完毕~~~~~~~~~~"); 502 | if (instance.getIO().getInstance().connected != true) { 503 | return error("reconnect"); 504 | } 505 | }); 506 | pro.resolve("~~~~~~~~~~~~start~~~~~~~~~~~"); 507 | }; 508 | 509 | 510 | })(); 511 | -------------------------------------------------------------------------------- /web_SDK_文件结构说明.txt: -------------------------------------------------------------------------------- 1 | web SDk 2 | |--------------------------------- 3 | |嵌入式客服| 4 | | [modules/Embedded.js] 5 | |--------------------------------- 6 | |帮助模块| 7 | | [modules/emoji-0.9.2.js] 8 | | [modules/indexedDB.js] 9 | | [modules/loadImage.js] 10 | | [modules/voice-0.9.1.js] 11 | |--------------------------------- 12 | |消息格式化| 13 | | [external/protobuf.js] 14 | | [external/swfobject.js] 15 | | [external/xhrpolling.js] 16 | |--------------------------------- 17 | |SDK 源文件| 18 | | [ dist/RongIMClient.js] 19 | |--------------------------------- 20 | |flash 源文件| 21 | | [external/WebSocketMain.zip] 22 | |---------------------------------- 23 | |测试用例| 24 | | [test/Junit.js] 25 | | [test/SDk_invoker.html] 26 | |---------------------------------- 27 | |sdk代码分块| 28 | | [src] 29 | |---------------------------------- 30 | 31 | 联系人:张亚涛 32 | email:xiaodezhang@foxmail.com 33 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | module.exports = { 3 | devtool: '#cheap-source-map', 4 | entry: "./src/IMClient/entry.js", 5 | output: { 6 | path: path.join(__dirname, '/dest'), 7 | filename: 'RongIMClient.js', 8 | sourceMapFilename: '[file].map', 9 | libraryTarget: 'umd', 10 | library: 'RongIMClient', 11 | pathinfo: true 12 | }, 13 | resolve: { 14 | extensions: ['', '.js', '.json', '.coffee'], 15 | root: [process.cwd() + '/src', process.cwd() + '/node_modules'] //本文件中的require从哪里找 16 | } 17 | }; --------------------------------------------------------------------------------