perf: remove charts (close #10611)
note: - ActiveUsersChart is kept - backend can be further refactored
This commit is contained in:
parent
fd0c8c5789
commit
a4603525aa
95 changed files with 1278 additions and 4510 deletions
|
@ -2,6 +2,21 @@
|
|||
|
||||
Breaking changes are indicated by the :warning: icon.
|
||||
|
||||
## Unreleased
|
||||
|
||||
- :warning: The following endpoints are removed:
|
||||
- `charts/ap-request`
|
||||
- `charts/drive`
|
||||
- `charts/federation`
|
||||
- `charts/hashtag`
|
||||
- `charts/instance`
|
||||
- `charts/notes`
|
||||
- `charts/user/drive`
|
||||
- `charts/user/following`
|
||||
- `charts/user/notes`
|
||||
- `charts/user/reactions`
|
||||
- `charts/users`
|
||||
|
||||
## v20240221
|
||||
|
||||
- Added `admin/set-emoji-moderator` endpoint, where moderators can give these permissions to regular users:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
BEGIN;
|
||||
|
||||
DELETE FROM "migrations" WHERE name IN (
|
||||
'RemoveCharts1709047957489',
|
||||
'DropUserProfileLanguage1708452631156',
|
||||
'EmojiModerator1692825433698',
|
||||
'RemoveNsfwDetection1705848938166',
|
||||
|
@ -8,6 +9,584 @@ DELETE FROM "migrations" WHERE name IN (
|
|||
'RemoveNativeUtilsMigration1705877093218'
|
||||
);
|
||||
|
||||
-- remove-charts
|
||||
CREATE TABLE public.__chart__ap_request (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___deliverFailed" integer DEFAULT 0 NOT NULL,
|
||||
"___deliverSucceeded" integer DEFAULT 0 NOT NULL,
|
||||
"___inboxReceived" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__ap_request_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__ap_request_id_seq OWNED BY public.__chart__ap_request.id;
|
||||
|
||||
CREATE TABLE public.__chart__drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___local_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__drive_id_seq OWNED BY public.__chart__drive.id;
|
||||
|
||||
CREATE TABLE public.__chart__federation (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"unique_temp___deliveredInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___deliveredInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"unique_temp___inboxInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___inboxInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
unique_temp___stalled character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
___stalled smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___sub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pubsub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___subActive" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___pubActive" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__federation_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__federation_id_seq OWNED BY public.__chart__federation.id;
|
||||
|
||||
CREATE TABLE public.__chart__hashtag (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_users integer DEFAULT 0 NOT NULL,
|
||||
___remote_users integer DEFAULT 0 NOT NULL,
|
||||
unique_temp___local_users character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
unique_temp___remote_users character varying[] DEFAULT '{}'::character varying[] NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__hashtag_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__hashtag_id_seq OWNED BY public.__chart__hashtag.id;
|
||||
|
||||
CREATE TABLE public.__chart__instance (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___requests_failed smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_succeeded smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_received smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___users_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___following_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_totalFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___notes_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__instance_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__instance_id_seq OWNED BY public.__chart__instance.id;
|
||||
|
||||
CREATE TABLE public.__chart__network (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___incomingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalTime" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incomingBytes" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingBytes" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__network_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__network_id_seq OWNED BY public.__chart__network.id;
|
||||
|
||||
CREATE TABLE public.__chart__notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_diffs_withFile" integer DEFAULT 0 NOT NULL,
|
||||
"___remote_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__notes_id_seq OWNED BY public.__chart__notes.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
"___totalCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___decCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_drive_id_seq OWNED BY public.__chart__per_user_drive.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_following (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_following_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_following_id_seq OWNED BY public.__chart__per_user_following.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_normal smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_reply smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_renote smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___diffs_withFile" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_notes_id_seq OWNED BY public.__chart__per_user_notes.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_reaction (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_count smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_count smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_reaction_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_reaction_id_seq OWNED BY public.__chart__per_user_reaction.id;
|
||||
|
||||
CREATE TABLE public.__chart__test (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128),
|
||||
___foo_total bigint NOT NULL,
|
||||
___foo_inc bigint NOT NULL,
|
||||
___foo_dec bigint NOT NULL
|
||||
);
|
||||
CREATE TABLE public.__chart__test_grouped (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128),
|
||||
___foo_total bigint NOT NULL,
|
||||
___foo_inc bigint NOT NULL,
|
||||
___foo_dec bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__test_grouped_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__test_grouped_id_seq OWNED BY public.__chart__test_grouped.id;
|
||||
|
||||
CREATE SEQUENCE public.__chart__test_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__test_id_seq OWNED BY public.__chart__test.id;
|
||||
|
||||
CREATE TABLE public.__chart__test_unique (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128),
|
||||
___foo character varying[] DEFAULT '{}'::character varying[] NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__test_unique_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__test_unique_id_seq OWNED BY public.__chart__test_unique.id;
|
||||
|
||||
CREATE TABLE public.__chart__users (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__users_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__users_id_seq OWNED BY public.__chart__users.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__ap_request (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___deliverFailed" integer DEFAULT 0 NOT NULL,
|
||||
"___deliverSucceeded" integer DEFAULT 0 NOT NULL,
|
||||
"___inboxReceived" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__ap_request_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__ap_request_id_seq OWNED BY public.__chart_day__ap_request.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___local_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__drive_id_seq OWNED BY public.__chart_day__drive.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__federation (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"unique_temp___deliveredInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___deliveredInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"unique_temp___inboxInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___inboxInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
unique_temp___stalled character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
___stalled smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___sub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pubsub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___subActive" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___pubActive" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__federation_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__federation_id_seq OWNED BY public.__chart_day__federation.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__hashtag (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_users integer DEFAULT 0 NOT NULL,
|
||||
___remote_users integer DEFAULT 0 NOT NULL,
|
||||
unique_temp___local_users character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
unique_temp___remote_users character varying[] DEFAULT '{}'::character varying[] NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__hashtag_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__hashtag_id_seq OWNED BY public.__chart_day__hashtag.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__instance (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___requests_failed smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_succeeded smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_received smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___users_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___following_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_totalFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___notes_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__instance_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__instance_id_seq OWNED BY public.__chart_day__instance.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__network (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___incomingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalTime" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incomingBytes" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingBytes" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__network_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__network_id_seq OWNED BY public.__chart_day__network.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_diffs_withFile" integer DEFAULT 0 NOT NULL,
|
||||
"___remote_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__notes_id_seq OWNED BY public.__chart_day__notes.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
"___totalCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___decCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_drive_id_seq OWNED BY public.__chart_day__per_user_drive.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_following (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_following_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_following_id_seq OWNED BY public.__chart_day__per_user_following.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_normal smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_reply smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_renote smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___diffs_withFile" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_notes_id_seq OWNED BY public.__chart_day__per_user_notes.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_reaction (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_count smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_count smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_reaction_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_reaction_id_seq OWNED BY public.__chart_day__per_user_reaction.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__users (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__users_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__users_id_seq OWNED BY public.__chart_day__users.id;
|
||||
|
||||
-- drop-user-profile-language
|
||||
ALTER TABLE "user_profile" ADD COLUMN "lang" character varying(32);
|
||||
|
||||
|
|
618
packages/backend/migration/1709047957489-remove-charts.js
Normal file
618
packages/backend/migration/1709047957489-remove-charts.js
Normal file
|
@ -0,0 +1,618 @@
|
|||
export class RemoveCharts1709047957489 {
|
||||
name = "RemoveCharts1709047957489";
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`DROP TABLE "__chart__ap_request" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__ap_request" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__drive" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__federation" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__hashtag" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__instance" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__network" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__notes" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__per_user_drive" CASCADE`);
|
||||
await queryRunner.query(
|
||||
`DROP TABLE "__chart_day__per_user_following" CASCADE`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__per_user_notes" CASCADE`);
|
||||
await queryRunner.query(
|
||||
`DROP TABLE "__chart_day__per_user_reaction" CASCADE`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "__chart_day__users" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__drive" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__federation" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__hashtag" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__instance" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__network" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__notes" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_drive" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_following" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_notes" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_reaction" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__test" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__test_unique" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__test_grouped" CASCADE`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__users" CASCADE`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE public.__chart__ap_request (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___deliverFailed" integer DEFAULT 0 NOT NULL,
|
||||
"___deliverSucceeded" integer DEFAULT 0 NOT NULL,
|
||||
"___inboxReceived" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__ap_request_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__ap_request_id_seq OWNED BY public.__chart__ap_request.id;
|
||||
|
||||
CREATE TABLE public.__chart__drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___local_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__drive_id_seq OWNED BY public.__chart__drive.id;
|
||||
|
||||
CREATE TABLE public.__chart__federation (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"unique_temp___deliveredInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___deliveredInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"unique_temp___inboxInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___inboxInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
unique_temp___stalled character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
___stalled smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___sub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pubsub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___subActive" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___pubActive" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__federation_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__federation_id_seq OWNED BY public.__chart__federation.id;
|
||||
|
||||
CREATE TABLE public.__chart__hashtag (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_users integer DEFAULT 0 NOT NULL,
|
||||
___remote_users integer DEFAULT 0 NOT NULL,
|
||||
unique_temp___local_users character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
unique_temp___remote_users character varying[] DEFAULT '{}'::character varying[] NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__hashtag_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__hashtag_id_seq OWNED BY public.__chart__hashtag.id;
|
||||
|
||||
CREATE TABLE public.__chart__instance (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___requests_failed smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_succeeded smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_received smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___users_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___following_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_totalFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___notes_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__instance_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__instance_id_seq OWNED BY public.__chart__instance.id;
|
||||
|
||||
CREATE TABLE public.__chart__network (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___incomingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalTime" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incomingBytes" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingBytes" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__network_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__network_id_seq OWNED BY public.__chart__network.id;
|
||||
|
||||
CREATE TABLE public.__chart__notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_diffs_withFile" integer DEFAULT 0 NOT NULL,
|
||||
"___remote_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__notes_id_seq OWNED BY public.__chart__notes.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
"___totalCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___decCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_drive_id_seq OWNED BY public.__chart__per_user_drive.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_following (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_following_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_following_id_seq OWNED BY public.__chart__per_user_following.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_normal smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_reply smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_renote smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___diffs_withFile" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_notes_id_seq OWNED BY public.__chart__per_user_notes.id;
|
||||
|
||||
CREATE TABLE public.__chart__per_user_reaction (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_count smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_count smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__per_user_reaction_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__per_user_reaction_id_seq OWNED BY public.__chart__per_user_reaction.id;
|
||||
|
||||
CREATE TABLE public.__chart__test (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128),
|
||||
___foo_total bigint NOT NULL,
|
||||
___foo_inc bigint NOT NULL,
|
||||
___foo_dec bigint NOT NULL
|
||||
);
|
||||
CREATE TABLE public.__chart__test_grouped (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128),
|
||||
___foo_total bigint NOT NULL,
|
||||
___foo_inc bigint NOT NULL,
|
||||
___foo_dec bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__test_grouped_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__test_grouped_id_seq OWNED BY public.__chart__test_grouped.id;
|
||||
|
||||
CREATE SEQUENCE public.__chart__test_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__test_id_seq OWNED BY public.__chart__test.id;
|
||||
|
||||
CREATE TABLE public.__chart__test_unique (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128),
|
||||
___foo character varying[] DEFAULT '{}'::character varying[] NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__test_unique_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__test_unique_id_seq OWNED BY public.__chart__test_unique.id;
|
||||
|
||||
CREATE TABLE public.__chart__users (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart__users_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart__users_id_seq OWNED BY public.__chart__users.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__ap_request (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___deliverFailed" integer DEFAULT 0 NOT NULL,
|
||||
"___deliverSucceeded" integer DEFAULT 0 NOT NULL,
|
||||
"___inboxReceived" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__ap_request_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__ap_request_id_seq OWNED BY public.__chart_day__ap_request.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___local_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_decSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___remote_decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__drive_id_seq OWNED BY public.__chart_day__drive.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__federation (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"unique_temp___deliveredInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___deliveredInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"unique_temp___inboxInstances" character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
"___inboxInstances" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
unique_temp___stalled character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
___stalled smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___sub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
___pubsub smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___subActive" smallint DEFAULT '0'::smallint NOT NULL,
|
||||
"___pubActive" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__federation_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__federation_id_seq OWNED BY public.__chart_day__federation.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__hashtag (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_users integer DEFAULT 0 NOT NULL,
|
||||
___remote_users integer DEFAULT 0 NOT NULL,
|
||||
unique_temp___local_users character varying[] DEFAULT '{}'::character varying[] NOT NULL,
|
||||
unique_temp___remote_users character varying[] DEFAULT '{}'::character varying[] NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__hashtag_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__hashtag_id_seq OWNED BY public.__chart_day__hashtag.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__instance (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___requests_failed smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_succeeded smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___requests_received smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___notes_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___users_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___users_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___following_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___following_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_totalFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_incUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decFiles" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___drive_decUsage" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___notes_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__instance_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__instance_id_seq OWNED BY public.__chart_day__instance.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__network (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"___incomingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingRequests" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalTime" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incomingBytes" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___outgoingBytes" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__network_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__network_id_seq OWNED BY public.__chart_day__network.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_normal integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_reply integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_diffs_renote integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___local_diffs_withFile" integer DEFAULT 0 NOT NULL,
|
||||
"___remote_diffs_withFile" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__notes_id_seq OWNED BY public.__chart_day__notes.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_drive (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
"___totalCount" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___totalSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___incCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___incSize" integer DEFAULT '0'::bigint NOT NULL,
|
||||
"___decCount" smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___decSize" integer DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_drive_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_drive_id_seq OWNED BY public.__chart_day__per_user_drive.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_following (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_followers_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followings_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_followers_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_following_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_following_id_seq OWNED BY public.__chart_day__per_user_following.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_notes (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_normal smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_reply smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___diffs_renote smallint DEFAULT '0'::bigint NOT NULL,
|
||||
"___diffs_withFile" smallint DEFAULT '0'::smallint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_notes_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_notes_id_seq OWNED BY public.__chart_day__per_user_notes.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__per_user_reaction (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
"group" character varying(128) NOT NULL,
|
||||
___local_count smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_count smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__per_user_reaction_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__per_user_reaction_id_seq OWNED BY public.__chart_day__per_user_reaction.id;
|
||||
|
||||
CREATE TABLE public.__chart_day__users (
|
||||
id integer NOT NULL,
|
||||
date integer NOT NULL,
|
||||
___local_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___local_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___local_dec smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_total integer DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_inc smallint DEFAULT '0'::bigint NOT NULL,
|
||||
___remote_dec smallint DEFAULT '0'::bigint NOT NULL
|
||||
);
|
||||
CREATE SEQUENCE public.__chart_day__users_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE public.__chart_day__users_id_seq OWNED BY public.__chart_day__users.id;
|
||||
`);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import { inspect } from "node:util";
|
|||
* @callback BeforeShutdownListener
|
||||
* @param {string} [signalOrEvent] The exit signal or event name received on the process.
|
||||
*/
|
||||
type BeforeShutdownListener = (signalOrEvent: string) => PromiseLike<void>;
|
||||
|
||||
/**
|
||||
* System signals the app will listen to initiate shutdown.
|
||||
|
@ -23,7 +24,7 @@ const SHUTDOWN_TIMEOUT = 15000;
|
|||
* down the process.
|
||||
* @type {BeforeShutdownListener[]}
|
||||
*/
|
||||
const shutdownListeners: ((signalOrEvent: string) => void)[] = [];
|
||||
const shutdownListeners: BeforeShutdownListener[] = [];
|
||||
|
||||
/**
|
||||
* Listen for signals and execute given `fn` function once.
|
||||
|
@ -86,7 +87,9 @@ async function shutdownHandler(signalOrEvent: string) {
|
|||
* @param {BeforeShutdownListener} listener The shutdown listener to register.
|
||||
* @returns {BeforeShutdownListener} Echoes back the supplied `listener`.
|
||||
*/
|
||||
export function beforeShutdown(listener: () => void) {
|
||||
export function beforeShutdown(
|
||||
listener: BeforeShutdownListener,
|
||||
): BeforeShutdownListener {
|
||||
shutdownListeners.push(listener);
|
||||
return listener;
|
||||
}
|
||||
|
|
|
@ -486,7 +486,9 @@ export const UserRepository = db.getRepository(User).extend({
|
|||
url: profile!.url,
|
||||
uri: user.uri,
|
||||
movedToUri: user.movedToUri
|
||||
? await this.userFromURI(user.movedToUri).catch(() => user.movedToUri)
|
||||
? await this.userFromURI(user.movedToUri).catch(
|
||||
() => user.movedToUri,
|
||||
)
|
||||
: null,
|
||||
alsoKnownAs: user.alsoKnownAs,
|
||||
createdAt: user.createdAt.toISOString(),
|
||||
|
|
|
@ -528,24 +528,6 @@ export default function () {
|
|||
processObjectStorage(objectStorageQueue);
|
||||
processBackground(backgroundQueue);
|
||||
|
||||
systemQueue.add(
|
||||
"tickCharts",
|
||||
{},
|
||||
{
|
||||
repeat: { cron: "55 * * * *" },
|
||||
removeOnComplete: true,
|
||||
},
|
||||
);
|
||||
|
||||
systemQueue.add(
|
||||
"resyncCharts",
|
||||
{},
|
||||
{
|
||||
repeat: { cron: "0 0 * * *" },
|
||||
removeOnComplete: true,
|
||||
},
|
||||
);
|
||||
|
||||
systemQueue.add(
|
||||
"cleanCharts",
|
||||
{},
|
||||
|
|
|
@ -3,11 +3,6 @@ import request from "@/remote/activitypub/request.js";
|
|||
import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js";
|
||||
import Logger from "@/services/logger.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import {
|
||||
apRequestChart,
|
||||
federationChart,
|
||||
instanceChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { StatusError } from "@/misc/fetch.js";
|
||||
|
@ -42,10 +37,6 @@ export default async (job: Bull.Job<DeliverJobData>) => {
|
|||
});
|
||||
|
||||
fetchInstanceMetadata(i);
|
||||
|
||||
instanceChart.requestSent(i.host, true);
|
||||
apRequestChart.deliverSucc();
|
||||
federationChart.deliverd(i.host, true);
|
||||
});
|
||||
|
||||
return "Success";
|
||||
|
@ -57,10 +48,6 @@ export default async (job: Bull.Job<DeliverJobData>) => {
|
|||
latestStatus: res instanceof StatusError ? res.statusCode : null,
|
||||
isNotResponding: true,
|
||||
});
|
||||
|
||||
instanceChart.requestSent(i.host, false);
|
||||
apRequestChart.deliverFail();
|
||||
federationChart.deliverd(i.host, false);
|
||||
});
|
||||
|
||||
if (res instanceof StatusError) {
|
||||
|
|
|
@ -5,11 +5,6 @@ import perform from "@/remote/activitypub/perform.js";
|
|||
import Logger from "@/services/logger.js";
|
||||
import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import {
|
||||
apRequestChart,
|
||||
federationChart,
|
||||
instanceChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { toPuny, extractDbHost } from "@/misc/convert-host.js";
|
||||
import { getApId } from "@/remote/activitypub/type.js";
|
||||
|
@ -189,10 +184,6 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
|||
});
|
||||
|
||||
fetchInstanceMetadata(i);
|
||||
|
||||
instanceChart.requestReceived(i.host);
|
||||
apRequestChart.inbox();
|
||||
federationChart.inbox(i.host);
|
||||
});
|
||||
|
||||
// アクティビティを処理
|
||||
|
|
|
@ -1,20 +1,7 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import {
|
||||
activeUsersChart,
|
||||
driveChart,
|
||||
federationChart,
|
||||
hashtagChart,
|
||||
instanceChart,
|
||||
notesChart,
|
||||
perUserDriveChart,
|
||||
perUserFollowingChart,
|
||||
perUserNotesChart,
|
||||
perUserReactionsChart,
|
||||
usersChart,
|
||||
apRequestChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { activeUsersChart } from "@/services/chart/index.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("clean-charts");
|
||||
|
||||
|
@ -22,23 +9,8 @@ export async function cleanCharts(
|
|||
job: Bull.Job<Record<string, unknown>>,
|
||||
done: any,
|
||||
): Promise<void> {
|
||||
logger.info("Clean charts...");
|
||||
|
||||
await Promise.all([
|
||||
federationChart.clean(),
|
||||
notesChart.clean(),
|
||||
usersChart.clean(),
|
||||
activeUsersChart.clean(),
|
||||
instanceChart.clean(),
|
||||
perUserNotesChart.clean(),
|
||||
driveChart.clean(),
|
||||
perUserReactionsChart.clean(),
|
||||
hashtagChart.clean(),
|
||||
perUserFollowingChart.clean(),
|
||||
perUserDriveChart.clean(),
|
||||
apRequestChart.clean(),
|
||||
]);
|
||||
|
||||
logger.succ("All charts successfully cleaned.");
|
||||
logger.info("Cleaning active users chart...");
|
||||
await activeUsersChart.clean();
|
||||
logger.succ("Active users chart has been cleaned.");
|
||||
done();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import type Bull from "bull";
|
||||
import { tickCharts } from "./tick-charts.js";
|
||||
import { resyncCharts } from "./resync-charts.js";
|
||||
import { cleanCharts } from "./clean-charts.js";
|
||||
import { checkExpiredMutings } from "./check-expired-mutings.js";
|
||||
import { clean } from "./clean.js";
|
||||
|
@ -8,8 +6,6 @@ import { setLocalEmojiSizes } from "./local-emoji-size.js";
|
|||
import { verifyLinks } from "./verify-links.js";
|
||||
|
||||
const jobs = {
|
||||
tickCharts,
|
||||
resyncCharts,
|
||||
cleanCharts,
|
||||
checkExpiredMutings,
|
||||
clean,
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { driveChart, notesChart, usersChart } from "@/services/chart/index.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("resync-charts");
|
||||
|
||||
export async function resyncCharts(
|
||||
job: Bull.Job<Record<string, unknown>>,
|
||||
done: any,
|
||||
): Promise<void> {
|
||||
logger.info("Resync charts...");
|
||||
|
||||
// TODO: ユーザーごとのチャートも更新する
|
||||
// TODO: インスタンスごとのチャートも更新する
|
||||
await Promise.all([
|
||||
driveChart.resync(),
|
||||
notesChart.resync(),
|
||||
usersChart.resync(),
|
||||
]);
|
||||
|
||||
logger.succ("All charts successfully resynced.");
|
||||
done();
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import {
|
||||
activeUsersChart,
|
||||
driveChart,
|
||||
federationChart,
|
||||
hashtagChart,
|
||||
instanceChart,
|
||||
notesChart,
|
||||
perUserDriveChart,
|
||||
perUserFollowingChart,
|
||||
perUserNotesChart,
|
||||
perUserReactionsChart,
|
||||
usersChart,
|
||||
apRequestChart,
|
||||
} from "@/services/chart/index.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("tick-charts");
|
||||
|
||||
export async function tickCharts(
|
||||
job: Bull.Job<Record<string, unknown>>,
|
||||
done: any,
|
||||
): Promise<void> {
|
||||
logger.info("Tick charts...");
|
||||
|
||||
await Promise.all([
|
||||
federationChart.tick(false),
|
||||
notesChart.tick(false),
|
||||
usersChart.tick(false),
|
||||
activeUsersChart.tick(false),
|
||||
instanceChart.tick(false),
|
||||
perUserNotesChart.tick(false),
|
||||
driveChart.tick(false),
|
||||
perUserReactionsChart.tick(false),
|
||||
hashtagChart.tick(false),
|
||||
perUserFollowingChart.tick(false),
|
||||
perUserDriveChart.tick(false),
|
||||
apRequestChart.tick(false),
|
||||
]);
|
||||
|
||||
logger.succ("All charts successfully ticked.");
|
||||
done();
|
||||
}
|
|
@ -17,7 +17,6 @@ import { User } from "@/models/entities/user.js";
|
|||
import type { Emoji } from "@/models/entities/emoji.js";
|
||||
import { UserNotePining } from "@/models/entities/user-note-pining.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { instanceChart, usersChart } from "@/services/chart/index.js";
|
||||
import { UserPublickey } from "@/models/entities/user-publickey.js";
|
||||
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
|
@ -358,12 +357,9 @@ export async function createPerson(
|
|||
// Register host
|
||||
registerOrFetchInstanceDoc(host).then((i) => {
|
||||
Instances.increment({ id: i.id }, "usersCount", 1);
|
||||
instanceChart.newUser(i.host);
|
||||
fetchInstanceMetadata(i);
|
||||
});
|
||||
|
||||
usersChart.update(user!, true);
|
||||
|
||||
// Hashtag update
|
||||
updateUsertags(user!, tags);
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import { IsNull } from "typeorm";
|
|||
import { genId } from "@/misc/gen-id.js";
|
||||
import { toPunyNullable } from "@/misc/convert-host.js";
|
||||
import { UserKeypair } from "@/models/entities/user-keypair.js";
|
||||
import { usersChart } from "@/services/chart/index.js";
|
||||
import { UsedUsername } from "@/models/entities/used-username.js";
|
||||
import { db } from "@/db/postgre.js";
|
||||
import config from "@/config/index.js";
|
||||
|
@ -135,7 +134,5 @@ export async function signup(opts: {
|
|||
);
|
||||
});
|
||||
|
||||
usersChart.update(account, true);
|
||||
|
||||
return { account, secret };
|
||||
}
|
||||
|
|
|
@ -99,17 +99,6 @@ import * as ep___channels_timeline from "./endpoints/channels/timeline.js";
|
|||
import * as ep___channels_unfollow from "./endpoints/channels/unfollow.js";
|
||||
import * as ep___channels_update from "./endpoints/channels/update.js";
|
||||
import * as ep___charts_activeUsers from "./endpoints/charts/active-users.js";
|
||||
import * as ep___charts_apRequest from "./endpoints/charts/ap-request.js";
|
||||
import * as ep___charts_drive from "./endpoints/charts/drive.js";
|
||||
import * as ep___charts_federation from "./endpoints/charts/federation.js";
|
||||
import * as ep___charts_hashtag from "./endpoints/charts/hashtag.js";
|
||||
import * as ep___charts_instance from "./endpoints/charts/instance.js";
|
||||
import * as ep___charts_notes from "./endpoints/charts/notes.js";
|
||||
import * as ep___charts_user_drive from "./endpoints/charts/user/drive.js";
|
||||
import * as ep___charts_user_following from "./endpoints/charts/user/following.js";
|
||||
import * as ep___charts_user_notes from "./endpoints/charts/user/notes.js";
|
||||
import * as ep___charts_user_reactions from "./endpoints/charts/user/reactions.js";
|
||||
import * as ep___charts_users from "./endpoints/charts/users.js";
|
||||
import * as ep___clips_addNote from "./endpoints/clips/add-note.js";
|
||||
import * as ep___clips_removeNote from "./endpoints/clips/remove-note.js";
|
||||
import * as ep___clips_create from "./endpoints/clips/create.js";
|
||||
|
@ -457,17 +446,6 @@ const eps = [
|
|||
["channels/unfollow", ep___channels_unfollow],
|
||||
["channels/update", ep___channels_update],
|
||||
["charts/active-users", ep___charts_activeUsers],
|
||||
["charts/ap-request", ep___charts_apRequest],
|
||||
["charts/drive", ep___charts_drive],
|
||||
["charts/federation", ep___charts_federation],
|
||||
["charts/hashtag", ep___charts_hashtag],
|
||||
["charts/instance", ep___charts_instance],
|
||||
["charts/notes", ep___charts_notes],
|
||||
["charts/user/drive", ep___charts_user_drive],
|
||||
["charts/user/following", ep___charts_user_following],
|
||||
["charts/user/notes", ep___charts_user_notes],
|
||||
["charts/user/reactions", ep___charts_user_reactions],
|
||||
["charts/users", ep___charts_users],
|
||||
["clips/add-note", ep___clips_addNote],
|
||||
["clips/remove-note", ep___clips_removeNote],
|
||||
["clips/create", ep___clips_create],
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { apRequestChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(apRequestChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
},
|
||||
required: ["span"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await apRequestChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
);
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { driveChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "drive"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(driveChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
},
|
||||
required: ["span"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await driveChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
);
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { federationChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(federationChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
},
|
||||
required: ["span"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await federationChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
);
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { hashtagChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "hashtags"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(hashtagChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
tag: { type: "string" },
|
||||
},
|
||||
required: ["span", "tag"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await hashtagChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
ps.tag,
|
||||
);
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { instanceChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(instanceChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
host: { type: "string" },
|
||||
},
|
||||
required: ["span", "host"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await instanceChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
ps.host,
|
||||
);
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { notesChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "notes"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(notesChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
},
|
||||
required: ["span"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await notesChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
);
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { perUserDriveChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "drive", "users"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserDriveChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
userId: { type: "string", format: "misskey:id" },
|
||||
},
|
||||
required: ["span", "userId"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await perUserDriveChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
ps.userId,
|
||||
);
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { perUserFollowingChart } from "@/services/chart/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "users", "following"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserFollowingChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
userId: { type: "string", format: "misskey:id" },
|
||||
},
|
||||
required: ["span", "userId"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await perUserFollowingChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
ps.userId,
|
||||
);
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { perUserNotesChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "users", "notes"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserNotesChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
userId: { type: "string", format: "misskey:id" },
|
||||
},
|
||||
required: ["span", "userId"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await perUserNotesChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
ps.userId,
|
||||
);
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { perUserReactionsChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "users", "reactions"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserReactionsChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
userId: { type: "string", format: "misskey:id" },
|
||||
},
|
||||
required: ["span", "userId"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await perUserReactionsChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
ps.userId,
|
||||
);
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
import { getJsonSchema } from "@/services/chart/core.js";
|
||||
import { usersChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["charts", "users"],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(usersChart.schema),
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
span: { type: "string", enum: ["day", "hour"] },
|
||||
limit: { type: "integer", minimum: 1, maximum: 500, default: 30 },
|
||||
offset: { type: "integer", nullable: true, default: null },
|
||||
},
|
||||
required: ["span"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
return await usersChart.getChart(
|
||||
ps.span,
|
||||
ps.limit,
|
||||
ps.offset ? new Date(ps.offset) : null,
|
||||
);
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import { Instances, NoteReactions, Notes, Users } from "@/models/index.js";
|
||||
import { Instances, Users, Notes } from "@/models/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { driveChart, notesChart, usersChart } from "@/services/chart/index.js";
|
||||
import { IsNull } from "typeorm";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: false,
|
||||
|
@ -8,6 +8,8 @@ export const meta = {
|
|||
|
||||
tags: ["meta"],
|
||||
|
||||
cacheSec: 600,
|
||||
|
||||
res: {
|
||||
type: "object",
|
||||
optional: false,
|
||||
|
@ -38,16 +40,6 @@ export const meta = {
|
|||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
driveUsageLocal: {
|
||||
type: "number",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
driveUsageRemote: {
|
||||
type: "number",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
@ -59,28 +51,31 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async () => {
|
||||
const notesChartData = await notesChart.getChart("hour", 1, null);
|
||||
const notesCount =
|
||||
notesChartData.local.total[0] + notesChartData.remote.total[0];
|
||||
const originalNotesCount = notesChartData.local.total[0];
|
||||
|
||||
const usersChartData = await usersChart.getChart("hour", 1, null);
|
||||
const usersCount =
|
||||
usersChartData.local.total[0] + usersChartData.remote.total[0];
|
||||
const originalUsersCount = usersChartData.local.total[0];
|
||||
const driveChartData = await driveChart.getChart("hour", 1, null);
|
||||
//TODO: fixme currently returns 0
|
||||
const driveUsageLocal = driveChartData.local.incSize[0];
|
||||
const driveUsageRemote = driveChartData.remote.incSize[0];
|
||||
|
||||
const [
|
||||
reactionsCount,
|
||||
//originalReactionsCount,
|
||||
notesCount,
|
||||
originalNotesCount,
|
||||
usersCount,
|
||||
originalUsersCount,
|
||||
instances,
|
||||
] = await Promise.all([
|
||||
NoteReactions.count({ cache: 3600000 }), // 1 hour
|
||||
//NoteReactions.count({ where: { userHost: IsNull() }, cache: 3600000 }),
|
||||
Instances.count({ cache: 3600000 }),
|
||||
// notesCount
|
||||
Notes.count(),
|
||||
// originalNotesCount
|
||||
Notes.count({
|
||||
where: {
|
||||
userHost: IsNull(),
|
||||
},
|
||||
}),
|
||||
// usersCount
|
||||
Users.count(),
|
||||
// originalUsersCount
|
||||
Users.count({
|
||||
where: {
|
||||
host: IsNull(),
|
||||
},
|
||||
}),
|
||||
// instances
|
||||
Instances.count(),
|
||||
]);
|
||||
|
||||
return {
|
||||
|
@ -88,10 +83,6 @@ export default define(meta, paramDef, async () => {
|
|||
originalNotesCount,
|
||||
usersCount,
|
||||
originalUsersCount,
|
||||
reactionsCount,
|
||||
//originalReactionsCount,
|
||||
instances,
|
||||
driveUsageLocal,
|
||||
driveUsageRemote,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
UserListJoinings,
|
||||
UserLists,
|
||||
} from "@/models/index.js";
|
||||
import { perUserFollowingChart } from "@/services/chart/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { getActiveWebhooks } from "@/misc/webhook-cache.js";
|
||||
import { webhookDeliver } from "@/queue/index.js";
|
||||
|
@ -119,7 +118,6 @@ async function unFollow(follower: User, followee: User) {
|
|||
Followings.delete(following.id),
|
||||
Users.decrement({ id: follower.id }, "followingCount", 1),
|
||||
Users.decrement({ id: followee.id }, "followersCount", 1),
|
||||
perUserFollowingChart.update(follower, followee, false),
|
||||
]);
|
||||
|
||||
// Publish unfollow event
|
||||
|
|
|
@ -16,14 +16,6 @@ export default class ActiveUsersChart extends Chart<typeof schema> {
|
|||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public read(user: {
|
||||
id: User["id"];
|
||||
host: null;
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { name, schema } from "./entities/ap-request.js";
|
||||
|
||||
/**
|
||||
* Chart about ActivityPub requests
|
||||
*/
|
||||
|
||||
export default class ApRequestChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async deliverSucc(): Promise<void> {
|
||||
await this.commit({
|
||||
deliverSucceeded: 1,
|
||||
});
|
||||
}
|
||||
|
||||
public async deliverFail(): Promise<void> {
|
||||
await this.commit({
|
||||
deliverFailed: 1,
|
||||
});
|
||||
}
|
||||
|
||||
public async inbox(): Promise<void> {
|
||||
await this.commit({
|
||||
inboxReceived: 1,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { name, schema } from "./entities/drive.js";
|
||||
|
||||
/**
|
||||
* ドライブに関するチャート
|
||||
*/
|
||||
|
||||
export default class DriveChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(file: DriveFile, isAdditional: boolean): Promise<void> {
|
||||
const fileSizeKb = file.size / 1000;
|
||||
await this.commit(
|
||||
file.userHost === null
|
||||
? {
|
||||
"local.incCount": isAdditional ? 1 : 0,
|
||||
"local.incSize": isAdditional ? fileSizeKb : 0,
|
||||
"local.decCount": isAdditional ? 0 : 1,
|
||||
"local.decSize": isAdditional ? 0 : fileSizeKb,
|
||||
}
|
||||
: {
|
||||
"remote.incCount": isAdditional ? 1 : 0,
|
||||
"remote.incSize": isAdditional ? fileSizeKb : 0,
|
||||
"remote.decCount": isAdditional ? 0 : 1,
|
||||
"remote.decSize": isAdditional ? 0 : fileSizeKb,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "apRequest";
|
||||
|
||||
export const schema = {
|
||||
deliverFailed: {},
|
||||
deliverSucceeded: {},
|
||||
inboxReceived: {},
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,16 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "drive";
|
||||
|
||||
export const schema = {
|
||||
"local.incCount": {},
|
||||
"local.incSize": {}, // in kilobyte
|
||||
"local.decCount": {},
|
||||
"local.decSize": {}, // in kilobyte
|
||||
"remote.incCount": {},
|
||||
"remote.incSize": {}, // in kilobyte
|
||||
"remote.decCount": {},
|
||||
"remote.decSize": {}, // in kilobyte
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,16 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "federation";
|
||||
|
||||
export const schema = {
|
||||
deliveredInstances: { uniqueIncrement: true, range: "small" },
|
||||
inboxInstances: { uniqueIncrement: true, range: "small" },
|
||||
stalled: { uniqueIncrement: true, range: "small" },
|
||||
sub: { accumulate: true, range: "small" },
|
||||
pub: { accumulate: true, range: "small" },
|
||||
pubsub: { accumulate: true, range: "small" },
|
||||
subActive: { accumulate: true, range: "small" },
|
||||
pubActive: { accumulate: true, range: "small" },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,10 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "hashtag";
|
||||
|
||||
export const schema = {
|
||||
"local.users": { uniqueIncrement: true },
|
||||
"remote.users": { uniqueIncrement: true },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema, true);
|
|
@ -1,32 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "instance";
|
||||
|
||||
export const schema = {
|
||||
"requests.failed": { range: "small" },
|
||||
"requests.succeeded": { range: "small" },
|
||||
"requests.received": { range: "small" },
|
||||
"notes.total": { accumulate: true },
|
||||
"notes.inc": {},
|
||||
"notes.dec": {},
|
||||
"notes.diffs.normal": {},
|
||||
"notes.diffs.reply": {},
|
||||
"notes.diffs.renote": {},
|
||||
"notes.diffs.withFile": {},
|
||||
"users.total": { accumulate: true },
|
||||
"users.inc": { range: "small" },
|
||||
"users.dec": { range: "small" },
|
||||
"following.total": { accumulate: true },
|
||||
"following.inc": { range: "small" },
|
||||
"following.dec": { range: "small" },
|
||||
"followers.total": { accumulate: true },
|
||||
"followers.inc": { range: "small" },
|
||||
"followers.dec": { range: "small" },
|
||||
"drive.totalFiles": { accumulate: true },
|
||||
"drive.incFiles": {},
|
||||
"drive.decFiles": {},
|
||||
"drive.incUsage": {}, // in kilobyte
|
||||
"drive.decUsage": {}, // in kilobyte
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema, true);
|
|
@ -1,22 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "notes";
|
||||
|
||||
export const schema = {
|
||||
"local.total": { accumulate: true },
|
||||
"local.inc": {},
|
||||
"local.dec": {},
|
||||
"local.diffs.normal": {},
|
||||
"local.diffs.reply": {},
|
||||
"local.diffs.renote": {},
|
||||
"local.diffs.withFile": {},
|
||||
"remote.total": { accumulate: true },
|
||||
"remote.inc": {},
|
||||
"remote.dec": {},
|
||||
"remote.diffs.normal": {},
|
||||
"remote.diffs.reply": {},
|
||||
"remote.diffs.renote": {},
|
||||
"remote.diffs.withFile": {},
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,14 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "perUserDrive";
|
||||
|
||||
export const schema = {
|
||||
totalCount: { accumulate: true },
|
||||
totalSize: { accumulate: true }, // in kilobyte
|
||||
incCount: { range: "small" },
|
||||
incSize: {}, // in kilobyte
|
||||
decCount: { range: "small" },
|
||||
decSize: {}, // in kilobyte
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema, true);
|
|
@ -1,20 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "perUserFollowing";
|
||||
|
||||
export const schema = {
|
||||
"local.followings.total": { accumulate: true },
|
||||
"local.followings.inc": { range: "small" },
|
||||
"local.followings.dec": { range: "small" },
|
||||
"local.followers.total": { accumulate: true },
|
||||
"local.followers.inc": { range: "small" },
|
||||
"local.followers.dec": { range: "small" },
|
||||
"remote.followings.total": { accumulate: true },
|
||||
"remote.followings.inc": { range: "small" },
|
||||
"remote.followings.dec": { range: "small" },
|
||||
"remote.followers.total": { accumulate: true },
|
||||
"remote.followers.inc": { range: "small" },
|
||||
"remote.followers.dec": { range: "small" },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema, true);
|
|
@ -1,15 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "perUserNotes";
|
||||
|
||||
export const schema = {
|
||||
total: { accumulate: true },
|
||||
inc: { range: "small" },
|
||||
dec: { range: "small" },
|
||||
"diffs.normal": { range: "small" },
|
||||
"diffs.reply": { range: "small" },
|
||||
"diffs.renote": { range: "small" },
|
||||
"diffs.withFile": { range: "small" },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema, true);
|
|
@ -1,10 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "perUserReaction";
|
||||
|
||||
export const schema = {
|
||||
"local.count": { range: "small" },
|
||||
"remote.count": { range: "small" },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema, true);
|
|
@ -1,11 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "testGrouped";
|
||||
|
||||
export const schema = {
|
||||
"foo.total": { accumulate: true },
|
||||
"foo.inc": {},
|
||||
"foo.dec": {},
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema, true);
|
|
@ -1,11 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "testIntersection";
|
||||
|
||||
export const schema = {
|
||||
a: { uniqueIncrement: true },
|
||||
b: { uniqueIncrement: true },
|
||||
aAndB: { intersection: ["a", "b"] },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,9 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "testUnique";
|
||||
|
||||
export const schema = {
|
||||
foo: { uniqueIncrement: true },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,11 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "test";
|
||||
|
||||
export const schema = {
|
||||
"foo.total": { accumulate: true },
|
||||
"foo.inc": {},
|
||||
"foo.dec": {},
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,14 +0,0 @@
|
|||
import Chart from "../../core.js";
|
||||
|
||||
export const name = "users";
|
||||
|
||||
export const schema = {
|
||||
"local.total": { accumulate: true },
|
||||
"local.inc": { range: "small" },
|
||||
"local.dec": { range: "small" },
|
||||
"remote.total": { accumulate: true },
|
||||
"remote.inc": { range: "small" },
|
||||
"remote.dec": { range: "small" },
|
||||
} as const;
|
||||
|
||||
export const entity = Chart.schemaToEntity(name, schema);
|
|
@ -1,142 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { Followings, Instances } from "@/models/index.js";
|
||||
import { name, schema } from "./entities/federation.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
|
||||
/**
|
||||
* フェデレーションに関するチャート
|
||||
*/
|
||||
|
||||
export default class FederationChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
const meta = await fetchMeta();
|
||||
|
||||
const suspendedInstancesQuery = Instances.createQueryBuilder("instance")
|
||||
.select("instance.host")
|
||||
.where("instance.isSuspended = true");
|
||||
|
||||
const pubsubSubQuery = Followings.createQueryBuilder("f")
|
||||
.select("f.followerHost")
|
||||
.where("f.followerHost IS NOT NULL");
|
||||
|
||||
const subInstancesQuery = Followings.createQueryBuilder("f")
|
||||
.select("f.followeeHost")
|
||||
.where("f.followeeHost IS NOT NULL");
|
||||
|
||||
const pubInstancesQuery = Followings.createQueryBuilder("f")
|
||||
.select("f.followerHost")
|
||||
.where("f.followerHost IS NOT NULL");
|
||||
|
||||
const [sub, pub, pubsub, subActive, pubActive] = await Promise.all([
|
||||
Followings.createQueryBuilder("following")
|
||||
.select("COUNT(DISTINCT following.followeeHost)")
|
||||
.where("following.followeeHost IS NOT NULL")
|
||||
.andWhere(
|
||||
meta.blockedHosts.length === 0
|
||||
? "1=1"
|
||||
: "following.followeeHost NOT IN (:...blocked)",
|
||||
{ blocked: meta.blockedHosts },
|
||||
)
|
||||
.andWhere(
|
||||
`following.followeeHost NOT IN (${suspendedInstancesQuery.getQuery()})`,
|
||||
)
|
||||
.getRawOne()
|
||||
.then((x) => parseInt(x.count, 10)),
|
||||
Followings.createQueryBuilder("following")
|
||||
.select("COUNT(DISTINCT following.followerHost)")
|
||||
.where("following.followerHost IS NOT NULL")
|
||||
.andWhere(
|
||||
meta.blockedHosts.length === 0
|
||||
? "1=1"
|
||||
: "following.followerHost NOT IN (:...blocked)",
|
||||
{ blocked: meta.blockedHosts },
|
||||
)
|
||||
.andWhere(
|
||||
`following.followerHost NOT IN (${suspendedInstancesQuery.getQuery()})`,
|
||||
)
|
||||
.getRawOne()
|
||||
.then((x) => parseInt(x.count, 10)),
|
||||
Followings.createQueryBuilder("following")
|
||||
.select("COUNT(DISTINCT following.followeeHost)")
|
||||
.where("following.followeeHost IS NOT NULL")
|
||||
.andWhere(
|
||||
meta.blockedHosts.length === 0
|
||||
? "1=1"
|
||||
: "following.followeeHost NOT IN (:...blocked)",
|
||||
{ blocked: meta.blockedHosts },
|
||||
)
|
||||
.andWhere(
|
||||
`following.followeeHost NOT IN (${suspendedInstancesQuery.getQuery()})`,
|
||||
)
|
||||
.andWhere(`following.followeeHost IN (${pubsubSubQuery.getQuery()})`)
|
||||
.setParameters(pubsubSubQuery.getParameters())
|
||||
.getRawOne()
|
||||
.then((x) => parseInt(x.count, 10)),
|
||||
Instances.createQueryBuilder("instance")
|
||||
.select("COUNT(instance.id)")
|
||||
.where(`instance.host IN (${subInstancesQuery.getQuery()})`)
|
||||
.andWhere(
|
||||
meta.blockedHosts.length === 0
|
||||
? "1=1"
|
||||
: "instance.host NOT IN (:...blocked)",
|
||||
{ blocked: meta.blockedHosts },
|
||||
)
|
||||
.andWhere("instance.isSuspended = false")
|
||||
.andWhere("instance.lastCommunicatedAt > :gt", {
|
||||
gt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30),
|
||||
})
|
||||
.getRawOne()
|
||||
.then((x) => parseInt(x.count, 10)),
|
||||
Instances.createQueryBuilder("instance")
|
||||
.select("COUNT(instance.id)")
|
||||
.where(`instance.host IN (${pubInstancesQuery.getQuery()})`)
|
||||
.andWhere(
|
||||
meta.blockedHosts.length === 0
|
||||
? "1=1"
|
||||
: "instance.host NOT IN (:...blocked)",
|
||||
{ blocked: meta.blockedHosts },
|
||||
)
|
||||
.andWhere("instance.isSuspended = false")
|
||||
.andWhere("instance.lastCommunicatedAt > :gt", {
|
||||
gt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30),
|
||||
})
|
||||
.getRawOne()
|
||||
.then((x) => parseInt(x.count, 10)),
|
||||
]);
|
||||
|
||||
return {
|
||||
sub: sub,
|
||||
pub: pub,
|
||||
pubsub: pubsub,
|
||||
subActive: subActive,
|
||||
pubActive: pubActive,
|
||||
};
|
||||
}
|
||||
|
||||
public async deliverd(host: string, succeeded: boolean): Promise<void> {
|
||||
await this.commit(
|
||||
succeeded
|
||||
? {
|
||||
deliveredInstances: [host],
|
||||
}
|
||||
: {
|
||||
stalled: [host],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public async inbox(host: string): Promise<void> {
|
||||
await this.commit({
|
||||
inboxInstances: [host],
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { name, schema } from "./entities/hashtag.js";
|
||||
|
||||
/**
|
||||
* ハッシュタグに関するチャート
|
||||
*/
|
||||
|
||||
export default class HashtagChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema, true);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(
|
||||
hashtag: string,
|
||||
user: { id: User["id"]; host: User["host"] },
|
||||
): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
"local.users": Users.isLocalUser(user) ? [user.id] : [],
|
||||
"remote.users": Users.isLocalUser(user) ? [] : [user.id],
|
||||
},
|
||||
hashtag,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { DriveFiles, Followings, Users, Notes } from "@/models/index.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { name, schema } from "./entities/instance.js";
|
||||
|
||||
/**
|
||||
* インスタンスごとのチャート
|
||||
*/
|
||||
|
||||
export default class InstanceChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema, true);
|
||||
}
|
||||
|
||||
protected async tickMajor(
|
||||
group: string,
|
||||
): Promise<Partial<KVs<typeof schema>>> {
|
||||
const [notesCount, usersCount, followingCount, followersCount, driveFiles] =
|
||||
await Promise.all([
|
||||
Notes.countBy({ userHost: group }),
|
||||
Users.countBy({ host: group }),
|
||||
Followings.countBy({ followerHost: group }),
|
||||
Followings.countBy({ followeeHost: group }),
|
||||
DriveFiles.countBy({ userHost: group }),
|
||||
]);
|
||||
|
||||
return {
|
||||
"notes.total": notesCount,
|
||||
"users.total": usersCount,
|
||||
"following.total": followingCount,
|
||||
"followers.total": followersCount,
|
||||
"drive.totalFiles": driveFiles,
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async requestReceived(host: string): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
"requests.received": 1,
|
||||
},
|
||||
toPuny(host),
|
||||
);
|
||||
}
|
||||
|
||||
public async requestSent(host: string, isSucceeded: boolean): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
"requests.succeeded": isSucceeded ? 1 : 0,
|
||||
"requests.failed": isSucceeded ? 0 : 1,
|
||||
},
|
||||
toPuny(host),
|
||||
);
|
||||
}
|
||||
|
||||
public async newUser(host: string): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
"users.total": 1,
|
||||
"users.inc": 1,
|
||||
},
|
||||
toPuny(host),
|
||||
);
|
||||
}
|
||||
|
||||
public async updateNote(
|
||||
host: string,
|
||||
note: Note,
|
||||
isAdditional: boolean,
|
||||
): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
"notes.total": isAdditional ? 1 : -1,
|
||||
"notes.inc": isAdditional ? 1 : 0,
|
||||
"notes.dec": isAdditional ? 0 : 1,
|
||||
"notes.diffs.normal":
|
||||
note.replyId == null && note.renoteId == null
|
||||
? isAdditional
|
||||
? 1
|
||||
: -1
|
||||
: 0,
|
||||
"notes.diffs.renote":
|
||||
note.renoteId != null ? (isAdditional ? 1 : -1) : 0,
|
||||
"notes.diffs.reply": note.replyId != null ? (isAdditional ? 1 : -1) : 0,
|
||||
"notes.diffs.withFile":
|
||||
note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0,
|
||||
},
|
||||
toPuny(host),
|
||||
);
|
||||
}
|
||||
|
||||
public async updateFollowing(
|
||||
host: string,
|
||||
isAdditional: boolean,
|
||||
): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
"following.total": isAdditional ? 1 : -1,
|
||||
"following.inc": isAdditional ? 1 : 0,
|
||||
"following.dec": isAdditional ? 0 : 1,
|
||||
},
|
||||
toPuny(host),
|
||||
);
|
||||
}
|
||||
|
||||
public async updateFollowers(
|
||||
host: string,
|
||||
isAdditional: boolean,
|
||||
): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
"followers.total": isAdditional ? 1 : -1,
|
||||
"followers.inc": isAdditional ? 1 : 0,
|
||||
"followers.dec": isAdditional ? 0 : 1,
|
||||
},
|
||||
toPuny(host),
|
||||
);
|
||||
}
|
||||
|
||||
public async updateDrive(
|
||||
file: DriveFile,
|
||||
isAdditional: boolean,
|
||||
): Promise<void> {
|
||||
const fileSizeKb = file.size / 1000;
|
||||
await this.commit(
|
||||
{
|
||||
"drive.totalFiles": isAdditional ? 1 : -1,
|
||||
"drive.incFiles": isAdditional ? 1 : 0,
|
||||
"drive.incUsage": isAdditional ? fileSizeKb : 0,
|
||||
"drive.decFiles": isAdditional ? 1 : 0,
|
||||
"drive.decUsage": isAdditional ? fileSizeKb : 0,
|
||||
},
|
||||
file.userHost,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import { Not, IsNull } from "typeorm";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { name, schema } from "./entities/notes.js";
|
||||
|
||||
/**
|
||||
* ノートに関するチャート
|
||||
*/
|
||||
|
||||
export default class NotesChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
const [localCount, remoteCount] = await Promise.all([
|
||||
Notes.countBy({ userHost: IsNull() }),
|
||||
Notes.countBy({ userHost: Not(IsNull()) }),
|
||||
]);
|
||||
|
||||
return {
|
||||
"local.total": localCount,
|
||||
"remote.total": remoteCount,
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(
|
||||
note: Note,
|
||||
isAdditional: boolean,
|
||||
byBot = false,
|
||||
): Promise<void> {
|
||||
const prefix = note.userHost === null ? "local" : "remote";
|
||||
|
||||
await this.commit({
|
||||
[`${prefix}.total`]: isAdditional ? 1 : -1,
|
||||
[`${prefix}.inc`]: isAdditional ? 1 : 0,
|
||||
[`${prefix}.dec`]: isAdditional ? 0 : 1,
|
||||
[`${prefix}.diffs.normal`]:
|
||||
note.replyId == null && note.renoteId == null
|
||||
? isAdditional
|
||||
? 1
|
||||
: -1
|
||||
: 0,
|
||||
[`${prefix}.diffs.renote`]:
|
||||
note.renoteId != null && !byBot ? (isAdditional ? 1 : -1) : 0,
|
||||
[`${prefix}.diffs.reply`]:
|
||||
note.replyId != null ? (isAdditional ? 1 : -1) : 0,
|
||||
[`${prefix}.diffs.withFile`]:
|
||||
note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { DriveFiles } from "@/models/index.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { name, schema } from "./entities/per-user-drive.js";
|
||||
|
||||
/**
|
||||
* ユーザーごとのドライブに関するチャート
|
||||
*/
|
||||
|
||||
export default class PerUserDriveChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema, true);
|
||||
}
|
||||
|
||||
protected async tickMajor(
|
||||
group: string,
|
||||
): Promise<Partial<KVs<typeof schema>>> {
|
||||
const [count, size] = await Promise.all([
|
||||
DriveFiles.countBy({ userId: group }),
|
||||
DriveFiles.calcDriveUsageOf(group),
|
||||
]);
|
||||
|
||||
return {
|
||||
totalCount: count,
|
||||
totalSize: size,
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(file: DriveFile, isAdditional: boolean): Promise<void> {
|
||||
const fileSizeKb = file.size / 1000;
|
||||
await this.commit(
|
||||
{
|
||||
totalCount: isAdditional ? 1 : -1,
|
||||
totalSize: isAdditional ? fileSizeKb : -fileSizeKb,
|
||||
incCount: isAdditional ? 1 : 0,
|
||||
incSize: isAdditional ? fileSizeKb : 0,
|
||||
decCount: isAdditional ? 0 : 1,
|
||||
decSize: isAdditional ? 0 : fileSizeKb,
|
||||
},
|
||||
file.userId,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { Followings, Users } from "@/models/index.js";
|
||||
import { Not, IsNull } from "typeorm";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { name, schema } from "./entities/per-user-following.js";
|
||||
|
||||
/**
|
||||
* ユーザーごとのフォローに関するチャート
|
||||
*/
|
||||
|
||||
export default class PerUserFollowingChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema, true);
|
||||
}
|
||||
|
||||
protected async tickMajor(
|
||||
group: string,
|
||||
): Promise<Partial<KVs<typeof schema>>> {
|
||||
const [
|
||||
localFollowingsCount,
|
||||
localFollowersCount,
|
||||
remoteFollowingsCount,
|
||||
remoteFollowersCount,
|
||||
] = await Promise.all([
|
||||
Followings.countBy({ followerId: group, followeeHost: IsNull() }),
|
||||
Followings.countBy({ followeeId: group, followerHost: IsNull() }),
|
||||
Followings.countBy({ followerId: group, followeeHost: Not(IsNull()) }),
|
||||
Followings.countBy({ followeeId: group, followerHost: Not(IsNull()) }),
|
||||
]);
|
||||
|
||||
return {
|
||||
"local.followings.total": localFollowingsCount,
|
||||
"local.followers.total": localFollowersCount,
|
||||
"remote.followings.total": remoteFollowingsCount,
|
||||
"remote.followers.total": remoteFollowersCount,
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(
|
||||
follower: { id: User["id"]; host: User["host"] },
|
||||
followee: { id: User["id"]; host: User["host"] },
|
||||
isFollow: boolean,
|
||||
): Promise<void> {
|
||||
const prefixFollower = Users.isLocalUser(follower) ? "local" : "remote";
|
||||
const prefixFollowee = Users.isLocalUser(followee) ? "local" : "remote";
|
||||
|
||||
this.commit(
|
||||
{
|
||||
[`${prefixFollower}.followings.total`]: isFollow ? 1 : -1,
|
||||
[`${prefixFollower}.followings.inc`]: isFollow ? 1 : 0,
|
||||
[`${prefixFollower}.followings.dec`]: isFollow ? 0 : 1,
|
||||
},
|
||||
follower.id,
|
||||
);
|
||||
this.commit(
|
||||
{
|
||||
[`${prefixFollowee}.followers.total`]: isFollow ? 1 : -1,
|
||||
[`${prefixFollowee}.followers.inc`]: isFollow ? 1 : 0,
|
||||
[`${prefixFollowee}.followers.dec`]: isFollow ? 0 : 1,
|
||||
},
|
||||
followee.id,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { name, schema } from "./entities/per-user-notes.js";
|
||||
|
||||
/**
|
||||
* ユーザーごとのノートに関するチャート
|
||||
*/
|
||||
|
||||
export default class PerUserNotesChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema, true);
|
||||
}
|
||||
|
||||
protected async tickMajor(
|
||||
group: string,
|
||||
): Promise<Partial<KVs<typeof schema>>> {
|
||||
const [count] = await Promise.all([Notes.countBy({ userId: group })]);
|
||||
|
||||
return {
|
||||
total: count,
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(
|
||||
user: { id: User["id"] },
|
||||
note: Note,
|
||||
isAdditional: boolean,
|
||||
byBot = false,
|
||||
): Promise<void> {
|
||||
await this.commit(
|
||||
{
|
||||
total: isAdditional ? 1 : -1,
|
||||
inc: isAdditional ? 1 : 0,
|
||||
dec: isAdditional ? 0 : 1,
|
||||
"diffs.normal":
|
||||
note.replyId == null && note.renoteId == null
|
||||
? isAdditional
|
||||
? 1
|
||||
: -1
|
||||
: 0,
|
||||
"diffs.renote":
|
||||
note.renoteId != null && !byBot ? (isAdditional ? 1 : -1) : 0,
|
||||
"diffs.reply": note.replyId != null ? (isAdditional ? 1 : -1) : 0,
|
||||
"diffs.withFile": note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0,
|
||||
},
|
||||
user.id,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { name, schema } from "./entities/per-user-reactions.js";
|
||||
|
||||
/**
|
||||
* ユーザーごとのリアクションに関するチャート
|
||||
*/
|
||||
|
||||
export default class PerUserReactionsChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema, true);
|
||||
}
|
||||
|
||||
protected async tickMajor(
|
||||
group: string,
|
||||
): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(
|
||||
user: { id: User["id"]; host: User["host"] },
|
||||
note: Note,
|
||||
): Promise<void> {
|
||||
const prefix = Users.isLocalUser(user) ? "local" : "remote";
|
||||
this.commit(
|
||||
{
|
||||
[`${prefix}.count`]: 1,
|
||||
},
|
||||
note.userId,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { name, schema } from "./entities/test-grouped.js";
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*/
|
||||
|
||||
export default class TestGroupedChart extends Chart<typeof schema> {
|
||||
private total = {} as Record<string, number>;
|
||||
|
||||
constructor() {
|
||||
super(name, schema, true);
|
||||
}
|
||||
|
||||
protected async tickMajor(
|
||||
group: string,
|
||||
): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {
|
||||
"foo.total": this.total[group],
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async increment(group: string): Promise<void> {
|
||||
if (this.total[group] == null) this.total[group] = 0;
|
||||
|
||||
this.total[group]++;
|
||||
|
||||
await this.commit(
|
||||
{
|
||||
"foo.total": 1,
|
||||
"foo.inc": 1,
|
||||
},
|
||||
group,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { name, schema } from "./entities/test-intersection.js";
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*/
|
||||
|
||||
export default class TestIntersectionChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async addA(key: string): Promise<void> {
|
||||
await this.commit({
|
||||
a: [key],
|
||||
});
|
||||
}
|
||||
|
||||
public async addB(key: string): Promise<void> {
|
||||
await this.commit({
|
||||
b: [key],
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { name, schema } from "./entities/test-unique.js";
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*/
|
||||
|
||||
export default class TestUniqueChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async uniqueIncrement(key: string): Promise<void> {
|
||||
await this.commit({
|
||||
foo: [key],
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { name, schema } from "./entities/test.js";
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*/
|
||||
|
||||
export default class TestChart extends Chart<typeof schema> {
|
||||
public total = 0; // publicにするのはテストのため
|
||||
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {
|
||||
"foo.total": this.total,
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async increment(): Promise<void> {
|
||||
this.total++;
|
||||
|
||||
await this.commit({
|
||||
"foo.total": 1,
|
||||
"foo.inc": 1,
|
||||
});
|
||||
}
|
||||
|
||||
public async decrement(): Promise<void> {
|
||||
this.total--;
|
||||
|
||||
await this.commit({
|
||||
"foo.total": -1,
|
||||
"foo.dec": 1,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
import type { KVs } from "../core.js";
|
||||
import Chart from "../core.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { Not, IsNull } from "typeorm";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { name, schema } from "./entities/users.js";
|
||||
|
||||
/**
|
||||
* ユーザー数に関するチャート
|
||||
*/
|
||||
|
||||
export default class UsersChart extends Chart<typeof schema> {
|
||||
constructor() {
|
||||
super(name, schema);
|
||||
}
|
||||
|
||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
const [localCount, remoteCount] = await Promise.all([
|
||||
Users.countBy({ host: IsNull() }),
|
||||
Users.countBy({ host: Not(IsNull()) }),
|
||||
]);
|
||||
|
||||
return {
|
||||
"local.total": localCount,
|
||||
"remote.total": remoteCount,
|
||||
};
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
return {};
|
||||
}
|
||||
|
||||
public async update(
|
||||
user: { id: User["id"]; host: User["host"] },
|
||||
isAdditional: boolean,
|
||||
): Promise<void> {
|
||||
const prefix = Users.isLocalUser(user) ? "local" : "remote";
|
||||
|
||||
await this.commit({
|
||||
[`${prefix}.total`]: isAdditional ? 1 : -1,
|
||||
[`${prefix}.inc`]: isAdditional ? 1 : 0,
|
||||
[`${prefix}.dec`]: isAdditional ? 0 : 1,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -163,16 +163,6 @@ export default abstract class Chart<T extends Schema> {
|
|||
date: number;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* 1日に一回程度実行されれば良いような計算処理を入れる(主にCASCADE削除などアプリケーション側で感知できない変動によるズレの修正用)
|
||||
*/
|
||||
protected abstract tickMajor(group: string | null): Promise<Partial<KVs<T>>>;
|
||||
|
||||
/**
|
||||
* 少なくとも最小スパン内に1回は実行されて欲しい計算処理を入れる
|
||||
*/
|
||||
protected abstract tickMinor(group: string | null): Promise<Partial<KVs<T>>>;
|
||||
|
||||
private static convertSchemaToColumnDefinitions(
|
||||
schema: Schema,
|
||||
): Record<string, { type: string; array?: boolean; default?: any }> {
|
||||
|
@ -680,58 +670,6 @@ export default abstract class Chart<T extends Schema> {
|
|||
);
|
||||
}
|
||||
|
||||
public async tick(
|
||||
major: boolean,
|
||||
group: string | null = null,
|
||||
): Promise<void> {
|
||||
const data = major
|
||||
? await this.tickMajor(group)
|
||||
: await this.tickMinor(group);
|
||||
|
||||
const columns = {} as Record<keyof Columns<T>, number>;
|
||||
for (const [k, v] of Object.entries(data) as [
|
||||
keyof typeof data,
|
||||
number,
|
||||
][]) {
|
||||
const name = (columnPrefix +
|
||||
(k as string).replaceAll(".", columnDot)) as keyof Columns<T>;
|
||||
columns[name] = v;
|
||||
}
|
||||
|
||||
if (Object.keys(columns).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const update = async (
|
||||
logHour: RawRecord<T>,
|
||||
logDay: RawRecord<T>,
|
||||
): Promise<void> => {
|
||||
await Promise.all([
|
||||
this.repositoryForHour
|
||||
.createQueryBuilder()
|
||||
.update()
|
||||
.set(columns)
|
||||
.where("id = :id", { id: logHour.id })
|
||||
.execute(),
|
||||
this.repositoryForDay
|
||||
.createQueryBuilder()
|
||||
.update()
|
||||
.set(columns)
|
||||
.where("id = :id", { id: logDay.id })
|
||||
.execute(),
|
||||
]);
|
||||
};
|
||||
|
||||
return Promise.all([
|
||||
this.claimCurrentLog(group, "hour"),
|
||||
this.claimCurrentLog(group, "day"),
|
||||
]).then(([logHour, logDay]) => update(logHour, logDay));
|
||||
}
|
||||
|
||||
public resync(group: string | null = null): Promise<void> {
|
||||
return this.tick(true, group);
|
||||
}
|
||||
|
||||
public async clean(): Promise<void> {
|
||||
const current = dateUTC(Chart.getCurrentDate());
|
||||
|
||||
|
|
|
@ -1,57 +1,3 @@
|
|||
import { entity as FederationChart } from "./charts/entities/federation.js";
|
||||
import { entity as NotesChart } from "./charts/entities/notes.js";
|
||||
import { entity as UsersChart } from "./charts/entities/users.js";
|
||||
import { entity as ActiveUsersChart } from "./charts/entities/active-users.js";
|
||||
import { entity as InstanceChart } from "./charts/entities/instance.js";
|
||||
import { entity as PerUserNotesChart } from "./charts/entities/per-user-notes.js";
|
||||
import { entity as DriveChart } from "./charts/entities/drive.js";
|
||||
import { entity as PerUserReactionsChart } from "./charts/entities/per-user-reactions.js";
|
||||
import { entity as HashtagChart } from "./charts/entities/hashtag.js";
|
||||
import { entity as PerUserFollowingChart } from "./charts/entities/per-user-following.js";
|
||||
import { entity as PerUserDriveChart } from "./charts/entities/per-user-drive.js";
|
||||
import { entity as ApRequestChart } from "./charts/entities/ap-request.js";
|
||||
|
||||
import { entity as TestChart } from "./charts/entities/test.js";
|
||||
import { entity as TestGroupedChart } from "./charts/entities/test-grouped.js";
|
||||
import { entity as TestUniqueChart } from "./charts/entities/test-unique.js";
|
||||
import { entity as TestIntersectionChart } from "./charts/entities/test-intersection.js";
|
||||
|
||||
export const entities = [
|
||||
FederationChart.hour,
|
||||
FederationChart.day,
|
||||
NotesChart.hour,
|
||||
NotesChart.day,
|
||||
UsersChart.hour,
|
||||
UsersChart.day,
|
||||
ActiveUsersChart.hour,
|
||||
ActiveUsersChart.day,
|
||||
InstanceChart.hour,
|
||||
InstanceChart.day,
|
||||
PerUserNotesChart.hour,
|
||||
PerUserNotesChart.day,
|
||||
DriveChart.hour,
|
||||
DriveChart.day,
|
||||
PerUserReactionsChart.hour,
|
||||
PerUserReactionsChart.day,
|
||||
HashtagChart.hour,
|
||||
HashtagChart.day,
|
||||
PerUserFollowingChart.hour,
|
||||
PerUserFollowingChart.day,
|
||||
PerUserDriveChart.hour,
|
||||
PerUserDriveChart.day,
|
||||
ApRequestChart.hour,
|
||||
ApRequestChart.day,
|
||||
|
||||
...(process.env.NODE_ENV === "test"
|
||||
? [
|
||||
TestChart.hour,
|
||||
TestChart.day,
|
||||
TestGroupedChart.hour,
|
||||
TestGroupedChart.day,
|
||||
TestUniqueChart.hour,
|
||||
TestUniqueChart.day,
|
||||
TestIntersectionChart.hour,
|
||||
TestIntersectionChart.day,
|
||||
]
|
||||
: []),
|
||||
];
|
||||
export const entities = [ActiveUsersChart.hour, ActiveUsersChart.day];
|
||||
|
|
|
@ -1,54 +1,7 @@
|
|||
import { beforeShutdown } from "@/misc/before-shutdown.js";
|
||||
|
||||
import FederationChart from "./charts/federation.js";
|
||||
import NotesChart from "./charts/notes.js";
|
||||
import UsersChart from "./charts/users.js";
|
||||
import ActiveUsersChart from "./charts/active-users.js";
|
||||
import InstanceChart from "./charts/instance.js";
|
||||
import PerUserNotesChart from "./charts/per-user-notes.js";
|
||||
import DriveChart from "./charts/drive.js";
|
||||
import PerUserReactionsChart from "./charts/per-user-reactions.js";
|
||||
import HashtagChart from "./charts/hashtag.js";
|
||||
import PerUserFollowingChart from "./charts/per-user-following.js";
|
||||
import PerUserDriveChart from "./charts/per-user-drive.js";
|
||||
import ApRequestChart from "./charts/ap-request.js";
|
||||
|
||||
export const federationChart = new FederationChart();
|
||||
export const notesChart = new NotesChart();
|
||||
export const usersChart = new UsersChart();
|
||||
export const activeUsersChart = new ActiveUsersChart();
|
||||
export const instanceChart = new InstanceChart();
|
||||
export const perUserNotesChart = new PerUserNotesChart();
|
||||
export const driveChart = new DriveChart();
|
||||
export const perUserReactionsChart = new PerUserReactionsChart();
|
||||
export const hashtagChart = new HashtagChart();
|
||||
export const perUserFollowingChart = new PerUserFollowingChart();
|
||||
export const perUserDriveChart = new PerUserDriveChart();
|
||||
export const apRequestChart = new ApRequestChart();
|
||||
|
||||
const charts = [
|
||||
federationChart,
|
||||
notesChart,
|
||||
usersChart,
|
||||
activeUsersChart,
|
||||
instanceChart,
|
||||
perUserNotesChart,
|
||||
driveChart,
|
||||
perUserReactionsChart,
|
||||
hashtagChart,
|
||||
perUserFollowingChart,
|
||||
perUserDriveChart,
|
||||
apRequestChart,
|
||||
];
|
||||
|
||||
// 20分おきにメモリ情報をDBに書き込み
|
||||
setInterval(
|
||||
() => {
|
||||
for (const chart of charts) {
|
||||
chart.save();
|
||||
}
|
||||
},
|
||||
1000 * 60 * 20,
|
||||
);
|
||||
|
||||
beforeShutdown(() => Promise.all(charts.map((chart) => chart.save())));
|
||||
setInterval(() => activeUsersChart.save(), 1000 * 60 * 20);
|
||||
beforeShutdown(() => activeUsersChart.save());
|
||||
|
|
|
@ -17,11 +17,6 @@ import {
|
|||
} from "@/models/index.js";
|
||||
import { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type { IRemoteUser, User } from "@/models/entities/user.js";
|
||||
import {
|
||||
driveChart,
|
||||
perUserDriveChart,
|
||||
instanceChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
||||
import { FILE_TYPE_BROWSERSAFE } from "@/const.js";
|
||||
|
@ -655,12 +650,5 @@ export async function addFile({
|
|||
});
|
||||
}
|
||||
|
||||
// 統計を更新
|
||||
driveChart.update(file, true);
|
||||
perUserDriveChart.update(file, true);
|
||||
if (file.userHost !== null) {
|
||||
instanceChart.updateDrive(file, true);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { InternalStorage } from "./internal-storage.js";
|
||||
import { DriveFiles } from "@/models/index.js";
|
||||
import {
|
||||
driveChart,
|
||||
perUserDriveChart,
|
||||
instanceChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { createDeleteObjectStorageFileJob } from "@/queue/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { getS3 } from "./s3.js";
|
||||
|
@ -84,13 +79,6 @@ async function postProcess(file: DriveFile, isExpired = false) {
|
|||
} else {
|
||||
DriveFiles.delete(file.id);
|
||||
}
|
||||
|
||||
// 統計を更新
|
||||
driveChart.update(file, false);
|
||||
perUserDriveChart.update(file, false);
|
||||
if (file.userHost != null) {
|
||||
instanceChart.updateDrive(file, false);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteObjectStorageFile(key: string) {
|
||||
|
|
|
@ -17,10 +17,6 @@ import {
|
|||
Instances,
|
||||
UserProfiles,
|
||||
} from "@/models/index.js";
|
||||
import {
|
||||
instanceChart,
|
||||
perUserFollowingChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { createNotification } from "@/services/create-notification.js";
|
||||
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
||||
|
@ -111,18 +107,14 @@ export async function insertFollowingDoc(
|
|||
if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) {
|
||||
registerOrFetchInstanceDoc(follower.host).then((i) => {
|
||||
Instances.increment({ id: i.id }, "followingCount", 1);
|
||||
instanceChart.updateFollowing(i.host, true);
|
||||
});
|
||||
} else if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) {
|
||||
registerOrFetchInstanceDoc(followee.host).then((i) => {
|
||||
Instances.increment({ id: i.id }, "followersCount", 1);
|
||||
instanceChart.updateFollowers(i.host, true);
|
||||
});
|
||||
}
|
||||
//#endregion
|
||||
|
||||
perUserFollowingChart.update(follower, followee, true);
|
||||
|
||||
// Publish follow event
|
||||
if (Users.isLocalUser(follower)) {
|
||||
Users.pack(followee.id, follower, {
|
||||
|
|
|
@ -8,10 +8,6 @@ import Logger from "../logger.js";
|
|||
import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { Followings, Users, Instances } from "@/models/index.js";
|
||||
import {
|
||||
instanceChart,
|
||||
perUserFollowingChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { getActiveWebhooks } from "@/misc/webhook-cache.js";
|
||||
|
||||
const logger = new Logger("following/delete");
|
||||
|
@ -99,15 +95,11 @@ export async function decrementFollowing(
|
|||
if (Users.isRemoteUser(follower) && Users.isLocalUser(followee)) {
|
||||
registerOrFetchInstanceDoc(follower.host).then((i) => {
|
||||
Instances.decrement({ id: i.id }, "followingCount", 1);
|
||||
instanceChart.updateFollowing(i.host, false);
|
||||
});
|
||||
} else if (Users.isLocalUser(follower) && Users.isRemoteUser(followee)) {
|
||||
registerOrFetchInstanceDoc(followee.host).then((i) => {
|
||||
Instances.decrement({ id: i.id }, "followersCount", 1);
|
||||
instanceChart.updateFollowers(i.host, false);
|
||||
});
|
||||
}
|
||||
//#endregion
|
||||
|
||||
perUserFollowingChart.update(follower, followee, false);
|
||||
}
|
||||
|
|
|
@ -39,12 +39,7 @@ import type { App } from "@/models/entities/app.js";
|
|||
import { Not, In } from "typeorm";
|
||||
import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import {
|
||||
notesChart,
|
||||
perUserNotesChart,
|
||||
activeUsersChart,
|
||||
instanceChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import { activeUsersChart } from "@/services/chart/index.js";
|
||||
import type { IPoll } from "@/models/entities/poll.js";
|
||||
import { Poll } from "@/models/entities/poll.js";
|
||||
import { createNotification } from "@/services/create-notification.js";
|
||||
|
@ -350,15 +345,10 @@ export default async (
|
|||
|
||||
res(note);
|
||||
|
||||
// 統計を更新
|
||||
notesChart.update(note, true, user.isBot);
|
||||
perUserNotesChart.update(user, note, true, user.isBot);
|
||||
|
||||
// Register host
|
||||
if (Users.isRemoteUser(user)) {
|
||||
registerOrFetchInstanceDoc(user.host).then((i) => {
|
||||
Instances.increment({ id: i.id }, "notesCount", 1);
|
||||
instanceChart.updateNote(i.host, note, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,6 @@ import config from "@/config/index.js";
|
|||
import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js";
|
||||
import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js";
|
||||
import { Notes, Users, Instances } from "@/models/index.js";
|
||||
import {
|
||||
notesChart,
|
||||
perUserNotesChart,
|
||||
instanceChart,
|
||||
} from "@/services/chart/index.js";
|
||||
import {
|
||||
deliverToFollowers,
|
||||
deliverToUser,
|
||||
|
@ -109,14 +104,9 @@ export default async function (
|
|||
}
|
||||
//#endregion
|
||||
|
||||
// 統計を更新
|
||||
notesChart.update(note, false);
|
||||
perUserNotesChart.update(user, note, false);
|
||||
|
||||
if (Users.isRemoteUser(user)) {
|
||||
registerOrFetchInstanceDoc(user.host).then((i) => {
|
||||
Instances.decrement({ id: i.id }, "notesCount", 1);
|
||||
instanceChart.updateNote(i.host, note, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import {
|
|||
Blockings,
|
||||
} from "@/models/index.js";
|
||||
import { IsNull, Not } from "typeorm";
|
||||
import { perUserReactionsChart } from "@/services/chart/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { createNotification } from "@/services/create-notification.js";
|
||||
import deleteReaction from "./delete.js";
|
||||
|
@ -91,8 +90,6 @@ export default async (
|
|||
.where("id = :id", { id: note.id })
|
||||
.execute();
|
||||
|
||||
perUserReactionsChart.update(user, note);
|
||||
|
||||
// カスタム絵文字リアクションだったら絵文字情報も送る
|
||||
const decodedReaction = decodeReaction(reaction);
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { User } from "@/models/entities/user.js";
|
||||
import { Hashtags, Users } from "@/models/index.js";
|
||||
import { hashtagChart } from "@/services/chart/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import type { Hashtag } from "@/models/entities/hashtag.js";
|
||||
import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||
|
@ -151,8 +150,4 @@ export async function updateHashtag(
|
|||
} as Hashtag);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isUserAttached) {
|
||||
hashtagChart.update(tag, user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,575 +0,0 @@
|
|||
process.env.NODE_ENV = "test";
|
||||
|
||||
import * as assert from "assert";
|
||||
import * as lolex from "@sinonjs/fake-timers";
|
||||
import { initDb } from "../src/db/postgre.js";
|
||||
import TestGroupedChart from "../src/services/chart/charts/test-grouped.js";
|
||||
import TestIntersectionChart from "../src/services/chart/charts/test-intersection.js";
|
||||
import TestUniqueChart from "../src/services/chart/charts/test-unique.js";
|
||||
import TestChart from "../src/services/chart/charts/test.js";
|
||||
|
||||
describe("Chart", () => {
|
||||
let testChart: TestChart;
|
||||
let testGroupedChart: TestGroupedChart;
|
||||
let testUniqueChart: TestUniqueChart;
|
||||
let testIntersectionChart: TestIntersectionChart;
|
||||
let clock: lolex.InstalledClock;
|
||||
|
||||
beforeEach(async () => {
|
||||
await initDb(true);
|
||||
|
||||
testChart = new TestChart();
|
||||
testGroupedChart = new TestGroupedChart();
|
||||
testUniqueChart = new TestUniqueChart();
|
||||
testIntersectionChart = new TestIntersectionChart();
|
||||
|
||||
clock = lolex.install({
|
||||
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
||||
shouldClearNativeTimers: true,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clock.uninstall();
|
||||
});
|
||||
|
||||
it("Can updates", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("Can updates (dec)", async () => {
|
||||
await testChart.decrement();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [1, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [-1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [1, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [-1, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("Empty chart", async () => {
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [0, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [0, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("Can updates at multiple times at same time", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.increment();
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [3, 0, 0],
|
||||
total: [3, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [3, 0, 0],
|
||||
total: [3, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("複数回saveされてもデータの更新は一度だけ", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
await testChart.save();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("Can updates at different times", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
clock.tick("01:00:00");
|
||||
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 1, 0],
|
||||
total: [2, 1, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [2, 0, 0],
|
||||
total: [2, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 仕様上はこうなってほしいけど、実装は難しそうなのでskip
|
||||
/*
|
||||
it('Can updates at different times without save', async () => {
|
||||
await testChart.increment();
|
||||
|
||||
clock.tick('01:00:00');
|
||||
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart('hour', 3, null);
|
||||
const chartDays = await testChart.getChart('day', 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 1, 0],
|
||||
total: [2, 1, 0]
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [2, 0, 0],
|
||||
total: [2, 0, 0]
|
||||
},
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
it("Can padding", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
clock.tick("02:00:00");
|
||||
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 1],
|
||||
total: [2, 1, 1],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [2, 0, 0],
|
||||
total: [2, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 要求された範囲にログがひとつもない場合でもパディングできる
|
||||
it("Can padding from past range", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
clock.tick("05:00:00");
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [1, 1, 1],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 要求された範囲の最も古い箇所に位置するログが存在しない場合でもパディングできる
|
||||
// Issue #3190
|
||||
it("Can padding from past range 2", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
clock.tick("05:00:00");
|
||||
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [2, 1, 1],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [2, 0, 0],
|
||||
total: [2, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("Can specify offset", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
clock.tick("01:00:00");
|
||||
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart(
|
||||
"hour",
|
||||
3,
|
||||
new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
||||
);
|
||||
const chartDays = await testChart.getChart(
|
||||
"day",
|
||||
3,
|
||||
new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [2, 0, 0],
|
||||
total: [2, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("Can specify offset (floor time)", async () => {
|
||||
clock.tick("00:30:00");
|
||||
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
clock.tick("01:30:00");
|
||||
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
const chartHours = await testChart.getChart(
|
||||
"hour",
|
||||
3,
|
||||
new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
||||
);
|
||||
const chartDays = await testChart.getChart(
|
||||
"day",
|
||||
3,
|
||||
new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [2, 0, 0],
|
||||
total: [2, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe("Grouped", () => {
|
||||
it("Can updates", async () => {
|
||||
await testGroupedChart.increment("alice");
|
||||
await testGroupedChart.save();
|
||||
|
||||
const aliceChartHours = await testGroupedChart.getChart(
|
||||
"hour",
|
||||
3,
|
||||
null,
|
||||
"alice",
|
||||
);
|
||||
const aliceChartDays = await testGroupedChart.getChart(
|
||||
"day",
|
||||
3,
|
||||
null,
|
||||
"alice",
|
||||
);
|
||||
const bobChartHours = await testGroupedChart.getChart(
|
||||
"hour",
|
||||
3,
|
||||
null,
|
||||
"bob",
|
||||
);
|
||||
const bobChartDays = await testGroupedChart.getChart(
|
||||
"day",
|
||||
3,
|
||||
null,
|
||||
"bob",
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(aliceChartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(aliceChartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(bobChartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [0, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(bobChartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [0, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Unique increment", () => {
|
||||
it("Can updates", async () => {
|
||||
await testUniqueChart.uniqueIncrement("alice");
|
||||
await testUniqueChart.uniqueIncrement("alice");
|
||||
await testUniqueChart.uniqueIncrement("bob");
|
||||
await testUniqueChart.save();
|
||||
|
||||
const chartHours = await testUniqueChart.getChart("hour", 3, null);
|
||||
const chartDays = await testUniqueChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: [2, 0, 0],
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: [2, 0, 0],
|
||||
});
|
||||
});
|
||||
|
||||
describe("Intersection", () => {
|
||||
it("条件が満たされていない場合はカウントされない", async () => {
|
||||
await testIntersectionChart.addA("alice");
|
||||
await testIntersectionChart.addA("bob");
|
||||
await testIntersectionChart.addB("carol");
|
||||
await testIntersectionChart.save();
|
||||
|
||||
const chartHours = await testIntersectionChart.getChart(
|
||||
"hour",
|
||||
3,
|
||||
null,
|
||||
);
|
||||
const chartDays = await testIntersectionChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
a: [2, 0, 0],
|
||||
b: [1, 0, 0],
|
||||
aAndB: [0, 0, 0],
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
a: [2, 0, 0],
|
||||
b: [1, 0, 0],
|
||||
aAndB: [0, 0, 0],
|
||||
});
|
||||
});
|
||||
|
||||
it("条件が満たされている場合にカウントされる", async () => {
|
||||
await testIntersectionChart.addA("alice");
|
||||
await testIntersectionChart.addA("bob");
|
||||
await testIntersectionChart.addB("carol");
|
||||
await testIntersectionChart.addB("alice");
|
||||
await testIntersectionChart.save();
|
||||
|
||||
const chartHours = await testIntersectionChart.getChart(
|
||||
"hour",
|
||||
3,
|
||||
null,
|
||||
);
|
||||
const chartDays = await testIntersectionChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
a: [2, 0, 0],
|
||||
b: [2, 0, 0],
|
||||
aAndB: [1, 0, 0],
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
a: [2, 0, 0],
|
||||
b: [2, 0, 0],
|
||||
aAndB: [1, 0, 0],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Resync", () => {
|
||||
it("Can resync", async () => {
|
||||
testChart.total = 1;
|
||||
|
||||
await testChart.resync();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 0, 0],
|
||||
total: [1, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("Can resync (2)", async () => {
|
||||
await testChart.increment();
|
||||
await testChart.save();
|
||||
|
||||
clock.tick("01:00:00");
|
||||
|
||||
testChart.total = 100;
|
||||
|
||||
await testChart.resync();
|
||||
|
||||
const chartHours = await testChart.getChart("hour", 3, null);
|
||||
const chartDays = await testChart.getChart("day", 3, null);
|
||||
|
||||
assert.deepStrictEqual(chartHours, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [0, 1, 0],
|
||||
total: [100, 1, 0],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(chartDays, {
|
||||
foo: {
|
||||
dec: [0, 0, 0],
|
||||
inc: [1, 0, 0],
|
||||
total: [100, 0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -15,7 +15,6 @@ import { defaultStore } from "@/store";
|
|||
import { useChartTooltip } from "@/scripts/use-chart-tooltip";
|
||||
import { alpha } from "@/scripts/color";
|
||||
import { initChart } from "@/scripts/init-chart";
|
||||
import { $i } from "@/reactiveAccount";
|
||||
|
||||
initChart();
|
||||
|
||||
|
@ -26,20 +25,15 @@ const props = defineProps<{
|
|||
const rootEl = shallowRef<HTMLDivElement>(null);
|
||||
const chartEl = shallowRef<HTMLCanvasElement>(null);
|
||||
const now = new Date();
|
||||
let chartInstance: Chart = null,
|
||||
fetching = ref(true);
|
||||
let chartInstance: Chart | null = null;
|
||||
const fetching = ref(true);
|
||||
|
||||
const { handler: externalTooltipHandler } = useChartTooltip({
|
||||
position: "middle",
|
||||
});
|
||||
|
||||
const addArrays = (arr1: number[], arr2: number[], arr3: number[]) =>
|
||||
arr1.length === arr2.length && arr2.length === arr3.length
|
||||
? arr1.map((val, i) => val + arr2[i] + arr3[i])
|
||||
: null;
|
||||
|
||||
async function renderChart() {
|
||||
if (chartInstance) {
|
||||
async function renderActiveUsersChart() {
|
||||
if (chartInstance != null) {
|
||||
chartInstance.destroy();
|
||||
}
|
||||
|
||||
|
@ -72,46 +66,11 @@ async function renderChart() {
|
|||
});
|
||||
};
|
||||
|
||||
let values;
|
||||
|
||||
if (props.src === "active-users") {
|
||||
const raw = await os.api("charts/active-users", {
|
||||
const activeUsers = await os.api("charts/active-users", {
|
||||
limit: chartLimit,
|
||||
span: "day",
|
||||
});
|
||||
values = raw.readWrite;
|
||||
} else if (props.src === "notes") {
|
||||
const raw = await os.api("charts/notes", {
|
||||
limit: chartLimit,
|
||||
span: "day",
|
||||
});
|
||||
values = raw.local.inc;
|
||||
} else if (props.src === "ap-requests-inbox-received") {
|
||||
const raw = await os.api("charts/ap-request", {
|
||||
limit: chartLimit,
|
||||
span: "day",
|
||||
});
|
||||
values = raw.inboxReceived;
|
||||
} else if (props.src === "ap-requests-deliver-succeeded") {
|
||||
const raw = await os.api("charts/ap-request", {
|
||||
limit: chartLimit,
|
||||
span: "day",
|
||||
});
|
||||
values = raw.deliverSucceeded;
|
||||
} else if (props.src === "ap-requests-deliver-failed") {
|
||||
const raw = await os.api("charts/ap-request", {
|
||||
limit: chartLimit,
|
||||
span: "day",
|
||||
});
|
||||
values = raw.deliverFailed;
|
||||
} else if (props.src === "my-notes") {
|
||||
const raw = await os.api("charts/user/notes", {
|
||||
limit: chartLimit,
|
||||
span: "day",
|
||||
userId: $i.id,
|
||||
});
|
||||
values = addArrays(raw.diffs.normal, raw.diffs.reply, raw.diffs.renote);
|
||||
}
|
||||
const values = activeUsers.readWrite;
|
||||
|
||||
fetching.value = false;
|
||||
|
||||
|
@ -248,11 +207,11 @@ watch(
|
|||
() => props.src,
|
||||
() => {
|
||||
fetching.value = true;
|
||||
renderChart();
|
||||
renderActiveUsersChart();
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
renderChart();
|
||||
renderActiveUsersChart();
|
||||
});
|
||||
</script>
|
|
@ -361,239 +361,6 @@ const render = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const exportData = () => {
|
||||
// TODO
|
||||
};
|
||||
|
||||
const fetchFederationChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/federation", {
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Received",
|
||||
type: "area",
|
||||
data: format(raw.inboxInstances),
|
||||
color: colors.blue,
|
||||
},
|
||||
{
|
||||
name: "Delivered",
|
||||
type: "area",
|
||||
data: format(raw.deliveredInstances),
|
||||
color: colors.green,
|
||||
},
|
||||
{
|
||||
name: "Stalled",
|
||||
type: "area",
|
||||
data: format(raw.stalled),
|
||||
color: colors.red,
|
||||
},
|
||||
{
|
||||
name: "Pub Active",
|
||||
type: "line",
|
||||
data: format(raw.pubActive),
|
||||
color: colors.purple,
|
||||
},
|
||||
{
|
||||
name: "Sub Active",
|
||||
type: "line",
|
||||
data: format(raw.subActive),
|
||||
color: colors.orange,
|
||||
},
|
||||
{
|
||||
name: "Pub & Sub",
|
||||
type: "line",
|
||||
data: format(raw.pubsub),
|
||||
dashed: true,
|
||||
color: colors.cyan,
|
||||
},
|
||||
{
|
||||
name: "Pub",
|
||||
type: "line",
|
||||
data: format(raw.pub),
|
||||
dashed: true,
|
||||
color: colors.purple,
|
||||
},
|
||||
{
|
||||
name: "Sub",
|
||||
type: "line",
|
||||
data: format(raw.sub),
|
||||
dashed: true,
|
||||
color: colors.orange,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchApRequestChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/ap-request", {
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "In",
|
||||
type: "area",
|
||||
color: "#31748f",
|
||||
data: format(raw.inboxReceived),
|
||||
},
|
||||
{
|
||||
name: "Out (succ)",
|
||||
type: "area",
|
||||
color: "#c4a7e7",
|
||||
data: format(raw.deliverSucceeded),
|
||||
},
|
||||
{
|
||||
name: "Out (fail)",
|
||||
type: "area",
|
||||
color: "#f6c177",
|
||||
data: format(raw.deliverFailed),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/notes", {
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "All",
|
||||
type: "line",
|
||||
data: format(
|
||||
type === "combined"
|
||||
? sum(
|
||||
raw.local.inc,
|
||||
negate(raw.local.dec),
|
||||
raw.remote.inc,
|
||||
negate(raw.remote.dec),
|
||||
)
|
||||
: sum(raw[type].inc, negate(raw[type].dec)),
|
||||
),
|
||||
color: "#888888",
|
||||
},
|
||||
{
|
||||
name: "Renotes",
|
||||
type: "area",
|
||||
data: format(
|
||||
type === "combined"
|
||||
? sum(raw.local.diffs.renote, raw.remote.diffs.renote)
|
||||
: raw[type].diffs.renote,
|
||||
),
|
||||
color: colors.green,
|
||||
},
|
||||
{
|
||||
name: "Replies",
|
||||
type: "area",
|
||||
data: format(
|
||||
type === "combined"
|
||||
? sum(raw.local.diffs.reply, raw.remote.diffs.reply)
|
||||
: raw[type].diffs.reply,
|
||||
),
|
||||
color: colors.yellow,
|
||||
},
|
||||
{
|
||||
name: "Normal",
|
||||
type: "area",
|
||||
data: format(
|
||||
type === "combined"
|
||||
? sum(raw.local.diffs.normal, raw.remote.diffs.normal)
|
||||
: raw[type].diffs.normal,
|
||||
),
|
||||
color: colors.blue,
|
||||
},
|
||||
{
|
||||
name: "With file",
|
||||
type: "area",
|
||||
data: format(
|
||||
type === "combined"
|
||||
? sum(
|
||||
raw.local.diffs.withFile,
|
||||
raw.remote.diffs.withFile,
|
||||
)
|
||||
: raw[type].diffs.withFile,
|
||||
),
|
||||
color: colors.purple,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchNotesTotalChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/notes", {
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Combined",
|
||||
type: "line",
|
||||
data: format(sum(raw.local.total, raw.remote.total)),
|
||||
},
|
||||
{
|
||||
name: "Local",
|
||||
type: "area",
|
||||
data: format(raw.local.total),
|
||||
},
|
||||
{
|
||||
name: "Remote",
|
||||
type: "area",
|
||||
data: format(raw.remote.total),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/users", {
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Combined",
|
||||
type: "line",
|
||||
data: format(
|
||||
total
|
||||
? sum(raw.local.total, raw.remote.total)
|
||||
: sum(
|
||||
raw.local.inc,
|
||||
negate(raw.local.dec),
|
||||
raw.remote.inc,
|
||||
negate(raw.remote.dec),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Local",
|
||||
type: "area",
|
||||
data: format(
|
||||
total
|
||||
? raw.local.total
|
||||
: sum(raw.local.inc, negate(raw.local.dec)),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Remote",
|
||||
type: "area",
|
||||
data: format(
|
||||
total
|
||||
? raw.remote.total
|
||||
: sum(raw.remote.inc, negate(raw.remote.dec)),
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchActiveUsersChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/active-users", {
|
||||
limit: props.limit,
|
||||
|
@ -659,428 +426,9 @@ const fetchActiveUsersChart = async (): Promise<typeof chartData> => {
|
|||
};
|
||||
};
|
||||
|
||||
const fetchDriveChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/drive", {
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
bytes: true,
|
||||
series: [
|
||||
{
|
||||
name: "All",
|
||||
type: "line",
|
||||
dashed: true,
|
||||
data: format(
|
||||
sum(
|
||||
raw.local.incSize,
|
||||
negate(raw.local.decSize),
|
||||
raw.remote.incSize,
|
||||
negate(raw.remote.decSize),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Local +",
|
||||
type: "area",
|
||||
data: format(raw.local.incSize),
|
||||
},
|
||||
{
|
||||
name: "Local -",
|
||||
type: "area",
|
||||
data: format(negate(raw.local.decSize)),
|
||||
},
|
||||
{
|
||||
name: "Remote +",
|
||||
type: "area",
|
||||
data: format(raw.remote.incSize),
|
||||
},
|
||||
{
|
||||
name: "Remote -",
|
||||
type: "area",
|
||||
data: format(negate(raw.remote.decSize)),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchDriveFilesChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/drive", {
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "All",
|
||||
type: "line",
|
||||
dashed: true,
|
||||
data: format(
|
||||
sum(
|
||||
raw.local.incCount,
|
||||
negate(raw.local.decCount),
|
||||
raw.remote.incCount,
|
||||
negate(raw.remote.decCount),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Local +",
|
||||
type: "area",
|
||||
data: format(raw.local.incCount),
|
||||
},
|
||||
{
|
||||
name: "Local -",
|
||||
type: "area",
|
||||
data: format(negate(raw.local.decCount)),
|
||||
},
|
||||
{
|
||||
name: "Remote +",
|
||||
type: "area",
|
||||
data: format(raw.remote.incCount),
|
||||
},
|
||||
{
|
||||
name: "Remote -",
|
||||
type: "area",
|
||||
data: format(negate(raw.remote.decCount)),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchInstanceRequestsChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/instance", {
|
||||
host: props.args.host,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "In",
|
||||
type: "area",
|
||||
color: "#31748f",
|
||||
data: format(raw.requests.received),
|
||||
},
|
||||
{
|
||||
name: "Out (succ)",
|
||||
type: "area",
|
||||
color: "#c4a7e7",
|
||||
data: format(raw.requests.succeeded),
|
||||
},
|
||||
{
|
||||
name: "Out (fail)",
|
||||
type: "area",
|
||||
color: "#f6c177",
|
||||
data: format(raw.requests.failed),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchInstanceUsersChart = async (
|
||||
total: boolean,
|
||||
): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/instance", {
|
||||
host: props.args.host,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Users",
|
||||
type: "area",
|
||||
color: "#31748f",
|
||||
data: format(
|
||||
total
|
||||
? raw.users.total
|
||||
: sum(raw.users.inc, negate(raw.users.dec)),
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchInstanceNotesChart = async (
|
||||
total: boolean,
|
||||
): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/instance", {
|
||||
host: props.args.host,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Posts",
|
||||
type: "area",
|
||||
color: "#31748f",
|
||||
data: format(
|
||||
total
|
||||
? raw.notes.total
|
||||
: sum(raw.notes.inc, negate(raw.notes.dec)),
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchInstanceFfChart = async (
|
||||
total: boolean,
|
||||
): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/instance", {
|
||||
host: props.args.host,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Following",
|
||||
type: "area",
|
||||
color: "#31748f",
|
||||
data: format(
|
||||
total
|
||||
? raw.following.total
|
||||
: sum(raw.following.inc, negate(raw.following.dec)),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Followers",
|
||||
type: "area",
|
||||
color: "#c4a7e7",
|
||||
data: format(
|
||||
total
|
||||
? raw.followers.total
|
||||
: sum(raw.followers.inc, negate(raw.followers.dec)),
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchInstanceDriveUsageChart = async (
|
||||
total: boolean,
|
||||
): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/instance", {
|
||||
host: props.args.host,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
bytes: true,
|
||||
series: [
|
||||
{
|
||||
name: "Drive usage",
|
||||
type: "area",
|
||||
color: "#31748f",
|
||||
data: format(
|
||||
total
|
||||
? raw.drive.totalUsage
|
||||
: sum(raw.drive.incUsage, negate(raw.drive.decUsage)),
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchInstanceDriveFilesChart = async (
|
||||
total: boolean,
|
||||
): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/instance", {
|
||||
host: props.args.host,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Drive files",
|
||||
type: "area",
|
||||
color: "#31748f",
|
||||
data: format(
|
||||
total
|
||||
? raw.drive.totalFiles
|
||||
: sum(raw.drive.incFiles, negate(raw.drive.decFiles)),
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchPerUserNotesChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/user/notes", {
|
||||
userId: props.args.user.id,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
...(props.args.withoutAll
|
||||
? []
|
||||
: [
|
||||
{
|
||||
name: "All",
|
||||
type: "line",
|
||||
data: format(sum(raw.inc, negate(raw.dec))),
|
||||
color: "#888888",
|
||||
},
|
||||
]),
|
||||
{
|
||||
name: "With file",
|
||||
type: "area",
|
||||
data: format(raw.diffs.withFile),
|
||||
color: colors.purple,
|
||||
},
|
||||
{
|
||||
name: "Renotes",
|
||||
type: "area",
|
||||
data: format(raw.diffs.renote),
|
||||
color: colors.green,
|
||||
},
|
||||
{
|
||||
name: "Replies",
|
||||
type: "area",
|
||||
data: format(raw.diffs.reply),
|
||||
color: colors.yellow,
|
||||
},
|
||||
{
|
||||
name: "Normal",
|
||||
type: "area",
|
||||
data: format(raw.diffs.normal),
|
||||
color: colors.blue,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchPerUserFollowingChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/user/following", {
|
||||
userId: props.args.user.id,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Local",
|
||||
type: "area",
|
||||
data: format(raw.local.followings.total),
|
||||
},
|
||||
{
|
||||
name: "Remote",
|
||||
type: "area",
|
||||
data: format(raw.remote.followings.total),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchPerUserFollowersChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/user/following", {
|
||||
userId: props.args.user.id,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Local",
|
||||
type: "area",
|
||||
data: format(raw.local.followers.total),
|
||||
},
|
||||
{
|
||||
name: "Remote",
|
||||
type: "area",
|
||||
data: format(raw.remote.followers.total),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchPerUserDriveChart = async (): Promise<typeof chartData> => {
|
||||
const raw = await os.apiGet("charts/user/drive", {
|
||||
userId: props.args.user.id,
|
||||
limit: props.limit,
|
||||
span: props.span,
|
||||
});
|
||||
return {
|
||||
series: [
|
||||
{
|
||||
name: "Inc",
|
||||
type: "area",
|
||||
data: format(raw.incSize),
|
||||
},
|
||||
{
|
||||
name: "Dec",
|
||||
type: "area",
|
||||
data: format(raw.decSize),
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchAndRender = async () => {
|
||||
const fetchData = () => {
|
||||
switch (props.src) {
|
||||
case "federation":
|
||||
return fetchFederationChart();
|
||||
case "ap-request":
|
||||
return fetchApRequestChart();
|
||||
case "users":
|
||||
return fetchUsersChart(false);
|
||||
case "users-total":
|
||||
return fetchUsersChart(true);
|
||||
case "active-users":
|
||||
return fetchActiveUsersChart();
|
||||
case "notes":
|
||||
return fetchNotesChart("combined");
|
||||
case "local-notes":
|
||||
return fetchNotesChart("local");
|
||||
case "remote-notes":
|
||||
return fetchNotesChart("remote");
|
||||
case "notes-total":
|
||||
return fetchNotesTotalChart();
|
||||
case "drive":
|
||||
return fetchDriveChart();
|
||||
case "drive-files":
|
||||
return fetchDriveFilesChart();
|
||||
case "instance-requests":
|
||||
return fetchInstanceRequestsChart();
|
||||
case "instance-users":
|
||||
return fetchInstanceUsersChart(false);
|
||||
case "instance-users-total":
|
||||
return fetchInstanceUsersChart(true);
|
||||
case "instance-notes":
|
||||
return fetchInstanceNotesChart(false);
|
||||
case "instance-notes-total":
|
||||
return fetchInstanceNotesChart(true);
|
||||
case "instance-ff":
|
||||
return fetchInstanceFfChart(false);
|
||||
case "instance-ff-total":
|
||||
return fetchInstanceFfChart(true);
|
||||
case "instance-drive-usage":
|
||||
return fetchInstanceDriveUsageChart(false);
|
||||
case "instance-drive-usage-total":
|
||||
return fetchInstanceDriveUsageChart(true);
|
||||
case "instance-drive-files":
|
||||
return fetchInstanceDriveFilesChart(false);
|
||||
case "instance-drive-files-total":
|
||||
return fetchInstanceDriveFilesChart(true);
|
||||
|
||||
case "per-user-notes":
|
||||
return fetchPerUserNotesChart();
|
||||
case "per-user-following":
|
||||
return fetchPerUserFollowingChart();
|
||||
case "per-user-followers":
|
||||
return fetchPerUserFollowersChart();
|
||||
case "per-user-drive":
|
||||
return fetchPerUserDriveChart();
|
||||
}
|
||||
};
|
||||
fetching.value = true;
|
||||
chartData = await fetchData();
|
||||
chartData = await fetchActiveUsersChart();
|
||||
fetching.value = false;
|
||||
render();
|
||||
};
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
{{ instance.softwareVersion }}</span
|
||||
>
|
||||
</div>
|
||||
<MkMiniChart v-if="chartValues" class="chart" :src="chartValues" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -27,7 +26,6 @@
|
|||
import { ref } from "vue";
|
||||
|
||||
import type { entities } from "firefish-js";
|
||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||
import * as os from "@/os";
|
||||
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";
|
||||
|
||||
|
@ -35,18 +33,6 @@ const props = defineProps<{
|
|||
instance: entities.Instance;
|
||||
}>();
|
||||
|
||||
const chartValues = ref<number[] | null>(null);
|
||||
|
||||
os.apiGet("charts/instance", {
|
||||
host: props.instance.host,
|
||||
limit: 16 + 1,
|
||||
span: "day",
|
||||
}).then((res) => {
|
||||
// 今日のぶんの値はまだ途中の値であり、それも含めると大抵の場合前日よりも下降しているようなグラフになってしまうため今日は弾く
|
||||
res.requests.received.splice(0, 1);
|
||||
chartValues.value = res.requests.received;
|
||||
});
|
||||
|
||||
function getInstanceIcon(instance): string {
|
||||
return (
|
||||
getProxiedImageUrlNullable(instance.faviconUrl, "preview") ??
|
||||
|
@ -104,10 +90,6 @@ function getInstanceIcon(instance): string {
|
|||
}
|
||||
}
|
||||
|
||||
> :global(.chart) {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
&:global(.yellow) {
|
||||
--c: rgb(255 196 0 / 15%);
|
||||
background-image: linear-gradient(
|
||||
|
|
|
@ -1,52 +1,9 @@
|
|||
<template>
|
||||
<div :class="$style.root">
|
||||
<MkFolder class="item">
|
||||
<template #header>Chart</template>
|
||||
<template #header>Active Users</template>
|
||||
<div :class="$style.chart">
|
||||
<div class="selects">
|
||||
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1">
|
||||
<optgroup :label="i18n.ts.federation">
|
||||
<option value="federation">
|
||||
{{ i18n.ts._charts.federation }}
|
||||
</option>
|
||||
<option value="ap-request">
|
||||
{{ i18n.ts._charts.apRequest }}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup :label="i18n.ts.users">
|
||||
<option value="users">
|
||||
{{ i18n.ts._charts.usersIncDec }}
|
||||
</option>
|
||||
<option value="users-total">
|
||||
{{ i18n.ts._charts.usersTotal }}
|
||||
</option>
|
||||
<option value="active-users">
|
||||
{{ i18n.ts._charts.activeUsers }}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup :label="i18n.ts.notes">
|
||||
<option value="notes">
|
||||
{{ i18n.ts._charts.notesIncDec }}
|
||||
</option>
|
||||
<option value="local-notes">
|
||||
{{ i18n.ts._charts.localNotesIncDec }}
|
||||
</option>
|
||||
<option value="remote-notes">
|
||||
{{ i18n.ts._charts.remoteNotesIncDec }}
|
||||
</option>
|
||||
<option value="notes-total">
|
||||
{{ i18n.ts._charts.notesTotal }}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup :label="i18n.ts.drive">
|
||||
<option value="drive-files">
|
||||
{{ i18n.ts._charts.filesIncDec }}
|
||||
</option>
|
||||
<option value="drive">
|
||||
{{ i18n.ts._charts.storageUsageIncDec }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</MkSelect>
|
||||
<MkSelect v-model="chartSpan" style="margin: 0 0 0 10px">
|
||||
<option value="hour">{{ i18n.ts.perHour }}</option>
|
||||
<option value="day">{{ i18n.ts.perDay }}</option>
|
||||
|
@ -54,32 +11,15 @@
|
|||
</div>
|
||||
<div class="chart _panel">
|
||||
<MkChart
|
||||
:src="chartSrc"
|
||||
src="active-users"
|
||||
:span="chartSpan"
|
||||
:limit="chartLimit"
|
||||
:detailed="true"
|
||||
></MkChart>
|
||||
</div>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder class="item">
|
||||
<template #header>Active users heatmap</template>
|
||||
<MkSelect v-model="heatmapSrc" style="margin: 0 0 12px 0">
|
||||
<option value="active-users">Active users</option>
|
||||
<option value="notes">Posts</option>
|
||||
<option value="ap-requests-inbox-received">
|
||||
Fediverse Requests: inboxReceived
|
||||
</option>
|
||||
<option value="ap-requests-deliver-succeeded">
|
||||
Fediverse Requests: deliverSucceeded
|
||||
</option>
|
||||
<option value="ap-requests-deliver-failed">
|
||||
Fediverse Requests: deliverFailed
|
||||
</option>
|
||||
</MkSelect>
|
||||
<div class="_panel" :class="$style.heatmap">
|
||||
<MkHeatmap :src="heatmapSrc" />
|
||||
<MkActiveUsersHeatmap />
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
|
@ -109,7 +49,7 @@ import MkChart from "@/components/MkChart.vue";
|
|||
import { useChartTooltip } from "@/scripts/use-chart-tooltip";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import MkHeatmap from "@/components/MkHeatmap.vue";
|
||||
import MkActiveUsersHeatmap from "@/components/MkActiveUsersHeatmap.vue";
|
||||
import MkFolder from "@/components/MkFolder.vue";
|
||||
import { initChart } from "@/scripts/init-chart";
|
||||
|
||||
|
@ -117,8 +57,6 @@ initChart();
|
|||
|
||||
const chartLimit = 500;
|
||||
const chartSpan = ref<"hour" | "day">("hour");
|
||||
const chartSrc = ref("active-users");
|
||||
const heatmapSrc = ref("active-users");
|
||||
const subDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||
const pubDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
v-if="tab === 'renotes' && renotes"
|
||||
:key="item.user.id"
|
||||
:user="item.user"
|
||||
:with-chart="false"
|
||||
/>
|
||||
<!-- </MkPagination> -->
|
||||
<MkLoading v-else-if="tab === 'renotes' && note.renoteCount > 0" />
|
||||
|
|
|
@ -23,12 +23,7 @@
|
|||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<MkUserCardMini
|
||||
v-for="user in users"
|
||||
:key="user.id"
|
||||
:user="user"
|
||||
:with-chart="false"
|
||||
/>
|
||||
<MkUserCardMini v-for="user in users" :key="user.id" :user="user" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<MkLoading />
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
></span
|
||||
>
|
||||
</div>
|
||||
<MkMiniChart v-if="chartValues" class="chart" :src="chartValues" />
|
||||
</MkA>
|
||||
</template>
|
||||
|
||||
|
@ -29,35 +28,17 @@
|
|||
import { ref } from "vue";
|
||||
|
||||
import { acct, type entities } from "firefish-js";
|
||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||
import * as os from "@/os";
|
||||
import { userPage } from "@/filters/user";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
user: entities.User;
|
||||
withChart?: boolean;
|
||||
showAboutPage?: boolean;
|
||||
}>(),
|
||||
{
|
||||
withChart: true,
|
||||
showAboutPage: false,
|
||||
},
|
||||
);
|
||||
|
||||
const chartValues = ref<number[] | null>(null);
|
||||
|
||||
if (props.withChart) {
|
||||
os.apiGet("charts/user/notes", {
|
||||
userId: props.user.id,
|
||||
limit: 16 + 1,
|
||||
span: "day",
|
||||
}).then((res) => {
|
||||
// 今日のぶんの値はまだ途中の値であり、それも含めると大抵の場合前日よりも下降しているようなグラフになってしまうため今日は弾く
|
||||
res.inc.splice(0, 1);
|
||||
chartValues.value = res.inc;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -1,289 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<MkLoading v-if="fetching" />
|
||||
<div v-show="!fetching" :class="$style.root">
|
||||
<div class="charts _panel">
|
||||
<div class="chart">
|
||||
<canvas ref="chartEl2"></canvas>
|
||||
</div>
|
||||
<div class="chart">
|
||||
<canvas ref="chartEl"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, shallowRef } from "vue";
|
||||
import { Chart } from "chart.js";
|
||||
import gradient from "chartjs-plugin-gradient";
|
||||
import * as os from "@/os";
|
||||
import { useChartTooltip } from "@/scripts/use-chart-tooltip";
|
||||
import { chartVLine } from "@/scripts/chart-vline";
|
||||
import { defaultStore } from "@/store";
|
||||
import { alpha } from "@/scripts/color";
|
||||
import { initChart } from "@/scripts/init-chart";
|
||||
|
||||
initChart();
|
||||
|
||||
const chartLimit = 50;
|
||||
const chartEl = shallowRef<HTMLCanvasElement>();
|
||||
const chartEl2 = shallowRef<HTMLCanvasElement>();
|
||||
const fetching = ref(true);
|
||||
|
||||
const { handler: externalTooltipHandler } = useChartTooltip();
|
||||
const { handler: externalTooltipHandler2 } = useChartTooltip();
|
||||
|
||||
onMounted(async () => {
|
||||
const now = new Date();
|
||||
|
||||
const getDate = (ago: number) => {
|
||||
const y = now.getFullYear();
|
||||
const m = now.getMonth();
|
||||
const d = now.getDate();
|
||||
|
||||
return new Date(y, m, d - ago);
|
||||
};
|
||||
|
||||
const format = (arr) => {
|
||||
return arr.map((v, i) => ({
|
||||
x: getDate(i).getTime(),
|
||||
y: v,
|
||||
}));
|
||||
};
|
||||
|
||||
const formatMinus = (arr) => {
|
||||
return arr.map((v, i) => ({
|
||||
x: getDate(i).getTime(),
|
||||
y: -v,
|
||||
}));
|
||||
};
|
||||
|
||||
const raw = await os.api("charts/ap-request", {
|
||||
limit: chartLimit,
|
||||
span: "day",
|
||||
});
|
||||
|
||||
const vLineColor = defaultStore.state.darkMode
|
||||
? "rgba(255, 255, 255, 0.2)"
|
||||
: "rgba(0, 0, 0, 0.2)";
|
||||
const succColor = "#9ccfd8";
|
||||
const failColor = "#f6c177";
|
||||
|
||||
new Chart(chartEl.value, {
|
||||
type: "line",
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
stack: "a",
|
||||
parsing: false,
|
||||
label: "Out: Succ",
|
||||
data: format(raw.deliverSucceeded).slice().reverse(),
|
||||
tension: 0.3,
|
||||
pointRadius: 0,
|
||||
borderWidth: 2,
|
||||
borderColor: succColor,
|
||||
borderJoinStyle: "round",
|
||||
borderRadius: 4,
|
||||
backgroundColor: alpha(succColor, 0.35),
|
||||
fill: true,
|
||||
clip: 8,
|
||||
},
|
||||
{
|
||||
stack: "a",
|
||||
parsing: false,
|
||||
label: "Out: Fail",
|
||||
data: formatMinus(raw.deliverFailed).slice().reverse(),
|
||||
tension: 0.3,
|
||||
pointRadius: 0,
|
||||
borderWidth: 2,
|
||||
borderColor: failColor,
|
||||
borderJoinStyle: "round",
|
||||
borderRadius: 4,
|
||||
backgroundColor: alpha(failColor, 0.35),
|
||||
fill: true,
|
||||
clip: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
aspectRatio: 2.5,
|
||||
layout: {
|
||||
padding: {
|
||||
left: 0,
|
||||
right: 8,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
type: "time",
|
||||
stacked: true,
|
||||
offset: false,
|
||||
time: {
|
||||
stepSize: 1,
|
||||
unit: "day",
|
||||
},
|
||||
grid: {
|
||||
display: true,
|
||||
},
|
||||
ticks: {
|
||||
display: true,
|
||||
maxRotation: 0,
|
||||
autoSkipPadding: 16,
|
||||
},
|
||||
min: getDate(chartLimit).getTime(),
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
position: "left",
|
||||
suggestedMax: 10,
|
||||
grid: {
|
||||
display: true,
|
||||
},
|
||||
ticks: {
|
||||
display: true,
|
||||
// mirror: true,
|
||||
callback: (value, index, values) =>
|
||||
value < 0 ? -value : value,
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: "index",
|
||||
},
|
||||
elements: {
|
||||
point: {
|
||||
hoverRadius: 5,
|
||||
hoverBorderWidth: 2,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
mode: "index",
|
||||
animation: {
|
||||
duration: 0,
|
||||
},
|
||||
external: externalTooltipHandler,
|
||||
},
|
||||
gradient,
|
||||
},
|
||||
},
|
||||
plugins: [chartVLine(vLineColor)],
|
||||
});
|
||||
|
||||
new Chart(chartEl2.value, {
|
||||
type: "bar",
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
parsing: false,
|
||||
label: "In",
|
||||
data: format(raw.inboxReceived).slice().reverse(),
|
||||
tension: 0.3,
|
||||
pointRadius: 0,
|
||||
borderWidth: 0,
|
||||
borderJoinStyle: "round",
|
||||
borderRadius: 4,
|
||||
backgroundColor: "#c4a7e7",
|
||||
barPercentage: 0.8,
|
||||
categoryPercentage: 0.9,
|
||||
fill: true,
|
||||
clip: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
aspectRatio: 5,
|
||||
layout: {
|
||||
padding: {
|
||||
left: 0,
|
||||
right: 8,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
type: "time",
|
||||
offset: false,
|
||||
time: {
|
||||
stepSize: 1,
|
||||
unit: "day",
|
||||
displayFormats: {
|
||||
day: "M/d",
|
||||
month: "Y/M",
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
maxRotation: 0,
|
||||
autoSkipPadding: 16,
|
||||
},
|
||||
min: getDate(chartLimit).getTime(),
|
||||
},
|
||||
y: {
|
||||
position: "left",
|
||||
suggestedMax: 10,
|
||||
grid: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: "index",
|
||||
},
|
||||
elements: {
|
||||
point: {
|
||||
hoverRadius: 5,
|
||||
hoverBorderWidth: 2,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
mode: "index",
|
||||
animation: {
|
||||
duration: 0,
|
||||
},
|
||||
external: externalTooltipHandler2,
|
||||
},
|
||||
gradient,
|
||||
},
|
||||
},
|
||||
plugins: [chartVLine(vLineColor)],
|
||||
});
|
||||
|
||||
fetching.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
&:global {
|
||||
> .charts {
|
||||
> .chart {
|
||||
padding: 16px;
|
||||
|
||||
&:first-child {
|
||||
border-bottom: solid 0.5px var(--divider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -17,40 +17,6 @@
|
|||
<div class="subTitle">Top 10</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!fetching" class="items">
|
||||
<div class="item _panel sub">
|
||||
<div class="icon">
|
||||
<i :class="icon('ph-download ph-xl', false)"></i>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="value">
|
||||
{{ number(federationSubActive) }}
|
||||
<MkNumberDiff
|
||||
v-tooltip="i18n.ts.dayOverDayChanges"
|
||||
class="diff"
|
||||
:value="federationSubActiveDiff"
|
||||
></MkNumberDiff>
|
||||
</div>
|
||||
<div class="label">Sub</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item _panel pub">
|
||||
<div class="icon">
|
||||
<i :class="icon('ph-upload ph-xl', false)"></i>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="value">
|
||||
{{ number(federationPubActive) }}
|
||||
<MkNumberDiff
|
||||
v-tooltip="i18n.ts.dayOverDayChanges"
|
||||
class="diff"
|
||||
:value="federationPubActiveDiff"
|
||||
></MkNumberDiff>
|
||||
</div>
|
||||
<div class="label">Pub</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -59,32 +25,15 @@
|
|||
import { onMounted, ref } from "vue";
|
||||
import XPie from "./overview.pie.vue";
|
||||
import * as os from "@/os";
|
||||
import number from "@/filters/number";
|
||||
import MkNumberDiff from "@/components/MkNumberDiff.vue";
|
||||
import { i18n } from "@/i18n";
|
||||
import { useChartTooltip } from "@/scripts/use-chart-tooltip";
|
||||
import icon from "@/scripts/icon";
|
||||
|
||||
const topSubInstancesForPie = ref<any>(null);
|
||||
const topPubInstancesForPie = ref<any>(null);
|
||||
const federationPubActive = ref<number | null>(null);
|
||||
const federationPubActiveDiff = ref<number | null>(null);
|
||||
const federationSubActive = ref<number | null>(null);
|
||||
const federationSubActiveDiff = ref<number | null>(null);
|
||||
const fetching = ref(true);
|
||||
|
||||
useChartTooltip();
|
||||
|
||||
onMounted(async () => {
|
||||
const chart = await os.apiGet("charts/federation", {
|
||||
limit: 2,
|
||||
span: "day",
|
||||
});
|
||||
federationPubActive.value = chart.pubActive[0];
|
||||
federationPubActiveDiff.value = chart.pubActive[0] - chart.pubActive[1];
|
||||
federationSubActive.value = chart.subActive[0];
|
||||
federationSubActiveDiff.value = chart.subActive[0] - chart.subActive[1];
|
||||
|
||||
os.apiGet("federation/stats", { limit: 10 }).then((res) => {
|
||||
topSubInstancesForPie.value = res.topSubInstances
|
||||
.map((x) => ({
|
||||
|
|
|
@ -1,29 +1,11 @@
|
|||
<template>
|
||||
<div class="_panel" :class="$style.root">
|
||||
<MkSelect v-model="src" style="margin: 0 0 12px 0" small>
|
||||
<option value="notes">Posts</option>
|
||||
<option value="active-users">Active users</option>
|
||||
<option value="ap-requests-inbox-received">
|
||||
Fediverse Requests: inboxReceived
|
||||
</option>
|
||||
<option value="ap-requests-deliver-succeeded">
|
||||
Fediverse Requests: deliverSucceeded
|
||||
</option>
|
||||
<option value="ap-requests-deliver-failed">
|
||||
Fediverse Requests: deliverFailed
|
||||
</option>
|
||||
</MkSelect>
|
||||
<MkHeatmap :src="src" />
|
||||
<MkActiveUsersHeatmap />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
import MkHeatmap from "@/components/MkHeatmap.vue";
|
||||
import MkSelect from "@/components/form/select.vue";
|
||||
|
||||
const src = ref("notes");
|
||||
import MkActiveUsersHeatmap from "@/components/MkActiveUsersHeatmap.vue";
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -16,11 +16,6 @@
|
|||
:value="stats.originalUsersCount"
|
||||
style="margin-right: 0.5em"
|
||||
/>
|
||||
<MkNumberDiff
|
||||
v-tooltip="i18n.ts.dayOverDayChanges"
|
||||
class="diff"
|
||||
:value="usersComparedToThePrevDay"
|
||||
></MkNumberDiff>
|
||||
</div>
|
||||
<div class="label">{{ i18n.ts.users }}</div>
|
||||
</div>
|
||||
|
@ -35,11 +30,6 @@
|
|||
:value="stats.originalNotesCount"
|
||||
style="margin-right: 0.5em"
|
||||
/>
|
||||
<MkNumberDiff
|
||||
v-tooltip="i18n.ts.dayOverDayChanges"
|
||||
class="diff"
|
||||
:value="notesComparedToThePrevDay"
|
||||
></MkNumberDiff>
|
||||
</div>
|
||||
<div class="label">{{ i18n.ts.notes }}</div>
|
||||
</div>
|
||||
|
@ -96,15 +86,12 @@
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import * as os from "@/os";
|
||||
import MkNumberDiff from "@/components/MkNumberDiff.vue";
|
||||
import MkNumber from "@/components/MkNumber.vue";
|
||||
import { i18n } from "@/i18n";
|
||||
import { defaultStore } from "@/store";
|
||||
import icon from "@/scripts/icon";
|
||||
|
||||
const stats = ref(null);
|
||||
const usersComparedToThePrevDay = ref<number>();
|
||||
const notesComparedToThePrevDay = ref<number>();
|
||||
const onlineUsersCount = ref(0);
|
||||
const emojiCount = ref(0);
|
||||
const fetching = ref(true);
|
||||
|
@ -117,16 +104,6 @@ onMounted(async () => {
|
|||
stats.value = _stats;
|
||||
onlineUsersCount.value = _onlineUsersCount;
|
||||
|
||||
os.apiGet("charts/users", { limit: 2, span: "day" }).then((chart) => {
|
||||
usersComparedToThePrevDay.value =
|
||||
stats.value.originalUsersCount - chart.local.total[1];
|
||||
});
|
||||
|
||||
os.apiGet("charts/notes", { limit: 2, span: "day" }).then((chart) => {
|
||||
notesComparedToThePrevDay.value =
|
||||
stats.value.originalNotesCount - chart.local.total[1];
|
||||
});
|
||||
|
||||
os.api("meta", { detail: false }).then((meta) => {
|
||||
emojiCount.value = meta.emojis.length;
|
||||
});
|
||||
|
|
|
@ -14,30 +14,14 @@
|
|||
></span
|
||||
>
|
||||
</div>
|
||||
<MkMiniChart v-if="chart" class="chart" :src="chart.inc" />
|
||||
</MkA>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
import { acct, type entities } from "firefish-js";
|
||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||
import * as os from "@/os";
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
user: entities.User;
|
||||
}>();
|
||||
|
||||
const chart = ref(null);
|
||||
|
||||
os.apiGet("charts/user/notes", {
|
||||
userId: props.user.id,
|
||||
limit: 16,
|
||||
span: "day",
|
||||
}).then((res) => {
|
||||
chart.value = res;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -9,10 +9,6 @@
|
|||
<MkFolder class="item">
|
||||
<template #header>Active users</template>
|
||||
<XActiveUsers />
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder class="item">
|
||||
<template #header>Heatmap</template>
|
||||
<XHeatmap />
|
||||
</MkFolder>
|
||||
|
||||
|
@ -31,11 +27,6 @@
|
|||
<XInstances />
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder class="item">
|
||||
<template #header>Fediverse Requests</template>
|
||||
<XApRequests />
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder class="item">
|
||||
<template #header>New users</template>
|
||||
<XUsers />
|
||||
|
@ -71,7 +62,6 @@ import {
|
|||
import XFederation from "./overview.federation.vue";
|
||||
import XInstances from "./overview.instances.vue";
|
||||
import XQueue from "./overview.queue.vue";
|
||||
import XApRequests from "./overview.ap-requests.vue";
|
||||
import XUsers from "./overview.users.vue";
|
||||
import XActiveUsers from "./overview.active-users.vue";
|
||||
import XStats from "./overview.stats.vue";
|
||||
|
@ -89,10 +79,6 @@ const rootEl = shallowRef<HTMLElement>();
|
|||
const serverInfo = ref<any>(null);
|
||||
const topSubInstancesForPie = ref<any>(null);
|
||||
const topPubInstancesForPie = ref<any>(null);
|
||||
const federationPubActive = ref<number | null>(null);
|
||||
const federationPubActiveDiff = ref<number | null>(null);
|
||||
const federationSubActive = ref<number | null>(null);
|
||||
const federationSubActiveDiff = ref<number | null>(null);
|
||||
const newUsers = ref(null);
|
||||
const activeInstances = shallowRef(null);
|
||||
const queueStatsConnection = markRaw(stream.useChannel("queueStats"));
|
||||
|
@ -108,13 +94,6 @@ onMounted(async () => {
|
|||
magicGrid.listen();
|
||||
*/
|
||||
|
||||
os.apiGet("charts/federation", { limit: 2, span: "day" }).then((chart) => {
|
||||
federationPubActive.value = chart.pubActive[0];
|
||||
federationPubActiveDiff.value = chart.pubActive[0] - chart.pubActive[1];
|
||||
federationSubActive.value = chart.subActive[0];
|
||||
federationSubActiveDiff.value = chart.subActive[0] - chart.subActive[1];
|
||||
});
|
||||
|
||||
os.apiGet("federation/stats", { limit: 10 }).then((res) => {
|
||||
topSubInstancesForPie.value = res.topSubInstances
|
||||
.map((x) => ({
|
||||
|
|
|
@ -221,79 +221,6 @@
|
|||
</FormSection>
|
||||
</div>
|
||||
</swiper-slide>
|
||||
<swiper-slide>
|
||||
<div class="_formRoot">
|
||||
<div class="cmhjzshl">
|
||||
<div class="selects">
|
||||
<MkSelect
|
||||
v-model="chartSrc"
|
||||
style="margin: 0 10px 0 0; flex: 1"
|
||||
>
|
||||
<option value="instance-requests">
|
||||
{{ i18n.ts._instanceCharts.requests }}
|
||||
</option>
|
||||
<option value="instance-users">
|
||||
{{ i18n.ts._instanceCharts.users }}
|
||||
</option>
|
||||
<option value="instance-users-total">
|
||||
{{ i18n.ts._instanceCharts.usersTotal }}
|
||||
</option>
|
||||
<option value="instance-notes">
|
||||
{{ i18n.ts._instanceCharts.notes }}
|
||||
</option>
|
||||
<option value="instance-notes-total">
|
||||
{{ i18n.ts._instanceCharts.notesTotal }}
|
||||
</option>
|
||||
<option value="instance-ff">
|
||||
{{ i18n.ts._instanceCharts.ff }}
|
||||
</option>
|
||||
<option value="instance-ff-total">
|
||||
{{ i18n.ts._instanceCharts.ffTotal }}
|
||||
</option>
|
||||
<option value="instance-drive-usage">
|
||||
{{ i18n.ts._instanceCharts.cacheSize }}
|
||||
</option>
|
||||
<option value="instance-drive-usage-total">
|
||||
{{
|
||||
i18n.ts._instanceCharts
|
||||
.cacheSizeTotal
|
||||
}}
|
||||
</option>
|
||||
<option value="instance-drive-files">
|
||||
{{ i18n.ts._instanceCharts.files }}
|
||||
</option>
|
||||
<option value="instance-drive-files-total">
|
||||
{{ i18n.ts._instanceCharts.filesTotal }}
|
||||
</option>
|
||||
</MkSelect>
|
||||
</div>
|
||||
<div class="charts">
|
||||
<div class="label">
|
||||
{{ i18n.t("recentNHours", { n: 90 }) }}
|
||||
</div>
|
||||
<MkChart
|
||||
class="chart"
|
||||
:src="chartSrc"
|
||||
span="hour"
|
||||
:limit="90"
|
||||
:args="{ host: host }"
|
||||
:detailed="true"
|
||||
></MkChart>
|
||||
<div class="label">
|
||||
{{ i18n.t("recentNDays", { n: 90 }) }}
|
||||
</div>
|
||||
<MkChart
|
||||
class="chart"
|
||||
:src="chartSrc"
|
||||
span="day"
|
||||
:limit="90"
|
||||
:args="{ host: host }"
|
||||
:detailed="true"
|
||||
></MkChart>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</swiper-slide>
|
||||
<swiper-slide>
|
||||
<div class="_formRoot">
|
||||
<MkPagination
|
||||
|
@ -339,7 +266,6 @@ import { computed, ref, watch } from "vue";
|
|||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import type { entities } from "firefish-js";
|
||||
import MkChart from "@/components/MkChart.vue";
|
||||
import MkObjectView from "@/components/MkObjectView.vue";
|
||||
import FormLink from "@/components/form/link.vue";
|
||||
import MkLink from "@/components/MkLink.vue";
|
||||
|
@ -375,17 +301,16 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const tabs = ["overview"];
|
||||
if (isAdmin) tabs.push("chart", "users", "raw");
|
||||
if (isAdmin) tabs.push("users", "raw");
|
||||
const tab = ref(tabs[0]);
|
||||
watch(tab, () => syncSlide(tabs.indexOf(tab.value)));
|
||||
|
||||
const chartSrc = ref("instance-requests");
|
||||
const meta = ref<AugmentedInstanceMetadata | null>(null);
|
||||
const instance = ref<AugmentedInstance | null>(null);
|
||||
const suspended = ref(false);
|
||||
const isBlocked = ref(false);
|
||||
const isSilenced = ref(false);
|
||||
const faviconUrl = ref(null);
|
||||
const faviconUrl = ref<string | null>(null);
|
||||
|
||||
const usersPagination = {
|
||||
endpoint: isAdmin ? "admin/show-users" : ("users" as const),
|
||||
|
@ -486,11 +411,6 @@ const theTabs = [
|
|||
|
||||
if (isAdmin) {
|
||||
theTabs.push(
|
||||
{
|
||||
key: "chart",
|
||||
title: i18n.ts.charts,
|
||||
icon: `${icon("ph-chart-bar")}`,
|
||||
},
|
||||
{
|
||||
key: "users",
|
||||
title: i18n.ts.users,
|
||||
|
@ -549,12 +469,5 @@ function syncSlide(index) {
|
|||
display: flex;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
> .charts {
|
||||
> .label {
|
||||
margin-bottom: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -17,20 +17,6 @@
|
|||
</FormSplit>
|
||||
</FormSection>
|
||||
|
||||
<FormSection>
|
||||
<template #label>{{ i18n.ts.statistics }}</template>
|
||||
<MkChart
|
||||
src="per-user-drive"
|
||||
:args="{ user: $i }"
|
||||
span="day"
|
||||
:limit="7 * 5"
|
||||
:bar="true"
|
||||
:stacked="true"
|
||||
:detailed="false"
|
||||
:aspect-ratio="6"
|
||||
/>
|
||||
</FormSection>
|
||||
|
||||
<FormSection>
|
||||
<FormButton @click="chooseUploadFolder()">
|
||||
{{ i18n.ts.uploadFolder }}
|
||||
|
@ -69,7 +55,6 @@ import FormSplit from "@/components/form/split.vue";
|
|||
import * as os from "@/os";
|
||||
import bytes from "@/filters/bytes";
|
||||
import { defaultStore } from "@/store";
|
||||
import MkChart from "@/components/MkChart.vue";
|
||||
import { i18n } from "@/i18n";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
import { $i, isSignedIn } from "@/reactiveAccount";
|
||||
|
|
|
@ -330,44 +330,6 @@
|
|||
</FormInput>
|
||||
</FormSection>
|
||||
</div>
|
||||
<div v-else-if="tab === 'chart'" class="_formRoot">
|
||||
<div class="cmhjzshm">
|
||||
<div class="selects">
|
||||
<MkSelect
|
||||
v-model="chartSrc"
|
||||
style="margin: 0 10px 0 0; flex: 1"
|
||||
>
|
||||
<option value="per-user-notes">
|
||||
{{ i18n.ts.notes }}
|
||||
</option>
|
||||
</MkSelect>
|
||||
</div>
|
||||
<div class="charts">
|
||||
<div class="label">
|
||||
{{ i18n.t("recentNHours", { n: 90 }) }}
|
||||
</div>
|
||||
<MkChart
|
||||
class="chart"
|
||||
:src="chartSrc"
|
||||
span="hour"
|
||||
:limit="90"
|
||||
:args="{ user, withoutAll: true }"
|
||||
:detailed="true"
|
||||
></MkChart>
|
||||
<div class="label">
|
||||
{{ i18n.t("recentNDays", { n: 90 }) }}
|
||||
</div>
|
||||
<MkChart
|
||||
class="chart"
|
||||
:src="chartSrc"
|
||||
span="day"
|
||||
:limit="90"
|
||||
:args="{ user, withoutAll: true }"
|
||||
:detailed="true"
|
||||
></MkChart>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="tab === 'raw'" class="_formRoot">
|
||||
<MkObjectView v-if="info && isAdmin" tall :value="info">
|
||||
</MkObjectView>
|
||||
|
@ -382,7 +344,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { acct, type entities } from "firefish-js";
|
||||
import MkChart from "@/components/MkChart.vue";
|
||||
import MkObjectView from "@/components/MkObjectView.vue";
|
||||
import FormTextarea from "@/components/form/textarea.vue";
|
||||
import FormSwitch from "@/components/form/switch.vue";
|
||||
|
@ -410,7 +371,6 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const tab = ref("overview");
|
||||
const chartSrc = ref("per-user-notes");
|
||||
const user = ref<null | entities.UserDetailed>();
|
||||
const init = ref<ReturnType<typeof createFetcher>>();
|
||||
const info = ref();
|
||||
|
@ -680,11 +640,6 @@ const headerTabs = computed(() =>
|
|||
icon: `${icon("ph-shield")}`,
|
||||
}
|
||||
: null,
|
||||
{
|
||||
key: "chart",
|
||||
title: i18n.ts.charts,
|
||||
icon: `${icon("ph-chart-bar")}`,
|
||||
},
|
||||
{
|
||||
key: "raw",
|
||||
title: "Raw",
|
||||
|
@ -772,20 +727,6 @@ definePageMetadata(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cmhjzshm {
|
||||
> .selects {
|
||||
display: flex;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
> .charts {
|
||||
> .label {
|
||||
margin-bottom: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -347,11 +347,6 @@
|
|||
>
|
||||
<template v-if="narrow">
|
||||
<XPhotos :key="user.id" :user="user" />
|
||||
<!-- <XActivity
|
||||
:key="user.id"
|
||||
:user="user"
|
||||
style="margin-top: var(--margin)"
|
||||
/> -->
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -360,11 +355,6 @@
|
|||
</div>
|
||||
<div v-if="!narrow" class="sub">
|
||||
<XPhotos :key="user.id" :user="user" />
|
||||
<XActivity
|
||||
:key="user.id"
|
||||
:user="user"
|
||||
style="margin-top: var(--margin)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
|
@ -399,7 +389,6 @@ import { host } from "@/config";
|
|||
import icon from "@/scripts/icon";
|
||||
|
||||
const XPhotos = defineAsyncComponent(() => import("./index.photos.vue"));
|
||||
const XActivity = defineAsyncComponent(() => import("./index.activity.vue"));
|
||||
|
||||
const hideFollowButton = defaultStore.state.hideFollowButtons;
|
||||
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
<template>
|
||||
<MkContainer>
|
||||
<template #header
|
||||
><i :class="icon('ph-chart-bar')" style="margin-right: 0.5em"></i
|
||||
>{{ i18n.ts.activity }}</template
|
||||
>
|
||||
<template #func>
|
||||
<button class="_button" @click="showMenu">
|
||||
<i :class="icon('ph-dots-three-outline')"></i>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<div style="padding: 8px">
|
||||
<MkChart
|
||||
:src="chartSrc"
|
||||
:args="{ user, withoutAll: true }"
|
||||
span="day"
|
||||
:limit="limit"
|
||||
:bar="true"
|
||||
:stacked="true"
|
||||
:detailed="false"
|
||||
:aspect-ratio="5"
|
||||
/>
|
||||
</div>
|
||||
</MkContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
import type { entities } from "firefish-js";
|
||||
import MkContainer from "@/components/MkContainer.vue";
|
||||
import MkChart from "@/components/MkChart.vue";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import icon from "@/scripts/icon";
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
user: entities.User;
|
||||
limit?: number;
|
||||
}>(),
|
||||
{
|
||||
limit: 50,
|
||||
},
|
||||
);
|
||||
|
||||
const chartSrc = ref("per-user-notes");
|
||||
|
||||
function showMenu(ev: MouseEvent) {
|
||||
os.popupMenu(
|
||||
[
|
||||
{
|
||||
text: i18n.ts.notes,
|
||||
active: true,
|
||||
action: () => {
|
||||
chartSrc.value = "per-user-notes";
|
||||
},
|
||||
} /*, {
|
||||
text: i18n.ts.following,
|
||||
action: () => {
|
||||
chartSrc = 'per-user-following';
|
||||
}
|
||||
}, {
|
||||
text: i18n.ts.followers,
|
||||
action: () => {
|
||||
chartSrc = 'per-user-followers';
|
||||
}
|
||||
} */,
|
||||
],
|
||||
ev.currentTarget ?? ev.target,
|
||||
);
|
||||
}
|
||||
</script>
|
|
@ -1,102 +0,0 @@
|
|||
<template>
|
||||
<svg viewBox="0 0 21 7">
|
||||
<rect
|
||||
v-for="record in activity"
|
||||
class="day"
|
||||
width="1"
|
||||
height="1"
|
||||
:x="record.x"
|
||||
:y="record.date.weekday"
|
||||
rx="1"
|
||||
ry="1"
|
||||
fill="transparent"
|
||||
>
|
||||
<title>
|
||||
{{ record.date.year }}/{{ record.date.month + 1 }}/{{
|
||||
record.date.day
|
||||
}}
|
||||
</title>
|
||||
</rect>
|
||||
<rect
|
||||
v-for="record in activity"
|
||||
class="day"
|
||||
:width="record.v"
|
||||
:height="record.v"
|
||||
:x="record.x + (1 - record.v) / 2"
|
||||
:y="record.date.weekday + (1 - record.v) / 2"
|
||||
rx="1"
|
||||
ry="1"
|
||||
:fill="record.color"
|
||||
style="pointer-events: none"
|
||||
/>
|
||||
<rect
|
||||
class="today"
|
||||
width="1"
|
||||
height="1"
|
||||
:x="activity[0].x"
|
||||
:y="activity[0].date.weekday"
|
||||
rx="1"
|
||||
ry="1"
|
||||
fill="none"
|
||||
stroke-width="0.1"
|
||||
stroke="#eb6f92"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps<{
|
||||
activity: any[];
|
||||
}>();
|
||||
|
||||
for (const d of props.activity) {
|
||||
d.total = d.notes + d.replies + d.renotes;
|
||||
}
|
||||
const peak = Math.max(...props.activity.map((d) => d.total));
|
||||
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth();
|
||||
const day = now.getDate();
|
||||
|
||||
let x = 20;
|
||||
props.activity.slice().forEach((d, i) => {
|
||||
d.x = x;
|
||||
|
||||
const date = new Date(year, month, day - i);
|
||||
d.date = {
|
||||
year: date.getFullYear(),
|
||||
month: date.getMonth(),
|
||||
day: date.getDate(),
|
||||
weekday: date.getDay(),
|
||||
};
|
||||
|
||||
d.v = peak === 0 ? 0 : d.total / (peak / 2);
|
||||
if (d.v > 1) d.v = 1;
|
||||
const ch = d.date.weekday === 0 || d.date.weekday === 6 ? 275 : 170;
|
||||
const cs = d.v * 100;
|
||||
const cl = 15 + (1 - d.v) * 80;
|
||||
d.color = `hsl(${ch}, ${cs}%, ${cl}%)`;
|
||||
|
||||
if (d.date.weekday === 0) x--;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
svg {
|
||||
display: block;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
> rect {
|
||||
transform-origin: center;
|
||||
|
||||
&.day {
|
||||
&:hover {
|
||||
fill: rgba(#000, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,136 +0,0 @@
|
|||
<template>
|
||||
<svg
|
||||
:viewBox="`0 0 ${viewBoxX} ${viewBoxY}`"
|
||||
@mousedown.prevent="onMousedown"
|
||||
>
|
||||
<polyline
|
||||
:points="pointsNote"
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#c4a7e7"
|
||||
/>
|
||||
<polyline
|
||||
:points="pointsReply"
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#eb6f92"
|
||||
/>
|
||||
<polyline
|
||||
:points="pointsRenote"
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#ebbcba"
|
||||
/>
|
||||
<polyline
|
||||
:points="pointsTotal"
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#6e6a86"
|
||||
stroke-dasharray="2 2"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
activity: any[];
|
||||
}>();
|
||||
|
||||
const viewBoxX: number = ref(147);
|
||||
const viewBoxY: number = ref(60);
|
||||
const zoom: number = ref(1);
|
||||
const pos: number = ref(0);
|
||||
const pointsNote: any = ref(null);
|
||||
const pointsReply: any = ref(null);
|
||||
const pointsRenote: any = ref(null);
|
||||
const pointsTotal: any = ref(null);
|
||||
|
||||
function dragListen(fn) {
|
||||
window.addEventListener("mousemove", fn);
|
||||
window.addEventListener("mouseleave", dragClear.bind(null, fn));
|
||||
window.addEventListener("mouseup", dragClear.bind(null, fn));
|
||||
}
|
||||
|
||||
function dragClear(fn) {
|
||||
window.removeEventListener("mousemove", fn);
|
||||
window.removeEventListener("mouseleave", dragClear);
|
||||
window.removeEventListener("mouseup", dragClear);
|
||||
}
|
||||
|
||||
function onMousedown(ev) {
|
||||
const clickX = ev.clientX;
|
||||
const clickY = ev.clientY;
|
||||
const baseZoom = zoom.value;
|
||||
const basePos = pos.value;
|
||||
|
||||
// 動かした時
|
||||
dragListen((me) => {
|
||||
const moveLeft = me.clientX - clickX;
|
||||
const moveTop = me.clientY - clickY;
|
||||
|
||||
zoom.value = Math.max(1, baseZoom + -moveTop / 20);
|
||||
pos.value = Math.min(0, basePos + moveLeft);
|
||||
if (
|
||||
pos.value <
|
||||
-((props.activity.length - 1) * zoom.value - viewBoxX.value)
|
||||
)
|
||||
pos.value = -(
|
||||
(props.activity.length - 1) * zoom.value -
|
||||
viewBoxX.value
|
||||
);
|
||||
|
||||
render();
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
const peak = Math.max(...props.activity.map((d) => d.total));
|
||||
if (peak !== 0) {
|
||||
const activity = props.activity.slice().reverse();
|
||||
pointsNote.value = activity
|
||||
.map(
|
||||
(d, i) =>
|
||||
`${i * zoom.value + pos.value},${
|
||||
(1 - d.notes / peak) * viewBoxY.value
|
||||
}`,
|
||||
)
|
||||
.join(" ");
|
||||
pointsReply.value = activity
|
||||
.map(
|
||||
(d, i) =>
|
||||
`${i * zoom.value + pos.value},${
|
||||
(1 - d.replies / peak) * viewBoxY.value
|
||||
}`,
|
||||
)
|
||||
.join(" ");
|
||||
pointsRenote.value = activity
|
||||
.map(
|
||||
(d, i) =>
|
||||
`${i * zoom.value + pos.value},${
|
||||
(1 - d.renotes / peak) * viewBoxY.value
|
||||
}`,
|
||||
)
|
||||
.join(" ");
|
||||
pointsTotal.value = activity
|
||||
.map(
|
||||
(d, i) =>
|
||||
`${i * zoom.value + pos.value},${
|
||||
(1 - d.total / peak) * viewBoxY.value
|
||||
}`,
|
||||
)
|
||||
.join(" ");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
svg {
|
||||
display: block;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
cursor: all-scroll;
|
||||
}
|
||||
</style>
|
|
@ -1,121 +0,0 @@
|
|||
<template>
|
||||
<MkContainer
|
||||
:show-header="widgetProps.showHeader"
|
||||
:naked="widgetProps.transparent"
|
||||
class="mkw-activity"
|
||||
>
|
||||
<template #header
|
||||
><i :class="icon('ph-chart-bar')"></i
|
||||
>{{ i18n.ts._widgets.activity }}</template
|
||||
>
|
||||
<template #func
|
||||
><button
|
||||
v-if="!widgetProps.newStyle"
|
||||
class="_button"
|
||||
@click="toggleView()"
|
||||
>
|
||||
<i :class="icon('ph-sort-ascending')"></i></button
|
||||
></template>
|
||||
|
||||
<div v-if="widgetProps.newStyle">
|
||||
<MkHeatmap src="my-notes" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<MkLoading v-if="fetching" />
|
||||
<template v-else>
|
||||
<XCalendar
|
||||
v-show="widgetProps.view === 0"
|
||||
:activity="[].concat(activity)"
|
||||
/>
|
||||
<XChart
|
||||
v-show="widgetProps.view === 1"
|
||||
:activity="[].concat(activity)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</MkContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import type { Widget, WidgetComponentExpose } from "./widget";
|
||||
import { useWidgetPropsManager } from "./widget";
|
||||
import XCalendar from "./activity.calendar.vue";
|
||||
import XChart from "./activity.chart.vue";
|
||||
import MkHeatmap from "@/components/MkHeatmap.vue";
|
||||
import type { GetFormResultType } from "@/scripts/form";
|
||||
import * as os from "@/os";
|
||||
import MkContainer from "@/components/MkContainer.vue";
|
||||
import { $i } from "@/reactiveAccount";
|
||||
import { i18n } from "@/i18n";
|
||||
import icon from "@/scripts/icon";
|
||||
|
||||
const name = "activity";
|
||||
|
||||
const widgetPropsDef = {
|
||||
newStyle: {
|
||||
type: "boolean" as const,
|
||||
default: true,
|
||||
},
|
||||
showHeader: {
|
||||
type: "boolean" as const,
|
||||
default: true,
|
||||
},
|
||||
transparent: {
|
||||
type: "boolean" as const,
|
||||
default: false,
|
||||
},
|
||||
view: {
|
||||
type: "number" as const,
|
||||
default: 0,
|
||||
hidden: true,
|
||||
},
|
||||
};
|
||||
|
||||
type WidgetProps = GetFormResultType<typeof widgetPropsDef>;
|
||||
|
||||
// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない
|
||||
// const props = defineProps<WidgetComponentProps<WidgetProps>>();
|
||||
// const emit = defineEmits<WidgetComponentEmits<WidgetProps>>();
|
||||
const props = defineProps<{ widget?: Widget<WidgetProps> }>();
|
||||
const emit = defineEmits<{ (ev: "updateProps", props: WidgetProps) }>();
|
||||
|
||||
const { widgetProps, configure, save } = useWidgetPropsManager(
|
||||
name,
|
||||
widgetPropsDef,
|
||||
props,
|
||||
emit,
|
||||
);
|
||||
|
||||
const activity = ref(null);
|
||||
const fetching = ref(true);
|
||||
|
||||
const toggleView = () => {
|
||||
if (widgetProps.view === 1) {
|
||||
widgetProps.view = 0;
|
||||
} else {
|
||||
widgetProps.view++;
|
||||
}
|
||||
save();
|
||||
};
|
||||
|
||||
os.apiGet("charts/user/notes", {
|
||||
userId: $i.id,
|
||||
span: "day",
|
||||
limit: 7 * 21,
|
||||
}).then((res) => {
|
||||
activity.value = res.diffs.normal.map((_, i) => ({
|
||||
total: res.diffs.normal[i] + res.diffs.reply[i] + res.diffs.renote[i],
|
||||
notes: res.diffs.normal[i],
|
||||
replies: res.diffs.reply[i],
|
||||
renotes: res.diffs.renote[i],
|
||||
}));
|
||||
fetching.value = false;
|
||||
});
|
||||
|
||||
defineExpose<WidgetComponentExpose>({
|
||||
name,
|
||||
configure,
|
||||
id: props.widget ? props.widget.id : null,
|
||||
});
|
||||
</script>
|
|
@ -37,10 +37,6 @@
|
|||
{{ instance.softwareVersion }}
|
||||
</p>
|
||||
</div>
|
||||
<MkMiniChart
|
||||
class="chart"
|
||||
:src="charts[i].requests.received"
|
||||
/>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
|
@ -53,7 +49,6 @@ import type { Widget, WidgetComponentExpose } from "./widget";
|
|||
import { useWidgetPropsManager } from "./widget";
|
||||
import type { GetFormResultType } from "@/scripts/form";
|
||||
import MkContainer from "@/components/MkContainer.vue";
|
||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||
import * as os from "@/os";
|
||||
import { useInterval } from "@/scripts/use-interval";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -90,7 +85,6 @@ const { widgetProps, configure } = useWidgetPropsManager(
|
|||
);
|
||||
|
||||
const instances = ref([]);
|
||||
const charts = ref([]);
|
||||
const fetching = ref(true);
|
||||
|
||||
const fetch = async () => {
|
||||
|
@ -98,17 +92,7 @@ const fetch = async () => {
|
|||
sort: "+lastCommunicatedAt",
|
||||
limit: 5,
|
||||
});
|
||||
const fetchedCharts = await Promise.all(
|
||||
fetchedInstances.map((i) =>
|
||||
os.apiGet("charts/instance", {
|
||||
host: i.host,
|
||||
limit: 16,
|
||||
span: "hour",
|
||||
}),
|
||||
),
|
||||
);
|
||||
instances.value = fetchedInstances;
|
||||
charts.value = fetchedCharts;
|
||||
fetching.value = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -34,10 +34,6 @@ export default function (app: App) {
|
|||
"MkwClock",
|
||||
defineAsyncComponent(() => import("./clock.vue")),
|
||||
);
|
||||
app.component(
|
||||
"MkwActivity",
|
||||
defineAsyncComponent(() => import("./activity.vue")),
|
||||
);
|
||||
app.component(
|
||||
"MkwPhotos",
|
||||
defineAsyncComponent(() => import("./photos.vue")),
|
||||
|
@ -106,7 +102,6 @@ export const widgets = [
|
|||
"rssTicker",
|
||||
"trends",
|
||||
"clock",
|
||||
"activity",
|
||||
"photos",
|
||||
"digitalClock",
|
||||
"unixClock",
|
||||
|
|
|
@ -216,185 +216,6 @@ export type Endpoints = {
|
|||
};
|
||||
};
|
||||
};
|
||||
"charts/drive": {
|
||||
req: { span: "day" | "hour"; limit?: number; offset?: number | null };
|
||||
res: {
|
||||
local: {
|
||||
decCount: number[];
|
||||
decSize: number[];
|
||||
incCount: number[];
|
||||
incSize: number[];
|
||||
totalCount: number[];
|
||||
totalSize: number[];
|
||||
};
|
||||
remote: {
|
||||
decCount: number[];
|
||||
decSize: number[];
|
||||
incCount: number[];
|
||||
incSize: number[];
|
||||
totalCount: number[];
|
||||
totalSize: number[];
|
||||
};
|
||||
};
|
||||
};
|
||||
"charts/federation": {
|
||||
req: { span: "day" | "hour"; limit?: number; offset?: number | null };
|
||||
res: {
|
||||
instance: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
};
|
||||
};
|
||||
};
|
||||
"charts/hashtag": {
|
||||
req: { span: "day" | "hour"; limit?: number; offset?: number | null };
|
||||
res: TODO;
|
||||
};
|
||||
"charts/instance": {
|
||||
req: {
|
||||
span: "day" | "hour";
|
||||
limit?: number;
|
||||
offset?: number | null;
|
||||
host: string;
|
||||
};
|
||||
res: {
|
||||
drive: {
|
||||
decFiles: number[];
|
||||
decUsage: number[];
|
||||
incFiles: number[];
|
||||
incUsage: number[];
|
||||
totalFiles: number[];
|
||||
totalUsage: number[];
|
||||
};
|
||||
followers: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
};
|
||||
following: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
};
|
||||
notes: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
diffs: {
|
||||
normal: number[];
|
||||
renote: number[];
|
||||
reply: number[];
|
||||
};
|
||||
};
|
||||
requests: {
|
||||
failed: number[];
|
||||
received: number[];
|
||||
succeeded: number[];
|
||||
};
|
||||
users: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
};
|
||||
};
|
||||
};
|
||||
"charts/network": {
|
||||
req: { span: "day" | "hour"; limit?: number; offset?: number | null };
|
||||
res: TODO;
|
||||
};
|
||||
"charts/notes": {
|
||||
req: { span: "day" | "hour"; limit?: number; offset?: number | null };
|
||||
res: {
|
||||
local: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
diffs: {
|
||||
normal: number[];
|
||||
renote: number[];
|
||||
reply: number[];
|
||||
};
|
||||
};
|
||||
remote: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
diffs: {
|
||||
normal: number[];
|
||||
renote: number[];
|
||||
reply: number[];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"charts/user/drive": {
|
||||
req: {
|
||||
span: "day" | "hour";
|
||||
limit?: number;
|
||||
offset?: number | null;
|
||||
userId: User["id"];
|
||||
};
|
||||
res: {
|
||||
decCount: number[];
|
||||
decSize: number[];
|
||||
incCount: number[];
|
||||
incSize: number[];
|
||||
totalCount: number[];
|
||||
totalSize: number[];
|
||||
};
|
||||
};
|
||||
"charts/user/following": {
|
||||
req: {
|
||||
span: "day" | "hour";
|
||||
limit?: number;
|
||||
offset?: number | null;
|
||||
userId: User["id"];
|
||||
};
|
||||
res: TODO;
|
||||
};
|
||||
"charts/user/notes": {
|
||||
req: {
|
||||
span: "day" | "hour";
|
||||
limit?: number;
|
||||
offset?: number | null;
|
||||
userId: User["id"];
|
||||
};
|
||||
res: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
diffs: {
|
||||
normal: number[];
|
||||
renote: number[];
|
||||
reply: number[];
|
||||
};
|
||||
};
|
||||
};
|
||||
"charts/user/reactions": {
|
||||
req: {
|
||||
span: "day" | "hour";
|
||||
limit?: number;
|
||||
offset?: number | null;
|
||||
userId: User["id"];
|
||||
};
|
||||
res: TODO;
|
||||
};
|
||||
"charts/users": {
|
||||
req: { span: "day" | "hour"; limit?: number; offset?: number | null };
|
||||
res: {
|
||||
local: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
};
|
||||
remote: {
|
||||
dec: number[];
|
||||
inc: number[];
|
||||
total: number[];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// clips
|
||||
"clips/add-note": { req: TODO; res: TODO };
|
||||
|
|
Loading…
Reference in a new issue