From e01156df085b7785685b0ff30e1b91fc2ad985f9 Mon Sep 17 00:00:00 2001
From: AkiraFukushima
Date: Thu, 8 Aug 2019 23:39:27 +0900
Subject: [PATCH 1/4] refs #985 Add cache db for accounts
---
src/main/cache/account.ts | 37 +++++++++++++++++++++++++++++++++
src/main/index.ts | 22 +++++++++++++++++++-
src/types/cachedAccount.ts | 5 +++++
src/types/insertAccountCache.ts | 4 ++++
4 files changed, 67 insertions(+), 1 deletion(-)
create mode 100644 src/main/cache/account.ts
create mode 100644 src/types/cachedAccount.ts
create mode 100644 src/types/insertAccountCache.ts
diff --git a/src/main/cache/account.ts b/src/main/cache/account.ts
new file mode 100644
index 00000000..01c3eb0f
--- /dev/null
+++ b/src/main/cache/account.ts
@@ -0,0 +1,37 @@
+import { isEmpty } from 'lodash'
+import Datastore from 'nedb'
+import { CachedAccount } from '~/src/types/cachedAccount'
+
+export default class AccountCache {
+ private db: Datastore
+
+ constructor(path: string) {
+ this.db = new Datastore({
+ filename: path,
+ autoload: true
+ })
+ }
+
+ listAccounts(ownerID: string): Promise> {
+ return new Promise((resolve, reject) => {
+ this.db.find({ owner_id: ownerID }, (err, docs) => {
+ if (err) return reject(err)
+ resolve(docs)
+ })
+ })
+ }
+
+ insertAccount(ownerID: string, acct: string): Promise {
+ return new Promise((resolve, reject) => {
+ // At first confirm records for unique.
+ this.db.findOne({ owner_id: ownerID, acct: acct }, (err, doc) => {
+ if (err) return reject(err)
+ if (!isEmpty(doc)) return reject(new Error('Record already exists'))
+ this.db.insert({ owner_id: ownerID, acct: acct }, (err, doc) => {
+ if (err) return reject(err)
+ resolve(doc)
+ })
+ })
+ })
+ }
+}
diff --git a/src/main/index.ts b/src/main/index.ts
index 1ad337f6..f0989cac 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -41,6 +41,8 @@ import { UnreadNotification as UnreadNotificationConfig } from '~/src/types/unre
import { Notify } from '~/src/types/notify'
import { StreamingError } from '~/src/errors/streamingError'
import HashtagCache from './cache/hashtag'
+import AccountCache from './cache/account'
+import { InsertAccountCache } from '~/src/types/insertAccountCache'
/**
* Context menu
@@ -107,6 +109,9 @@ const preferencesDBPath = process.env.NODE_ENV === 'production' ? userData + './
const hashtagCachePath = process.env.NODE_ENV === 'production' ? userData + '/cache/hashtag.db' : 'cache/hashtag.db'
const hashtagCache = new HashtagCache(hashtagCachePath)
+const accountCachePath = process.env.NODE_ENV === 'production' ? userData + '/cache/account.db' : 'cache/account.db'
+const accountCache = new AccountCache(accountCachePath)
+
const soundBasePath =
process.env.NODE_ENV === 'development' ? path.join(__dirname, '../../build/sounds/') : path.join(process.resourcesPath!, 'build/sounds/')
@@ -1005,7 +1010,22 @@ ipcMain.on('insert-cache-hashtags', (event: Event, tags: Array) => {
tags.map(async name => {
await hashtagCache.insertHashtag(name)
})
- event.sender.send('response-insert-cache-hashtag')
+ event.sender.send('response-insert-cache-hashtags')
+})
+
+ipcMain.on('get-cache-accounts', async (event: Event, ownerID: string) => {
+ const accounts = await accountCache.listAccounts(ownerID)
+ event.sender.send('response-get-cache-accounts', accounts)
+})
+
+ipcMain.on('insert-cache-accounts', (event: Event, obj: InsertAccountCache) => {
+ const { ownerID, accts } = obj
+ accts.map(async acct => {
+ await accountCache.insertAccount(ownerID, acct).catch(err => {
+ console.warn(err)
+ })
+ })
+ event.sender.send('response-insert-cache-accounts')
})
// Application control
diff --git a/src/types/cachedAccount.ts b/src/types/cachedAccount.ts
new file mode 100644
index 00000000..7a82b299
--- /dev/null
+++ b/src/types/cachedAccount.ts
@@ -0,0 +1,5 @@
+export type CachedAccount = {
+ _id?: string
+ acct: string
+ owner_id: string
+}
diff --git a/src/types/insertAccountCache.ts b/src/types/insertAccountCache.ts
new file mode 100644
index 00000000..c4d298f6
--- /dev/null
+++ b/src/types/insertAccountCache.ts
@@ -0,0 +1,4 @@
+export type InsertAccountCache = {
+ ownerID: string
+ accts: Array
+}
From 93a7ae5148d71e0d24b1376d7d4c515b9e01bb50 Mon Sep 17 00:00:00 2001
From: AkiraFukushima
Date: Sat, 10 Aug 2019 18:31:50 +0900
Subject: [PATCH 2/4] refs #985 Save account cache when updated
---
src/main/index.ts | 10 ++++++----
.../store/TimelineSpace/Modals/NewToot/Status.ts | 5 +++++
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/main/index.ts b/src/main/index.ts
index f0989cac..977768fb 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -465,7 +465,7 @@ ipcMain.on('start-all-user-streamings', (event: Event, accounts: Array {
+ async (update: Status) => {
if (!event.sender.isDestroyed()) {
event.sender.send(`update-start-all-user-streamings-${id}`, update)
}
@@ -473,6 +473,9 @@ ipcMain.on('start-all-user-streamings', (event: Event, accounts: Array {
await hashtagCache.insertHashtag(tag.name)
})
+ // Cache account
+ // Ignore error for unique constratins.
+ await accountCache.insertAccount(id, update.account.acct).catch(err => console.info(err))
},
(notification: RemoteNotification) => {
const preferences = new Preferences(preferencesDBPath)
@@ -1021,9 +1024,8 @@ ipcMain.on('get-cache-accounts', async (event: Event, ownerID: string) => {
ipcMain.on('insert-cache-accounts', (event: Event, obj: InsertAccountCache) => {
const { ownerID, accts } = obj
accts.map(async acct => {
- await accountCache.insertAccount(ownerID, acct).catch(err => {
- console.warn(err)
- })
+ // Ignore error for unique constratins.
+ await accountCache.insertAccount(ownerID, acct).catch(err => console.info(err))
})
event.sender.send('response-insert-cache-accounts')
})
diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts
index 4f95d4c0..121cfe5c 100644
--- a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts
+++ b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts
@@ -4,6 +4,7 @@ import Mastodon, { Account, Tag, Response, Results } from 'megalodon'
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store/index'
import { LocalTag } from '~/src/types/localTag'
+import { InsertAccountCache } from '~/src/types/insertAccountCache'
type Suggest = {
name: string
@@ -113,6 +114,10 @@ const actions: ActionTree = {
const res: Response = await client.get('/search', { q: word, resolve: false })
commit(MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS, res.data.accounts)
if (res.data.accounts.length === 0) throw new Error('Empty')
+ ipcRenderer.send('insert-cache-accounts', {
+ ownerID: rootState.TimelineSpace.account._id!,
+ accts: res.data.accounts.map(a => a.acct)
+ } as InsertAccountCache)
commit(MUTATION_TYPES.CHANGE_OPEN_SUGGEST, true)
commit(MUTATION_TYPES.CHANGE_START_INDEX, start)
commit(MUTATION_TYPES.CHANGE_MATCH_WORD, word)
From 56c2387b8eb6ecd5e3043d6f51082afe099255ec Mon Sep 17 00:00:00 2001
From: AkiraFukushima
Date: Sat, 10 Aug 2019 22:22:17 +0900
Subject: [PATCH 3/4] refs #985 Search accounts from cache and API
---
.../TimelineSpace/Modals/NewToot/Status.ts | 70 ++++++++++++-------
1 file changed, 46 insertions(+), 24 deletions(-)
diff --git a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts
index 121cfe5c..44b0b574 100644
--- a/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts
+++ b/src/renderer/store/TimelineSpace/Modals/NewToot/Status.ts
@@ -1,10 +1,11 @@
import { ipcRenderer } from 'electron'
import emojilib from 'emojilib'
-import Mastodon, { Account, Tag, Response, Results } from 'megalodon'
+import Mastodon, { Response, Results } from 'megalodon'
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store/index'
import { LocalTag } from '~/src/types/localTag'
import { InsertAccountCache } from '~/src/types/insertAccountCache'
+import { CachedAccount } from '~/src/types/cachedAccount'
type Suggest = {
name: string
@@ -39,7 +40,7 @@ const state = (): StatusState => ({
})
export const MUTATION_TYPES = {
- UPDATE_FILTERED_ACCOUNTS: 'updateFilteredAccounts',
+ APPEND_FILTERED_ACCOUNTS: 'appendFilteredAccounts',
CLEAR_FILTERED_ACCOUNTS: 'clearFilteredAccounts',
APPEND_FILTERED_HASHTAGS: 'appendFilteredHashtags',
CLEAR_FILTERED_HASHTAGS: 'clearFilteredHashtags',
@@ -55,16 +56,17 @@ export const MUTATION_TYPES = {
}
const mutations: MutationTree = {
- [MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS]: (state, accounts: Array) => {
- state.filteredAccounts = accounts.map(a => ({
- name: `@${a.acct}`,
+ [MUTATION_TYPES.APPEND_FILTERED_ACCOUNTS]: (state, accounts: Array) => {
+ const appended = accounts.map(a => ({
+ name: `@${a}`,
image: null
}))
+ state.filteredAccounts = appended.filter((elem, index, self) => self.indexOf(elem) === index)
},
[MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: state => {
state.filteredAccounts = []
},
- [MUTATION_TYPES.APPEND_FILTERED_HASHTAGS]: (state, tags: Array) => {
+ [MUTATION_TYPES.APPEND_FILTERED_HASHTAGS]: (state, tags: Array) => {
const appended = tags.map(t => ({
name: `#${t}`,
image: null
@@ -110,19 +112,39 @@ const actions: ActionTree = {
commit(MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS)
commit(MUTATION_TYPES.FILTERED_SUGGESTION_FROM_ACCOUNTS)
const { word, start } = wordStart
- const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
- const res: Response = await client.get('/search', { q: word, resolve: false })
- commit(MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS, res.data.accounts)
- if (res.data.accounts.length === 0) throw new Error('Empty')
- ipcRenderer.send('insert-cache-accounts', {
- ownerID: rootState.TimelineSpace.account._id!,
- accts: res.data.accounts.map(a => a.acct)
- } as InsertAccountCache)
- commit(MUTATION_TYPES.CHANGE_OPEN_SUGGEST, true)
- commit(MUTATION_TYPES.CHANGE_START_INDEX, start)
- commit(MUTATION_TYPES.CHANGE_MATCH_WORD, word)
- commit(MUTATION_TYPES.FILTERED_SUGGESTION_FROM_ACCOUNTS)
- return res.data.accounts
+ const searchCache = () => {
+ return new Promise(resolve => {
+ const target = word.replace('@', '')
+ ipcRenderer.once('response-get-cache-accounts', (_, accounts: Array) => {
+ console.log(accounts)
+ const matched = accounts.map(account => account.acct).filter(acct => acct.includes(target))
+ if (matched.length === 0) throw new Error('Empty')
+ commit(MUTATION_TYPES.APPEND_FILTERED_ACCOUNTS, matched)
+ commit(MUTATION_TYPES.CHANGE_OPEN_SUGGEST, true)
+ commit(MUTATION_TYPES.CHANGE_START_INDEX, start)
+ commit(MUTATION_TYPES.CHANGE_MATCH_WORD, word)
+ commit(MUTATION_TYPES.FILTERED_SUGGESTION_FROM_ACCOUNTS)
+ resolve(matched)
+ })
+ ipcRenderer.send('get-cache-accounts', rootState.TimelineSpace.account._id)
+ })
+ }
+ const searchAPI = async () => {
+ const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
+ const res: Response = await client.get('/search', { q: word, resolve: false })
+ if (res.data.accounts.length === 0) throw new Error('Empty')
+ commit(MUTATION_TYPES.APPEND_FILTERED_ACCOUNTS, res.data.accounts.map(account => account.acct))
+ ipcRenderer.send('insert-cache-accounts', {
+ ownerID: rootState.TimelineSpace.account._id!,
+ accts: res.data.accounts.map(a => a.acct)
+ } as InsertAccountCache)
+ commit(MUTATION_TYPES.CHANGE_OPEN_SUGGEST, true)
+ commit(MUTATION_TYPES.CHANGE_START_INDEX, start)
+ commit(MUTATION_TYPES.CHANGE_MATCH_WORD, word)
+ commit(MUTATION_TYPES.FILTERED_SUGGESTION_FROM_ACCOUNTS)
+ return res.data.accounts
+ }
+ await Promise.all([searchCache(), searchAPI()])
},
suggestHashtag: async ({ commit, rootState }, wordStart: WordStart) => {
commit(MUTATION_TYPES.CLEAR_FILTERED_HASHTAGS)
@@ -132,14 +154,14 @@ const actions: ActionTree = {
return new Promise(resolve => {
const target = word.replace('#', '')
ipcRenderer.once('response-get-cache-hashtags', (_, tags: Array) => {
- const mached = tags.filter(tag => tag.tagName.includes(target)).map(tag => tag.tagName)
- commit(MUTATION_TYPES.APPEND_FILTERED_HASHTAGS, mached)
- if (mached.length === 0) throw new Error('Empty')
+ const matched = tags.map(tag => tag.tagName).filter(tag => tag.includes(target))
+ if (matched.length === 0) throw new Error('Empty')
+ commit(MUTATION_TYPES.APPEND_FILTERED_HASHTAGS, matched)
commit(MUTATION_TYPES.CHANGE_OPEN_SUGGEST, true)
commit(MUTATION_TYPES.CHANGE_START_INDEX, start)
commit(MUTATION_TYPES.CHANGE_MATCH_WORD, word)
commit(MUTATION_TYPES.FILTERED_SUGGESTION_FROM_HASHTAGS)
- resolve(mached)
+ resolve(matched)
})
ipcRenderer.send('get-cache-hashtags')
})
@@ -148,8 +170,8 @@ const actions: ActionTree = {
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
const res: Response = await client.get('/search', { q: word })
commit(MUTATION_TYPES.APPEND_FILTERED_HASHTAGS, res.data.hashtags)
- ipcRenderer.send('insert-cache-hashtags', res.data.hashtags)
if (res.data.hashtags.length === 0) throw new Error('Empty')
+ ipcRenderer.send('insert-cache-hashtags', res.data.hashtags)
commit(MUTATION_TYPES.CHANGE_OPEN_SUGGEST, true)
commit(MUTATION_TYPES.CHANGE_START_INDEX, start)
commit(MUTATION_TYPES.CHANGE_MATCH_WORD, word)
From 9b459549dc0c3f5f5e315f91c2fd02f3b4707a4d Mon Sep 17 00:00:00 2001
From: AkiraFukushima
Date: Sat, 10 Aug 2019 22:30:30 +0900
Subject: [PATCH 4/4] refs #985 Ignore error for unique constraints in account
cache
---
src/main/cache/account.ts | 9 +++++----
src/main/index.ts | 6 ++----
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/src/main/cache/account.ts b/src/main/cache/account.ts
index 01c3eb0f..b1c5f674 100644
--- a/src/main/cache/account.ts
+++ b/src/main/cache/account.ts
@@ -25,11 +25,12 @@ export default class AccountCache {
return new Promise((resolve, reject) => {
// At first confirm records for unique.
this.db.findOne({ owner_id: ownerID, acct: acct }, (err, doc) => {
- if (err) return reject(err)
- if (!isEmpty(doc)) return reject(new Error('Record already exists'))
- this.db.insert({ owner_id: ownerID, acct: acct }, (err, doc) => {
+ if (err) return err
+ // Ignore error for unique constraints.
+ if (!isEmpty(doc)) return err
+ return this.db.insert({ owner_id: ownerID, acct: acct }, (err, doc) => {
if (err) return reject(err)
- resolve(doc)
+ return resolve(doc)
})
})
})
diff --git a/src/main/index.ts b/src/main/index.ts
index 977768fb..2ae73526 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -474,8 +474,7 @@ ipcMain.on('start-all-user-streamings', (event: Event, accounts: Array console.info(err))
+ await accountCache.insertAccount(id, update.account.acct).catch(err => console.error(err))
},
(notification: RemoteNotification) => {
const preferences = new Preferences(preferencesDBPath)
@@ -1024,8 +1023,7 @@ ipcMain.on('get-cache-accounts', async (event: Event, ownerID: string) => {
ipcMain.on('insert-cache-accounts', (event: Event, obj: InsertAccountCache) => {
const { ownerID, accts } = obj
accts.map(async acct => {
- // Ignore error for unique constratins.
- await accountCache.insertAccount(ownerID, acct).catch(err => console.info(err))
+ await accountCache.insertAccount(ownerID, acct).catch(err => console.error(err))
})
event.sender.send('response-insert-cache-accounts')
})