Compare commits
9 Commits
13edd23245
...
f0ca0fbbd4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0ca0fbbd4 | ||
|
|
3e5fc722e6 | ||
|
|
a646d7908a | ||
|
|
cfe8df43d1 | ||
|
|
743ccd1172 | ||
|
|
3c5bd187b7 | ||
|
|
27035eb2ca | ||
|
|
7a308e2261 | ||
|
|
3cc60986ab |
229
client-protocol/Chat.ts
Normal file
229
client-protocol/Chat.ts
Normal file
@@ -0,0 +1,229 @@
|
||||
import BaseClientObject from "./BaseClientObject.ts"
|
||||
import BaseChatSettingsBean from "./bean/BaseChatSettingsBean.ts"
|
||||
import ChatBean from "./bean/ChatBean.ts"
|
||||
import JoinRequestBean from "./bean/JoinRequestBean.ts"
|
||||
import MessageBean from "./bean/MessageBean.ts"
|
||||
import CallbackError from "./CallbackError.ts"
|
||||
import JoinRequest from "./JoinRequest.ts"
|
||||
import LingChairClient from "./LingChairClient.ts"
|
||||
import Message from "./Message.ts"
|
||||
|
||||
export default class Chat extends BaseClientObject {
|
||||
declare bean: ChatBean
|
||||
constructor(client: LingChairClient, bean: ChatBean) {
|
||||
super(client)
|
||||
this.bean = bean
|
||||
}
|
||||
/*
|
||||
* ================================================
|
||||
* 实例化方法
|
||||
* ================================================
|
||||
*/
|
||||
static async getById(client: LingChairClient, id: string) {
|
||||
try {
|
||||
return await this.getByIdOrThrow(client, id)
|
||||
} catch (_) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
static async getByIdOrThrow(client: LingChairClient, id: string) {
|
||||
const re = await client.invoke("Chat.getInfo", {
|
||||
token: client.access_token,
|
||||
target: id,
|
||||
})
|
||||
if (re.code == 200)
|
||||
return new Chat(client, re.data as unknown as ChatBean)
|
||||
throw new CallbackError(re)
|
||||
}
|
||||
/**
|
||||
* ================================================
|
||||
* 创建对话 (另类实例化方法)
|
||||
* ================================================
|
||||
*/
|
||||
static async getOrCreatePrivateChat(client: LingChairClient, user_id: string) {
|
||||
try {
|
||||
return await this.getOrCreatePrivateChatOrThrow(client, user_id)
|
||||
} catch (_) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
static async getOrCreatePrivateChatOrThrow(client: LingChairClient, user_id: string) {
|
||||
const re = await client.invoke("Chat.getIdForPrivate", {
|
||||
token: client.access_token,
|
||||
target: user_id,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
return new Chat(client, re.data as unknown as ChatBean)
|
||||
}
|
||||
static async createGroup(client: LingChairClient, title: string, name?: string) {
|
||||
try {
|
||||
return await this.createGroupOrThrow(client, title, name)
|
||||
} catch (_) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
static async createGroupOrThrow(client: LingChairClient, title: string, name?: string) {
|
||||
const re = await client.invoke("Chat.createGroup", {
|
||||
token: client.access_token,
|
||||
title,
|
||||
name,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
return new Chat(client, re.data as unknown as ChatBean)
|
||||
}
|
||||
/**
|
||||
* ================================================
|
||||
* 对话消息
|
||||
* ================================================
|
||||
*/
|
||||
async getMessages(page: number = 0) {
|
||||
return (await this.getMessageBeans(page)).map((v) => new Message(this.client, v))
|
||||
}
|
||||
async getMessagesOrThrow(page: number = 0) {
|
||||
return (await this.getMessageBeansOrThrow(page)).map((v) => new Message(this.client, v))
|
||||
}
|
||||
async getMessageBeans(page: number = 0) {
|
||||
try {
|
||||
return await this.getMessageBeansOrThrow(page)
|
||||
} catch (_) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
async getMessageBeansOrThrow(page: number = 0) {
|
||||
const re = await this.client.invoke("Chat.getMessageHistory", {
|
||||
token: this.client.access_token,
|
||||
page,
|
||||
target: this.bean.id,
|
||||
})
|
||||
if (re.code == 200) return re.data!.messages as MessageBean[]
|
||||
throw new CallbackError(re)
|
||||
}
|
||||
async sendMessage(text: string) {
|
||||
try {
|
||||
return await this.sendMessageOrThrow(text)
|
||||
} catch (_) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
async sendMessageOrThrow(text: string) {
|
||||
const re = await this.client.invoke("Chat.sendMessage", {
|
||||
token: this.client.access_token,
|
||||
text,
|
||||
target: this.bean.id,
|
||||
})
|
||||
if (re.code == 200)
|
||||
return new Message(this.client, re.data!.message as MessageBean)
|
||||
throw new CallbackError(re)
|
||||
}
|
||||
/**
|
||||
* ================================================
|
||||
* 加入对话申请
|
||||
* ================================================
|
||||
*/
|
||||
async getJoinRequests() {
|
||||
try {
|
||||
return await this.getJoinRequestsOrThrow()
|
||||
} catch (_) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
async getJoinRequestsOrThrow() {
|
||||
const join_requests = await this.getJoinRequestBeansOrThrow()
|
||||
return join_requests.map((jr) => new JoinRequest(this.client, jr, this.bean.id))
|
||||
}
|
||||
async getJoinRequestBeans() {
|
||||
try {
|
||||
return await this.getJoinRequestBeansOrThrow()
|
||||
} catch (_) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
async getJoinRequestBeansOrThrow() {
|
||||
const re = await this.client.invoke("Chat.getJoinRequests", {
|
||||
token: this.client.access_token
|
||||
})
|
||||
if (re.code == 200)
|
||||
return re.data!.join_requests as JoinRequestBean[]
|
||||
throw new CallbackError(re)
|
||||
}
|
||||
/**
|
||||
* ================================================
|
||||
* 对话信息
|
||||
* ================================================
|
||||
*/
|
||||
async setAvatarFileHash(file_hash: string) {
|
||||
try {
|
||||
await this.setAvatarFileHashOrThrow(file_hash)
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
async setAvatarFileHashOrThrow(file_hash: string) {
|
||||
const re = await this.client.invoke("Chat.setAvatar", {
|
||||
token: this.client.access_token,
|
||||
file_hash,
|
||||
target: this.bean.id,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
this.bean.avatar_file_hash = file_hash
|
||||
}
|
||||
async updateSettings(args: BaseChatSettingsBean) {
|
||||
try {
|
||||
await this.updateSettingsOrThrow(args)
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
async updateSettingsOrThrow(args: BaseChatSettingsBean) {
|
||||
const re = await this.client.invoke("Chat.updateSettings", {
|
||||
token: this.client.access_token,
|
||||
target: this.bean.id,
|
||||
settings: args
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
this.bean.settings = args
|
||||
}
|
||||
async getTheOtherUserId() {
|
||||
try {
|
||||
return await this.getTheOtherUserIdOrThrow()
|
||||
} catch (_) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
async getTheOtherUserIdOrThrow() {
|
||||
const re = await this.client.invoke("Chat.updateSettings", {
|
||||
token: this.client.access_token,
|
||||
target: this.bean.id,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
return re.data!.user_id as string
|
||||
}
|
||||
/*
|
||||
* ================================================
|
||||
* 基本 Bean
|
||||
* ================================================
|
||||
*/
|
||||
getId() {
|
||||
return this.bean.id
|
||||
}
|
||||
getTitle() {
|
||||
return this.bean.title
|
||||
}
|
||||
getType() {
|
||||
return this.bean.type
|
||||
}
|
||||
isMember() {
|
||||
return this.bean.is_member
|
||||
}
|
||||
isAdmin() {
|
||||
return this.bean.is_admin
|
||||
}
|
||||
getAvatarFileHash() {
|
||||
return this.bean.avatar_file_hash
|
||||
}
|
||||
getSettings() {
|
||||
return this.bean.settings
|
||||
}
|
||||
}
|
||||
66
client-protocol/JoinRequest.ts
Normal file
66
client-protocol/JoinRequest.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import BaseClientObject from "./BaseClientObject.ts"
|
||||
import JoinRequestBean from "./bean/JoinRequestBean.ts"
|
||||
import CallbackError from "./CallbackError.ts"
|
||||
import LingChairClient from "./LingChairClient.ts"
|
||||
import JoinRequestAction from "./type/JoinRequestAction.ts"
|
||||
|
||||
export default class JoinRequest extends BaseClientObject {
|
||||
declare bean: JoinRequestBean
|
||||
declare chat_id: string
|
||||
constructor(client: LingChairClient, bean: JoinRequestBean, chat_id: string) {
|
||||
super(client)
|
||||
this.bean = bean
|
||||
this.chat_id = chat_id
|
||||
}
|
||||
/*
|
||||
* ================================================
|
||||
* 操作
|
||||
* ================================================
|
||||
*/
|
||||
async accept() {
|
||||
return await this.process('accept')
|
||||
}
|
||||
async acceptOrThrow() {
|
||||
return await this.processOrThrow('accept')
|
||||
}
|
||||
async remove() {
|
||||
return await this.process('remove')
|
||||
}
|
||||
async removOrThrow() {
|
||||
return await this.processOrThrow('remove')
|
||||
}
|
||||
async process(action: JoinRequestAction) {
|
||||
try {
|
||||
await this.processOrThrow(action)
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
async processOrThrow(action: JoinRequestAction) {
|
||||
const re = await this.client.invoke("Chat.processJoinRequest", {
|
||||
token: this.client.access_token,
|
||||
chat_id: this.chat_id,
|
||||
user_id: this.bean.user_id,
|
||||
action,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
}
|
||||
/*
|
||||
* ================================================
|
||||
* 基本 Bean
|
||||
* ================================================
|
||||
*/
|
||||
getAvatarFileHash() {
|
||||
return this.bean.avatar_file_hash
|
||||
}
|
||||
getUserId() {
|
||||
return this.bean.user_id
|
||||
}
|
||||
getNickName() {
|
||||
return this.bean.title
|
||||
}
|
||||
getReason() {
|
||||
return this.bean.reason
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,12 @@ import { CallMethod, ClientEvent } from './ApiDeclare.ts'
|
||||
import ApiCallbackMessage from './ApiCallbackMessage.ts'
|
||||
import User from "./User.ts"
|
||||
import UserMySelf from "./UserMySelf.ts"
|
||||
import CallbackError from "./CallbackError.ts"
|
||||
import Chat from "./Chat.ts"
|
||||
|
||||
export {
|
||||
User,
|
||||
Chat,
|
||||
UserMySelf,
|
||||
}
|
||||
|
||||
@@ -81,7 +84,7 @@ export default class LingChairClient {
|
||||
password?: string,
|
||||
}) {
|
||||
try {
|
||||
this.authOrThrow(args)
|
||||
await this.authOrThrow(args)
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
|
||||
39
client-protocol/Message.ts
Normal file
39
client-protocol/Message.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import BaseClientObject from "./BaseClientObject.ts"
|
||||
import MessageBean from "./bean/MessageBean.ts"
|
||||
import LingChairClient from "./LingChairClient.ts"
|
||||
import Chat from "./Chat.ts"
|
||||
import User from "./User.ts"
|
||||
|
||||
export default class Message extends BaseClientObject {
|
||||
declare bean: MessageBean
|
||||
constructor(client: LingChairClient, bean: MessageBean) {
|
||||
super(client)
|
||||
this.bean = bean
|
||||
}
|
||||
/*
|
||||
* ================================================
|
||||
* 基本 Bean
|
||||
* ================================================
|
||||
*/
|
||||
getId() {
|
||||
return this.bean.id
|
||||
}
|
||||
getChatId() {
|
||||
return this.bean.chat_id
|
||||
}
|
||||
async getChat() {
|
||||
return await Chat.getById(this.client, this.bean.chat_id as string)
|
||||
}
|
||||
getText() {
|
||||
return this.bean.text
|
||||
}
|
||||
getUserId() {
|
||||
return this.bean.user_id
|
||||
}
|
||||
async getUser() {
|
||||
return await User.getById(this.client, this.bean.user_id as string)
|
||||
}
|
||||
getTime() {
|
||||
return this.bean.time
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ export default class UserMySelf extends User {
|
||||
async resetPasswordOrThrow(old_password: string, new_password: string) {
|
||||
const re = await this.client.invoke("User.resetPassword", {
|
||||
token: this.client.access_token,
|
||||
old_password,
|
||||
old_password,
|
||||
new_password,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
@@ -66,6 +66,7 @@ export default class UserMySelf extends User {
|
||||
file_hash,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
this.bean.avatar_file_hash = file_hash
|
||||
}
|
||||
async setUserName(user_name: string) {
|
||||
return await this.updateProfile({ username: user_name })
|
||||
@@ -103,6 +104,8 @@ export default class UserMySelf extends User {
|
||||
username,
|
||||
})
|
||||
if (re.code != 200) throw new CallbackError(re)
|
||||
nickname && (this.bean.nickname = nickname)
|
||||
username && (this.bean.username = username)
|
||||
}
|
||||
/*
|
||||
* ================================================
|
||||
@@ -143,7 +146,7 @@ export default class UserMySelf extends User {
|
||||
try {
|
||||
return await this.getMyFavouriteChatBeansOrThrow()
|
||||
} catch (_) {
|
||||
return null
|
||||
return []
|
||||
}
|
||||
}
|
||||
async getMyFavouriteChatBeansOrThrow() {
|
||||
@@ -163,7 +166,7 @@ export default class UserMySelf extends User {
|
||||
try {
|
||||
return await this.getMyRecentChatBeansOrThrow()
|
||||
} catch (_) {
|
||||
return null
|
||||
return []
|
||||
}
|
||||
}
|
||||
async getMyRecentChatBeansOrThrow() {
|
||||
|
||||
5
client-protocol/bean/BaseChatSettingsBean.ts
Normal file
5
client-protocol/bean/BaseChatSettingsBean.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
interface BaseChatSettings {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export default BaseChatSettings
|
||||
@@ -1,11 +1,12 @@
|
||||
import ChatType from "./ChatType.ts"
|
||||
import BaseChatSettingsBean from "./BaseChatSettingsBean.ts"
|
||||
import ChatType from "../type/ChatType.ts"
|
||||
|
||||
export default class ChatBean {
|
||||
declare type: ChatType
|
||||
declare id: string
|
||||
declare title: string
|
||||
declare avatar_file_hash?: string
|
||||
declare settings?: { [key: string]: unknown }
|
||||
declare settings?: BaseChatSettingsBean
|
||||
|
||||
declare is_member: boolean
|
||||
declare is_admin: boolean
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
interface GroupSettingsBean {
|
||||
import BaseChatSettings from "./BaseChatSettingsBean.ts"
|
||||
|
||||
interface GroupSettingsBean extends BaseChatSettings {
|
||||
allow_new_member_join?: boolean
|
||||
allow_new_member_from_invitation?: boolean
|
||||
new_member_join_method?: 'disabled' | 'allowed_by_admin' | 'answered_and_allowed_by_admin'
|
||||
@@ -7,8 +9,6 @@ interface GroupSettingsBean {
|
||||
// 下面两个比较特殊, 由服务端给予
|
||||
group_title: string
|
||||
group_name: string
|
||||
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export default GroupSettingsBean
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export default class JoinRequestBean {
|
||||
declare user_id: string
|
||||
declare title: string
|
||||
declare avatar?: string
|
||||
declare nickname: string
|
||||
declare avatar_file_hash?: string
|
||||
declare reason?: string
|
||||
|
||||
[key: string]: unknown
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export default class MessageBean {
|
||||
declare id: number
|
||||
declare text: string
|
||||
declare user_id: string
|
||||
declare user_id?: string
|
||||
declare chat_id?: string
|
||||
declare time: string
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import LingChairClient, { User, UserMySelf } from "./LingChairClient.ts"
|
||||
import LingChairClient, { Chat, UserMySelf } from "./LingChairClient.ts"
|
||||
import OnMessageData from "./type/OnMessageData.ts"
|
||||
|
||||
const client = new LingChairClient({
|
||||
@@ -9,7 +9,10 @@ await client.auth({
|
||||
account: '满月',
|
||||
password: '满月',
|
||||
})
|
||||
client.on('Client.onMessage', (data: OnMessageData) => {
|
||||
console.log(data)
|
||||
client.on('Client.onMessage', async (data: OnMessageData) => {
|
||||
const chat = await Chat.getById(client, data.chat)
|
||||
const regexp = /^test (.*)/g.exec(data.msg.text)
|
||||
if (regexp?.[0] != null) {
|
||||
chat?.sendMessage(`Hello, ${regexp[1]}`)
|
||||
}
|
||||
})
|
||||
console.log(await (await UserMySelf.getMySelf(client))?.getMyRecentChatBeans())
|
||||
|
||||
3
client-protocol/type/JoinRequestAction.ts
Normal file
3
client-protocol/type/JoinRequestAction.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
type JoinRequestAction = 'accept' | 'remove'
|
||||
|
||||
export default JoinRequestAction
|
||||
@@ -62,17 +62,22 @@ export default class ChatApi extends BaseApi {
|
||||
const userInst = User.findById(id)
|
||||
userInst?.updateRecentChat(chat.bean.id, args.text as string)
|
||||
})
|
||||
const m = {
|
||||
...msg,
|
||||
id,
|
||||
chat_id: chat.bean.id,
|
||||
}
|
||||
this.boardcastToUsers(users, 'Client.onMessage', {
|
||||
chat: chat.bean.id,
|
||||
msg: {
|
||||
...msg,
|
||||
id
|
||||
}
|
||||
msg: m
|
||||
})
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
msg: "成功",
|
||||
data: {
|
||||
message: m,
|
||||
}
|
||||
}
|
||||
})
|
||||
/**
|
||||
@@ -191,6 +196,8 @@ export default class ChatApi extends BaseApi {
|
||||
return {
|
||||
user_id: user?.bean.id,
|
||||
reason: v.reason,
|
||||
nickname: user!.getNickName(),
|
||||
// TODO: 这个得删掉, 应该用 nickname
|
||||
title: user!.getNickName(),
|
||||
avatar_file_hash: user!.getAvatarFileHash() ? user!.getAvatarFileHash() : null,
|
||||
}
|
||||
@@ -337,7 +344,18 @@ export default class ChatApi extends BaseApi {
|
||||
code: 200,
|
||||
msg: '成功',
|
||||
data: {
|
||||
// TODO: 移除这个, 将本方法重命名为 getOrCreatePrivateChat
|
||||
// 并重构原 Web 客户端所引用的内容
|
||||
chat_id: chat.bean.id,
|
||||
|
||||
id: chat.bean.id,
|
||||
name: chat.bean.name,
|
||||
type: chat.bean.type,
|
||||
title: chat.getTitle(user),
|
||||
avatar_file_hash: chat.getAvatarFileHash(user) ? chat.getAvatarFileHash(user) : undefined,
|
||||
settings: JSON.parse(chat.bean.settings),
|
||||
is_member: true,
|
||||
is_admin: true,
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -379,7 +397,23 @@ export default class ChatApi extends BaseApi {
|
||||
code: 200,
|
||||
msg: '成功',
|
||||
data: {
|
||||
// TODO: 移除这个
|
||||
// 并重构原 Web 客户端所引用的内容
|
||||
chat_id: chat.bean.id,
|
||||
|
||||
id: chat.bean.id,
|
||||
name: chat.bean.name,
|
||||
type: chat.bean.type,
|
||||
title: chat.getTitle(),
|
||||
avatar_file_hash: chat.getAvatarFileHash() ? chat.getAvatarFileHash() : undefined,
|
||||
settings: {
|
||||
...JSON.parse(chat.bean.settings),
|
||||
// 下面两个比较特殊, 用于群设置
|
||||
group_name: chat.bean.name,
|
||||
group_title: chat.getTitle(),
|
||||
},
|
||||
is_member: UserChatLinker.checkUserIsLinkedToChat(token.author, chat!.bean.id),
|
||||
is_admin: chat.checkUserIsAdmin(token.author),
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -463,7 +497,7 @@ export default class ChatApi extends BaseApi {
|
||||
})
|
||||
// 更新頭像
|
||||
this.registerEvent("Chat.setAvatar", (args, { deviceId }) => {
|
||||
if (this.checkArgsMissing(args, ['file_hash', 'token'])) return {
|
||||
if (this.checkArgsMissing(args, ['file_hash', 'token', 'target'])) return {
|
||||
msg: "参数缺失",
|
||||
code: 400,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ export default class MessageBean {
|
||||
declare id: number
|
||||
declare text: string
|
||||
declare user_id?: string
|
||||
declare chat_id?: string
|
||||
declare time: string
|
||||
|
||||
[key: string]: unknown
|
||||
|
||||
@@ -60,7 +60,11 @@ export default class MessagesManager {
|
||||
})
|
||||
}
|
||||
getMessages(limit: number = 15, offset: number = 0) {
|
||||
return MessagesManager.database.prepare(`SELECT * FROM ${this.getTableName()} ORDER BY id DESC LIMIT ? OFFSET ?;`).all(limit, offset) as unknown as MessageBean[]
|
||||
const ls = MessagesManager.database.prepare(`SELECT * FROM ${this.getTableName()} ORDER BY id DESC LIMIT ? OFFSET ?;`).all(limit, offset) as unknown as MessageBean[]
|
||||
return ls.map((v) => ({
|
||||
...v,
|
||||
chat_id: this.chat.bean.id,
|
||||
}))
|
||||
}
|
||||
getMessagesWithPage(limit: number = 15, page: number = 0) {
|
||||
return this.getMessages(limit, limit * page)
|
||||
|
||||
Reference in New Issue
Block a user