Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wecloud_im_server
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
hewei
wecloud_im_server
Commits
d9ac2d80
Commit
d9ac2d80
authored
Nov 05, 2021
by
giaogiao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
支持多端登陆,保存多端channel
parent
c2c00664
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
169 additions
and
40 deletions
+169
-40
bootstrap/src/test/java/io/geekidea/springbootplus/test/MapTest.java
+43
-0
common/src/main/java/com/wecloud/im/ws/model/ClientInfo.java
+19
-3
common/src/main/java/com/wecloud/im/ws/service/MangerChannelService.java
+8
-4
common/src/main/java/com/wecloud/im/ws/service/impl/MangerChannelServiceImpl.java
+32
-3
docs/md/内部/wecloud-im服务端REST API对接文档.md
+1
-2
docs/md/客户/wecloud-im即时通讯聊天云服务_外部客户对接文档.md
+37
-5
安装中间件.md
+6
-3
开发记录.md
+23
-20
No files found.
bootstrap/src/test/java/io/geekidea/springbootplus/test/MapTest.java
0 → 100755
View file @
d9ac2d80
/*
* Copyright 2019-2029 geekidea(https://github.com/geekidea)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
io
.
geekidea
.
springbootplus
.
test
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
/**
* @author geekidea
* @date 2020/3/16
**/
public
class
MapTest
{
public
static
void
main
(
String
[]
args
)
{
Map
<
String
,
Set
<
String
>>
hashMap
=
new
ConcurrentHashMap
<>();
Set
<
String
>
sets
=
new
HashSet
<>();
sets
.
add
(
"hi"
);
hashMap
.
put
(
"a1"
,
sets
);
sets
.
add
(
"hi2"
);
}
}
common/src/main/java/com/wecloud/im/ws/model/
UserSession
.java
→
common/src/main/java/com/wecloud/im/ws/model/
ClientInfo
.java
View file @
d9ac2d80
package
com
.
wecloud
.
im
.
ws
.
model
;
package
com
.
wecloud
.
im
.
ws
.
model
;
import
io.netty.channel.socket.nio.NioSocketChannel
;
import
lombok.Data
;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.io.Serializable
;
/**
* 连接的client信息
*/
@Data
@Data
public
class
UserSession
implements
Serializable
{
public
class
ClientInfo
implements
Serializable
{
private
NioSocketChannel
nioSocketChannel
;
/**
/**
*
通道id
*
设备ID
*/
*/
private
String
channel
Id
;
private
String
device
Id
;
/**
* 设备类型
*/
private
String
deviceType
;
private
String
deviceType
;
/**
* 设备推送token
*/
private
String
deviceToken
;
private
String
deviceToken
;
/**
* 登陆token
*/
private
String
token
;
private
String
token
;
}
}
common/src/main/java/com/wecloud/im/ws/service/MangerChannelService.java
View file @
d9ac2d80
package
com
.
wecloud
.
im
.
ws
.
service
;
package
com
.
wecloud
.
im
.
ws
.
service
;
import
com.wecloud.im.ws.model.
UserSession
;
import
com.wecloud.im.ws.model.
ClientInfo
;
import
io.netty.channel.ChannelHandlerContext
;
import
io.netty.channel.ChannelHandlerContext
;
import
io.netty.channel.socket.nio.NioSocketChannel
;
import
io.netty.channel.socket.nio.NioSocketChannel
;
import
io.netty.util.AttributeKey
;
import
io.netty.util.AttributeKey
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
/**
/**
...
@@ -23,11 +23,15 @@ public interface MangerChannelService {
...
@@ -23,11 +23,15 @@ public interface MangerChannelService {
*/
*/
Map
<
String
,
NioSocketChannel
>
CHANNEL_MAP
=
new
ConcurrentHashMap
<>();
Map
<
String
,
NioSocketChannel
>
CHANNEL_MAP
=
new
ConcurrentHashMap
<>();
/**
/**
* 本地维护 uid 对应 channel_shortID
* 本地维护 uid 对应 channel_shortID
*/
*/
Map
<
String
,
List
<
UserSession
>>
USER_SESSION_MAP
=
new
ConcurrentHashMap
<>();
Map
<
String
,
Set
<
String
>>
CLIENTS_MAP
=
new
ConcurrentHashMap
<>();
/**
* channel_shortID对应client端数据
*/
Map
<
String
,
ClientInfo
>
SESSION_INFO_MAP
=
new
ConcurrentHashMap
<>();
/**
/**
* CLIENT_ID,是客户端的字符串id
* CLIENT_ID,是客户端的字符串id
...
...
common/src/main/java/com/wecloud/im/ws/service/impl/MangerChannelServiceImpl.java
View file @
d9ac2d80
package
com
.
wecloud
.
im
.
ws
.
service
.
impl
;
package
com
.
wecloud
.
im
.
ws
.
service
.
impl
;
import
com.wecloud.im.ws.cache.UserCache
;
import
com.wecloud.im.ws.cache.UserCache
;
import
com.wecloud.im.ws.model.ClientInfo
;
import
com.wecloud.im.ws.service.MangerChannelService
;
import
com.wecloud.im.ws.service.MangerChannelService
;
import
io.netty.channel.Channel
;
import
io.netty.channel.Channel
;
import
io.netty.channel.ChannelFuture
;
import
io.netty.channel.ChannelFuture
;
...
@@ -12,6 +13,9 @@ import lombok.extern.slf4j.Slf4j;
...
@@ -12,6 +13,9 @@ import lombok.extern.slf4j.Slf4j;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
import
java.util.HashSet
;
import
java.util.Set
;
/**
/**
* @Description 维护netty用户channel对象
* @Description 维护netty用户channel对象
* @Author hewei hwei1233@163.com
* @Author hewei hwei1233@163.com
...
@@ -21,6 +25,7 @@ import org.springframework.stereotype.Component;
...
@@ -21,6 +25,7 @@ import org.springframework.stereotype.Component;
@Slf4j
@Slf4j
public
class
MangerChannelServiceImpl
implements
MangerChannelService
{
public
class
MangerChannelServiceImpl
implements
MangerChannelService
{
// private final static ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder()
// private final static ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder()
// .setNamePrefix("rpcWrite-").build();
// .setNamePrefix("rpcWrite-").build();
/**
/**
...
@@ -53,7 +58,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
...
@@ -53,7 +58,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
@Override
@Override
public
NioSocketChannel
get
(
String
appKey
,
String
clientId
)
{
public
NioSocketChannel
get
(
String
appKey
,
String
clientId
)
{
return
MangerChannelService
.
CHANNEL_MAP
.
get
(
appKey
+
clientId
);
return
this
.
CHANNEL_MAP
.
get
(
appKey
+
clientId
);
}
}
@Override
@Override
...
@@ -66,9 +71,33 @@ public class MangerChannelServiceImpl implements MangerChannelService {
...
@@ -66,9 +71,33 @@ public class MangerChannelServiceImpl implements MangerChannelService {
nioSocketChannel
.
close
();
nioSocketChannel
.
close
();
}
}
MangerChannelService
.
CHANNEL_MAP
.
put
(
appKey
+
clientId
,
channel
);
this
.
CHANNEL_MAP
.
put
(
appKey
+
clientId
,
channel
);
String
ShortChannelId
=
channel
.
id
().
asShortText
();
this
.
putClientsMap
(
appKey
,
clientId
,
ShortChannelId
);
this
.
putSessionInfoMap
(
ShortChannelId
,
channel
);
}
void
putSessionInfoMap
(
String
ShortChannelId
,
NioSocketChannel
channel
)
{
ClientInfo
clientInfo
=
new
ClientInfo
();
clientInfo
.
setDeviceId
(
""
);
clientInfo
.
setDeviceType
(
""
);
clientInfo
.
setDeviceToken
(
""
);
clientInfo
.
setNioSocketChannel
(
channel
);
clientInfo
.
setToken
(
""
);
this
.
SESSION_INFO_MAP
.
put
(
ShortChannelId
,
clientInfo
);
}
void
putClientsMap
(
String
appKey
,
String
clientId
,
String
ShortChannelId
)
{
Set
<
String
>
set
=
this
.
CLIENTS_MAP
.
get
(
appKey
+
":"
+
clientId
);
if
(
set
.
isEmpty
())
{
HashSet
<
String
>
shortChannelId
=
new
HashSet
<>();
shortChannelId
.
add
(
ShortChannelId
);
this
.
CLIENTS_MAP
.
put
(
appKey
+
":"
+
clientId
,
shortChannelId
);
}
else
{
set
.
add
(
ShortChannelId
);
}
}
}
@Override
@Override
...
@@ -85,7 +114,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
...
@@ -85,7 +114,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
String
userId
=
String
.
valueOf
(
this
.
getInfoByChannel
(
channelHandlerContext
));
String
userId
=
String
.
valueOf
(
this
.
getInfoByChannel
(
channelHandlerContext
));
userCache
.
offline
(
userId
);
userCache
.
offline
(
userId
);
log
.
info
(
"不活跃remove,uid:"
+
userId
);
log
.
info
(
"不活跃remove,uid:"
+
userId
);
MangerChannelService
.
CHANNEL_MAP
.
remove
(
userId
);
this
.
CHANNEL_MAP
.
remove
(
userId
);
channelHandlerContext
.
channel
().
close
();
channelHandlerContext
.
channel
().
close
();
}
}
}
}
...
...
docs/md/内部/wecloud-im服务端REST API对接文档.md
View file @
d9ac2d80
# wec
loud-im服务端REST API对接文档
# wec
loud-im服务端REST API对接文档
...
@@ -168,4 +168,3 @@ curl -X PUT \
...
@@ -168,4 +168,3 @@ curl -X PUT \
### 移除对话黑名单
### 移除对话黑名单
### 查询对话黑名单
### 查询对话黑名单
docs/md/客户/wecloud-im即时通讯聊天云服务_外部客户对接文档.md
View file @
d9ac2d80
# wec
loud-im 即时通讯云对接文档
# wec
loud-im 即时通讯云对接文档
...
@@ -95,7 +95,7 @@ appKey为应用在蔚可云的唯一标识, appSecret为安全密钥, 均由蔚
...
@@ -95,7 +95,7 @@ appKey为应用在蔚可云的唯一标识, appSecret为安全密钥, 均由蔚
### 生成sign签名
### 生成sign签名
sign 由接入方后端生成, 进行加签的参数: MD5{timestamp + clientId + appKey + appSecret}
sign 由接入方后端生成, 进行加签的参数: MD5{timestamp + clientId + appKey + appSecret}
timestamp:毫秒时间戳
timestamp:毫秒时间戳
clientId:由后端生成
clientId:由后端生成
...
@@ -151,7 +151,7 @@ clientId:由后端生成
...
@@ -151,7 +151,7 @@ clientId:由后端生成
```
java
```
java
import
org.springframework.util.DigestUtils
;
import
org.springframework.util.DigestUtils
;
private
void
getSign
(
String
timestamp
,
String
clientId
,
String
appKey
,
String
appSecret
)
{
private
void
getSign
(
String
timestamp
,
String
clientId
,
String
appKey
,
String
appSecret
)
{
String
data
=
timestamp
+
clientId
+
appKey
+
appSecret
;
String
data
=
timestamp
+
clientId
+
appKey
+
appSecret
;
String
sign
=
DigestUtils
.
md5DigestAsHex
(
data
.
getBytes
());
String
sign
=
DigestUtils
.
md5DigestAsHex
(
data
.
getBytes
());
}
}
...
@@ -197,10 +197,43 @@ public static void main(String[] args) {
...
@@ -197,10 +197,43 @@ public static void main(String[] args) {
wecloud为提供
**HTTPS**
,以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性,。HTTPS 在HTTP 的基础下加入
**SSL**
,HTTPS 的安全基础是 SSL,。保障终端设备到服务器传输时的数据安全,不被窃取.
wecloud为提供
**HTTPS**
,以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性,。HTTPS 在HTTP 的基础下加入
**SSL**
,HTTPS 的安全基础是 SSL,。保障终端设备到服务器传输时的数据安全,不被窃取.
## IOS推送指南
客户方将应用APNS证书上传至wecloud控制台
## Android 混合推送开发指南
### 混合推送概述
自 Android 8.0 之后,系统权限控制越来越严,第三方推送通道的生命周期受到较大限制;同时,国内主流厂商也开始推出自己独立的推送服务,而厂商间千差万别的繁杂接口徒增了开发和代码维护的难度。为此,我们推出了混合推送的方案。我们逐一对接国内主流厂商,将它们不同的接口隐藏起来,让开发者通过统一的 API 完成推送任务。这不仅大幅降低了开发复杂度,还保障了主流 Android 系统上的推送到达率。
在混合推送方案里,消息下发时使用的通道不再是我们自己维持的 WebSocket 长连接,而是借用厂商和 OS 层的系统通道进行通信。一条推送消息下发的步骤如下:
1.
开发者调用云服务 Push API 请求对全部或特定设备进行推送;
2.
云推送服务端将请求转发给厂商的推送接口;
3.
厂商通过手机端的系统通道下发推送消息,同时手机端系统消息接收器将推送消息展示到通知栏;
4.
终端用户点击消息之后唤起目标应用或者页面。
整个流程与苹果的 APNs 推送类似,SDK 在客户端基本不会得到调用,消息的下发和展示都依赖厂商客户端的行为。所以如果部分厂商在某些推送中夹带了其他非开发者提交的消息,或者在服务启用的时候,有额外营销性质的弹窗,这都是厂商自己的行为,与我们完全无关,还请大家了解。另外,如果开发者碰到厂商 SDK 的问题,我们也无法深入调查,还请大家自行到厂商的论坛或技术支持渠道咨询解决。
Android 混合推送功能仅对商用版应用开放,如果希望使用该功能,请进入
**云服务控制台 > 推送 > 设置 > 混合推送**
,打开混合推送的开关。
注意,混合推送可以随时按需开关。当该选项关闭后,下一次 Android 推送会与普通推送一样自动选择自有通道送达客户端,除了会再次遇到上面提到的自有通道在部分 ROM 上会受到限制的问题之外,不会有别的影响。而当该选项再次开启后,Android 推送又会去选择厂商推送渠道。
开启了混合推送之后,Installation 表中每一个设备对应的记录,会增加一个 vendor 字段(如果没有这一字段,则说明客户端集成有问题),其值分别为:+
| vendor | 厂商 |
| :----- | :--------------------- |
|
`HMS`
| 华为 HMS 推送 |
|
`mi`
| 小米推送 |
|
`mz`
| 魅族推送 |
|
`oppo`
| Oppo 推送 |
|
`vivo`
| VIVO 推送 |
|
`fcm`
| FCM 推送(仅限国际版) |
注意,混合推送对接的是厂商各自的推送服务,需要单独配置,不支持混用。 通常情况下,需要提交不同的版本(分别对接厂商的推送服务)到相应厂商的应用商店。 如果希望使用统一版本,那么需要自行判断手机型号,在手机上开启对应的推送。
## 富媒体消息
## 富媒体消息
为了方便开发者的使用,我们提供了几种封装好的基于 JSON 格式的富媒体消息类型(
`TypedMessage`
),譬如:
为了方便开发者的使用,我们提供了几种封装好的基于 JSON 格式的富媒体消息类型(
`TypedMessage`
),譬如:
...
@@ -212,8 +245,7 @@ wecloud为提供**HTTPS**,以安全为目标的 HTTP 通道,在HTTP的基础
...
@@ -212,8 +245,7 @@ wecloud为提供**HTTPS**,以安全为目标的 HTTP 通道,在HTTP的基础
-
位置(
`LocationMessage`
)
-
位置(
`LocationMessage`
)
### 自定义类型消息
## 自定义类型消息
如发送红包 转账通知 好友验证等等
如发送红包 转账通知 好友验证等等
...
...
安装中间件.md
View file @
d9ac2d80
## 本地
redis
## 本地
redis
...
@@ -8,4 +8,7 @@ docker run -p 3306:3306 --name mysql57 -v $PWD/dockerData/mysql57/data:/var/lib/
...
@@ -8,4 +8,7 @@ docker run -p 3306:3306 --name mysql57 -v $PWD/dockerData/mysql57/data:/var/lib/
## 本地建库语句
## 本地建库语句
CREATE DATABASE IF NOT EXISTS wecloud_im DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS wecloud_im DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
## nacos
## nacos
\ No newline at end of file
RabbitMQ
\ No newline at end of file
开发记录.md
View file @
d9ac2d80
...
@@ -301,6 +301,9 @@ com.xteng.Hibro 123456
...
@@ -301,6 +301,9 @@ com.xteng.Hibro 123456
飞蛙测试外网
https://testws.frogsell.com/api/doc.html#/home
国内IM集成版
国内IM集成版
正式环境
正式环境
121.
37.208.9
121.
37.208.9
...
@@ -318,33 +321,33 @@ web示例:
...
@@ -318,33 +321,33 @@ web示例:
imwebtest.wecloud.cn
imwebtest.wecloud.cn
2021年11月05日 <<
## 多端在线 + 服务器集群
## 多端在线 + 服务器集群
本地维护 uid 对应 channel_shortID
本地维护 uid 对应 channel_shortID
map
<String
id
,
set
<
channelId
>
>>
1123=
[
channelId_ababab1,channelId_ababab2,channelId_ababab3
]
1123:{
channel_shortID对应client端数据
channelId = ababab1 ,
map
<String
channelId
,
ChannelInfo
>
channelId_ababab1:{
deviceTypeId =23123,
deviceType = ios,
deviceType = ios,
deviceToken = abdsbsn,
deviceToken = abdsbsn,
token = sjn321sdjfsdf
token = sjn321sdjfsdf
}
}
1123:{
channelId_ababab1:{
channelId = ababab2 ,
deviceType = android,
deviceType = android,
deviceToken = abdsbsn,
deviceToken = abdsbsn,
token = sjn321sdjfsdf
token = sjnsdj123fsdf
}
}
channelId_ababab1:{
1123:{
deviceType = web,
channelId = ababab3 ,
deviceToken = abdsbsn,
deviceType = web,
token = null
deviceToken = abdsb123sn,
token = null
}
}
2021年11月05日 >>
\ No newline at end of file
飞蛙测试外网
https://testws.frogsell.com/api/doc.html#/home
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment