From dc59c88b0a7c431df167e91a5dac11096d3bf3b9 Mon Sep 17 00:00:00 2001
From: AkiraFukushima
Date: Fri, 24 May 2019 01:37:02 +0900
Subject: [PATCH] refs #41 Handle delete message from streaming
---
.prettierrc | 6 ++++
example/javascript/streaming.js | 24 ++++++--------
example/javascript/web_socket.js | 30 ++++++-----------
src/entities/status.ts | 50 ++++++++++++++--------------
src/parser.ts | 47 ++++++++++++++------------
src/stream_listener.ts | 12 +++----
src/web_socket.ts | 57 ++++++++++++++++++--------------
7 files changed, 114 insertions(+), 112 deletions(-)
create mode 100644 .prettierrc
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..6692425
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "tabWidth": 2,
+ "semi": false,
+ "singleQuote": true,
+ "printWidth": 140
+}
\ No newline at end of file
diff --git a/example/javascript/streaming.js b/example/javascript/streaming.js
index 1e23d7a..2715025 100644
--- a/example/javascript/streaming.js
+++ b/example/javascript/streaming.js
@@ -1,13 +1,10 @@
-const Mastodon = require( '../../lib/mastodon')
+const Mastodon = require('../../lib/mastodon')
-const BASE_URL = 'https://mastodon.social'
+const BASE_URL = 'https://mstdn.jp'
-const access_token = '...'
+const access_token = process.env.MASTODON_ACCESS_TOKEN
-const client = new Mastodon(
- access_token,
- BASE_URL + '/api/v1'
-)
+const client = new Mastodon(access_token, BASE_URL + '/api/v1')
const stream = client.stream('/streaming/public')
stream.on('connect', event => {
@@ -18,27 +15,26 @@ stream.on('not-event-stream', mes => {
console.log(mes)
})
-stream.on('update', (status) => {
+stream.on('update', status => {
console.log(status)
})
-stream.on('notification', (notification) => {
+stream.on('notification', notification => {
console.log(notification)
})
-stream.on('delete', (id) => {
- console.log(id)
+stream.on('delete', id => {
+ console.log(`delete: ${id}`)
})
-stream.on('error', (err) => {
+stream.on('error', err => {
console.error(err)
})
-stream.on('heartbeat', (msg) => {
+stream.on('heartbeat', msg => {
console.log('thump.')
})
stream.on('connection-limit-exceeded', err => {
console.error(err)
})
-
diff --git a/example/javascript/web_socket.js b/example/javascript/web_socket.js
index bc8840d..4b74f10 100644
--- a/example/javascript/web_socket.js
+++ b/example/javascript/web_socket.js
@@ -2,38 +2,32 @@ const Mastodon = require('../../lib/mastodon')
const BASE_URL = 'wss://pleroma.io'
-const access_token = '...'
+const access_token = process.env.PLEROMA_ACCESS_TOKEN
-const client = new Mastodon(
- access_token,
- BASE_URL + '/api/v1'
-)
+const client = new Mastodon(access_token, BASE_URL + '/api/v1')
-const stream = client.socket(
- '/streaming',
- 'user'
-)
+const stream = client.socket('/streaming', 'user')
stream.on('connect', event => {
console.log('connect')
})
-stream.on('update', (status) => {
+stream.on('update', status => {
console.log(status)
})
-stream.on('notification', (notification) => {
+stream.on('notification', notification => {
console.log(notification)
})
-stream.on('delete', (id) => {
- console.log(id)
+stream.on('delete', id => {
+ console.log(`delete: ${id}`)
})
-stream.on('error', (err) => {
+stream.on('error', err => {
console.error(err)
})
-stream.on('heartbeat', (msg) => {
+stream.on('heartbeat', msg => {
console.log('thump.')
})
@@ -41,10 +35,6 @@ stream.on('close', () => {
console.log('close')
})
-stream.on('parser-error', (err) => {
+stream.on('parser-error', err => {
console.error(err)
})
-
-setTimeout(() => {
- stream.stop()
-}, 10000)
diff --git a/src/entities/status.ts b/src/entities/status.ts
index d853a30..2cbee1e 100644
--- a/src/entities/status.ts
+++ b/src/entities/status.ts
@@ -7,30 +7,30 @@ import Emoji from './emoji'
import Card from './card'
export default interface Status {
- id: number,
- uri: string,
- url: string,
- account: Account,
- in_reply_to_id: number | null,
- in_reply_to_account_id: number | null,
- reblog: Status | null,
- content: string,
- created_at: string,
- emojis: Emoji[],
- replies_count: number,
- reblogs_count: number,
- favourites_count: number,
- reblogged: boolean | null,
- favourited: boolean | null,
- muted: boolean | null,
- sensitive: boolean,
- spoiler_text: string,
- visibility: 'public' | 'unlisted' | 'private' | 'direct',
- media_attachments: Attachment[],
- mentions: Mention[],
- tags: Tag[],
- card: Card | null,
- application: Application,
- language: string | null,
+ id: string
+ uri: string
+ url: string
+ account: Account
+ in_reply_to_id: number | null
+ in_reply_to_account_id: number | null
+ reblog: Status | null
+ content: string
+ created_at: string
+ emojis: Emoji[]
+ replies_count: number
+ reblogs_count: number
+ favourites_count: number
+ reblogged: boolean | null
+ favourited: boolean | null
+ muted: boolean | null
+ sensitive: boolean
+ spoiler_text: string
+ visibility: 'public' | 'unlisted' | 'private' | 'direct'
+ media_attachments: Attachment[]
+ mentions: Mention[]
+ tags: Tag[]
+ card: Card | null
+ application: Application
+ language: string | null
pinned: boolean | null
}
diff --git a/src/parser.ts b/src/parser.ts
index a8fe490..2cbd0af 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -52,30 +52,33 @@ class Parser extends EventEmitter {
const event: string = root[0].substr(7)
const data: string = root[1].substr(6)
+ let jsonObj = {}
try {
- const obj = JSON.parse(data)
- switch (event) {
- case 'update':
- this.emit('update', obj as Status)
- break
- case 'notification':
- this.emit('notification', obj as Notification)
- break
- case 'conversation':
- this.emit('conversation', obj as Conversation)
- break
- case 'delete':
- // When delete, data is an ID of the deleted status
- this.emit('delete', obj as number)
- break
- default:
- this.emit('error', new Error(`Unknown event has received: ${event}`))
- break
- }
+ jsonObj = JSON.parse(data)
} catch (err) {
- this.emit('error', new Error(`Error parsing API reply: '${piece}', error message: '${err}'`))
- } finally {
- continue
+ // delete event does not have json object
+ if (event !== 'delete') {
+ this.emit('error', new Error(`Error parsing API reply: '${piece}', error message: '${err}'`))
+ continue
+ }
+ }
+ switch (event) {
+ case 'update':
+ this.emit('update', jsonObj as Status)
+ break
+ case 'notification':
+ this.emit('notification', jsonObj as Notification)
+ break
+ case 'conversation':
+ this.emit('conversation', jsonObj as Conversation)
+ break
+ case 'delete':
+ // When delete, data is an ID of the deleted status
+ this.emit('delete', data as string)
+ break
+ default:
+ this.emit('error', new Error(`Unknown event has received: ${event}`))
+ continue
}
}
offset++
diff --git a/src/stream_listener.ts b/src/stream_listener.ts
index de9b2c6..9d82092 100644
--- a/src/stream_listener.ts
+++ b/src/stream_listener.ts
@@ -18,7 +18,6 @@ class StreamingError extends Error {
}
}
-
/**
* StreamListener
* Listener of streaming. It receives data, and parse when streaming.
@@ -35,7 +34,6 @@ class StreamListener extends EventEmitter {
private _usedFirstReconnect: boolean
private _stallAbortTimeout: NodeJS.Timer | undefined
-
/**
* @param url full url of streaming: e.g. https://mastodon.social/api/v1/streaming/user
* @param headers headers of streaming request
@@ -113,7 +111,7 @@ class StreamListener extends EventEmitter {
this.request = Request.get(this._buildRequestOption())
this.emit('connect', this.request)
- this.request.on('response', (response) => {
+ this.request.on('response', response => {
// reset our reconnection attempt flag so next attempt goes through with 0 delay
// if we get a transport-level error
this._usedFirstReconnect = false
@@ -125,7 +123,7 @@ class StreamListener extends EventEmitter {
}
if (STATUS_CODES_TO_ABORT_ON.indexOf(response.statusCode) > -1) {
let body: string = ''
- this.response.on('data', (chunk) => {
+ this.response.on('data', chunk => {
body += chunk.toString()
try {
@@ -141,14 +139,14 @@ class StreamListener extends EventEmitter {
body = ''
})
} else {
- this.response.on('data', (chunk) => {
+ this.response.on('data', chunk => {
this._connectInterval = 0
this._resetStallAbortTimeout()
this.parser.parse(chunk.toString())
})
- this.response.on('error', (err) => {
+ this.response.on('error', err => {
// expose response errors on twit instance
this.emit('error', err)
})
@@ -286,7 +284,7 @@ class StreamListener extends EventEmitter {
this.parser.on('conversation', (conversation: Conversation) => {
this.emit('conversation', conversation)
})
- this.parser.on('delete', (id: number) => {
+ this.parser.on('delete', (id: string) => {
this.emit('delete', id)
})
this.parser.on('error', (err: Error) => {
diff --git a/src/web_socket.ts b/src/web_socket.ts
index 2f0ba53..10c8b1c 100644
--- a/src/web_socket.ts
+++ b/src/web_socket.ts
@@ -122,17 +122,17 @@ export default class WebSocket extends EventEmitter {
*/
private _getClient(): client {
const cli = new client()
- cli.on('connectFailed', (err) => {
+ cli.on('connectFailed', err => {
console.error(err)
this._reconnect(cli)
})
- cli.on('connect', (conn) => {
+ cli.on('connect', conn => {
this._socketConnection = conn
this.emit('connect', {})
- conn.on('error', (err) => {
+ conn.on('error', err => {
this.emit('error', err)
})
- conn.on('close', (code) => {
+ conn.on('close', code => {
// Refer the code: https://tools.ietf.org/html/rfc6455#section-7.4
if (code === 1000) {
this.emit('close', {})
@@ -162,7 +162,7 @@ export default class WebSocket extends EventEmitter {
this.parser.on('notification', (notification: Notification) => {
this.emit('notification', notification)
})
- this.parser.on('delete', (id: number) => {
+ this.parser.on('delete', (id: string) => {
this.emit('delete', id)
})
this.parser.on('conversation', (conversation: Conversation) => {
@@ -200,28 +200,37 @@ class Parser extends EventEmitter {
return
}
+ let event = ''
+ let payload = ''
+ let mes = {}
try {
const obj = JSON.parse(data)
- const payload: string = obj.payload
- const mes = JSON.parse(payload)
- switch (obj.event) {
- case 'update':
- this.emit('update', mes as Status)
- break
- case 'notification':
- this.emit('notification', mes as Notification)
- break
- case 'delete':
- this.emit('delete', mes as number)
- break
- case 'conversation':
- this.emit('conversation', mes as Conversation)
- break
- default:
- this.emit('error', new Error(`Unknown event has received: ${obj}`))
- }
+ event = obj.event
+ payload = obj.payload
+ mes = JSON.parse(payload)
} catch (err) {
- this.emit('error', new Error(`Error parsing websocket reply: ${data}, error message: ${err}`))
+ // delete event does not have json object
+ if (event !== 'delete') {
+ this.emit('error', new Error(`Error parsing websocket reply: ${data}, error message: ${err}`))
+ return
+ }
+ }
+
+ switch (event) {
+ case 'update':
+ this.emit('update', mes as Status)
+ break
+ case 'notification':
+ this.emit('notification', mes as Notification)
+ break
+ case 'conversation':
+ this.emit('conversation', mes as Conversation)
+ break
+ case 'delete':
+ this.emit('delete', payload as string)
+ break
+ default:
+ this.emit('error', new Error(`Unknown event has received: ${data}`))
}
return
}