Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
8be791c4
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8be791c4
编写于
12月 17, 2016
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add reactive WebSocketClient and RxNetty implementation
Issue: SPR-14527
上级
bcf6f6e7
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
192 addition
and
22 deletion
+192
-22
spring-web-reactive/src/main/java/org/springframework/web/reactive/socket/client/RxNettyWebSocketClient.java
...rk/web/reactive/socket/client/RxNettyWebSocketClient.java
+121
-0
spring-web-reactive/src/main/java/org/springframework/web/reactive/socket/client/WebSocketClient.java
...framework/web/reactive/socket/client/WebSocketClient.java
+48
-0
spring-web-reactive/src/main/java/org/springframework/web/reactive/socket/client/package-info.java
...ingframework/web/reactive/socket/client/package-info.java
+4
-0
spring-web-reactive/src/test/java/org/springframework/web/reactive/socket/server/WebSocketIntegrationTests.java
...web/reactive/socket/server/WebSocketIntegrationTests.java
+19
-22
未找到文件。
spring-web-reactive/src/main/java/org/springframework/web/reactive/socket/client/RxNettyWebSocketClient.java
0 → 100644
浏览文件 @
8be791c4
/*
* Copyright 2002-2016 the original author or authors.
*
* 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
org.springframework.web.reactive.socket.client
;
import
java.net.URI
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.function.Function
;
import
javax.net.ssl.SSLContext
;
import
javax.net.ssl.SSLEngine
;
import
io.netty.buffer.ByteBuf
;
import
io.netty.buffer.ByteBufAllocator
;
import
io.reactivex.netty.protocol.http.client.HttpClient
;
import
io.reactivex.netty.protocol.http.ws.WebSocketConnection
;
import
io.reactivex.netty.protocol.http.ws.client.WebSocketRequest
;
import
reactor.core.publisher.Mono
;
import
reactor.util.function.Tuples
;
import
rx.Observable
;
import
rx.RxReactiveStreams
;
import
org.springframework.core.io.buffer.NettyDataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.web.reactive.socket.WebSocketSession
;
import
org.springframework.web.reactive.socket.adapter.HandshakeInfo
;
import
org.springframework.web.reactive.socket.adapter.RxNettyWebSocketSession
;
/**
* A {@link WebSocketClient} based on RxNetty.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public
class
RxNettyWebSocketClient
implements
WebSocketClient
{
private
final
Function
<
URI
,
HttpClient
<
ByteBuf
,
ByteBuf
>>
httpClientFactory
;
/**
* Default constructor that uses {@link HttpClient#newClient(String, int)}
* to create HTTP client instances when connecting.
*/
public
RxNettyWebSocketClient
()
{
this
(
RxNettyWebSocketClient:
:
createDefaultHttpClient
);
}
/**
* Constructor with a function to create {@link HttpClient} instances.
* @param httpClientFactory factory to create clients
*/
public
RxNettyWebSocketClient
(
Function
<
URI
,
HttpClient
<
ByteBuf
,
ByteBuf
>>
httpClientFactory
)
{
this
.
httpClientFactory
=
httpClientFactory
;
}
private
static
HttpClient
<
ByteBuf
,
ByteBuf
>
createDefaultHttpClient
(
URI
url
)
{
boolean
secure
=
"wss"
.
equals
(
url
.
getScheme
());
int
port
=
url
.
getPort
()
>
0
?
url
.
getPort
()
:
secure
?
443
:
80
;
HttpClient
<
ByteBuf
,
ByteBuf
>
httpClient
=
HttpClient
.
newClient
(
url
.
getHost
(),
port
);
if
(
secure
)
{
try
{
SSLContext
context
=
SSLContext
.
getDefault
();
SSLEngine
engine
=
context
.
createSSLEngine
(
url
.
getHost
(),
port
);
engine
.
setUseClientMode
(
true
);
httpClient
.
secure
(
engine
);
}
catch
(
NoSuchAlgorithmException
ex
)
{
throw
new
IllegalStateException
(
"Failed to create HttpClient for "
+
url
,
ex
);
}
}
return
httpClient
;
}
@Override
public
Mono
<
WebSocketSession
>
connect
(
URI
url
)
{
return
connect
(
url
,
new
HttpHeaders
());
}
@Override
public
Mono
<
WebSocketSession
>
connect
(
URI
url
,
HttpHeaders
headers
)
{
HandshakeInfo
info
=
new
HandshakeInfo
(
url
,
headers
,
Mono
.
empty
());
Observable
<
WebSocketSession
>
observable
=
connectInternal
(
info
);
return
Mono
.
from
(
RxReactiveStreams
.
toPublisher
(
observable
));
}
private
Observable
<
WebSocketSession
>
connectInternal
(
HandshakeInfo
info
)
{
return
createWebSocketRequest
(
info
.
getUri
())
.
flatMap
(
response
->
{
ByteBufAllocator
allocator
=
response
.
unsafeNettyChannel
().
alloc
();
NettyDataBufferFactory
bufferFactory
=
new
NettyDataBufferFactory
(
allocator
);
Observable
<
WebSocketConnection
>
conn
=
response
.
getWebSocketConnection
();
return
Observable
.
zip
(
conn
,
Observable
.
just
(
bufferFactory
),
Tuples:
:
of
);
})
.
map
(
tuple
->
{
WebSocketConnection
conn
=
tuple
.
getT1
();
NettyDataBufferFactory
bufferFactory
=
tuple
.
getT2
();
return
new
RxNettyWebSocketSession
(
conn
,
info
,
bufferFactory
);
});
}
private
WebSocketRequest
<
ByteBuf
>
createWebSocketRequest
(
URI
url
)
{
String
query
=
url
.
getRawQuery
();
return
this
.
httpClientFactory
.
apply
(
url
)
.
createGet
(
url
.
getRawPath
()
+
(
query
!=
null
?
"?"
+
query
:
""
))
.
requestWebSocketUpgrade
();
}
}
spring-web-reactive/src/main/java/org/springframework/web/reactive/socket/client/WebSocketClient.java
0 → 100644
浏览文件 @
8be791c4
/*
* Copyright 2002-2016 the original author or authors.
*
* 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
org.springframework.web.reactive.socket.client
;
import
java.net.URI
;
import
reactor.core.publisher.Mono
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.web.reactive.socket.WebSocketSession
;
/**
* Contract for starting a WebSocket interaction.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public
interface
WebSocketClient
{
/**
* Start a WebSocket interaction to the given url.
* @param url the handshake url
* @return the session for the WebSocket interaction
*/
Mono
<
WebSocketSession
>
connect
(
URI
url
);
/**
* Start a WebSocket interaction to the given url.
* @param url the handshake url
* @param headers headers for the handshake request
* @return the session for the WebSocket interaction
*/
Mono
<
WebSocketSession
>
connect
(
URI
url
,
HttpHeaders
headers
);
}
spring-web-reactive/src/main/java/org/springframework/web/reactive/socket/client/package-info.java
0 → 100644
浏览文件 @
8be791c4
/**
* Client support for WebSocket interactions.
*/
package
org.springframework.web.reactive.socket.client
;
spring-web-reactive/src/test/java/org/springframework/web/reactive/socket/server/
Server
WebSocketIntegrationTests.java
→
spring-web-reactive/src/test/java/org/springframework/web/reactive/socket/server/WebSocketIntegrationTests.java
浏览文件 @
8be791c4
...
...
@@ -15,24 +15,22 @@
*/
package
org.springframework.web.reactive.socket.server
;
import
java.n
io.charset.StandardCharsets
;
import
java.n
et.URI
;
import
java.util.HashMap
;
import
java.util.Map
;
import
io.netty.handler.codec.http.websocketx.TextWebSocketFrame
;
import
io.netty.handler.codec.http.websocketx.WebSocketFrame
;
import
io.reactivex.netty.protocol.http.client.HttpClient
;
import
io.reactivex.netty.protocol.http.ws.client.WebSocketResponse
;
import
org.junit.Test
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
rx.Observable
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.web.reactive.HandlerMapping
;
import
org.springframework.web.reactive.handler.SimpleUrlHandlerMapping
;
import
org.springframework.web.reactive.socket.WebSocketHandler
;
import
org.springframework.web.reactive.socket.WebSocketSession
;
import
org.springframework.web.reactive.socket.client.RxNettyWebSocketClient
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
...
...
@@ -42,7 +40,7 @@ import static org.junit.Assert.assertEquals;
* @author Rossen Stoyanchev
*/
@SuppressWarnings
({
"unused"
,
"WeakerAccess"
})
public
class
Server
WebSocketIntegrationTests
extends
AbstractWebSocketIntegrationTests
{
public
class
WebSocketIntegrationTests
extends
AbstractWebSocketIntegrationTests
{
@Override
...
...
@@ -54,21 +52,20 @@ public class ServerWebSocketIntegrationTests extends AbstractWebSocketIntegratio
@Test
public
void
echo
()
throws
Exception
{
int
count
=
100
;
Observable
<
String
>
input
=
Observable
.
range
(
1
,
count
).
map
(
index
->
"msg-"
+
index
);
Observable
<
String
>
output
=
HttpClient
.
newClient
(
"localhost"
,
this
.
port
)
.
createGet
(
"/echo"
)
.
requestWebSocketUpgrade
()
.
flatMap
(
WebSocketResponse:
:
getWebSocketConnection
)
.
flatMap
(
conn
->
conn
.
write
(
input
.
map
(
TextWebSocketFrame:
:
new
)).
cast
(
WebSocketFrame
.
class
)
.
mergeWith
(
conn
.
getInput
())
.
take
(
count
)
.
map
(
frame
->
{
String
text
=
frame
.
content
().
toString
(
StandardCharsets
.
UTF_8
);
frame
.
release
();
return
text
;
}));
assertEquals
(
input
.
toList
().
toBlocking
().
first
(),
output
.
toList
().
toBlocking
().
first
());
Flux
<
String
>
input
=
Flux
.
range
(
1
,
count
).
map
(
index
->
"msg-"
+
index
);
Flux
<
String
>
output
=
new
RxNettyWebSocketClient
()
.
connect
(
new
URI
(
"ws://localhost:"
+
this
.
port
+
"/echo"
))
.
flatMap
(
session
->
session
.
send
(
input
.
map
(
session:
:
textMessage
))
.
thenMany
(
session
.
receive
()
.
take
(
count
)
.
map
(
message
->
{
String
text
=
message
.
getPayloadAsText
();
DataBufferUtils
.
release
(
message
.
getPayload
());
return
text
;
})
));
assertEquals
(
input
.
collectList
().
blockMillis
(
5000
),
output
.
collectList
().
blockMillis
(
5000
));
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录