summaryrefslogtreecommitdiff
path: root/packages/backend/src/misc
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2023-07-21 20:36:07 +0900
committerGitHub <noreply@github.com>2023-07-21 20:36:07 +0900
commite64a81aa1d2801516e8eac8dc69aac540489f20b (patch)
tree56accbc0f5f71db864e1e975920135fb0a957291 /packages/backend/src/misc
parentMerge pull request #10990 from misskey-dev/develop (diff)
parentNew Crowdin updates (#11336) (diff)
downloadmisskey-e64a81aa1d2801516e8eac8dc69aac540489f20b.tar.gz
misskey-e64a81aa1d2801516e8eac8dc69aac540489f20b.tar.bz2
misskey-e64a81aa1d2801516e8eac8dc69aac540489f20b.zip
Merge pull request #11301 from misskey-dev/develop
Release: 13.14.0
Diffstat (limited to 'packages/backend/src/misc')
-rw-r--r--packages/backend/src/misc/acct.ts2
-rw-r--r--packages/backend/src/misc/cache.ts34
-rw-r--r--packages/backend/src/misc/check-https.ts6
-rw-r--r--packages/backend/src/misc/dev-null.ts14
-rw-r--r--packages/backend/src/misc/generate-invite-code.ts20
-rw-r--r--packages/backend/src/misc/generate-native-user-token.ts2
-rw-r--r--packages/backend/src/misc/get-ip-hash.ts2
-rw-r--r--packages/backend/src/misc/id/ulid.ts12
-rw-r--r--packages/backend/src/misc/is-duplicate-key-value-error.ts4
-rw-r--r--packages/backend/src/misc/json-schema.ts4
-rw-r--r--packages/backend/src/misc/prelude/array.ts5
-rw-r--r--packages/backend/src/misc/prelude/await-all.ts2
-rw-r--r--packages/backend/src/misc/prelude/url.ts2
-rw-r--r--packages/backend/src/misc/secure-rndstr.ts5
14 files changed, 77 insertions, 37 deletions
diff --git a/packages/backend/src/misc/acct.ts b/packages/backend/src/misc/acct.ts
index d1a6852a95..fb3b657cf7 100644
--- a/packages/backend/src/misc/acct.ts
+++ b/packages/backend/src/misc/acct.ts
@@ -4,7 +4,7 @@ export type Acct = {
};
export function parse(acct: string): Acct {
- if (acct.startsWith('@')) acct = acct.substr(1);
+ if (acct.startsWith('@')) acct = acct.substring(1);
const split = acct.split('@', 2);
return { username: split[0], host: split[1] ?? null };
}
diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts
index f130a7db8b..e825d51371 100644
--- a/packages/backend/src/misc/cache.ts
+++ b/packages/backend/src/misc/cache.ts
@@ -181,14 +181,28 @@ export class RedisSingleCache<T> {
// TODO: メモリ節約のためあまり参照されないキーを定期的に削除できるようにする?
-export class MemoryKVCache<T> {
- public cache: Map<string, { date: number; value: T; }>;
+function nothingToDo<T, V = T>(value: T): V {
+ return value as unknown as V;
+}
+
+export class MemoryKVCache<T, V = T> {
+ public cache: Map<string, { date: number; value: V; }>;
private lifetime: number;
private gcIntervalHandle: NodeJS.Timer;
+ private toMapConverter: (value: T) => V;
+ private fromMapConverter: (cached: V) => T | undefined;
- constructor(lifetime: MemoryKVCache<never>['lifetime']) {
+ constructor(lifetime: MemoryKVCache<never>['lifetime'], options: {
+ toMapConverter: (value: T) => V;
+ fromMapConverter: (cached: V) => T | undefined;
+ } = {
+ toMapConverter: nothingToDo,
+ fromMapConverter: nothingToDo,
+ }) {
this.cache = new Map();
this.lifetime = lifetime;
+ this.toMapConverter = options.toMapConverter;
+ this.fromMapConverter = options.fromMapConverter;
this.gcIntervalHandle = setInterval(() => {
this.gc();
@@ -199,7 +213,7 @@ export class MemoryKVCache<T> {
public set(key: string, value: T): void {
this.cache.set(key, {
date: Date.now(),
- value,
+ value: this.toMapConverter(value),
});
}
@@ -211,7 +225,7 @@ export class MemoryKVCache<T> {
this.cache.delete(key);
return undefined;
}
- return cached.value;
+ return this.fromMapConverter(cached.value);
}
@bindThis
@@ -222,9 +236,10 @@ export class MemoryKVCache<T> {
/**
* キャッシュがあればそれを返し、無ければfetcherを呼び出して結果をキャッシュ&返します
* optional: キャッシュが存在してもvalidatorでfalseを返すとキャッシュ無効扱いにします
+ * fetcherの引数はcacheに保存されている値があれば渡されます
*/
@bindThis
- public async fetch(key: string, fetcher: () => Promise<T>, validator?: (cachedValue: T) => boolean): Promise<T> {
+ public async fetch(key: string, fetcher: (value: V | undefined) => Promise<T>, validator?: (cachedValue: T) => boolean): Promise<T> {
const cachedValue = this.get(key);
if (cachedValue !== undefined) {
if (validator) {
@@ -239,7 +254,7 @@ export class MemoryKVCache<T> {
}
// Cache MISS
- const value = await fetcher();
+ const value = await fetcher(this.cache.get(key)?.value);
this.set(key, value);
return value;
}
@@ -247,9 +262,10 @@ export class MemoryKVCache<T> {
/**
* キャッシュがあればそれを返し、無ければfetcherを呼び出して結果をキャッシュ&返します
* optional: キャッシュが存在してもvalidatorでfalseを返すとキャッシュ無効扱いにします
+ * fetcherの引数はcacheに保存されている値があれば渡されます
*/
@bindThis
- public async fetchMaybe(key: string, fetcher: () => Promise<T | undefined>, validator?: (cachedValue: T) => boolean): Promise<T | undefined> {
+ public async fetchMaybe(key: string, fetcher: (value: V | undefined) => Promise<T | undefined>, validator?: (cachedValue: T) => boolean): Promise<T | undefined> {
const cachedValue = this.get(key);
if (cachedValue !== undefined) {
if (validator) {
@@ -264,7 +280,7 @@ export class MemoryKVCache<T> {
}
// Cache MISS
- const value = await fetcher();
+ const value = await fetcher(this.cache.get(key)?.value);
if (value !== undefined) {
this.set(key, value);
}
diff --git a/packages/backend/src/misc/check-https.ts b/packages/backend/src/misc/check-https.ts
index b33f019973..612032fe97 100644
--- a/packages/backend/src/misc/check-https.ts
+++ b/packages/backend/src/misc/check-https.ts
@@ -1,4 +1,4 @@
-export function checkHttps(url: string) {
- return url.startsWith('https://') ||
- (url.startsWith('http://') && process.env.NODE_ENV !== 'production');
+export function checkHttps(url: string): boolean {
+ return url.startsWith('https://') ||
+ (url.startsWith('http://') && process.env.NODE_ENV !== 'production');
}
diff --git a/packages/backend/src/misc/dev-null.ts b/packages/backend/src/misc/dev-null.ts
index 38b9d82669..6706af5e52 100644
--- a/packages/backend/src/misc/dev-null.ts
+++ b/packages/backend/src/misc/dev-null.ts
@@ -1,11 +1,11 @@
-import { Writable, WritableOptions } from "node:stream";
+import { Writable, WritableOptions } from 'node:stream';
export class DevNull extends Writable implements NodeJS.WritableStream {
- constructor(opts?: WritableOptions) {
- super(opts);
- }
+ constructor(opts?: WritableOptions) {
+ super(opts);
+ }
- _write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
- setImmediate(cb);
- }
+ _write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
+ setImmediate(cb);
+ }
}
diff --git a/packages/backend/src/misc/generate-invite-code.ts b/packages/backend/src/misc/generate-invite-code.ts
new file mode 100644
index 0000000000..617b27361d
--- /dev/null
+++ b/packages/backend/src/misc/generate-invite-code.ts
@@ -0,0 +1,20 @@
+import { secureRndstr } from './secure-rndstr.js';
+
+const CHARS = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // [0-9A-Z] w/o [01IO] (32 patterns)
+
+export function generateInviteCode(): string {
+ const code = secureRndstr(8, {
+ chars: CHARS,
+ });
+
+ const uniqueId = [];
+ let n = Math.floor(Date.now() / 1000 / 60);
+ while (true) {
+ uniqueId.push(CHARS[n % CHARS.length]);
+ const t = Math.floor(n / CHARS.length);
+ if (!t) break;
+ n = t;
+ }
+
+ return code + uniqueId.reverse().join('');
+}
diff --git a/packages/backend/src/misc/generate-native-user-token.ts b/packages/backend/src/misc/generate-native-user-token.ts
index 5d8a4c5378..7292d765a8 100644
--- a/packages/backend/src/misc/generate-native-user-token.ts
+++ b/packages/backend/src/misc/generate-native-user-token.ts
@@ -1,3 +1,3 @@
import { secureRndstr } from '@/misc/secure-rndstr.js';
-export default () => secureRndstr(16, true);
+export default () => secureRndstr(16);
diff --git a/packages/backend/src/misc/get-ip-hash.ts b/packages/backend/src/misc/get-ip-hash.ts
index 70e61aef8c..1a86fb8814 100644
--- a/packages/backend/src/misc/get-ip-hash.ts
+++ b/packages/backend/src/misc/get-ip-hash.ts
@@ -1,6 +1,6 @@
import IPCIDR from 'ip-cidr';
-export function getIpHash(ip: string) {
+export function getIpHash(ip: string): string {
try {
// because a single person may control many IPv6 addresses,
// only a /64 subnet prefix of any IP will be taken into account.
diff --git a/packages/backend/src/misc/id/ulid.ts b/packages/backend/src/misc/id/ulid.ts
index e8aa752890..bfbc363cf5 100644
--- a/packages/backend/src/misc/id/ulid.ts
+++ b/packages/backend/src/misc/id/ulid.ts
@@ -5,10 +5,10 @@ const CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
export function parseUlid(id: string): { date: Date; } {
- const timestamp = id.slice(0, 10);
- let time = 0;
- for (let i = 0; i < 10; i++) {
- time = time * 32 + CHARS.indexOf(timestamp[i]);
- }
- return { date: new Date(time) };
+ const timestamp = id.slice(0, 10);
+ let time = 0;
+ for (let i = 0; i < 10; i++) {
+ time = time * 32 + CHARS.indexOf(timestamp[i]);
+ }
+ return { date: new Date(time) };
}
diff --git a/packages/backend/src/misc/is-duplicate-key-value-error.ts b/packages/backend/src/misc/is-duplicate-key-value-error.ts
index 04ff191e41..f5343d187c 100644
--- a/packages/backend/src/misc/is-duplicate-key-value-error.ts
+++ b/packages/backend/src/misc/is-duplicate-key-value-error.ts
@@ -1,3 +1,5 @@
+import { QueryFailedError } from 'typeorm';
+
export function isDuplicateKeyValueError(e: unknown | Error): boolean {
- return (e as any).message && (e as Error).message.startsWith('duplicate key value');
+ return e instanceof QueryFailedError && e.driverError.code === '23505';
}
diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts
index e748f93a26..ec6bc4a5fb 100644
--- a/packages/backend/src/misc/json-schema.ts
+++ b/packages/backend/src/misc/json-schema.ts
@@ -19,6 +19,7 @@ import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js'
import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
+import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js';
import { packedPageSchema } from '@/models/json-schema/page.js';
import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js';
import { packedChannelSchema } from '@/models/json-schema/channel.js';
@@ -52,6 +53,7 @@ export const refs = {
RenoteMuting: packedRenoteMutingSchema,
Blocking: packedBlockingSchema,
Hashtag: packedHashtagSchema,
+ InviteCode: packedInviteCodeSchema,
Page: packedPageSchema,
Channel: packedChannelSchema,
QueueCount: packedQueueCountSchema,
@@ -131,7 +133,7 @@ type NullOrUndefined<p extends Schema, T> =
| T;
// https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
-// Get intersection from union
+// Get intersection from union
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type PartialIntersection<T> = Partial<UnionToIntersection<T>>;
diff --git a/packages/backend/src/misc/prelude/array.ts b/packages/backend/src/misc/prelude/array.ts
index 0b2830cb7b..2524eacfb3 100644
--- a/packages/backend/src/misc/prelude/array.ts
+++ b/packages/backend/src/misc/prelude/array.ts
@@ -67,8 +67,9 @@ export function maximum(xs: number[]): number {
export function groupBy<T>(f: EndoRelation<T>, xs: T[]): T[][] {
const groups = [] as T[][];
for (const x of xs) {
- if (groups.length !== 0 && f(groups[groups.length - 1][0], x)) {
- groups[groups.length - 1].push(x);
+ const lastGroup = groups.at(-1);
+ if (lastGroup !== undefined && f(lastGroup[0], x)) {
+ lastGroup.push(x);
} else {
groups.push([x]);
}
diff --git a/packages/backend/src/misc/prelude/await-all.ts b/packages/backend/src/misc/prelude/await-all.ts
index b955c3a5d8..fd9832d6f8 100644
--- a/packages/backend/src/misc/prelude/await-all.ts
+++ b/packages/backend/src/misc/prelude/await-all.ts
@@ -10,7 +10,7 @@ export async function awaitAll<T>(obj: Promiseable<T>): Promise<T> {
const resolvedValues = await Promise.all(values.map(value =>
(!value || !value.constructor || value.constructor.name !== 'Object')
? value
- : awaitAll(value)
+ : awaitAll(value),
));
for (let i = 0; i < keys.length; i++) {
diff --git a/packages/backend/src/misc/prelude/url.ts b/packages/backend/src/misc/prelude/url.ts
index 9b1dabc789..5239678280 100644
--- a/packages/backend/src/misc/prelude/url.ts
+++ b/packages/backend/src/misc/prelude/url.ts
@@ -2,7 +2,7 @@
* 1. 配列に何も入っていない時はクエリを付けない
* 2. プロパティがundefinedの時はクエリを付けない
* (new URLSearchParams(obj)ではそこまで丁寧なことをしてくれない)
- */
+ */
export function query(obj: Record<string, unknown>): string {
const params = Object.entries(obj)
.filter(([, v]) => Array.isArray(v) ? v.length : v !== undefined)
diff --git a/packages/backend/src/misc/secure-rndstr.ts b/packages/backend/src/misc/secure-rndstr.ts
index 8d4fcb1ba9..cde64c8142 100644
--- a/packages/backend/src/misc/secure-rndstr.ts
+++ b/packages/backend/src/misc/secure-rndstr.ts
@@ -1,10 +1,9 @@
import * as crypto from 'node:crypto';
-const L_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
+export const L_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
const LU_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-export function secureRndstr(length = 32, useLU = true): string {
- const chars = useLU ? LU_CHARS : L_CHARS;
+export function secureRndstr(length = 32, { chars = LU_CHARS } = {}): string {
const chars_len = chars.length;
let str = '';