├── app.js
├── app.json
├── app.wxss
├── config.js
├── pages
├── chat
│ ├── chat.js
│ ├── chat.json
│ ├── chat.wxml
│ ├── chat.wxss
│ └── images
│ │ ├── avator.png
│ │ └── say.jpg
└── index
│ ├── index.js
│ ├── index.wxml
│ ├── index.wxss
│ └── user-unlogin.png
├── project.config.json
├── utils
├── util.js
└── websocket.js
└── vendor
└── wafer2-client-sdk
├── index.js
├── lib
├── constants.js
├── login.js
├── request.js
├── session.js
├── tunnel.js
├── utils.js
└── wxTunnel.js
└── package.json
/app.js:
--------------------------------------------------------------------------------
1 | //app.js
2 | App({
3 | onLaunch: function () {
4 | // 展示本地存储能力
5 | var logs = wx.getStorageSync('logs') || []
6 | logs.unshift(Date.now())
7 | wx.setStorageSync('logs', logs)
8 |
9 | // 登录
10 | wx.login({
11 | success: res => {
12 | wx.showToast({
13 | title: '已登陆',
14 | icon: "none",
15 | duration: 2000
16 | })
17 | if (res.code) {
18 | //发起网络请求
19 | // wx.request({
20 | // url: 'https://rylvdab1.qcloud.la',
21 | // data: {
22 | // code: res.code
23 | // },
24 | // success:function(res){
25 | // console.log(res.data)
26 | // }
27 | // })
28 | } else {
29 | console.log('获取用户登录态失败!' + res.errMsg)
30 | }
31 | // 发送 res.code 到后台换取 openId, sessionKey, unionId
32 | }
33 | })
34 | // 获取用户信息
35 | wx.getSetting({
36 | success: res => {
37 | if (res.authSetting['scope.userInfo']) {
38 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
39 | wx.getUserInfo({
40 | success: res => {
41 | // 可以将 res 发送给后台解码出 unionId
42 | // console.log(res)
43 | this.globalData.userInfo = res.userInfo
44 |
45 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
46 | // 所以此处加入 callback 以防止这种情况
47 | if (this.userInfoReadyCallback) {
48 | this.userInfoReadyCallback(res)
49 | }
50 | }
51 | })
52 | }
53 | }
54 | })
55 | },
56 | globalData: {
57 | userInfo: null
58 | }
59 | })
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages":[
3 | "pages/index/index",
4 | "pages/chat/chat"
5 | ],
6 | "window":{
7 | "backgroundTextStyle":"black",
8 | "navigationBarBackgroundColor": "#eee",
9 | "navigationBarTitleText": "首页",
10 | "navigationBarTextStyle":"black",
11 | "navigationStyle":"default"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: space-between;
8 | padding: 200rpx 0;
9 | box-sizing: border-box;
10 | }
11 |
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 小程序配置文件
3 | */
4 |
5 | // 此处主机域名修改成腾讯云解决方案分配的域名
6 | var host = 'https://rylvdab1.qcloud.la';
7 |
8 | var config = {
9 |
10 | // 下面的地址配合云端 Demo 工作
11 | service: {
12 | host,
13 |
14 | // 登录地址,用于建立会话
15 | loginUrl: `${host}/weapp/login`,
16 |
17 | // 测试的请求地址,用于测试会话
18 | requestUrl: `${host}/weapp/user`,
19 |
20 | // 测试的信道服务地址
21 | tunnelUrl: `${host}/weapp/tunnel`,
22 |
23 | // 上传图片接口
24 | uploadUrl: `${host}/weapp/upload`
25 | }
26 | };
27 |
28 | module.exports = config;
29 |
--------------------------------------------------------------------------------
/pages/chat/chat.js:
--------------------------------------------------------------------------------
1 | // pages/chat/chat.js
2 | const app = getApp()
3 | var websocket = require('../../utils/websocket.js');
4 | var utils = require('../../utils/util.js');
5 | Page({
6 |
7 | /**
8 | * 页面的初始数据
9 | */
10 | data: {
11 | newslist:[],
12 | userInfo: {},
13 | scrollTop: 0,
14 | increase:false,//图片添加区域隐藏
15 | aniStyle: true,//动画效果
16 | message:"",
17 | previewImgList:[]
18 | },
19 | /**
20 | * 生命周期函数--监听页面加载
21 | */
22 | onLoad: function () {
23 | var that = this
24 | if (app.globalData.userInfo) {
25 | this.setData({
26 | userInfo: app.globalData.userInfo
27 | })
28 | }
29 | //调通接口
30 | websocket.connect(this.data.userInfo, function (res) {
31 | // console.log(JSON.parse(res.data))
32 | var list = []
33 | list = that.data.newslist
34 | list.push(JSON.parse(res.data))
35 | that.setData({
36 | newslist: list
37 | })
38 | })
39 | },
40 | // 页面卸载
41 | onUnload(){
42 | wx.closeSocket();
43 | wx.showToast({
44 | title: '连接已断开~',
45 | icon: "none",
46 | duration: 2000
47 | })
48 | },
49 | //事件处理函数
50 | send: function () {
51 | var flag = this
52 | if (this.data.message.trim() == ""){
53 | wx.showToast({
54 | title: '消息不能为空哦~',
55 | icon: "none",
56 | duration: 2000
57 | })
58 | }else {
59 | setTimeout(function(){
60 | flag.setData({
61 | increase: false
62 | })
63 | },500)
64 | websocket.send('{ "content": "' + this.data.message + '", "date": "' + utils.formatTime(new Date()) + '","type":"text", "nickName": "' + this.data.userInfo.nickName + '", "avatarUrl": "' + this.data.userInfo.avatarUrl+'" }')
65 | this.bottom()
66 | }
67 | },
68 | //监听input值的改变
69 | bindChange(res) {
70 | this.setData({
71 | message : res.detail.value
72 | })
73 | },
74 | cleanInput(){
75 | //button会自动清空,所以不能再次清空而是应该给他设置目前的input值
76 | this.setData({
77 | message: this.data.message
78 | })
79 | },
80 | increase() {
81 | this.setData({
82 | increase: true,
83 | aniStyle: true
84 | })
85 | },
86 | //点击空白隐藏message下选框
87 | outbtn(){
88 | this.setData({
89 | increase: false,
90 | aniStyle: true
91 | })
92 | },
93 | chooseImage() {
94 | var that = this
95 | wx.chooseImage({
96 | count: 1, // 默认9
97 | sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
98 | sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
99 | success: function (res) {
100 | // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
101 | var tempFilePaths = res.tempFilePaths
102 | // console.log(tempFilePaths)
103 | wx.uploadFile({
104 | url: 'http://192.168.137.91/index/index/upload', //仅为示例,非真实的接口地址
105 | filePath: tempFilePaths[0],
106 | name: 'file',
107 | headers: {
108 | 'Content-Type': 'form-data'
109 | },
110 | success: function (res) {
111 | if (res.data){
112 | that.setData({
113 | increase: false
114 | })
115 | websocket.send('{"images":"'+ res.data +'","date":"'+utils.formatTime(new Date())+'","type":"image","nickName":"'+that.data.userInfo.nickName+'","avatarUrl":"'+that.data.userInfo.avatarUrl+'"}')
116 | that.bottom()
117 | }
118 | }
119 | })
120 |
121 | }
122 | })
123 | },
124 | //图片预览
125 | previewImg(e){
126 | var that = this
127 | //必须给对应的wxml的image标签设置data-set=“图片路径”,否则接收不到
128 | var res = e.target.dataset.src
129 | var list = this.data.previewImgList //页面的图片集合数组
130 |
131 | //判断res在数组中是否存在,不存在则push到数组中, -1表示res不存在
132 | if (list.indexOf(res) == -1 ) {
133 | this.data.previewImgList.push(res)
134 | }
135 | wx.previewImage({
136 | current: res, // 当前显示图片的http链接
137 | urls: that.data.previewImgList // 需要预览的图片http链接列表
138 | })
139 |
140 | },
141 | //聊天消息始终显示最底端
142 | bottom: function () {
143 | var query = wx.createSelectorQuery()
144 | query.select('#flag').boundingClientRect()
145 | query.selectViewport().scrollOffset()
146 | query.exec(function (res) {
147 | wx.pageScrollTo({
148 | scrollTop: res[0].bottom // #the-id节点的下边界坐标
149 | })
150 | res[1].scrollTop // 显示区域的竖直滚动位置
151 | })
152 | },
153 | })
--------------------------------------------------------------------------------
/pages/chat/chat.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": " ♥ 聊天室"
3 | }
--------------------------------------------------------------------------------
/pages/chat/chat.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 系统消息: 欢迎 {{ userInfo.nickName }} 加入群聊
4 |
5 |
6 |
7 |
8 |
9 |
23 | {{item.date}}
24 |
25 |
26 |
27 | {{ item.nickName }}
28 |
29 |
30 |
31 |
32 | {{item.content}}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | {{ item.nickName }}
44 |
45 |
46 |
47 | {{item.content}}
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
66 |
67 | 相册
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/pages/chat/chat.wxss:
--------------------------------------------------------------------------------
1 | /* pages/chat/chat.wxss */
2 | page {
3 | background-color: #f7f7f7;
4 | height: 100%;
5 | }
6 | /* 聊天内容 */
7 | .news {
8 | padding-top: 30rpx;
9 | text-align: center;
10 | /* height:100%; */
11 | box-sizing:border-box;
12 | }
13 | #flag{
14 | margin-bottom: 100rpx;
15 | height: 30rpx;
16 | }
17 | .chat-notice{
18 | text-align: center;
19 | font-size: 30rpx;
20 | padding: 10rpx 0;
21 | color: #666;
22 | }
23 | .historycon {
24 | height: 100%;
25 | width: 100%;
26 | /* flex-direction: column; */
27 | display: flex;
28 | border-top: 0px;
29 | }
30 | /* .img_null {
31 | height: 60rpx;
32 | } */
33 |
34 | /* .l {
35 | height: 5rpx;
36 | width: 20%;
37 | margin-top: 30rpx;
38 | color: #000;
39 | } */
40 |
41 | /* 聊天 */
42 | .chat-news{
43 | width: 100%;
44 | overflow: hidden;
45 | }
46 | .chat-news .my_right {
47 | float: right;
48 | /* right: 40rpx; */
49 | padding: 10rpx 10rpx;
50 | }
51 | .chat-news .name{
52 | margin-right: 10rpx;
53 | }
54 | .chat-news .you_left {
55 | float: left;
56 | /* left: 5rpx; */
57 | padding: 10rpx 10rpx;
58 | }
59 | .selectImg{
60 | display: inline-block;
61 | width: 150rpx;
62 | height: 150rpx;
63 | margin-left: 50rpx;
64 | }
65 | .my_right .selectImg{
66 | margin-right: 80rpx;
67 | }
68 | .new_img {
69 | width: 60rpx;
70 | height: 60rpx;
71 | border-radius: 50%;
72 | vertical-align: middle;
73 | margin-right: 10rpx;
74 | }
75 | .new_txt {
76 | max-width: 300rpx;
77 | display: inline-block;
78 | border-radius: 6rpx;
79 | line-height: 60rpx;
80 | background-color: #95d4ff;
81 | padding: 5rpx 20rpx;
82 | margin: 0 10rpx;
83 | margin-left: 50rpx;
84 | }
85 | .my_right .new_txt{
86 | margin-right:60rpx;
87 | }
88 | .you{
89 | background-color: lightgreen;
90 | }
91 |
92 | /* .sanjiao {
93 | top: 70rpx;
94 | position: relative;
95 | width: 0px;
96 | height: 0px;
97 | border-width: 10px;
98 | border-style: solid;
99 | } */
100 |
101 | .my {
102 | border-color: transparent transparent transparent #95d4ff;
103 | }
104 |
105 | .you {
106 | border-color: transparent #95d4ff transparent transparent;
107 | }
108 |
109 | .hei{
110 | margin-top: 50px;
111 | height: 20rpx;
112 | }
113 | .history {
114 | height: 100%;
115 | margin-top: 15px;
116 | padding: 10rpx;
117 | font-size: 14px;
118 | line-height: 40px;
119 | word-break: break-all;
120 | }
121 | ::-webkit-scrollbar {
122 | width: 0;
123 | height: 0;
124 | color: transparent;
125 | z-index: -1;
126 | }
127 |
128 | /* 信息输入区域 */
129 | .message{
130 | position: fixed;
131 | bottom:0;
132 | width: 100%;
133 | }
134 | .sendMessage{
135 | display: block;
136 | height: 80rpx;
137 | padding: 10rpx 10rpx;
138 | background-color: #fff;
139 | border-top: 2rpx solid #eee;
140 | border-bottom: 2rpx solid #eee;
141 | z-index:3;
142 | }
143 | .sendMessage input{
144 | float:left;
145 | width: 66%;
146 | height: 100%;
147 | line-height: 80rpx;
148 | border-bottom: 1rpx solid #ccc;
149 | padding:0 10rpx;
150 | font-size: 35rpx;
151 | color: #666;
152 | }
153 | .sendMessage view{
154 | display: inline-block;
155 | width: 80rpx;
156 | height: 80rpx;
157 | line-height: 80rpx;
158 | font-size: 60rpx;
159 | text-align: center;
160 | color: #999;
161 | border: 1rpx solid #ccc;
162 | border-radius: 50%;
163 | margin-left: 10rpx;
164 | }
165 | .sendMessage button {
166 | float: right;
167 | font-size: 35rpx;
168 | }
169 | .increased{
170 | width:100%;
171 | /* height: 150rpx; */
172 | padding: 40rpx 30rpx;
173 | background-color: #fff;
174 | }
175 | .increased .image{
176 | width: 100rpx;
177 | height: 100rpx;
178 | border: 3rpx solid #ccc;
179 | line-height: 100rpx;
180 | text-align: center;
181 | border-radius: 8rpx;
182 | font-size:35rpx;
183 | }
184 | @keyframes slidedown {
185 | from {
186 | transform: translateY(0);
187 | }
188 | to {
189 | transform: translateY(100%);
190 | }
191 | }
192 | .slidedown {
193 | animation: slidedown 0.5s linear ;
194 | }
195 | .slideup {
196 | animation: slideup 0.5s linear ;
197 | }
198 | @keyframes slideup {
199 | from {
200 | transform: translateY(100%);
201 | }
202 | to {
203 | transform: translateY(0);
204 | }
205 | }
--------------------------------------------------------------------------------
/pages/chat/images/avator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chongwenwen/weixin_chat/8928a7f9c37082edf058d359c9d3984b20eb791b/pages/chat/images/avator.png
--------------------------------------------------------------------------------
/pages/chat/images/say.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chongwenwen/weixin_chat/8928a7f9c37082edf058d359c9d3984b20eb791b/pages/chat/images/say.jpg
--------------------------------------------------------------------------------
/pages/index/index.js:
--------------------------------------------------------------------------------
1 | //index.js
2 | //获取应用实例
3 | const app = getApp()
4 |
5 | Page({
6 | data: {
7 | userInfo: {},
8 | hasUserInfo: false,
9 | canIUse: wx.canIUse('button.open-type.getUserInfo')
10 | },
11 | //事件处理函数
12 | // bindViewTap: function() {
13 | // wx.navigateTo({
14 | // url: '../chat/chat'
15 | // })
16 | // },
17 | toChat: function () {
18 | wx.navigateTo({
19 | url: '../chat/chat'
20 | })
21 | },
22 | onLoad: function () {
23 | console.log(app.globalData.userInfo)
24 | if (app.globalData.userInfo) {
25 | this.setData({
26 | userInfo: app.globalData.userInfo,
27 | hasUserInfo: true
28 | })
29 | } else if (this.data.canIUse){
30 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
31 | // 所以此处加入 callback 以防止这种情况
32 | app.userInfoReadyCallback = res => {
33 | this.setData({
34 | userInfo: res.userInfo,
35 | hasUserInfo: true
36 | })
37 | }
38 | } else {
39 | // 在没有 open-type=getUserInfo 版本的兼容处理
40 | wx.getUserInfo({
41 | success: res => {
42 | app.globalData.userInfo = res.userInfo
43 | this.setData({
44 | userInfo: res.userInfo,
45 | hasUserInfo: true
46 | })
47 | }
48 | })
49 | }
50 | },
51 | getUserInfo: function(e) {
52 | console.log(e)
53 | app.globalData.userInfo = e.detail.userInfo
54 | this.setData({
55 | userInfo: e.detail.userInfo,
56 | hasUserInfo: true
57 | })
58 | }
59 | })
60 |
--------------------------------------------------------------------------------
/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{userInfo.nickName}}
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | .userinfo {
3 | display: flex;
4 | flex-direction: column;
5 | align-items: center;
6 | }
7 |
8 | .userinfo-avatar {
9 | width: 128rpx;
10 | height: 128rpx;
11 | margin: 20rpx;
12 | border-radius: 50%;
13 | }
14 |
15 | .userinfo-nickname {
16 | color: #aaa;
17 | }
18 | .chat{
19 | font-size: 35rpx;
20 | margin: 40rpx 0;
21 | }
--------------------------------------------------------------------------------
/pages/index/user-unlogin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chongwenwen/weixin_chat/8928a7f9c37082edf058d359c9d3984b20eb791b/pages/index/user-unlogin.png
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件。",
3 | "packOptions": {
4 | "ignore": []
5 | },
6 | "setting": {
7 | "urlCheck": false,
8 | "es6": true,
9 | "postcss": true,
10 | "minified": true,
11 | "newFeature": true
12 | },
13 | "compileType": "miniprogram",
14 | "libVersion": "2.0.4",
15 | "appid": "wx73b9fecfd1047b8f",
16 | "projectname": "%E7%88%B1%E5%BF%83%E8%81%8A%E5%A4%A9%E5%AE%A4",
17 | "condition": {
18 | "search": {
19 | "current": -1,
20 | "list": []
21 | },
22 | "conversation": {
23 | "current": -1,
24 | "list": []
25 | },
26 | "game": {
27 | "currentL": -1,
28 | "list": []
29 | },
30 | "miniprogram": {
31 | "current": -1,
32 | "list": []
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/utils/util.js:
--------------------------------------------------------------------------------
1 | const formatTime = date => {
2 | // const year = date.getFullYear()
3 | // const month = date.getMonth() + 1
4 | // const day = date.getDate()
5 | const hour = date.getHours()
6 | const minute = date.getMinutes()
7 | const second = date.getSeconds()
8 |
9 | // return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
10 | return [hour, minute].map(formatNumber).join(':')
11 | }
12 |
13 | const formatNumber = n => {
14 | n = n.toString()
15 | return n[1] ? n : '0' + n
16 | }
17 | //数组去重
18 | function contains(arr, obj) {
19 | var i = arr.length;
20 | while (i--) {
21 | if (arr[i] === obj) {
22 | return true;
23 | }
24 | }
25 | return false;
26 | }
27 |
28 | module.exports = {
29 | formatTime: formatTime,
30 | contains: contains
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/utils/websocket.js:
--------------------------------------------------------------------------------
1 | // 聊天室
2 | var url = 'ws://192.168.137.91:2346';
3 | // var utils = require('./util.js');
4 |
5 | function connect(user,func) {
6 | wx.connectSocket({
7 | url: url,
8 | header:{'content-type': 'application/json'},
9 | success: function () {
10 | console.log('信道连接成功~')
11 | },
12 | fail: function () {
13 | console.log('信道连接失败~')
14 | }
15 | })
16 | wx.onSocketOpen(function (res) {
17 | wx.showToast({
18 | title: '信道已开通~',
19 | icon: "success",
20 | duration: 2000
21 | })
22 | //接受服务器消息
23 | wx.onSocketMessage(func);//func回调可以拿到服务器返回的数据
24 | });
25 | wx.onSocketError(function (res) {
26 | wx.showToast({
27 | title: '信道连接失败,请检查!',
28 | icon: "none",
29 | duration: 2000
30 | })
31 | })
32 | }
33 | //发送消息
34 | function send(msg) {
35 | wx.sendSocketMessage({
36 | data: msg
37 | });
38 | }
39 | module.exports = {
40 | connect: connect,
41 | send: send
42 | }
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/index.js:
--------------------------------------------------------------------------------
1 | var constants = require('./lib/constants');
2 | var login = require('./lib/login');
3 | var Session = require('./lib/session');
4 | var request = require('./lib/request');
5 | var Tunnel = require('./lib/tunnel');
6 |
7 | var exports = module.exports = {
8 | login: login.login,
9 | setLoginUrl: login.setLoginUrl,
10 | LoginError: login.LoginError,
11 |
12 | clearSession: Session.clear,
13 |
14 | request: request.request,
15 | RequestError: request.RequestError,
16 |
17 | Tunnel: Tunnel,
18 | };
19 |
20 | // 导出错误类型码
21 | Object.keys(constants).forEach(function (key) {
22 | if (key.indexOf('ERR_') === 0) {
23 | exports[key] = constants[key];
24 | }
25 | });
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/lib/constants.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | WX_HEADER_CODE: 'X-WX-Code',
3 | WX_HEADER_ENCRYPTED_DATA: 'X-WX-Encrypted-Data',
4 | WX_HEADER_IV: 'X-WX-IV',
5 | WX_HEADER_ID: 'X-WX-Id',
6 | WX_HEADER_SKEY: 'X-WX-Skey',
7 |
8 | WX_SESSION_MAGIC_ID: 'F2C224D4-2BCE-4C64-AF9F-A6D872000D1A',
9 |
10 | ERR_INVALID_PARAMS: 'ERR_INVALID_PARAMS',
11 |
12 | ERR_WX_LOGIN_FAILED: 'ERR_WX_LOGIN_FAILED',
13 | ERR_WX_GET_USER_INFO: 'ERR_WX_GET_USER_INFO',
14 | ERR_LOGIN_TIMEOUT: 'ERR_LOGIN_TIMEOUT',
15 | ERR_LOGIN_FAILED: 'ERR_LOGIN_FAILED',
16 | ERR_LOGIN_SESSION_NOT_RECEIVED: 'ERR_LOGIN_MISSING_SESSION',
17 |
18 | ERR_SESSION_INVALID: 'ERR_SESSION_INVALID',
19 | ERR_CHECK_LOGIN_FAILED: 'ERR_CHECK_LOGIN_FAILED',
20 | };
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/lib/login.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils');
2 | var constants = require('./constants');
3 | var Session = require('./session');
4 |
5 | /***
6 | * @class
7 | * 表示登录过程中发生的异常
8 | */
9 | var LoginError = (function () {
10 | function LoginError(type, message) {
11 | Error.call(this, message);
12 | this.type = type;
13 | this.message = message;
14 | }
15 |
16 | LoginError.prototype = new Error();
17 | LoginError.prototype.constructor = LoginError;
18 |
19 | return LoginError;
20 | })();
21 |
22 | /**
23 | * 微信登录,获取 code 和 encryptData
24 | */
25 | var getWxLoginResult = function getLoginCode(callback) {
26 | wx.login({
27 | success: function (loginResult) {
28 | wx.getUserInfo({
29 | success: function (userResult) {
30 | callback(null, {
31 | code: loginResult.code,
32 | encryptedData: userResult.encryptedData,
33 | iv: userResult.iv,
34 | userInfo: userResult.userInfo,
35 | });
36 | },
37 |
38 | fail: function (userError) {
39 | var error = new LoginError(constants.ERR_WX_GET_USER_INFO, '获取微信用户信息失败,请检查网络状态');
40 | error.detail = userError;
41 | callback(error, null);
42 | },
43 | });
44 | },
45 |
46 | fail: function (loginError) {
47 | var error = new LoginError(constants.ERR_WX_LOGIN_FAILED, '微信登录失败,请检查网络状态');
48 | error.detail = loginError;
49 | callback(error, null);
50 | },
51 | });
52 | };
53 |
54 | var noop = function noop() {};
55 | var defaultOptions = {
56 | method: 'GET',
57 | success: noop,
58 | fail: noop,
59 | loginUrl: null,
60 | };
61 |
62 | /**
63 | * @method
64 | * 进行服务器登录,以获得登录会话
65 | *
66 | * @param {Object} options 登录配置
67 | * @param {string} options.loginUrl 登录使用的 URL,服务器应该在这个 URL 上处理登录请求
68 | * @param {string} [options.method] 请求使用的 HTTP 方法,默认为 "GET"
69 | * @param {Function} options.success(userInfo) 登录成功后的回调函数,参数 userInfo 微信用户信息
70 | * @param {Function} options.fail(error) 登录失败后的回调函数,参数 error 错误信息
71 | */
72 | var login = function login(options) {
73 | options = utils.extend({}, defaultOptions, options);
74 |
75 | if (!defaultOptions.loginUrl) {
76 | options.fail(new LoginError(constants.ERR_INVALID_PARAMS, '登录错误:缺少登录地址,请通过 setLoginUrl() 方法设置登录地址'));
77 | return;
78 | }
79 |
80 | var doLogin = () => getWxLoginResult(function (wxLoginError, wxLoginResult) {
81 | if (wxLoginError) {
82 | options.fail(wxLoginError);
83 | return;
84 | }
85 |
86 | var userInfo = wxLoginResult.userInfo;
87 |
88 | // 构造请求头,包含 code、encryptedData 和 iv
89 | var code = wxLoginResult.code;
90 | var encryptedData = wxLoginResult.encryptedData;
91 | var iv = wxLoginResult.iv;
92 | var header = {};
93 |
94 | header[constants.WX_HEADER_CODE] = code;
95 | header[constants.WX_HEADER_ENCRYPTED_DATA] = encryptedData;
96 | header[constants.WX_HEADER_IV] = iv;
97 |
98 | // 请求服务器登录地址,获得会话信息
99 | wx.request({
100 | url: options.loginUrl,
101 | header: header,
102 | method: options.method,
103 | data: options.data,
104 | success: function (result) {
105 | var data = result.data;
106 |
107 | // 成功地响应会话信息
108 | if (data && data.code === 0 && data.data.skey) {
109 | var res = data.data
110 | if (res.userinfo) {
111 | Session.set(res.skey);
112 | options.success(userInfo);
113 | } else {
114 | var errorMessage = '登录失败(' + data.error + '):' + (data.message || '未知错误');
115 | var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, errorMessage);
116 | options.fail(noSessionError);
117 | }
118 |
119 | // 没有正确响应会话信息
120 | } else {
121 | var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, JSON.stringify(data));
122 | options.fail(noSessionError);
123 | }
124 | },
125 |
126 | // 响应错误
127 | fail: function (loginResponseError) {
128 | var error = new LoginError(constants.ERR_LOGIN_FAILED, '登录失败,可能是网络错误或者服务器发生异常');
129 | options.fail(error);
130 | },
131 | });
132 | });
133 |
134 | var session = Session.get();
135 | if (session) {
136 | wx.checkSession({
137 | success: function () {
138 | options.success(session.userInfo);
139 | },
140 |
141 | fail: function () {
142 | Session.clear();
143 | doLogin();
144 | },
145 | });
146 | } else {
147 | doLogin();
148 | }
149 | };
150 |
151 | var setLoginUrl = function (loginUrl) {
152 | defaultOptions.loginUrl = loginUrl;
153 | };
154 |
155 | module.exports = {
156 | LoginError: LoginError,
157 | login: login,
158 | setLoginUrl: setLoginUrl,
159 | };
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/lib/request.js:
--------------------------------------------------------------------------------
1 | var constants = require('./constants');
2 | var utils = require('./utils');
3 | var Session = require('./session');
4 | var loginLib = require('./login');
5 |
6 | var noop = function noop() {};
7 |
8 | var buildAuthHeader = function buildAuthHeader(session) {
9 | var header = {};
10 |
11 | if (session) {
12 | header[constants.WX_HEADER_SKEY] = session;
13 | }
14 |
15 | return header;
16 | };
17 |
18 | /***
19 | * @class
20 | * 表示请求过程中发生的异常
21 | */
22 | var RequestError = (function () {
23 | function RequestError(type, message) {
24 | Error.call(this, message);
25 | this.type = type;
26 | this.message = message;
27 | }
28 |
29 | RequestError.prototype = new Error();
30 | RequestError.prototype.constructor = RequestError;
31 |
32 | return RequestError;
33 | })();
34 |
35 | function request(options) {
36 | if (typeof options !== 'object') {
37 | var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型';
38 | throw new RequestError(constants.ERR_INVALID_PARAMS, message);
39 | }
40 |
41 | var requireLogin = options.login;
42 | var success = options.success || noop;
43 | var fail = options.fail || noop;
44 | var complete = options.complete || noop;
45 | var originHeader = options.header || {};
46 |
47 | // 成功回调
48 | var callSuccess = function () {
49 | success.apply(null, arguments);
50 | complete.apply(null, arguments);
51 | };
52 |
53 | // 失败回调
54 | var callFail = function (error) {
55 | fail.call(null, error);
56 | complete.call(null, error);
57 | };
58 |
59 | // 是否已经进行过重试
60 | var hasRetried = false;
61 |
62 | if (requireLogin) {
63 | doRequestWithLogin();
64 | } else {
65 | doRequest();
66 | }
67 |
68 | // 登录后再请求
69 | function doRequestWithLogin() {
70 | loginLib.login({ success: doRequest, fail: callFail });
71 | }
72 |
73 | // 实际进行请求的方法
74 | function doRequest() {
75 | var authHeader = buildAuthHeader(Session.get());
76 |
77 | wx.request(utils.extend({}, options, {
78 | header: utils.extend({}, originHeader, authHeader),
79 |
80 | success: function (response) {
81 | var data = response.data;
82 |
83 | var error, message;
84 | if (data && data.code === -1) {
85 | Session.clear();
86 | // 如果是登录态无效,并且还没重试过,会尝试登录后刷新凭据重新请求
87 | if (!hasRetried) {
88 | hasRetried = true;
89 | doRequestWithLogin();
90 | return;
91 | }
92 |
93 | message = '登录态已过期';
94 | error = new RequestError(data.error, message);
95 |
96 | callFail(error);
97 | return;
98 | } else {
99 | callSuccess.apply(null, arguments);
100 | }
101 | },
102 |
103 | fail: callFail,
104 | complete: noop,
105 | }));
106 | };
107 |
108 | };
109 |
110 | module.exports = {
111 | RequestError: RequestError,
112 | request: request,
113 | };
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/lib/session.js:
--------------------------------------------------------------------------------
1 | var constants = require('./constants');
2 | var SESSION_KEY = 'weapp_session_' + constants.WX_SESSION_MAGIC_ID;
3 |
4 | var Session = {
5 | get: function () {
6 | return wx.getStorageSync(SESSION_KEY) || null;
7 | },
8 |
9 | set: function (session) {
10 | wx.setStorageSync(SESSION_KEY, session);
11 | },
12 |
13 | clear: function () {
14 | wx.removeStorageSync(SESSION_KEY);
15 | },
16 | };
17 |
18 | module.exports = Session;
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/lib/tunnel.js:
--------------------------------------------------------------------------------
1 | var requestLib = require('./request');
2 | var wxTunnel = require('./wxTunnel');
3 |
4 | /**
5 | * 当前打开的信道,同一时间只能有一个信道打开
6 | */
7 | var currentTunnel = null;
8 |
9 | // 信道状态枚举
10 | var STATUS_CLOSED = Tunnel.STATUS_CLOSED = 'CLOSED';
11 | var STATUS_CONNECTING = Tunnel.STATUS_CONNECTING = 'CONNECTING';
12 | var STATUS_ACTIVE = Tunnel.STATUS_ACTIVE = 'ACTIVE';
13 | var STATUS_RECONNECTING = Tunnel.STATUS_RECONNECTING = 'RECONNECTING';
14 |
15 | // 错误类型枚举
16 | var ERR_CONNECT_SERVICE = Tunnel.ERR_CONNECT_SERVICE = 1001;
17 | var ERR_CONNECT_SOCKET = Tunnel.ERR_CONNECT_SOCKET = 1002;
18 | var ERR_RECONNECT = Tunnel.ERR_RECONNECT = 2001;
19 | var ERR_SOCKET_ERROR = Tunnel.ERR_SOCKET_ERROR = 3001;
20 |
21 | // 包类型枚举
22 | var PACKET_TYPE_MESSAGE = 'message';
23 | var PACKET_TYPE_PING = 'ping';
24 | var PACKET_TYPE_PONG = 'pong';
25 | var PACKET_TYPE_TIMEOUT = 'timeout';
26 | var PACKET_TYPE_CLOSE = 'close';
27 |
28 | // 断线重连最多尝试 5 次
29 | var DEFAULT_MAX_RECONNECT_TRY_TIMES = 5;
30 |
31 | // 每次重连前,等待时间的增量值
32 | var DEFAULT_RECONNECT_TIME_INCREASE = 1000;
33 |
34 | function Tunnel(serviceUrl) {
35 | if (currentTunnel && currentTunnel.status !== STATUS_CLOSED) {
36 | throw new Error('当前有未关闭的信道,请先关闭之前的信道,再打开新信道');
37 | }
38 |
39 | currentTunnel = this;
40 |
41 | // 等确认微信小程序全面支持 ES6 就不用那么麻烦了
42 | var me = this;
43 |
44 | //=========================================================================
45 | // 暴露实例状态以及方法
46 | //=========================================================================
47 | this.serviceUrl = serviceUrl;
48 | this.socketUrl = null;
49 | this.status = null;
50 |
51 | this.open = openConnect;
52 | this.on = registerEventHandler;
53 | this.emit = emitMessagePacket;
54 | this.close = close;
55 |
56 | this.isClosed = isClosed;
57 | this.isConnecting = isConnecting;
58 | this.isActive = isActive;
59 | this.isReconnecting = isReconnecting;
60 |
61 |
62 | //=========================================================================
63 | // 信道状态处理,状态说明:
64 | // closed - 已关闭
65 | // connecting - 首次连接
66 | // active - 当前信道已经在工作
67 | // reconnecting - 断线重连中
68 | //=========================================================================
69 | function isClosed() { return me.status === STATUS_CLOSED; }
70 | function isConnecting() { return me.status === STATUS_CONNECTING; }
71 | function isActive() { return me.status === STATUS_ACTIVE; }
72 | function isReconnecting() { return me.status === STATUS_RECONNECTING; }
73 |
74 | function setStatus(status) {
75 | var lastStatus = me.status;
76 | if (lastStatus !== status) {
77 | me.status = status;
78 | }
79 | }
80 |
81 | // 初始为关闭状态
82 | setStatus(STATUS_CLOSED);
83 |
84 |
85 | //=========================================================================
86 | // 信道事件处理机制
87 | // 信道事件包括:
88 | // connect - 连接已建立
89 | // close - 连接被关闭(包括主动关闭和被动关闭)
90 | // reconnecting - 开始重连
91 | // reconnect - 重连成功
92 | // error - 发生错误,其中包括连接失败、重连失败、解包失败等等
93 | // [message] - 信道服务器发送过来的其它事件类型,如果事件类型和上面内置的事件类型冲突,将在事件类型前面添加前缀 `@`
94 | //=========================================================================
95 | var preservedEventTypes = 'connect,close,reconnecting,reconnect,error'.split(',');
96 | var eventHandlers = [];
97 |
98 | /**
99 | * 注册消息处理函数
100 | * @param {string} messageType 支持内置消息类型("connect"|"close"|"reconnecting"|"reconnect"|"error")以及业务消息类型
101 | */
102 | function registerEventHandler(eventType, eventHandler) {
103 | if (typeof eventHandler === 'function') {
104 | eventHandlers.push([eventType, eventHandler]);
105 | }
106 | }
107 |
108 | /**
109 | * 派发事件,通知所有处理函数进行处理
110 | */
111 | function dispatchEvent(eventType, eventPayload) {
112 | eventHandlers.forEach(function (handler) {
113 | var handleType = handler[0];
114 | var handleFn = handler[1];
115 |
116 | if (handleType === '*') {
117 | handleFn(eventType, eventPayload);
118 | } else if (handleType === eventType) {
119 | handleFn(eventPayload);
120 | }
121 | });
122 | }
123 |
124 | /**
125 | * 派发事件,事件类型和系统保留冲突的,事件名会自动加上 '@' 前缀
126 | */
127 | function dispatchEscapedEvent(eventType, eventPayload) {
128 | if (preservedEventTypes.indexOf(eventType) > -1) {
129 | eventType = '@' + eventType;
130 | }
131 |
132 | dispatchEvent(eventType, eventPayload);
133 | }
134 |
135 |
136 | //=========================================================================
137 | // 信道连接控制
138 | //=========================================================================
139 | var isFirstConnection = true;
140 | var isOpening = false;
141 |
142 | /**
143 | * 连接信道服务器,获取 WebSocket 连接地址,获取地址成功后,开始进行 WebSocket 连接
144 | */
145 | function openConnect() {
146 | if (isOpening) return;
147 | isOpening = true;
148 |
149 | // 只有关闭状态才会重新进入准备中
150 | setStatus(isFirstConnection ? STATUS_CONNECTING : STATUS_RECONNECTING);
151 |
152 | requestLib.request({
153 | url: serviceUrl,
154 | method: 'GET',
155 | success: function (response) {
156 | if (+response.statusCode === 200 && response.data && response.data.data.connectUrl) {
157 | openSocket(me.socketUrl = response.data.data.connectUrl);
158 | } else {
159 | dispatchConnectServiceError(response);
160 | }
161 | },
162 | fail: dispatchConnectServiceError,
163 | complete: () => isOpening = false,
164 | });
165 |
166 | function dispatchConnectServiceError(detail) {
167 | if (isFirstConnection) {
168 | setStatus(STATUS_CLOSED);
169 |
170 | dispatchEvent('error', {
171 | code: ERR_CONNECT_SERVICE,
172 | message: '连接信道服务失败,网络错误或者信道服务没有正确响应',
173 | detail: detail || null,
174 | });
175 |
176 | } else {
177 | startReconnect(detail);
178 | }
179 | }
180 | }
181 |
182 | /**
183 | * 打开 WebSocket 连接,打开后,注册微信的 Socket 处理方法
184 | */
185 | function openSocket(url) {
186 | wxTunnel.listen({
187 | onOpen: handleSocketOpen,
188 | onMessage: handleSocketMessage,
189 | onClose: handleSocketClose,
190 | onError: handleSocketError,
191 | });
192 |
193 | wx.connectSocket({ url: url });
194 | isFirstConnection = false;
195 | }
196 |
197 |
198 | //=========================================================================
199 | // 处理消息通讯
200 | //
201 | // packet - 数据包,序列化形式为 `${type}` 或者 `${type}:${content}`
202 | // packet.type - 包类型,包括 message, ping, pong, close
203 | // packet.content? - 当包类型为 message 的时候,会附带 message 数据
204 | //
205 | // message - 消息体,会使用 JSON 序列化后作为 packet.content
206 | // message.type - 消息类型,表示业务消息类型
207 | // message.content? - 消息实体,可以为任意类型,表示消息的附带数据,也可以为空
208 | //
209 | // 数据包示例:
210 | // - 'ping' 表示 Ping 数据包
211 | // - 'message:{"type":"speak","content":"hello"}' 表示一个打招呼的数据包
212 | //=========================================================================
213 |
214 | // 连接还没成功建立的时候,需要发送的包会先存放到队列里
215 | var queuedPackets = [];
216 |
217 | /**
218 | * WebSocket 打开之后,更新状态,同时发送所有遗留的数据包
219 | */
220 | function handleSocketOpen() {
221 | /* istanbul ignore else */
222 | if (isConnecting()) {
223 | dispatchEvent('connect');
224 |
225 | }
226 | else if (isReconnecting()) {
227 | dispatchEvent('reconnect');
228 | resetReconnectionContext();
229 | }
230 |
231 | setStatus(STATUS_ACTIVE);
232 | emitQueuedPackets();
233 | nextPing();
234 | }
235 |
236 | /**
237 | * 收到 WebSocket 数据包,交给处理函数
238 | */
239 | function handleSocketMessage(message) {
240 | resolvePacket(message.data);
241 | }
242 |
243 | /**
244 | * 发送数据包,如果信道没有激活,将先存放队列
245 | */
246 | function emitPacket(packet) {
247 | if (isActive()) {
248 | sendPacket(packet);
249 | } else {
250 | queuedPackets.push(packet);
251 | }
252 | }
253 |
254 | /**
255 | * 数据包推送到信道
256 | */
257 | function sendPacket(packet) {
258 | var encodedPacket = [packet.type];
259 |
260 | if (packet.content) {
261 | encodedPacket.push(JSON.stringify(packet.content));
262 | }
263 |
264 | wx.sendSocketMessage({
265 | data: encodedPacket.join(':'),
266 | fail: handleSocketError,
267 | });
268 | }
269 |
270 | function emitQueuedPackets() {
271 | queuedPackets.forEach(emitPacket);
272 |
273 | // empty queued packets
274 | queuedPackets.length = 0;
275 | }
276 |
277 | /**
278 | * 发送消息包
279 | */
280 | function emitMessagePacket(messageType, messageContent) {
281 | var packet = {
282 | type: PACKET_TYPE_MESSAGE,
283 | content: {
284 | type: messageType,
285 | content: messageContent,
286 | },
287 | };
288 |
289 | emitPacket(packet);
290 | }
291 |
292 | /**
293 | * 发送 Ping 包
294 | */
295 | function emitPingPacket() {
296 | emitPacket({ type: PACKET_TYPE_PING });
297 | }
298 |
299 | /**
300 | * 发送关闭包
301 | */
302 | function emitClosePacket() {
303 | emitPacket({ type: PACKET_TYPE_CLOSE });
304 | }
305 |
306 | /**
307 | * 解析并处理从信道接收到的包
308 | */
309 | function resolvePacket(raw) {
310 | var packetParts = raw.split(':');
311 | var packetType = packetParts.shift();
312 | var packetContent = packetParts.join(':') || null;
313 | var packet = { type: packetType };
314 |
315 | if (packetContent) {
316 | try {
317 | packet.content = JSON.parse(packetContent);
318 | } catch (e) {}
319 | }
320 |
321 | switch (packet.type) {
322 | case PACKET_TYPE_MESSAGE:
323 | handleMessagePacket(packet);
324 | break;
325 | case PACKET_TYPE_PONG:
326 | handlePongPacket(packet);
327 | break;
328 | case PACKET_TYPE_TIMEOUT:
329 | handleTimeoutPacket(packet);
330 | break;
331 | case PACKET_TYPE_CLOSE:
332 | handleClosePacket(packet);
333 | break;
334 | default:
335 | handleUnknownPacket(packet);
336 | break;
337 | }
338 | }
339 |
340 | /**
341 | * 收到消息包,直接 dispatch 给处理函数
342 | */
343 | function handleMessagePacket(packet) {
344 | var message = packet.content;
345 | dispatchEscapedEvent(message.type, message.content);
346 | }
347 |
348 |
349 | //=========================================================================
350 | // 心跳、断开与重连处理
351 | //=========================================================================
352 |
353 | /**
354 | * Ping-Pong 心跳检测超时控制,这个值有两个作用:
355 | * 1. 表示收到服务器的 Pong 相应之后,过多久再发下一次 Ping
356 | * 2. 如果 Ping 发送之后,超过这个时间还没收到 Pong,断开与服务器的连接
357 | * 该值将在与信道服务器建立连接后被更新
358 | */
359 | let pingPongTimeout = 15000;
360 | let pingTimer = 0;
361 | let pongTimer = 0;
362 |
363 | /**
364 | * 信道服务器返回 Ping-Pong 控制超时时间
365 | */
366 | function handleTimeoutPacket(packet) {
367 | var timeout = packet.content * 1000;
368 | /* istanbul ignore else */
369 | if (!isNaN(timeout)) {
370 | pingPongTimeout = timeout;
371 | ping();
372 | }
373 | }
374 |
375 | /**
376 | * 收到服务器 Pong 响应,定时发送下一个 Ping
377 | */
378 | function handlePongPacket(packet) {
379 | nextPing();
380 | }
381 |
382 | /**
383 | * 发送下一个 Ping 包
384 | */
385 | function nextPing() {
386 | clearTimeout(pingTimer);
387 | clearTimeout(pongTimer);
388 | pingTimer = setTimeout(ping, pingPongTimeout);
389 | }
390 |
391 | /**
392 | * 发送 Ping,等待 Pong
393 | */
394 | function ping() {
395 | /* istanbul ignore else */
396 | if (isActive()) {
397 | emitPingPacket();
398 |
399 | // 超时没有响应,关闭信道
400 | pongTimer = setTimeout(handlePongTimeout, pingPongTimeout);
401 | }
402 | }
403 |
404 | /**
405 | * Pong 超时没有响应,信道可能已经不可用,需要断开重连
406 | */
407 | function handlePongTimeout() {
408 | startReconnect('服务器已失去响应');
409 | }
410 |
411 | // 已经重连失败的次数
412 | var reconnectTryTimes = 0;
413 |
414 | // 最多允许失败次数
415 | var maxReconnectTryTimes = Tunnel.MAX_RECONNECT_TRY_TIMES || DEFAULT_MAX_RECONNECT_TRY_TIMES;
416 |
417 | // 重连前等待的时间
418 | var waitBeforeReconnect = 0;
419 |
420 | // 重连前等待时间增量
421 | var reconnectTimeIncrease = Tunnel.RECONNECT_TIME_INCREASE || DEFAULT_RECONNECT_TIME_INCREASE;
422 |
423 | var reconnectTimer = 0;
424 |
425 | function startReconnect(lastError) {
426 | if (reconnectTryTimes >= maxReconnectTryTimes) {
427 | close();
428 |
429 | dispatchEvent('error', {
430 | code: ERR_RECONNECT,
431 | message: '重连失败',
432 | detail: lastError,
433 | });
434 | }
435 | else {
436 | wx.closeSocket();
437 | waitBeforeReconnect += reconnectTimeIncrease;
438 | setStatus(STATUS_RECONNECTING);
439 | reconnectTimer = setTimeout(doReconnect, waitBeforeReconnect);
440 | }
441 |
442 | if (reconnectTryTimes === 0) {
443 | dispatchEvent('reconnecting');
444 | }
445 |
446 | reconnectTryTimes += 1;
447 | }
448 |
449 | function doReconnect() {
450 | openConnect();
451 | }
452 |
453 | function resetReconnectionContext() {
454 | reconnectTryTimes = 0;
455 | waitBeforeReconnect = 0;
456 | }
457 |
458 | /**
459 | * 收到服务器的关闭请求
460 | */
461 | function handleClosePacket(packet) {
462 | close();
463 | }
464 |
465 | function handleUnknownPacket(packet) {
466 | // throw away
467 | }
468 |
469 | var isClosing = false;
470 |
471 | /**
472 | * 收到 WebSocket 断开的消息,处理断开逻辑
473 | */
474 | function handleSocketClose() {
475 | /* istanbul ignore if */
476 | if (isClosing) return;
477 |
478 | /* istanbul ignore else */
479 | if (isActive()) {
480 | // 意外断开的情况,进行重连
481 | startReconnect('链接已断开');
482 | }
483 | }
484 |
485 | function close() {
486 | isClosing = true;
487 | closeSocket();
488 | setStatus(STATUS_CLOSED);
489 | resetReconnectionContext();
490 | isFirstConnection = false;
491 | clearTimeout(pingTimer);
492 | clearTimeout(pongTimer);
493 | clearTimeout(reconnectTimer);
494 | dispatchEvent('close');
495 | isClosing = false;
496 | }
497 |
498 | function closeSocket(emitClose) {
499 | if (isActive() && emitClose !== false) {
500 | emitClosePacket();
501 | }
502 |
503 | wx.closeSocket();
504 | }
505 |
506 |
507 | //=========================================================================
508 | // 错误处理
509 | //=========================================================================
510 |
511 | /**
512 | * 错误处理
513 | */
514 | function handleSocketError(detail) {
515 | switch (me.status) {
516 | case Tunnel.STATUS_CONNECTING:
517 | dispatchEvent('error', {
518 | code: ERR_SOCKET_ERROR,
519 | message: '连接信道失败,网络错误或者信道服务不可用',
520 | detail: detail,
521 | });
522 | break;
523 | }
524 | }
525 |
526 | }
527 |
528 | module.exports = Tunnel;
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/lib/utils.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * 拓展对象
4 | */
5 | exports.extend = function extend(target) {
6 | var sources = Array.prototype.slice.call(arguments, 1);
7 |
8 | for (var i = 0; i < sources.length; i += 1) {
9 | var source = sources[i];
10 | for (var key in source) {
11 | if (source.hasOwnProperty(key)) {
12 | target[key] = source[key];
13 | }
14 | }
15 | }
16 |
17 | return target;
18 | };
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/lib/wxTunnel.js:
--------------------------------------------------------------------------------
1 | /* istanbul ignore next */
2 | const noop = () => void(0);
3 |
4 | let onOpen, onClose, onMessage, onError;
5 |
6 | /* istanbul ignore next */
7 | function listen(listener) {
8 | if (listener) {
9 | onOpen = listener.onOpen;
10 | onClose = listener.onClose;
11 | onMessage = listener.onMessage;
12 | onError = listener.onError;
13 | } else {
14 | onOpen = noop;
15 | onClose = noop;
16 | onMessage = noop;
17 | onError = noop;
18 | }
19 | }
20 |
21 | /* istanbul ignore next */
22 | function bind() {
23 | wx.onSocketOpen(result => onOpen(result));
24 | wx.onSocketClose(result => onClose(result));
25 | wx.onSocketMessage(result => onMessage(result));
26 | wx.onSocketError(error => onError(error));
27 | }
28 |
29 | listen(null);
30 | bind();
31 |
32 | module.exports = { listen };
--------------------------------------------------------------------------------
/vendor/wafer2-client-sdk/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "wafer2-client-sdk",
3 | "_id": "wafer2-client-sdk@1.0.0",
4 | "_inBundle": false,
5 | "_integrity": "sha1-4hExQwJ+2YIN3LOn0EtbBd8uTYg=",
6 | "_location": "/wafer2-client-sdk",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "tag",
10 | "registry": true,
11 | "raw": "wafer2-client-sdk",
12 | "name": "wafer2-client-sdk",
13 | "escapedName": "wafer2-client-sdk",
14 | "rawSpec": "",
15 | "saveSpec": null,
16 | "fetchSpec": "latest"
17 | },
18 | "_requiredBy": [
19 | "#USER",
20 | "/"
21 | ],
22 | "_resolved": "http://r.tnpm.oa.com/wafer2-client-sdk/download/wafer2-client-sdk-1.0.0.tgz",
23 | "_shasum": "e2113143027ed9820ddcb3a7d04b5b05df2e4d88",
24 | "_spec": "wafer2-client-sdk",
25 | "_where": "/Users/Jason/Tencent/ide-test/wafer-client-demo",
26 | "author": {
27 | "name": "CFETeam"
28 | },
29 | "bugs": {
30 | "url": "https://github.com/tencentyun/wafer2-client-sdk/issues"
31 | },
32 | "bundleDependencies": false,
33 | "deprecated": false,
34 | "description": "Wafer client SDK",
35 | "directories": {
36 | "lib": "lib"
37 | },
38 | "homepage": "https://github.com/tencentyun/wafer2-client-sdk#readme",
39 | "license": "MIT",
40 | "main": "index.js",
41 | "name": "wafer2-client-sdk",
42 | "repository": {
43 | "type": "git",
44 | "url": "git+https://github.com/tencentyun/wafer2-client-sdk.git"
45 | },
46 | "version": "1.0.0"
47 | }
48 |
--------------------------------------------------------------------------------