Skip to content

Commit db12338

Browse files
authored
Merge pull request #1 from lz1998/master
update
2 parents a372954 + 9826255 commit db12338

File tree

20 files changed

+346
-278
lines changed

20 files changed

+346
-278
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ out/
3737
### MIRAI ###
3838
device.json
3939
src/main/java/onebot/
40+
src/main/java/dto/
4041

4142

4243
### Mac ###

README.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
# Spring-Mirai-Client
2-
可通过HTTP请求创建Mirai QQ机器人,处理登陆验证码、URL等信息
32

4-
本项目(client端)使用 Kotlin 编写(因为 Mirai 是 kotlin 的)
3+
用于收发QQ消息,并通过 websocket + protobuf 上报给 server 进行处理。
54

6-
server 端:可使用任意语言编写
5+
本项目对应前端:https://github.com/protobufbot/spring-mirai-client-ui
76

8-
通信协议:https://github.com/lz1998/onebot/tree/master/v11/specs/idl
7+
server端可以使用任意语言编写,通信协议:https://github.com/lz1998/onebot_idl
98

10-
## TODO
11-
- 整合 onebot 协议,与远程服务器通过 http/websocket/rpc 方式进行通信
12-
- 群/私聊 消息事件 -> protobuf/json
13-
- 接受API调用,执行并返回结果
9+
Java/Kotlin用户推荐使用 [spring-boot-starter](https://github.com/protobufbot/pbbot-spring-boot-starter)
1410

11+
支持发送的消息:文字、表情、图片、闪照、atQQ、atAll
12+
13+
## 使用说明
14+
15+
下载release:https://github.com/ProtobufBot/Spring-Mirai-Client/releases
16+
17+
解压后运行
18+
```bash
19+
java -jar spring-mirai-client-版本.jar
20+
```
21+
22+
浏览器打开 http://localhost:9000/
23+
24+
创建机器人并处理下方验证码(图形验证码或设备锁)
25+
26+
27+
![截图](https://github.com/lz1998/Spring-Mirai-Client/blob/master/screenshot/client.jpg?raw=true)

build.gradle.kts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ plugins {
2626
}
2727

2828
group = "net.lz1998"
29-
version = "0.0.1-SNAPSHOT"
29+
version = "0.0.3"
3030
java.sourceCompatibility = JavaVersion.VERSION_1_8
3131

3232
configurations {
@@ -41,16 +41,19 @@ repositories {
4141
maven(url = "http://maven.aliyun.com/nexus/content/repositories/jcenter")
4242
mavenCentral()
4343
jcenter()
44-
maven(url = "http://repo.spring.io/plugins-release")
44+
// maven(url = "http://repo.spring.io/plugins-release")
4545
maven(url = "https://plugins.gradle.org/m2/")
4646
}
4747

4848
dependencies {
49-
implementation("net.mamoe:mirai-core-qqandroid:1.3.0")
49+
implementation("net.mamoe:mirai-core-qqandroid:1.3.1")
5050
implementation("com.squareup.okhttp3:okhttp:4.8.0")
51-
implementation("com.google.protobuf:protobuf-java:3.12.2")
5251
// implementation("com.google.protobuf:protobuf-javalite:3.8.0")
52+
53+
implementation("com.google.protobuf:protobuf-java:3.12.2")
54+
implementation("com.googlecode.protobuf-java-format:protobuf-java-format:1.4")
5355
implementation("com.google.protobuf:protobuf-java-util:3.12.2")
56+
// implementation("com.googlecode.protobuf:protobuf-java-format:1.2")
5457

5558
implementation("org.springframework.boot:spring-boot-starter-web")
5659
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
@@ -67,7 +70,20 @@ dependencies {
6770
protobuf {
6871
generatedFilesBaseDir = "$projectDir/src"
6972
println(generatedFilesBaseDir)
70-
protoc { artifact = "com.google.protobuf:protoc:3.7.0" }
73+
protoc {
74+
// You still need protoc like in the non-Android case
75+
artifact = "com.google.protobuf:protoc:3.8.0"
76+
}
77+
generateProtoTasks {
78+
all().forEach {
79+
it.builtins{
80+
// remove("java")
81+
// id("java"){
82+
// option("lite")
83+
// }
84+
}
85+
}
86+
}
7187
}
7288
sourceSets {
7389
main {

screenshot/client.jpg

192 KB
Loading

src/main/kotlin/net/lz1998/mirai/SpringMiraiClientApplication.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package net.lz1998.mirai
22

3+
import net.lz1998.mirai.properties.ClientProperties
34
import org.springframework.boot.autoconfigure.SpringBootApplication
5+
import org.springframework.boot.context.properties.EnableConfigurationProperties
46
import org.springframework.boot.runApplication
7+
import org.springframework.context.annotation.Bean
8+
import org.springframework.context.annotation.Configuration
9+
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter
510

611
@SpringBootApplication
12+
@EnableConfigurationProperties(ClientProperties::class)
713
class SpringMiraiClientApplication
814

915
fun main(args: Array<String>) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.lz1998.mirai.config
2+
3+
import org.springframework.context.annotation.Bean
4+
import org.springframework.context.annotation.Configuration
5+
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter
6+
7+
@Configuration
8+
class ProtobufConfig {
9+
@Bean
10+
fun createProtobufConverter(): ProtobufHttpMessageConverter {
11+
return ProtobufHttpMessageConverter();
12+
}
13+
}
Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,40 @@
11
package net.lz1998.mirai.controller
22

3-
import kotlinx.coroutines.runBlocking
3+
import dto.HttpDto
4+
import kotlinx.coroutines.GlobalScope
5+
import kotlinx.coroutines.launch
46
import net.lz1998.mirai.service.BotService
5-
import net.lz1998.mirai.service.LoginDataType
6-
import net.lz1998.mirai.service.myLoginSolver
7+
import net.lz1998.mirai.service.MyLoginSolver
78
import org.springframework.beans.factory.annotation.Autowired
8-
import org.springframework.http.MediaType
9-
import org.springframework.web.bind.annotation.RequestMapping
10-
import org.springframework.web.bind.annotation.RestController
9+
import org.springframework.web.bind.annotation.*
1110

1211
@RestController
12+
@RequestMapping("/bot")
1313
class BotController {
1414

1515
@Autowired
1616
lateinit var botService: BotService
1717

1818

19-
@RequestMapping("/createBot")
20-
fun createBot(botId: Long, password: String): String {
21-
println(botId)
22-
println(password)
23-
runBlocking { // TODO 是否可以优化? suspend报错怎么解决?
24-
botService.createBot(botId, password)
25-
}
26-
return "ok"
19+
// 创建一个机器人并登陆
20+
@RequestMapping("/create/v1", produces = ["application/x-protobuf"], consumes = ["application/x-protobuf"])
21+
fun createBot(@RequestBody param: HttpDto.CreateBotReq): HttpDto.CreateBotResp {
22+
GlobalScope.launch { botService.createBot(param.botId, param.password) }
23+
return HttpDto.CreateBotResp.newBuilder().build()
2724
}
2825

29-
// 通过轮询获取登陆验证url
30-
@RequestMapping("/getLoginUrl")
31-
fun getLoginUrl(botId: Long): String? {
32-
val loginData = myLoginSolver.getLoginData(botId) ?: return null
33-
return if (loginData.type != LoginDataType.PIC_CAPTCHA) {
34-
loginData.url
35-
} else {
36-
null
37-
}
26+
@RequestMapping("/list/v1", produces = ["application/x-protobuf"], consumes = ["application/x-protobuf"])
27+
fun listBot(): HttpDto.ListBotResp {
28+
val botList = botService.listBot()
29+
return HttpDto.ListBotResp.newBuilder().addAllBotList(botList).build()
3830
}
3931

40-
// 通过轮询获取登陆图片验证码
41-
@RequestMapping("/getLoginImage", produces = [MediaType.IMAGE_JPEG_VALUE])
42-
fun getLoginData(botId: Long): ByteArray? {
43-
val loginData = myLoginSolver.getLoginData(botId) ?: return null
44-
return if (loginData.type == LoginDataType.PIC_CAPTCHA) {
45-
loginData.data
46-
} else {
47-
null
32+
@RequestMapping("/login/v1", produces = ["application/x-protobuf"], consumes = ["application/x-protobuf"])
33+
fun botLoginAsync(@RequestBody param: HttpDto.BotLoginAsyncReq): HttpDto.BotLoginAsyncResp {
34+
GlobalScope.launch {
35+
botService.botLogin(param.botId)
4836
}
37+
return HttpDto.BotLoginAsyncResp.newBuilder().build()
4938
}
5039

51-
// 处理登陆
52-
@RequestMapping("/solveLogin")
53-
fun solveLogin(botId: Long, result: String): String {
54-
myLoginSolver.solveLogin(botId, result)
55-
return "ok"
56-
}
5740
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package net.lz1998.mirai.controller
2+
3+
import dto.HttpDto
4+
import net.lz1998.mirai.service.MyLoginSolver
5+
import org.springframework.beans.factory.annotation.Autowired
6+
import org.springframework.web.bind.annotation.RequestBody
7+
import org.springframework.web.bind.annotation.RequestMapping
8+
import org.springframework.web.bind.annotation.RestController
9+
10+
@RestController
11+
@RequestMapping("/captcha")
12+
class CaptchaController {
13+
14+
@Autowired
15+
lateinit var myLoginSolver: MyLoginSolver
16+
17+
@RequestMapping("/list/v1", produces = ["application/x-protobuf"], consumes = ["application/x-protobuf"])
18+
fun getCaptchaList(): HttpDto.GetCaptchaListResp {
19+
val captchaList = myLoginSolver.getCaptchaList()
20+
return HttpDto.GetCaptchaListResp.newBuilder().addAllCaptchaList(captchaList).build()
21+
}
22+
23+
@RequestMapping("/solve/v1", produces = ["application/x-protobuf"], consumes = ["application/x-protobuf"])
24+
fun solveCaptcha(@RequestBody param: HttpDto.SolveCaptchaReq): HttpDto.SolveCaptchaResp {
25+
myLoginSolver.solveLogin(param.botId, param.result)
26+
return HttpDto.SolveCaptchaResp.newBuilder().build()
27+
}
28+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package net.lz1998.mirai.controller
2+
3+
import org.springframework.context.annotation.Configuration
4+
import org.springframework.web.servlet.config.annotation.CorsRegistry
5+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
6+
7+
@Configuration
8+
class CorsConf : WebMvcConfigurer {
9+
override fun addCorsMappings(registry: CorsRegistry) {
10+
registry.addMapping("/**")
11+
//是否发送Cookie
12+
.allowCredentials(true)
13+
//放行哪些原始域
14+
.allowedOrigins("*")
15+
.allowedMethods("GET", "POST", "PUT", "DELETE")
16+
// .allowedHeaders("*")
17+
// .exposedHeaders("*")
18+
19+
}
20+
}

src/main/kotlin/net/lz1998/mirai/entity/RemoteBot.kt

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,17 @@
11
package net.lz1998.mirai.entity
22

3-
import net.lz1998.mirai.ext.messageSourceLru
4-
import net.lz1998.mirai.service.myLoginSolver
53
import net.mamoe.mirai.Bot
6-
import net.mamoe.mirai.alsoLogin
74
import net.mamoe.mirai.event.events.BotEvent
8-
import net.mamoe.mirai.event.subscribeAlways
9-
import net.mamoe.mirai.message.MessageEvent
105
import onebot.OnebotFrame
116

127
interface RemoteBot {
138
var bot: Bot
149
var botId: Long
1510
var password: String
1611

17-
suspend fun initBot() {
18-
bot = Bot(botId, password) {
19-
fileBasedDeviceInfo("device.json")
20-
loginSolver = myLoginSolver
21-
noNetworkLog()
22-
}.alsoLogin()
23-
bot.subscribeAlways<BotEvent> {
24-
onBotEvent(this)
25-
}
26-
bot.subscribeAlways<MessageEvent> {
27-
val messageSource = this.source // 撤回消息用
28-
bot.messageSourceLru.put(messageSource.id, messageSource)
29-
}
30-
}
12+
suspend fun initBot()
13+
14+
suspend fun login()
3115

3216
// 执行并返回结果
3317
suspend fun onRemoteApi(req: OnebotFrame.Frame): OnebotFrame.Frame

0 commit comments

Comments
 (0)