refs #983 Get streaming url for instance API before start streaming

This commit is contained in:
AkiraFukushima 2019-07-29 23:32:02 +09:00
parent 869defd927
commit 1c836dfb95
2 changed files with 247 additions and 240 deletions

View File

@ -28,7 +28,7 @@ import sanitizeHtml from 'sanitize-html'
import pkg from '~/package.json' import pkg from '~/package.json'
import Authentication from './auth' import Authentication from './auth'
import Account from './account' import Account from './account'
import WebSocket from './websocket' import WebSocket, { StreamingURL } from './websocket'
import Preferences from './preferences' import Preferences from './preferences'
import Fonts from './fonts' import Fonts from './fonts'
import Hashtags from './hashtags' import Hashtags from './hashtags'
@ -441,79 +441,78 @@ ipcMain.on('reset-badge', () => {
let userStreamings: { [key: string]: WebSocket | null } = {} let userStreamings: { [key: string]: WebSocket | null } = {}
ipcMain.on('start-all-user-streamings', (event: Event, accounts: Array<LocalAccount>) => { ipcMain.on('start-all-user-streamings', (event: Event, accounts: Array<LocalAccount>) => {
accounts.map(account => { accounts.map(async account => {
const id: string = account._id! const id: string = account._id!
accountManager try {
.getAccount(id) const acct = await accountManager.getAccount(id)
.then(acct => { // Stop old user streaming
// Stop old user streaming if (userStreamings[id]) {
if (userStreamings[id]) { userStreamings[id]!.stop()
userStreamings[id]!.stop() userStreamings[id] = null
userStreamings[id] = null }
} const url = await StreamingURL(acct)
userStreamings[id] = new WebSocket(acct) userStreamings[id] = new WebSocket(acct, url)
userStreamings[id]!.startUserStreaming( userStreamings[id]!.startUserStreaming(
(update: Status) => { (update: Status) => {
if (!event.sender.isDestroyed()) { if (!event.sender.isDestroyed()) {
event.sender.send(`update-start-all-user-streamings-${id}`, update) event.sender.send(`update-start-all-user-streamings-${id}`, update)
} }
}, },
(notification: RemoteNotification) => { (notification: RemoteNotification) => {
const preferences = new Preferences(preferencesDBPath) const preferences = new Preferences(preferencesDBPath)
preferences.load().then(conf => { preferences.load().then(conf => {
const options = createNotification(notification, conf.notification.notify) const options = createNotification(notification, conf.notification.notify)
if (options !== null) { if (options !== null) {
const notify = new Notification(options) const notify = new Notification(options)
notify.on('click', _ => { notify.on('click', _ => {
if (!event.sender.isDestroyed()) { if (!event.sender.isDestroyed()) {
event.sender.send('open-notification-tab', id) event.sender.send('open-notification-tab', id)
} }
}) })
notify.show() notify.show()
}
})
if (process.platform === 'darwin') {
app.dock.setBadge('•')
} }
})
if (process.platform === 'darwin') {
app.dock.setBadge('•')
}
// In macOS and Windows, sometimes window is closed (not quit). // In macOS and Windows, sometimes window is closed (not quit).
// But streamings are always running. // But streamings are always running.
// When window is closed, we can not send event to webContents; because it is already destroyed. // When window is closed, we can not send event to webContents; because it is already destroyed.
// So we have to guard it. // So we have to guard it.
if (!event.sender.isDestroyed()) { if (!event.sender.isDestroyed()) {
// To update notification timeline // To update notification timeline
event.sender.send(`notification-start-all-user-streamings-${id}`, notification) event.sender.send(`notification-start-all-user-streamings-${id}`, notification)
// Does not exist a endpoint for only mention. And mention is a part of notification. // Does not exist a endpoint for only mention. And mention is a part of notification.
// So we have to get mention from notification. // So we have to get mention from notification.
if (notification.type === 'mention') { if (notification.type === 'mention') {
event.sender.send(`mention-start-all-user-streamings-${id}`, notification) event.sender.send(`mention-start-all-user-streamings-${id}`, notification)
}
}
},
(statusId: string) => {
if (!event.sender.isDestroyed()) {
event.sender.send(`delete-start-all-user-streamings-${id}`, statusId)
}
},
(err: Error) => {
log.error(err)
// In macOS, sometimes window is closed (not quit).
// When window is closed, we can not send event to webContents; because it is destroyed.
// So we have to guard it.
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-all-user-streamings', err)
} }
} }
) },
}) (statusId: string) => {
.catch((err: Error) => { if (!event.sender.isDestroyed()) {
log.error(err) event.sender.send(`delete-start-all-user-streamings-${id}`, statusId)
const streamingError = new StreamingError(err.message, account.domain) }
if (!event.sender.isDestroyed()) { },
event.sender.send('error-start-all-user-streamings', streamingError) (err: Error) => {
log.error(err)
// In macOS, sometimes window is closed (not quit).
// When window is closed, we can not send event to webContents; because it is destroyed.
// So we have to guard it.
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-all-user-streamings', err)
}
} }
}) )
} catch (err) {
log.error(err)
const streamingError = new StreamingError(err.message, account.domain)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-all-user-streamings', streamingError)
}
}
}) })
}) })
@ -545,44 +544,44 @@ type StreamingSetting = {
let directMessagesStreaming: WebSocket | null = null let directMessagesStreaming: WebSocket | null = null
ipcMain.on('start-directmessages-streaming', (event: Event, obj: StreamingSetting) => { ipcMain.on('start-directmessages-streaming', async (event: Event, obj: StreamingSetting) => {
const { account } = obj const { account } = obj
accountManager try {
.getAccount(account._id!) const acct = await accountManager.getAccount(account._id!)
.then(acct => {
// Stop old directmessages streaming
if (directMessagesStreaming !== null) {
directMessagesStreaming.stop()
directMessagesStreaming = null
}
directMessagesStreaming = new WebSocket(acct) // Stop old directmessages streaming
directMessagesStreaming.start( if (directMessagesStreaming !== null) {
'direct', directMessagesStreaming.stop()
(update: Status) => { directMessagesStreaming = null
if (!event.sender.isDestroyed()) { }
event.sender.send('update-start-directmessages-streaming', update)
} const url = await StreamingURL(acct)
}, directMessagesStreaming = new WebSocket(acct, url)
(id: string) => { directMessagesStreaming.start(
if (!event.sender.isDestroyed()) { 'direct',
event.sender.send('delete-start-directmessages-streaming', id) (update: Status) => {
} if (!event.sender.isDestroyed()) {
}, event.sender.send('update-start-directmessages-streaming', update)
(err: Error) => { }
log.error(err) },
if (!event.sender.isDestroyed()) { (id: string) => {
event.sender.send('error-start-directmessages-streaming', err) if (!event.sender.isDestroyed()) {
} event.sender.send('delete-start-directmessages-streaming', id)
}
},
(err: Error) => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-directmessages-streaming', err)
} }
)
})
.catch(err => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-directmessages-streaming', err)
} }
}) )
} catch (err) {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-directmessages-streaming', err)
}
}
}) })
ipcMain.on('stop-directmessages-streaming', () => { ipcMain.on('stop-directmessages-streaming', () => {
@ -594,44 +593,44 @@ ipcMain.on('stop-directmessages-streaming', () => {
let localStreaming: WebSocket | null = null let localStreaming: WebSocket | null = null
ipcMain.on('start-local-streaming', (event: Event, obj: StreamingSetting) => { ipcMain.on('start-local-streaming', async (event: Event, obj: StreamingSetting) => {
const { account } = obj const { account } = obj
accountManager try {
.getAccount(account._id!) const acct = await accountManager.getAccount(account._id!)
.then(acct => {
// Stop old local streaming
if (localStreaming !== null) {
localStreaming.stop()
localStreaming = null
}
localStreaming = new WebSocket(acct) // Stop old local streaming
localStreaming.start( if (localStreaming !== null) {
'public:local', localStreaming.stop()
(update: Status) => { localStreaming = null
if (!event.sender.isDestroyed()) { }
event.sender.send('update-start-local-streaming', update)
} const url = await StreamingURL(acct)
}, localStreaming = new WebSocket(acct, url)
(id: string) => { localStreaming.start(
if (!event.sender.isDestroyed()) { 'public:local',
event.sender.send('delete-start-local-streaming', id) (update: Status) => {
} if (!event.sender.isDestroyed()) {
}, event.sender.send('update-start-local-streaming', update)
(err: Error) => { }
log.error(err) },
if (!event.sender.isDestroyed()) { (id: string) => {
event.sender.send('error-start-local-streaming', err) if (!event.sender.isDestroyed()) {
} event.sender.send('delete-start-local-streaming', id)
}
},
(err: Error) => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-local-streaming', err)
} }
)
})
.catch(err => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-local-streaming', err)
} }
}) )
} catch (err) {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-local-streaming', err)
}
}
}) })
ipcMain.on('stop-local-streaming', () => { ipcMain.on('stop-local-streaming', () => {
@ -643,44 +642,44 @@ ipcMain.on('stop-local-streaming', () => {
let publicStreaming: WebSocket | null = null let publicStreaming: WebSocket | null = null
ipcMain.on('start-public-streaming', (event: Event, obj: StreamingSetting) => { ipcMain.on('start-public-streaming', async (event: Event, obj: StreamingSetting) => {
const { account } = obj const { account } = obj
accountManager try {
.getAccount(account._id!) const acct = await accountManager.getAccount(account._id!)
.then(acct => {
// Stop old public streaming
if (publicStreaming !== null) {
publicStreaming.stop()
publicStreaming = null
}
publicStreaming = new WebSocket(acct) // Stop old public streaming
publicStreaming.start( if (publicStreaming !== null) {
'public', publicStreaming.stop()
(update: Status) => { publicStreaming = null
if (!event.sender.isDestroyed()) { }
event.sender.send('update-start-public-streaming', update)
} const url = await StreamingURL(acct)
}, publicStreaming = new WebSocket(acct, url)
(id: string) => { publicStreaming.start(
if (!event.sender.isDestroyed()) { 'public',
event.sender.send('delete-start-public-streaming', id) (update: Status) => {
} if (!event.sender.isDestroyed()) {
}, event.sender.send('update-start-public-streaming', update)
(err: Error) => { }
log.error(err) },
if (!event.sender.isDestroyed()) { (id: string) => {
event.sender.send('error-start-public-streaming', err) if (!event.sender.isDestroyed()) {
} event.sender.send('delete-start-public-streaming', id)
}
},
(err: Error) => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-public-streaming', err)
} }
)
})
.catch(err => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-public-streaming', err)
} }
}) )
} catch (err) {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-public-streaming', err)
}
}
}) })
ipcMain.on('stop-public-streaming', () => { ipcMain.on('stop-public-streaming', () => {
@ -696,44 +695,44 @@ type ListID = {
listID: string listID: string
} }
ipcMain.on('start-list-streaming', (event: Event, obj: ListID & StreamingSetting) => { ipcMain.on('start-list-streaming', async (event: Event, obj: ListID & StreamingSetting) => {
const { listID, account } = obj const { listID, account } = obj
accountManager try {
.getAccount(account._id!) const acct = await accountManager.getAccount(account._id!)
.then(acct => {
// Stop old list streaming
if (listStreaming !== null) {
listStreaming.stop()
listStreaming = null
}
listStreaming = new WebSocket(acct) // Stop old list streaming
listStreaming.start( if (listStreaming !== null) {
`list&list=${listID}`, listStreaming.stop()
(update: Status) => { listStreaming = null
if (!event.sender.isDestroyed()) { }
event.sender.send('update-start-list-streaming', update)
} const url = await StreamingURL(acct)
}, listStreaming = new WebSocket(acct, url)
(id: string) => { listStreaming.start(
if (!event.sender.isDestroyed()) { `list&list=${listID}`,
event.sender.send('delete-start-list-streaming', id) (update: Status) => {
} if (!event.sender.isDestroyed()) {
}, event.sender.send('update-start-list-streaming', update)
(err: Error) => { }
log.error(err) },
if (!event.sender.isDestroyed()) { (id: string) => {
event.sender.send('error-start-list-streaming', err) if (!event.sender.isDestroyed()) {
} event.sender.send('delete-start-list-streaming', id)
}
},
(err: Error) => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-list-streaming', err)
} }
)
})
.catch(err => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-list-streaming', err)
} }
}) )
} catch (err) {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-list-streaming', err)
}
}
}) })
ipcMain.on('stop-list-streaming', () => { ipcMain.on('stop-list-streaming', () => {
@ -749,44 +748,44 @@ type Tag = {
tag: string tag: string
} }
ipcMain.on('start-tag-streaming', (event: Event, obj: Tag & StreamingSetting) => { ipcMain.on('start-tag-streaming', async (event: Event, obj: Tag & StreamingSetting) => {
const { tag, account } = obj const { tag, account } = obj
accountManager try {
.getAccount(account._id!) const acct = await accountManager.getAccount(account._id!)
.then(acct => {
// Stop old tag streaming
if (tagStreaming !== null) {
tagStreaming.stop()
tagStreaming = null
}
tagStreaming = new WebSocket(acct) // Stop old tag streaming
tagStreaming.start( if (tagStreaming !== null) {
`hashtag&tag=${tag}`, tagStreaming.stop()
(update: Status) => { tagStreaming = null
if (!event.sender.isDestroyed()) { }
event.sender.send('update-start-tag-streaming', update)
} const url = await StreamingURL(acct)
}, tagStreaming = new WebSocket(acct, url)
(id: string) => { tagStreaming.start(
if (!event.sender.isDestroyed()) { `hashtag&tag=${tag}`,
event.sender.send('delete-start-tag-streaming', id) (update: Status) => {
} if (!event.sender.isDestroyed()) {
}, event.sender.send('update-start-tag-streaming', update)
(err: Error) => { }
log.error(err) },
if (!event.sender.isDestroyed()) { (id: string) => {
event.sender.send('error-start-tag-streaming', err) if (!event.sender.isDestroyed()) {
} event.sender.send('delete-start-tag-streaming', id)
}
},
(err: Error) => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-tag-streaming', err)
} }
)
})
.catch(err => {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-tag-streaming', err)
} }
}) )
} catch (err) {
log.error(err)
if (!event.sender.isDestroyed()) {
event.sender.send('error-start-tag-streaming', err)
}
}
}) })
ipcMain.on('stop-tag-streaming', () => { ipcMain.on('stop-tag-streaming', () => {

View File

@ -1,13 +1,21 @@
import Mastodon, { WebSocket as SocketListener, Status, Notification } from 'megalodon' import Mastodon, { WebSocket as SocketListener, Status, Notification, Instance } from 'megalodon'
import log from 'electron-log' import log from 'electron-log'
import { LocalAccount } from '~/src/types/localAccount' import { LocalAccount } from '~/src/types/localAccount'
const StreamingURL = async (account: LocalAccount): Promise<string> => {
const client = new Mastodon(account.accessToken!, account.baseURL + '/api/v1')
const res = await client.get<Instance>('/instance')
return res.data.urls.streaming_api
}
export { StreamingURL }
export default class WebSocket { export default class WebSocket {
private client: Mastodon private client: Mastodon
private listener: SocketListener | null private listener: SocketListener | null
constructor(account: LocalAccount) { constructor(account: LocalAccount, streamingURL: string) {
const url = account.baseURL.replace(/^https:\/\//, 'wss://') const url = streamingURL.replace(/^https:\/\//, 'wss://')
this.client = new Mastodon(account.accessToken!, url + '/api/v1') this.client = new Mastodon(account.accessToken!, url + '/api/v1')
this.listener = null this.listener = null
} }