refs #41 Handle delete message from streaming
This commit is contained in:
parent
8db1d4940b
commit
dc59c88b0a
6
.prettierrc
Normal file
6
.prettierrc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"tabWidth": 2,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 140
|
||||||
|
}
|
|
@ -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(
|
const client = new Mastodon(access_token, BASE_URL + '/api/v1')
|
||||||
access_token,
|
|
||||||
BASE_URL + '/api/v1'
|
|
||||||
)
|
|
||||||
|
|
||||||
const stream = client.stream('/streaming/public')
|
const stream = client.stream('/streaming/public')
|
||||||
stream.on('connect', event => {
|
stream.on('connect', event => {
|
||||||
|
@ -18,27 +15,26 @@ stream.on('not-event-stream', mes => {
|
||||||
console.log(mes)
|
console.log(mes)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('update', (status) => {
|
stream.on('update', status => {
|
||||||
console.log(status)
|
console.log(status)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('notification', (notification) => {
|
stream.on('notification', notification => {
|
||||||
console.log(notification)
|
console.log(notification)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('delete', (id) => {
|
stream.on('delete', id => {
|
||||||
console.log(id)
|
console.log(`delete: ${id}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('error', (err) => {
|
stream.on('error', err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('heartbeat', (msg) => {
|
stream.on('heartbeat', msg => {
|
||||||
console.log('thump.')
|
console.log('thump.')
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('connection-limit-exceeded', err => {
|
stream.on('connection-limit-exceeded', err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,38 +2,32 @@ const Mastodon = require('../../lib/mastodon')
|
||||||
|
|
||||||
const BASE_URL = 'wss://pleroma.io'
|
const BASE_URL = 'wss://pleroma.io'
|
||||||
|
|
||||||
const access_token = '...'
|
const access_token = process.env.PLEROMA_ACCESS_TOKEN
|
||||||
|
|
||||||
const client = new Mastodon(
|
const client = new Mastodon(access_token, BASE_URL + '/api/v1')
|
||||||
access_token,
|
|
||||||
BASE_URL + '/api/v1'
|
|
||||||
)
|
|
||||||
|
|
||||||
const stream = client.socket(
|
const stream = client.socket('/streaming', 'user')
|
||||||
'/streaming',
|
|
||||||
'user'
|
|
||||||
)
|
|
||||||
stream.on('connect', event => {
|
stream.on('connect', event => {
|
||||||
console.log('connect')
|
console.log('connect')
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('update', (status) => {
|
stream.on('update', status => {
|
||||||
console.log(status)
|
console.log(status)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('notification', (notification) => {
|
stream.on('notification', notification => {
|
||||||
console.log(notification)
|
console.log(notification)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('delete', (id) => {
|
stream.on('delete', id => {
|
||||||
console.log(id)
|
console.log(`delete: ${id}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('error', (err) => {
|
stream.on('error', err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('heartbeat', (msg) => {
|
stream.on('heartbeat', msg => {
|
||||||
console.log('thump.')
|
console.log('thump.')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -41,10 +35,6 @@ stream.on('close', () => {
|
||||||
console.log('close')
|
console.log('close')
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.on('parser-error', (err) => {
|
stream.on('parser-error', err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
stream.stop()
|
|
||||||
}, 10000)
|
|
||||||
|
|
|
@ -7,30 +7,30 @@ import Emoji from './emoji'
|
||||||
import Card from './card'
|
import Card from './card'
|
||||||
|
|
||||||
export default interface Status {
|
export default interface Status {
|
||||||
id: number,
|
id: string
|
||||||
uri: string,
|
uri: string
|
||||||
url: string,
|
url: string
|
||||||
account: Account,
|
account: Account
|
||||||
in_reply_to_id: number | null,
|
in_reply_to_id: number | null
|
||||||
in_reply_to_account_id: number | null,
|
in_reply_to_account_id: number | null
|
||||||
reblog: Status | null,
|
reblog: Status | null
|
||||||
content: string,
|
content: string
|
||||||
created_at: string,
|
created_at: string
|
||||||
emojis: Emoji[],
|
emojis: Emoji[]
|
||||||
replies_count: number,
|
replies_count: number
|
||||||
reblogs_count: number,
|
reblogs_count: number
|
||||||
favourites_count: number,
|
favourites_count: number
|
||||||
reblogged: boolean | null,
|
reblogged: boolean | null
|
||||||
favourited: boolean | null,
|
favourited: boolean | null
|
||||||
muted: boolean | null,
|
muted: boolean | null
|
||||||
sensitive: boolean,
|
sensitive: boolean
|
||||||
spoiler_text: string,
|
spoiler_text: string
|
||||||
visibility: 'public' | 'unlisted' | 'private' | 'direct',
|
visibility: 'public' | 'unlisted' | 'private' | 'direct'
|
||||||
media_attachments: Attachment[],
|
media_attachments: Attachment[]
|
||||||
mentions: Mention[],
|
mentions: Mention[]
|
||||||
tags: Tag[],
|
tags: Tag[]
|
||||||
card: Card | null,
|
card: Card | null
|
||||||
application: Application,
|
application: Application
|
||||||
language: string | null,
|
language: string | null
|
||||||
pinned: boolean | null
|
pinned: boolean | null
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,30 +52,33 @@ class Parser extends EventEmitter {
|
||||||
const event: string = root[0].substr(7)
|
const event: string = root[0].substr(7)
|
||||||
const data: string = root[1].substr(6)
|
const data: string = root[1].substr(6)
|
||||||
|
|
||||||
|
let jsonObj = {}
|
||||||
try {
|
try {
|
||||||
const obj = JSON.parse(data)
|
jsonObj = 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
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.emit('error', new Error(`Error parsing API reply: '${piece}', error message: '${err}'`))
|
// delete event does not have json object
|
||||||
} finally {
|
if (event !== 'delete') {
|
||||||
continue
|
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++
|
offset++
|
||||||
|
|
|
@ -18,7 +18,6 @@ class StreamingError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StreamListener
|
* StreamListener
|
||||||
* Listener of streaming. It receives data, and parse when streaming.
|
* Listener of streaming. It receives data, and parse when streaming.
|
||||||
|
@ -35,7 +34,6 @@ class StreamListener extends EventEmitter {
|
||||||
private _usedFirstReconnect: boolean
|
private _usedFirstReconnect: boolean
|
||||||
private _stallAbortTimeout: NodeJS.Timer | undefined
|
private _stallAbortTimeout: NodeJS.Timer | undefined
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param url full url of streaming: e.g. https://mastodon.social/api/v1/streaming/user
|
* @param url full url of streaming: e.g. https://mastodon.social/api/v1/streaming/user
|
||||||
* @param headers headers of streaming request
|
* @param headers headers of streaming request
|
||||||
|
@ -113,7 +111,7 @@ class StreamListener extends EventEmitter {
|
||||||
|
|
||||||
this.request = Request.get(this._buildRequestOption())
|
this.request = Request.get(this._buildRequestOption())
|
||||||
this.emit('connect', this.request)
|
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
|
// reset our reconnection attempt flag so next attempt goes through with 0 delay
|
||||||
// if we get a transport-level error
|
// if we get a transport-level error
|
||||||
this._usedFirstReconnect = false
|
this._usedFirstReconnect = false
|
||||||
|
@ -125,7 +123,7 @@ class StreamListener extends EventEmitter {
|
||||||
}
|
}
|
||||||
if (STATUS_CODES_TO_ABORT_ON.indexOf(response.statusCode) > -1) {
|
if (STATUS_CODES_TO_ABORT_ON.indexOf(response.statusCode) > -1) {
|
||||||
let body: string = ''
|
let body: string = ''
|
||||||
this.response.on('data', (chunk) => {
|
this.response.on('data', chunk => {
|
||||||
body += chunk.toString()
|
body += chunk.toString()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -141,14 +139,14 @@ class StreamListener extends EventEmitter {
|
||||||
body = ''
|
body = ''
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.response.on('data', (chunk) => {
|
this.response.on('data', chunk => {
|
||||||
this._connectInterval = 0
|
this._connectInterval = 0
|
||||||
|
|
||||||
this._resetStallAbortTimeout()
|
this._resetStallAbortTimeout()
|
||||||
this.parser.parse(chunk.toString())
|
this.parser.parse(chunk.toString())
|
||||||
})
|
})
|
||||||
|
|
||||||
this.response.on('error', (err) => {
|
this.response.on('error', err => {
|
||||||
// expose response errors on twit instance
|
// expose response errors on twit instance
|
||||||
this.emit('error', err)
|
this.emit('error', err)
|
||||||
})
|
})
|
||||||
|
@ -286,7 +284,7 @@ class StreamListener extends EventEmitter {
|
||||||
this.parser.on('conversation', (conversation: Conversation) => {
|
this.parser.on('conversation', (conversation: Conversation) => {
|
||||||
this.emit('conversation', conversation)
|
this.emit('conversation', conversation)
|
||||||
})
|
})
|
||||||
this.parser.on('delete', (id: number) => {
|
this.parser.on('delete', (id: string) => {
|
||||||
this.emit('delete', id)
|
this.emit('delete', id)
|
||||||
})
|
})
|
||||||
this.parser.on('error', (err: Error) => {
|
this.parser.on('error', (err: Error) => {
|
||||||
|
|
|
@ -122,17 +122,17 @@ export default class WebSocket extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
private _getClient(): client {
|
private _getClient(): client {
|
||||||
const cli = new client()
|
const cli = new client()
|
||||||
cli.on('connectFailed', (err) => {
|
cli.on('connectFailed', err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
this._reconnect(cli)
|
this._reconnect(cli)
|
||||||
})
|
})
|
||||||
cli.on('connect', (conn) => {
|
cli.on('connect', conn => {
|
||||||
this._socketConnection = conn
|
this._socketConnection = conn
|
||||||
this.emit('connect', {})
|
this.emit('connect', {})
|
||||||
conn.on('error', (err) => {
|
conn.on('error', err => {
|
||||||
this.emit('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
|
// Refer the code: https://tools.ietf.org/html/rfc6455#section-7.4
|
||||||
if (code === 1000) {
|
if (code === 1000) {
|
||||||
this.emit('close', {})
|
this.emit('close', {})
|
||||||
|
@ -162,7 +162,7 @@ export default class WebSocket extends EventEmitter {
|
||||||
this.parser.on('notification', (notification: Notification) => {
|
this.parser.on('notification', (notification: Notification) => {
|
||||||
this.emit('notification', notification)
|
this.emit('notification', notification)
|
||||||
})
|
})
|
||||||
this.parser.on('delete', (id: number) => {
|
this.parser.on('delete', (id: string) => {
|
||||||
this.emit('delete', id)
|
this.emit('delete', id)
|
||||||
})
|
})
|
||||||
this.parser.on('conversation', (conversation: Conversation) => {
|
this.parser.on('conversation', (conversation: Conversation) => {
|
||||||
|
@ -200,28 +200,37 @@ class Parser extends EventEmitter {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let event = ''
|
||||||
|
let payload = ''
|
||||||
|
let mes = {}
|
||||||
try {
|
try {
|
||||||
const obj = JSON.parse(data)
|
const obj = JSON.parse(data)
|
||||||
const payload: string = obj.payload
|
event = obj.event
|
||||||
const mes = JSON.parse(payload)
|
payload = obj.payload
|
||||||
switch (obj.event) {
|
mes = JSON.parse(payload)
|
||||||
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}`))
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} 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
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue