diff --git a/src/client/app/common/views/widgets/hashtags.vue b/src/client/app/common/views/widgets/hashtags.vue new file mode 100644 index 0000000000..0ac62af705 --- /dev/null +++ b/src/client/app/common/views/widgets/hashtags.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/client/app/common/views/widgets/index.ts b/src/client/app/common/views/widgets/index.ts index 0190393ba7..7d548ef353 100644 --- a/src/client/app/common/views/widgets/index.ts +++ b/src/client/app/common/views/widgets/index.ts @@ -13,6 +13,7 @@ import wSlideshow from './slideshow.vue'; import wTips from './tips.vue'; import wDonation from './donation.vue'; import wNav from './nav.vue'; +import wHashtags from './hashtags.vue'; Vue.component('mkw-analog-clock', wAnalogClock); Vue.component('mkw-nav', wNav); @@ -27,3 +28,4 @@ Vue.component('mkw-posts-monitor', wPostsMonitor); Vue.component('mkw-memo', wMemo); Vue.component('mkw-rss', wRss); Vue.component('mkw-version', wVersion); +Vue.component('mkw-hashtags', wHashtags); diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue index cac1fd935b..8774aada63 100644 --- a/src/client/app/desktop/views/components/home.vue +++ b/src/client/app/desktop/views/components/home.vue @@ -23,6 +23,7 @@ + diff --git a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue index 2a3a2472dc..a41bf8c3ca 100644 --- a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue +++ b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue @@ -23,6 +23,7 @@ + diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue index ea8580b4d0..294c80e7a0 100644 --- a/src/client/app/mobile/views/pages/widgets.vue +++ b/src/client/app/mobile/views/pages/widgets.vue @@ -15,6 +15,7 @@ + diff --git a/src/index.ts b/src/index.ts index 27c5dd0275..35cf5a243b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,7 +19,6 @@ import MachineInfo from './utils/machineInfo'; import DependencyInfo from './utils/dependencyInfo'; import serverStats from './daemons/server-stats'; import notesStats from './daemons/notes-stats'; -import hashtagsStats from './daemons/hashtags-stats'; import loadConfig from './config/load'; import { Config } from './config/types'; @@ -53,7 +52,6 @@ function main() { ev.mount(); serverStats(); notesStats(); - hashtagsStats(); } else { workerMain(opt); } diff --git a/src/server/api/endpoints.ts b/src/server/api/endpoints.ts index 91e5298e73..5f0a020d6f 100644 --- a/src/server/api/endpoints.ts +++ b/src/server/api/endpoints.ts @@ -628,6 +628,11 @@ const endpoints: Endpoint[] = [ withCredential: true }, + { + name: 'hashtags/trend', + withCredential: true + }, + { name: 'messaging/history', withCredential: true, diff --git a/src/server/api/endpoints/hashtags/trend.ts b/src/server/api/endpoints/hashtags/trend.ts new file mode 100644 index 0000000000..3b95e1fa4c --- /dev/null +++ b/src/server/api/endpoints/hashtags/trend.ts @@ -0,0 +1,78 @@ +import Note from '../../../../models/note'; + +/** + * Get trends of hashtags + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // 10分 + const interval = 1000 * 60 * 10; + + const data = await Note.aggregate([{ + $match: { + createdAt: { + $gt: new Date(Date.now() - interval) + }, + tags: { + $exists: true, + $ne: [] + } + } + }, { + $unwind: '$tags' + }, { + $group: { + _id: '$tags', + count: { + $sum: 1 + } + } + }, { + $group: { + _id: null, + tags: { + $push: { + tag: '$_id', + count: '$count' + } + } + } + }, { + $project: { + _id: false, + tags: true + } + }]) as Array<{ + tags: Array<{ + tag: string; + count: number; + }> + }>; + + const hots = data[0].tags + .sort((a, b) => a.count - b.count) + .map(tag => tag.tag) + .slice(0, 10); + + const countPromises: Array> = []; + + for (let i = 0; i < 10; i++) { + countPromises.push(Promise.all(hots.map(tag => Note.count({ + tags: tag, + createdAt: { + $lt: new Date(Date.now() - (interval * i)), + $gt: new Date(Date.now() - (interval * (i + 1))) + } + })))); + } + + const countsLog = await Promise.all(countPromises); + + const stats = hots.map((tag, i) => ({ + tag, + chart: countsLog.map(counts => counts[i]) + })); + + console.log(stats); + + res(stats); +}); diff --git a/src/server/api/stream/hashtags-stats.ts b/src/server/api/stream/hashtags-stats.ts deleted file mode 100644 index 47183467f5..0000000000 --- a/src/server/api/stream/hashtags-stats.ts +++ /dev/null @@ -1,35 +0,0 @@ -import * as websocket from 'websocket'; -import Xev from 'xev'; - -const ev = new Xev(); - -export default function(request: websocket.request, connection: websocket.connection): void { - const onStats = stats => { - connection.send(JSON.stringify({ - type: 'stats', - body: stats - })); - }; - - connection.on('message', async data => { - const msg = JSON.parse(data.utf8Data); - - switch (msg.type) { - case 'requestLog': - ev.once('hashtagsStatsLog:' + msg.id, statsLog => { - connection.send(JSON.stringify({ - type: 'statsLog', - body: statsLog - })); - }); - ev.emit('requestHashtagsStatsLog', msg.id); - break; - } - }); - - ev.addListener('hashtagsStats', onStats); - - connection.on('close', () => { - ev.removeListener('hashtagsStats', onStats); - }); -} diff --git a/src/server/api/streaming.ts b/src/server/api/streaming.ts index e4156096ef..2d4cfc108f 100644 --- a/src/server/api/streaming.ts +++ b/src/server/api/streaming.ts @@ -14,7 +14,6 @@ import othelloGameStream from './stream/othello-game'; import othelloStream from './stream/othello'; import serverStatsStream from './stream/server-stats'; import notesStatsStream from './stream/notes-stats'; -import hashtagsStatsStream from './stream/hashtags-stats'; import requestsStream from './stream/requests'; import { ParsedUrlQuery } from 'querystring'; import authenticate from './authenticate'; @@ -40,11 +39,6 @@ module.exports = (server: http.Server) => { return; } - if (request.resourceURL.pathname === '/hashtags-stats') { - hashtagsStatsStream(request, connection); - return; - } - if (request.resourceURL.pathname === '/requests') { requestsStream(request, connection); return;