]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/core-utils.ts
Refractor retry transaction function
[github/Chocobozzz/PeerTube.git] / server / helpers / core-utils.ts
... / ...
CommitLineData
1/*
2 Different from 'utils' because we don't not import other PeerTube modules.
3 Useful to avoid circular dependencies.
4*/
5
6import * as bcrypt from 'bcrypt'
7import * as createTorrent from 'create-torrent'
8import { pseudoRandomBytes } from 'crypto'
9import { copyFile, readdir, readFile, rename, stat, Stats, unlink, writeFile } from 'fs'
10import * as mkdirp from 'mkdirp'
11import { isAbsolute, join } from 'path'
12import * as pem from 'pem'
13import * as rimraf from 'rimraf'
14import { URL } from 'url'
15import { truncate } from 'lodash'
16
17function sanitizeUrl (url: string) {
18 const urlObject = new URL(url)
19
20 if (urlObject.protocol === 'https:' && urlObject.port === '443') {
21 urlObject.port = ''
22 } else if (urlObject.protocol === 'http:' && urlObject.port === '80') {
23 urlObject.port = ''
24 }
25
26 return urlObject.href.replace(/\/$/, '')
27}
28
29// Don't import remote scheme from constants because we are in core utils
30function sanitizeHost (host: string, remoteScheme: string) {
31 const toRemove = remoteScheme === 'https' ? 443 : 80
32
33 return host.replace(new RegExp(`:${toRemove}$`), '')
34}
35
36function isTestInstance () {
37 return process.env.NODE_ENV === 'test'
38}
39
40function root () {
41 // We are in /helpers/utils.js
42 const paths = [ __dirname, '..', '..' ]
43
44 // We are under /dist directory
45 if (process.mainModule.filename.endsWith('.ts') === false) {
46 paths.push('..')
47 }
48
49 return join.apply(null, paths)
50}
51
52// Thanks: https://stackoverflow.com/a/12034334
53function escapeHTML (stringParam) {
54 if (!stringParam) return ''
55
56 const entityMap = {
57 '&': '&',
58 '<': '&lt;',
59 '>': '&gt;',
60 '"': '&quot;',
61 "'": '&#39;',
62 '/': '&#x2F;',
63 '`': '&#x60;',
64 '=': '&#x3D;'
65 }
66
67 return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s])
68}
69
70function pageToStartAndCount (page: number, itemsPerPage: number) {
71 const start = (page - 1) * itemsPerPage
72
73 return { start, count: itemsPerPage }
74}
75
76function buildPath (path: string) {
77 if (isAbsolute(path)) return path
78
79 return join(root(), path)
80}
81
82// Consistent with .length, lodash truncate function is not
83function peertubeTruncate (str: string, maxLength: number) {
84 const options = {
85 length: maxLength
86 }
87 const truncatedStr = truncate(str, options)
88
89 // The truncated string is okay, we can return it
90 if (truncatedStr.length <= maxLength) return truncatedStr
91
92 // Lodash takes into account all UTF characters, whereas String.prototype.length does not: some characters have a length of 2
93 // We always use the .length so we need to truncate more if needed
94 options.length -= truncatedStr.length - maxLength
95 return truncate(str, options)
96}
97
98function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> {
99 return function promisified (): Promise<A> {
100 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
101 func.apply(null, [ (err: any, res: A) => err ? reject(err) : resolve(res) ])
102 })
103 }
104}
105
106// Thanks to https://gist.github.com/kumasento/617daa7e46f13ecdd9b2
107function promisify1<T, A> (func: (arg: T, cb: (err: any, result: A) => void) => void): (arg: T) => Promise<A> {
108 return function promisified (arg: T): Promise<A> {
109 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
110 func.apply(null, [ arg, (err: any, res: A) => err ? reject(err) : resolve(res) ])
111 })
112 }
113}
114
115function promisify1WithVoid<T> (func: (arg: T, cb: (err: any) => void) => void): (arg: T) => Promise<void> {
116 return function promisified (arg: T): Promise<void> {
117 return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
118 func.apply(null, [ arg, (err: any) => err ? reject(err) : resolve() ])
119 })
120 }
121}
122
123function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> {
124 return function promisified (arg1: T, arg2: U): Promise<A> {
125 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
126 func.apply(null, [ arg1, arg2, (err: any, res: A) => err ? reject(err) : resolve(res) ])
127 })
128 }
129}
130
131function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => void) => void): (arg1: T, arg2: U) => Promise<void> {
132 return function promisified (arg1: T, arg2: U): Promise<void> {
133 return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
134 func.apply(null, [ arg1, arg2, (err: any) => err ? reject(err) : resolve() ])
135 })
136 }
137}
138
139const copyFilePromise = promisify2WithVoid<string, string>(copyFile)
140const readFileBufferPromise = promisify1<string, Buffer>(readFile)
141const unlinkPromise = promisify1WithVoid<string>(unlink)
142const renamePromise = promisify2WithVoid<string, string>(rename)
143const writeFilePromise = promisify2WithVoid<string, any>(writeFile)
144const readdirPromise = promisify1<string, string[]>(readdir)
145const mkdirpPromise = promisify1<string, string>(mkdirp)
146const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
147const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
148const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
149const bcryptComparePromise = promisify2<any, string, boolean>(bcrypt.compare)
150const bcryptGenSaltPromise = promisify1<number, string>(bcrypt.genSalt)
151const bcryptHashPromise = promisify2<any, string | number, string>(bcrypt.hash)
152const createTorrentPromise = promisify2<string, any, any>(createTorrent)
153const rimrafPromise = promisify1WithVoid<string>(rimraf)
154const statPromise = promisify1<string, Stats>(stat)
155
156// ---------------------------------------------------------------------------
157
158export {
159 isTestInstance,
160 root,
161 escapeHTML,
162 pageToStartAndCount,
163 sanitizeUrl,
164 sanitizeHost,
165 buildPath,
166 peertubeTruncate,
167
168 promisify0,
169 promisify1,
170
171 copyFilePromise,
172 readdirPromise,
173 readFileBufferPromise,
174 unlinkPromise,
175 renamePromise,
176 writeFilePromise,
177 mkdirpPromise,
178 pseudoRandomBytesPromise,
179 createPrivateKey,
180 getPublicKey,
181 bcryptComparePromise,
182 bcryptGenSaltPromise,
183 bcryptHashPromise,
184 createTorrentPromise,
185 rimrafPromise,
186 statPromise
187}