├── .eslintrc.json
├── .github
└── FUNDING.yml
├── .gitignore
├── .releaserc.json
├── .travis.yml
├── LICENSE
├── README.md
├── cq-websocket.d.ts
├── demo
├── echobot.js
└── webpack
│ ├── app.js
│ ├── webpack.config.js
│ └── www
│ ├── bundle.js
│ └── index.html
├── dist
├── cq-websocket.kaomojified.js
└── cq-websocket.min.js
├── docs
├── CHANGELOG-v1.md
├── CHANGELOG.md
├── CNAME
├── README.md
├── _config.yml
├── api
│ ├── ArrayMessage.md
│ ├── CQEvent.md
│ ├── CQHTTPMessage.md
│ ├── CQWebSocket.md
│ ├── EventListener.md
│ ├── README.md
│ ├── WebSocketState.md
│ ├── WebSocketType.md
│ ├── errors.md
│ ├── events.md
│ └── messages.md
└── get-started
│ ├── README.md
│ ├── connection.md
│ ├── errors.md
│ ├── example.md
│ └── features.md
├── package-lock.json
├── package.json
├── performance
├── leak.test.js
├── leakage
│ ├── on-off.test.js
│ └── once.test.js
├── package.json
└── sample.js
├── renovate.json
├── src
├── errors.js
├── event-bus.js
├── index.js
├── message
│ ├── CQTag.js
│ ├── index.js
│ ├── isSupportedTag.js
│ ├── models
│ │ ├── CQAnonymous.js
│ │ ├── CQAt.js
│ │ ├── CQBFace.js
│ │ ├── CQCustomMusic.js
│ │ ├── CQDice.js
│ │ ├── CQEmoji.js
│ │ ├── CQFace.js
│ │ ├── CQImage.js
│ │ ├── CQMusic.js
│ │ ├── CQRPS.js
│ │ ├── CQRecord.js
│ │ ├── CQSFace.js
│ │ ├── CQShake.js
│ │ ├── CQShare.js
│ │ ├── CQText.js
│ │ └── index.js
│ └── parse.js
└── util
│ ├── callable.js
│ ├── optional.js
│ └── traverse.js
├── test
├── api
│ └── index.test.js
├── connection
│ ├── connection.test.js
│ ├── error-after-success.js
│ ├── failure-without-success.js
│ ├── manual-reconnect-after-closed.js
│ ├── manual-reconnect-after-success.js
│ ├── multiple-connect-calls-before-success.js
│ ├── multiple-disconnect-calls-before-disconnected.js
│ ├── multiple-reconnect-calls-before-reconnected.js
│ ├── success-after-failures.js
│ └── success-without-failure.js
├── events
│ ├── cq-event.test.js
│ ├── events.js
│ ├── events.test.js
│ └── invalid-context.test.js
├── features
│ └── auto-fetch-qq.test.js
├── fixture
│ ├── CQFakeTag.js
│ ├── FakeWebSocket.js
│ ├── connect-success.js
│ └── setup.js
├── message
│ ├── CQTag.test.js
│ ├── models.test.js
│ ├── models
│ │ ├── CQAnonymous.js
│ │ ├── CQAt.js
│ │ ├── CQBFace.js
│ │ ├── CQCustomMusic.js
│ │ ├── CQDice.js
│ │ ├── CQEmoji.js
│ │ ├── CQFace.js
│ │ ├── CQImage.js
│ │ ├── CQMusic.js
│ │ ├── CQRPS.js
│ │ ├── CQRecord.js
│ │ ├── CQSFace.js
│ │ ├── CQShake.js
│ │ ├── CQShare.js
│ │ └── CQText.js
│ └── parse.test.js
└── unit
│ ├── CQWebsocket.test.js
│ ├── call.test.js
│ ├── connect.test.js
│ ├── disconnect.test.js
│ ├── isReady.test.js
│ ├── isSocketConnected.test.js
│ ├── off.test.js
│ ├── on.test.js
│ ├── once.test.js
│ └── reconnect.test.js
└── webpack.config.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "standard"
3 | }
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
4 | - https://www.buymeacoffee.com/momocow
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 |
--------------------------------------------------------------------------------
/.releaserc.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "@semantic-release/commit-analyzer",
4 | "@semantic-release/release-notes-generator",
5 | [
6 | "@semantic-release/changelog",
7 | {
8 | "changelogFile": "docs/CHANGELOG.md",
9 | "changelogTitle": "CQWebSocket"
10 | }
11 | ],
12 | "@semantic-release/npm",
13 | "@semantic-release/github",
14 | [
15 | "@semantic-release/git",
16 | {
17 | "assets": [
18 | "dist/**/*.js",
19 | "docs/CHANGELOG.md",
20 | "package.json",
21 | "package-lock.json",
22 | "npm-shrinkwrap.json"
23 | ]
24 | }
25 | ]
26 | ]
27 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: 8
3 |
4 | script:
5 | - npm run lint
6 | - npm test
7 | - npm run build
8 |
9 | deploy:
10 | provider: script
11 | skip_cleanup: true
12 | on:
13 | branch: master
14 | script:
15 | - npm run release
16 |
17 | after_success: npm run coverage
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 牛牛/MomoCow
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > **本項目即日起停止維護,隨著酷Q、CQHTTP一同走入歷史,畫下完美句點。感謝各方好友的支持與參與。**
2 |
3 | ---
4 |
5 | # node-cq-websocket
6 | [](https://www.npmjs.com/package/cq-websocket)
7 | [](https://www.npmjs.com/package/cq-websocket)
8 | [](https://github.com/momocow/node-cq-websocket#readme)
9 | [](https://github.com/richardchien/coolq-http-api#readme)
10 | [](http://commitizen.github.io/cz-cli/)
11 | [](https://github.com/semantic-release/semantic-release)
12 | [](https://snyk.io//test/github/momocow/node-cq-websocket?targetFile=package.json)
13 |
14 | ## 🚧 分支狀態
15 | - 主線
16 | - [](https://travis-ci.org/momocow/node-cq-websocket)
17 | - [](https://coveralls.io/github/momocow/node-cq-websocket?branch=master)
18 | - dev
19 | - [](https://travis-ci.org/momocow/node-cq-websocket)
20 | - [](https://coveralls.io/github/momocow/node-cq-websocket?branch=dev)
21 |
22 | ## 🗯️ 關於此 SDK
23 | 依賴 CQHTTP API 插件的 websocket 接口, 為 NodeJs 開發者提供一個搭建 QQ 聊天機器人的 SDK。
24 |
25 | 關於 CQHTTP API 插件,見 [richardchien/coolq-http-api](https://github.com/richardchien/coolq-http-api#readme)
26 |
27 | > 本 SDK 尚處於測試階段,使用上仍有機會碰到Bug,歡迎提交PR或issue回報。
28 |
29 | > 由於付費問題,本 SDK 目前僅針對酷Q Air做測試。
30 |
31 | ## 🎉 功能/特色
32 | - 輕鬆配置, 快速搭建 QQ 聊天機器人。
33 | - 自動維護底層連線, 開發者只需專注在聊天應用的開發。若斷線, 可依照配置[重新連線](docs/get-started/features.md#%E6%96%B7%E7%B7%9A%E9%87%8D%E9%80%A3)。
34 | - 支持消息監聽器內, [快速響應](docs/get-started/features.md#%E5%BF%AB%E9%80%9F%E9%9F%BF%E6%87%89)。
35 | - 連線建立時, 可[自動獲取機器人QQ號](docs/get-started/features.md#%E8%87%AA%E5%8B%95%E7%8D%B2%E5%8F%96%E6%A9%9F%E5%99%A8%E4%BA%BAqq%E8%99%9F)。
36 |
37 | ## 🗎 SDK 文件
38 | [閱讀更多 ➡️](docs/README.md)
39 |
40 | ## 🛠️ 開發者看板
41 | 本 SDK 採用 [ava](https://github.com/avajs/ava) 框架執行測試。
42 |
43 | ### 打包 CQWebSocket 至 browser 環境
44 | ```
45 | npm run build
46 | ```
47 | 使用 webpack 將 SDK 及所有依賴打包, 並在 `/dist`目錄下產生一個 `cq-websocket.min.js`。
48 |
49 | ### 建置 demo/webpack
50 | ```
51 | npm run build-demo
52 | ```
53 | 打包 `/demo/webpack/app.js` 內容, 在 `/demo/webpack/www` 目錄下產生一個 `bundle.js`。
54 |
55 | ### 開發日誌
56 | [閱讀更多 ➡️](docs/CHANGELOG.md)
57 |
58 | ### Known Issues
59 | - CQHTTP API 插件尚未支援收發 Fragmant, 暫時禁用
60 | - 自`v1.2.6`
61 | - [node-cq-websocket #2](https://github.com/momocow/node-cq-websocket/pull/2)
62 | - [coolq-http-api #85](https://github.com/richardchien/coolq-http-api/issues/85)
63 | - 在 Node 10.x 下, Buffer 寫入時的 RangeError (發生在 SDK 調用 API 方法時)。
64 | > 這是 Node 的問題, 暫時使用 Node 8.x 以下就沒問題。
65 | ```
66 | RangeError [ERR_OUT_OF_RANGE]: The value of "value" is out of range. It must be >= 0 and <= 4294967295. Received -805456141
67 | at checkInt (internal/buffer.js:35:11)
68 | at writeU_Int32BE (internal/buffer.js:625:3)
69 | at Buffer.writeUInt32BE (internal/buffer.js:638:10)
70 | at WebSocketFrame.toBuffer (/***/node-cq-websocket/node_modules/websocket/lib/WebSocketFrame.js:257:24)
71 | at WebSocketConnection.sendFrame (/***/node-cq-websocket/node_modules/websocket/lib/WebSocketConnection.js:857:43)
72 | at WebSocketConnection.fragmentAndSend (/***/node-cq-websocket/node_modules/websocket/lib/WebSocketConnection.js:793:14)
73 | at WebSocketConnection.sendUTF (/***/node-cq-websocket/node_modules/websocket/lib/WebSocketConnection.js:733:10)
74 | at W3CWebSocket.send (/***/node-cq-websocket/node_modules/websocket/lib/W3CWebSocket.js:116:26)
75 | ```
76 |
77 | ## 🍙 歡迎餵食
78 | 請勿拍打 🤜 無限期掙飯中 ☕
79 |
80 |
81 |
--------------------------------------------------------------------------------
/cq-websocket.d.ts:
--------------------------------------------------------------------------------
1 | export enum WebSocketType {
2 | API = '/api',
3 | EVENT = '/event'
4 | }
5 | export enum WebSocketState {
6 | DISABLED = -1,
7 | INIT = 0,
8 | CONNECTING = 1,
9 | CONNECTED = 2,
10 | CLOSING = 3,
11 | CLOSED = 4
12 | }
13 | export interface CQRequestOptions {
14 | timeout: number
15 | }
16 | export type WebSocketProtocol = "http:" | "https:" | "ws:" | "wss:"
17 | export interface CQWebSocketOption {
18 | accessToken: string
19 | enableAPI: boolean
20 | enableEvent: boolean
21 | protocol: WebSocketProtocol
22 | host: string
23 | port: number
24 | baseUrl: string
25 | qq: number | string
26 | reconnection: boolean
27 | reconnectionAttempts: number
28 | reconnectionDelay: number
29 | fragmentOutgoingMessages: boolean
30 | fragmentationThreshold: number
31 | tlsOptions: any
32 | requestOptions: CQRequestOptions
33 | }
34 |
35 | export type BaseEvents = 'message'
36 | | 'notice'
37 | | 'request'
38 | | 'error'
39 | | 'ready'
40 | export type MessageEvents = 'message.private'
41 | | 'message.discuss'
42 | | 'message.discuss.@'
43 | | 'message.discuss.@.me'
44 | | 'message.group'
45 | | 'message.group.@'
46 | | 'message.group.@.me'
47 |
48 | export type NoticeEvents = 'notice.group_upload'
49 | | 'notice.group_admin.set'
50 | | 'notice.group_admin.unset'
51 | | 'notice.group_decrease.leave'
52 | | 'notice.group_decrease.kick'
53 | | 'notice.group_decrease.kick_me'
54 | | 'notice.group_increase.approve'
55 | | 'notice.group_increase.invite'
56 | | 'notice.friend_add'
57 | // node
58 | | 'notice.group_admin'
59 | | 'notice.group_decrease'
60 | | 'notice.group_increase'
61 |
62 | export type RequestEvents = 'request.friend'
63 | | 'request.group.add'
64 | | 'request.group.invite'
65 | // node
66 | | 'request.group'
67 |
68 | export type MetaEvents = 'meta_event.lifecycle'
69 | | 'meta_event.heartbeat'
70 |
71 | export type SocketEvents = 'socket.connecting'
72 | | 'socket.connect'
73 | | 'socket.failed'
74 | | 'socket.reconnecting'
75 | | 'socket.reconnect'
76 | | 'socket.reconnect_failed'
77 | | 'socket.max_reconnect'
78 | | 'socket.closing'
79 | | 'socket.close'
80 | | 'socket.error'
81 |
82 | export type APIEvents = 'api.send.pre' | 'api.send.post' | 'api.response'
83 |
84 | export type Events = BaseEvents | MessageEvents | NoticeEvents | RequestEvents | SocketEvents | APIEvents
85 |
86 | export type ListenerReturn = void | Promise
87 | export type ArrayMessage = (CQTag|CQHTTPMessage|string)[]
88 | export type MessageListenerReturn = ListenerReturn | string | Promise | ArrayMessage | Promise | Promise
89 | export type MessageEventListener = (event: CQEvent, context: Record, tags: CQTag[]) => MessageListenerReturn
90 | export type ContextEventListener = (context: Record) => ListenerReturn
91 | export type SocketEventListener = (type: WebSocketType, attempts: number) => ListenerReturn
92 | export type SocketExcludeType = 'socket.connect' | 'socket.closing' | 'socket.close' | 'socket.error'
93 |
94 | export interface APITimeoutError extends Error {
95 | readonly req: APIRequest
96 | }
97 |
98 | export interface SocketError extends Error { }
99 |
100 | export interface InvalidWsTypeError extends Error {
101 | readonly which: WebSocketType
102 | }
103 |
104 | export interface InvalidContextError extends SyntaxError {
105 | readonly which: WebSocketType
106 | readonly data: string
107 | }
108 |
109 | export interface UnexpectedContextError extends Error {
110 | readonly context: Record
111 | readonly reason: string
112 | }
113 |
114 | export declare class CQEvent {
115 | readonly messageFormat: "string" | "array"
116 | stopPropagation (): void
117 | getMessage (): string | ArrayMessage
118 | setMessage (msg: string | ArrayMessage): void
119 | appendMessage (msg: string | CQTag | CQHTTPMessage): void
120 | hasMessage (): boolean
121 | onResponse (handler: (res: object) => void, options: number | CQRequestOptions): void
122 | onError (handler: (err: APITimeoutError) => void): void
123 | }
124 |
125 | export interface APIRequest {
126 | action: string,
127 | params?: any
128 | }
129 | export interface APIResponse {
130 | status: string,
131 | retcode: number,
132 | data: T
133 | }
134 |
135 | export class CQWebSocket {
136 | constructor (opt?: Partial)
137 |
138 | connect (wsType?: WebSocketType): CQWebSocket
139 | disconnect (wsType?: WebSocketType): CQWebSocket
140 | reconnect (delay?: number, wsType?: WebSocketType): CQWebSocket
141 | isSockConnected (wsType: WebSocketType): CQWebSocket
142 | isReady (): boolean
143 |
144 | on (event_type: MessageEvents | 'message', listener: MessageEventListener): CQWebSocket
145 | on (
146 | event_type: NoticeEvents | RequestEvents | MetaEvents | 'notice' | 'request' | 'meta_event',
147 | listener: ContextEventListener
148 | ): CQWebSocket
149 | on (event_type: Exclude, listener: SocketEventListener): CQWebSocket
150 | on (event_type: 'socket.connect', listener: (type: WebSocketType, socket: any, attempts: number) => void): CQWebSocket
151 | on (event_type: 'socket.closing', listener: (type: WebSocketType) => void): CQWebSocket
152 | on (event_type: 'socket.close', listener: (type: WebSocketType, code: number, desc: string) => void): CQWebSocket
153 | on (event_type: 'socket.error', listener: (type: WebSocketType, err: SocketError) => void): CQWebSocket
154 | on (event_type: 'api.send.pre', listener: (apiRequest: APIRequest) => void): CQWebSocket
155 | on (event_type: 'api.send.post', listener: () => void): CQWebSocket
156 | on (event_type: 'api.response', listener: (result: APIResponse) => void): CQWebSocket
157 | on (event_type: 'error', listener: (err: InvalidContextError | UnexpectedContextError) => void): CQWebSocket
158 | on (event_type: 'ready', listener: () => void): CQWebSocket
159 |
160 | once (event_type: MessageEvents | 'message', listener: MessageEventListener): CQWebSocket
161 | once (
162 | event_type: NoticeEvents | RequestEvents | MetaEvents | 'notice' | 'request' | 'meta_event',
163 | listener: ContextEventListener
164 | ): CQWebSocket
165 | once (event_type: Exclude, listener: SocketEventListener): CQWebSocket
166 | once (event_type: 'socket.connect', listener: (type: WebSocketType, socket: any, attempts: number) => void): CQWebSocket
167 | once (event_type: 'socket.closing', listener: (type: WebSocketType) => void): CQWebSocket
168 | once (event_type: 'socket.close', listener: (type: WebSocketType, code: number, desc: string) => void): CQWebSocket
169 | once (event_type: 'socket.error', listener: (type: WebSocketType, err: Error) => void): CQWebSocket
170 | once (event_type: 'api.send.pre', listener: (apiRequest: APIRequest) => void): CQWebSocket
171 | once (event_type: 'api.send.post', listener: () => void): CQWebSocket
172 | once (event_type: 'api.response', listener: (result: APIResponse) => void): CQWebSocket
173 | once (event_type: 'error', listener: (err: Error) => void): CQWebSocket
174 | once (event_type: 'ready', listener: () => void): CQWebSocket
175 |
176 | off (event_type?: Events, listener?: Function): CQWebSocket
177 | }
178 | export interface CQWebSocket {
179 | (method: string, params?: Record, options?: number | CQRequestOptions): Promise>
180 | }
181 |
182 | export default CQWebSocket
183 |
184 | /******************************************/
185 |
186 | export type Serializable = string | number | boolean
187 |
188 | export interface CQHTTPMessage {
189 | type: string
190 | data: Record | null
191 | }
192 |
193 | export declare class CQTag {
194 | readonly tagName: string
195 | readonly data: Readonly>
196 | modifier: Record
197 |
198 | equals(another: CQTag): boolean
199 | coerce(): this
200 | toJSON(): CQHTTPMessage
201 | valueOf(): string
202 | toString(): string
203 | }
204 |
205 | export class CQAt extends CQTag {
206 | readonly qq: number
207 | constructor(qq: number)
208 | }
209 |
210 | export class CQAnonymous extends CQTag {
211 | ignore: boolean
212 | constructor(shouldIgnoreIfFailed?: boolean)
213 | }
214 |
215 | export class CQBFace extends CQTag {
216 | readonly id: number
217 |
218 | /**
219 | * To send a bface, not only `id` but also `p`,
220 | * which is the name of child directory of `data/bface`,
221 | * is required.
222 | * @see https://github.com/richardchien/coolq-http-api/wiki/CQ-%E7%A0%81%E7%9A%84%E5%9D%91
223 | */
224 | constructor (id: number, p: string)
225 | }
226 |
227 | export class CQCustomMusic extends CQTag {
228 | readonly url: string
229 | readonly audio: string
230 | readonly title: string
231 | readonly content?: string
232 | readonly image?: string
233 | readonly type: "custom"
234 | constructor(url: string, audio: string, title: string, content?: string, image?: string)
235 | }
236 |
237 | export class CQDice extends CQTag {
238 | readonly type: number
239 | constructor()
240 | }
241 |
242 | export class CQEmoji extends CQTag {
243 | readonly id: number
244 | constructor(id: number)
245 | }
246 |
247 | export class CQFace extends CQTag {
248 | readonly id: number
249 | constructor(id: number)
250 | }
251 |
252 | export class CQImage extends CQTag {
253 | readonly file: string
254 | readonly url?: string
255 | cache?: boolean
256 | constructor(file: string, cache?: boolean)
257 | }
258 |
259 | export class CQMusic extends CQTag {
260 | readonly type: string
261 | readonly id: number
262 | constructor(type: string, id: number)
263 | }
264 |
265 | export class CQRecord extends CQTag {
266 | readonly file: string
267 | magic?: true
268 | constructor(file: string, magic?: boolean)
269 | hasMagic(): boolean
270 | }
271 |
272 | export class CQRPS extends CQTag {
273 | readonly type: number
274 | constructor()
275 | }
276 |
277 | export class CQSFace extends CQTag {
278 | readonly id: number
279 | constructor(id: number)
280 | }
281 |
282 | export class CQShake extends CQTag {
283 | constructor()
284 | }
285 |
286 | export class CQShare extends CQTag {
287 | readonly url: string
288 | readonly title: string
289 | readonly content?: string
290 | readonly image?: string
291 | constructor(url: string, title: string, content?: string, image?: string)
292 | }
293 |
294 | export class CQText extends CQTag {
295 | readonly text: string
296 | constructor(text: string)
297 | }
298 |
--------------------------------------------------------------------------------
/demo/echobot.js:
--------------------------------------------------------------------------------
1 | ///******************************/
2 | ///* 這是一台最基礎的複讀機 */
3 | ///******************************/
4 |
5 | const mri = require('mri')
6 | const options = mri(process.argv.slice(2), {
7 | alias: {
8 | help: 'h'
9 | },
10 | boolean: [ 'help' ]
11 | })
12 |
13 | if (options.help) {
14 | console.log('\nUsage: npm run demo-echobot -- [options]\n')
15 | console.log('Options:')
16 | console.log(' -h,--help Show usage\n')
17 | console.log(' --host CQHttp ws server host')
18 | console.log(' --port CQHttp ws server port')
19 | console.log(' --url CQHttp ws server base URL')
20 | console.log(' --token CQHttp ws server access token')
21 | console.log(' --qq QQ account of the bot, used to determine whether someone "@" the bot or not')
22 | } else {
23 | const CQWebsocket = require('../')
24 | let bot = new CQWebsocket({
25 | host: options.host,
26 | port: options.port,
27 | baseUrl: options.url,
28 | qq: options.qq,
29 | accessToken: options.token
30 | })
31 |
32 | // 設定訊息監聽
33 | bot
34 | // 連線例外處理
35 | .on('socket.error', console.error)
36 | .on('socket.connecting', (wsType) => console.log('[%s] 建立連線中, 請稍後...', wsType))
37 | .on('socket.connect', (wsType, sock, attempts) => console.log('[%s] 連線成功 ヽ(✿゚▽゚)ノ 蛆蛆%d個嘗試', wsType, attempts))
38 | .on('socket.failed', (wsType, attempts) => console.log('[%s] 連線失敗 。・゚・(つд`゚)・゚・ [丑%d] 對噗起', wsType, attempts))
39 | .on('api.response', (resObj) => console.log('伺服器響應: %O', resObj))
40 | .on('socket.close', (wsType, code, desc) => console.log('[%s] 連線關閉(%d: %s)', wsType, code, desc))
41 | .on('ready', () => console.log('今天又是複讀複讀的一天 。:.゚ヽ(*´∀`)ノ゚.:。'))
42 |
43 | // 聽取私人信息
44 | .on('message.private', (e, context) => {
45 | console.log('叮咚 ✿')
46 | console.log(context)
47 |
48 | // 以下提供三種方式將原訊息以原路送回
49 | switch (Date.now() % 3) {
50 | case 0:
51 | // 1. 調用 CoolQ HTTP API 之 send_msg 方法
52 | bot('send_msg', context)
53 | break
54 | case 1:
55 | // 2. 或者透過返回值快速響應
56 | return context.message
57 | case 2:
58 | // 3. 或者透過CQEvent實例,先獲取事件處理權再設置響應訊息
59 | e.stopPropagation()
60 | e.setMessage(context.message)
61 | }
62 | })
63 |
64 | bot.connect()
65 | }
66 |
--------------------------------------------------------------------------------
/demo/webpack/app.js:
--------------------------------------------------------------------------------
1 | const { CQWebSocket } = require('../..')
2 |
3 | const qs = new URLSearchParams(window.location.search.substr(1))
4 |
5 | const bot = new CQWebSocket({
6 | host: qs.get('host') || undefined,
7 | port: qs.get('port') || undefined,
8 | baseUrl: qs.get('url') || undefined,
9 | qq: qs.get('qq') || undefined
10 | })
11 |
12 | bot.on('message', function (e, { raw_message: rawMessage }) {
13 | document.getElementById('messages').appendChild(document.createElement('div')).innerHTML = `
14 | ${new Date().toLocaleString()}${rawMessage}
15 | `
16 | })
17 |
18 | bot.connect()
19 |
--------------------------------------------------------------------------------
/demo/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | mode: 'production',
5 | entry: path.join(__dirname, 'app.js'),
6 | output: {
7 | path: path.join(__dirname, 'www'),
8 | filename: 'bundle.js'
9 | }
10 | }
--------------------------------------------------------------------------------
/demo/webpack/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CQWebSocket Demo
5 |
6 |
7 |
8 |
9 | Message Box
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/CHANGELOG-v1.md:
--------------------------------------------------------------------------------
1 | # 開發日誌
2 | 列為`棄用`表示**仍然支援**, 但請盡速修正為最新版本的實作。
3 |
4 | ## v1.6.1
5 | - 修正
6 | - `message` 事件監聽器返回值的類型聲明。[#25](https://github.com/momocow/node-cq-websocket/issues/25) [#26](https://github.com/momocow/node-cq-websocket/issues/26) [#27](https://github.com/momocow/node-cq-websocket/issues/27)
7 | - API 響應文本的類型聲明,包含 `api.response` 事件的第一個參數及 callable 的返回值。 [#27](https://github.com/momocow/node-cq-websocket/issues/27)
8 |
9 | ## v1.6.0
10 | - 新增
11 | - 類型聲明, 支持 Typescript。[#18](https://github.com/momocow/node-cq-websocket/issues/18) [#20](https://github.com/momocow/node-cq-websocket/issues/20)
12 | - 默認 API 導出 (default export)。[#21](https://github.com/momocow/node-cq-websocket/issues/21)
13 |
14 | ## v1.5.0
15 | - 新增
16 | - 支持在 browser 環境運行。(須使用 browserify 或 webpack 等工具先行打包, 可見 [/demo/webpack 示例](../demo/webpack)))
17 | - 本倉庫 dist/ 目錄下已經打包了一個 cq-websocket.min.js 可直接在 web 引用, 並透過 `window.CQWebSocket` 變數使用本 SDK。
18 | - [`message` 事件快速響應](../README.md#事件傳播)的新機制: 為了追蹤快速響應的結果(成功或失敗), 監聽器一旦判定該訊息須由它來進行回應, 則須先調用 CQEvent `#stopPropagation()` (原 `#cancel()`) 獲取響應的處理權, 同監聽器內還可透過 CQEvent `#onResponse()` 設置結果監聽器, 並透過 CQEvent `#onError()` 處理響應的錯誤。若沒有 CQEvent `#onError()` 進行錯誤處理, 則會觸發 [`error` 事件](../README.md#基本事件)。
19 | - CQEvent `#appendMessage()`
20 | - [自動獲取機器人QQ號](../README.md#自動獲取機器人qq號): 建立連線時, 若有啟用 API 連線且未配置QQ號, 則自動透過API連線獲取。
21 | - `message.discuss.@`, `message.group.@` 兩個事件。可參考文件在 [message 子事件](../README.md#message-子事件) 及 [CQTag 類別](../README.md#cqtag-類別)的章節
22 | - `CQWebSocket` 建構子新增 [`requestOptions` 選項](../README.md#new-cqwebsocketopt), 該選項下目前只有一個 `timeout` 字段, 調用 API 方法時作為全局默認 timeout 選項。
23 |
24 | - 變更
25 | - [api 子事件](../README.md#api-子事件) 移除監聽器中原第一個參數 WebsocketType。
26 | - 直接對 CQWebSocket 實例進行[方法調用](../README.md#方法調用)之返回值, 由 `this` 變更為 `Promise`, 用以追蹤方法調用的結果。
27 |
28 | - 棄用
29 | - CQEvent `#cancel()` => [`#stopPropagation()`](#cqevent-stoppropagation))
30 | - CQEvent `#isCanceled()` (禁用, 無替代)
31 | - ~~`message.discuss.@me`~~ 和 ~~`message.group.@me`~~ 事件, 將更名為 `message..@.me`事件。請見 [message 子事件](../README.md#message-子事件)文件。
32 |
33 | ## v1.4.2
34 | - 新增
35 | - 默認 `socket.error` 監聽器將會由 stderr 輸出警告訊息。[#4](https://github.com/momocow/node-cq-websocket/issues/4)
36 | - 內部狀態控管, 加強連線管理。[#5](https://github.com/momocow/node-cq-websocket/issues/5)
37 | - `socket.reconnecting`, `socket.reconnect`, `socket.reconnect_failed` 及 `socket.max_reconnect` 事件。(參見 [socket 子事件](../README.md#socket-子事件))
38 | - CQWebSocket 建構時的選項增加 `baseUrl` 一項, 為某些如反向代理之網路環境提供較彈性的設定方式。
39 | - 變更
40 | - `ready` 事件不再針對個別連線(`/api`, `/event`)進行上報, 改為在**所有已啟用**之連線準備就緒後, 一次性發布。若需要掌握個別連線, 請利用 `socket.connect` 事件。
41 | - 修正
42 | - 事件名稱錯誤。(`closing` => `socket.closing`, `connecting` => `socket.connecting`)
43 |
44 | ## v1.4.0
45 | 增強對連線的管理與維護, 斷線後自動嘗試重新連線。
46 | - 新增
47 | - [`off()` 方法](../README.md#cqwebsocket-offevent_type-listener)以移除指定監聽器。
48 | - [reconnect() 方法](../README.md#cqwebsocket-reconnectdelay-wstype)以重新建立連線。
49 | - [isSockConnected() 方法](../README.md#cqwebsocket-issockconnectedwstype)檢測 socket 是否正在連線。
50 | - `socket.connecting`, `socket.failed` 及 `socket.closing` 事件(參見 [socket 子事件](../README.md#socket-子事件))。
51 | - 變更
52 | - [`connect()`](../README.md#cqwebsocket-connectwstype), [`disconnect()`](../README.md#cqwebsocket-disconnectwstype), [`reconnect()`](../README.md#cqwebsocket-reconnectdelay-wstype) 三個方法增加參數 `wsType` 以指定目標連線, 若 `wsType` 為 undefined 指涉全部連線。
53 | - [CQWebSocket 建構子](../README.md#new-cqwebsocketopt)增加額外3個設定, `reconnection`, `reconnectionAttempts` 及 `reconnectionDelay`, 提供連線失敗時自動重連之功能。
54 | - 修正
55 | - [`once()` 方法](../README.md#cqwebsocket-onceevent_type-listener)執行後無法正確移除監聽器之問題。
56 | - 棄用
57 | - `isConnected()` 方法
58 | > 重新命名為 [`isReady()`](../README.md#cqwebsocket-isready)。
59 |
60 | ## v1.3.0
61 | 兼容 CoolQ HTTP API v3.x 及 v4.x 兩個主版本。
62 | - 新增
63 | - 給予 CoolQ HTTP API v4.x 之上報事件 `notice` 實作更多[子事件](../README.md#notice-子事件)。(群文件上傳, 群管變動, 群成員增減, 好友添加)
64 | - 給予上報事件 `request` 實作更多[子事件](../README.md#request-子事件)。(好友請求, 群請求/群邀請)
65 | - 棄用
66 | - 上報事件: `event` -> 請改用 `notice`事件。
67 | ## v1.2.6
68 | - 變更
69 | - 禁用 websocket fragment, 待 CoolQ HTTP API 修正問題時再次啟用。
70 | > 於此帖追蹤進度。[coolq-http-api #85](https://github.com/richardchien/coolq-http-api/issues/85)
--------------------------------------------------------------------------------
/docs/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | CQWebSocket
2 |
3 | ## [2.1.1](https://github.com/momocow/node-cq-websocket/compare/v2.1.0...v2.1.1) (2020-03-23)
4 |
5 |
6 | ### Bug Fixes
7 |
8 | * Fix typing ([#87](https://github.com/momocow/node-cq-websocket/issues/87)) and upgrade dependencies. ([bbb54ad](https://github.com/momocow/node-cq-websocket/commit/bbb54adc15a1e59d963f77e0111a56c0227473a3))
9 |
10 | # [2.1.0](https://github.com/momocow/node-cq-websocket/compare/v2.0.2...v2.1.0) (2020-01-31)
11 |
12 |
13 | ### Features
14 |
15 | * add group_ban event ([928e257](https://github.com/momocow/node-cq-websocket/commit/928e257)), closes [#84](https://github.com/momocow/node-cq-websocket/issues/84)
16 |
17 | ## [2.0.2](https://github.com/momocow/node-cq-websocket/compare/v2.0.1...v2.0.2) (2019-07-23)
18 |
19 |
20 | ### Bug Fixes
21 |
22 | * **types:** Fix definitions of meta events. ([ca1a731](https://github.com/momocow/node-cq-websocket/commit/ca1a731)), closes [#77](https://github.com/momocow/node-cq-websocket/issues/77)
23 |
24 | ## [2.0.1](https://github.com/momocow/node-cq-websocket/compare/v2.0.0...v2.0.1) (2019-04-21)
25 |
26 |
27 | ### Bug Fixes
28 |
29 | * **pack:** Fix missing .d.ts in the NPM package. ([a6bf75b](https://github.com/momocow/node-cq-websocket/commit/a6bf75b))
30 |
31 | # [2.0.0](https://github.com/momocow/node-cq-websocke/compare/v1.8.1...v2.0.0) (2018-11-02)
32 |
33 |
34 | ### Bug Fixes
35 |
36 | * fix CQTag #equals() performs not as expected ([0d1bbbd](https://github.com/momocow/node-cq-websocke/commit/0d1bbbd)), closes [#17](https://github.com/momocow/node-cq-websocke/issues/17) [#34](https://github.com/momocow/node-cq-websocke/issues/34)
37 | * fix error JSON representative of CQText ([732522d](https://github.com/momocow/node-cq-websocke/commit/732522d))
38 | * fix string messages without CQTags are not parsed as a CQText instance. ([0f345cf](https://github.com/momocow/node-cq-websocke/commit/0f345cf)), closes [#17](https://github.com/momocow/node-cq-websocke/issues/17)
39 | * replace CQEvent #cancel() with #stopPropagation() ([1ad3408](https://github.com/momocow/node-cq-websocke/commit/1ad3408)), closes [#29](https://github.com/momocow/node-cq-websocke/issues/29)
40 |
41 |
42 | ### Code Refactoring
43 |
44 | * expose CQWebSocket as default export ([f36e864](https://github.com/momocow/node-cq-websocke/commit/f36e864)), closes [#21](https://github.com/momocow/node-cq-websocke/issues/21) [#23](https://github.com/momocow/node-cq-websocke/issues/23)
45 | * remove "event" event in favour of "notice" event ([405b48c](https://github.com/momocow/node-cq-websocke/commit/405b48c)), closes [#29](https://github.com/momocow/node-cq-websocke/issues/29)
46 | * remove CQEvent instance method "cancel()" ([c8923d8](https://github.com/momocow/node-cq-websocke/commit/c8923d8)), closes [#29](https://github.com/momocow/node-cq-websocke/issues/29)
47 | * remove CQWebSocket instance method "isConnected()" ([c38b1cf](https://github.com/momocow/node-cq-websocke/commit/c38b1cf)), closes [#29](https://github.com/momocow/node-cq-websocke/issues/29)
48 | * rename constructor option "access_token" to "accessToken" ([6caedb6](https://github.com/momocow/node-cq-websocke/commit/6caedb6)), closes [#29](https://github.com/momocow/node-cq-websocke/issues/29)
49 | * use CQWebSocket instead of CQWebsocket for public API ([0b81b53](https://github.com/momocow/node-cq-websocke/commit/0b81b53)), closes [#22](https://github.com/momocow/node-cq-websocke/issues/22)
50 | * **browser:** expose the API under global variable "CQWebSocketSDK". ([db37019](https://github.com/momocow/node-cq-websocke/commit/db37019)), closes [#23](https://github.com/momocow/node-cq-websocke/issues/23)
51 |
52 |
53 | ### Features
54 |
55 | * add CQ tags and add the 3rd parameter of message events to be a list of parsed tags ([06e38a7](https://github.com/momocow/node-cq-websocke/commit/06e38a7)), closes [#17](https://github.com/momocow/node-cq-websocke/issues/17) [#34](https://github.com/momocow/node-cq-websocke/issues/34)
56 | * CQ tags parsing now is based on "message" field instead of "raw_message" field ([e6b4992](https://github.com/momocow/node-cq-websocke/commit/e6b4992))
57 | * support mixing string, CQTag and CQHTTPMessage in array-type messages. ([777281e](https://github.com/momocow/node-cq-websocke/commit/777281e))
58 | * support to append string when the CQEvent message is in array type ([b3091da](https://github.com/momocow/node-cq-websocke/commit/b3091da))
59 |
60 |
61 | ### Tests
62 |
63 | * remove tests for event "message.discuss.[@me](https://github.com/me)" and "message.group.[@me](https://github.com/me)" ([0698300](https://github.com/momocow/node-cq-websocke/commit/0698300)), closes [#29](https://github.com/momocow/node-cq-websocke/issues/29)
64 |
65 |
66 | ### BREAKING CHANGES
67 |
68 | * **browser:** global variable "CQWebSocketSDK" will retrieve the same structure of API as
69 | require('cq-websocket')
70 | * all message events now receive a list of parsed tags as the 3rd parameter
71 | * Option renaming from "access_token" to "accessToken"
72 | * No more CQWebsocket => use CQWebSocket
73 | * CQWebSocket is exposed as default export and a named export, "CQWebSocket".
74 | * Use "message.discuss.@.me" instead of "message.discuss.@me" and
75 | "message.group.@.me" instead of "message.group.@me"
76 | * Use CQEvent #stopPropagation() instead of #cancel().
77 | * Use CQWebSocket #isReady() instead of #isConnected()
78 | * No longer provide support for CQHTTP v3.x
79 |
80 | ## [1.8.1](https://github.com/momocow/node-cq-websocket/compare/v1.8.0...v1.8.1) (2018-10-24)
81 |
82 |
83 | ### Bug Fixes
84 |
85 | * do not include version in filename of browser bundle ([374f378](https://github.com/momocow/node-cq-websocket/commit/374f378)), closes [#36](https://github.com/momocow/node-cq-websocket/issues/36)
86 |
87 | # [1.8.0](https://github.com/momocow/node-cq-websocket/compare/v1.7.0...v1.8.0) (2018-10-22)
88 |
89 |
90 | ### Features
91 |
92 | * add meta events: lifecycle and heartbeat. ([bd8b9f9](https://github.com/momocow/node-cq-websocket/commit/bd8b9f9)), closes [#35](https://github.com/momocow/node-cq-websocket/issues/35)
93 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | cq-websocket.js.org
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | > **本項目即日起停止維護,隨著酷Q、CQHTTP一同走入歷史,畫下完美句點。感謝各方好友的支持與參與。**
2 |
3 | ---
4 |
5 | # CQWebSocket SDK 說明文件
6 |
7 | ## 使用方式
8 | ### CDN
9 |
10 | 如果你在網頁前端上使用,可以通過 CDN 引入。
11 |
12 | - 最新版
13 | ```html
14 |
15 | ```
16 |
17 | - 指定版本 (以 `v2.0.0` 為例, 可依照實際需求版本自行替換版號)
18 | > CDN 引入方式僅提供 v1.8.1 以上的版本使用
19 | ```html
20 |
21 | ```
22 |
23 | 在你的 js 代碼中, 使用全局變數 `CQWebSocketSDK` 獲取 SDK。
24 |
25 | ```js
26 | // 全局變數 CQWebSocketSDK 存在於 window 對象下
27 | const { CQWebSocket } = window.CQWebSocketSDK
28 | const bot = new CQWebSocket()
29 | ```
30 |
31 | ### NPM
32 |
33 | 如果你使用打包工具(如 webpack, browserify...)或 NodeJS,可以通過 NPM 安裝。
34 |
35 | ```
36 | npm install cq-websocket
37 | ```
38 |
39 | 將 SDK 導入代碼
40 | ```js
41 | const { CQWebSocket } = require('cq-websocket')
42 | ```
43 |
44 | 或是使用 ES6 import
45 | ```js
46 | import { CQWebSocket } from 'cq-websocket'
47 | ```
48 |
49 | ## 快速開始
50 | [閱讀更多 ➡️](get-started/README.md)
51 |
52 | ## API 文件
53 | [閱讀更多 ➡️](api/README.md)
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-architect
--------------------------------------------------------------------------------
/docs/api/ArrayMessage.md:
--------------------------------------------------------------------------------
1 | # ArrayMessage
2 | ```ts
3 | type ArrayMessage = (CQTag | CQHTTPMessage | string)[]
4 | ```
5 |
6 | - `CQTag` 見 [CQTag](message/README.md#CQTag)。
7 | - `CQHTTPMessage` 見 [CQHTTPMessage](CQHTTPMessage.md)。
8 |
9 | 此結構可作為**快速響應**或是 **API 調用發送訊息**之消息格式。
10 |
11 | 可見 CQHTTP API 之[消息格式](https://cqhttp.cc/docs/#/Message)說明。
12 |
--------------------------------------------------------------------------------
/docs/api/CQEvent.md:
--------------------------------------------------------------------------------
1 | # CQEvents
2 |
3 | - [CQEvents](#cqevents)
4 | - [stopPropagation](#stoppropagation)
5 | - [messageFormat](#messageformat)
6 | - [getMessage](#getmessage)
7 | - [setMessage](#setmessage)
8 | - [appendMessage](#appendmessage)
9 | - [hasMessage](#hasmessage)
10 | - [onResponse](#onresponse)
11 | - [onError](#onerror)
12 |
13 | 此類別無法自行創建實例。
14 | 此類別的實例於 `message` 事件監聽器,作為第一個參數傳入。
15 |
16 | ## stopPropagation
17 | ```js
18 | e.stopPropagation()
19 | ```
20 | - 返回值: `void`
21 |
22 |
23 | 截獲事件並停止[事件傳播](#事件傳播)。
24 |
25 | ## messageFormat
26 | ```js
27 | e.messageFormat
28 | ```
29 | - `"array"` | `"string"`
30 |
31 | messageFormat 字段下可以知道當前響應訊息的型態為 "string" 或 "array"。
32 |
33 | 可參考[CQHTTP API 消息格式](https://cqhttp.cc/docs/#/Message)。
34 |
35 | ## getMessage
36 | ```js
37 | e.getMessage()
38 | ```
39 | - 返回值: `string` | [`ArrayMessage`](ArrayMessage.md)
40 |
41 | 取得目前的響應訊息。
42 |
43 | ## setMessage
44 | ```js
45 | e.setMessage(msg)
46 | ```
47 | - `msg` string | [`ArrayMessage`](ArrayMessage.md)
48 | - 返回值: `void`
49 |
50 | 設置響應訊息。
51 |
52 | ## appendMessage
53 | ```js
54 | e.appendMessage(msg)
55 | ```
56 | - `msg` string | [CQTag](message/README.md) | [CQHTTPMessage](CQHTTPMessage.md)
57 | - 返回值: `void`
58 |
59 | 串接響應訊息。
60 |
61 | ## hasMessage
62 | ```js
63 | e.hasMessage()
64 | ```
65 |
66 | - 返回值: `boolean`
67 |
68 | 是否有響應訊息。
69 |
70 | ## onResponse
71 | ```js
72 | e.onResponse(handler[, options])
73 | e.onResponse(options)
74 | ```
75 | - `handler` (res: ResObj) => void
76 | - `options` object 同[API 調用](CQWebSocket.md#api-call)之 options
77 |
78 | 設置響應結果的處理器, 用以追蹤訊息是否傳送成功。
79 |
80 | `ResObj` 對象, 此為 CQHttp API 的[回應對象](https://cqhttp.cc/docs/#/WebSocketAPI?id=api-%E6%8E%A5%E5%8F%A3)。
81 |
82 | ## onError
83 | ```js
84 | e.onError(handler)
85 | ```
86 | - `handler` (err: ApiTimeoutError) => void
87 |
88 | 設置錯誤處理器, 可能的錯誤已知有響應超時。
--------------------------------------------------------------------------------
/docs/api/CQHTTPMessage.md:
--------------------------------------------------------------------------------
1 | # CQHTTPMessage
2 | ```ts
3 | interface CQHTTPMessage {
4 | type: string
5 | data: null | {
6 | [key: string]: string
7 | }
8 | }
9 | ```
10 |
11 | 見 CQHTTP API 之[消息段](https://cqhttp.cc/docs/#/Message?id=%E6%B6%88%E6%81%AF%E6%AE%B5%EF%BC%88%E5%B9%BF%E4%B9%89-cq-%E7%A0%81%EF%BC%89)說明。
12 |
--------------------------------------------------------------------------------
/docs/api/CQWebSocket.md:
--------------------------------------------------------------------------------
1 | # CQWebSocket
2 |
3 | - [CQWebSocket](#cqwebsocket)
4 | - [constructor](#constructor)
5 | - [CQWebSocketOption](#cqwebsocketoption)
6 | - [connect()](#connect)
7 | - [disconnect](#disconnect)
8 | - [reconnect](#reconnect)
9 | - [isSockConnected](#issockconnected)
10 | - [isReady](#isready)
11 | - [on](#on)
12 | - [once](#once)
13 | - [off](#off)
14 | - [API call](#api-call)
15 | - [範例](#%E7%AF%84%E4%BE%8B)
16 |
17 | ## constructor
18 | ```js
19 | new CQWebSocket(opt)
20 | ```
21 |
22 | - `opt` [CQWebSocketOption](#cqwebsocketoption)
23 |
24 | ### CQWebSocketOption
25 | | 屬性 | 類型 | 默認值 | 說明
26 | | - | - | - | - |
27 | | `accessToken` | string | `""` | API 訪問 token 。見 CQHTTP API 之[配置文件說明](https://cqhttp.cc/docs/#/Configuration) |
28 | | `enableAPI` | boolean | `true` | 啟用 /api 連線 |
29 | | `enableEvent` | boolean | `true` | 啟用 /event 連線 |
30 | | `protocol` | string | `"ws:"` | 協議名 |
31 | | `host` | string | `"127.0.0.1"` | 酷Q伺服器 IP |
32 | | `port` | number | 6700 | 酷Q伺服器端口 |
33 | | `baseUrl` | string | 6700 | 酷Q伺服器位址 (SDK在建立連線時會依照此設定加上前綴項 `ws://` 及後綴項 `/[?accessToken={token}]`) |
34 | | `qq` | number | string | -1 | 觸發 `@me` 事件用的QQ帳號,通常同登入酷Q之帳號,用在討論組消息及群消息中辨認是否有人at此帳號 |
35 | | `reconnection` | boolean | true | 是否連線錯誤時自動重連 |
36 | | `reconnectionAttempts` | number | Infinity | **連續**連線失敗的次數不超過這個值 |
37 | | `reconnectionDelay` | number | 1000 | 重複連線的延遲時間, 單位: ms |
38 | | `fragmentOutgoingMessages` | boolean | false | 由於 CQHTTP API 插件的 websocket 服務器尚未支持 fragment, 故建議維持 `false` 禁用 fragment。
※詳情請見 [WebSocketClient 選項說明](https://github.com/theturtle32/WebSocket-Node/blob/master/docs/WebSocketClient.md#client-config-options)。 |
39 | | `fragmentationThreshold` | number | 0x4000 | 每個 frame 的最大容量, 默認為 16 KiB, 單位: byte
※詳情請見 [WebSocketClient 選項說明](https://github.com/theturtle32/WebSocket-Node/blob/master/docs/WebSocketClient.md#client-config-options)。 |
40 | | `tlsOptions` | object | {} | 若需調用安全連線 [https.request](https://nodejs.org/api/https.html#https_https_request_options_callback) 時的選項 |
41 | | `requestOptions` | {
`timeout`: number
} | {} | 調用 API 方法時的全局默認選項。 |
42 |
43 | ## connect()
44 | ```js
45 | bot.connect([socketType])
46 | ```
47 |
48 | - `socketType` [WebSocketType](WebSocketType.md) 未提供此項,則默認所有連線。
49 | - 返回值: `this`
50 | - 事件
51 | - `ready` 所有 socket 就緒。
52 | - `socket.connecting` 呼叫後立刻觸發,在任何連線嘗試之前。
53 | - `socket.connect` 連線成功。
54 | - `socket.failed` 連線失敗。
55 | - `socket.error` 連線失敗會一併觸發 error 事件。
56 |
57 | ## disconnect
58 | ```js
59 | bot.disconnect([socketType])
60 | ```
61 |
62 | - `socketType` [WebSocketType](WebSocketType.md) 未提供此項,則默認所有連線。
63 | - 返回值: `this`
64 | - 事件
65 | - `socket.closing` 正在關閉連線。
66 | - `socket.close` 連線斷開後。
67 |
68 | ## reconnect
69 | ```js
70 | bot.reconnect([delay[, socketType]])
71 | ```
72 |
73 | - `delay` number 單位為 ms,表示`socket.close`**事件觸發後的延遲時間**, 延遲時間過後才會呼叫 connect()。
74 | - `socketType` [WebSocketType](WebSocketType.md) 未提供此項,則默認所有連線。
75 | - 返回值: `this`
76 | - 事件
77 | > 此方法會先呼叫 disconnect() 等待 `socket.close` 事件觸發後再呼叫 connect(), 可以參考以上兩個方法的事件。
78 |
79 | ## isSockConnected
80 | ```js
81 | bot.isSockConnected(socketType)
82 | ```
83 |
84 | - `socketType` [WebSocketType](WebSocketType.md)
85 | - 返回值: `boolean`
86 |
87 | > ※若未給定 `socketType`,使用此方法會**拋出錯誤**。
88 |
89 | ## isReady
90 | ```js
91 | bot.isReady()
92 | ```
93 |
94 | - 返回值: `boolean`
95 |
96 | 檢查連線狀態是否就緒。
97 |
98 | > 僅檢查已透過 `enableAPI` 及 `enableEvent` 啟用之連線。
99 |
100 | ## on
101 | ```js
102 | bot.on(event, listener)
103 | ```
104 |
105 | - `event` string
106 | - `listener` [EventListener](EventListener.md)
107 | - 返回值: `this`
108 |
109 | 註冊常駐監聽器。
110 |
111 | ## once
112 | ```js
113 | bot.once(event, listener)
114 | ```
115 |
116 | - `event` string
117 | - `listener` [EventListener](EventListener.md#OnceListener)
118 | - 返回值: `this`
119 |
120 | 註冊一次性監聽器。
121 |
122 | ## off
123 | ```js
124 | bot.off([event[, listener]])
125 | ```
126 |
127 | - `event` string
128 | - `listener` [EventListener](EventListener.md)
129 | - 返回值: `this`
130 |
131 | 移除 `event` 事件中的 `listener` 監聽器。
132 | 若 `event` 不為字串,則移除所有監聽器。
133 | 若 `listener` 不為方法,則移除所有該事件的監聽器。
134 |
135 | ## API call
136 | ```js
137 | bot(method[, params[, options]])
138 | ```
139 | - `method` string 見 [API 列表](https://cqhttp.cc/docs/#/API?id=api-%E5%88%97%E8%A1%A8)
140 | - `params` object 見 [API 列表](https://cqhttp.cc/docs/#/API?id=api-%E5%88%97%E8%A1%A8)
141 | - `options` object | number
142 | - `timeout` number (默認: `Infinity`)
143 | - 返回值: `Promise`
144 |
145 | 返回值為一個 Promise 對象, 用作追蹤該次 API 調用的結果。
146 |
147 | Promise 對象實現後第一個參數會拿到 `ResObj` 對象, 此為 CQHttp API 的[回應對象](https://cqhttp.cc/docs/#/WebSocketAPI?id=api-%E6%8E%A5%E5%8F%A3)。
148 |
149 | 若有配置 `timeout` 選項(原先默認為 `Infinity`, 不會對請求計時), 則發生超時之後, 將放棄收取本次調用的結果, 並拋出一個 `ApiTimeoutError`。
150 |
151 | `options` 除了是一個對象外, 也可以直接給一個數值, 該數值會被直接當作 `timeout` 使用。
152 |
153 | ### 範例
154 | ```js
155 | bot('send_private_msg', {
156 | user_id: 123456789,
157 | message: 'Hello world!'
158 | }, {
159 | timeout: 10000 // 10 sec
160 | })
161 | .then((res) => {
162 | console.log(res)
163 | // {
164 | // status: 'ok',
165 | // retcode: 0,
166 | // data: null
167 | // }
168 | })
169 | .catch((err) => {
170 | console.error('請求超時!')
171 | })
172 | ```
--------------------------------------------------------------------------------
/docs/api/EventListener.md:
--------------------------------------------------------------------------------
1 | # 事件監聽器
2 |
3 | - [事件監聽器](#%E4%BA%8B%E4%BB%B6%E7%9B%A3%E8%81%BD%E5%99%A8)
4 | - [EventListener](#eventlistener)
5 | - [OnceListener](#oncelistener)
6 | - [MessageEventListener](#messageeventlistener)
7 | - [OnceMessageEventListener](#oncemessageeventlistener)
8 |
9 | ## EventListener
10 | ```ts
11 | listener: (context: object) => void | Promise
12 | ```
13 |
14 | - `context` 為上報的文本,可見 CQHTTP API 之[事件列表](https://cqhttp.cc/docs/#/Post?id=%E4%BA%8B%E4%BB%B6%E5%88%97%E8%A1%A8)。
15 |
16 |
17 | ## OnceListener
18 | ```ts
19 | listener: (context: object) => void | Promise | false
20 | ```
21 | 用於 [`bot.once(event, listener)`](CQWebSocket.md#once)。
22 |
23 | 當返回值為 `false` ,指涉該監聽器並未完成任務,則保留該監聽器繼續聽取事件,不做移除。下一次事件發生時,該監聽器在調用後會再次以返回值判定去留。若返回值非 `false` ,指涉該監聽器處理完畢,立即移除。
24 |
25 | ## MessageEventListener
26 | ```ts
27 | listener: (e: CQEvent, context: object, tags: CQTag[]) => void | Promise | string | Promise | ArrayMessage | Promise
28 | ```
29 |
30 | - `CQEvent` 見 [CQEvent](CQEvent.md)。
31 | - `CQTag` 見 [CQTag](message/README.md#CQTag)。
32 | - `ArrayMessage` 見 [ArrayMessage](ArrayMessage.md)。
33 |
34 | 用於監聽 [`message` 及其子事件](events.md#message)。
35 |
36 | 返回值為 `string | Promise | ArrayMessage | Promise` 時,會以該返回值作為響應訊息。
37 |
38 | ## OnceMessageEventListener
39 | ```ts
40 | listener: (e: CQEvent, context: object, tags: CQTag[]) => void | Promise | string | Promise | ArrayMessage | Promise | false
41 | ```
42 | 用於一次性監聽 [`message` 及其子事件](events.md#message)。
43 |
44 | 返回值為 `false` 時,行為同 [OnceListener](#oncelistener);返回值非 `false` 時,行為同 [MessageEventListener](#messageeventlistener)。
--------------------------------------------------------------------------------
/docs/api/README.md:
--------------------------------------------------------------------------------
1 | # API 文件
2 |
3 | - [CQWebSocket SDK](CQWebSocket.md)
4 | - [CQEvent](CQEvent.md)
5 | - [CQ 碼 🐴](messages.md)
6 | - [響應/發送消息結構](ArrayMessage.md)
7 | - [消息段](CQHTTPMessage.md)
8 | - [事件監聽器](EventListener.md)
9 | - [事件列表](events.md)
10 | - [WebSocketType](WebSocketType.md)
11 | - [WebSocketState](WebSocketState.md)
12 |
--------------------------------------------------------------------------------
/docs/api/WebSocketState.md:
--------------------------------------------------------------------------------
1 | # WebSocketState
2 |
3 | ```ts
4 | enum WebSocketState {
5 | DISABLED = -1,
6 | INIT = 0,
7 | CONNECTING = 1,
8 | CONNECTED = 2,
9 | CLOSING = 3,
10 | CLOSED = 4
11 | }
12 | ```
--------------------------------------------------------------------------------
/docs/api/WebSocketType.md:
--------------------------------------------------------------------------------
1 | # WebSocketType
2 |
3 | ```ts
4 | enum WebSocketType {
5 | API = '/api',
6 | EVENT = '/event'
7 | }
8 | ```
9 |
--------------------------------------------------------------------------------
/docs/api/errors.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/momocow/node-cq-websocket/fafce7389578b559a114700ed5d8693eff9066ed/docs/api/errors.md
--------------------------------------------------------------------------------
/docs/api/events.md:
--------------------------------------------------------------------------------
1 | # 事件列表
2 |
3 | - [事件列表](#%E4%BA%8B%E4%BB%B6%E5%88%97%E8%A1%A8)
4 | - [事件樹](#%E4%BA%8B%E4%BB%B6%E6%A8%B9)
5 | - [基本事件](#%E5%9F%BA%E6%9C%AC%E4%BA%8B%E4%BB%B6)
6 | - [message](#message)
7 | - [notice](#notice)
8 | - [request](#request)
9 | - [meta_event](#metaevent)
10 | - [socket](#socket)
11 | - [api](#api)
12 |
13 | ## 事件樹
14 | ```
15 | ├─ message
16 | │ ├─ private
17 | │ ├─ discuss
18 | │ │ └─ @
19 | │ │ └─ me
20 | │ └─ group
21 | │ └─ @
22 | │ └─ me
23 | ├─ notice
24 | │ ├─ group_upload
25 | │ ├─ group_admin
26 | │ │ ├─ set
27 | │ │ └─ unset
28 | │ ├─ group_decrease
29 | │ │ ├─ leave
30 | │ │ ├─ kick
31 | │ │ └─ kick_me
32 | │ ├─ group_increase
33 | │ │ ├─ approve
34 | │ │ └─ invite
35 | │ └─ friend_add
36 | ├─ request
37 | │ ├─ friend
38 | │ └─ group
39 | | ├─ add
40 | | └─ invite
41 | ├─ meta_event
42 | | ├─ lifecycle
43 | | └─ heartbeat
44 | ├─ error
45 | ├─ ready
46 | ├─ socket ※
47 | │ ├─ connecting
48 | │ ├─ connect
49 | │ ├─ failed
50 | │ ├─ reconnecting
51 | │ ├─ reconnect
52 | │ ├─ reconnect_failed
53 | │ ├─ max_reconnect
54 | │ ├─ closing
55 | │ ├─ close
56 | │ └─ error
57 | └─ api ※
58 | ├─ response
59 | └─ send ※
60 | ├─ pre
61 | └─ post
62 |
63 | ※: 表示無法在該節點進行監聽
64 | ```
65 |
66 | ## 基本事件
67 | 前三個基本事件之說明,可以另外參考 CQHTTP API 的[數據上報格式](https://cqhttp.cc/docs/4.2/#/Post?id=%E4%B8%8A%E6%8A%A5%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F)。
68 |
69 | 參數 `context` 可見[事件列表](https://cqhttp.cc/docs/4.2/#/Post?id=%E4%BA%8B%E4%BB%B6%E5%88%97%E8%A1%A8)。
70 |
71 | | 事件類型 | 監聽器參數 `...args` | 說明 |
72 | | - | - | - |
73 | | message | `event` [CQEvent](#cqevent-類別)
`context` object
`tags` CQTag[]| 所有流入的訊息。 |
74 | | notice | `context` object | 群文件上傳, 群管變動, 群成員增減, 好友添加...等QQ事件。 |
75 | | request | `context` object | 好友請求, 群請求/群邀請...等QQ事件。 |
76 | | meta_event | `context` object | 來自 CQHTTP API 的元事件。 |
77 | | error | `err` Error | 應用層面的錯誤, 如 CQHttp API 消息格式錯誤, 響應超時... 等 |
78 | | ready | `this` | 設定中啟用之連線均成功並初始化完成,可以開始調用API (送消息...等操作)。 |
79 |
80 | ### message
81 | | 事件類型 | 監聽器參數 | 說明 |
82 | | - | - | - |
83 | | message.private | `event` CQEvent
`context` object
`tags` CQTag[] | 私聊消息。 |
84 | | message.discuss | `event` CQEvent
`context` object
`tags` CQTag[] | 討論組消息。 |
85 | | message.discuss.@ | `event` CQEvent
`context` object
`tags` CQTag[] | 有人於討論組消息中被at。 |
86 | | message.discuss.@.me | `event` CQEvent
`context` object
`tags` CQTag[] | 有人於討論組消息at機器人。 |
87 | | message.group | `event` CQEvent
`context` object
`tags` CQTag[] | 群消息。 |
88 | | message.group.@ | `event` CQEvent
`context` object
`tags` CQTag[] | 有人於群消息中被at。 |
89 | | message.group.@.me | `event` CQEvent
`context` object
`tags` CQTag[] | 有人於群消息at機器人。 |
90 |
91 | ### notice
92 | | 事件類型 | 監聽器參數 | 說明 |
93 | | - | - | - |
94 | | notice.group_upload | `context` object | 群文件上傳。 |
95 | | notice.group_admin.set | `context` object | 設置管理員。 |
96 | | notice.group_admin.unset | `context` object | 取消管理員。 |
97 | | notice.group_decrease.leave | `context` object | 自主退群。 |
98 | | notice.group_decrease.kick | `context` object | 被動踢出群。 |
99 | | notice.group_decrease.kick_me | `context` object | 機器人被踢出群。 |
100 | | notice.group_increase.approve | `context` object | 管理員同意入群。 |
101 | | notice.group_increase.invite | `context` object | 管理員邀請入群。 |
102 | | notice.friend_add | `context` object | 新添加好友。 |
103 |
104 | ### request
105 | | 事件類型 | 監聽器參數 | 說明 |
106 | | - | - | - |
107 | | request.friend | `context` object | 私聊消息。 |
108 | | request.group.add | `context` object | 加群請求。 |
109 | | request.group.invite | `context` object | 邀請入群。 |
110 |
111 | ### meta_event
112 | | 事件類型 | 監聽器參數 | 說明 |
113 | | - | - | - |
114 | | meta_event.lifecycle | `context` object | 生命周期。 |
115 | | meta_event.heartbeat | `context` object | 心跳。 |
116 |
117 | ### socket
118 | 底層 socket 連線的事件, 可用於掌握連線狀況。
119 |
120 | | 事件類型 | 監聽器參數 | 說明 |
121 | | - | - | - |
122 | | socket.connecting | `type` WebsocketType
`attempts` number | 開始嘗試連線, 連線成功/失敗之前。 |
123 | | socket.connect | `type` WebsocketType
`socket` [WebSocketConnection](https://github.com/theturtle32/WebSocket-Node/blob/d941f975e8ef6b55eafc0ef45996f4198013832c/docs/WebSocketConnection.md#websocketconnection)
`attempts` number | 連線成功後,尚未初始化之前。 |
124 | | socket.failed | `type` WebsocketType
`attempts` number | 連線失敗。 |
125 | | socket.reconnecting | `type` WebsocketType
`attempts` number | 開始嘗試重新連線, 若存在持續中的連線, 則先斷線。 |
126 | | socket.reconnect | `type` WebsocketType
`attempts` number | 重連成功。 |
127 | | socket.reconnect_failed | `type` WebsocketType
`attempts` number | 重連失敗。 |
128 | | socket.max_reconnect | `type` WebsocketType
`attempts` number | 已抵達重連次數上限。 |
129 | | socket.closing | `type` WebsocketType | 連線關閉之前。 |
130 | | socket.close | `type` WebsocketType
`code` number
`desc` string | 連線關閉。(連線關閉代碼 `code` 可參照 [RFC 文件](https://tools.ietf.org/html/rfc6455#section-7.4))) |
131 | | socket.error | `type` WebsocketType
`err` Error | 連線錯誤。若該事件無監聽器,則會安裝默認監聽器,固定拋出例外。 |
132 |
133 | ### api
134 | | 事件類型 | 監聽器參數 | 說明 |
135 | | - | - | - |
136 | | api.send.pre | `apiRequest` object | 傳送 API 請求之前。關於 `apiRequest` 可見 [/api/接口說明](https://cqhttp.cc/docs/4.2/#/WebSocketAPI?id=api-%E6%8E%A5%E5%8F%A3)。 |
137 | | api.send.post | | 傳送 API 請求之後。 |
138 | | api.response | `result` object | 對於 API 請求的響應。詳細格式見 [/api/接口說明](https://cqhttp.cc/docs/4.2/#/WebSocketAPI?id=api-%E6%8E%A5%E5%8F%A3)。
此為集中處理所有 API 請求的響應, 若需對個別請求追蹤結果, 請參考[方法調用](#方法調用)中返回的 Promise 對象。
若需追蹤消息快速響應的結果, 請參考 [響應結果追蹤](#響應結果追蹤)。 |
139 |
--------------------------------------------------------------------------------
/docs/api/messages.md:
--------------------------------------------------------------------------------
1 | # CQ 碼 🐴
2 |
3 | - [CQ 碼 🐴](#cq-%E7%A2%BC-%F0%9F%90%B4)
4 | - [CQTag](#cqtag)
5 | - [CQTag tagName](#cqtag-tagname)
6 | - [CQTag data](#cqtag-data)
7 | - [CQTag modifier](#cqtag-modifier)
8 | - [CQTag equals](#cqtag-equals)
9 | - [CQTag coerce](#cqtag-coerce)
10 | - [CQTag toString](#cqtag-tostring)
11 | - [CQTag valueOf](#cqtag-valueof)
12 | - [範例](#%E7%AF%84%E4%BE%8B)
13 | - [CQTag toJSON](#cqtag-tojson)
14 | - [CQAnonymous](#cqanonymous)
15 | - [CQAnonymous constructor](#cqanonymous-constructor)
16 | - [CQAnonymous ignore](#cqanonymous-ignore)
17 | - [CQAt](#cqat)
18 | - [CQAt constructor](#cqat-constructor)
19 | - [CQAt qq](#cqat-qq)
20 | - [CQBFace](#cqbface)
21 | - [CQBFace constructor](#cqbface-constructor)
22 | - [CQBFace id](#cqbface-id)
23 | - [CQCustomMusic](#cqcustommusic)
24 | - [CQCustomMusic constructor](#cqcustommusic-constructor)
25 | - [CQCustomMusic type](#cqcustommusic-type)
26 | - [CQCustomMusic url](#cqcustommusic-url)
27 | - [CQCustomMusic audio](#cqcustommusic-audio)
28 | - [CQCustomMusic title](#cqcustommusic-title)
29 | - [CQCustomMusic content](#cqcustommusic-content)
30 | - [CQCustomMusic image](#cqcustommusic-image)
31 | - [CQDice](#cqdice)
32 | - [CQDice constructor](#cqdice-constructor)
33 | - [CQDice type](#cqdice-type)
34 | - [CQEmoji](#cqemoji)
35 | - [CQEmoji constructor](#cqemoji-constructor)
36 | - [CQEmoji id](#cqemoji-id)
37 | - [CQFace](#cqface)
38 | - [CQFace constructor](#cqface-constructor)
39 | - [CQFace id](#cqface-id)
40 | - [CQImage](#cqimage)
41 | - [CQImage constructor](#cqimage-constructor)
42 | - [CQImage file](#cqimage-file)
43 | - [CQImage url](#cqimage-url)
44 | - [CQImage cache](#cqimage-cache)
45 | - [CQMusic](#cqmusic)
46 | - [CQMusic constructor](#cqmusic-constructor)
47 | - [CQMusic type](#cqmusic-type)
48 | - [CQMusic id](#cqmusic-id)
49 | - [CQRecord](#cqrecord)
50 | - [CQRecord constructor](#cqrecord-constructor)
51 | - [CQRecord file](#cqrecord-file)
52 | - [CQRecord magic](#cqrecord-magic)
53 | - [CQRecord hasMagic](#cqrecord-hasmagic)
54 | - [CQRPS](#cqrps)
55 | - [CQRPS constructor](#cqrps-constructor)
56 | - [CQRPS type](#cqrps-type)
57 | - [CQSFace](#cqsface)
58 | - [CQSFace constructor](#cqsface-constructor)
59 | - [CQSFace id](#cqsface-id)
60 | - [CQShake](#cqshake)
61 | - [CQShake constructor](#cqshake-constructor)
62 | - [CQShare](#cqshare)
63 | - [CQShare constructor](#cqshare-constructor)
64 | - [CQShare url](#cqshare-url)
65 | - [CQShare title](#cqshare-title)
66 | - [CQShare content](#cqshare-content)
67 | - [CQShare image](#cqshare-image)
68 | - [CQText](#cqtext)
69 | - [CQText constructor](#cqtext-constructor)
70 | - [CQText text](#cqtext-text)
71 |
72 | ## CQTag
73 | CQTag 為一個抽象類別,*正常情況下並**不會**直接建立一個 CQTag 的實例*,而是使用其子類別,如 CQAt、CQImage... 等。
74 |
75 | CQTag 作為所有 CQ 碼的親類別。
76 |
77 | ### CQTag tagName
78 | ```js
79 | tag.tagName
80 | ```
81 | - `string`
82 |
83 | CQ碼功能名,如 `"at"`、`"image"`... 等。
84 |
85 | ### CQTag data
86 | ```js
87 | tag.data
88 | ```
89 | - `ReadOnly