wip
This commit is contained in:
parent
678b718c24
commit
8785621fcf
|
@ -593,4 +593,35 @@ export class NoteEntityService implements OnModuleInit {
|
|||
relations: ['user'],
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async ogogogo(noteIds: MiNote['id'][]) {
|
||||
if (noteIds.length === 0) return [];
|
||||
|
||||
const notes = await this.notesRepository.find({
|
||||
where: {
|
||||
id: In(noteIds),
|
||||
},
|
||||
select: {
|
||||
reactions: true,
|
||||
reactionAndUserPairCache: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(notes);
|
||||
|
||||
const bufferedReactionsMap = this.meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(noteIds) : null;
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const note of notes) {
|
||||
const bufferedReactions = bufferedReactionsMap?.get(note.id);
|
||||
const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferedReactions.pairs.map(x => x.join('/')));
|
||||
|
||||
results.push({
|
||||
id: note.id,
|
||||
reactions: this.reactionService.convertLegacyReactions(this.reactionsBufferingService.mergeReactions(note.reactions, bufferedReactions.deltas ?? {})),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { GetterService } from '@/server/api/GetterService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
|
||||
errors: {
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
noteIds: { type: 'array', items: { type: 'string', format: 'misskey:id' }, maxItems: 100, minItems: 1 },
|
||||
},
|
||||
required: ['noteIds'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
|
@ -514,7 +514,10 @@ function react(): void {
|
|||
misskeyApi('notes/reactions/create', {
|
||||
noteId: appearNote.value.id,
|
||||
reaction: reaction,
|
||||
}).then(() => {
|
||||
// 別にthenを待たなくても良いかも(楽観的更新)
|
||||
});
|
||||
|
||||
if (appearNote.value.text && appearNote.value.text.length > 100 && (Date.now() - new Date(appearNote.value.createdAt).getTime() < 1000 * 3)) {
|
||||
claimAchievement('reactWithoutRead');
|
||||
}
|
||||
|
|
|
@ -5,12 +5,32 @@
|
|||
|
||||
import { onUnmounted } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import type { Ref, ShallowRef } from 'vue';
|
||||
import { useStream } from '@/stream.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { store } from '@/store.js';
|
||||
|
||||
export function useNoteCapture(props: {
|
||||
const noteEvents = new EventEmitter<{
|
||||
reacted: Misskey.entities.Note;
|
||||
unreacted: Misskey.entities.Note;
|
||||
pollVoted: Misskey.entities.Note;
|
||||
deleted: Misskey.entities.Note;
|
||||
}>();
|
||||
|
||||
const capturedNoteIdMapForPolling = new Map<string, number>();
|
||||
|
||||
const POLLING_INTERVAL = 1000 * 10;
|
||||
|
||||
window.setInterval(() => {
|
||||
const ids = [...capturedNoteIdMapForPolling.keys()];
|
||||
if (ids.length === 0) return;
|
||||
if (window.document.hidden) return;
|
||||
|
||||
console.log('Polling notes', ids);
|
||||
}, POLLING_INTERVAL);
|
||||
|
||||
function pseudoNoteCapture(props: {
|
||||
rootEl: ShallowRef<HTMLElement | undefined>;
|
||||
note: Ref<Misskey.entities.Note>;
|
||||
pureNote: Ref<Misskey.entities.Note>;
|
||||
|
@ -18,7 +38,34 @@ export function useNoteCapture(props: {
|
|||
}) {
|
||||
const note = props.note;
|
||||
const pureNote = props.pureNote;
|
||||
const connection = $i && store.s.realtimeMode ? useStream() : null;
|
||||
|
||||
function onReacted(): void {
|
||||
|
||||
}
|
||||
|
||||
if (capturedNoteIdMapForPolling.has(note.value.id)) {
|
||||
capturedNoteIdMapForPolling.set(note.value.id, capturedNoteIdMapForPolling.get(note.value.id)! + 1);
|
||||
} else {
|
||||
capturedNoteIdMapForPolling.set(note.value.id, 1);
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
capturedNoteIdMapForPolling.set(note.value.id, capturedNoteIdMapForPolling.get(note.value.id)! - 1);
|
||||
if (capturedNoteIdMapForPolling.get(note.value.id) === 0) {
|
||||
capturedNoteIdMapForPolling.delete(note.value.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function realtimeNoteCapture(props: {
|
||||
rootEl: ShallowRef<HTMLElement | undefined>;
|
||||
note: Ref<Misskey.entities.Note>;
|
||||
pureNote: Ref<Misskey.entities.Note>;
|
||||
isDeletedRef: Ref<boolean>;
|
||||
}): void {
|
||||
const note = props.note;
|
||||
const pureNote = props.pureNote;
|
||||
const connection = useStream();
|
||||
|
||||
function onStreamNoteUpdated(noteData): void {
|
||||
const { type, id, body } = noteData;
|
||||
|
@ -85,26 +132,22 @@ export function useNoteCapture(props: {
|
|||
}
|
||||
|
||||
function capture(withHandler = false): void {
|
||||
if (connection) {
|
||||
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
||||
connection.send(window.document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id });
|
||||
if (pureNote.value.id !== note.value.id) connection.send('s', { id: pureNote.value.id });
|
||||
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
||||
}
|
||||
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
||||
connection.send(window.document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id });
|
||||
if (pureNote.value.id !== note.value.id) connection.send('s', { id: pureNote.value.id });
|
||||
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
||||
}
|
||||
|
||||
function decapture(withHandler = false): void {
|
||||
if (connection) {
|
||||
connection.send('un', {
|
||||
id: note.value.id,
|
||||
});
|
||||
if (pureNote.value.id !== note.value.id) {
|
||||
connection.send('un', {
|
||||
id: note.value.id,
|
||||
id: pureNote.value.id,
|
||||
});
|
||||
if (pureNote.value.id !== note.value.id) {
|
||||
connection.send('un', {
|
||||
id: pureNote.value.id,
|
||||
});
|
||||
}
|
||||
if (withHandler) connection.off('noteUpdated', onStreamNoteUpdated);
|
||||
}
|
||||
if (withHandler) connection.off('noteUpdated', onStreamNoteUpdated);
|
||||
}
|
||||
|
||||
function onStreamConnected() {
|
||||
|
@ -112,14 +155,23 @@ export function useNoteCapture(props: {
|
|||
}
|
||||
|
||||
capture(true);
|
||||
if (connection) {
|
||||
connection.on('_connected_', onStreamConnected);
|
||||
}
|
||||
connection.on('_connected_', onStreamConnected);
|
||||
|
||||
onUnmounted(() => {
|
||||
decapture(true);
|
||||
if (connection) {
|
||||
connection.off('_connected_', onStreamConnected);
|
||||
}
|
||||
connection.off('_connected_', onStreamConnected);
|
||||
});
|
||||
}
|
||||
|
||||
export function useNoteCapture(props: {
|
||||
rootEl: ShallowRef<HTMLElement | undefined>;
|
||||
note: Ref<Misskey.entities.Note>;
|
||||
pureNote: Ref<Misskey.entities.Note>;
|
||||
isDeletedRef: Ref<boolean>;
|
||||
}) {
|
||||
if ($i && store.s.realtimeMode) {
|
||||
realtimeNoteCapture(props);
|
||||
} else {
|
||||
pseudoNoteCapture(props);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue