From a28daf7f446c2b2e7e3ded088c45a7d44ebfc9e9 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Wed, 23 Feb 2022 16:17:16 +0900
Subject: [PATCH] feat: add pub & sub item for federation chart

---
 CHANGELOG.md                                  |  1 +
 .../1645599900873-federation-chart-pubsub.js  | 15 +++++++++
 .../chart/charts/entities/federation.ts       |  1 +
 .../src/services/chart/charts/federation.ts   | 14 +++++++-
 packages/client/src/components/chart.vue      | 32 +++++++++++--------
 5 files changed, 49 insertions(+), 14 deletions(-)
 create mode 100644 packages/backend/migration/1645599900873-federation-chart-pubsub.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c78be1b090..0c918ec53d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ You should also include the user name that made the change.
 
 ### Improvements
 - プロフィールの追加情報を最大16まで保存できるように
+- 連合チャートにPub&Subを追加
 
 ### Bugfixes
 - Client: リアクションピッカーの高さが低くなったまま戻らないことがあるのを修正 @syuilo
diff --git a/packages/backend/migration/1645599900873-federation-chart-pubsub.js b/packages/backend/migration/1645599900873-federation-chart-pubsub.js
new file mode 100644
index 0000000000..f695d123ab
--- /dev/null
+++ b/packages/backend/migration/1645599900873-federation-chart-pubsub.js
@@ -0,0 +1,15 @@
+const { MigrationInterface, QueryRunner } = require("typeorm");
+
+module.exports = class federationChartPubsub1645599900873 {
+    name = 'federationChartPubsub1645599900873'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "__chart__federation" ADD "___pubsub" smallint NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__federation" ADD "___pubsub" smallint NOT NULL DEFAULT '0'`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "__chart_day__federation" DROP COLUMN "___pubsub"`);
+        await queryRunner.query(`ALTER TABLE "__chart__federation" DROP COLUMN "___pubsub"`);
+    }
+}
diff --git a/packages/backend/src/services/chart/charts/entities/federation.ts b/packages/backend/src/services/chart/charts/entities/federation.ts
index 6b2089f0b4..3ed5d7352a 100644
--- a/packages/backend/src/services/chart/charts/entities/federation.ts
+++ b/packages/backend/src/services/chart/charts/entities/federation.ts
@@ -8,6 +8,7 @@ export const schema = {
 	'stalled': { uniqueIncrement: true, range: 'small' },
 	'sub': { accumulate: true, range: 'small' },
 	'pub': { accumulate: true, range: 'small' },
+	'pubsub': { accumulate: true, range: 'small' },
 } as const;
 
 export const entity = Chart.schemaToEntity(name, schema);
diff --git a/packages/backend/src/services/chart/charts/federation.ts b/packages/backend/src/services/chart/charts/federation.ts
index 211ba1debc..020f89fe72 100644
--- a/packages/backend/src/services/chart/charts/federation.ts
+++ b/packages/backend/src/services/chart/charts/federation.ts
@@ -20,7 +20,11 @@ export default class FederationChart extends Chart<typeof schema> {
 
 	@autobind
 	protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
-		const [sub, pub] = await Promise.all([
+		const pubsubSubQuery = Followings.createQueryBuilder('f')
+			.select('f.followerHost')
+			.where('f.followerHost IS NOT NULL');
+
+		const [sub, pub, pubsub] = await Promise.all([
 			Followings.createQueryBuilder('following')
 				.select('COUNT(DISTINCT following.followeeHost)')
 				.where('following.followeeHost IS NOT NULL')
@@ -31,11 +35,19 @@ export default class FederationChart extends Chart<typeof schema> {
 				.where('following.followerHost IS NOT NULL')
 				.getRawOne()
 				.then(x => parseInt(x.count, 10)),
+			Followings.createQueryBuilder('following')
+				.select('COUNT(DISTINCT following.followeeHost)')
+				.where('following.followeeHost IS NOT NULL')
+				.andWhere(`following.followerHost IN (${ pubsubSubQuery.getQuery() })`)
+				.setParameters(pubsubSubQuery.getParameters())
+				.getRawOne()
+				.then(x => parseInt(x.count, 10)),
 		]);
 
 		return {
 			'sub': sub,
 			'pub': pub,
+			'pubsub': pubsub,
 		};
 	}
 
diff --git a/packages/client/src/components/chart.vue b/packages/client/src/components/chart.vue
index b90c790c3f..3787c5f066 100644
--- a/packages/client/src/components/chart.vue
+++ b/packages/client/src/components/chart.vue
@@ -70,6 +70,7 @@ const colors = {
 	red: '#FF4560',
 	purple: '#e300db',
 	orange: '#fe6919',
+	lime: '#c7f400',
 };
 const colorSets = [colors.blue, colors.green, colors.yellow, colors.red, colors.purple];
 const getColor = (i) => {
@@ -224,7 +225,7 @@ export default defineComponent({
 								axis: 'y',
 								colors: {
 									0: alpha(x.color ? x.color : getColor(i), 0),
-									[maxes[i]]: alpha(x.color ? x.color : getColor(i), 0.15),
+									[maxes[i]]: alpha(x.color ? x.color : getColor(i), 0.175),
 								},
 							},
 						},
@@ -373,16 +374,6 @@ export default defineComponent({
 			const raw = await os.api('charts/federation', { limit: props.limit, span: props.span });
 			return {
 				series: [{
-					name: 'Sub',
-					type: 'area',
-					data: format(raw.sub),
-					color: colors.orange,
-				}, {
-					name: 'Pub',
-					type: 'area',
-					data: format(raw.pub),
-					color: colors.purple,
-				}, {
 					name: 'Received',
 					type: 'area',
 					data: format(raw.inboxInstances),
@@ -397,6 +388,21 @@ export default defineComponent({
 					type: 'area',
 					data: format(raw.stalled),
 					color: colors.red,
+				}, {
+					name: 'Pub & Sub',
+					type: 'area',
+					data: format(raw.pubsub),
+					color: colors.lime,
+				}, {
+					name: 'Pub',
+					type: 'area',
+					data: format(raw.pub),
+					color: colors.purple,
+				}, {
+					name: 'Sub',
+					type: 'area',
+					data: format(raw.sub),
+					color: colors.orange,
 				}],
 			};
 		};
@@ -529,12 +535,12 @@ export default defineComponent({
 					name: 'Write',
 					type: 'area',
 					data: format(raw.write),
-					color: colors.blue,
+					color: colors.lime,
 				}, {
 					name: 'Read',
 					type: 'area',
 					data: format(raw.read),
-					color: '#888888',
+					color: colors.blue,
 				}, {
 					name: '< Week',
 					type: 'area',