Files
reader/examples/plugins/demo-chapters/main.mjs

55 lines
2.2 KiB
JavaScript

import { createInterface } from 'node:readline';
const entry = {
ref: 'demo-book',
title: '插件示例书',
authors: ['Reader'],
description: '用于验证外部插件的发现、获取和章节阅读协议。',
};
const methods = {
validateConfig: () => null,
browse: () => ({ title: '示例书库', items: [entry] }),
search: ({ request }) => ({ items: entry.title.includes(request.query) ? [entry] : [] }),
detail: ({ entryRef }) => {
if (entryRef !== entry.ref) throw Object.assign(new Error('书籍不存在'), { code: 'RESOURCE_GONE' });
return entry;
},
acquire: ({ request }) => {
if (request.entryRef !== entry.ref) throw Object.assign(new Error('书籍不存在'), { code: 'RESOURCE_GONE' });
return { kind: 'chapters', publicationRef: entry.ref };
},
getManifest: ({ publicationRef }) => {
if (publicationRef !== entry.ref) throw Object.assign(new Error('书籍不存在'), { code: 'RESOURCE_GONE' });
return {
publicationRef,
version: '1',
items: [{ id: 'chapter-one', seq: 0, title: '第一章', kind: 'chapter', mediaType: 'text/plain', ref: 'chapter-one' }],
};
},
readResource: ({ request }) => {
if (request.publicationRef !== entry.ref || request.ref !== 'chapter-one') {
throw Object.assign(new Error('章节不存在'), { code: 'RESOURCE_GONE' });
}
return { mediaType: 'text/plain; charset=utf-8', text: '第一章\n\n这是通过独立 Node 进程提供的示例章节。' };
},
};
const input = createInterface({ input: process.stdin, crlfDelay: Infinity });
for await (const line of input) {
let request;
try {
request = JSON.parse(line);
if (request.method === '$/cancelRequest') continue;
const method = methods[request.method];
if (!method) throw Object.assign(new Error('不支持的方法'), { code: 'UNSUPPORTED_OPERATION' });
const result = await method(request.params);
process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result }) + '\n');
} catch (error) {
process.stdout.write(JSON.stringify({
jsonrpc: '2.0', id: request?.id,
error: { code: error.code ?? 'PLUGIN_ERROR', message: error.message },
}) + '\n');
}
}