Fix megalodon class for 3.0.0 in main
This commit is contained in:
parent
6709156c7f
commit
5ab9c28ead
|
@ -1,5 +1,5 @@
|
|||
import { isEmpty } from 'lodash'
|
||||
import Mastodon, { Account as RemoteAccount, ProxyConfig } from 'megalodon'
|
||||
import generator, { detector, Entity, ProxyConfig } from 'megalodon'
|
||||
import Datastore from 'nedb'
|
||||
import log from 'electron-log'
|
||||
import { LocalAccount } from '~/src/types/localAccount'
|
||||
|
@ -295,10 +295,11 @@ export default class Account {
|
|||
* @return {LocalAccount} updated account
|
||||
*/
|
||||
async refresh(account: LocalAccount, proxy: ProxyConfig | false): Promise<LocalAccount> {
|
||||
let client = new Mastodon(account.accessToken!, account.baseURL + '/api/v1', 'Whalebird', proxy)
|
||||
const sns = await detector(account.baseURL, proxy)
|
||||
let client = generator(sns, account.baseURL, account.accessToken, 'Whalebird', proxy)
|
||||
let json = {}
|
||||
try {
|
||||
const res = await client.get<RemoteAccount>('/accounts/verify_credentials')
|
||||
const res = await client.verifyAccountCredentials()
|
||||
json = {
|
||||
username: res.data.username,
|
||||
accountId: res.data.id,
|
||||
|
@ -311,9 +312,9 @@ export default class Account {
|
|||
if (!account.refreshToken) {
|
||||
throw new RefreshTokenDoesNotExist()
|
||||
}
|
||||
const token = await Mastodon.refreshToken(account.clientId, account.clientSecret, account.refreshToken, account.baseURL, proxy)
|
||||
client = new Mastodon(token.access_token, account.baseURL + '/api/v1', 'Whalebird', proxy)
|
||||
const res = await client.get<RemoteAccount>('/accounts/verify_credentials')
|
||||
const token = await client.refreshToken(account.clientId, account.clientSecret, account.refreshToken)
|
||||
client = generator(sns, account.baseURL, token.access_token, 'Whalebird', proxy)
|
||||
const res = await client.verifyAccountCredentials()
|
||||
json = {
|
||||
username: res.data.username,
|
||||
accountId: res.data.id,
|
||||
|
@ -326,9 +327,14 @@ export default class Account {
|
|||
}
|
||||
|
||||
// Confirm the access token, and check duplicate
|
||||
async fetchAccount(account: LocalAccount, accessToken: string, proxy: ProxyConfig | false): Promise<RemoteAccount> {
|
||||
const client = new Mastodon(accessToken, account.baseURL + '/api/v1', 'Whalebird', proxy)
|
||||
const res = await client.get<RemoteAccount>('/accounts/verify_credentials')
|
||||
async fetchAccount(
|
||||
sns: 'mastodon' | 'pleroma' | 'misskey',
|
||||
account: LocalAccount,
|
||||
accessToken: string,
|
||||
proxy: ProxyConfig | false
|
||||
): Promise<Entity.Account> {
|
||||
const client = generator(sns, account.baseURL, accessToken, 'Whalebird', proxy)
|
||||
const res = await client.verifyAccountCredentials()
|
||||
const query = {
|
||||
baseURL: account.baseURL,
|
||||
username: res.data.username
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import Mastodon, { OAuth, ProxyConfig } from 'megalodon'
|
||||
import generator, { ProxyConfig, detector } from 'megalodon'
|
||||
import Account from './account'
|
||||
import { LocalAccount } from '~/src/types/localAccount'
|
||||
|
||||
const appName = 'Whalebird'
|
||||
const appURL = 'https://whalebird.org'
|
||||
const scope = 'read write follow'
|
||||
const scopes = ['read', 'write', 'follow']
|
||||
|
||||
export default class Authentication {
|
||||
private db: Account
|
||||
|
@ -32,15 +32,12 @@ export default class Authentication {
|
|||
|
||||
async getAuthorizationUrl(domain = 'mastodon.social', proxy: ProxyConfig | false): Promise<string> {
|
||||
this.setOtherInstance(domain)
|
||||
const res = await Mastodon.registerApp(
|
||||
appName,
|
||||
{
|
||||
scopes: scope,
|
||||
website: appURL
|
||||
},
|
||||
this.baseURL,
|
||||
proxy
|
||||
)
|
||||
const sns = await detector(this.baseURL, proxy)
|
||||
const client = generator(sns, this.baseURL, null, 'Whalebird', proxy)
|
||||
const res = await client.registerApp(appName, {
|
||||
scopes: scopes,
|
||||
website: appURL
|
||||
})
|
||||
this.clientId = res.clientId
|
||||
this.clientSecret = res.clientSecret
|
||||
|
||||
|
@ -71,14 +68,9 @@ export default class Authentication {
|
|||
}
|
||||
|
||||
async getAccessToken(code: string, proxy: ProxyConfig | false): Promise<string> {
|
||||
const tokenData: OAuth.TokenData = await Mastodon.fetchAccessToken(
|
||||
this.clientId,
|
||||
this.clientSecret,
|
||||
code,
|
||||
this.baseURL,
|
||||
'urn:ietf:wg:oauth:2.0:oob',
|
||||
proxy
|
||||
)
|
||||
const sns = await detector(this.baseURL, proxy)
|
||||
const client = generator(sns, this.baseURL, null, 'Whalebird', proxy)
|
||||
const tokenData = await client.fetchAccessToken(this.clientId, this.clientSecret, code, 'urn:ietf:wg:oauth:2.0:oob')
|
||||
const search = {
|
||||
baseURL: this.baseURL,
|
||||
domain: this.domain,
|
||||
|
@ -88,7 +80,7 @@ export default class Authentication {
|
|||
const rec = await this.db.searchAccount(search)
|
||||
const accessToken = tokenData.accessToken
|
||||
const refreshToken = tokenData.refreshToken
|
||||
const data = await this.db.fetchAccount(rec, accessToken, proxy)
|
||||
const data = await this.db.fetchAccount(sns, rec, accessToken, proxy)
|
||||
await this.db.updateAccount(rec._id!, {
|
||||
username: data.username,
|
||||
accountId: data.id,
|
||||
|
|
|
@ -24,14 +24,14 @@ import path from 'path'
|
|||
import ContextMenu from 'electron-context-menu'
|
||||
import { initSplashScreen, Config } from '@trodi/electron-splashscreen'
|
||||
import openAboutWindow from 'about-window'
|
||||
import { Status, Notification as RemoteNotification, Account as RemoteAccount } from 'megalodon'
|
||||
import { Entity, detector } from 'megalodon'
|
||||
import sanitizeHtml from 'sanitize-html'
|
||||
import AutoLaunch from 'auto-launch'
|
||||
|
||||
import pkg from '~/package.json'
|
||||
import Authentication from './auth'
|
||||
import Account from './account'
|
||||
import WebSocket, { StreamingURL } from './websocket'
|
||||
import { StreamingURL, UserStreaming, DirectStreaming, LocalStreaming, PublicStreaming, ListStreaming, TagStreaming } from './websocket'
|
||||
import Preferences from './preferences'
|
||||
import Fonts from './fonts'
|
||||
import Hashtags from './hashtags'
|
||||
|
@ -530,7 +530,7 @@ ipcMain.on('reset-badge', () => {
|
|||
})
|
||||
|
||||
// user streaming
|
||||
let userStreamings: { [key: string]: WebSocket | null } = {}
|
||||
let userStreamings: { [key: string]: UserStreaming | null } = {}
|
||||
|
||||
ipcMain.on('start-all-user-streamings', (event: IpcMainEvent, accounts: Array<LocalAccount>) => {
|
||||
accounts.map(async account => {
|
||||
|
@ -543,10 +543,11 @@ ipcMain.on('start-all-user-streamings', (event: IpcMainEvent, accounts: Array<Lo
|
|||
userStreamings[id] = null
|
||||
}
|
||||
const proxy = await proxyConfiguration.forMastodon()
|
||||
const url = await StreamingURL(acct, proxy)
|
||||
userStreamings[id] = new WebSocket(acct, url, proxy)
|
||||
userStreamings[id]!.startUserStreaming(
|
||||
async (update: Status) => {
|
||||
const sns = await detector(acct.baseURL, proxy)
|
||||
const url = await StreamingURL(sns, acct, proxy)
|
||||
userStreamings[id] = new UserStreaming(sns, acct, url, proxy)
|
||||
userStreamings[id]!.start(
|
||||
async (update: Entity.Status) => {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send(`update-start-all-user-streamings-${id}`, update)
|
||||
}
|
||||
|
@ -557,7 +558,7 @@ ipcMain.on('start-all-user-streamings', (event: IpcMainEvent, accounts: Array<Lo
|
|||
// Cache account
|
||||
await accountCache.insertAccount(id, update.account.acct).catch(err => console.error(err))
|
||||
},
|
||||
(notification: RemoteNotification) => {
|
||||
(notification: Entity.Notification) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.load().then(conf => {
|
||||
const options = createNotification(notification, conf.notification.notify)
|
||||
|
@ -641,7 +642,7 @@ type StreamingSetting = {
|
|||
account: LocalAccount
|
||||
}
|
||||
|
||||
let directMessagesStreaming: WebSocket | null = null
|
||||
let directMessagesStreaming: DirectStreaming | null = null
|
||||
|
||||
ipcMain.on('start-directmessages-streaming', async (event: IpcMainEvent, obj: StreamingSetting) => {
|
||||
const { account } = obj
|
||||
|
@ -654,11 +655,11 @@ ipcMain.on('start-directmessages-streaming', async (event: IpcMainEvent, obj: St
|
|||
directMessagesStreaming = null
|
||||
}
|
||||
const proxy = await proxyConfiguration.forMastodon()
|
||||
const url = await StreamingURL(acct, proxy)
|
||||
directMessagesStreaming = new WebSocket(acct, url, proxy)
|
||||
const sns = await detector(acct.baseURL, proxy)
|
||||
const url = await StreamingURL(sns, acct, proxy)
|
||||
directMessagesStreaming = new DirectStreaming(sns, acct, url, proxy)
|
||||
directMessagesStreaming.start(
|
||||
'direct',
|
||||
(update: Status) => {
|
||||
(update: Entity.Status) => {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('update-start-directmessages-streaming', update)
|
||||
}
|
||||
|
@ -690,7 +691,7 @@ ipcMain.on('stop-directmessages-streaming', () => {
|
|||
}
|
||||
})
|
||||
|
||||
let localStreaming: WebSocket | null = null
|
||||
let localStreaming: LocalStreaming | null = null
|
||||
|
||||
ipcMain.on('start-local-streaming', async (event: IpcMainEvent, obj: StreamingSetting) => {
|
||||
const { account } = obj
|
||||
|
@ -703,11 +704,11 @@ ipcMain.on('start-local-streaming', async (event: IpcMainEvent, obj: StreamingSe
|
|||
localStreaming = null
|
||||
}
|
||||
const proxy = await proxyConfiguration.forMastodon()
|
||||
const url = await StreamingURL(acct, proxy)
|
||||
localStreaming = new WebSocket(acct, url, proxy)
|
||||
const sns = await detector(acct.baseURL, proxy)
|
||||
const url = await StreamingURL(sns, acct, proxy)
|
||||
localStreaming = new LocalStreaming(sns, acct, url, proxy)
|
||||
localStreaming.start(
|
||||
'public:local',
|
||||
(update: Status) => {
|
||||
(update: Entity.Status) => {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('update-start-local-streaming', update)
|
||||
}
|
||||
|
@ -739,7 +740,7 @@ ipcMain.on('stop-local-streaming', () => {
|
|||
}
|
||||
})
|
||||
|
||||
let publicStreaming: WebSocket | null = null
|
||||
let publicStreaming: PublicStreaming | null = null
|
||||
|
||||
ipcMain.on('start-public-streaming', async (event: IpcMainEvent, obj: StreamingSetting) => {
|
||||
const { account } = obj
|
||||
|
@ -752,11 +753,11 @@ ipcMain.on('start-public-streaming', async (event: IpcMainEvent, obj: StreamingS
|
|||
publicStreaming = null
|
||||
}
|
||||
const proxy = await proxyConfiguration.forMastodon()
|
||||
const url = await StreamingURL(acct, proxy)
|
||||
publicStreaming = new WebSocket(acct, url, proxy)
|
||||
const sns = await detector(acct.baseURL, proxy)
|
||||
const url = await StreamingURL(sns, acct, proxy)
|
||||
publicStreaming = new PublicStreaming(sns, acct, url, proxy)
|
||||
publicStreaming.start(
|
||||
'public',
|
||||
(update: Status) => {
|
||||
(update: Entity.Status) => {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('update-start-public-streaming', update)
|
||||
}
|
||||
|
@ -788,7 +789,7 @@ ipcMain.on('stop-public-streaming', () => {
|
|||
}
|
||||
})
|
||||
|
||||
let listStreaming: WebSocket | null = null
|
||||
let listStreaming: ListStreaming | null = null
|
||||
|
||||
type ListID = {
|
||||
listID: string
|
||||
|
@ -805,11 +806,12 @@ ipcMain.on('start-list-streaming', async (event: IpcMainEvent, obj: ListID & Str
|
|||
listStreaming = null
|
||||
}
|
||||
const proxy = await proxyConfiguration.forMastodon()
|
||||
const url = await StreamingURL(acct, proxy)
|
||||
listStreaming = new WebSocket(acct, url, proxy)
|
||||
const sns = await detector(acct.baseURL, proxy)
|
||||
const url = await StreamingURL(sns, acct, proxy)
|
||||
listStreaming = new ListStreaming(sns, acct, url, proxy)
|
||||
listStreaming.start(
|
||||
`list&list=${listID}`,
|
||||
(update: Status) => {
|
||||
listID,
|
||||
(update: Entity.Status) => {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('update-start-list-streaming', update)
|
||||
}
|
||||
|
@ -841,7 +843,7 @@ ipcMain.on('stop-list-streaming', () => {
|
|||
}
|
||||
})
|
||||
|
||||
let tagStreaming: WebSocket | null = null
|
||||
let tagStreaming: TagStreaming | null = null
|
||||
|
||||
type Tag = {
|
||||
tag: string
|
||||
|
@ -858,11 +860,12 @@ ipcMain.on('start-tag-streaming', async (event: IpcMainEvent, obj: Tag & Streami
|
|||
tagStreaming = null
|
||||
}
|
||||
const proxy = await proxyConfiguration.forMastodon()
|
||||
const url = await StreamingURL(acct, proxy)
|
||||
tagStreaming = new WebSocket(acct, url, proxy)
|
||||
const sns = await detector(acct.baseURL, proxy)
|
||||
const url = await StreamingURL(sns, acct, proxy)
|
||||
tagStreaming = new TagStreaming(sns, acct, url, proxy)
|
||||
tagStreaming.start(
|
||||
`hashtag&tag=${tag}`,
|
||||
(update: Status) => {
|
||||
tag,
|
||||
(update: Entity.Status) => {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('update-start-tag-streaming', update)
|
||||
}
|
||||
|
@ -1375,7 +1378,7 @@ async function reopenWindow() {
|
|||
}
|
||||
}
|
||||
|
||||
const createNotification = (notification: RemoteNotification, notifyConfig: Notify): NotificationConstructorOptions | null => {
|
||||
const createNotification = (notification: Entity.Notification, notifyConfig: Notify): NotificationConstructorOptions | null => {
|
||||
switch (notification.type) {
|
||||
case 'favourite':
|
||||
if (notifyConfig.favourite) {
|
||||
|
@ -1422,7 +1425,7 @@ const createNotification = (notification: RemoteNotification, notifyConfig: Noti
|
|||
return null
|
||||
}
|
||||
|
||||
const username = (account: RemoteAccount): string => {
|
||||
const username = (account: Entity.Account): string => {
|
||||
if (account.display_name !== '') {
|
||||
return account.display_name
|
||||
} else {
|
||||
|
|
|
@ -1,73 +1,39 @@
|
|||
import Mastodon, { WebSocket as SocketListener, Status, Notification, Instance, Response, ProxyConfig } from 'megalodon'
|
||||
import generator, { MegalodonInterface, WebSocketInterface, Entity, ProxyConfig } from 'megalodon'
|
||||
import log from 'electron-log'
|
||||
import { LocalAccount } from '~/src/types/localAccount'
|
||||
|
||||
const StreamingURL = async (account: LocalAccount, proxy: ProxyConfig | false): Promise<string> => {
|
||||
const StreamingURL = async (
|
||||
sns: 'mastodon' | 'pleroma' | 'misskey',
|
||||
account: LocalAccount,
|
||||
proxy: ProxyConfig | false
|
||||
): Promise<string> => {
|
||||
if (!account.accessToken) {
|
||||
throw new Error('access token is empty')
|
||||
}
|
||||
const client = new Mastodon(account.accessToken, account.baseURL + '/api/v1', 'Whalebird', proxy)
|
||||
const res: Response<Instance> = await client.get<Instance>('/instance')
|
||||
const client = generator(sns, account.baseURL, account.accessToken, 'Whalebird', proxy)
|
||||
const res = await client.getInstance()
|
||||
return res.data.urls.streaming_api
|
||||
}
|
||||
|
||||
export { StreamingURL }
|
||||
|
||||
export default class WebSocket {
|
||||
private client: Mastodon
|
||||
private listener: SocketListener | null
|
||||
class WebSocket {
|
||||
public client: MegalodonInterface
|
||||
public listener: WebSocketInterface | null
|
||||
|
||||
constructor(account: LocalAccount, streamingURL: string, proxy: ProxyConfig | false) {
|
||||
constructor(sns: 'mastodon' | 'pleroma' | 'misskey', account: LocalAccount, streamingURL: string, proxy: ProxyConfig | false) {
|
||||
const url = streamingURL.replace(/^https:\/\//, 'wss://')
|
||||
this.client = new Mastodon(account.accessToken!, url + '/api/v1', 'Whalebird', proxy)
|
||||
this.client = generator(sns, url, account.accessToken, 'Whalebird', proxy)
|
||||
this.listener = null
|
||||
}
|
||||
|
||||
startUserStreaming(updateCallback: Function, notificationCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.socket('/streaming', 'user')
|
||||
public bindListener(updateCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
if (!this.listener) {
|
||||
log.error('listener does not exist')
|
||||
return
|
||||
}
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('/streaming/?stream=user started')
|
||||
})
|
||||
|
||||
this.listener.on('update', (status: Status) => {
|
||||
updateCallback(status)
|
||||
})
|
||||
|
||||
this.listener.on('notification', (notification: Notification) => {
|
||||
notificationCallback(notification)
|
||||
})
|
||||
|
||||
this.listener.on('delete', (id: string) => {
|
||||
deleteCallback(id)
|
||||
})
|
||||
|
||||
this.listener.on('error', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
|
||||
this.listener.on('parser-error', (err: Error) => {
|
||||
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: string, updateCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.socket('/streaming', stream)
|
||||
this.listener.on('connect', _ => {
|
||||
log.info(`/streaming/?stream=${stream} started`)
|
||||
})
|
||||
|
||||
this.listener.on('update', (status: Status) => {
|
||||
this.listener.on('update', (status: Entity.Status) => {
|
||||
updateCallback(status)
|
||||
})
|
||||
|
||||
|
@ -84,7 +50,7 @@ export default class WebSocket {
|
|||
})
|
||||
}
|
||||
|
||||
stop() {
|
||||
public stop() {
|
||||
if (this.listener) {
|
||||
this.listener.removeAllListeners('connect')
|
||||
this.listener.removeAllListeners('update')
|
||||
|
@ -102,3 +68,79 @@ export default class WebSocket {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class UserStreaming extends WebSocket {
|
||||
public start(updateCallback: Function, notificationCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.userSocket()
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('user streaming is started')
|
||||
})
|
||||
|
||||
this.listener.on('notification', (notification: Entity.Notification) => {
|
||||
notificationCallback(notification)
|
||||
})
|
||||
|
||||
this.bindListener(updateCallback, deleteCallback, errCallback)
|
||||
}
|
||||
}
|
||||
|
||||
export class DirectStreaming extends WebSocket {
|
||||
public start(updateCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.directSocket()
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('direct streaming is started')
|
||||
})
|
||||
|
||||
this.bindListener(updateCallback, deleteCallback, errCallback)
|
||||
}
|
||||
}
|
||||
|
||||
export class LocalStreaming extends WebSocket {
|
||||
public start(updateCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.localSocket()
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('local streaming is started')
|
||||
})
|
||||
|
||||
this.bindListener(updateCallback, deleteCallback, errCallback)
|
||||
}
|
||||
}
|
||||
|
||||
export class PublicStreaming extends WebSocket {
|
||||
public start(updateCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.publicSocket()
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('public streaming is started')
|
||||
})
|
||||
|
||||
this.bindListener(updateCallback, deleteCallback, errCallback)
|
||||
}
|
||||
}
|
||||
|
||||
export class ListStreaming extends WebSocket {
|
||||
public start(listID: string, updateCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.listSocket(listID)
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('list streaming is started')
|
||||
})
|
||||
|
||||
this.bindListener(updateCallback, deleteCallback, errCallback)
|
||||
}
|
||||
}
|
||||
|
||||
export class TagStreaming extends WebSocket {
|
||||
public start(tag: string, updateCallback: Function, deleteCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.tagSocket(tag)
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('tag streaming is started')
|
||||
})
|
||||
|
||||
this.bindListener(updateCallback, deleteCallback, errCallback)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue