feat: add openapi bot client

and fix some problem
- mention auto fill username
- bbcode no message fallback
pull/90/head
moonrailgun 2 years ago
parent 7f0568feed
commit 7c658583c2

@ -1,6 +1,6 @@
{
"name": "tailchat-client-sdk",
"version": "1.0.0",
"version": "1.0.3",
"description": "",
"main": "lib/index.js",
"scripts": {
@ -12,6 +12,7 @@
"author": "moonrailgun <moonrailgun@gmail.com>",
"license": "MIT",
"devDependencies": {
"@types/node": "^18.16.1",
"typescript": "^4.9.5"
},
"dependencies": {

@ -1 +1,2 @@
export * from './openapi';
export * from './plugins/simplenotify';

@ -0,0 +1,142 @@
import axios, { AxiosInstance } from 'axios';
import crypto from 'crypto';
export class TailchatClient {
request: AxiosInstance;
jwt: string | null = null;
userId: string | null = null;
loginP: Promise<void>;
constructor(
public url: string,
public appId: string,
public appSecret: string
) {
if (!url || !appId || !appSecret) {
throw new Error(
'Require params: apiUrl, appId, appSecret. You can set it with env'
);
}
this.request = axios.create({
baseURL: url,
});
this.request.interceptors.request.use(async (val) => {
if (
this.jwt &&
['post', 'get'].includes(String(val.method).toLowerCase()) &&
!val.headers['X-Token']
) {
// 任何请求都尝试增加token
val.headers['X-Token'] = this.jwt;
}
return val;
});
this.loginP = this.login();
}
async login() {
try {
console.log('Login...');
const { data } = await this.request.post('/api/openapi/bot/login', {
appId: this.appId,
token: this.getBotToken(),
});
// NOTICE: 注意有30天过期时间需要定期重新登录以换取新的token
// 这里先不换
this.jwt = data.data?.jwt;
console.log('tailchat openapp login success!');
// 尝试调用函数
// this.whoami().then(console.log);
} catch (err) {
console.error(err);
throw new Error('Login failed, please check application credentials');
}
}
async call(action: string, params = {}) {
try {
await Promise.resolve(this.loginP);
console.log('Calling:', action);
const { data } = await this.request.post(
'/api/' + action.replace(/\./g, '/'),
params
);
return data;
} catch (err: any) {
console.error('Service Call Failed:', err);
const data: string = err?.response?.data;
if (data) {
throw new Error(
JSON.stringify({
action,
data,
})
);
} else {
throw err;
}
}
}
async whoami() {
return this.call('user.whoami');
}
getBotToken() {
return crypto
.createHash('md5')
.update(this.appId + this.appSecret)
.digest('hex');
}
/**
* Send normal message to tailchat
*/
async sendMessage(payload: {
converseId: string;
groupId?: string;
content: string;
plain?: string;
meta?: object;
}) {
return this.call('chat.message.sendMessage', payload);
}
/**
* Reply message
*/
async replyMessage(
replyInfo: {
messageId: string;
author: string;
content: string;
},
payload: {
converseId: string;
groupId?: string;
content: string;
plain?: string;
meta?: object;
}
) {
return this.sendMessage({
...payload,
meta: {
...payload.meta,
mentions: [replyInfo.author],
reply: {
_id: replyInfo.messageId,
author: replyInfo.author,
content: replyInfo.content,
},
},
content: `[at=${replyInfo.author}][/at] ${payload.content}`,
});
}
}

@ -11,6 +11,7 @@
"moduleResolution": "node",
"strict": true,
"importsNotUsedAsValues": "error",
"typeRoots": ["./node_modules/@types"]
},
"include": ["./src/*"]
}

@ -24,7 +24,7 @@ interface BBCodeProps {
plainText: string;
}
export const BBCode: React.FC<BBCodeProps> = React.memo(({ plainText }) => {
const bbcodeComponent = bbcodeParser.render(preProcessText(plainText));
const bbcodeComponent = bbcodeParser.render(preProcessText(plainText ?? ''));
return <Fragment>{bbcodeComponent}</Fragment>;
});

@ -7,9 +7,11 @@ export const MentionTag: React.FC<TagProps> = React.memo((props) => {
const userName = node.content.join('');
const userId = node.attrs.at;
const hasUserName = userName !== '';
return (
<span className="plugin-bbcode-mention-tag" data-userid={userId}>
@{userName ?? <UserName userId={userId} />}
@{hasUserName ? userName : <UserName userId={userId} />}
</span>
);
});

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save