Skip to content

Commit e8603f6

Browse files
authored
Merge pull request #59 from simple-robot/dev/support-without-ws
允许不启用WebSocket连接
2 parents 39de294 + d04dd43 commit e8603f6

File tree

5 files changed

+317
-26
lines changed

5 files changed

+317
-26
lines changed

Writerside/topics/OneBot11.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,10 @@ OneBot组件选择使用
1313
作为事件订阅的方式。
1414

1515
简单来说,就是不论是API交互还是事件订阅,都由OneBot组件作为**主动方**:主动发起HTTP请求、主动发起WebSocket连接。
16+
17+
## 反向?
18+
19+
如果你真的想要通过反向HTTP来接收事件推送,那么你需要自行搭建 HTTP 服务端,然后使用 `OneBotBot.push` 手动推送原始事件的JSON字符串。
20+
你可以前往参考
21+
`OneBotBot`
22+
<a href="onebot11-OneBotBot.md#外部事件" /> 。

Writerside/topics/onebot11-OneBotBot.md

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,264 @@ public class MyComponent {
469469
有关事件的更多内容参考
470470
<a href="onebot11-event.md" /> 。
471471
</warning>
472+
473+
474+
## 外部事件
475+
476+
`OneBotBot` 提供了 `push(String)` 来允许直接从外部推送一个原始的事件字符串。
477+
478+
<tabs group="code">
479+
<tab title="Kotlin" group-key="Kotlin">
480+
481+
```Kotlin
482+
val json = """
483+
{
484+
"time": 1515204254,
485+
"self_id": 10001000,
486+
"post_type": "message",
487+
"message_type": "private",
488+
"sub_type": "friend",
489+
"message_id": 12,
490+
"user_id": 12345678,
491+
"message": "你好~",
492+
"raw_message": "你好~",
493+
"font": 456,
494+
"sender": {
495+
"nickname": "小不点",
496+
"sex": "male",
497+
"age": 18
498+
}
499+
}
500+
"""
501+
502+
bot.push(json).collect()
503+
```
504+
505+
</tab>
506+
<tab title="Java" group-key="Java">
507+
508+
```Java
509+
var json = """
510+
{
511+
"time": 1515204254,
512+
"self_id": 10001000,
513+
"post_type": "message",
514+
"message_type": "private",
515+
"sub_type": "friend",
516+
"message_id": 12,
517+
"user_id": 12345678,
518+
"message": "你好~",
519+
"raw_message": "你好~",
520+
"font": 456,
521+
"sender": {
522+
"nickname": "小不点",
523+
"sex": "male",
524+
"age": 18
525+
}
526+
}
527+
"""
528+
529+
// 推送并在异步中处理
530+
bot.pushAndLaunch(json);
531+
```
532+
533+
由于 `bot.push` 返回的结果是 `Flow`, 因此 Java 中想要直接使用它会比较困难。
534+
你可以先通过 `Collectables.valueOf(flow)` 将其转化为 `Collectable` (与关系对象相关API的结果类型一样),
535+
然后再做进一步操作。
536+
537+
538+
```java
539+
var collectable = Collectables.valueOf(flow);
540+
// 使用 collectAsync 异步遍历
541+
// 或者 Collectables 中提供的各种辅助API
542+
// 或者 transform 转化为其他的类型,比如响应式的 Flux
543+
```
544+
545+
</tab>
546+
</tabs>
547+
548+
> 示例JSON来自
549+
> https://github.com/botuniverse/onebot-11/blob/master/communication/http-post.md
550+
551+
这可以让你能够使用**反向事件推送**来接收事件,比如通过接收来自 HTTP 的事件推送请求。
552+
553+
简单示例:
554+
555+
<tabs>
556+
<tab title="Ktor">
557+
558+
```kotlin
559+
suspend fun main() {
560+
val application = launchSimpleApplication {
561+
useOneBot11()
562+
}
563+
// 注册事件省略...
564+
565+
// 注册bot并启动
566+
val bot = application.oneBot11Bots {
567+
register {
568+
// 内容省略
569+
}.apply { start() }
570+
}
571+
572+
// 启动一个Ktor Server
573+
embeddedServer(Netty, port = 5959, module = { serverModule(bot) })
574+
.start(wait = true)
575+
}
576+
577+
fun io.ktor.server.application.Application.serverModule(bot: OneBotBot) {
578+
routing {
579+
post("/event") {
580+
// 收到事件,推送并在异步中处理
581+
// 你也可以选择直接 push(body).collect(),
582+
// 直到事件被完全处理后在返回
583+
val body = call.receiveText()
584+
bot.pushAndLaunch(body)
585+
586+
// 响应一个默认的空JSON结果
587+
call.response.header(HttpHeaders.ContentType, "application/json")
588+
call.respond("{}")
589+
}
590+
}
591+
}
592+
```
593+
594+
</tab>
595+
<tab title="Spring Boot Web">
596+
597+
```java
598+
@RestController
599+
public class MyController {
600+
private final Application application;
601+
602+
// 一个简单的返回值类型,假设始终返回空JSON {}
603+
public record Result() {
604+
}
605+
606+
private static final Result OK = new Result();
607+
608+
public MyController(Application application) {
609+
this.application = application;
610+
}
611+
612+
/**
613+
* 通过 /xxx/event 接收事件,
614+
* xxx 为你bot配置的 uniqueBotId
615+
*/
616+
@PostMapping("/{botId}/event")
617+
public Result onEvent(@PathVariable String botId, @RequestBody String body) {
618+
for (var botManager : application.getBotManagers()) {
619+
if (botManager instanceof OneBotBotManager obManager) {
620+
// 找到这个bot
621+
var bot = obManager.find(Identifies.of(botId));
622+
// 如果有就推送这个事件并退出寻找
623+
if (bot != null) {
624+
// 推送事件并在异步中处理
625+
// 你也可以参考上面有关 Flux 和 Collectable 的说明
626+
// 来阻塞地等待事件处理完成后再返回
627+
bot.pushAndLaunch(body);
628+
break;
629+
}
630+
}
631+
}
632+
633+
return OK;
634+
}
635+
}
636+
```
637+
638+
</tab>
639+
<tab title="Spring Boot WebFlux">
640+
641+
<tabs>
642+
<tab title="异步处理">
643+
644+
如果选择直接异步处理,那么其实跟 Spring Boot Web 的情况下没什么太大区别。
645+
646+
```java
647+
@RestController
648+
public class MyController {
649+
private final Application application;
650+
651+
public record Result() {
652+
}
653+
654+
private static final Result OK = new Result();
655+
656+
public MyController(Application application) {
657+
this.application = application;
658+
}
659+
660+
/**
661+
* 通过 /xxx/event 接收事件,
662+
* xxx 为你bot配置的 uniqueBotId
663+
*/
664+
@PostMapping("/{botId}/event")
665+
public Mono<Result> onEvent(@PathVariable String botId, @RequestBody String body) {
666+
for (var botManager : application.getBotManagers()) {
667+
if (botManager instanceof OneBotBotManager obManager) {
668+
// 找到这个bot
669+
var bot = obManager.find(Identifies.of(botId));
670+
// 如果有就推送这个事件并退出寻找
671+
if (bot != null) {
672+
bot.pushAndLaunch(body);
673+
break;
674+
}
675+
}
676+
}
677+
678+
return Mono.just(OK);
679+
}
680+
}
681+
```
682+
683+
</tab>
684+
<tab title="顺序响应式处理">
685+
686+
```java
687+
@RestController
688+
public class MyController {
689+
private final Application application;
690+
691+
public record Result() {
692+
}
693+
694+
private static final Result OK = new Result();
695+
696+
public MyController(Application application) {
697+
this.application = application;
698+
}
699+
700+
/**
701+
* 通过 /xxx/event 接收事件,
702+
* xxx 为你bot配置的 uniqueBotId
703+
*/
704+
@PostMapping("/{botId}/event")
705+
public Mono<Result> onEvent(@PathVariable String botId, @RequestBody String body) {
706+
for (var botManager : application.getBotManagers()) {
707+
if (botManager instanceof OneBotBotManager obManager) {
708+
// 找到这个bot
709+
var bot = obManager.find(Identifies.of(botId));
710+
// 如果有就推送这个事件并退出寻找
711+
if (bot != null) {
712+
final var flow = bot.push(body);
713+
// 将 flow 转为 reactor 的 Flux
714+
// 需要添加依赖 [[[kotlinx-coroutines-reactor|https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive]]]
715+
return ReactorFlowKt
716+
.asFlux(flow)
717+
.then(Mono.just(OK));
718+
}
719+
}
720+
}
721+
722+
// 没找到,直接返回
723+
return Mono.just(OK);
724+
}
725+
}
726+
```
727+
728+
</tab>
729+
</tabs>
730+
731+
</tab>
732+
</tabs>

Writerside/topics/onebot11-bot-config.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ Bot配置文件通常情况下是配合Spring Boot starter的时候用的。
2424
"botUniqueId": "123456",
2525
// api地址,是个http/https服务器的路径,默认localhost:3000
2626
"apiServerHost": "http://localhost:3000",
27-
// 订阅事件的服务器地址,是个ws/wss路径,默认localhost:3001
27+
// 订阅事件的服务器地址,是个ws/wss路径,默认 `null`
28+
// 如果为 `null` 则不会连接 ws 和订阅事件
2829
"eventServerHost": "ws://localhost:3001",
2930
// 配置的 token,可以是null, 代表同时配置 apiAccessToken 和 eventAccessToken
3031
"accessToken": null,

simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/bot/OneBotBotConfiguration.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,18 @@ public class OneBotBotConfiguration {
119119
}
120120

121121
/**
122-
* 必填属性,订阅事件的目标服务器地址。应当是ws或wss协议。
122+
* 订阅事件的目标服务器地址。应当是ws或wss协议。
123+
* 如果为 `null` 则不启用 ws 连接。
123124
*/
124-
public var eventServerHost: Url = Url("ws://localhost:3001")
125+
public var eventServerHost: Url? = null
125126

126127
/**
127128
* 配置 [eventServerHost]
128129
*
129130
* @see eventServerHost
130131
*/
131-
public fun setEventServerHost(urlString: String) {
132-
eventServerHost = Url(urlString)
132+
public fun setEventServerHost(urlString: String?) {
133+
eventServerHost = urlString?.let { Url(it) }
133134
}
134135

135136
/**

0 commit comments

Comments
 (0)