-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from Clansty/easymob
Easymob
- Loading branch information
Showing
23 changed files
with
968 additions
and
208 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
username: '学习通登录名' | ||
password: 学习通密码 | ||
dbName: YJSNPI | ||
bot: | ||
uin: qq机器人用户名 | ||
password: 机器人密码 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import ImMessageCheckin from '../types/ImMessageCheckin' | ||
import {error, info, success, warn} from '../utils/log' | ||
import getCheckinDetail from '../requests/getCheckinDetail' | ||
import * as db from '../providers/db' | ||
import handlerSimpleCheckin from './handlerSimpleCheckin' | ||
import pushQMsg from '../utils/pushQMsg' | ||
|
||
export default async (message: ImMessageCheckin) => { | ||
try { | ||
if (!message.ext.attachment) return | ||
if (message.ext.attachment.attachmentType !== 15) { | ||
//不是签到信息 | ||
return | ||
} | ||
const aid = message.ext.attachment.att_chat_course.aid | ||
const courseName = message.ext.attachment.att_chat_course.courseInfo.coursename | ||
if (!aid) { | ||
warn('处理 IM 消息时出现异常,找不到 aid') | ||
return | ||
} | ||
switch (message.ext.attachment.att_chat_course.atype) { | ||
case 2: | ||
const checkinInfo = await getCheckinDetail(await db.getMeta<string>('cookie'), aid) | ||
info('收到', checkinInfo.type, '类型签到') | ||
let mts = `收到 ${courseName} 的签到\n类型:${checkinInfo.type}` | ||
if (checkinInfo.type !== 'qr') { | ||
try { | ||
const res = await handlerSimpleCheckin(aid) | ||
mts += `\n自动签到:${res}` | ||
if (res === 'success') { | ||
success('签到成功', aid) | ||
} | ||
else | ||
warn('签到失败', aid, res) | ||
} catch (e) { | ||
error('签到失败', aid, e) | ||
mts += `\n自动签到:抛错\n${e}` | ||
} | ||
} | ||
else { | ||
info('收到二维码签到') | ||
mts = `收到 ${courseName} 的二维码签到,需要提供一张二维码` | ||
} | ||
pushQMsg(mts) | ||
break | ||
default: | ||
const activityName=message.ext.attachment.att_chat_course.atypeName | ||
pushQMsg(`收到 ${courseName} 的 ${activityName} 类型活动`) | ||
} | ||
} catch (e) { | ||
error('处理 IM 消息时出现异常,可能不是活动消息', e) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import * as db from '../providers/db' | ||
import {genSimpleCheckinParams} from '../utils/genCheckinParams' | ||
import checkin from '../requests/checkin' | ||
|
||
export default async (activeId: string | number) => { | ||
const cookie = await db.getMeta<string>('cookie') | ||
const name = await db.getMeta<string>('name') | ||
const uid = await db.getMeta<number>('uid') | ||
|
||
const params = genSimpleCheckinParams({uid, name, activeId}) | ||
return await checkin(cookie, params) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,36 @@ | ||
import config from "./providers/config"; | ||
import validateCookie from "./requests/validateCookie"; | ||
import { info, warn } from "./utils/log"; | ||
import * as db from "./providers/db"; | ||
import { bot, loginBot } from "./providers/bot"; | ||
import loginAndSaveInfo from "./utils/loginAndSaveInfo"; | ||
import axios from "axios"; | ||
import attachGroupMessageHandler from "./handlers/attachGroupMessageHandler"; | ||
import validateCookie from './requests/validateCookie' | ||
import {info, success, warn} from './utils/log' | ||
import * as db from './providers/db' | ||
import {bot, loginBot} from './providers/bot' | ||
import loginAndSaveInfo from './utils/loginAndSaveInfo' | ||
import axios from 'axios' | ||
import attachGroupMessageHandler from './handlers/attachGroupMessageHandler' | ||
import {imConnect} from './providers/easemob' | ||
|
||
(async () => { | ||
//初始化数据库连接和 bot | ||
axios.defaults.proxy = false; | ||
await db.connect(config.dbName); | ||
await loginBot(); | ||
console.info("系统初始化完毕"); | ||
//验证及获取 cookie | ||
let isCookieValid = false; | ||
let cookie = await db.getMeta<string>("cookie"); | ||
if (cookie) { | ||
isCookieValid = await validateCookie(cookie); | ||
if (isCookieValid) info("Cookie 有效"); | ||
else warn("Cookie 无效"); | ||
} | ||
if (!isCookieValid) { | ||
cookie = await loginAndSaveInfo(); | ||
} | ||
//登录步骤完成 | ||
const schoolname = await db.getMeta<string>("schoolname"); | ||
const name = await db.getMeta<string>("name"); | ||
info(`欢迎来自 ${schoolname} 的 ${name}`); | ||
//机器人接收二维码和解码签到事件 | ||
attachGroupMessageHandler(bot); | ||
})(); | ||
//初始化数据库连接和 bot | ||
axios.defaults.proxy = false | ||
await db.connect() | ||
await loginBot() | ||
//验证及获取 cookie | ||
let isCookieValid = false | ||
let cookie = await db.getMeta<string>('cookie') | ||
if (cookie) { | ||
isCookieValid = await validateCookie(cookie) | ||
if (isCookieValid) info('Cookie 有效') | ||
else warn('Cookie 无效') | ||
} | ||
if (!isCookieValid) { | ||
cookie = await loginAndSaveInfo() | ||
} | ||
//登录步骤完成 | ||
const schoolname = await db.getMeta<string>('schoolname') | ||
const name = await db.getMeta<string>('name') | ||
success(`欢迎来自 ${schoolname} 的 ${name}`) | ||
//机器人接收二维码和解码签到事件 | ||
attachGroupMessageHandler(bot) | ||
//连接 IM | ||
info('准备连接 IM') | ||
await imConnect() | ||
info('系统初始化完毕') | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,33 @@ | ||
import fs from "fs/promises"; | ||
import fsOrigin from "fs"; | ||
import fs from 'fs/promises' | ||
import fsOrigin from 'fs' | ||
|
||
let meta: Record<string, any> = {}; | ||
let thisDbName: string; | ||
let meta: Record<string, any> = {} | ||
|
||
export const connect = async (dbName: string) => { | ||
thisDbName = dbName; | ||
try { | ||
// 按道理可以改成同步的,但是懒得手动返回 Promise 了 | ||
const metaStream = await fs.readFile( | ||
`./build/data/data-${thisDbName}.json` | ||
); | ||
const metaStr = metaStream.toString(); | ||
meta = JSON.parse(metaStr); | ||
} catch (error) {} // 试图读取数据,没有数据就当无事发生 | ||
}; | ||
export const connect = async () => { | ||
try { | ||
// 按道理可以改成同步的,但是懒得手动返回 Promise 了 | ||
const metaStream = await fs.readFile( | ||
'./data/superstar-data.json', | ||
) | ||
const metaStr = metaStream.toString() | ||
meta = JSON.parse(metaStr) | ||
} catch (error) { | ||
} // 试图读取数据,没有数据就当无事发生 | ||
} | ||
|
||
export const getMeta = async <T>(name: string) => { | ||
const data = meta[name]; | ||
return data ? (data as T) : null; | ||
}; | ||
const data = meta[name] | ||
return data ? (data as T) : null | ||
} | ||
|
||
export const setMeta = async <T>(name: string, value: T) => { | ||
meta[name] = value; | ||
}; | ||
meta[name] = value | ||
} | ||
|
||
process.on("SIGINT", () => { | ||
fsOrigin.writeFileSync( | ||
`./build/data/data-${thisDbName}.json`, | ||
JSON.stringify(meta, null, 2) | ||
); | ||
process.exit(0); | ||
}); | ||
process.on('SIGINT', () => { | ||
fsOrigin.writeFileSync( | ||
'./data/superstar-data.json', | ||
JSON.stringify(meta, null, 2), | ||
) | ||
process.exit(0) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
//提供学习通即时通信协议 | ||
|
||
import jsdom from 'jsdom' | ||
|
||
const {JSDOM} = jsdom //在jsdom中导出JSDOM对象 | ||
const {window} = new JSDOM('<!doctype html><html><body></body></html>', {url: 'https://im.chaoxing.com/webim/me'}); //导出JSDOM中的window对象 | ||
(global as any).window = window; //将window对象设置为nodejs中全局对象; | ||
(global as any).navigator = window.navigator; | ||
(global as any).location = window.location; | ||
(global as any).document = window.document; | ||
(global as any).WebSocket = window.WebSocket | ||
import '../sdk/Easemob-chat-3.6.3' | ||
import {info, success, warn} from '../utils/log' | ||
import * as db from './db' | ||
import getImToken from '../requests/getImToken' | ||
import handleEasemobMessage from '../handlers/handleEasemobMessage' | ||
import sleep from '../utils/sleep' | ||
|
||
window.WebIM.config = { | ||
xmppURL: 'https://im-api-vip6-v2.easecdn.com/ws', | ||
apiURL: 'https://a1-vip6.easecdn.com', | ||
appkey: 'cx-dev#cxstudy', | ||
Host: 'easemob.com', | ||
https: true, | ||
isHttpDNS: false, | ||
isMultiLoginSessions: true, | ||
isAutoLogin: true, | ||
isWindowSDK: false, | ||
isSandBox: false, | ||
isDebug: false, | ||
autoReconnectNumMax: Number.POSITIVE_INFINITY, | ||
autoReconnectInterval: 2, | ||
isWebRTC: true, | ||
heartBeatWait: 2000, | ||
delivery: false, | ||
} | ||
window.WebIM.conn = new window.WebIM.connection({ | ||
appKey: window.WebIM.config.appkey, | ||
isHttpDNS: window.WebIM.config.isHttpDNS, | ||
isMultiLoginSessions: window.WebIM.config.isMultiLoginSessions, | ||
host: window.WebIM.config.Host, | ||
https: window.WebIM.config.https, | ||
url: window.WebIM.config.xmppURL, | ||
apiUrl: window.WebIM.config.apiURL, | ||
isAutoLogin: false, | ||
heartBeatWait: window.WebIM.config.heartBeatWait, | ||
autoReconnectNumMax: window.WebIM.config.autoReconnectNumMax, | ||
autoReconnectInterval: window.WebIM.config.autoReconnectInterval, | ||
isStropheLog: window.WebIM.config.isStropheLog, | ||
delivery: window.WebIM.config.delivery, | ||
isDebug: window.WebIM.config.isDebug, | ||
}) | ||
|
||
window.WebIM.conn.listen({ | ||
onOpened: function (message) { | ||
success('IM 协议连接成功') | ||
}, | ||
onClosed: function (message) { | ||
warn('IM 协议连接关闭') | ||
}, | ||
onTextMessage: function (message) { | ||
info('IM 协议收到文本消息', JSON.stringify(message)) | ||
handleEasemobMessage(message) | ||
}, | ||
onEmojiMessage: function (message) { | ||
}, | ||
onPictureMessage: function (message) { | ||
}, | ||
onCmdMessage: function (message) { | ||
}, | ||
onAudioMessage: function (message) { | ||
}, | ||
onLocationMessage: function (message) { | ||
}, | ||
onFileMessage: function (message) { | ||
}, | ||
onVideoMessage: function (message) { | ||
}, | ||
onPresence: function (message) { | ||
}, | ||
onRoster: function (message) { | ||
}, | ||
onInviteMessage: function (message) { | ||
}, | ||
onOnline: function () { | ||
}, | ||
onOffline: function () { | ||
warn('IM 下线') | ||
}, | ||
onError: async function (message) { | ||
warn('IM 协议错误', message) | ||
if(message.type===40){ | ||
window.WebIM.conn.close() | ||
warn('IM 协议身份验证失败,重新获取 token') | ||
await sleep(2000) | ||
imConnect() | ||
} | ||
}, | ||
onBlacklistUpdate: function (list) { | ||
}, | ||
}) | ||
|
||
const connect = (user: string | number, accessToken: string) => { | ||
const options = { | ||
apiUrl: 'https://a1-vip6.easecdn.com', | ||
user, | ||
accessToken, | ||
appKey: 'cx-dev#cxstudy', | ||
} | ||
window.WebIM.conn.open(options) | ||
} | ||
|
||
export const imConnect = async () => { | ||
const cookie = await db.getMeta<string>('cookie') | ||
const uid = await db.getMeta<number>('uid') | ||
const imToken = await getImToken(cookie) | ||
connect(uid, imToken) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.