Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
626d64631e | ||
![]() |
608fa287c7 | ||
![]() |
a35d01ee0f | ||
![]() |
77c9b90e6d | ||
![]() |
2f8992f98a | ||
![]() |
c8ab0e9d62 | ||
![]() |
072bc2d9fb | ||
![]() |
cc7fec4b9f | ||
![]() |
570931cff8 | ||
![]() |
88ec15d4c7 | ||
![]() |
c23c8ae4c3 | ||
![]() |
92af4401e2 |
@@ -79,6 +79,8 @@ redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
#pass: example-pass
|
||||
#prefix: example-prefix
|
||||
#db: 1
|
||||
|
||||
# ┌─────────────────────────────┐
|
||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||
|
@@ -1,6 +1,13 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
11.35.1 (2019/11/05)
|
||||
--------------------
|
||||
### 🐛Fixes
|
||||
* リモートのフォローボタンを押してmisskeyインスタンスを入力したとき正しく動作しない問題を修正
|
||||
* リアクション設定で改行ができない問題を修正
|
||||
* nodeinfoのmetadataを一般的なものに修正
|
||||
|
||||
11.35.0 (2019/11/01)
|
||||
--------------------
|
||||
### ✨Improvements
|
||||
|
@@ -167,7 +167,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||
</tr></table>
|
||||
|
||||
**Last updated:** Thu, 31 Oct 2019 06:09:07 UTC
|
||||
**Last updated:** Sat, 02 Nov 2019 18:09:05 UTC
|
||||
<!-- PATREON_END -->
|
||||
|
||||
:four_leaf_clover: Copyright
|
||||
|
@@ -96,7 +96,7 @@ gulp.task('cleanall', gulp.parallel('clean', cb =>
|
||||
));
|
||||
|
||||
gulp.task('build:client:script', () => {
|
||||
const client = require('./built/client/meta.json');
|
||||
const client = require('./built/meta.json');
|
||||
return gulp.src(['./src/client/app/boot.js', './src/client/app/safe.js'])
|
||||
.pipe(replace('VERSION', JSON.stringify(client.version)))
|
||||
.pipe(replace('ENV', JSON.stringify(env)))
|
||||
|
@@ -312,6 +312,7 @@ common:
|
||||
sync: "同期"
|
||||
save: "保存"
|
||||
saved: "保存しました"
|
||||
preview: "プレビュー"
|
||||
home-profile: "ホームのプロファイル"
|
||||
deck-profile: "デッキのプロファイル"
|
||||
room: "ルーム"
|
||||
|
29
migration/1572760203493-nodeinfo.ts
Normal file
29
migration/1572760203493-nodeinfo.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class nodeinfo1572760203493 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "system"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "softwareName" character varying(64) DEFAULT null`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "softwareVersion" character varying(64) DEFAULT null`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "openRegistrations" boolean DEFAULT null`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "name" character varying(256) DEFAULT null`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "description" character varying(4096) DEFAULT null`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "maintainerName" character varying(128) DEFAULT null`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "maintainerEmail" character varying(256) DEFAULT null`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "infoUpdatedAt" TIMESTAMP WITH TIME ZONE`, undefined);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "infoUpdatedAt"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "maintainerEmail"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "maintainerName"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "description"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "name"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "openRegistrations"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "softwareVersion"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "softwareName"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "system" character varying(64)`, undefined);
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "11.35.0",
|
||||
"version": "11.35.1",
|
||||
"codename": "daybreak",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -103,7 +103,7 @@
|
||||
"@typescript-eslint/parser": "2.3.3",
|
||||
"agentkeepalive": "4.1.0",
|
||||
"animejs": "3.1.0",
|
||||
"apexcharts": "3.10.0",
|
||||
"apexcharts": "3.10.1",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autosize": "4.0.2",
|
||||
"autwh": "0.1.0",
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import * as program from 'commander';
|
||||
import * as pkg from '../package.json';
|
||||
import config from './config';
|
||||
|
||||
program
|
||||
.version(pkg.version)
|
||||
.version(config.version)
|
||||
.option('--no-daemons', 'Disable daemon processes (for debbuging)')
|
||||
.option('--disable-clustering', 'Disable clustering')
|
||||
.option('--only-server', 'Run server only (without job queue processing)')
|
||||
|
@@ -8,7 +8,6 @@ import Logger from '../services/logger';
|
||||
import loadConfig from '../config/load';
|
||||
import { Config } from '../config/types';
|
||||
import { lessThan } from '../prelude/array';
|
||||
import * as pkg from '../../package.json';
|
||||
import { program } from '../argv';
|
||||
import { showMachineInfo } from '../misc/show-machine-info';
|
||||
import { initDb } from '../db/postgre';
|
||||
@@ -16,10 +15,10 @@ import { initDb } from '../db/postgre';
|
||||
const logger = new Logger('core', 'cyan');
|
||||
const bootLogger = logger.createSubLogger('boot', 'magenta', false);
|
||||
|
||||
function greet() {
|
||||
function greet(config: Config) {
|
||||
if (!program.quiet) {
|
||||
//#region Misskey logo
|
||||
const v = `v${pkg.version}`;
|
||||
const v = `v${config.version}`;
|
||||
console.log(' _____ _ _ ');
|
||||
console.log(' | |_|___ ___| |_ ___ _ _ ');
|
||||
console.log(' | | | | |_ -|_ -| \'_| -_| | |');
|
||||
@@ -35,21 +34,21 @@ function greet() {
|
||||
}
|
||||
|
||||
bootLogger.info('Welcome to Misskey!');
|
||||
bootLogger.info(`Misskey v${pkg.version}`, null, true);
|
||||
bootLogger.info(`Misskey v${config.version}`, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init master process
|
||||
*/
|
||||
export async function masterMain() {
|
||||
greet();
|
||||
|
||||
let config!: Config;
|
||||
|
||||
try {
|
||||
// initialize app
|
||||
config = await init();
|
||||
|
||||
greet(config);
|
||||
|
||||
if (config.port == null || Number.isNaN(config.port)) {
|
||||
bootLogger.error('The port is not configured. Please configure port.', null, true);
|
||||
process.exit(1);
|
||||
|
@@ -145,13 +145,18 @@ export default (opts: Opts = {}) => ({
|
||||
this.blur();
|
||||
const w = this.$root.new(MkReactionPicker, {
|
||||
source: this.$refs.reactButton,
|
||||
note: this.appearNote,
|
||||
showFocus: viaKeyboard,
|
||||
animation: !viaKeyboard
|
||||
}).$once('closed', this.focus);
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
w.close();
|
||||
});
|
||||
w.$once('chosen', reaction => {
|
||||
this.$root.api('notes/reactions/create', {
|
||||
noteId: this.appearNote.id,
|
||||
reaction: reaction
|
||||
}).then(() => {
|
||||
w.close();
|
||||
});
|
||||
});
|
||||
w.$once('closed', this.focus);
|
||||
},
|
||||
|
||||
reactDirectly(reaction) {
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<div class="popover" :class="{ isMobile: $root.isMobile }" ref="popover">
|
||||
<p v-if="!$root.isMobile">{{ title }}</p>
|
||||
<div class="buttons" ref="buttons" :class="{ showFocus }">
|
||||
<button v-for="(reaction, i) in $store.state.settings.reactions" :key="reaction" @click="react(reaction)" @mouseover="onMouseover" @mouseout="onMouseout" :tabindex="i + 1" :title="/^[a-z]+$/.test(reaction) ? $t('@.reactions.' + reaction) : reaction" v-particle><mk-reaction-icon :reaction="reaction"/></button>
|
||||
<button v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" @mouseover="onMouseover" @mouseout="onMouseout" :tabindex="i + 1" :title="/^[a-z]+$/.test(reaction) ? $t('@.reactions.' + reaction) : reaction" v-particle><mk-reaction-icon :reaction="reaction"/></button>
|
||||
</div>
|
||||
<div v-if="enableEmojiReaction" class="text">
|
||||
<input v-model="text" :placeholder="$t('input-reaction-placeholder')" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
|
||||
@@ -22,16 +22,11 @@ import { emojiRegex } from '../../../../../misc/emoji-regex';
|
||||
export default Vue.extend({
|
||||
i18n: i18n('common/views/components/reaction-picker.vue'),
|
||||
props: {
|
||||
note: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
|
||||
source: {
|
||||
required: true
|
||||
},
|
||||
|
||||
cb: {
|
||||
reactions: {
|
||||
required: false
|
||||
},
|
||||
|
||||
@@ -50,6 +45,7 @@ export default Vue.extend({
|
||||
|
||||
data() {
|
||||
return {
|
||||
rs: this.reactions || this.$store.state.settings.reactions,
|
||||
title: this.$t('choose-reaction'),
|
||||
text: null,
|
||||
enableEmojiReaction: false,
|
||||
@@ -134,14 +130,7 @@ export default Vue.extend({
|
||||
|
||||
methods: {
|
||||
react(reaction) {
|
||||
this.$root.api('notes/reactions/create', {
|
||||
noteId: this.note.id,
|
||||
reaction: reaction
|
||||
}).then(() => {
|
||||
if (this.cb) this.cb();
|
||||
this.$emit('closed');
|
||||
this.destroyDom();
|
||||
});
|
||||
this.$emit('chosen', reaction);
|
||||
},
|
||||
|
||||
reactText() {
|
||||
|
@@ -113,6 +113,10 @@
|
||||
<ui-textarea v-model="reactions">
|
||||
{{ $t('@._settings.reactions') }}<template #desc>{{ $t('@._settings.reactions-description') }}</template>
|
||||
</ui-textarea>
|
||||
<ui-horizon-group>
|
||||
<ui-button @click="save('reactions', reactions.trim().split('\n'))" primary><fa :icon="faSave"/> {{ $t('@._settings.save') }}</ui-button>
|
||||
<ui-button @click="previewReaction()" ref="reactionsPreviewButton"><fa :icon="faEye"/> {{ $t('@._settings.preview') }}</ui-button>
|
||||
</ui-horizon-group>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -311,11 +315,12 @@ import XApi from './api.vue';
|
||||
import XLanguage from './language.vue';
|
||||
import XAppType from './app-type.vue';
|
||||
import XNotification from './notification.vue';
|
||||
import MkReactionPicker from '../reaction-picker.vue';
|
||||
|
||||
import { url, version } from '../../../../config';
|
||||
import checkForUpdate from '../../../scripts/check-for-update';
|
||||
import { formatTimeString } from '../../../../../../misc/format-time-string';
|
||||
import { faSave } from '@fortawesome/free-regular-svg-icons';
|
||||
import { faSave, faEye } from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n(),
|
||||
@@ -346,11 +351,12 @@ export default Vue.extend({
|
||||
return {
|
||||
meta: null,
|
||||
version,
|
||||
reactions: this.$store.state.settings.reactions.join('\n'),
|
||||
webSearchEngine: this.$store.state.settings.webSearchEngine,
|
||||
pastedFileName : this.$store.state.settings.pastedFileName,
|
||||
latestVersion: undefined,
|
||||
checkingForUpdate: false,
|
||||
faSave
|
||||
faSave, faEye
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -414,11 +420,6 @@ export default Vue.extend({
|
||||
set(value) { this.$store.dispatch('settings/set', { key: 'disableViaMobile', value }); }
|
||||
},
|
||||
|
||||
reactions: {
|
||||
get() { return this.$store.state.settings.reactions.join('\n'); },
|
||||
set(value: string) { this.$store.dispatch('settings/set', { key: 'reactions', value: value.trim().split('\n') }); }
|
||||
},
|
||||
|
||||
useShadow: {
|
||||
get() { return this.$store.state.device.useShadow; },
|
||||
set(value) { this.$store.commit('device/set', { key: 'useShadow', value }); }
|
||||
@@ -655,6 +656,16 @@ export default Vue.extend({
|
||||
pastedFileNamePreview() {
|
||||
return `${formatTimeString(new Date(), this.pastedFileName).replace(/{{number}}/g, `1`)}.png`
|
||||
},
|
||||
previewReaction() {
|
||||
const picker = this.$root.new(MkReactionPicker, {
|
||||
source: this.$refs.reactionsPreviewButton.$el,
|
||||
reactions: this.reactions.trim().split('\n'),
|
||||
showFocus: false,
|
||||
});
|
||||
picker.$once('chosen', reaction => {
|
||||
picker.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@@ -72,11 +72,40 @@ export default Vue.extend({
|
||||
const acct = new URL(location.href).searchParams.get('acct');
|
||||
this.fetching = true;
|
||||
Progress.start();
|
||||
this.$root.api('users/show', parseAcct(acct)).then(user => {
|
||||
this.user = user;
|
||||
this.fetching = false;
|
||||
Progress.done();
|
||||
});
|
||||
if (acct.match(/^https?:/)) {
|
||||
this.$root.api('ap/show', {
|
||||
uri: acct
|
||||
}).then((res: { type: string, object: any }) => {
|
||||
if (res.type !== 'User') {
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: 'acct is not an user'
|
||||
});
|
||||
} else {
|
||||
this.user = res.object;
|
||||
}
|
||||
}).catch((e: any) => {
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: e.message
|
||||
});
|
||||
}).finally(() => {
|
||||
this.fetching = false;
|
||||
Progress.done();
|
||||
});
|
||||
} else {
|
||||
this.$root.api('users/show', parseAcct(acct)).then((user: any) => {
|
||||
this.user = user;
|
||||
}).catch((e: any) => {
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: e.message
|
||||
});
|
||||
}).finally(() => {
|
||||
this.fetching = false;
|
||||
Progress.done();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async onClick() {
|
||||
|
@@ -5,7 +5,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as yaml from 'js-yaml';
|
||||
import { Source, Mixin } from './types';
|
||||
import * as pkg from '../../package.json';
|
||||
import * as meta from '../meta.json';
|
||||
|
||||
/**
|
||||
* Path of configuration directory
|
||||
@@ -30,6 +30,7 @@ export default function load() {
|
||||
|
||||
config.port = config.port || parseInt(process.env.PORT || '', 10);
|
||||
|
||||
mixin.version = meta.version;
|
||||
mixin.host = url.host;
|
||||
mixin.hostname = url.hostname;
|
||||
mixin.scheme = url.protocol.replace(/:$/, '');
|
||||
@@ -38,7 +39,7 @@ export default function load() {
|
||||
mixin.apiUrl = `${mixin.scheme}://${mixin.host}/api`;
|
||||
mixin.authUrl = `${mixin.scheme}://${mixin.host}/auth`;
|
||||
mixin.driveUrl = `${mixin.scheme}://${mixin.host}/files`;
|
||||
mixin.userAgent = `Misskey/${pkg.version} (${config.url})`;
|
||||
mixin.userAgent = `Misskey/${meta.version} (${config.url})`;
|
||||
|
||||
if (config.autoAdmin == null) config.autoAdmin = false;
|
||||
|
||||
|
@@ -58,6 +58,7 @@ export type Source = {
|
||||
* Misskeyが自動的に(ユーザーが設定した情報から推論して)設定する情報
|
||||
*/
|
||||
export type Mixin = {
|
||||
version: string;
|
||||
host: string;
|
||||
hostname: string;
|
||||
scheme: string;
|
||||
|
3
src/meta.json
Normal file
3
src/meta.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"version": "unknown"
|
||||
}
|
@@ -20,3 +20,7 @@ const lock: (key: string, timeout?: number) => Promise<() => void>
|
||||
export function getApLock(uri: string, timeout = 30 * 1000) {
|
||||
return lock(`ap-object:${uri}`, timeout);
|
||||
}
|
||||
|
||||
export function getNodeinfoLock(host: string, timeout = 30 * 1000) {
|
||||
return lock(`nodeinfo:${host}`, timeout);
|
||||
}
|
||||
|
@@ -25,15 +25,6 @@ export class Instance {
|
||||
})
|
||||
public host: string;
|
||||
|
||||
/**
|
||||
* インスタンスのシステム (MastodonとかMisskeyとかPleromaとか)
|
||||
*/
|
||||
@Column('varchar', {
|
||||
length: 64, nullable: true,
|
||||
comment: 'The system of the Instance.'
|
||||
})
|
||||
public system: string | null;
|
||||
|
||||
/**
|
||||
* インスタンスのユーザー数
|
||||
*/
|
||||
@@ -129,4 +120,45 @@ export class Instance {
|
||||
default: false
|
||||
})
|
||||
public isMarkedAsClosed: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 64, nullable: true, default: null,
|
||||
comment: 'The software of the Instance.'
|
||||
})
|
||||
public softwareName: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 64, nullable: true, default: null,
|
||||
})
|
||||
public softwareVersion: string | null;
|
||||
|
||||
@Column('boolean', {
|
||||
nullable: true, default: null,
|
||||
})
|
||||
public openRegistrations: boolean | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 256, nullable: true, default: null,
|
||||
})
|
||||
public name: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 4096, nullable: true, default: null,
|
||||
})
|
||||
public description: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128, nullable: true, default: null,
|
||||
})
|
||||
public maintainerName: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 256, nullable: true, default: null,
|
||||
})
|
||||
public maintainerEmail: string | null;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
nullable: true,
|
||||
})
|
||||
public infoUpdatedAt: Date | null;
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import { registerOrFetchInstanceDoc } from '../../services/register-or-fetch-ins
|
||||
import Logger from '../../services/logger';
|
||||
import { Instances } from '../../models';
|
||||
import { instanceChart } from '../../services/chart';
|
||||
import { fetchNodeinfo } from '../../services/fetch-nodeinfo';
|
||||
|
||||
const logger = new Logger('deliver');
|
||||
|
||||
@@ -28,6 +29,8 @@ export default async (job: Bull.Job) => {
|
||||
isNotResponding: false
|
||||
});
|
||||
|
||||
fetchNodeinfo(i);
|
||||
|
||||
instanceChart.requestSent(i.host, true);
|
||||
});
|
||||
|
||||
|
@@ -13,6 +13,7 @@ import { fetchMeta } from '../../misc/fetch-meta';
|
||||
import { toPuny } from '../../misc/convert-host';
|
||||
import { validActor } from '../../remote/activitypub/type';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { fetchNodeinfo } from '../../services/fetch-nodeinfo';
|
||||
|
||||
const logger = new Logger('inbox');
|
||||
|
||||
@@ -105,6 +106,8 @@ export default async (job: Bull.Job): Promise<void> => {
|
||||
isNotResponding: false
|
||||
});
|
||||
|
||||
fetchNodeinfo(i);
|
||||
|
||||
instanceChart.requestReceived(i.host);
|
||||
});
|
||||
|
||||
|
@@ -27,6 +27,7 @@ import { validActor } from '../../../remote/activitypub/type';
|
||||
import { getConnection } from 'typeorm';
|
||||
import { ensure } from '../../../prelude/ensure';
|
||||
import { toArray } from '../../../prelude/array';
|
||||
import { fetchNodeinfo } from '../../../services/fetch-nodeinfo';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
@@ -191,6 +192,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
|
||||
registerOrFetchInstanceDoc(host).then(i => {
|
||||
Instances.increment({ id: i.id }, 'usersCount', 1);
|
||||
instanceChart.newUser(i.host);
|
||||
fetchNodeinfo(i);
|
||||
});
|
||||
|
||||
usersChart.update(user!, true);
|
||||
|
@@ -3,7 +3,6 @@ import * as os from 'os';
|
||||
import config from '../../../config';
|
||||
import define from '../define';
|
||||
import { fetchMeta } from '../../../misc/fetch-meta';
|
||||
import * as pkg from '../../../../package.json';
|
||||
import { Emojis } from '../../../models';
|
||||
import { getConnection } from 'typeorm';
|
||||
import redis from '../../../db/redis';
|
||||
@@ -36,7 +35,7 @@ export const meta = {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The version of Misskey of this instance.',
|
||||
example: pkg.version
|
||||
example: config.version
|
||||
},
|
||||
name: {
|
||||
type: 'string' as const,
|
||||
@@ -114,7 +113,7 @@ export default define(meta, async (ps, me) => {
|
||||
maintainerName: instance.maintainerName,
|
||||
maintainerEmail: instance.maintainerEmail,
|
||||
|
||||
version: pkg.version,
|
||||
version: config.version,
|
||||
|
||||
name: instance.name,
|
||||
uri: config.url,
|
||||
|
@@ -2,7 +2,6 @@ import * as Router from '@koa/router';
|
||||
import config from '../config';
|
||||
import { fetchMeta } from '../misc/fetch-meta';
|
||||
// import User from '../models/user';
|
||||
import { name as softwareName, version, repository } from '../../package.json';
|
||||
// import Note from '../models/note';
|
||||
|
||||
const router = new Router();
|
||||
@@ -20,27 +19,7 @@ export const links = [/* (awaiting release) {
|
||||
|
||||
const nodeinfo2 = async () => {
|
||||
const [
|
||||
{
|
||||
name,
|
||||
description,
|
||||
maintainerName,
|
||||
maintainerEmail,
|
||||
langs,
|
||||
ToSUrl,
|
||||
repositoryUrl,
|
||||
feedbackUrl,
|
||||
announcements,
|
||||
disableRegistration,
|
||||
disableLocalTimeline,
|
||||
disableGlobalTimeline,
|
||||
enableRecaptcha,
|
||||
maxNoteTextLength,
|
||||
enableTwitterIntegration,
|
||||
enableGithubIntegration,
|
||||
enableDiscordIntegration,
|
||||
enableEmail,
|
||||
enableServiceWorker
|
||||
},
|
||||
meta,
|
||||
// total,
|
||||
// activeHalfyear,
|
||||
// activeMonth,
|
||||
@@ -57,43 +36,43 @@ const nodeinfo2 = async () => {
|
||||
|
||||
return {
|
||||
software: {
|
||||
name: softwareName,
|
||||
version,
|
||||
repository: repository.url
|
||||
name: 'misskey',
|
||||
version: config.version,
|
||||
repository: meta.repositoryUrl,
|
||||
},
|
||||
protocols: ['activitypub'],
|
||||
services: {
|
||||
inbound: [] as string[],
|
||||
outbound: ['atom1.0', 'rss2.0']
|
||||
},
|
||||
openRegistrations: !disableRegistration,
|
||||
openRegistrations: !meta.disableRegistration,
|
||||
usage: {
|
||||
users: {} // { total, activeHalfyear, activeMonth },
|
||||
// localPosts,
|
||||
// localComments
|
||||
},
|
||||
metadata: {
|
||||
name,
|
||||
description,
|
||||
nodeName: meta.name,
|
||||
nodeDescription: meta.description,
|
||||
maintainer: {
|
||||
name: maintainerName,
|
||||
email: maintainerEmail
|
||||
name: meta.maintainerName,
|
||||
email: meta.maintainerEmail
|
||||
},
|
||||
langs,
|
||||
ToSUrl,
|
||||
repositoryUrl,
|
||||
feedbackUrl,
|
||||
announcements,
|
||||
disableRegistration,
|
||||
disableLocalTimeline,
|
||||
disableGlobalTimeline,
|
||||
enableRecaptcha,
|
||||
maxNoteTextLength,
|
||||
enableTwitterIntegration,
|
||||
enableGithubIntegration,
|
||||
enableDiscordIntegration,
|
||||
enableEmail,
|
||||
enableServiceWorker
|
||||
langs: meta.langs,
|
||||
ToSUrl: meta.ToSUrl,
|
||||
repositoryUrl: meta.repositoryUrl,
|
||||
feedbackUrl: meta.feedbackUrl,
|
||||
announcements: meta.announcements,
|
||||
disableRegistration: meta.disableRegistration,
|
||||
disableLocalTimeline: meta.disableLocalTimeline,
|
||||
disableGlobalTimeline: meta.disableGlobalTimeline,
|
||||
enableRecaptcha: meta.enableRecaptcha,
|
||||
maxNoteTextLength: meta.maxNoteTextLength,
|
||||
enableTwitterIntegration: meta.enableTwitterIntegration,
|
||||
enableGithubIntegration: meta.enableGithubIntegration,
|
||||
enableDiscordIntegration: meta.enableDiscordIntegration,
|
||||
enableEmail: meta.enableEmail,
|
||||
enableServiceWorker: meta.enableServiceWorker
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@@ -13,7 +13,6 @@ import * as views from 'koa-views';
|
||||
import docs from './docs';
|
||||
import packFeed from './feed';
|
||||
import { fetchMeta } from '../../misc/fetch-meta';
|
||||
import * as pkg from '../../../package.json';
|
||||
import { genOpenapiSpec } from '../api/openapi/gen-spec';
|
||||
import config from '../../config';
|
||||
import { Users, Notes, Emojis, UserProfiles, Pages } from '../../models';
|
||||
@@ -257,7 +256,7 @@ router.get('/info', async ctx => {
|
||||
where: { host: null }
|
||||
});
|
||||
await ctx.render('info', {
|
||||
version: pkg.version,
|
||||
version: config.version,
|
||||
machine: os.hostname(),
|
||||
os: os.platform(),
|
||||
node: process.version,
|
||||
|
@@ -69,7 +69,8 @@ function postProcess(file: DriveFile, isExpired = false) {
|
||||
isLink: true,
|
||||
url: file.uri,
|
||||
thumbnailUrl: file.uri,
|
||||
webpublicUrl: file.uri
|
||||
webpublicUrl: file.uri,
|
||||
size: 0,
|
||||
});
|
||||
} else {
|
||||
DriveFiles.delete(file.id);
|
||||
|
91
src/services/fetch-nodeinfo.ts
Normal file
91
src/services/fetch-nodeinfo.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import * as request from 'request-promise-native';
|
||||
import { Instance } from '../models/entities/instance';
|
||||
import { Instances } from '../models';
|
||||
import config from '../config';
|
||||
import { getNodeinfoLock } from '../misc/app-lock';
|
||||
import Logger from '../services/logger';
|
||||
|
||||
export const logger = new Logger('nodeinfo', 'cyan');
|
||||
|
||||
export async function fetchNodeinfo(instance: Instance) {
|
||||
const unlock = await getNodeinfoLock(instance.host);
|
||||
|
||||
const _instance = await Instances.findOne({ host: instance.host });
|
||||
const now = Date.now();
|
||||
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(`Fetching nodeinfo of ${instance.host} ...`);
|
||||
|
||||
try {
|
||||
const wellknown = await request({
|
||||
url: 'https://' + instance.host + '/.well-known/nodeinfo',
|
||||
proxy: config.proxy,
|
||||
timeout: 1000 * 10,
|
||||
forever: true,
|
||||
headers: {
|
||||
'User-Agent': config.userAgent,
|
||||
Accept: 'application/json, */*'
|
||||
},
|
||||
json: true
|
||||
}).catch(e => {
|
||||
if (e.statusCode === 404) {
|
||||
throw 'No nodeinfo provided';
|
||||
} else {
|
||||
throw e.statusCode || e.message;
|
||||
}
|
||||
});
|
||||
|
||||
if (wellknown.links == null || !Array.isArray(wellknown.links)) {
|
||||
throw 'No wellknown links';
|
||||
}
|
||||
|
||||
const links = wellknown.links as any[];
|
||||
|
||||
const lnik1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0');
|
||||
const lnik2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0');
|
||||
const lnik2_1 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.1');
|
||||
const link = lnik2_1 || lnik2_0 || lnik1_0;
|
||||
|
||||
if (link == null) {
|
||||
throw 'No nodeinfo link provided';
|
||||
}
|
||||
|
||||
const info = await request({
|
||||
url: link.href,
|
||||
proxy: config.proxy,
|
||||
timeout: 1000 * 10,
|
||||
forever: true,
|
||||
headers: {
|
||||
'User-Agent': config.userAgent,
|
||||
Accept: 'application/json, */*'
|
||||
},
|
||||
json: true
|
||||
}).catch(e => {
|
||||
throw e.statusCode || e.message;
|
||||
});
|
||||
|
||||
await Instances.update(instance.id, {
|
||||
infoUpdatedAt: new Date(),
|
||||
softwareName: info.software.name.toLowerCase(),
|
||||
softwareVersion: info.software.version,
|
||||
openRegistrations: info.openRegistrations,
|
||||
name: info.metadata ? (info.metadata.nodeName || info.metadata.name || null) : null,
|
||||
description: info.metadata ? (info.metadata.nodeDescription || info.metadata.description || null) : null,
|
||||
maintainerName: info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.name || null) : null : null,
|
||||
maintainerEmail: info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.email || null) : null : null,
|
||||
});
|
||||
|
||||
logger.succ(`Successfuly fetched nodeinfo of ${instance.host}`);
|
||||
} catch (e) {
|
||||
logger.error(`Failed to fetch nodeinfo of ${instance.host}: ${e}`);
|
||||
|
||||
await Instances.update(instance.id, {
|
||||
infoUpdatedAt: new Date(),
|
||||
});
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
@@ -15,7 +15,6 @@ export async function registerOrFetchInstanceDoc(host: string): Promise<Instance
|
||||
host,
|
||||
caughtAt: new Date(),
|
||||
lastCommunicatedAt: new Date(),
|
||||
system: null // TODO
|
||||
});
|
||||
|
||||
federationChart.update(true);
|
||||
|
@@ -130,7 +130,7 @@ module.exports = {
|
||||
'process.env.NODE_ENV': JSON.stringify(isProduction ? 'production' : 'development')
|
||||
}),
|
||||
new WebpackOnBuildPlugin((stats: any) => {
|
||||
fs.writeFileSync('./built/client/meta.json', JSON.stringify({ version: meta.version }), 'utf-8');
|
||||
fs.writeFileSync('./built/meta.json', JSON.stringify({ version: meta.version }), 'utf-8');
|
||||
|
||||
fs.mkdirSync('./built/client/assets/locales', { recursive: true });
|
||||
|
||||
|
Reference in New Issue
Block a user