1
0
mirror of https://github.com/h3poteto/whalebird-desktop synced 2025-02-01 01:47:01 +01:00

refs #635 Connect to Pleroma with Web Socket to streaming update

This commit is contained in:
AkiraFukushima 2018-10-05 08:42:59 +09:00
parent c00fa89b4e
commit d341c9205e
6 changed files with 259 additions and 20 deletions

63
package-lock.json generated
View File

@ -208,6 +208,11 @@
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz",
"integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A=="
},
"@types/events": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA=="
},
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
@ -279,6 +284,15 @@
"@types/uglify-js": "*"
}
},
"@types/websocket": {
"version": "0.0.40",
"resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-0.0.40.tgz",
"integrity": "sha512-ldteZwWIgl9cOy7FyvYn+39Ah4+PfpVE72eYKw75iy2L0zTbhbcwvzeJ5IOu6DQP93bjfXq0NGHY6FYtmYoqFQ==",
"requires": {
"@types/events": "*",
"@types/node": "*"
}
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -10479,16 +10493,18 @@
"dev": true
},
"megalodon": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/megalodon/-/megalodon-0.3.0.tgz",
"integrity": "sha512-PSSqnLmZUToMF6yFpufq58By0+Pc+ar8NiT+xrQlG6GW6O6CedWc2ZR1bQwUVO5pJjRnEvI4oyp1xA5Gu3hBAA==",
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/megalodon/-/megalodon-0.4.2.tgz",
"integrity": "sha512-k5xRgg2H+p8yEM9O9kdB6yMgxruHcZMFB5iS2F+u3N1hM4RcW8pF7H2Q0Pip8+7mlzGolLVxDu+W0atHnNAPcQ==",
"requires": {
"@types/oauth": "^0.9.0",
"@types/request": "^2.47.0",
"@types/websocket": "0.0.40",
"axios": "^0.18.0",
"oauth": "^0.9.15",
"request": "^2.87.0",
"typescript": "^2.9.1"
"typescript": "^2.9.1",
"websocket": "^1.0.28"
}
},
"mem": {
@ -16375,6 +16391,14 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"requires": {
"is-typedarray": "^1.0.0"
}
},
"typescript": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
@ -17764,6 +17788,32 @@
}
}
},
"websocket": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.28.tgz",
"integrity": "sha512-00y/20/80P7H4bCYkzuuvvfDvh+dgtXi5kzDf3UcZwN6boTYaKvsrtZ5lIYm1Gsg48siMErd9M4zjSYfYFHTrA==",
"requires": {
"debug": "^2.2.0",
"nan": "^2.11.0",
"typedarray-to-buffer": "^3.1.5",
"yaeti": "^0.0.6"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"nan": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz",
"integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA=="
}
}
},
"websocket-driver": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
@ -18017,6 +18067,11 @@
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",

View File

@ -110,7 +110,7 @@
"i18next-sync-fs-backend": "^1.1.0",
"is-empty": "^1.2.0",
"lodash": "^4.17.10",
"megalodon": "^0.3.0",
"megalodon": "0.4.2",
"moment": "^2.21.0",
"mousetrap": "^1.6.2",
"nedb": "^1.8.0",

View File

@ -13,7 +13,7 @@ import openAboutWindow from 'about-window'
import Authentication from './auth'
import Account from './account'
import Streaming from './streaming'
import StreamingManager from './streaming_manager'
import Preferences from './preferences'
import Fonts from './fonts'
import Hashtags from './hashtags'
@ -396,8 +396,8 @@ ipcMain.on('start-user-streaming', (event, ac) => {
userStreaming = null
}
userStreaming = new Streaming(account)
userStreaming.startUserStreaming(
userStreaming = new StreamingManager(account)
userStreaming.startUser(
(update) => {
event.sender.send('update-start-user-streaming', update)
},
@ -438,9 +438,9 @@ ipcMain.on('start-local-streaming', (event, ac) => {
localStreaming = null
}
localStreaming = new Streaming(account)
localStreaming = new StreamingManager(account)
localStreaming.start(
'/streaming/public/local',
'public/local',
(update) => {
event.sender.send('update-start-local-streaming', update)
},
@ -475,9 +475,9 @@ ipcMain.on('start-public-streaming', (event, ac) => {
publicStreaming = null
}
publicStreaming = new Streaming(account)
publicStreaming = new StreamingManager(account)
publicStreaming.start(
'/streaming/public',
'public',
(update) => {
event.sender.send('update-start-public-streaming', update)
},
@ -512,9 +512,9 @@ ipcMain.on('start-list-streaming', (event, obj) => {
listStreaming = null
}
listStreaming = new Streaming(account)
listStreaming = new StreamingManager(account)
listStreaming.start(
`/streaming/list?list=${obj.list_id}`,
`list?list=${obj.list_id}`,
(update) => {
event.sender.send('update-start-list-streaming', update)
},
@ -549,9 +549,9 @@ ipcMain.on('start-tag-streaming', (event, obj) => {
tagStreaming = null
}
tagStreaming = new Streaming(account)
tagStreaming = new StreamingManager(account)
tagStreaming.start(
`/streaming/hashtag?tag=${obj.tag}`,
`hashtag?tag=${obj.tag}`,
(update) => {
event.sender.send('update-start-tag-streaming', update)
},

View File

@ -13,7 +13,10 @@ export default class Streaming {
startUserStreaming (updateCallback, notificationCallback, errCallback) {
this.listener = this.client.stream('/streaming/user')
log.info('/streaming/user started')
this.listener.on('connect', _ => {
log.info('/streaming/user started')
})
this.listener.on('update', (status) => {
updateCallback(status)
@ -26,11 +29,17 @@ export default class Streaming {
this.listener.on('error', (err) => {
errCallback(err)
})
this.listener.on('connection-limit-exceeded', err => {
errCallback(err)
})
}
start (path, updateCallback, errCallback) {
this.listener = this.client.stream(path)
log.info(`${path} started`)
this.listener.on('connect', _ => {
log.info(`${path} started`)
})
this.listener.on('update', (status) => {
updateCallback(status)
@ -39,10 +48,16 @@ export default class Streaming {
this.listener.on('error', (err) => {
errCallback(err)
})
this.listener.on('connection-limit-exceeded', err => {
errCallback(err)
})
}
stop () {
this.listener.stop()
log.info('streaming stopped')
if (this.listener) {
this.listener.stop()
log.info('streaming stopped')
}
}
}

View File

@ -0,0 +1,96 @@
import Mastodon from 'megalodon'
import Streaming from './streaming'
import WebSocket from './websocket'
import log from 'electron-log'
export default class StreamingManager {
constructor (account) {
this.account = account
this.streaming = new Streaming(account)
this.websocket = new WebSocket(account)
this.mastodon = true
}
/**
* Find Pleroma comment in the response
*/
async detectPleroma () {
const data = await Mastodon.get('/instance', {}, this.account.baseURL + '/api/v1')
if (data.version.includes('Pleroma')) {
this.mastodon = false
log.info('detect Pleroma')
}
}
startUser (updateCallback, notificationCallback, errCallback) {
this.detectPleroma()
.then(() => {
if (this.mastodon) {
this._startUserStreaming(updateCallback, notificationCallback, errCallback)
} else {
this._startUserSocket(updateCallback, notificationCallback, errCallback)
}
})
.catch(err => errCallback(err))
}
start (path, updateCallback, errCallback) {
this.detectPleroma()
.then(() => {
if (this.mastodon) {
this._startStreaming(path, updateCallback, errCallback)
} else {
this._startSocket(path, updateCallback, errCallback)
}
})
.catch(err => errCallback(err))
}
stop () {
this._stopStreaming()
this._stopSocket()
}
/**
* Using streaming for Mastodon
*/
_startUserStreaming (updateCallback, notificationCallback, errCallback) {
this.streaming.startUserStreaming(updateCallback, notificationCallback, errCallback)
}
_startStreaming (path, updateCallback, errCallback) {
const target = `/streaming/${path}`
this.streaming.start(
target,
updateCallback,
errCallback
)
}
_stopStreaming () {
this.streaming.stop()
}
/**
* Using websocket for Pleroma
*/
_startUserSocket (updateCallback, notificationCallback, errCallback) {
this.websocket.startUserStreaming(updateCallback, notificationCallback, errCallback)
}
_startSocket (path, updateCallback, errCallback) {
let stream = path
if (stream === 'public/local') {
stream = 'public:local'
}
this.websocket.start(
stream,
updateCallback,
errCallback
)
}
_stopSocket () {
this.websocket.stop()
}
}

73
src/main/websocket.js Normal file
View File

@ -0,0 +1,73 @@
import Mastodon from 'megalodon'
import log from 'electron-log'
export default class WebSocket {
constructor (account) {
this.account = account
this.client = new Mastodon(
account.accessToken,
account.baseURL + '/api/v1'
)
this.listener = null
}
startUserStreaming (updateCallback, notificationCallback, errCallback) {
this.listener = this.client.socket('/streaming', 'user')
this.listener.on('connect', _ => {
log.info('/streaming/?stream=user started')
})
this.listener.on('update', (status) => {
updateCallback(status)
})
this.listener.on('notification', (notification) => {
notificationCallback(notification)
})
this.listener.on('error', (err) => {
errCallback(err)
})
this.listener.on('parser-error', (err) => {
errCallback(err)
})
}
/**
* Start new custom streaming with websocket.
* @param stream Path of streaming.
* @param updateCallback A callback function which is called update.
* @param errCallback A callback function which ic called error.
* When local timeline, the path is `public:local`.
* When public timeline, the path is `public`.
* When hashtag timeline, the path is `hashtag&tag=tag_name`.
* When list timeline, the path is `list&list=list_id`.
*/
start (stream, updateCallback, errCallback) {
this.listener = this.client.socket('/streaming', stream)
this.listener.on('connect', _ => {
log.info(`/streaming/?stream=${stream} started`)
})
this.listener.on('update', status => {
updateCallback(status)
})
this.listener.on('error', (err) => {
errCallback(err)
})
this.listener.on('parser-error', (err) => {
errCallback(err)
})
}
stop () {
if (this.listener) {
this.listener.stop()
log.info('streaming stopped')
}
}
}