Skip to content

Commit

Permalink
perf: update sstore to a lightweight version
Browse files Browse the repository at this point in the history
  • Loading branch information
beetcb committed Dec 5, 2021
1 parent 3864e04 commit 644dcf1
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 80 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@

- 多用户非阻塞: 利用 Node.js 异步特征,多用户可并行,实现毫秒级的多用户同时操作

- 关于签到插件: (学校配置时)使用百度地图 API 获取学校全局签到地址, 使用今日校园接口返回的签到数据获取签到经纬度, 简单来说, 只需知道学校英文简称即可配置好所有签到信息, 充分懒人化
- 关于签到插件: ([学校配置](./docs/config.md))使用百度地图 API 获取学校全局签到地址, 使用今日校园接口返回的签到数据获取签到经纬度, 简单来说, 只需知道学校英文简称即可配置好所有签到信息, 充分懒人化

- 关于签到或查寝中的图片上传:无需特意配置,Cea 会自动使用之前成功签到过的图片来完成上传,这样既无需配置图片地址、也在运行过程中省去了图片上传操作(我们都知道这是个相对耗时的过程)

- 支持日志路由转发到微信:方便查看运行结果日志 (详见 [部署指南](./docs/deploy.md)),这也方便 Cea 插件开发者实现推送和统一日志输出 (详见 [插件开发](https://github.com/ceajs/cea#%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91))

- 支持一键部署签到程序:依赖自动安装、触发器自动配置,可能是全网最快最方便的部署 (详见 [部署指南](./docs/deploy.md))
- 支持[一键部署签到程序](./docs/deploy.md):依赖自动安装、触发器自动配置,可能是全网最快最方便的部署

## 准备工作

Expand Down
42 changes: 21 additions & 21 deletions core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@
},
"license": "MIT",
"dependencies": {
"@beetcb/sstore": "^0.2.0",
"@ceajs/slider-captcha": "^0.0.0",
"@beetcb/sstore": "^0.3.0",
"@ceajs/slider-captcha": "^0.0.1",
"@iarna/toml": "^2.2.5",
"cheerio": "^1.0.0-rc.10",
"node-fetch": "^2.6.5",
"signale": "^1.4.0",
"terminal-image": "^2.0.0",
"tesseract.js": "^2.1.5",
"user-agents": "^1.0.799"
"user-agents": "^1.0.856"
},
"devDependencies": {
"@types/node-fetch": "^2.5.12",
Expand Down
22 changes: 12 additions & 10 deletions core/src/conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function getSchoolInfos({
const isSchoolAddrNeeded = users.find((e) => e.addr.length === 1)
for (const abbreviation of schoolNamesSet) {
res = (await fetch(
`https://mobile.campushoy.com/v6/config/guest/tenant/info?ids=${abbreviation}`
`https://mobile.campushoy.com/v6/config/guest/tenant/info?ids=${abbreviation}`,
).catch(log.error)) as Response

const data = (await res.json().catch(log.error)).data?.[0] as StringKV
Expand All @@ -51,9 +51,11 @@ export async function getSchoolInfos({
}
if (isSchoolAddrNeeded) {
res = (await fetch(
`https://api.map.baidu.com/?qt=s&wd=${encodeURIComponent(
data.name
)}&ak=E4805d16520de693a3fe707cdc962045&rn=10&ie=utf-8&oue=1&fromproduct=jsapi&res=api`
`https://api.map.baidu.com/?qt=s&wd=${
encodeURIComponent(
data.name,
)
}&ak=E4805d16520de693a3fe707cdc962045&rn=10&ie=utf-8&oue=1&fromproduct=jsapi&res=api`,
).catch(log.error)) as Response
const addrInfo = (await res.json()) as {
content: Array<{ addr: string; blinfo?: Array<string> }>
Expand All @@ -65,9 +67,11 @@ export async function getSchoolInfos({

// Get Edge-cases
const edgeCaseRes = await fetch(
`https://cea.beetcb.com/api/edge-case?name=${encodeURIComponent(
data.name
)}&c=${isCloud ? 'true' : ''}`
`https://cea.beetcb.com/api/edge-case?name=${
encodeURIComponent(
data.name,
)
}&c=${isCloud ? 'true' : ''}`,
).catch(log.error)
if (edgeCaseRes?.ok) {
const edgeCase = (await edgeCaseRes.json()) as SchoolEdgeCase
Expand All @@ -82,9 +86,7 @@ export async function getSchoolInfos({
edgeCase,
}
log.success(
`学校 ${data.name} 已完成设定,接入方式为 ${
isCloud ? 'CLOUD' : 'NOTCLOUD'
}`
`学校 ${data.name} 已完成设定,接入方式为 ${isCloud ? 'CLOUD' : 'NOTCLOUD'}`,
)
} else {
throw new Error('Failed to get school edge case!')
Expand Down
23 changes: 11 additions & 12 deletions core/src/crawler/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type { UnifiedLoginResult } from '../types/login'
*/
export default async function login(
school: SchoolConfOpts,
user: UserConfOpts
user: UserConfOpts,
) {
// improve school campatibility with defaults and edge-cases
const schoolEdgeCase: SchoolEdgeCase = school.edgeCase
Expand Down Expand Up @@ -68,13 +68,13 @@ export default async function login(
})

// Check captcha
const addtionalParams = `?username=${user.username}&ltId=${
hiddenInputNameValueMap.lt || ''
}&_=${Date.now()}`
const addtionalParams =
`?username=${user.username}&ltId=${hiddenInputNameValueMap.lt
|| ''}&_=${Date.now()}`
needCaptcha = (
await (
await fetch.get(
`${school.authOrigin}${schoolEdgeCase.checkCaptchaPath}${addtionalParams}`
`${school.authOrigin}${schoolEdgeCase.checkCaptchaPath}${addtionalParams}`,
)
).text()
).includes('true')
Expand Down Expand Up @@ -110,11 +110,9 @@ export default async function login(
// Handle captcha
while (true) {
if (needCaptcha) {
const captchaUrl = `${school.authOrigin}${
schoolEdgeCase.getCaptchaPath
}?username=${user.username}&ltId=${
hiddenInputNameValueMap.lt ?? ''
}&_=${Date.now()}`
const captchaUrl =
`${school.authOrigin}${schoolEdgeCase.getCaptchaPath}?username=${user.username}&ltId=${hiddenInputNameValueMap
.lt ?? ''}&_=${Date.now()}`
log.warn({
message: '登录需要验证码',
suffix: `@${name}`,
Expand Down Expand Up @@ -150,12 +148,13 @@ export default async function login(
const source: SliderCaptchaGetResult = await response.json()
const percentage = await sliderCaptchaRecognizer(
source.bigImage,
source.smallImage
source.smallImage,
)
const sliderCanvasLength = schoolEdgeCase.sliderCanvasLength ?? 280
if (percentage) {
const moveLength = Math.floor(sliderCanvasLength * percentage)
const verifySliderUrl = `${school.authOrigin}${schoolEdgeCase.verifySliderCaptchaPath}?canvasLength=${sliderCanvasLength}&moveLength=${moveLength}`
const verifySliderUrl =
`${school.authOrigin}${schoolEdgeCase.verifySliderCaptchaPath}?canvasLength=${sliderCanvasLength}&moveLength=${moveLength}`
log.warn({
message: `开始滑块验证,移动比例:${moveLength} / ${sliderCanvasLength}`,
suffix: `@${name}`,
Expand Down
4 changes: 2 additions & 2 deletions core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export async function handleCookie() {
users.map(async (i: UserConfOpts) => {
const storeCookiePath = `cookie.${i.alias}`
await handleLogin(i, storeCookiePath)
})
}),
)
} else {
log.error('请先加载用户 <cea load>')
Expand All @@ -46,7 +46,7 @@ export async function handleCookie() {
async function loginAndStoreCookie(
school: SchoolConfOpts,
user: UserConfOpts,
storeCookiePath: string
storeCookiePath: string,
) {
const result = await login(school, user)
if (result) {
Expand Down
4 changes: 2 additions & 2 deletions core/src/types/conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ export type UsersConf = {
readonly users: Array<UserConfOpts>
}
export type UserConfOpts = {
addr: [''] | [string, string, string]
readonly username: string
readonly password: string
readonly alias: string
readonly school: string
readonly retry?: number
readonly captcha?: 'MANUAL' | 'OCR'
readonly signedDataMonth?: `${number}-${number}`
addr: Array<string>
}

export type SchoolConf = {
[school: string]: SchoolConfOpts
}

export type SchoolConfOpts = {
readonly preAuthURL: string
readonly loginURL?: string
readonly preAuthURL: string
readonly captchaAuthMode: CaptchaAuthMode
readonly chineseName: string
readonly defaultAddr: string
Expand Down
26 changes: 10 additions & 16 deletions core/src/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,18 @@ const log: LogRouter = {
notify,
}

const logProxiedRouter = new Proxy(
log as typeof log & {
notify: () => Promise<void>
object: (obj: { [K: string]: string }) => void
},
{
get(target, prop, receiver) {
if (prop === 'error' || prop === 'success' || prop === 'warn') {
if (isNotificationEnabled) {
return (...args: any[]) => {
saveNotifications(args)
target[prop].apply(target, args)
}
const logProxiedRouter = new Proxy(log, {
get(target, prop, receiver) {
if (prop === 'error' || prop === 'success' || prop === 'warn') {
if (isNotificationEnabled) {
return (...args: any[]) => {
saveNotifications(args)
target[prop].apply(target, args)
}
}
return Reflect.get(target, prop, receiver)
},
}
return Reflect.get(target, prop, receiver)
},
)
})

export default logProxiedRouter
11 changes: 6 additions & 5 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
readonly notifier?: [`${number}`, string, string]
readonly users: Array<UserConfOpts>
}

type UserConfOpts = {
addr: [''] | [string, string, string]
readonly username: string
readonly password: string
readonly alias: string
readonly school: string
readonly retry?: number
readonly captcha?: 'MANUAL' | 'OCR'
readonly signedDataMonth?: `${number}-${number}`
addr: Array<string>
}
```
Expand All @@ -23,16 +25,15 @@
可以很清晰地看到,我们主要配置的是一个用户数组,每个用户有不同地配置项,下面我们就来看看各个配置项:
- `addr`: 配置签到地址,有两种可能的格式
- `[""]`:表示使用自动获取的学校地址签到
- `["经度""纬度", "中文详细地址"]`:适合在家签到
- `["经度""纬度", "中文详细地址"]`:适合自定义(或在家)签到
- `alias`:配置用户简称,用于简化输出,多用户 alias 不能重复
- `username`:学校统一身份验证的账号
- `password`: 学校统一身份验证的密码
- `school`:学校简称,部分学校是英文简称,其它学校是随机字符,请使用 **[学校 ID 查询工具](https://cea.beetcb.com)** 搜索查询
- `captcha`:可选配置项,决定登录时验证码的填写方式,缺省为 `OCR`,可填写 `MANUAL`,代表人工手动填写(交互式)
- `retry`:可选配置项,决定登录重试次数,缺省为 `1`,表示总共只登录一次,当登录有滑块/图片验证码时可适当增加此值
- `signedDataMonth`: 可选配置项,指定 `年份-月份`(`YY-MM`) 用于查寝(后面可能用于信息收集)签到时查找成功的历史签到,缺省值为 `21-11`;如果 21 年 11 月没有成功的签到数据,则需单独指定此值
## 配置格式及语法
Expand Down
Loading

0 comments on commit 644dcf1

Please sign in to comment.