Skip to content

Commit 8beddf4

Browse files
committed
feat(docker): Add QR code login support and Docker environment detection
- Add Docker environment detection utility to check for /.dockerenv file - Implement QR code generation and display for login in Docker containers - Add qrcode and @types/qrcode dependencies to package.json - Generate QR code as both terminal output and PNG file for Docker login flow - Update Docker build scripts and Dockerfiles to create /.dockerenv marker - Configure Vite alias for qrcode server module - Display login QR code URL for browser-based scanning when running in Docker - Trigger QR code display only once during initial login check in Docker environment
1 parent 1ef3053 commit 8beddf4

File tree

7 files changed

+54
-2
lines changed

7 files changed

+54
-2
lines changed

docker/Dockerfile.local

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ COPY --from=builder /app/dist .
3535
COPY docker/startup.sh /startup.sh
3636
RUN chmod +x /startup.sh
3737

38+
RUN touch /.dockerenv
39+
3840
ENTRYPOINT ["/startup.sh"]

docker/debug-build-amd64.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
docker buildx build -f docker/debug.Dockerfile --progress=plain --platform linux/amd64 -t linyuchen/llonebot .
1+
docker buildx build -f docker/debug.Dockerfile --progress=plain --platform linux/amd64 -t linyuchen/llbot .

docker/debug.Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ COPY docker/startup.sh /startup.sh
2121

2222
RUN chmod +x /startup.sh
2323

24+
RUN touch /.dockerenv
25+
2426
#RUN wget https://github.com/LLOneBot/LLOneBot/releases/download/v$LLONEBOT_VERSION/LLOneBot.zip -O /app/llonebot.zip
2527

2628
COPY /dist /app/llonebot

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"minato": "^3.7.0",
3535
"multer": "^2.0.2",
3636
"nodemailer": "^8.0.1",
37+
"qrcode": "^1.5.4",
3738
"silk-wasm": "^3.7.1",
3839
"ws": "^8.19.0",
3940
"zod": "^4.3.6"
@@ -45,6 +46,7 @@
4546
"@types/multer": "^2.0.0",
4647
"@types/node": "^24.10.11",
4748
"@types/nodemailer": "^7.0.10",
49+
"@types/qrcode": "^1.5.6",
4850
"@types/ws": "^8.18.1",
4951
"supports-color": "^10.2.2",
5052
"ts-case-convert": "^2.1.0",

src/common/utils/environment.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { existsSync } from "fs"
2+
3+
export function isDockerEnvironment(): boolean {
4+
try {
5+
return existsSync('/.dockerenv')
6+
} catch {
7+
return false
8+
}
9+
}

src/main/main.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import path from 'node:path'
2+
import { writeFile } from 'node:fs/promises'
3+
import QRCode from 'qrcode'
24

35
// 全局异常处理,防止未捕获的异常导致程序崩溃
46
process.on('uncaughtException', (err) => {
@@ -42,6 +44,7 @@ import { pmhq } from '@/ntqqapi/native/pmhq'
4244
import { sleep } from '@/common/utils'
4345
import EmailNotificationService from '@/common/emailNotification'
4446
import { EmailConfig } from '@/common/emailConfig'
47+
import { isDockerEnvironment } from '@/common/utils/environment'
4548

4649
declare module 'cordis' {
4750
interface Events {
@@ -51,6 +54,8 @@ declare module 'cordis' {
5154
}
5255

5356

57+
58+
5459
async function onLoad() {
5560
if (!existsSync(DATA_DIR)) {
5661
mkdirSync(DATA_DIR, { recursive: true })
@@ -107,6 +112,33 @@ async function onLoad() {
107112
ctx.plugin(EmailNotificationService)
108113
}
109114

115+
const isDocker = isDockerEnvironment()
116+
let qrCodeTriggered = false
117+
118+
const printLoginQrCode = async () => {
119+
try {
120+
const data = await ctx.ntLoginApi.getLoginQrCode()
121+
122+
const qrText = await QRCode.toString(data.qrcodeUrl, { type: 'terminal', small: true })
123+
console.log('\n========== 请使用手机QQ扫描二维码登录 ==========')
124+
console.log(qrText)
125+
console.log('================================================\n')
126+
127+
const base64Data = data.pngBase64QrcodeData.replace(/^data:image\/png;base64,/, '')
128+
const qrFilePath = path.join(TEMP_DIR, 'login-qrcode.png')
129+
if (!existsSync(TEMP_DIR)) {
130+
mkdirSync(TEMP_DIR, { recursive: true })
131+
}
132+
await writeFile(qrFilePath, Buffer.from(base64Data, 'base64'))
133+
ctx.logger.info(`二维码文件已保存: ${qrFilePath}`)
134+
135+
const qrWebUrl = `https://api.2dcode.biz/v1/create-qr-code?data=${encodeURIComponent(data.qrcodeUrl)}`
136+
ctx.logger.info(`或浏览器打开二维码网址: ${qrWebUrl}`)
137+
} catch (e) {
138+
ctx.logger.warn('获取登录二维码失败', e)
139+
}
140+
}
141+
110142
const checkLogin = async () => {
111143
let pmhqSelfInfo = { ...selfInfo }
112144
try {
@@ -117,6 +149,10 @@ async function onLoad() {
117149
return
118150
}
119151
if (!pmhqSelfInfo.online) {
152+
if (isDocker && !qrCodeTriggered) {
153+
qrCodeTriggered = true
154+
printLoginQrCode()
155+
}
120156
setTimeout(checkLogin, 1000)
121157
return
122158
}

vite.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,9 @@ export default defineConfig({
8181
},
8282
resolve: {
8383
alias: {
84-
'@': '/src', // 可选:配置路径别名
84+
'@': '/src',
8585
'supports-color': 'node_modules/supports-color/index.js',
86+
'qrcode': 'node_modules/qrcode/lib/server.js',
8687
},
8788
},
8889
})

0 commit comments

Comments
 (0)