Skip to content

Commit

Permalink
feat: 完成了一点点
Browse files Browse the repository at this point in the history
  • Loading branch information
TheresaQWQ committed Aug 3, 2023
1 parent 3378eff commit 591b511
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 11 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@
{
"username": "", // 花园用户名
"password": "", // 花园密码
"root": "", // 机器人所在房间
"room": "", // 机器人所在房间
"color": "" // 机器人消息颜色
},
// 账号2
{
"username": "", // 花园用户名
"password": "", // 花园密码
"root": "", // 机器人所在房间
"room": "", // 机器人所在房间
"color": "" // 机器人消息颜色
}
// ... 可以添加更多账号
Expand Down
100 changes: 100 additions & 0 deletions src/bridge/Users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { bots } from "."

interface UserData {
email: string,
location: string,
website: string,
hobby: string,
intro: string,
background: string,
music: string,
lastLoginTime: Date,
visits: string,
title: string,
rooms: string[],
tags: string,
regTime: Date,
online: string,
credit: string,
life: {
image: string,
time: Date,
desc: string
}[],
mate: {
username: string | null,
avatar: string | null,
color: string | null
},
money: {
hold: string,
bank: string
},
like: {
times: number,
users: string[]
}
}

class User {
public data?: UserData
public uid?: string
public username?: string
constructor({ uid, username }: { uid?: string, username?: string }) {
this.uid = uid
this.username = username

if (!uid && !username) {
throw new Error("uid or username must be provided")
}
}
}

class GlobalUserCache {
private users: User[] = []

public get({ uid, username }: { uid?: string, username?: string }) {
const user = this.users.find(user => user.uid === uid || user.username === username)
return user
}

public set({ uid, username }: { uid?: string, username?: string }) {
const user = new User({ uid, username })
this.users.push(user)
return user
}

public update({ uid, username }: { uid?: string, username?: string }) {
const user = this.get({ uid, username })
if (user) {
user.uid = uid
user.username = username

return true
}

return false
}

public async syncAllData({ uid, username }: { uid?: string, username?: string }) {
const user = this.get({ uid, username })
if (!user || !user.username) throw new Error("user not found")

const bot = bots.find(bot => bot.online)

if (!bot) throw new Error("all bots offline")

const profile = await bot.getUserProfile(user.username)
if (!profile) throw new Error("user not found")

user.data = profile

return user
}

public getAll() {
return this.users
}
}

export default new GlobalUserCache()
31 changes: 29 additions & 2 deletions src/bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,26 @@ import * as OneBot from '../onebot'
import { getConfig } from "../core/config";
import * as MessageProcessor from './message'
import id from "../core/id";
import Users from "./Users";

const bots: Bot[] = []
export const bots: Bot[] = []

getConfig('accounts').forEach((account: any, index: number) => {
const bot = new Bot(account)
bots[index] = bot
bots[index].index = index

bot.on('PublicMessage', msg => {
const username = msg.username
const uid = msg.uid

const user = Users.get({ uid, username })
if (!user) {
Users.set({ uid, username })
} else {
Users.update({ uid, username })
}

OneBot.boardcast(JSON.stringify({
"id": id(),
"self": getConfig('compatibility.events.self'),
Expand All @@ -22,7 +33,7 @@ getConfig('accounts').forEach((account: any, index: number) => {
"message_id": msg.messageId,
"message": [
...MessageProcessor.str2msg(msg.message)
// 处理回复消息
// TODO: 处理回复消息
],
"alt_message": msg.message,
"group_id": index.toString(),
Expand All @@ -43,6 +54,22 @@ OneBot.eventPipe.on('request', (action, params, callback) => {
online: !hasOffline,
}]
})
} else if (action === 'get_user_info') {
const user = Users.get({ uid: params.user_id as string })
if (!user) {
return callback('failed', 35001, null, 'User not found')
}
} else if (action === 'get_friend_list') {
const list = Users.getAll().map(item => {
return {
user_id: item.uid,
user_name: item.username,
user_displayname: "",
user_remark: item.username,
}
})

callback('ok', 0, list, 'success')
} else if (action === 'send_message') {
// 发送消息
const detail_type = params.detail_type
Expand Down
3 changes: 2 additions & 1 deletion src/core/logger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import log4js from 'log4js';
import { getConfig } from './config';

const config = {
appenders: {
Expand All @@ -16,7 +17,7 @@ const config = {
categories: {
default: {
appenders: ['console', 'file'],
level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
level: getConfig('app.logger.level')
},
},
};
Expand Down
32 changes: 32 additions & 0 deletions src/iirose/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { PrivateMessage } from "./packets/decoders/PrivateMessage";
import { PublicMessage } from "./packets/decoders/PublicMessage";

import logger from "../core/logger";
import { UserProfileCallback } from "./packets/decoders/ProfileCallback";

interface IEmissions {
JoinRoom: (data: JoinRoom) => void;
Expand Down Expand Up @@ -36,7 +37,9 @@ export interface Account {

export default class Bot extends EventEmitter {
private ws?: WebSocket;
// @ts-ignore
private _untypedOn = this.on
// @ts-ignore
private _untypedEmit = this.emit
public on = <K extends keyof IEmissions>(event: K, listener: IEmissions[K]): this => this._untypedOn(event, listener)
public emit = <K extends keyof IEmissions>(event: K, ...args: Parameters<IEmissions[K]>): boolean => this._untypedEmit(event, ...args)
Expand Down Expand Up @@ -130,4 +133,33 @@ export default class Bot extends EventEmitter {
const succ = this.ws.send(packets.encode.DeleteMessage(id));
if (!succ) throw new Error('Failed to delete message');
}

private callApiWithCallback (data: string, eventName: string) {
return new Promise((resolve, reject) => {
if (!this.ws) return
let end = false
const timeout = setTimeout(() => {
reject('timeout')
}, 5000)

this.once(eventName, (data: any) => {
if (end) return
resolve(data)

end = true
clearTimeout(timeout)
})

this.ws.send(data)
})
}

/**
* @description 获取用户资料
* @param username 用户名
* @returns
*/
public getUserProfile (username: string) {
return this.callApiWithCallback(packets.encode.GetUserProfile(username), 'UserProfileCallback') as Promise<UserProfileCallback>
}
}
21 changes: 18 additions & 3 deletions src/iirose/network/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ws from 'ws'
import pako from 'pako'
import getLogger from '../../core/logger'
import EventEmitter from 'events'
import { Agent } from 'https'

interface IEmissions {
open: () => void
Expand All @@ -10,17 +11,25 @@ interface IEmissions {
message: (data: string) => void
}

const options = {
agent: new Agent({
rejectUnauthorized: false,
keepAlive: true,
})
}

export class WebSocket extends EventEmitter {
private socket: ws
private logger = getLogger('WebSocket')
private _untypedOn = this.on
private _untypedEmit = this.emit
public on = <K extends keyof IEmissions>(event: K, listener: IEmissions[K]): this => this._untypedOn(event, listener)
public emit = <K extends keyof IEmissions>(event: K, ...args: Parameters<IEmissions[K]>): boolean => this._untypedEmit(event, ...args)
private timer?: NodeJS.Timeout

constructor(url: string) {
super()
this.socket = new ws(url)
this.socket = new ws(url, options)
this.init()
}

Expand All @@ -40,6 +49,11 @@ export class WebSocket extends EventEmitter {
private openHandler() {
this.logger.info('WebSocket connected')
this.emit('open')
this.timer = setInterval(() => {
if (this.isOpen()) {
this.socket.send('')
}
}, 60e3)
}

private packetHandler(data: ws.MessageEvent) {
Expand All @@ -52,14 +66,15 @@ export class WebSocket extends EventEmitter {
const packet = pako.inflate(arrayBuf.slice(1))
this.messageHandler(packet.toString())
} else {
this.messageHandler(arrayBuf.toString())
this.messageHandler(Buffer.from(arrayBuf).toString())
}
}

private closeHandler() {
clearInterval(this.timer!)
this.emit('close')
this.logger.info('WebSocket closed, reconnecting...')
this.socket = new ws(this.socket.url)
this.socket = new ws(this.socket.url, options)
this.init()
}

Expand Down
81 changes: 81 additions & 0 deletions src/iirose/packets/decoders/ProfileCallback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
export interface UserProfileCallback {
email:string,
location:string,
website:string,
hobby:string,
intro:string,
background: string,
music: string,
lastLoginTime: Date,
visits: string,
title: string,
rooms: string[],
tags: string,
regTime: Date,
online: string,
credit: string,
life: {
image: string,
time: Date,
desc: string
}[],
mate: {
username: string | null,
avatar: string | null,
color: string | null
},
money: {
hold: string,
bank: string
},
like: {
times: number,
users: string[]
}
}

export default (message: string) => {
if (message.substring(0, 2) === '+1') {
const tmp = message.substring(2).split('>')
const msg: UserProfileCallback = {
email: tmp[0],
location: tmp[4],
website: tmp[5],
hobby: tmp[6],
intro: tmp[8],
background: tmp[9],
music: tmp[11],
lastLoginTime: new Date(Number(tmp[12]) * 1e3),
visits: tmp[13],
title: tmp[14],
rooms: tmp[21].split('"'),
tags: tmp[22],
regTime: new Date(Number(tmp[24]) * 1e3),
online: tmp[25],
credit: tmp[32],
life: tmp[31].split('<').map(e => {
const data = {
image: `http${e.split(' ')[0]}`,
time: new Date(Number(e.split(' ')[1]) * 1e3),
desc: e.split(' ').splice(2).join(' ')
}
return data
}),
mate: {
username: tmp[23] ? tmp[23].split('<')[0] : null,
avatar: tmp[23] ? tmp[23].split('<')[1] : null,
color: tmp[23] ? tmp[23].split('<')[2] : null
},
money: {
hold: tmp[17],
bank: tmp[33]
},
like: {
times: Number(tmp[16].split('"')[0]),
users: tmp[16].split('"')[1].split("'")
}
}

return [['UserProfileCallback', msg]]
}
}
3 changes: 3 additions & 0 deletions src/iirose/packets/encoders/GetUserProfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default (username: string) => {
return `+-${username}`
}
Loading

0 comments on commit 591b511

Please sign in to comment.