Skip to content

Commit

Permalink
feat: webui
Browse files Browse the repository at this point in the history
  • Loading branch information
BIYUEHU committed Aug 6, 2024
1 parent 17b504d commit 839438b
Show file tree
Hide file tree
Showing 42 changed files with 898 additions and 675 deletions.
4 changes: 2 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- [x] @kotori-bot/webui
- [x] @kotori-bot/kotori-plugin-webui
- [x] @kotori-bot/kotori-plugin-adapter-sandbox
- [X] @kotori-bot/kotori-plugin-adapter-mail (adapter and plugin)
- [x] @kotori-bot/kotori-plugin-adapter-mail (adapter and plugin)
- [x] @kotori-bot/kotori-plugin-adapter-telegram
- [x] @kotori-bot/kotori-plugin-adapter-discord
- [x] kotori-plugin-adapter-minecraft
Expand Down Expand Up @@ -43,5 +43,5 @@
- [x] Module Version with core tips
- [x] Kotori cli start
- [x] kotori-plugin-request: onGroupMsg and onPrivateMsg
- [ ] webui load tips twice
- [x] webui load tips twice
- [x] symbols props inject and reality context
13 changes: 10 additions & 3 deletions modules/adapter-cmd/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
* @Blog: https://hotaru.icu
* @Date: 2023-09-29 14:31:09
* @LastEditors: Hotaru [email protected]
* @LastEditTime: 2024-08-04 12:08:31
* @LastEditTime: 2024-08-06 11:12:35
*/
import { Adapter, type AdapterConfig, type Context, MessageScope, Tsu } from 'kotori-bot'
import { Adapter, type AdapterConfig, type Context, MessageScope, Tsu, type LoggerData } from 'kotori-bot'
import CmdApi from './api'
import CmdElements from './elements'

declare module 'kotori-bot' {
interface EventsMapping {
console_output(data: LoggerData | { msg: string }): void
}
}
export const config = Tsu.Object({
nickname: Tsu.String().default('Kotarou').describe("User's nickname"),
'self-nickname': Tsu.String().default('KotoriO').describe("Bot's nickname"),
Expand Down Expand Up @@ -79,7 +84,9 @@ export class CmdAdapter extends Adapter<CmdApi, CmdConfig, CmdElements> {
if (this.status.value !== 'online' || action !== 'send_private_msg' || !params) return
if (typeof (params as { message: string }).message !== 'string') return
if ((params as { user_id: unknown }).user_id !== this.config.master) return
process.stdout.write(`${this.config['self-nickname']} > ${(params as { message: string }).message} \r\n`)
const msg = `${this.config['self-nickname']} > ${(params as { message: string }).message} \r\n`
process.stdout.write(msg)
this.ctx.emit('console_output', { msg })
this.messageId += 1
}
}
Expand Down
2 changes: 1 addition & 1 deletion modules/adapter-discord/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const config = Tsu.Object({

- text

## Todo
## TODO

Support more standard api...

Expand Down
11 changes: 9 additions & 2 deletions modules/adapter-mail/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ Supports for email. Such as `Google Mail`, `QQ Mail`, `163 Mail` and more...
```typescript
export const config = Tsu.Object({
title: Tsu.String().domain().default('Love from kotori bot mailer').describe('Mail default title'),
commandEnable: Tsu.Boolean()
.default(true)
.describe("Whether to enable command, other bot's master can send mail by the command, please set at top mail bot"),
forward: Tsu.Array(Tsu.String())
.default([])
.describe("bots' identity, will forward to the bot's master on receiving mail, please set at top mail bot"),
user: Tsu.String().describe('Email address'),
interval: Tsu.Number().default(60).describe('Check mail interval (seconds)'),
password: Tsu.String().describe('Email password'),
imapHost: Tsu.String().domain().describe('IMAP server host'),
imapHost: Tsu.String().describe('IMAP server host'),
imapPort: Tsu.Number().describe('IMAP server port'),
smtpHost: Tsu.String().domain().describe('SMTP server host'),
smtpHost: Tsu.String().describe('SMTP server host'),
smtpPort: Tsu.Number().describe('SMTP server port')
})
```
Expand Down
16 changes: 16 additions & 0 deletions modules/adapter-mail/locales/ja_JP.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"adapter_mail.descr.mail": "指定メールアドレスにメールを送信",
"adapter_mail.msg.mail.input_target": "受信メールアドレスを入力してください",
"adapter_mail.msg.mail.input_title": "メールの件名を入力してください",
"adapter_mail.msg.mail.input_content": "メールの内容を入力してください",
"adapter_mail.msg.mail.sure": "件名:{0}\n内容:{1}\n-------------\n{2}にメールを送信しますか?(「1」で送信、他のキーでキャンセル)",
"adapter_mail.msg.mail.cancel": "送信をキャンセルしました",
"adapter_mail.msg.mail.success": "{0}へのメール送信に成功しました",
"adapter_mail.msg.mail.fail": "メール送信に失敗しました。メール設定を確認してください。詳細:{0}",
"adapter_mail.msg.mail.fail.2": "送信メール{0}が見つかりません。「{0}mail --list」で利用可能なメールリストを表示できます",
"adapter_mail.msg.mail.fail.3": "送信失敗。宛先メールアドレスの形式が正しくありません!",
"adapter_mail.msg.mail.item": "\n<=========>\n名前:{0}\nメール:{1}",
"adapter_mail.msg.mail.list": "利用可能なメールリスト:{0}",
"adapter_mail.option.mail.list": "利用可能なメールリストを表示",
"adapter_mail.forward": "新着メールがあります!\n差出人:{0}\n件名:{1}\n内容:{2}\n日付:{3}"
}
16 changes: 16 additions & 0 deletions modules/adapter-mail/locales/zh_CN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"adapter_mail.descr.mail": "通过目标邮箱发送邮件",
"adapter_mail.msg.mail.input_target": "请输入接收邮箱",
"adapter_mail.msg.mail.input_title": "请输入邮件标题",
"adapter_mail.msg.mail.input_content": "请输入邮件内容",
"adapter_mail.msg.mail.sure": "标题:{0}\n内容:{1}\n-------------\n确定发送邮件至{2}?(输入\"1\"发送,其他键取消)",
"adapter_mail.msg.mail.cancel": "成功取消发送",
"adapter_mail.msg.mail.success": "成功发送邮件至{0}",
"adapter_mail.msg.mail.fail": "发送邮件失败,请检查邮件配置,详情:{0}",
"adapter_mail.msg.mail.fail.2": "找不到发送邮箱{0},您可以输入\"{0}mail --list\"查看可用邮箱列表",
"adapter_mail.msg.mail.fail.3": "发送失败,目标邮箱格式错误!",
"adapter_mail.msg.mail.item": "\n<=========>\n名称:{0}\n邮箱:{1}",
"adapter_mail.msg.mail.list": "可用邮箱列表:{0}",
"adapter_mail.option.mail.list": "查看可用邮箱列表",
"adapter_mail.forward": "收到新邮件!\n来自:{0}\n标题:{1}\n内容:{2}\n日期:{3}"
}
135 changes: 73 additions & 62 deletions modules/adapter-mail/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
KotoriError,
Adapter,
Symbols,
formatFactory
formatFactory,
sleep,
type Api
} from 'kotori-bot'
import MailApi from './api'
import MailElements from './elements'
Expand All @@ -23,6 +25,7 @@ export const config = Tsu.Object({
.default([])
.describe("bots' identity, will forward to the bot's master on receiving mail, please set at top mail bot"),
user: Tsu.String().describe('Email address'),
interval: Tsu.Number().default(60).describe('Check mail interval (seconds)'),
password: Tsu.String().describe('Email password'),
imapHost: Tsu.String().describe('IMAP server host'),
imapPort: Tsu.Number().describe('IMAP server port'),
Expand All @@ -35,6 +38,8 @@ type MailConfig = Tsu.infer<typeof config> & AdapterConfig
let isLoaded = false

export class MailAdapter extends Adapter<MailApi, MailConfig, MailElements> {
private timerId?: NodeJS.Timeout

public readonly config: MailConfig

public readonly elements: MailElements = new MailElements(this)
Expand All @@ -60,6 +65,7 @@ export class MailAdapter extends Adapter<MailApi, MailConfig, MailElements> {
}
})
// Loading plugin
this.ctx.inject('db')
if (isLoaded) return
this.ctx.load({
...require('./plugin'),
Expand All @@ -68,7 +74,69 @@ export class MailAdapter extends Adapter<MailApi, MailConfig, MailElements> {
isLoaded = true
}

public handle() {}
public handle() {
const apis: Api[] = []
for (const bots of this.ctx[Symbols.bot].values()) apis.push(...bots)

this.imapConnection?.openBox('INBOX').then(async () => {
const fetchOptions = {
bodies: ['HEADER', 'TEXT'],
markSeen: false
}

const list = await this.ctx.db.get<number[]>('read', [])
const results = ((await this.imapConnection?.search(['UNSEEN'], fetchOptions)) ?? []).filter(
(item) => !list.includes(item.attributes.uid)
)

if (results.length === 0) return
this.ctx.logger.record(/* html */ `<magenta>${results.length} new email(s) received</magenta>`)
for await (const item of results) {
const all = item.parts.filter((part) => part.which === 'TEXT')
const id = item.attributes.uid
list.push(id)

const idHeader = `Imap-Id: ${id}\r\n`
for await (const part of all) {
const email = await simpleParser(idHeader + part.body)
if (!email.text) continue

for (const identity of this.config.forward) {
const api = apis.find((api) => api.adapter.identity === identity)
if (!api) {
this.ctx.emit(
'error',
KotoriError.from(`Failed to forward mail, cant not find ${identity} bot`, this.ctx.identity?.toString())
)
continue
}
api.sendPrivateMsg(
formatFactory(api.adapter.ctx.i18n)('adapter_mail.forward', [
email.from?.text,
email.subject,
email.text,
email.date ? api.adapter.ctx.i18n.date(email.date) : ''
]),
api.adapter.config.master
)
}
this.session('on_message', {
type: MessageScope.PRIVATE,
userId: email.from?.text ?? '',
message: email.text ?? email.subject ?? '',
messageAlt: email.text ?? email.subject ?? '',
messageId: id.toString(),
sender: {
nickname: email.from?.text || ''
},
time: email.date?.getTime() || Date.now()
})
}
}

await this.ctx.db.put('read', list)
})
}

public async start() {
try {
Expand All @@ -81,80 +149,23 @@ export class MailAdapter extends Adapter<MailApi, MailConfig, MailElements> {
tls: true
}
})

await this.imapConnection.openBox('INBOX')

this.imapConnection.on('mail', async (numNewMails: number) => {
console.log(`${numNewMails} new email(s) received`)

const fetchOptions = {
bodies: ['HEADER', 'TEXT'],
markSeen: false
}

const results = (await this.imapConnection?.search(['UNSEEN'], fetchOptions)) ?? []

for (const item of results) {
const all = item.parts.filter((part) => part.which === 'TEXT')
const id = item.attributes.uid
const idHeader = `Imap-Id: ${id}\r\n`

for (const part of all) {
const email = await simpleParser(idHeader + part.body)

for (const identity of this.config.forward) {
const api = Array.from(this.ctx[Symbols.bot].values()).map((bots) =>
Array.from(bots.values()).find((bot) => bot.adapter.identity === identity)
)[0]
if (!api) {
this.ctx.emit(
'error',
KotoriError.from(
`Failed to forward mail, cant not find ${identity} bot`,
this.ctx.identity?.toString()
)
)
continue
}
api.sendPrivateMsg(
formatFactory(api.adapter.ctx.i18n)('adapter_mail.forward', [
email.from?.text,
email.subject,
email.text,
email.date ? api.adapter.ctx.i18n.date(email.date) : ''
]),
api.adapter.config.master
)
}
this.session('on_message', {
type: MessageScope.PRIVATE,
userId: email.from?.text ?? '',
message: email.text ?? email.subject ?? '',
messageAlt: email.text ?? email.subject ?? '',
messageId: id.toString(),
sender: {
nickname: email.from?.text || ''
},
time: email.date?.getTime() || Date.now()
})
}
}
})

this.ctx.emit('connect', {
type: 'connect',
mode: 'other',
adapter: this,
normal: true,
address: `imap://${this.config.imapHost}:${this.config.imapPort}`
})
await sleep(10 * 1000)
this.timerId = setInterval(() => this.handle(), this.config.interval * 1000)
} catch (error) {
this.ctx.emit('error', KotoriError.from(error, this.ctx.identity?.toString()))
}
}

public stop() {
this.imapConnection?.end()
clearInterval(this.timerId)
this.ctx.emit('connect', {
type: 'disconnect',
mode: 'other',
Expand Down
19 changes: 19 additions & 0 deletions modules/adapter-qq/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@ export const config = Tsu.Object({
})
```

## Supports

### Events

- on_message (exclude `MessageScope.PRIVATE`)

### Api

- sendGroupMsg
- sendChannelMsg

### Elements

- text
- image
- voice
- mention
- video

## Reference

- [Kotori Docs](https://kotori.js.org/)
Expand Down
2 changes: 1 addition & 1 deletion modules/adapter-slack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const config = Tsu.Object({
- voice
- video

## Todo
## TODO

Support more standard api...

Expand Down
2 changes: 1 addition & 1 deletion modules/adapter-telegram/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const config = Tsu.Object({
- video
- location

## Todo
## TODO

Support more standard api...

Expand Down
2 changes: 1 addition & 1 deletion modules/core/locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"core.msg.core": "Global language: %lang%\nInstance directory: %root%\nRunning mode: %mode%\nNumber of modules: %modules%\nNumber of services: %services%\nNumber of bot instances: %bots%\nNumber of middlewares: %midwares%\nNumber of commands: %commands%\nNumber of regular expressions: %regexps%",
"core.msg.bots": "Instance list: %list%",
"core.msg.bots.list": "\n----------\nID: %identity%\nLanguage: %lang%\nPlatform: %platform%\nStatus: %status%",
"core.msg.about": "Kotori version: %version%\nLicense: %license%\nNodeJS version: %node_version%",
"core.msg.about": "Kotori version: %version%\nCore version: %core_version%\n%Loader version: %loader_version%%\nLicense: %license%\nNodeJS version: %node_version%",
"core.msg.locale": "Successfully set the display language for the current instance to: %lang%",
"core.msg.locale.global": "Successfully set the global display language to: %lang%",
"core.msg.locale.invalid": "Parameter is invalid, must be one of the following values: en_US, ja_JP, zh_CN, zh_TW",
Expand Down
2 changes: 1 addition & 1 deletion modules/core/locales/zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"core.msg.core": "全局语言:%lang%\n实例目录:%root%\n运行模式:%mode%\n模块数量:%modules%\n服务数量:%services%\nbot 实例数量:%bots%\n中间件数量:%midwares%\n指令数量:%commands%\n正则数量:%regexps%",
"core.msg.bots": "实例列表:%list%",
"core.msg.bots.list": "\n----------\nID:%identity%\n语言:%lang%\n平台:%platform%\n状态:%status%",
"core.msg.about": "Kotori 版本:%version%\n协议:%license%\nNodeJS 版本:%node_version%",
"core.msg.about": "Kotori 版本:%version%\n核心版本:%core_version%\n加载器版本:%loader_version%\n协议:%license%\nNodeJS 版本:%node_version%",
"core.msg.locale": "成功将当前实例显示语言设置为:%lang%",
"core.msg.locale.global": "成功将全局显示语言设置为:%lang%",
"core.msg.locale.invalid": "参数无效,必须是以下中的一个值:en_US、ja_JP、zh_CN、zh_TW",
Expand Down
12 changes: 9 additions & 3 deletions modules/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @Blog: https://hotaru.icu
* @Date: 2023-07-11 14:18:27
* @LastEditors: Hotaru [email protected]
* @LastEditTime: 2024-08-03 10:59:04
* @LastEditTime: 2024-08-06 11:18:36
*/

import {
Expand Down Expand Up @@ -183,8 +183,14 @@ export function main(ctx: Context) {
.shortcut(['小鸟', '小鳥', 'ことり', 'kotori', 'Kotori'])
.hide()
.action((_, session) => {
const { version, license } = session.api.adapter.ctx.meta
return session.format('core.msg.about', { version, license, node_version: process.version })
const { version, license, coreVersion, loaderVersion } = session.api.adapter.ctx.meta
return session.format('core.msg.about', {
version,
license,
core_version: coreVersion,
loader_version: loaderVersion,
node_version: process.version
})
})

ctx
Expand Down
Loading

0 comments on commit 839438b

Please sign in to comment.