├── .dockerignore ├── .gitignore ├── .pnp.cjs ├── .pnp.loader.mjs ├── .yarn ├── install-state.gz └── releases │ └── yarn-4.0.1.cjs ├── .yarnrc.yml ├── Dockerfile ├── README.md ├── config └── index.js ├── deployment_backend.yaml ├── event-code ├── cdm_event_code.json ├── cdm_event_code_message.json └── cdm_event_error.json ├── images └── favicon.ico ├── nodemon.json ├── package.json ├── private.crt ├── private.csr ├── private.key ├── server.js └── utils ├── api.js ├── common.js └── socket.js /.dockerignore: -------------------------------------------------------------------------------- 1 | # .dockerignore 2 | /event-code -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | yarn.lock 3 | node_modules -------------------------------------------------------------------------------- /.pnp.loader.mjs: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { URL as URL$1, fileURLToPath, pathToFileURL } from 'url'; 3 | import path from 'path'; 4 | import { createHash } from 'crypto'; 5 | import { EOL } from 'os'; 6 | import moduleExports, { isBuiltin } from 'module'; 7 | import assert from 'assert'; 8 | 9 | const SAFE_TIME = 456789e3; 10 | 11 | const PortablePath = { 12 | root: `/`, 13 | dot: `.`, 14 | parent: `..` 15 | }; 16 | const npath = Object.create(path); 17 | const ppath = Object.create(path.posix); 18 | npath.cwd = () => process.cwd(); 19 | ppath.cwd = process.platform === `win32` ? () => toPortablePath(process.cwd()) : process.cwd; 20 | if (process.platform === `win32`) { 21 | ppath.resolve = (...segments) => { 22 | if (segments.length > 0 && ppath.isAbsolute(segments[0])) { 23 | return path.posix.resolve(...segments); 24 | } else { 25 | return path.posix.resolve(ppath.cwd(), ...segments); 26 | } 27 | }; 28 | } 29 | const contains = function(pathUtils, from, to) { 30 | from = pathUtils.normalize(from); 31 | to = pathUtils.normalize(to); 32 | if (from === to) 33 | return `.`; 34 | if (!from.endsWith(pathUtils.sep)) 35 | from = from + pathUtils.sep; 36 | if (to.startsWith(from)) { 37 | return to.slice(from.length); 38 | } else { 39 | return null; 40 | } 41 | }; 42 | npath.contains = (from, to) => contains(npath, from, to); 43 | ppath.contains = (from, to) => contains(ppath, from, to); 44 | const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/; 45 | const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/; 46 | const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/; 47 | const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/; 48 | function fromPortablePathWin32(p) { 49 | let portablePathMatch, uncPortablePathMatch; 50 | if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP)) 51 | p = portablePathMatch[1]; 52 | else if (uncPortablePathMatch = p.match(UNC_PORTABLE_PATH_REGEXP)) 53 | p = `\\\\${uncPortablePathMatch[1] ? `.\\` : ``}${uncPortablePathMatch[2]}`; 54 | else 55 | return p; 56 | return p.replace(/\//g, `\\`); 57 | } 58 | function toPortablePathWin32(p) { 59 | p = p.replace(/\\/g, `/`); 60 | let windowsPathMatch, uncWindowsPathMatch; 61 | if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP)) 62 | p = `/${windowsPathMatch[1]}`; 63 | else if (uncWindowsPathMatch = p.match(UNC_WINDOWS_PATH_REGEXP)) 64 | p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`; 65 | return p; 66 | } 67 | const toPortablePath = process.platform === `win32` ? toPortablePathWin32 : (p) => p; 68 | const fromPortablePath = process.platform === `win32` ? fromPortablePathWin32 : (p) => p; 69 | npath.fromPortablePath = fromPortablePath; 70 | npath.toPortablePath = toPortablePath; 71 | function convertPath(targetPathUtils, sourcePath) { 72 | return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath); 73 | } 74 | 75 | const defaultTime = new Date(SAFE_TIME * 1e3); 76 | const defaultTimeMs = defaultTime.getTime(); 77 | async function copyPromise(destinationFs, destination, sourceFs, source, opts) { 78 | const normalizedDestination = destinationFs.pathUtils.normalize(destination); 79 | const normalizedSource = sourceFs.pathUtils.normalize(source); 80 | const prelayout = []; 81 | const postlayout = []; 82 | const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : await sourceFs.lstatPromise(normalizedSource); 83 | await destinationFs.mkdirpPromise(destinationFs.pathUtils.dirname(destination), { utimes: [atime, mtime] }); 84 | await copyImpl(prelayout, postlayout, destinationFs, normalizedDestination, sourceFs, normalizedSource, { ...opts, didParentExist: true }); 85 | for (const operation of prelayout) 86 | await operation(); 87 | await Promise.all(postlayout.map((operation) => { 88 | return operation(); 89 | })); 90 | } 91 | async function copyImpl(prelayout, postlayout, destinationFs, destination, sourceFs, source, opts) { 92 | const destinationStat = opts.didParentExist ? await maybeLStat(destinationFs, destination) : null; 93 | const sourceStat = await sourceFs.lstatPromise(source); 94 | const { atime, mtime } = opts.stableTime ? { atime: defaultTime, mtime: defaultTime } : sourceStat; 95 | let updated; 96 | switch (true) { 97 | case sourceStat.isDirectory(): 98 | { 99 | updated = await copyFolder(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); 100 | } 101 | break; 102 | case sourceStat.isFile(): 103 | { 104 | updated = await copyFile(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); 105 | } 106 | break; 107 | case sourceStat.isSymbolicLink(): 108 | { 109 | updated = await copySymlink(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); 110 | } 111 | break; 112 | default: 113 | { 114 | throw new Error(`Unsupported file type (${sourceStat.mode})`); 115 | } 116 | } 117 | if (opts.linkStrategy?.type !== `HardlinkFromIndex` || !sourceStat.isFile()) { 118 | if (updated || destinationStat?.mtime?.getTime() !== mtime.getTime() || destinationStat?.atime?.getTime() !== atime.getTime()) { 119 | postlayout.push(() => destinationFs.lutimesPromise(destination, atime, mtime)); 120 | updated = true; 121 | } 122 | if (destinationStat === null || (destinationStat.mode & 511) !== (sourceStat.mode & 511)) { 123 | postlayout.push(() => destinationFs.chmodPromise(destination, sourceStat.mode & 511)); 124 | updated = true; 125 | } 126 | } 127 | return updated; 128 | } 129 | async function maybeLStat(baseFs, p) { 130 | try { 131 | return await baseFs.lstatPromise(p); 132 | } catch (e) { 133 | return null; 134 | } 135 | } 136 | async function copyFolder(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { 137 | if (destinationStat !== null && !destinationStat.isDirectory()) { 138 | if (opts.overwrite) { 139 | prelayout.push(async () => destinationFs.removePromise(destination)); 140 | destinationStat = null; 141 | } else { 142 | return false; 143 | } 144 | } 145 | let updated = false; 146 | if (destinationStat === null) { 147 | prelayout.push(async () => { 148 | try { 149 | await destinationFs.mkdirPromise(destination, { mode: sourceStat.mode }); 150 | } catch (err) { 151 | if (err.code !== `EEXIST`) { 152 | throw err; 153 | } 154 | } 155 | }); 156 | updated = true; 157 | } 158 | const entries = await sourceFs.readdirPromise(source); 159 | const nextOpts = opts.didParentExist && !destinationStat ? { ...opts, didParentExist: false } : opts; 160 | if (opts.stableSort) { 161 | for (const entry of entries.sort()) { 162 | if (await copyImpl(prelayout, postlayout, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts)) { 163 | updated = true; 164 | } 165 | } 166 | } else { 167 | const entriesUpdateStatus = await Promise.all(entries.map(async (entry) => { 168 | await copyImpl(prelayout, postlayout, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts); 169 | })); 170 | if (entriesUpdateStatus.some((status) => status)) { 171 | updated = true; 172 | } 173 | } 174 | return updated; 175 | } 176 | async function copyFileViaIndex(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts, linkStrategy) { 177 | const sourceHash = await sourceFs.checksumFilePromise(source, { algorithm: `sha1` }); 178 | const indexPath = destinationFs.pathUtils.join(linkStrategy.indexPath, sourceHash.slice(0, 2), `${sourceHash}.dat`); 179 | let AtomicBehavior; 180 | ((AtomicBehavior2) => { 181 | AtomicBehavior2[AtomicBehavior2["Lock"] = 0] = "Lock"; 182 | AtomicBehavior2[AtomicBehavior2["Rename"] = 1] = "Rename"; 183 | })(AtomicBehavior || (AtomicBehavior = {})); 184 | let atomicBehavior = 1 /* Rename */; 185 | let indexStat = await maybeLStat(destinationFs, indexPath); 186 | if (destinationStat) { 187 | const isDestinationHardlinkedFromIndex = indexStat && destinationStat.dev === indexStat.dev && destinationStat.ino === indexStat.ino; 188 | const isIndexModified = indexStat?.mtimeMs !== defaultTimeMs; 189 | if (isDestinationHardlinkedFromIndex) { 190 | if (isIndexModified && linkStrategy.autoRepair) { 191 | atomicBehavior = 0 /* Lock */; 192 | indexStat = null; 193 | } 194 | } 195 | if (!isDestinationHardlinkedFromIndex) { 196 | if (opts.overwrite) { 197 | prelayout.push(async () => destinationFs.removePromise(destination)); 198 | destinationStat = null; 199 | } else { 200 | return false; 201 | } 202 | } 203 | } 204 | const tempPath = !indexStat && atomicBehavior === 1 /* Rename */ ? `${indexPath}.${Math.floor(Math.random() * 4294967296).toString(16).padStart(8, `0`)}` : null; 205 | let tempPathCleaned = false; 206 | prelayout.push(async () => { 207 | if (!indexStat) { 208 | if (atomicBehavior === 0 /* Lock */) { 209 | await destinationFs.lockPromise(indexPath, async () => { 210 | const content = await sourceFs.readFilePromise(source); 211 | await destinationFs.writeFilePromise(indexPath, content); 212 | }); 213 | } 214 | if (atomicBehavior === 1 /* Rename */ && tempPath) { 215 | const content = await sourceFs.readFilePromise(source); 216 | await destinationFs.writeFilePromise(tempPath, content); 217 | try { 218 | await destinationFs.linkPromise(tempPath, indexPath); 219 | } catch (err) { 220 | if (err.code === `EEXIST`) { 221 | tempPathCleaned = true; 222 | await destinationFs.unlinkPromise(tempPath); 223 | } else { 224 | throw err; 225 | } 226 | } 227 | } 228 | } 229 | if (!destinationStat) { 230 | await destinationFs.linkPromise(indexPath, destination); 231 | } 232 | }); 233 | postlayout.push(async () => { 234 | if (!indexStat) 235 | await destinationFs.lutimesPromise(indexPath, defaultTime, defaultTime); 236 | if (tempPath && !tempPathCleaned) { 237 | await destinationFs.unlinkPromise(tempPath); 238 | } 239 | }); 240 | return false; 241 | } 242 | async function copyFileDirect(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { 243 | if (destinationStat !== null) { 244 | if (opts.overwrite) { 245 | prelayout.push(async () => destinationFs.removePromise(destination)); 246 | destinationStat = null; 247 | } else { 248 | return false; 249 | } 250 | } 251 | prelayout.push(async () => { 252 | const content = await sourceFs.readFilePromise(source); 253 | await destinationFs.writeFilePromise(destination, content); 254 | }); 255 | return true; 256 | } 257 | async function copyFile(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { 258 | if (opts.linkStrategy?.type === `HardlinkFromIndex`) { 259 | return copyFileViaIndex(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts, opts.linkStrategy); 260 | } else { 261 | return copyFileDirect(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); 262 | } 263 | } 264 | async function copySymlink(prelayout, postlayout, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { 265 | if (destinationStat !== null) { 266 | if (opts.overwrite) { 267 | prelayout.push(async () => destinationFs.removePromise(destination)); 268 | destinationStat = null; 269 | } else { 270 | return false; 271 | } 272 | } 273 | prelayout.push(async () => { 274 | await destinationFs.symlinkPromise(convertPath(destinationFs.pathUtils, await sourceFs.readlinkPromise(source)), destination); 275 | }); 276 | return true; 277 | } 278 | 279 | class FakeFS { 280 | constructor(pathUtils) { 281 | this.pathUtils = pathUtils; 282 | } 283 | async *genTraversePromise(init, { stableSort = false } = {}) { 284 | const stack = [init]; 285 | while (stack.length > 0) { 286 | const p = stack.shift(); 287 | const entry = await this.lstatPromise(p); 288 | if (entry.isDirectory()) { 289 | const entries = await this.readdirPromise(p); 290 | if (stableSort) { 291 | for (const entry2 of entries.sort()) { 292 | stack.push(this.pathUtils.join(p, entry2)); 293 | } 294 | } else { 295 | throw new Error(`Not supported`); 296 | } 297 | } else { 298 | yield p; 299 | } 300 | } 301 | } 302 | async checksumFilePromise(path, { algorithm = `sha512` } = {}) { 303 | const fd = await this.openPromise(path, `r`); 304 | try { 305 | const CHUNK_SIZE = 65536; 306 | const chunk = Buffer.allocUnsafeSlow(CHUNK_SIZE); 307 | const hash = createHash(algorithm); 308 | let bytesRead = 0; 309 | while ((bytesRead = await this.readPromise(fd, chunk, 0, CHUNK_SIZE)) !== 0) 310 | hash.update(bytesRead === CHUNK_SIZE ? chunk : chunk.slice(0, bytesRead)); 311 | return hash.digest(`hex`); 312 | } finally { 313 | await this.closePromise(fd); 314 | } 315 | } 316 | async removePromise(p, { recursive = true, maxRetries = 5 } = {}) { 317 | let stat; 318 | try { 319 | stat = await this.lstatPromise(p); 320 | } catch (error) { 321 | if (error.code === `ENOENT`) { 322 | return; 323 | } else { 324 | throw error; 325 | } 326 | } 327 | if (stat.isDirectory()) { 328 | if (recursive) { 329 | const entries = await this.readdirPromise(p); 330 | await Promise.all(entries.map((entry) => { 331 | return this.removePromise(this.pathUtils.resolve(p, entry)); 332 | })); 333 | } 334 | for (let t = 0; t <= maxRetries; t++) { 335 | try { 336 | await this.rmdirPromise(p); 337 | break; 338 | } catch (error) { 339 | if (error.code !== `EBUSY` && error.code !== `ENOTEMPTY`) { 340 | throw error; 341 | } else if (t < maxRetries) { 342 | await new Promise((resolve) => setTimeout(resolve, t * 100)); 343 | } 344 | } 345 | } 346 | } else { 347 | await this.unlinkPromise(p); 348 | } 349 | } 350 | removeSync(p, { recursive = true } = {}) { 351 | let stat; 352 | try { 353 | stat = this.lstatSync(p); 354 | } catch (error) { 355 | if (error.code === `ENOENT`) { 356 | return; 357 | } else { 358 | throw error; 359 | } 360 | } 361 | if (stat.isDirectory()) { 362 | if (recursive) 363 | for (const entry of this.readdirSync(p)) 364 | this.removeSync(this.pathUtils.resolve(p, entry)); 365 | this.rmdirSync(p); 366 | } else { 367 | this.unlinkSync(p); 368 | } 369 | } 370 | async mkdirpPromise(p, { chmod, utimes } = {}) { 371 | p = this.resolve(p); 372 | if (p === this.pathUtils.dirname(p)) 373 | return void 0; 374 | const parts = p.split(this.pathUtils.sep); 375 | let createdDirectory; 376 | for (let u = 2; u <= parts.length; ++u) { 377 | const subPath = parts.slice(0, u).join(this.pathUtils.sep); 378 | if (!this.existsSync(subPath)) { 379 | try { 380 | await this.mkdirPromise(subPath); 381 | } catch (error) { 382 | if (error.code === `EEXIST`) { 383 | continue; 384 | } else { 385 | throw error; 386 | } 387 | } 388 | createdDirectory ??= subPath; 389 | if (chmod != null) 390 | await this.chmodPromise(subPath, chmod); 391 | if (utimes != null) { 392 | await this.utimesPromise(subPath, utimes[0], utimes[1]); 393 | } else { 394 | const parentStat = await this.statPromise(this.pathUtils.dirname(subPath)); 395 | await this.utimesPromise(subPath, parentStat.atime, parentStat.mtime); 396 | } 397 | } 398 | } 399 | return createdDirectory; 400 | } 401 | mkdirpSync(p, { chmod, utimes } = {}) { 402 | p = this.resolve(p); 403 | if (p === this.pathUtils.dirname(p)) 404 | return void 0; 405 | const parts = p.split(this.pathUtils.sep); 406 | let createdDirectory; 407 | for (let u = 2; u <= parts.length; ++u) { 408 | const subPath = parts.slice(0, u).join(this.pathUtils.sep); 409 | if (!this.existsSync(subPath)) { 410 | try { 411 | this.mkdirSync(subPath); 412 | } catch (error) { 413 | if (error.code === `EEXIST`) { 414 | continue; 415 | } else { 416 | throw error; 417 | } 418 | } 419 | createdDirectory ??= subPath; 420 | if (chmod != null) 421 | this.chmodSync(subPath, chmod); 422 | if (utimes != null) { 423 | this.utimesSync(subPath, utimes[0], utimes[1]); 424 | } else { 425 | const parentStat = this.statSync(this.pathUtils.dirname(subPath)); 426 | this.utimesSync(subPath, parentStat.atime, parentStat.mtime); 427 | } 428 | } 429 | } 430 | return createdDirectory; 431 | } 432 | async copyPromise(destination, source, { baseFs = this, overwrite = true, stableSort = false, stableTime = false, linkStrategy = null } = {}) { 433 | return await copyPromise(this, destination, baseFs, source, { overwrite, stableSort, stableTime, linkStrategy }); 434 | } 435 | copySync(destination, source, { baseFs = this, overwrite = true } = {}) { 436 | const stat = baseFs.lstatSync(source); 437 | const exists = this.existsSync(destination); 438 | if (stat.isDirectory()) { 439 | this.mkdirpSync(destination); 440 | const directoryListing = baseFs.readdirSync(source); 441 | for (const entry of directoryListing) { 442 | this.copySync(this.pathUtils.join(destination, entry), baseFs.pathUtils.join(source, entry), { baseFs, overwrite }); 443 | } 444 | } else if (stat.isFile()) { 445 | if (!exists || overwrite) { 446 | if (exists) 447 | this.removeSync(destination); 448 | const content = baseFs.readFileSync(source); 449 | this.writeFileSync(destination, content); 450 | } 451 | } else if (stat.isSymbolicLink()) { 452 | if (!exists || overwrite) { 453 | if (exists) 454 | this.removeSync(destination); 455 | const target = baseFs.readlinkSync(source); 456 | this.symlinkSync(convertPath(this.pathUtils, target), destination); 457 | } 458 | } else { 459 | throw new Error(`Unsupported file type (file: ${source}, mode: 0o${stat.mode.toString(8).padStart(6, `0`)})`); 460 | } 461 | const mode = stat.mode & 511; 462 | this.chmodSync(destination, mode); 463 | } 464 | async changeFilePromise(p, content, opts = {}) { 465 | if (Buffer.isBuffer(content)) { 466 | return this.changeFileBufferPromise(p, content, opts); 467 | } else { 468 | return this.changeFileTextPromise(p, content, opts); 469 | } 470 | } 471 | async changeFileBufferPromise(p, content, { mode } = {}) { 472 | let current = Buffer.alloc(0); 473 | try { 474 | current = await this.readFilePromise(p); 475 | } catch (error) { 476 | } 477 | if (Buffer.compare(current, content) === 0) 478 | return; 479 | await this.writeFilePromise(p, content, { mode }); 480 | } 481 | async changeFileTextPromise(p, content, { automaticNewlines, mode } = {}) { 482 | let current = ``; 483 | try { 484 | current = await this.readFilePromise(p, `utf8`); 485 | } catch (error) { 486 | } 487 | const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; 488 | if (current === normalizedContent) 489 | return; 490 | await this.writeFilePromise(p, normalizedContent, { mode }); 491 | } 492 | changeFileSync(p, content, opts = {}) { 493 | if (Buffer.isBuffer(content)) { 494 | return this.changeFileBufferSync(p, content, opts); 495 | } else { 496 | return this.changeFileTextSync(p, content, opts); 497 | } 498 | } 499 | changeFileBufferSync(p, content, { mode } = {}) { 500 | let current = Buffer.alloc(0); 501 | try { 502 | current = this.readFileSync(p); 503 | } catch (error) { 504 | } 505 | if (Buffer.compare(current, content) === 0) 506 | return; 507 | this.writeFileSync(p, content, { mode }); 508 | } 509 | changeFileTextSync(p, content, { automaticNewlines = false, mode } = {}) { 510 | let current = ``; 511 | try { 512 | current = this.readFileSync(p, `utf8`); 513 | } catch (error) { 514 | } 515 | const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; 516 | if (current === normalizedContent) 517 | return; 518 | this.writeFileSync(p, normalizedContent, { mode }); 519 | } 520 | async movePromise(fromP, toP) { 521 | try { 522 | await this.renamePromise(fromP, toP); 523 | } catch (error) { 524 | if (error.code === `EXDEV`) { 525 | await this.copyPromise(toP, fromP); 526 | await this.removePromise(fromP); 527 | } else { 528 | throw error; 529 | } 530 | } 531 | } 532 | moveSync(fromP, toP) { 533 | try { 534 | this.renameSync(fromP, toP); 535 | } catch (error) { 536 | if (error.code === `EXDEV`) { 537 | this.copySync(toP, fromP); 538 | this.removeSync(fromP); 539 | } else { 540 | throw error; 541 | } 542 | } 543 | } 544 | async lockPromise(affectedPath, callback) { 545 | const lockPath = `${affectedPath}.flock`; 546 | const interval = 1e3 / 60; 547 | const startTime = Date.now(); 548 | let fd = null; 549 | const isAlive = async () => { 550 | let pid; 551 | try { 552 | [pid] = await this.readJsonPromise(lockPath); 553 | } catch (error) { 554 | return Date.now() - startTime < 500; 555 | } 556 | try { 557 | process.kill(pid, 0); 558 | return true; 559 | } catch (error) { 560 | return false; 561 | } 562 | }; 563 | while (fd === null) { 564 | try { 565 | fd = await this.openPromise(lockPath, `wx`); 566 | } catch (error) { 567 | if (error.code === `EEXIST`) { 568 | if (!await isAlive()) { 569 | try { 570 | await this.unlinkPromise(lockPath); 571 | continue; 572 | } catch (error2) { 573 | } 574 | } 575 | if (Date.now() - startTime < 60 * 1e3) { 576 | await new Promise((resolve) => setTimeout(resolve, interval)); 577 | } else { 578 | throw new Error(`Couldn't acquire a lock in a reasonable time (via ${lockPath})`); 579 | } 580 | } else { 581 | throw error; 582 | } 583 | } 584 | } 585 | await this.writePromise(fd, JSON.stringify([process.pid])); 586 | try { 587 | return await callback(); 588 | } finally { 589 | try { 590 | await this.closePromise(fd); 591 | await this.unlinkPromise(lockPath); 592 | } catch (error) { 593 | } 594 | } 595 | } 596 | async readJsonPromise(p) { 597 | const content = await this.readFilePromise(p, `utf8`); 598 | try { 599 | return JSON.parse(content); 600 | } catch (error) { 601 | error.message += ` (in ${p})`; 602 | throw error; 603 | } 604 | } 605 | readJsonSync(p) { 606 | const content = this.readFileSync(p, `utf8`); 607 | try { 608 | return JSON.parse(content); 609 | } catch (error) { 610 | error.message += ` (in ${p})`; 611 | throw error; 612 | } 613 | } 614 | async writeJsonPromise(p, data, { compact = false } = {}) { 615 | const space = compact ? 0 : 2; 616 | return await this.writeFilePromise(p, `${JSON.stringify(data, null, space)} 617 | `); 618 | } 619 | writeJsonSync(p, data, { compact = false } = {}) { 620 | const space = compact ? 0 : 2; 621 | return this.writeFileSync(p, `${JSON.stringify(data, null, space)} 622 | `); 623 | } 624 | async preserveTimePromise(p, cb) { 625 | const stat = await this.lstatPromise(p); 626 | const result = await cb(); 627 | if (typeof result !== `undefined`) 628 | p = result; 629 | await this.lutimesPromise(p, stat.atime, stat.mtime); 630 | } 631 | async preserveTimeSync(p, cb) { 632 | const stat = this.lstatSync(p); 633 | const result = cb(); 634 | if (typeof result !== `undefined`) 635 | p = result; 636 | this.lutimesSync(p, stat.atime, stat.mtime); 637 | } 638 | } 639 | class BasePortableFakeFS extends FakeFS { 640 | constructor() { 641 | super(ppath); 642 | } 643 | } 644 | function getEndOfLine(content) { 645 | const matches = content.match(/\r?\n/g); 646 | if (matches === null) 647 | return EOL; 648 | const crlf = matches.filter((nl) => nl === `\r 649 | `).length; 650 | const lf = matches.length - crlf; 651 | return crlf > lf ? `\r 652 | ` : ` 653 | `; 654 | } 655 | function normalizeLineEndings(originalContent, newContent) { 656 | return newContent.replace(/\r?\n/g, getEndOfLine(originalContent)); 657 | } 658 | 659 | class ProxiedFS extends FakeFS { 660 | getExtractHint(hints) { 661 | return this.baseFs.getExtractHint(hints); 662 | } 663 | resolve(path) { 664 | return this.mapFromBase(this.baseFs.resolve(this.mapToBase(path))); 665 | } 666 | getRealPath() { 667 | return this.mapFromBase(this.baseFs.getRealPath()); 668 | } 669 | async openPromise(p, flags, mode) { 670 | return this.baseFs.openPromise(this.mapToBase(p), flags, mode); 671 | } 672 | openSync(p, flags, mode) { 673 | return this.baseFs.openSync(this.mapToBase(p), flags, mode); 674 | } 675 | async opendirPromise(p, opts) { 676 | return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(p), opts), { path: p }); 677 | } 678 | opendirSync(p, opts) { 679 | return Object.assign(this.baseFs.opendirSync(this.mapToBase(p), opts), { path: p }); 680 | } 681 | async readPromise(fd, buffer, offset, length, position) { 682 | return await this.baseFs.readPromise(fd, buffer, offset, length, position); 683 | } 684 | readSync(fd, buffer, offset, length, position) { 685 | return this.baseFs.readSync(fd, buffer, offset, length, position); 686 | } 687 | async writePromise(fd, buffer, offset, length, position) { 688 | if (typeof buffer === `string`) { 689 | return await this.baseFs.writePromise(fd, buffer, offset); 690 | } else { 691 | return await this.baseFs.writePromise(fd, buffer, offset, length, position); 692 | } 693 | } 694 | writeSync(fd, buffer, offset, length, position) { 695 | if (typeof buffer === `string`) { 696 | return this.baseFs.writeSync(fd, buffer, offset); 697 | } else { 698 | return this.baseFs.writeSync(fd, buffer, offset, length, position); 699 | } 700 | } 701 | async closePromise(fd) { 702 | return this.baseFs.closePromise(fd); 703 | } 704 | closeSync(fd) { 705 | this.baseFs.closeSync(fd); 706 | } 707 | createReadStream(p, opts) { 708 | return this.baseFs.createReadStream(p !== null ? this.mapToBase(p) : p, opts); 709 | } 710 | createWriteStream(p, opts) { 711 | return this.baseFs.createWriteStream(p !== null ? this.mapToBase(p) : p, opts); 712 | } 713 | async realpathPromise(p) { 714 | return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(p))); 715 | } 716 | realpathSync(p) { 717 | return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(p))); 718 | } 719 | async existsPromise(p) { 720 | return this.baseFs.existsPromise(this.mapToBase(p)); 721 | } 722 | existsSync(p) { 723 | return this.baseFs.existsSync(this.mapToBase(p)); 724 | } 725 | accessSync(p, mode) { 726 | return this.baseFs.accessSync(this.mapToBase(p), mode); 727 | } 728 | async accessPromise(p, mode) { 729 | return this.baseFs.accessPromise(this.mapToBase(p), mode); 730 | } 731 | async statPromise(p, opts) { 732 | return this.baseFs.statPromise(this.mapToBase(p), opts); 733 | } 734 | statSync(p, opts) { 735 | return this.baseFs.statSync(this.mapToBase(p), opts); 736 | } 737 | async fstatPromise(fd, opts) { 738 | return this.baseFs.fstatPromise(fd, opts); 739 | } 740 | fstatSync(fd, opts) { 741 | return this.baseFs.fstatSync(fd, opts); 742 | } 743 | lstatPromise(p, opts) { 744 | return this.baseFs.lstatPromise(this.mapToBase(p), opts); 745 | } 746 | lstatSync(p, opts) { 747 | return this.baseFs.lstatSync(this.mapToBase(p), opts); 748 | } 749 | async fchmodPromise(fd, mask) { 750 | return this.baseFs.fchmodPromise(fd, mask); 751 | } 752 | fchmodSync(fd, mask) { 753 | return this.baseFs.fchmodSync(fd, mask); 754 | } 755 | async chmodPromise(p, mask) { 756 | return this.baseFs.chmodPromise(this.mapToBase(p), mask); 757 | } 758 | chmodSync(p, mask) { 759 | return this.baseFs.chmodSync(this.mapToBase(p), mask); 760 | } 761 | async fchownPromise(fd, uid, gid) { 762 | return this.baseFs.fchownPromise(fd, uid, gid); 763 | } 764 | fchownSync(fd, uid, gid) { 765 | return this.baseFs.fchownSync(fd, uid, gid); 766 | } 767 | async chownPromise(p, uid, gid) { 768 | return this.baseFs.chownPromise(this.mapToBase(p), uid, gid); 769 | } 770 | chownSync(p, uid, gid) { 771 | return this.baseFs.chownSync(this.mapToBase(p), uid, gid); 772 | } 773 | async renamePromise(oldP, newP) { 774 | return this.baseFs.renamePromise(this.mapToBase(oldP), this.mapToBase(newP)); 775 | } 776 | renameSync(oldP, newP) { 777 | return this.baseFs.renameSync(this.mapToBase(oldP), this.mapToBase(newP)); 778 | } 779 | async copyFilePromise(sourceP, destP, flags = 0) { 780 | return this.baseFs.copyFilePromise(this.mapToBase(sourceP), this.mapToBase(destP), flags); 781 | } 782 | copyFileSync(sourceP, destP, flags = 0) { 783 | return this.baseFs.copyFileSync(this.mapToBase(sourceP), this.mapToBase(destP), flags); 784 | } 785 | async appendFilePromise(p, content, opts) { 786 | return this.baseFs.appendFilePromise(this.fsMapToBase(p), content, opts); 787 | } 788 | appendFileSync(p, content, opts) { 789 | return this.baseFs.appendFileSync(this.fsMapToBase(p), content, opts); 790 | } 791 | async writeFilePromise(p, content, opts) { 792 | return this.baseFs.writeFilePromise(this.fsMapToBase(p), content, opts); 793 | } 794 | writeFileSync(p, content, opts) { 795 | return this.baseFs.writeFileSync(this.fsMapToBase(p), content, opts); 796 | } 797 | async unlinkPromise(p) { 798 | return this.baseFs.unlinkPromise(this.mapToBase(p)); 799 | } 800 | unlinkSync(p) { 801 | return this.baseFs.unlinkSync(this.mapToBase(p)); 802 | } 803 | async utimesPromise(p, atime, mtime) { 804 | return this.baseFs.utimesPromise(this.mapToBase(p), atime, mtime); 805 | } 806 | utimesSync(p, atime, mtime) { 807 | return this.baseFs.utimesSync(this.mapToBase(p), atime, mtime); 808 | } 809 | async lutimesPromise(p, atime, mtime) { 810 | return this.baseFs.lutimesPromise(this.mapToBase(p), atime, mtime); 811 | } 812 | lutimesSync(p, atime, mtime) { 813 | return this.baseFs.lutimesSync(this.mapToBase(p), atime, mtime); 814 | } 815 | async mkdirPromise(p, opts) { 816 | return this.baseFs.mkdirPromise(this.mapToBase(p), opts); 817 | } 818 | mkdirSync(p, opts) { 819 | return this.baseFs.mkdirSync(this.mapToBase(p), opts); 820 | } 821 | async rmdirPromise(p, opts) { 822 | return this.baseFs.rmdirPromise(this.mapToBase(p), opts); 823 | } 824 | rmdirSync(p, opts) { 825 | return this.baseFs.rmdirSync(this.mapToBase(p), opts); 826 | } 827 | async linkPromise(existingP, newP) { 828 | return this.baseFs.linkPromise(this.mapToBase(existingP), this.mapToBase(newP)); 829 | } 830 | linkSync(existingP, newP) { 831 | return this.baseFs.linkSync(this.mapToBase(existingP), this.mapToBase(newP)); 832 | } 833 | async symlinkPromise(target, p, type) { 834 | const mappedP = this.mapToBase(p); 835 | if (this.pathUtils.isAbsolute(target)) 836 | return this.baseFs.symlinkPromise(this.mapToBase(target), mappedP, type); 837 | const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); 838 | const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); 839 | return this.baseFs.symlinkPromise(mappedTarget, mappedP, type); 840 | } 841 | symlinkSync(target, p, type) { 842 | const mappedP = this.mapToBase(p); 843 | if (this.pathUtils.isAbsolute(target)) 844 | return this.baseFs.symlinkSync(this.mapToBase(target), mappedP, type); 845 | const mappedAbsoluteTarget = this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(p), target)); 846 | const mappedTarget = this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(mappedP), mappedAbsoluteTarget); 847 | return this.baseFs.symlinkSync(mappedTarget, mappedP, type); 848 | } 849 | async readFilePromise(p, encoding) { 850 | return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); 851 | } 852 | readFileSync(p, encoding) { 853 | return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); 854 | } 855 | readdirPromise(p, opts) { 856 | return this.baseFs.readdirPromise(this.mapToBase(p), opts); 857 | } 858 | readdirSync(p, opts) { 859 | return this.baseFs.readdirSync(this.mapToBase(p), opts); 860 | } 861 | async readlinkPromise(p) { 862 | return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(p))); 863 | } 864 | readlinkSync(p) { 865 | return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(p))); 866 | } 867 | async truncatePromise(p, len) { 868 | return this.baseFs.truncatePromise(this.mapToBase(p), len); 869 | } 870 | truncateSync(p, len) { 871 | return this.baseFs.truncateSync(this.mapToBase(p), len); 872 | } 873 | async ftruncatePromise(fd, len) { 874 | return this.baseFs.ftruncatePromise(fd, len); 875 | } 876 | ftruncateSync(fd, len) { 877 | return this.baseFs.ftruncateSync(fd, len); 878 | } 879 | watch(p, a, b) { 880 | return this.baseFs.watch( 881 | this.mapToBase(p), 882 | a, 883 | b 884 | ); 885 | } 886 | watchFile(p, a, b) { 887 | return this.baseFs.watchFile( 888 | this.mapToBase(p), 889 | a, 890 | b 891 | ); 892 | } 893 | unwatchFile(p, cb) { 894 | return this.baseFs.unwatchFile(this.mapToBase(p), cb); 895 | } 896 | fsMapToBase(p) { 897 | if (typeof p === `number`) { 898 | return p; 899 | } else { 900 | return this.mapToBase(p); 901 | } 902 | } 903 | } 904 | 905 | class NodeFS extends BasePortableFakeFS { 906 | constructor(realFs = fs) { 907 | super(); 908 | this.realFs = realFs; 909 | } 910 | getExtractHint() { 911 | return false; 912 | } 913 | getRealPath() { 914 | return PortablePath.root; 915 | } 916 | resolve(p) { 917 | return ppath.resolve(p); 918 | } 919 | async openPromise(p, flags, mode) { 920 | return await new Promise((resolve, reject) => { 921 | this.realFs.open(npath.fromPortablePath(p), flags, mode, this.makeCallback(resolve, reject)); 922 | }); 923 | } 924 | openSync(p, flags, mode) { 925 | return this.realFs.openSync(npath.fromPortablePath(p), flags, mode); 926 | } 927 | async opendirPromise(p, opts) { 928 | return await new Promise((resolve, reject) => { 929 | if (typeof opts !== `undefined`) { 930 | this.realFs.opendir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 931 | } else { 932 | this.realFs.opendir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 933 | } 934 | }).then((dir) => { 935 | const dirWithFixedPath = dir; 936 | Object.defineProperty(dirWithFixedPath, `path`, { 937 | value: p, 938 | configurable: true, 939 | writable: true 940 | }); 941 | return dirWithFixedPath; 942 | }); 943 | } 944 | opendirSync(p, opts) { 945 | const dir = typeof opts !== `undefined` ? this.realFs.opendirSync(npath.fromPortablePath(p), opts) : this.realFs.opendirSync(npath.fromPortablePath(p)); 946 | const dirWithFixedPath = dir; 947 | Object.defineProperty(dirWithFixedPath, `path`, { 948 | value: p, 949 | configurable: true, 950 | writable: true 951 | }); 952 | return dirWithFixedPath; 953 | } 954 | async readPromise(fd, buffer, offset = 0, length = 0, position = -1) { 955 | return await new Promise((resolve, reject) => { 956 | this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => { 957 | if (error) { 958 | reject(error); 959 | } else { 960 | resolve(bytesRead); 961 | } 962 | }); 963 | }); 964 | } 965 | readSync(fd, buffer, offset, length, position) { 966 | return this.realFs.readSync(fd, buffer, offset, length, position); 967 | } 968 | async writePromise(fd, buffer, offset, length, position) { 969 | return await new Promise((resolve, reject) => { 970 | if (typeof buffer === `string`) { 971 | return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject)); 972 | } else { 973 | return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject)); 974 | } 975 | }); 976 | } 977 | writeSync(fd, buffer, offset, length, position) { 978 | if (typeof buffer === `string`) { 979 | return this.realFs.writeSync(fd, buffer, offset); 980 | } else { 981 | return this.realFs.writeSync(fd, buffer, offset, length, position); 982 | } 983 | } 984 | async closePromise(fd) { 985 | await new Promise((resolve, reject) => { 986 | this.realFs.close(fd, this.makeCallback(resolve, reject)); 987 | }); 988 | } 989 | closeSync(fd) { 990 | this.realFs.closeSync(fd); 991 | } 992 | createReadStream(p, opts) { 993 | const realPath = p !== null ? npath.fromPortablePath(p) : p; 994 | return this.realFs.createReadStream(realPath, opts); 995 | } 996 | createWriteStream(p, opts) { 997 | const realPath = p !== null ? npath.fromPortablePath(p) : p; 998 | return this.realFs.createWriteStream(realPath, opts); 999 | } 1000 | async realpathPromise(p) { 1001 | return await new Promise((resolve, reject) => { 1002 | this.realFs.realpath(npath.fromPortablePath(p), {}, this.makeCallback(resolve, reject)); 1003 | }).then((path) => { 1004 | return npath.toPortablePath(path); 1005 | }); 1006 | } 1007 | realpathSync(p) { 1008 | return npath.toPortablePath(this.realFs.realpathSync(npath.fromPortablePath(p), {})); 1009 | } 1010 | async existsPromise(p) { 1011 | return await new Promise((resolve) => { 1012 | this.realFs.exists(npath.fromPortablePath(p), resolve); 1013 | }); 1014 | } 1015 | accessSync(p, mode) { 1016 | return this.realFs.accessSync(npath.fromPortablePath(p), mode); 1017 | } 1018 | async accessPromise(p, mode) { 1019 | return await new Promise((resolve, reject) => { 1020 | this.realFs.access(npath.fromPortablePath(p), mode, this.makeCallback(resolve, reject)); 1021 | }); 1022 | } 1023 | existsSync(p) { 1024 | return this.realFs.existsSync(npath.fromPortablePath(p)); 1025 | } 1026 | async statPromise(p, opts) { 1027 | return await new Promise((resolve, reject) => { 1028 | if (opts) { 1029 | this.realFs.stat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 1030 | } else { 1031 | this.realFs.stat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 1032 | } 1033 | }); 1034 | } 1035 | statSync(p, opts) { 1036 | if (opts) { 1037 | return this.realFs.statSync(npath.fromPortablePath(p), opts); 1038 | } else { 1039 | return this.realFs.statSync(npath.fromPortablePath(p)); 1040 | } 1041 | } 1042 | async fstatPromise(fd, opts) { 1043 | return await new Promise((resolve, reject) => { 1044 | if (opts) { 1045 | this.realFs.fstat(fd, opts, this.makeCallback(resolve, reject)); 1046 | } else { 1047 | this.realFs.fstat(fd, this.makeCallback(resolve, reject)); 1048 | } 1049 | }); 1050 | } 1051 | fstatSync(fd, opts) { 1052 | if (opts) { 1053 | return this.realFs.fstatSync(fd, opts); 1054 | } else { 1055 | return this.realFs.fstatSync(fd); 1056 | } 1057 | } 1058 | async lstatPromise(p, opts) { 1059 | return await new Promise((resolve, reject) => { 1060 | if (opts) { 1061 | this.realFs.lstat(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 1062 | } else { 1063 | this.realFs.lstat(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 1064 | } 1065 | }); 1066 | } 1067 | lstatSync(p, opts) { 1068 | if (opts) { 1069 | return this.realFs.lstatSync(npath.fromPortablePath(p), opts); 1070 | } else { 1071 | return this.realFs.lstatSync(npath.fromPortablePath(p)); 1072 | } 1073 | } 1074 | async fchmodPromise(fd, mask) { 1075 | return await new Promise((resolve, reject) => { 1076 | this.realFs.fchmod(fd, mask, this.makeCallback(resolve, reject)); 1077 | }); 1078 | } 1079 | fchmodSync(fd, mask) { 1080 | return this.realFs.fchmodSync(fd, mask); 1081 | } 1082 | async chmodPromise(p, mask) { 1083 | return await new Promise((resolve, reject) => { 1084 | this.realFs.chmod(npath.fromPortablePath(p), mask, this.makeCallback(resolve, reject)); 1085 | }); 1086 | } 1087 | chmodSync(p, mask) { 1088 | return this.realFs.chmodSync(npath.fromPortablePath(p), mask); 1089 | } 1090 | async fchownPromise(fd, uid, gid) { 1091 | return await new Promise((resolve, reject) => { 1092 | this.realFs.fchown(fd, uid, gid, this.makeCallback(resolve, reject)); 1093 | }); 1094 | } 1095 | fchownSync(fd, uid, gid) { 1096 | return this.realFs.fchownSync(fd, uid, gid); 1097 | } 1098 | async chownPromise(p, uid, gid) { 1099 | return await new Promise((resolve, reject) => { 1100 | this.realFs.chown(npath.fromPortablePath(p), uid, gid, this.makeCallback(resolve, reject)); 1101 | }); 1102 | } 1103 | chownSync(p, uid, gid) { 1104 | return this.realFs.chownSync(npath.fromPortablePath(p), uid, gid); 1105 | } 1106 | async renamePromise(oldP, newP) { 1107 | return await new Promise((resolve, reject) => { 1108 | this.realFs.rename(npath.fromPortablePath(oldP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); 1109 | }); 1110 | } 1111 | renameSync(oldP, newP) { 1112 | return this.realFs.renameSync(npath.fromPortablePath(oldP), npath.fromPortablePath(newP)); 1113 | } 1114 | async copyFilePromise(sourceP, destP, flags = 0) { 1115 | return await new Promise((resolve, reject) => { 1116 | this.realFs.copyFile(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags, this.makeCallback(resolve, reject)); 1117 | }); 1118 | } 1119 | copyFileSync(sourceP, destP, flags = 0) { 1120 | return this.realFs.copyFileSync(npath.fromPortablePath(sourceP), npath.fromPortablePath(destP), flags); 1121 | } 1122 | async appendFilePromise(p, content, opts) { 1123 | return await new Promise((resolve, reject) => { 1124 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 1125 | if (opts) { 1126 | this.realFs.appendFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); 1127 | } else { 1128 | this.realFs.appendFile(fsNativePath, content, this.makeCallback(resolve, reject)); 1129 | } 1130 | }); 1131 | } 1132 | appendFileSync(p, content, opts) { 1133 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 1134 | if (opts) { 1135 | this.realFs.appendFileSync(fsNativePath, content, opts); 1136 | } else { 1137 | this.realFs.appendFileSync(fsNativePath, content); 1138 | } 1139 | } 1140 | async writeFilePromise(p, content, opts) { 1141 | return await new Promise((resolve, reject) => { 1142 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 1143 | if (opts) { 1144 | this.realFs.writeFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); 1145 | } else { 1146 | this.realFs.writeFile(fsNativePath, content, this.makeCallback(resolve, reject)); 1147 | } 1148 | }); 1149 | } 1150 | writeFileSync(p, content, opts) { 1151 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 1152 | if (opts) { 1153 | this.realFs.writeFileSync(fsNativePath, content, opts); 1154 | } else { 1155 | this.realFs.writeFileSync(fsNativePath, content); 1156 | } 1157 | } 1158 | async unlinkPromise(p) { 1159 | return await new Promise((resolve, reject) => { 1160 | this.realFs.unlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 1161 | }); 1162 | } 1163 | unlinkSync(p) { 1164 | return this.realFs.unlinkSync(npath.fromPortablePath(p)); 1165 | } 1166 | async utimesPromise(p, atime, mtime) { 1167 | return await new Promise((resolve, reject) => { 1168 | this.realFs.utimes(npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); 1169 | }); 1170 | } 1171 | utimesSync(p, atime, mtime) { 1172 | this.realFs.utimesSync(npath.fromPortablePath(p), atime, mtime); 1173 | } 1174 | async lutimesPromise(p, atime, mtime) { 1175 | return await new Promise((resolve, reject) => { 1176 | this.realFs.lutimes(npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); 1177 | }); 1178 | } 1179 | lutimesSync(p, atime, mtime) { 1180 | this.realFs.lutimesSync(npath.fromPortablePath(p), atime, mtime); 1181 | } 1182 | async mkdirPromise(p, opts) { 1183 | return await new Promise((resolve, reject) => { 1184 | this.realFs.mkdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 1185 | }); 1186 | } 1187 | mkdirSync(p, opts) { 1188 | return this.realFs.mkdirSync(npath.fromPortablePath(p), opts); 1189 | } 1190 | async rmdirPromise(p, opts) { 1191 | return await new Promise((resolve, reject) => { 1192 | if (opts) { 1193 | this.realFs.rmdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 1194 | } else { 1195 | this.realFs.rmdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 1196 | } 1197 | }); 1198 | } 1199 | rmdirSync(p, opts) { 1200 | return this.realFs.rmdirSync(npath.fromPortablePath(p), opts); 1201 | } 1202 | async linkPromise(existingP, newP) { 1203 | return await new Promise((resolve, reject) => { 1204 | this.realFs.link(npath.fromPortablePath(existingP), npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); 1205 | }); 1206 | } 1207 | linkSync(existingP, newP) { 1208 | return this.realFs.linkSync(npath.fromPortablePath(existingP), npath.fromPortablePath(newP)); 1209 | } 1210 | async symlinkPromise(target, p, type) { 1211 | return await new Promise((resolve, reject) => { 1212 | this.realFs.symlink(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type, this.makeCallback(resolve, reject)); 1213 | }); 1214 | } 1215 | symlinkSync(target, p, type) { 1216 | return this.realFs.symlinkSync(npath.fromPortablePath(target.replace(/\/+$/, ``)), npath.fromPortablePath(p), type); 1217 | } 1218 | async readFilePromise(p, encoding) { 1219 | return await new Promise((resolve, reject) => { 1220 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 1221 | this.realFs.readFile(fsNativePath, encoding, this.makeCallback(resolve, reject)); 1222 | }); 1223 | } 1224 | readFileSync(p, encoding) { 1225 | const fsNativePath = typeof p === `string` ? npath.fromPortablePath(p) : p; 1226 | return this.realFs.readFileSync(fsNativePath, encoding); 1227 | } 1228 | async readdirPromise(p, opts) { 1229 | return await new Promise((resolve, reject) => { 1230 | if (opts) { 1231 | this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); 1232 | } else { 1233 | this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback((value) => resolve(value), reject)); 1234 | } 1235 | }); 1236 | } 1237 | readdirSync(p, opts) { 1238 | if (opts) { 1239 | return this.realFs.readdirSync(npath.fromPortablePath(p), opts); 1240 | } else { 1241 | return this.realFs.readdirSync(npath.fromPortablePath(p)); 1242 | } 1243 | } 1244 | async readlinkPromise(p) { 1245 | return await new Promise((resolve, reject) => { 1246 | this.realFs.readlink(npath.fromPortablePath(p), this.makeCallback(resolve, reject)); 1247 | }).then((path) => { 1248 | return npath.toPortablePath(path); 1249 | }); 1250 | } 1251 | readlinkSync(p) { 1252 | return npath.toPortablePath(this.realFs.readlinkSync(npath.fromPortablePath(p))); 1253 | } 1254 | async truncatePromise(p, len) { 1255 | return await new Promise((resolve, reject) => { 1256 | this.realFs.truncate(npath.fromPortablePath(p), len, this.makeCallback(resolve, reject)); 1257 | }); 1258 | } 1259 | truncateSync(p, len) { 1260 | return this.realFs.truncateSync(npath.fromPortablePath(p), len); 1261 | } 1262 | async ftruncatePromise(fd, len) { 1263 | return await new Promise((resolve, reject) => { 1264 | this.realFs.ftruncate(fd, len, this.makeCallback(resolve, reject)); 1265 | }); 1266 | } 1267 | ftruncateSync(fd, len) { 1268 | return this.realFs.ftruncateSync(fd, len); 1269 | } 1270 | watch(p, a, b) { 1271 | return this.realFs.watch( 1272 | npath.fromPortablePath(p), 1273 | a, 1274 | b 1275 | ); 1276 | } 1277 | watchFile(p, a, b) { 1278 | return this.realFs.watchFile( 1279 | npath.fromPortablePath(p), 1280 | a, 1281 | b 1282 | ); 1283 | } 1284 | unwatchFile(p, cb) { 1285 | return this.realFs.unwatchFile(npath.fromPortablePath(p), cb); 1286 | } 1287 | makeCallback(resolve, reject) { 1288 | return (err, result) => { 1289 | if (err) { 1290 | reject(err); 1291 | } else { 1292 | resolve(result); 1293 | } 1294 | }; 1295 | } 1296 | } 1297 | 1298 | const NUMBER_REGEXP = /^[0-9]+$/; 1299 | const VIRTUAL_REGEXP = /^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/; 1300 | const VALID_COMPONENT = /^([^/]+-)?[a-f0-9]+$/; 1301 | class VirtualFS extends ProxiedFS { 1302 | constructor({ baseFs = new NodeFS() } = {}) { 1303 | super(ppath); 1304 | this.baseFs = baseFs; 1305 | } 1306 | static makeVirtualPath(base, component, to) { 1307 | if (ppath.basename(base) !== `__virtual__`) 1308 | throw new Error(`Assertion failed: Virtual folders must be named "__virtual__"`); 1309 | if (!ppath.basename(component).match(VALID_COMPONENT)) 1310 | throw new Error(`Assertion failed: Virtual components must be ended by an hexadecimal hash`); 1311 | const target = ppath.relative(ppath.dirname(base), to); 1312 | const segments = target.split(`/`); 1313 | let depth = 0; 1314 | while (depth < segments.length && segments[depth] === `..`) 1315 | depth += 1; 1316 | const finalSegments = segments.slice(depth); 1317 | const fullVirtualPath = ppath.join(base, component, String(depth), ...finalSegments); 1318 | return fullVirtualPath; 1319 | } 1320 | static resolveVirtual(p) { 1321 | const match = p.match(VIRTUAL_REGEXP); 1322 | if (!match || !match[3] && match[5]) 1323 | return p; 1324 | const target = ppath.dirname(match[1]); 1325 | if (!match[3] || !match[4]) 1326 | return target; 1327 | const isnum = NUMBER_REGEXP.test(match[4]); 1328 | if (!isnum) 1329 | return p; 1330 | const depth = Number(match[4]); 1331 | const backstep = `../`.repeat(depth); 1332 | const subpath = match[5] || `.`; 1333 | return VirtualFS.resolveVirtual(ppath.join(target, backstep, subpath)); 1334 | } 1335 | getExtractHint(hints) { 1336 | return this.baseFs.getExtractHint(hints); 1337 | } 1338 | getRealPath() { 1339 | return this.baseFs.getRealPath(); 1340 | } 1341 | realpathSync(p) { 1342 | const match = p.match(VIRTUAL_REGEXP); 1343 | if (!match) 1344 | return this.baseFs.realpathSync(p); 1345 | if (!match[5]) 1346 | return p; 1347 | const realpath = this.baseFs.realpathSync(this.mapToBase(p)); 1348 | return VirtualFS.makeVirtualPath(match[1], match[3], realpath); 1349 | } 1350 | async realpathPromise(p) { 1351 | const match = p.match(VIRTUAL_REGEXP); 1352 | if (!match) 1353 | return await this.baseFs.realpathPromise(p); 1354 | if (!match[5]) 1355 | return p; 1356 | const realpath = await this.baseFs.realpathPromise(this.mapToBase(p)); 1357 | return VirtualFS.makeVirtualPath(match[1], match[3], realpath); 1358 | } 1359 | mapToBase(p) { 1360 | if (p === ``) 1361 | return p; 1362 | if (this.pathUtils.isAbsolute(p)) 1363 | return VirtualFS.resolveVirtual(p); 1364 | const resolvedRoot = VirtualFS.resolveVirtual(this.baseFs.resolve(PortablePath.dot)); 1365 | const resolvedP = VirtualFS.resolveVirtual(this.baseFs.resolve(p)); 1366 | return ppath.relative(resolvedRoot, resolvedP) || PortablePath.dot; 1367 | } 1368 | mapFromBase(p) { 1369 | return p; 1370 | } 1371 | } 1372 | 1373 | const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10)); 1374 | const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13; 1375 | const HAS_LAZY_LOADED_TRANSLATORS = major > 19 || major === 19 && minor >= 3; 1376 | 1377 | function readPackageScope(checkPath) { 1378 | const rootSeparatorIndex = checkPath.indexOf(npath.sep); 1379 | let separatorIndex; 1380 | do { 1381 | separatorIndex = checkPath.lastIndexOf(npath.sep); 1382 | checkPath = checkPath.slice(0, separatorIndex); 1383 | if (checkPath.endsWith(`${npath.sep}node_modules`)) 1384 | return false; 1385 | const pjson = readPackage(checkPath + npath.sep); 1386 | if (pjson) { 1387 | return { 1388 | data: pjson, 1389 | path: checkPath 1390 | }; 1391 | } 1392 | } while (separatorIndex > rootSeparatorIndex); 1393 | return false; 1394 | } 1395 | function readPackage(requestPath) { 1396 | const jsonPath = npath.resolve(requestPath, `package.json`); 1397 | if (!fs.existsSync(jsonPath)) 1398 | return null; 1399 | return JSON.parse(fs.readFileSync(jsonPath, `utf8`)); 1400 | } 1401 | 1402 | async function tryReadFile$1(path2) { 1403 | try { 1404 | return await fs.promises.readFile(path2, `utf8`); 1405 | } catch (error) { 1406 | if (error.code === `ENOENT`) 1407 | return null; 1408 | throw error; 1409 | } 1410 | } 1411 | function tryParseURL(str, base) { 1412 | try { 1413 | return new URL$1(str, base); 1414 | } catch { 1415 | return null; 1416 | } 1417 | } 1418 | let entrypointPath = null; 1419 | function setEntrypointPath(file) { 1420 | entrypointPath = file; 1421 | } 1422 | function getFileFormat(filepath) { 1423 | const ext = path.extname(filepath); 1424 | switch (ext) { 1425 | case `.mjs`: { 1426 | return `module`; 1427 | } 1428 | case `.cjs`: { 1429 | return `commonjs`; 1430 | } 1431 | case `.wasm`: { 1432 | throw new Error( 1433 | `Unknown file extension ".wasm" for ${filepath}` 1434 | ); 1435 | } 1436 | case `.json`: { 1437 | return `json`; 1438 | } 1439 | case `.js`: { 1440 | const pkg = readPackageScope(filepath); 1441 | if (!pkg) 1442 | return `commonjs`; 1443 | return pkg.data.type ?? `commonjs`; 1444 | } 1445 | default: { 1446 | if (entrypointPath !== filepath) 1447 | return null; 1448 | const pkg = readPackageScope(filepath); 1449 | if (!pkg) 1450 | return `commonjs`; 1451 | if (pkg.data.type === `module`) 1452 | return null; 1453 | return pkg.data.type ?? `commonjs`; 1454 | } 1455 | } 1456 | } 1457 | 1458 | async function load$1(urlString, context, nextLoad) { 1459 | const url = tryParseURL(urlString); 1460 | if (url?.protocol !== `file:`) 1461 | return nextLoad(urlString, context, nextLoad); 1462 | const filePath = fileURLToPath(url); 1463 | const format = getFileFormat(filePath); 1464 | if (!format) 1465 | return nextLoad(urlString, context, nextLoad); 1466 | if (format === `json` && context.importAssertions?.type !== `json`) { 1467 | const err = new TypeError(`[ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "${urlString}" needs an import assertion of type "json"`); 1468 | err.code = `ERR_IMPORT_ASSERTION_TYPE_MISSING`; 1469 | throw err; 1470 | } 1471 | if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { 1472 | const pathToSend = pathToFileURL( 1473 | npath.fromPortablePath( 1474 | VirtualFS.resolveVirtual(npath.toPortablePath(filePath)) 1475 | ) 1476 | ).href; 1477 | process.send({ 1478 | "watch:import": WATCH_MODE_MESSAGE_USES_ARRAYS ? [pathToSend] : pathToSend 1479 | }); 1480 | } 1481 | return { 1482 | format, 1483 | source: format === `commonjs` ? void 0 : await fs.promises.readFile(filePath, `utf8`), 1484 | shortCircuit: true 1485 | }; 1486 | } 1487 | 1488 | const ArrayIsArray = Array.isArray; 1489 | const JSONStringify = JSON.stringify; 1490 | const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames; 1491 | const ObjectPrototypeHasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); 1492 | const RegExpPrototypeExec = (obj, string) => RegExp.prototype.exec.call(obj, string); 1493 | const RegExpPrototypeSymbolReplace = (obj, ...rest) => RegExp.prototype[Symbol.replace].apply(obj, rest); 1494 | const StringPrototypeEndsWith = (str, ...rest) => String.prototype.endsWith.apply(str, rest); 1495 | const StringPrototypeIncludes = (str, ...rest) => String.prototype.includes.apply(str, rest); 1496 | const StringPrototypeLastIndexOf = (str, ...rest) => String.prototype.lastIndexOf.apply(str, rest); 1497 | const StringPrototypeIndexOf = (str, ...rest) => String.prototype.indexOf.apply(str, rest); 1498 | const StringPrototypeReplace = (str, ...rest) => String.prototype.replace.apply(str, rest); 1499 | const StringPrototypeSlice = (str, ...rest) => String.prototype.slice.apply(str, rest); 1500 | const StringPrototypeStartsWith = (str, ...rest) => String.prototype.startsWith.apply(str, rest); 1501 | const SafeMap = Map; 1502 | const JSONParse = JSON.parse; 1503 | 1504 | function createErrorType(code, messageCreator, errorType) { 1505 | return class extends errorType { 1506 | constructor(...args) { 1507 | super(messageCreator(...args)); 1508 | this.code = code; 1509 | this.name = `${errorType.name} [${code}]`; 1510 | } 1511 | }; 1512 | } 1513 | const ERR_PACKAGE_IMPORT_NOT_DEFINED = createErrorType( 1514 | `ERR_PACKAGE_IMPORT_NOT_DEFINED`, 1515 | (specifier, packagePath, base) => { 1516 | return `Package import specifier "${specifier}" is not defined${packagePath ? ` in package ${packagePath}package.json` : ``} imported from ${base}`; 1517 | }, 1518 | TypeError 1519 | ); 1520 | const ERR_INVALID_MODULE_SPECIFIER = createErrorType( 1521 | `ERR_INVALID_MODULE_SPECIFIER`, 1522 | (request, reason, base = void 0) => { 1523 | return `Invalid module "${request}" ${reason}${base ? ` imported from ${base}` : ``}`; 1524 | }, 1525 | TypeError 1526 | ); 1527 | const ERR_INVALID_PACKAGE_TARGET = createErrorType( 1528 | `ERR_INVALID_PACKAGE_TARGET`, 1529 | (pkgPath, key, target, isImport = false, base = void 0) => { 1530 | const relError = typeof target === `string` && !isImport && target.length && !StringPrototypeStartsWith(target, `./`); 1531 | if (key === `.`) { 1532 | assert(isImport === false); 1533 | return `Invalid "exports" main target ${JSONStringify(target)} defined in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; 1534 | } 1535 | return `Invalid "${isImport ? `imports` : `exports`}" target ${JSONStringify( 1536 | target 1537 | )} defined for '${key}' in the package config ${pkgPath}package.json${base ? ` imported from ${base}` : ``}${relError ? `; targets must start with "./"` : ``}`; 1538 | }, 1539 | Error 1540 | ); 1541 | const ERR_INVALID_PACKAGE_CONFIG = createErrorType( 1542 | `ERR_INVALID_PACKAGE_CONFIG`, 1543 | (path, base, message) => { 1544 | return `Invalid package config ${path}${base ? ` while importing ${base}` : ``}${message ? `. ${message}` : ``}`; 1545 | }, 1546 | Error 1547 | ); 1548 | 1549 | function filterOwnProperties(source, keys) { 1550 | const filtered = /* @__PURE__ */ Object.create(null); 1551 | for (let i = 0; i < keys.length; i++) { 1552 | const key = keys[i]; 1553 | if (ObjectPrototypeHasOwnProperty(source, key)) { 1554 | filtered[key] = source[key]; 1555 | } 1556 | } 1557 | return filtered; 1558 | } 1559 | 1560 | const packageJSONCache = new SafeMap(); 1561 | function getPackageConfig(path, specifier, base, readFileSyncFn) { 1562 | const existing = packageJSONCache.get(path); 1563 | if (existing !== void 0) { 1564 | return existing; 1565 | } 1566 | const source = readFileSyncFn(path); 1567 | if (source === void 0) { 1568 | const packageConfig2 = { 1569 | pjsonPath: path, 1570 | exists: false, 1571 | main: void 0, 1572 | name: void 0, 1573 | type: "none", 1574 | exports: void 0, 1575 | imports: void 0 1576 | }; 1577 | packageJSONCache.set(path, packageConfig2); 1578 | return packageConfig2; 1579 | } 1580 | let packageJSON; 1581 | try { 1582 | packageJSON = JSONParse(source); 1583 | } catch (error) { 1584 | throw new ERR_INVALID_PACKAGE_CONFIG( 1585 | path, 1586 | (base ? `"${specifier}" from ` : "") + fileURLToPath(base || specifier), 1587 | error.message 1588 | ); 1589 | } 1590 | let { imports, main, name, type } = filterOwnProperties(packageJSON, [ 1591 | "imports", 1592 | "main", 1593 | "name", 1594 | "type" 1595 | ]); 1596 | const exports = ObjectPrototypeHasOwnProperty(packageJSON, "exports") ? packageJSON.exports : void 0; 1597 | if (typeof imports !== "object" || imports === null) { 1598 | imports = void 0; 1599 | } 1600 | if (typeof main !== "string") { 1601 | main = void 0; 1602 | } 1603 | if (typeof name !== "string") { 1604 | name = void 0; 1605 | } 1606 | if (type !== "module" && type !== "commonjs") { 1607 | type = "none"; 1608 | } 1609 | const packageConfig = { 1610 | pjsonPath: path, 1611 | exists: true, 1612 | main, 1613 | name, 1614 | type, 1615 | exports, 1616 | imports 1617 | }; 1618 | packageJSONCache.set(path, packageConfig); 1619 | return packageConfig; 1620 | } 1621 | function getPackageScopeConfig(resolved, readFileSyncFn) { 1622 | let packageJSONUrl = new URL("./package.json", resolved); 1623 | while (true) { 1624 | const packageJSONPath2 = packageJSONUrl.pathname; 1625 | if (StringPrototypeEndsWith(packageJSONPath2, "node_modules/package.json")) { 1626 | break; 1627 | } 1628 | const packageConfig2 = getPackageConfig( 1629 | fileURLToPath(packageJSONUrl), 1630 | resolved, 1631 | void 0, 1632 | readFileSyncFn 1633 | ); 1634 | if (packageConfig2.exists) { 1635 | return packageConfig2; 1636 | } 1637 | const lastPackageJSONUrl = packageJSONUrl; 1638 | packageJSONUrl = new URL("../package.json", packageJSONUrl); 1639 | if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { 1640 | break; 1641 | } 1642 | } 1643 | const packageJSONPath = fileURLToPath(packageJSONUrl); 1644 | const packageConfig = { 1645 | pjsonPath: packageJSONPath, 1646 | exists: false, 1647 | main: void 0, 1648 | name: void 0, 1649 | type: "none", 1650 | exports: void 0, 1651 | imports: void 0 1652 | }; 1653 | packageJSONCache.set(packageJSONPath, packageConfig); 1654 | return packageConfig; 1655 | } 1656 | 1657 | /** 1658 | @license 1659 | Copyright Node.js contributors. All rights reserved. 1660 | 1661 | Permission is hereby granted, free of charge, to any person obtaining a copy 1662 | of this software and associated documentation files (the "Software"), to 1663 | deal in the Software without restriction, including without limitation the 1664 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 1665 | sell copies of the Software, and to permit persons to whom the Software is 1666 | furnished to do so, subject to the following conditions: 1667 | 1668 | The above copyright notice and this permission notice shall be included in 1669 | all copies or substantial portions of the Software. 1670 | 1671 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1672 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1673 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1674 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1675 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 1676 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 1677 | IN THE SOFTWARE. 1678 | */ 1679 | function throwImportNotDefined(specifier, packageJSONUrl, base) { 1680 | throw new ERR_PACKAGE_IMPORT_NOT_DEFINED( 1681 | specifier, 1682 | packageJSONUrl && fileURLToPath(new URL(".", packageJSONUrl)), 1683 | fileURLToPath(base) 1684 | ); 1685 | } 1686 | function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) { 1687 | const reason = `request is not a valid subpath for the "${internal ? "imports" : "exports"}" resolution of ${fileURLToPath(packageJSONUrl)}`; 1688 | throw new ERR_INVALID_MODULE_SPECIFIER( 1689 | subpath, 1690 | reason, 1691 | base && fileURLToPath(base) 1692 | ); 1693 | } 1694 | function throwInvalidPackageTarget(subpath, target, packageJSONUrl, internal, base) { 1695 | if (typeof target === "object" && target !== null) { 1696 | target = JSONStringify(target, null, ""); 1697 | } else { 1698 | target = `${target}`; 1699 | } 1700 | throw new ERR_INVALID_PACKAGE_TARGET( 1701 | fileURLToPath(new URL(".", packageJSONUrl)), 1702 | subpath, 1703 | target, 1704 | internal, 1705 | base && fileURLToPath(base) 1706 | ); 1707 | } 1708 | const invalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i; 1709 | const patternRegEx = /\*/g; 1710 | function resolvePackageTargetString(target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) { 1711 | if (subpath !== "" && !pattern && target[target.length - 1] !== "/") 1712 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1713 | if (!StringPrototypeStartsWith(target, "./")) { 1714 | if (internal && !StringPrototypeStartsWith(target, "../") && !StringPrototypeStartsWith(target, "/")) { 1715 | let isURL = false; 1716 | try { 1717 | new URL(target); 1718 | isURL = true; 1719 | } catch { 1720 | } 1721 | if (!isURL) { 1722 | const exportTarget = pattern ? RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) : target + subpath; 1723 | return exportTarget; 1724 | } 1725 | } 1726 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1727 | } 1728 | if (RegExpPrototypeExec( 1729 | invalidSegmentRegEx, 1730 | StringPrototypeSlice(target, 2) 1731 | ) !== null) 1732 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1733 | const resolved = new URL(target, packageJSONUrl); 1734 | const resolvedPath = resolved.pathname; 1735 | const packagePath = new URL(".", packageJSONUrl).pathname; 1736 | if (!StringPrototypeStartsWith(resolvedPath, packagePath)) 1737 | throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); 1738 | if (subpath === "") 1739 | return resolved; 1740 | if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) { 1741 | const request = pattern ? StringPrototypeReplace(match, "*", () => subpath) : match + subpath; 1742 | throwInvalidSubpath(request, packageJSONUrl, internal, base); 1743 | } 1744 | if (pattern) { 1745 | return new URL( 1746 | RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath) 1747 | ); 1748 | } 1749 | return new URL(subpath, resolved); 1750 | } 1751 | function isArrayIndex(key) { 1752 | const keyNum = +key; 1753 | if (`${keyNum}` !== key) 1754 | return false; 1755 | return keyNum >= 0 && keyNum < 4294967295; 1756 | } 1757 | function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath, base, pattern, internal, conditions) { 1758 | if (typeof target === "string") { 1759 | return resolvePackageTargetString( 1760 | target, 1761 | subpath, 1762 | packageSubpath, 1763 | packageJSONUrl, 1764 | base, 1765 | pattern, 1766 | internal); 1767 | } else if (ArrayIsArray(target)) { 1768 | if (target.length === 0) { 1769 | return null; 1770 | } 1771 | let lastException; 1772 | for (let i = 0; i < target.length; i++) { 1773 | const targetItem = target[i]; 1774 | let resolveResult; 1775 | try { 1776 | resolveResult = resolvePackageTarget( 1777 | packageJSONUrl, 1778 | targetItem, 1779 | subpath, 1780 | packageSubpath, 1781 | base, 1782 | pattern, 1783 | internal, 1784 | conditions 1785 | ); 1786 | } catch (e) { 1787 | lastException = e; 1788 | if (e.code === "ERR_INVALID_PACKAGE_TARGET") { 1789 | continue; 1790 | } 1791 | throw e; 1792 | } 1793 | if (resolveResult === void 0) { 1794 | continue; 1795 | } 1796 | if (resolveResult === null) { 1797 | lastException = null; 1798 | continue; 1799 | } 1800 | return resolveResult; 1801 | } 1802 | if (lastException === void 0 || lastException === null) 1803 | return lastException; 1804 | throw lastException; 1805 | } else if (typeof target === "object" && target !== null) { 1806 | const keys = ObjectGetOwnPropertyNames(target); 1807 | for (let i = 0; i < keys.length; i++) { 1808 | const key = keys[i]; 1809 | if (isArrayIndex(key)) { 1810 | throw new ERR_INVALID_PACKAGE_CONFIG( 1811 | fileURLToPath(packageJSONUrl), 1812 | base, 1813 | '"exports" cannot contain numeric property keys.' 1814 | ); 1815 | } 1816 | } 1817 | for (let i = 0; i < keys.length; i++) { 1818 | const key = keys[i]; 1819 | if (key === "default" || conditions.has(key)) { 1820 | const conditionalTarget = target[key]; 1821 | const resolveResult = resolvePackageTarget( 1822 | packageJSONUrl, 1823 | conditionalTarget, 1824 | subpath, 1825 | packageSubpath, 1826 | base, 1827 | pattern, 1828 | internal, 1829 | conditions 1830 | ); 1831 | if (resolveResult === void 0) 1832 | continue; 1833 | return resolveResult; 1834 | } 1835 | } 1836 | return void 0; 1837 | } else if (target === null) { 1838 | return null; 1839 | } 1840 | throwInvalidPackageTarget( 1841 | packageSubpath, 1842 | target, 1843 | packageJSONUrl, 1844 | internal, 1845 | base 1846 | ); 1847 | } 1848 | function patternKeyCompare(a, b) { 1849 | const aPatternIndex = StringPrototypeIndexOf(a, "*"); 1850 | const bPatternIndex = StringPrototypeIndexOf(b, "*"); 1851 | const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; 1852 | const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; 1853 | if (baseLenA > baseLenB) 1854 | return -1; 1855 | if (baseLenB > baseLenA) 1856 | return 1; 1857 | if (aPatternIndex === -1) 1858 | return 1; 1859 | if (bPatternIndex === -1) 1860 | return -1; 1861 | if (a.length > b.length) 1862 | return -1; 1863 | if (b.length > a.length) 1864 | return 1; 1865 | return 0; 1866 | } 1867 | function packageImportsResolve({ name, base, conditions, readFileSyncFn }) { 1868 | if (name === "#" || StringPrototypeStartsWith(name, "#/") || StringPrototypeEndsWith(name, "/")) { 1869 | const reason = "is not a valid internal imports specifier name"; 1870 | throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base)); 1871 | } 1872 | let packageJSONUrl; 1873 | const packageConfig = getPackageScopeConfig(base, readFileSyncFn); 1874 | if (packageConfig.exists) { 1875 | packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); 1876 | const imports = packageConfig.imports; 1877 | if (imports) { 1878 | if (ObjectPrototypeHasOwnProperty(imports, name) && !StringPrototypeIncludes(name, "*")) { 1879 | const resolveResult = resolvePackageTarget( 1880 | packageJSONUrl, 1881 | imports[name], 1882 | "", 1883 | name, 1884 | base, 1885 | false, 1886 | true, 1887 | conditions 1888 | ); 1889 | if (resolveResult != null) { 1890 | return resolveResult; 1891 | } 1892 | } else { 1893 | let bestMatch = ""; 1894 | let bestMatchSubpath; 1895 | const keys = ObjectGetOwnPropertyNames(imports); 1896 | for (let i = 0; i < keys.length; i++) { 1897 | const key = keys[i]; 1898 | const patternIndex = StringPrototypeIndexOf(key, "*"); 1899 | if (patternIndex !== -1 && StringPrototypeStartsWith( 1900 | name, 1901 | StringPrototypeSlice(key, 0, patternIndex) 1902 | )) { 1903 | const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); 1904 | if (name.length >= key.length && StringPrototypeEndsWith(name, patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && StringPrototypeLastIndexOf(key, "*") === patternIndex) { 1905 | bestMatch = key; 1906 | bestMatchSubpath = StringPrototypeSlice( 1907 | name, 1908 | patternIndex, 1909 | name.length - patternTrailer.length 1910 | ); 1911 | } 1912 | } 1913 | } 1914 | if (bestMatch) { 1915 | const target = imports[bestMatch]; 1916 | const resolveResult = resolvePackageTarget( 1917 | packageJSONUrl, 1918 | target, 1919 | bestMatchSubpath, 1920 | bestMatch, 1921 | base, 1922 | true, 1923 | true, 1924 | conditions 1925 | ); 1926 | if (resolveResult != null) { 1927 | return resolveResult; 1928 | } 1929 | } 1930 | } 1931 | } 1932 | } 1933 | throwImportNotDefined(name, packageJSONUrl, base); 1934 | } 1935 | 1936 | const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/; 1937 | const isRelativeRegexp = /^\.{0,2}\//; 1938 | function tryReadFile(filePath) { 1939 | try { 1940 | return fs.readFileSync(filePath, `utf8`); 1941 | } catch (err) { 1942 | if (err.code === `ENOENT`) 1943 | return void 0; 1944 | throw err; 1945 | } 1946 | } 1947 | async function resolvePrivateRequest(specifier, issuer, context, nextResolve) { 1948 | const resolved = packageImportsResolve({ 1949 | name: specifier, 1950 | base: pathToFileURL(issuer), 1951 | conditions: new Set(context.conditions), 1952 | readFileSyncFn: tryReadFile 1953 | }); 1954 | if (resolved instanceof URL) { 1955 | return { url: resolved.href, shortCircuit: true }; 1956 | } else { 1957 | if (resolved.startsWith(`#`)) 1958 | throw new Error(`Mapping from one private import to another isn't allowed`); 1959 | return resolve$1(resolved, context, nextResolve); 1960 | } 1961 | } 1962 | async function resolve$1(originalSpecifier, context, nextResolve) { 1963 | const { findPnpApi } = moduleExports; 1964 | if (!findPnpApi || isBuiltin(originalSpecifier)) 1965 | return nextResolve(originalSpecifier, context, nextResolve); 1966 | let specifier = originalSpecifier; 1967 | const url = tryParseURL(specifier, isRelativeRegexp.test(specifier) ? context.parentURL : void 0); 1968 | if (url) { 1969 | if (url.protocol !== `file:`) 1970 | return nextResolve(originalSpecifier, context, nextResolve); 1971 | specifier = fileURLToPath(url); 1972 | } 1973 | const { parentURL, conditions = [] } = context; 1974 | const issuer = parentURL && tryParseURL(parentURL)?.protocol === `file:` ? fileURLToPath(parentURL) : process.cwd(); 1975 | const pnpapi = findPnpApi(issuer) ?? (url ? findPnpApi(specifier) : null); 1976 | if (!pnpapi) 1977 | return nextResolve(originalSpecifier, context, nextResolve); 1978 | if (specifier.startsWith(`#`)) 1979 | return resolvePrivateRequest(specifier, issuer, context, nextResolve); 1980 | const dependencyNameMatch = specifier.match(pathRegExp); 1981 | let allowLegacyResolve = false; 1982 | if (dependencyNameMatch) { 1983 | const [, dependencyName, subPath] = dependencyNameMatch; 1984 | if (subPath === `` && dependencyName !== `pnpapi`) { 1985 | const resolved = pnpapi.resolveToUnqualified(`${dependencyName}/package.json`, issuer); 1986 | if (resolved) { 1987 | const content = await tryReadFile$1(resolved); 1988 | if (content) { 1989 | const pkg = JSON.parse(content); 1990 | allowLegacyResolve = pkg.exports == null; 1991 | } 1992 | } 1993 | } 1994 | } 1995 | let result; 1996 | try { 1997 | result = pnpapi.resolveRequest(specifier, issuer, { 1998 | conditions: new Set(conditions), 1999 | extensions: allowLegacyResolve ? void 0 : [] 2000 | }); 2001 | } catch (err) { 2002 | if (err instanceof Error && `code` in err && err.code === `MODULE_NOT_FOUND`) 2003 | err.code = `ERR_MODULE_NOT_FOUND`; 2004 | throw err; 2005 | } 2006 | if (!result) 2007 | throw new Error(`Resolving '${specifier}' from '${issuer}' failed`); 2008 | const resultURL = pathToFileURL(result); 2009 | if (url) { 2010 | resultURL.search = url.search; 2011 | resultURL.hash = url.hash; 2012 | } 2013 | if (!parentURL) 2014 | setEntrypointPath(fileURLToPath(resultURL)); 2015 | return { 2016 | url: resultURL.href, 2017 | shortCircuit: true 2018 | }; 2019 | } 2020 | 2021 | if (!HAS_LAZY_LOADED_TRANSLATORS) { 2022 | const binding = process.binding(`fs`); 2023 | const originalfstat = binding.fstat; 2024 | const ZIP_MASK = 4278190080; 2025 | const ZIP_MAGIC = 704643072; 2026 | binding.fstat = function(...args) { 2027 | const [fd, useBigint, req] = args; 2028 | if ((fd & ZIP_MASK) === ZIP_MAGIC && useBigint === false && req === void 0) { 2029 | try { 2030 | const stats = fs.fstatSync(fd); 2031 | return new Float64Array([ 2032 | stats.dev, 2033 | stats.mode, 2034 | stats.nlink, 2035 | stats.uid, 2036 | stats.gid, 2037 | stats.rdev, 2038 | stats.blksize, 2039 | stats.ino, 2040 | stats.size, 2041 | stats.blocks 2042 | ]); 2043 | } catch { 2044 | } 2045 | } 2046 | return originalfstat.apply(this, args); 2047 | }; 2048 | } 2049 | 2050 | const resolve = resolve$1; 2051 | const load = load$1; 2052 | 2053 | export { load, resolve }; 2054 | -------------------------------------------------------------------------------- /.yarn/install-state.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacommand2/cdm-ui-backend/13f1d9611c8f0e6bca4dbd528bfefb937a0adbd3/.yarn/install-state.gz -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | #nodeLinker: node-modules 2 | nodeLinker: pnp 3 | 4 | yarnPath: .yarn/releases/yarn-4.0.1.cjs 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # FROM registry.datacommand.co.kr/node:v1.0.0 2 | FROM node:18.14.2-alpine 3 | 4 | WORKDIR /app 5 | 6 | ENV PATH /app/node_modules/.bin:$PATH 7 | 8 | COPY package*.json ./ 9 | RUN npm install 10 | RUN rm -rf package-lock.json 11 | 12 | COPY . . 13 | 14 | EXPOSE 8080 15 | 16 | CMD ["node", "server.js"] 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## CDM 서비스의 Web Backend Repository 2 | 3 | ### 1. Install 4 | 5 | ``` 6 | yarn install 7 | ``` 8 | 9 | ### 2. Usage 10 | 11 | ``` 12 | yarn start 13 | ``` 14 | 15 | ### 3. k8s 16 | 17 | ``` 18 | kubectl apply -f ./deployment_backend.yaml 19 | ``` 20 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | const dotenv = require('dotenv'); 2 | 3 | dotenv.config(); 4 | 5 | module.exports = { 6 | port: process.env.PORT ?? 8080, 7 | API_SERVER_URL: 8 | process.env?.NODE_ENV === 'production' 9 | ? process.env.CDM_CLOUD_API_GATEWAY_SERVICE_HOST + ':3415' 10 | : '192.168.0.246:32715', 11 | }; 12 | -------------------------------------------------------------------------------- /deployment_backend.yaml: -------------------------------------------------------------------------------- 1 | # deployment를 사용해서 백엔드 생성 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: cdm-ui-backend 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: cdm-ui-backend 11 | tier: backend 12 | template: 13 | metadata: 14 | labels: 15 | app: cdm-ui-backend 16 | tier: backend 17 | spec: 18 | containers: 19 | - name: cdm-ui-backend 20 | image: registry.datacommand.co.kr/cdm-ui-backend:develop 21 | imagePullPolicy: Always 22 | ports: 23 | - containerPort: 8443 24 | env: 25 | - name: NODE_ENV 26 | value: production 27 | 28 | restartPolicy: Always 29 | --- 30 | # cdm-ui-backend 서비스 오브젝트 생성 31 | # 서비스는 트래픽을 보내는 파드를 찾기 위해 셀렉터를 사용한다 32 | apiVersion: v1 33 | kind: Service 34 | metadata: 35 | name: cdm-ui-backend 36 | spec: 37 | ports: 38 | - port: 8443 39 | selector: 40 | app: cdm-ui-backend 41 | tier: backend 42 | -------------------------------------------------------------------------------- /event-code/cdm_event_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "cdm_event_error": [ 3 | { 4 | "code" : "abnormal_state", 5 | "solution" : "CDM-DisasterRecovery", 6 | "service" : "Manager", 7 | "contents" : "detail: abnormal state" 8 | }, 9 | { 10 | "code" : "all_plan_snapshot_creation_failed", 11 | "solution" : "CDM-DisasterRecovery", 12 | "service" : "Snapshot", 13 | "contents" : "detail: all plan snapshot creation failed \\n protection group ID: <%= protection_group_id %> \\n protection group snapshot ID: <%= protection_group_snapshot_id %>" 14 | }, 15 | { 16 | "code" : "already_deleted", 17 | "solution" : "CDM-Cloud", 18 | "service" : "Identity", 19 | "contents" : "detail: already deleted group \\n group ID: <%= group_id %>" 20 | }, 21 | { 22 | "code" : "already_login", 23 | "solution" : "CDM-Cloud", 24 | "service" : "Identity", 25 | "contents" : "detail: already login account \\n user ID: <%= user_id %>" 26 | }, 27 | { 28 | "code" : "already_migration_job_registered", 29 | "solution" : "CDM-DisasterRecovery", 30 | "service" : "Manager", 31 | "contents" : "detail: already recovery job registered \\n protection group ID: <%= protection_group_id %>" 32 | }, 33 | { 34 | "code" : "bad_request", 35 | "solution" : "CDM-Center", 36 | "service" : "Manager", 37 | "contents" : "detail: bad request \\n cause: <%= cause %>" 38 | }, 39 | { 40 | "code" : "conflict", 41 | "solution" : "CDM-Center", 42 | "service" : "Manager", 43 | "contents" : "detail: conflict error \\n cause: <%= cause %>" 44 | }, 45 | { 46 | "code" : "conflict_parameter", 47 | "solution" : "CDM-Cloud", 48 | "service" : "Common", 49 | "contents" : "detail: conflict parameter value \\n parameter: <%= param %> \\n value: <%= value %>" 50 | }, 51 | { 52 | "code" : "connection_failed", 53 | "solution" : "CDM-Cloud", 54 | "service" : "Monitor", 55 | "contents" : "detail: could not connect to telemetry service" 56 | }, 57 | { 58 | "code" : "current_password_mismatch", 59 | "solution" : "CDM-Center", 60 | "service" : "Manager", 61 | "contents" : "detail: current password mismatch \\n cluster ID: <%= cluster_id %>" 62 | }, 63 | { 64 | "code" : "decrypt_fail", 65 | "solution" : "CDM-Cloud", 66 | "service" : "License", 67 | "contents" : "detail: decrypt failed \\n cause: <%= cause %>" 68 | }, 69 | { 70 | "code" : "different_instances_list", 71 | "solution" : "CDM-DisasterRecovery", 72 | "service" : "Manager", 73 | "contents" : "detail: different instances list of protection group and plan detail \\n protection group ID: <%= protection_group_id %> \\n plan ID: <%= plan_id %>" 74 | }, 75 | { 76 | "code" : "expired_license", 77 | "solution" : "CDM-DisasterRecovery", 78 | "service" : "Manager", 79 | "contents" : "detail: expired license \\n now: <%= now %> \\n expire date: <%= expire_date %>" 80 | }, 81 | { 82 | "code" : "expired_session", 83 | "solution" : "CDM-Cloud", 84 | "service" : "Identity", 85 | "contents" : "detail: expired session \\n session: <%= session %>" 86 | }, 87 | { 88 | "code" : "failback_recovery_plan_existed", 89 | "solution" : "CDM-DisasterRecovery", 90 | "service" : "Manager", 91 | "contents" : "detail: failback recovery plan existed \\n protection group ID: <%= protection_group_id %> \\n recovery plan ID: <%= recovery_plan_id %>" 92 | }, 93 | { 94 | "code" : "floating_ip_address_duplicated", 95 | "solution" : "CDM-DisasterRecovery", 96 | "service" : "Manager", 97 | "contents" : "detail: protection instance floating IP address is duplicated of recovery cluster floating IP address \\n protection instance UUID: <%= protection_instance_uuid %> \\n floating IP address: <%= floating_ip_address %>" 98 | }, 99 | { 100 | "code" : "format_mismatch_parameter", 101 | "solution" : "CDM-Cloud", 102 | "service" : "Common", 103 | "contents" : "detail: format mismatch parameter value \\n parameter: <%= param %> \\n value: <%= value %> \\n format: <%= format %>" 104 | }, 105 | { 106 | "code" : "import_volume_rollback_failed", 107 | "solution" : "CDM-Center", 108 | "service" : "Manager", 109 | "contents" : "detail: fail to rollback import volume \\n volume pair: <%= volume_pair %> \\n snapshot pair list: <%= snapshot_pair_list %>" 110 | }, 111 | { 112 | "code" : "inactive_cluster", 113 | "solution" : "CDM-DisasterRecovery", 114 | "service" : "Manager", 115 | "contents" : "detail: inactive cluster \\n protection group ID: <%= protection_group_id %> \\n cluster ID: <%= cluster_id %>" 116 | }, 117 | { 118 | "code" : "incorrect_password", 119 | "solution" : "CDM-Cloud", 120 | "service" : "Identity", 121 | "contents" : "detail: password mismatch" 122 | }, 123 | { 124 | "code" : "instance_number_exceeded", 125 | "solution" : "CDM-DisasterRecovery", 126 | "service" : "Manager", 127 | "contents" : "detail: maximum number of instances allowed exceeded \\n added or updated: <%=added_or_updated %> \\n registered: <%= registered %> \\n limit: <%= limit %>" 128 | }, 129 | { 130 | "code" : "instance_status_timeout", 131 | "solution" : "CDM-Center", 132 | "service" : "Manager", 133 | "contents" : "detail: instance status timeout \\n status: <%= status %> \\n instance UUID: <%= instance_uuid %>" 134 | }, 135 | { 136 | "code" : "insufficient_recovery_hypervisor_resource", 137 | "solution" : "CDM-DisasterRecovery", 138 | "service" : "Manager", 139 | "contents" : "detail: insufficient recovery hypervisor resource \\n recovery cluster ID: <%= recovery_cluster_id %> \\n insufficient hypervisor info: <%= insufficient_hypervisor_info %>" 140 | }, 141 | { 142 | "code" : "insufficient_storage_space", 143 | "solution" : "CDM-DisasterRecovery", 144 | "service" : "Manager", 145 | "contents" : "detail: insufficient storage space \\n protection group ID: <%= protection_group_id %> \\n plan ID: <%= plan_id %> \\n required size: <%= required_size %> \\n free size: <%= free_size %>" 146 | }, 147 | { 148 | "code" : "invalid_end_at", 149 | "solution" : "CDM-Cloud", 150 | "service" : "Scheduler", 151 | "contents" : "detail: invalid end time \\n end at: <%= end_at %>" 152 | }, 153 | { 154 | "code" : "invalid_message", 155 | "solution" : "CDM-Cloud", 156 | "service" : "Scheduler", 157 | "contents" : "detail: invalid message" 158 | }, 159 | { 160 | "code" : "invalid_parameter", 161 | "solution" : "CDM-Cloud", 162 | "service" : "Common", 163 | "contents" : "detail: invalid parameter value \\n parameter: <%= param %> \\n value: <%= value %> \\n cause: <%= cause %>" 164 | }, 165 | { 166 | "code" : "invalid_request", 167 | "solution" : "CDM-Cloud", 168 | "service" : "Common", 169 | "contents" : "detail: invalid request \\n client ip: <%= client_ip %>" 170 | }, 171 | { 172 | "code" : "invalid_schedule_id", 173 | "solution" : "CDM-Cloud", 174 | "service" : "Scheduler", 175 | "contents" : "detail: invalid schedule id \\n : <%= %>" 176 | }, 177 | { 178 | "code" : "invalid_session", 179 | "solution" : "CDM-Cloud", 180 | "service" : "Identity", 181 | "contents" : "detail: invalid session \\n session: <%= session %>" 182 | }, 183 | { 184 | "code" : "invalid_start_at", 185 | "solution" : "CDM-Cloud", 186 | "service" : "Scheduler", 187 | "contents" : "detail: invalid start time \\n start at: <%= start_at %>" 188 | }, 189 | { 190 | "code" : "invalid_tenant_config", 191 | "solution" : "CDM-Cloud", 192 | "service" : "Identity", 193 | "contents" : "detail: invalid tenant config \\n key: <%= key %> \\n value: <%= value %>" 194 | }, 195 | { 196 | "code" : "invalid_timezone", 197 | "solution" : "CDM-Cloud", 198 | "service" : "Scheduler", 199 | "contents" : "detail: invalid timezone \\n timezone: <%= timezone %>" 200 | }, 201 | { 202 | "code" : "invalid_topic", 203 | "solution" : "CDM-Cloud", 204 | "service" : "Scheduler", 205 | "contents" : "detail: invalid topic" 206 | }, 207 | { 208 | "code" : "ipc_bad_request", 209 | "solution" : "CDM-DisasterRecovery", 210 | "service" : "Manager", 211 | "contents" : "detail: ipc failed bad request \\n code: <%= code %> \\n message: <%= message %>" 212 | }, 213 | { 214 | "code" : "ipc_failed", 215 | "solution" : "CDM-Cloud", 216 | "service" : "Common", 217 | "contents" : "detail: inter process communication failed \\n error code: <%= code %> \\n message: <%= message %>" 218 | }, 219 | { 220 | "code" : "ipc_no_content", 221 | "solution" : "CDM-DisasterRecovery", 222 | "service" : "Manager", 223 | "contents" : "detail: ipc no content" 224 | }, 225 | { 226 | "code" : "length_overflow_parameter", 227 | "solution" : "CDM-Cloud", 228 | "service" : "Common", 229 | "contents" : "detail: length overflow parameter value \\n parameter: <%= param %> \\n value: <%= value %> \\n maximum length: <%= max_length %>" 230 | }, 231 | { 232 | "code" : "login_restricted", 233 | "solution" : "CDM-Cloud", 234 | "service" : "Identity", 235 | "contents" : "detail: account restrict \\n account: <%= account %> \\n failed count: <%= failed_count %> \\n last failed at: <%= last_failed_at %> \\n login restricted time: <%= until %>" 236 | }, 237 | { 238 | "code" : "mismatch_password", 239 | "solution" : "CDM-Cloud", 240 | "service" : "Identity", 241 | "contents" : "detail: current password mismatch" 242 | }, 243 | { 244 | "code" : "no_content", 245 | "solution" : "CDM-Cloud", 246 | "service" : "Common", 247 | "contents" : "detail: no content" 248 | }, 249 | { 250 | "code" : "no_result", 251 | "solution" : "CDM-Cloud", 252 | "service" : "Monitor", 253 | "contents" : "detail: could not get result \\n query: <%= query %>" 254 | }, 255 | { 256 | "code" : "not_cancelable_state", 257 | "solution" : "CDM-DisasterRecovery", 258 | "service" : "Manager", 259 | "contents" : "detail: not cancelable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 260 | }, 261 | { 262 | "code" : "not_confirm_cancelable_state", 263 | "solution" : "CDM-DisasterRecovery", 264 | "service" : "Manager", 265 | "contents" : "detail: not confirm cancelable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 266 | }, 267 | { 268 | "code" : "not_confirm_retryable_state", 269 | "solution" : "CDM-DisasterRecovery", 270 | "service" : "Manager", 271 | "contents" : "detail: not confirm retryable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 272 | }, 273 | { 274 | "code" : "not_confirmable_state", 275 | "solution" : "CDM-DisasterRecovery", 276 | "service" : "Manager", 277 | "contents" : "detail: not confirmable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 278 | }, 279 | { 280 | "code" : "not_connected", 281 | "solution" : "CDM-Center", 282 | "service" : "Manager", 283 | "contents" : "detail: not connected to cluster \\n type code: <%= type_code %>" 284 | }, 285 | { 286 | "code" : "not_deletable_snapshot_existed", 287 | "solution" : "CDM-DisasterRecovery", 288 | "service" : "Manager", 289 | "contents" : "detail: deletable snapshot not existed \\n protection group ID: <%= protection_group_id %>" 290 | }, 291 | { 292 | "code" : "not_existed_creatable_plans", 293 | "solution" : "CDM-DisasterRecovery", 294 | "service" : "Manager", 295 | "contents" : "detail: not existed creatable plans \\n protection group ID: <%= protection_group_id %>" 296 | }, 297 | { 298 | "code" : "not_existed_replicator_snapshot_file", 299 | "solution" : "CDM-DisasterRecovery", 300 | "service" : "Manager", 301 | "contents" : "detail: not exist replicator snapshot file" 302 | }, 303 | { 304 | "code" : "not_extendable_pausing_time_state", 305 | "solution" : "CDM-DisasterRecovery", 306 | "service" : "Manager", 307 | "contents" : "detail: not extendable pause time state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 308 | }, 309 | { 310 | "code" : "not_extendable_rollback_time_state", 311 | "solution" : "CDM-DisasterRecovery", 312 | "service" : "Manager", 313 | "contents" : "detail: not extendable simulation rollback time state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 314 | }, 315 | { 316 | "code" : "not_found", 317 | "solution" : "CDM-Center", 318 | "service" : "Manager", 319 | "contents" : "detail: not found request resource \\n cause: <%= cause %>" 320 | }, 321 | { 322 | "code" : "not_found_NFS_export_path", 323 | "solution" : "CDM-Center", 324 | "service" : "Manager", 325 | "contents" : "detail: not found NFS export path \\n volume UUID: <%= volume_uuid %>" 326 | }, 327 | { 328 | "code" : "not_found_availability_zone_recovery_plan", 329 | "solution" : "CDM-DisasterRecovery", 330 | "service" : "Manager", 331 | "contents" : "detail: not found availability zone recovery plan \\n recovery plan ID: <%= recovery_plan_id %> \\n availability zone ID: <%= availability_zone_id %>" 332 | }, 333 | { 334 | "code" : "not_found_available_service_host_name", 335 | "solution" : "CDM-Center", 336 | "service" : "Manager", 337 | "contents" : "detail: not found available service host name \\n backend name: <%= backend_name %>" 338 | }, 339 | { 340 | "code" : "not_found_clear_task", 341 | "solution" : "CDM-DisasterRecovery", 342 | "service" : "Common", 343 | "contents" : "detail: not found clear task \\n job ID: <%= job_id %> \\n task ID: <%= task_id %>" 344 | }, 345 | { 346 | "code" : "not_found_cluster", 347 | "solution" : "CDM-Cloud", 348 | "service" : "Common", 349 | "contents" : "detail: not found cluster \\n cluster ID: <%= cluster_id %>" 350 | }, 351 | { 352 | "code" : "not_found_cluster_availability_zone", 353 | "solution" : "CDM-Center", 354 | "service" : "Manager", 355 | "contents" : "detail: not found cluster availability zone \\n cluster availability zone ID: <%= cluster_availability_zone_id %>" 356 | }, 357 | { 358 | "code" : "not_found_cluster_floating_ip", 359 | "solution" : "CDM-Center", 360 | "service" : "Manager", 361 | "contents" : "detail: not found cluster floating ip \\n cluster floating IP ID: <%= cluster_floating_ip_id %>" 362 | }, 363 | { 364 | "code" : "not_found_cluster_hypervisor", 365 | "solution" : "CDM-Center", 366 | "service" : "Manager", 367 | "contents" : "detail: not found cluster hypervisor \\n cluster hypervisor ID: <%= cluster_hypervisor_id %>" 368 | }, 369 | { 370 | "code" : "not_found_cluster_instance", 371 | "solution" : "CDM-Center", 372 | "service" : "Manager", 373 | "contents" : "detail: not found cluster instance \\n cluster instance ID: <%= cluster_instance_id %>" 374 | }, 375 | { 376 | "code" : "not_found_cluster_instance_by_uuid", 377 | "solution" : "CDM-Center", 378 | "service" : "Manager", 379 | "contents" : "detail: not found cluster instance by uuid \\n cluster instance UUID: <%= cluster_instance_uuid %>" 380 | }, 381 | { 382 | "code" : "not_found_cluster_instance_spec", 383 | "solution" : "CDM-Center", 384 | "service" : "Manager", 385 | "contents" : "detail: not found cluster instance spec \\n cluster instance spec ID: <%= cluster_instance_spec_id %>" 386 | }, 387 | { 388 | "code" : "not_found_cluster_instance_spec_by_uuid", 389 | "solution" : "CDM-Center", 390 | "service" : "Manager", 391 | "contents" : "detail: not found cluster instance spec by uuid \\n cluster instance spec UUID: <%= cluster_instance_spec_uuid %>" 392 | }, 393 | { 394 | "code" : "not_found_cluster_keypair", 395 | "solution" : "CDM-Center", 396 | "service" : "Manager", 397 | "contents" : "detail: not found cluster keypair \\n cluster keypair ID: <%= cluster_keypair_id %>" 398 | }, 399 | { 400 | "code" : "not_found_cluster_network", 401 | "solution" : "CDM-Center", 402 | "service" : "Manager", 403 | "contents" : "detail: not found cluster network \\n cluster network ID: <%= cluster_network_id %>" 404 | }, 405 | { 406 | "code" : "not_found_cluster_network_by_uuid", 407 | "solution" : "CDM-Center", 408 | "service" : "Manager", 409 | "contents" : "detail: not found cluster network by uuid \\n cluster network UUID: <%= cluster_network_uuid %>" 410 | }, 411 | { 412 | "code" : "not_found_cluster_router", 413 | "solution" : "CDM-Center", 414 | "service" : "Manager", 415 | "contents" : "detail: not found cluster router \\n cluster router ID : <%= cluster_router_id %>" 416 | }, 417 | { 418 | "code" : "not_found_cluster_router_by_uuid", 419 | "solution" : "CDM-Center", 420 | "service" : "Manager", 421 | "contents" : "detail: not found cluster router by uuid \\n cluster router UUID: <%= cluster_router_uuid %>" 422 | }, 423 | { 424 | "code" : "not_found_cluster_security_group", 425 | "solution" : "CDM-Center", 426 | "service" : "Manager", 427 | "contents" : "detail: not found cluster security group \\n cluster security group ID: <%= cluster_security_group_id %>" 428 | }, 429 | { 430 | "code" : "not_found_cluster_security_group_by_uuid", 431 | "solution" : "CDM-Center", 432 | "service" : "Manager", 433 | "contents" : "detail: not found cluster security group by uuid \\n cluster security group UUID: <%= cluster_security_group_uuid %>" 434 | }, 435 | { 436 | "code" : "not_found_cluster_storage", 437 | "solution" : "CDM-Center", 438 | "service" : "Manager", 439 | "contents" : "detail: not found cluster storage \\n cluster storage ID: <%= cluster_storage_id %>" 440 | }, 441 | { 442 | "code" : "not_found_cluster_subnet", 443 | "solution" : "CDM-Center", 444 | "service" : "Manager", 445 | "contents" : "detail: not found cluster subnet \\n cluster subnet ID: <%= cluster_subnet_id %>" 446 | }, 447 | { 448 | "code" : "not_found_cluster_sync_status", 449 | "solution" : "CDM-Center", 450 | "service" : "Manager", 451 | "contents" : "detail: not found cluster sync status \\n cluster ID: <%= cluster_id %>" 452 | }, 453 | { 454 | "code" : "not_found_cluster_tenant", 455 | "solution" : "CDM-Center", 456 | "service" : "Manager", 457 | "contents" : "detail: not found cluster tenant \\n cluster tenant ID: <%= cluster_tenant_id %>" 458 | }, 459 | { 460 | "code" : "not_found_cluster_tenant_by_uuid", 461 | "solution" : "CDM-Center", 462 | "service" : "Manager", 463 | "contents" : "detail: not found cluster tenant by uuid \\n cluster tenant UUID: <%= cluster_tenant_uuid %>" 464 | }, 465 | { 466 | "code" : "not_found_cluster_volume", 467 | "solution" : "CDM-Center", 468 | "service" : "Manager", 469 | "contents" : "detail: not found cluster volume \\n cluster volume ID: <%= cluster_volume_id %>" 470 | }, 471 | { 472 | "code" : "not_found_cluster_volume_by_uuid", 473 | "solution" : "CDM-Center", 474 | "service" : "Manager", 475 | "contents" : "detail: not found cluster volume by uuid \\n cluster volume UUID: <%= cluster_volume_uuid %>" 476 | }, 477 | { 478 | "code" : "not_found_config", 479 | "solution" : "CDM-Cloud", 480 | "service" : "Monitor", 481 | "contents" : "detail: not found Config \\n key: <%= key %>" 482 | }, 483 | { 484 | "code" : "not_found_consistency_group", 485 | "solution" : "CDM-DisasterRecovery", 486 | "service" : "Manager", 487 | "contents" : "detail: not found consistency group \\n protection group ID: <%= protection_group_id %> \\n cluster storage ID: <%= cluster_storage_id %> \\n cluster tenant ID: <%= cluster_tenant_id %>" 488 | }, 489 | { 490 | "code" : "not_found_endpoint", 491 | "solution" : "CDM-Center", 492 | "service" : "Manager", 493 | "contents" : "detail: not found endpoint \\n service type: <%= service_type %>" 494 | }, 495 | { 496 | "code" : "not_found_event", 497 | "solution" : "CDM-Cloud", 498 | "service" : "Notification", 499 | "contents" : "detail: not found event \\n event ID: <%= id %>" 500 | }, 501 | { 502 | "code" : "not_found_external_network_recovery_plan", 503 | "solution" : "CDM-DisasterRecovery", 504 | "service" : "Manager", 505 | "contents" : "detail: not found external network recovery plan \\n recovery plan ID: <%= recovery_plan_id %> \\n external network ID: <%= external_network_id %>" 506 | }, 507 | { 508 | "code" : "not_found_external_routing_interface", 509 | "solution" : "CDM-DisasterRecovery", 510 | "service" : "Manager", 511 | "contents" : "detail: not found external network routing interface \\n router ID: <%= router_id %>" 512 | }, 513 | { 514 | "code" : "not_found_floating_ip_recovery_plan", 515 | "solution" : "CDM-DisasterRecovery", 516 | "service" : "Manager", 517 | "contents" : "detail: not found floating ip recovery plan \\n recovery plan ID: <%= recovery_plan_id %> \\n floating ip ID: <%= floating_ip_id %>" 518 | }, 519 | { 520 | "code" : "not_found_group", 521 | "solution" : "CDM-Cloud", 522 | "service" : "Common", 523 | "contents" : "detail: not found group \\n group ID: <%= id %>" 524 | }, 525 | { 526 | "code" : "not_found_instance", 527 | "solution" : "CDM-DisasterRecovery", 528 | "service" : "Manager", 529 | "contents" : "detail: not found cluster instance \\n cluster ID: <%= cluster_id %>" 530 | }, 531 | { 532 | "code" : "not_found_instance_hypervisor", 533 | "solution" : "CDM-Center", 534 | "service" : "Manager", 535 | "contents" : "detail: not found hypervisor of instance \\n instance name: <%= instance_name %>" 536 | }, 537 | { 538 | "code" : "not_found_instance_recovery_plan", 539 | "solution" : "CDM-DisasterRecovery", 540 | "service" : "Manager", 541 | "contents" : "detail: not found instance recovery plan \\n recovery plan ID: <%= recovery_plan_id %> \\n instance ID: <%= instance_id %>" 542 | }, 543 | { 544 | "code" : "not_found_instance_recovery_plan_snapshot", 545 | "solution" : "CDM-DisasterRecovery", 546 | "service" : "Manager", 547 | "contents" : "detail: not found instance recovery plan snapshot \\n recovery plan ID: <%= recovery_plan_id %> \\n snapshot ID: <%= snapshot_id %> \\n instance ID: <%= instance_id %>" 548 | }, 549 | { 550 | "code" : "not_found_instance_spec", 551 | "solution" : "CDM-Center", 552 | "service" : "Manager", 553 | "contents" : "detail: not found instance spec \\n instance name: <%= instance_name %> \\n flavor name: <%= flavor_name %>" 554 | }, 555 | { 556 | "code" : "not_found_job", 557 | "solution" : "CDM-DisasterRecovery", 558 | "service" : "Common", 559 | "contents" : "detail: not found job \\n job ID: <%= job_id %>" 560 | }, 561 | { 562 | "code" : "not_found_job_detail", 563 | "solution" : "CDM-DisasterRecovery", 564 | "service" : "Common", 565 | "contents" : "detail: not found job detail \\n job ID: <%= job_id %>" 566 | }, 567 | { 568 | "code" : "not_found_job_instance_status", 569 | "solution" : "CDM-DisasterRecovery", 570 | "service" : "Common", 571 | "contents" : "detail: not found job instance result \\n job ID: <%= job_id %> \\n instance ID: <%= instance_id %>" 572 | }, 573 | { 574 | "code" : "not_found_job_log", 575 | "solution" : "CDM-DisasterRecovery", 576 | "service" : "Common", 577 | "contents" : "detail: not found job log \\n job ID: <%= job_id %> \\n log sequence number: <%= log_seq %>" 578 | }, 579 | { 580 | "code" : "not_found_job_result", 581 | "solution" : "CDM-DisasterRecovery", 582 | "service" : "Common", 583 | "contents" : "detail: not found job result \\n job ID: <%= job_id %>" 584 | }, 585 | { 586 | "code" : "not_found_job_volume_status", 587 | "solution" : "CDM-DisasterRecovery", 588 | "service" : "Common", 589 | "contents" : "detail: not found job volume result \\n job ID: <%= job_id %> \\n volume ID: <%= volume_id %>" 590 | }, 591 | { 592 | "code" : "not_found_key", 593 | "solution" : "CDM-Cloud", 594 | "service" : "Common", 595 | "contents" : "detail: not found key" 596 | }, 597 | { 598 | "code" : "not_found_license", 599 | "solution" : "CDM-Cloud", 600 | "service" : "License", 601 | "contents" : "detail: not found license" 602 | }, 603 | { 604 | "code" : "not_found_managed_volume", 605 | "solution" : "CDM-Center", 606 | "service" : "Manager", 607 | "contents" : "detail: not found managed volume \\n volume pair: <%= volume_pair %>" 608 | }, 609 | { 610 | "code" : "not_found_mirror_environment", 611 | "solution" : "CDM-DisasterRecovery", 612 | "service" : "Common", 613 | "contents" : "detail: not found mirror environment \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %>" 614 | }, 615 | { 616 | "code" : "not_found_mirror_environment_operation", 617 | "solution" : "CDM-DisasterRecovery", 618 | "service" : "Common", 619 | "contents" : "detail: not found mirror environment operation \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %>" 620 | }, 621 | { 622 | "code" : "not_found_mirror_environment_status", 623 | "solution" : "CDM-DisasterRecovery", 624 | "service" : "Common", 625 | "contents" : "detail: not found mirror environment status \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %>" 626 | }, 627 | { 628 | "code" : "not_found_mirror_volume", 629 | "solution" : "CDM-DisasterRecovery", 630 | "service" : "Common", 631 | "contents" : "detail: not found mirror volume \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %> \\n source volume ID: <%= source_volume_id %>" 632 | }, 633 | { 634 | "code" : "not_found_mirror_volume_operation", 635 | "solution" : "CDM-DisasterRecovery", 636 | "service" : "Common", 637 | "contents" : "detail: not found mirror volume operation \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %> \\n source volume ID: <%= source_volume_id %>" 638 | }, 639 | { 640 | "code" : "not_found_mirror_volume_snapshot", 641 | "solution" : "CDM-DisasterRecovery", 642 | "service" : "Snapshot", 643 | "contents" : "detail: not found mirror volume snapshot \\n mirror volume: <%= mirror_volume %> \\n snapshot UUID: <%= snapshot_uuid %>" 644 | }, 645 | { 646 | "code" : "not_found_mirror_volume_status", 647 | "solution" : "CDM-DisasterRecovery", 648 | "service" : "Common", 649 | "contents" : "detail: not found mirror volume status \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %> \\n source volume ID: <%= source_volume_id %>" 650 | }, 651 | { 652 | "code" : "not_found_mirror_volume_target_agent", 653 | "solution" : "CDM-DisasterRecovery", 654 | "service" : "Common", 655 | "contents" : "detail: not found mirror volume target agent \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %> \\n source volume ID: <%= source_volume_id %>" 656 | }, 657 | { 658 | "code" : "not_found_mirror_volume_target_metadata", 659 | "solution" : "CDM-DisasterRecovery", 660 | "service" : "Common", 661 | "contents" : "detail: not found mirror volume target metadata \\n source storage ID: <%= source_storage_id %> \\n target storage ID: <%= target_storage_id %> \\n source volume ID: <%= source_volume_id %>" 662 | }, 663 | { 664 | "code" : "not_found_node", 665 | "solution" : "CDM-Cloud", 666 | "service" : "Monitor", 667 | "contents" : "detail: not found node \\n node ID: <%= id %>" 668 | }, 669 | { 670 | "code" : "not_found_plan_snapshot", 671 | "solution" : "CDM-DisasterRecovery", 672 | "service" : "Snapshot", 673 | "contents" : "detail: not found plan snapshot \\n protection group ID: <%= protection_group_id %> \\n protection group snapshot ID: <%= protection_group_snapshot_id %> \\n plan ID: <%= plan_id %>" 674 | }, 675 | { 676 | "code" : "not_found_protection_group", 677 | "solution" : "CDM-DisasterRecovery", 678 | "service" : "Manager", 679 | "contents" : "detail: not found protection group \\n protection group ID: <%= protection_group_id %> \\n tenant ID: <%= tenant_id %>" 680 | }, 681 | { 682 | "code" : "not_found_protection_group_snapshot", 683 | "solution" : "CDM-DisasterRecovery", 684 | "service" : "Snapshot", 685 | "contents" : "detail: not found protection group snapshot \\n protection group ID: <%= protection_group_id %> \\n protection group snapshot ID: <%= protection_group_snapshot_id %>" 686 | }, 687 | { 688 | "code" : "not_found_recovery_job", 689 | "solution" : "CDM-DisasterRecovery", 690 | "service" : "Manager", 691 | "contents" : "detail: not found recovery job \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 692 | }, 693 | { 694 | "code" : "not_found_recovery_plan", 695 | "solution" : "CDM-DisasterRecovery", 696 | "service" : "Manager", 697 | "contents" : "detail: not found recovery plan \\n protection group ID: <%= protection_group_id %> \\n recovery plan ID: <%= recovery_plan_id %>" 698 | }, 699 | { 700 | "code" : "not_found_recovery_plan_snapshot", 701 | "solution" : "CDM-DisasterRecovery", 702 | "service" : "Manager", 703 | "contents" : "detail: not found recovery plan snapshot \\n protection group ID: <%= protection_group_id %> \\n recovery plan ID: <%= recovery_plan_id %> \\n protection group snapshot ID: <%= protection_group_snapshot_id %>" 704 | }, 705 | { 706 | "code" : "not_found_recovery_plans", 707 | "solution" : "CDM-DisasterRecovery", 708 | "service" : "Manager", 709 | "contents" : "detail: not found recovery plans \\n protection group ID: <%= protection_group_id %>" 710 | }, 711 | { 712 | "code" : "not_found_recovery_point_snapshot", 713 | "solution" : "CDM-DisasterRecovery", 714 | "service" : "Manager", 715 | "contents" : "detail: not found recovery point snapshot \\n protection group snapshot ID: <%= protection_group_snapshot_id %>" 716 | }, 717 | { 718 | "code" : "not_found_recovery_result", 719 | "solution" : "CDM-DisasterRecovery", 720 | "service" : "Manager", 721 | "contents" : "detail: not found recovery result \\n recovery result ID: <%= recovery_result_id %>" 722 | }, 723 | { 724 | "code" : "not_found_recovery_security_group", 725 | "solution" : "CDM-DisasterRecovery", 726 | "service" : "Manager", 727 | "contents" : "detail: not found recovery security group \\n protection group ID: <%= protection_group_id %> \\n cluster security group ID: <%= cluster_security_group_id %>" 728 | }, 729 | { 730 | "code" : "not_found_router_external_network", 731 | "solution" : "CDM-Center", 732 | "service" : "Manager", 733 | "contents" : "detail: not found relational external network \\n external network ID: <%= cluster_network_id %>" 734 | }, 735 | { 736 | "code" : "not_found_schedule", 737 | "solution" : "CDM-Cloud", 738 | "service" : "Scheduler", 739 | "contents" : "detail: not found schedule \\n schedule ID: <%= id %>" 740 | }, 741 | { 742 | "code" : "not_found_service", 743 | "solution" : "CDM-Cloud", 744 | "service" : "Monitor", 745 | "contents" : "detail: not found telemetry service \\n service name: <%= name %>" 746 | }, 747 | { 748 | "code" : "not_found_shared_task", 749 | "solution" : "CDM-DisasterRecovery", 750 | "service" : "Common", 751 | "contents" : "detail: not found shared task \\n shared task key: <%= shared_task_key %>" 752 | }, 753 | { 754 | "code" : "not_found_snapshot_source_name", 755 | "solution" : "CDM-Center", 756 | "service" : "Manager", 757 | "contents" : "detail: not found snapshot source name" 758 | }, 759 | { 760 | "code" : "not_found_source_volume_reference", 761 | "solution" : "CDM-DisasterRecovery", 762 | "service" : "Common", 763 | "contents" : "detail: not found source volume reference \\n source storage ID: <%= source_storage_id %> \\n source volume ID: <%= source_volume_id %>" 764 | }, 765 | { 766 | "code" : "not_found_storage", 767 | "solution" : "CDM-Center", 768 | "service" : "Manager", 769 | "contents" : "detail: not found storage \\n cluster ID: <%= cluster_id %> \\n cluster storage ID: <%= cluster_storage_id %>" 770 | }, 771 | { 772 | "code" : "not_found_storage_metadata", 773 | "solution" : "CDM-Center", 774 | "service" : "Manager", 775 | "contents" : "detail: not found storage metadata \\n cluster ID: <%= cluster_id %> \\n cluster storage ID: <%= cluster_storage_id %>" 776 | }, 777 | { 778 | "code" : "not_found_storage_recovery_plan", 779 | "solution" : "CDM-DisasterRecovery", 780 | "service" : "Manager", 781 | "contents" : "detail: not found storage recovery plan \\n recovery plan ID: <%= recovery_plan_id %> \\n storage ID: <%= storage_id %>" 782 | }, 783 | { 784 | "code" : "not_found_task", 785 | "solution" : "CDM-DisasterRecovery", 786 | "service" : "Common", 787 | "contents" : "detail: not found task \\n job ID: <%= job_id %> \\n task ID: <%= task_id %>" 788 | }, 789 | { 790 | "code" : "not_found_task_result", 791 | "solution" : "CDM-DisasterRecovery", 792 | "service" : "Common", 793 | "contents" : "detail: not found task result \\n job ID: <%= job_id %> \\n task ID: <%= task_id %>" 794 | }, 795 | { 796 | "code" : "not_found_tenant", 797 | "solution" : "CDM-Cloud", 798 | "service" : "Common", 799 | "contents" : "detail: not found tenant \\n tenant ID: <%= id %>" 800 | }, 801 | { 802 | "code" : "not_found_tenant_config", 803 | "solution" : "CDM-Cloud", 804 | "service" : "Identity", 805 | "contents" : "detail: not found tenant config \\n key: <%= key %>" 806 | }, 807 | { 808 | "code" : "not_found_tenant_recovery_plan", 809 | "solution" : "CDM-DisasterRecovery", 810 | "service" : "Manager", 811 | "contents" : "detail: not found tenant recovery plan \\n recovery plan ID: <%= recovery_plan_id %> \\n tenant ID: <%= tenant_id %>" 812 | }, 813 | { 814 | "code" : "not_found_user", 815 | "solution" : "CDM-Cloud", 816 | "service" : "Common", 817 | "contents" : "detail: not found user \\n user ID: <%= id %>" 818 | }, 819 | { 820 | "code" : "not_found_volume", 821 | "solution" : "CDM-Center", 822 | "service" : "Manager", 823 | "contents" : "detail: not found volume \\n cluster ID: <%= cluster_id %> \\n cluster volume ID: <%= cluster_volume_id %>" 824 | }, 825 | { 826 | "code" : "not_found_volume_backend_name", 827 | "solution" : "CDM-Center", 828 | "service" : "Manager", 829 | "contents" : "detail: not found volume backend name \\n volume type name: <%= volume_type_name %>" 830 | }, 831 | { 832 | "code" : "not_found_volume_metadata", 833 | "solution" : "CDM-Center", 834 | "service" : "Manager", 835 | "contents" : "detail: not found volume metadata \\n cluster ID: <%= cluster_id %> \\n cluster storage ID: <%= cluster_storage_id %>" 836 | }, 837 | { 838 | "code" : "not_found_volume_recovery_plan", 839 | "solution" : "CDM-DisasterRecovery", 840 | "service" : "Manager", 841 | "contents" : "detail: not found volume recovery plan \\n recovery plan ID: <%= recovery_plan_id %> \\n volume ID: <%=volume_id %>" 842 | }, 843 | { 844 | "code" : "not_found_volume_recovery_plan_snapshot", 845 | "solution" : "CDM-DisasterRecovery", 846 | "service" : "Manager", 847 | "contents" : "detail: not found volume recovery plan snapshot \\n recovery plan ID: <%= recovery_plan_id %> \\n snapshot ID: <%= snapshot_id %> \\n volume ID: <%= volume_id %>" 848 | }, 849 | { 850 | "code" : "not_found_volume_source_name", 851 | "solution" : "CDM-Center", 852 | "service" : "Manager", 853 | "contents" : "detail: not found volume source name" 854 | }, 855 | { 856 | "code" : "not_found_volume_type", 857 | "solution" : "CDM-Center", 858 | "service" : "Manager", 859 | "contents" : "detail: not found volume type \\n volume name: <%= volume_name %> \\n volume type name: <%= volume_type_name %>" 860 | }, 861 | { 862 | "code" : "not_pausable_state", 863 | "solution" : "CDM-DisasterRecovery", 864 | "service" : "Manager", 865 | "contents" : "detail: not pausable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 866 | }, 867 | { 868 | "code" : "not_resumable_state", 869 | "solution" : "CDM-DisasterRecovery", 870 | "service" : "Manager", 871 | "contents" : "detail: not resumable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 872 | }, 873 | { 874 | "code" : "not_retryable_state", 875 | "solution" : "CDM-DisasterRecovery", 876 | "service" : "Manager", 877 | "contents" : "detail: not retryable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 878 | }, 879 | { 880 | "code" : "not_reusable_old_password", 881 | "solution" : "CDM-Cloud", 882 | "service" : "Identity", 883 | "contents" : "detail: not reusable old password" 884 | }, 885 | { 886 | "code" : "not_rollback_ignorable_state", 887 | "solution" : "CDM-DisasterRecovery", 888 | "service" : "Manager", 889 | "contents" : "detail: not rollback ignorable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 890 | }, 891 | { 892 | "code" : "not_rollback_retryable_state", 893 | "solution" : "CDM-DisasterRecovery", 894 | "service" : "Manager", 895 | "contents" : "detail: not rollback retryable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 896 | }, 897 | { 898 | "code" : "not_rollbackable_state", 899 | "solution" : "CDM-DisasterRecovery", 900 | "service" : "Manager", 901 | "contents" : "detail: not rollbackable state \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 902 | }, 903 | { 904 | "code" : "not_runnable_recovery_job", 905 | "solution" : "CDM-DisasterRecovery", 906 | "service" : "Manager", 907 | "contents" : "detail: not runnable recovery job \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %> \\n cause: <%= cause %>" 908 | }, 909 | { 910 | "code" : "not_shared_task_type", 911 | "solution" : "CDM-DisasterRecovery", 912 | "service" : "Common", 913 | "contents" : "detail: not shared task type \\n task type: <%= task_type %>" 914 | }, 915 | { 916 | "code" : "not_simulation_recovery_job", 917 | "solution" : "CDM-DisasterRecovery", 918 | "service" : "Manager", 919 | "contents" : "detail: mismatch job type code \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %> \\n recovery job type code: <%= recovery_job_type_code %>" 920 | }, 921 | { 922 | "code" : "not_supported_storage_type", 923 | "solution" : "CDM-DisasterRecovery", 924 | "service" : "Snapshot", 925 | "contents" : "detail: not supported storage type \\n storage type: <%= storage_type %>" 926 | }, 927 | { 928 | "code" : "not_volume_mirroring_state", 929 | "solution" : "CDM-DisasterRecovery", 930 | "service" : "Snapshot", 931 | "contents" : "detail: not volume mirroring state \\n mirror volume: <%= mirror_volume %>" 932 | }, 933 | { 934 | "code" : "out_of_range_parameter", 935 | "solution" : "CDM-Cloud", 936 | "service" : "Common", 937 | "contents" : "detail: out of range parameter value \\n parameter: <%= param %> \\n value: <%= value %> \\n minimum: <%= min %> \\n maximum: <%= max %>" 938 | }, 939 | { 940 | "code" : "pattern_mismatch_parameter_value", 941 | "solution" : "CDM-Cloud", 942 | "service" : "Common", 943 | "contents" : "detail: pattern mismatch parameter value \\n parameter: <%= param %> \\n value: <%= value %> \\n pattern: <%= pattern %>" 944 | }, 945 | { 946 | "code" : "protection_group_existed", 947 | "solution" : "CDM-DisasterRecovery", 948 | "service" : "Manager", 949 | "contents" : "detail: protection group is existed \\n cluster ID: <%= cluster_id %>" 950 | }, 951 | { 952 | "code" : "protection_group_snapshot_precondition_failed", 953 | "solution" : "CDM-DisasterRecovery", 954 | "service" : "Manager", 955 | "contents" : "detail: precondition failed to create protection group snapshot \\n protection group ID: <%= protection_group_id %> \\n protection group snapshot ID: <%= protection_group_snapshot_id %> \\n cause: <%= cause %>" 956 | }, 957 | { 958 | "code" : "recovery_job_existed", 959 | "solution" : "CDM-DisasterRecovery", 960 | "service" : "Manager", 961 | "contents" : "detail: recovery job is existed \\n protection group ID: <%= protection_group_id %> \\n recovery plan ID: <%= recovery_plan_id %>" 962 | }, 963 | { 964 | "code" : "recovery_job_running", 965 | "solution" : "CDM-DisasterRecovery", 966 | "service" : "Manager", 967 | "contents" : "detail: recovery job state code is running \\n protection group ID: <%= protection_group_id %> \\n recovery plan ID: <%= recovery_plan_id %> \\n recovery job ID: <%= recovery_job_id %>" 968 | }, 969 | { 970 | "code" : "recovery_plan_existed", 971 | "solution" : "CDM-DisasterRecovery", 972 | "service" : "Manager", 973 | "contents" : "detail: recovery plan is existed \\n cluster ID: <%= cluster_id %> \\n protection_group ID: <%= protection_group_id %>" 974 | }, 975 | { 976 | "code" : "remote_server_error", 977 | "solution" : "CDM-Center", 978 | "service" : "Manager", 979 | "contents" : "detail: cluster server error \\n cause: <%= cause %>" 980 | }, 981 | { 982 | "code" : "required_parameter", 983 | "solution" : "CDM-Cloud", 984 | "service" : "Common", 985 | "contents" : "detail: required parameter \\n parameter: <%= param %>" 986 | }, 987 | { 988 | "code" : "server_busy", 989 | "solution" : "CDM-DisasterRecovery", 990 | "service" : "Manager", 991 | "contents" : "detail: server busy \\n cause: <%= cause %>" 992 | }, 993 | { 994 | "code" : "snapshot_creation_time_has_passed", 995 | "solution" : "CDM-DisasterRecovery", 996 | "service" : "Manager", 997 | "contents" : "detail: snapshot creation time has passed \\n protection group ID: <%= protection_group_id %>" 998 | }, 999 | { 1000 | "code" : "snapshot_creation_timeout", 1001 | "solution" : "CDM-DisasterRecovery", 1002 | "service" : "Manager", 1003 | "contents" : "detail: snapshot creation timeout \\n protection group ID: <%= protection_group_id %>" 1004 | }, 1005 | { 1006 | "code" : "stopping_mirror_environment_existed", 1007 | "solution" : "CDM-DisasterRecovery", 1008 | "service" : "Manager", 1009 | "contents" : "detail: stopping mirror environment is existed \\n source cluster storage ID: <%= source_cluster_storage_id %> \\n target cluster storage ID: <%= target_cluster_storage_id %>" 1010 | }, 1011 | { 1012 | "code" : "stopping_mirror_volume_existed", 1013 | "solution" : "CDM-DisasterRecovery", 1014 | "service" : "Manager", 1015 | "contents" : "detail: stopping mirror volume is existed \\n source cluster storage ID: <%= source_cluster_storage_id %> \\n target cluster storage ID: <%= target_cluster_storage_id %> \\n cluster volume ID: <%= cluster_volume_id %>" 1016 | }, 1017 | { 1018 | "code" : "storage_keyring_registration_required", 1019 | "solution" : "CDM-DisasterRecovery", 1020 | "service" : "Manager", 1021 | "contents" : "detail: storage keyring registration required \\n cluster ID: <%= cluster_id %> \\n storage UUID: <%= storage_uuid %>" 1022 | }, 1023 | { 1024 | "code" : "unable_to_synchronize_because_of_status", 1025 | "solution" : "CDM-Center", 1026 | "service" : "Manager", 1027 | "contents" : "detail: unable to synchronize because of status \\n cluster ID: <%= cluster_id %> \\n status: <%= status %>" 1028 | }, 1029 | { 1030 | "code" : "unassignable_role", 1031 | "solution" : "CDM-Cloud", 1032 | "service" : "Identity", 1033 | "contents" : "detail: unassignable role \\n role: <%= role %>" 1034 | }, 1035 | { 1036 | "code" : "unauthenticated", 1037 | "solution" : "CDM-Center", 1038 | "service" : "Manager", 1039 | "contents" : "detail: unauthenticated user \\n cause: <%= cause %>" 1040 | }, 1041 | { 1042 | "code" : "unauthenticated_request", 1043 | "solution" : "CDM-Cloud", 1044 | "service" : "Common", 1045 | "contents" : "detail: unauthenticated request \\n client ip: <%= client_ip %> \\n session key: <%= session_key %>" 1046 | }, 1047 | { 1048 | "code" : "unauthorized", 1049 | "solution" : "CDM-Center", 1050 | "service" : "Manager", 1051 | "contents" : "detail: unauthorized user \\n cause: <%= cause %>" 1052 | }, 1053 | { 1054 | "code" : "unauthorized_request", 1055 | "solution" : "CDM-Cloud", 1056 | "service" : "Common", 1057 | "contents" : "detail: unauthorized request \\n client ip: <%= client_ip %> \\n user name: <%= user_name %> \\n user account: <%= user_account %>" 1058 | }, 1059 | { 1060 | "code" : "unauthorized_user", 1061 | "solution" : "CDM-Center", 1062 | "service" : "Manager", 1063 | "contents" : "detail: unauthorized user \\n user name: <%= user_name %> \\n required role name: <%= required_role_name %>" 1064 | }, 1065 | { 1066 | "code" : "unavailable_instance_existed", 1067 | "solution" : "CDM-DisasterRecovery", 1068 | "service" : "Manager", 1069 | "contents" : "detail: unavailable instance is existed \\n instances: <%= instances %>" 1070 | }, 1071 | { 1072 | "code" : "unavailable_parameter", 1073 | "solution" : "CDM-Cloud", 1074 | "service" : "Common", 1075 | "contents" : "detail: unavailable parameter value \\n parameter: <%= param %> \\n value: <%= value %> \\n available values: <%= available_values %>" 1076 | }, 1077 | { 1078 | "code" : "unavailable_storage_existed", 1079 | "solution" : "CDM-DisasterRecovery", 1080 | "service" : "Common", 1081 | "contents" : "detail: unavailable storage is existed \\n storages: <%= storages %>" 1082 | }, 1083 | { 1084 | "code" : "unchangeable_parameter", 1085 | "solution" : "CDM-Cloud", 1086 | "service" : "Common", 1087 | "contents" : "detail: unchangeable parameter \\n parameter: <%= param %>" 1088 | }, 1089 | { 1090 | "code" : "unchangeable_recovery_job", 1091 | "solution" : "CDM-DisasterRecovery", 1092 | "service" : "Manager", 1093 | "contents" : "detail: unchangeable recovery job \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %>" 1094 | }, 1095 | { 1096 | "code" : "undeletable_group", 1097 | "solution" : "CDM-Cloud", 1098 | "service" : "Identity", 1099 | "contents" : "detail: undeletable group \\n group ID: <%= group_id %>" 1100 | }, 1101 | { 1102 | "code" : "undeletable_recovery_job", 1103 | "solution" : "CDM-DisasterRecovery", 1104 | "service" : "Manager", 1105 | "contents" : "detail: undeletable recovery job \\n protection group ID: <%= protection_group_id %> \\n recovery job ID: <%= recovery_job_id %> \\n recovery job state code: <%= recovery_job_state_code %>" 1106 | }, 1107 | { 1108 | "code" : "undeletable_recovery_result", 1109 | "solution" : "CDM-DisasterRecovery", 1110 | "service" : "Manager", 1111 | "contents" : "detail: undeletable recovery result \\n recovery result ID: <%= recovery_result_id %> \\n recovery_type_code: <%= recovery_type_code %>" 1112 | }, 1113 | { 1114 | "code" : "undeletable_user", 1115 | "solution" : "CDM-Cloud", 1116 | "service" : "Identity", 1117 | "contents" : "detail: undeletable user \\n user ID: <%= user_id %>" 1118 | }, 1119 | { 1120 | "code" : "unexpected_job_operation", 1121 | "solution" : "CDM-DisasterRecovery", 1122 | "service" : "Manager", 1123 | "contents" : "detail: unexpected job operation \\n recovery job ID: <%= recovery_job_id %> \\n recovery job state: <%= recovery_job_state %> \\n recovery job operation: <%= recovery_job_operation %>" 1124 | }, 1125 | { 1126 | "code" : "unknown", 1127 | "solution" : "CDM-Cloud", 1128 | "service" : "Common", 1129 | "contents" : "detail: unknown error \\n cause: <%= cause %>" 1130 | }, 1131 | { 1132 | "code" : "unknown_cluster_node", 1133 | "solution" : "CDM-DisasterRecovery", 1134 | "service" : "Manager", 1135 | "contents" : "detail: unknown cluster node" 1136 | }, 1137 | { 1138 | "code" : "unknown_instance_state", 1139 | "solution" : "CDM-Center", 1140 | "service" : "Manager", 1141 | "contents" : "detail: unknown instance state \\n instance name: <%= instance_name %> \\n state: <%= state %>" 1142 | }, 1143 | { 1144 | "code" : "unknown_job_operation", 1145 | "solution" : "CDM-DisasterRecovery", 1146 | "service" : "Common", 1147 | "contents" : "detail: invalid job operation \\n operation: <%= operation %>" 1148 | }, 1149 | { 1150 | "code" : "unknown_job_result_code", 1151 | "solution" : "CDM-DisasterRecovery", 1152 | "service" : "Common", 1153 | "contents" : "detail: invalid job result \\n result code: <%= result_code %>" 1154 | }, 1155 | { 1156 | "code" : "unknown_job_state_code", 1157 | "solution" : "CDM-DisasterRecovery", 1158 | "service" : "Common", 1159 | "contents" : "detail: invalid job state \\n state code: <%= state_code %>" 1160 | }, 1161 | { 1162 | "code" : "unknown_mirror_environment_operation", 1163 | "solution" : "CDM-DisasterRecovery", 1164 | "service" : "Common", 1165 | "contents" : "detail: invalid mirror environment operation value \\n operation: <%= operation %>" 1166 | }, 1167 | { 1168 | "code" : "unknown_mirror_environment_state", 1169 | "solution" : "CDM-DisasterRecovery", 1170 | "service" : "Common", 1171 | "contents" : "detail: invalid mirror environment state value \\n state: <%= state %>" 1172 | }, 1173 | { 1174 | "code" : "unknown_mirror_volume_operation", 1175 | "solution" : "CDM-DisasterRecovery", 1176 | "service" : "Common", 1177 | "contents" : "detail: invalid mirror volume operation value \\n operation: <%= operation %>" 1178 | }, 1179 | { 1180 | "code" : "unknown_mirror_volume_state", 1181 | "solution" : "CDM-DisasterRecovery", 1182 | "service" : "Common", 1183 | "contents" : "detail: invalid mirror volume state value \\n state: <%= state %>" 1184 | }, 1185 | { 1186 | "code" : "unknown_session", 1187 | "solution" : "CDM-Cloud", 1188 | "service" : "Identity", 1189 | "contents" : "detail: not found session \\n ID: <%= id %>" 1190 | }, 1191 | { 1192 | "code" : "unknown_user", 1193 | "solution" : "CDM-Cloud", 1194 | "service" : "Notification", 1195 | "contents" : "detail: no role of solution \\n solution: <%= solution %> \\n user ID: <%= user_id %>" 1196 | }, 1197 | { 1198 | "code" : "unsupported_cluster_type", 1199 | "solution" : "CDM-Center", 1200 | "service" : "Manager", 1201 | "contents" : "detail: unsupported cluster type \\n type code: <%= type_code %>" 1202 | }, 1203 | { 1204 | "code" : "unsupported_schedule_type", 1205 | "solution" : "CDM-Cloud", 1206 | "service" : "Scheduler", 1207 | "contents" : "detail: unsupported timezone \\n : <%= timezone %>" 1208 | }, 1209 | { 1210 | "code" : "unsupported_storage_type", 1211 | "solution" : "CDM-Center", 1212 | "service" : "Manager", 1213 | "contents" : "detail: unsupported storage type \\n storage type: <%= storage_type %>" 1214 | }, 1215 | { 1216 | "code" : "unsupported_timezone", 1217 | "solution" : "CDM-Cloud", 1218 | "service" : "Scheduler", 1219 | "contents" : "detail: unsupported schedule type \\n type: <%= type %>" 1220 | }, 1221 | { 1222 | "code" : "unusable_broker", 1223 | "solution" : "CDM-Cloud", 1224 | "service" : "Common", 1225 | "contents" : "detail: unusable broker \\n cause: <%= cause %>" 1226 | }, 1227 | { 1228 | "code" : "unusable_database", 1229 | "solution" : "CDM-Cloud", 1230 | "service" : "Common", 1231 | "contents" : "detail: unusable database \\n cause: <%= cause %> \\n database error: <%= db_error %>" 1232 | }, 1233 | { 1234 | "code" : "unusable_mirror_volume", 1235 | "solution" : "CDM-Center", 1236 | "service" : "Manager", 1237 | "contents" : "detail: unusable mirror volume \\n mirror volume: <%= mirror_volume %> \\n cause: <%= cause %>" 1238 | }, 1239 | { 1240 | "code" : "unusable_store", 1241 | "solution" : "CDM-Cloud", 1242 | "service" : "Common", 1243 | "contents" : "detail: unusable key-value store \\n cause: <%= cause %>" 1244 | }, 1245 | { 1246 | "code" : "unverified_session", 1247 | "solution" : "CDM-Cloud", 1248 | "service" : "Identity", 1249 | "contents" : "detail: unverified session \\n session: <%= session %> \\n cause: <%= cause %>" 1250 | }, 1251 | { 1252 | "code" : "volume_existed", 1253 | "solution" : "CDM-DisasterRecovery", 1254 | "service" : "Common", 1255 | "contents" : "detail: mirror volume exists" 1256 | }, 1257 | { 1258 | "code" : "volume_is_already_grouped", 1259 | "solution" : "CDM-DisasterRecovery", 1260 | "service" : "Manager", 1261 | "contents" : "detail: volume is already grouped \\n cluster ID: <%= cluster_id %> \\n instance ID: <%= instance_id %> \\n volume uuid: <%= volume_uuid %>" 1262 | }, 1263 | { 1264 | "code" : "volume_status_timeout", 1265 | "solution" : "CDM-Center", 1266 | "service" : "Manager", 1267 | "contents" : "detail: volume status timeout \\n status: <%= status %> \\n volume UUID: <%= volume_uuid %>" 1268 | } 1269 | ]} 1270 | -------------------------------------------------------------------------------- /images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacommand2/cdm-ui-backend/13f1d9611c8f0e6bca4dbd528bfefb937a0adbd3/images/favicon.ico -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["./"], 3 | "exec": "node server.js", 4 | "ext": "js json yaml", 5 | "ignore": ["./log/"] 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "axios": "^0.26.1", 14 | "body-parser": "^1.20.0", 15 | "cors": "^2.8.5", 16 | "dotenv": "^16.0.3", 17 | "express": "^4.17.3", 18 | "http": "0.0.1-security", 19 | "nodemon": "^2.0.15", 20 | "path": "^0.12.7", 21 | "shelljs": "^0.8.5", 22 | "socket.io": "^4.4.1", 23 | "ws": "^8.14.2" 24 | }, 25 | "packageManager": "yarn@4.0.1" 26 | } 27 | -------------------------------------------------------------------------------- /private.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDoTCCAokCFB5+Klb/a4ukl1R3dWTiUq/ooW2kMA0GCSqGSIb3DQEBCwUAMIGM 3 | MQswCQYDVQQGEwJLUjEOMAwGA1UECAwFU2VvdWwxETAPBgNVBAcMCEd5b2VuZ2dp 4 | MRIwEAYDVQQKDAljb21wYW55U0gxDDAKBgNVBAsMA1JuRDESMBAGA1UEAwwJbG9j 5 | YWxob3N0MSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBjb21wYW55U0guY28ua3IwHhcN 6 | MjMwNTAzMDA1NzMzWhcNMzMwNDMwMDA1NzMzWjCBjDELMAkGA1UEBhMCS1IxDjAM 7 | BgNVBAgMBVNlb3VsMREwDwYDVQQHDAhHeW9lbmdnaTESMBAGA1UECgwJY29tcGFu 8 | eVNIMQwwCgYDVQQLDANSbkQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3 9 | DQEJARYVYWRtaW5AY29tcGFueVNILmNvLmtyMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEA5+/uCx45EUhYFE7iCbvasl+18toJ60Ih3gIgdDoJnOiSJaCf 11 | IsCEbd3ARyDD54p0sf47LwcEmv+/C4s8YkBV/x9u4DPEZ1/Uj/OxKuAaVuEUUBnS 12 | vpsGb64aWxkZxWWY70RDczy4OBeCv3FfJeAE8vEVuQuv7tfsMoXDKUR1xTAoh1fi 13 | 3Nt75uo3Od0sGeP2nLSEOOjxX9TIGeCKJh3UnQT5OSF7Y04zk82NcMSzL0FtV1Vx 14 | U4Do88SPYhRVUUe/NXz+mCaIcWCQrT8Y0EI9WlYHYqMpLK1g6kCaZulHaQF3kLjX 15 | hdafpzpKNhsh82aS1xpFQ4+pl+xLJ6IfStFcQQIDAQABMA0GCSqGSIb3DQEBCwUA 16 | A4IBAQDkwSGT5n1UP/jwkVyqoOxTiNFu2PjZwKYLXYHwT1E++NUSZAjTCQKy5GJr 17 | 1kGfcvoTu8YjA2iIqanXnW3nIpNsV8CeV8OY01m60B/zHkdx6uRjHbNAxA1e8k2F 18 | GtZgx2WF4R8Y0TdhY6JytskytP4uicandWRKpjGyiylDY3Y5Vaiqp8oUIJqjtj/D 19 | FA9uCndTZHLdgTLmGNCNKUjJdG50RA/chQ0UFHHDXHHZLmS4q2UiArJuepZsNcTW 20 | xw1fGp2QnMzN12KEfM2IMh97OoOfzh0tiRdQ/6hEcdCRCZsstiyNMHMUIC+Gt2ZL 21 | 4prBjFHv6oQ1/DHt34snAqOILRsH 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /private.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIC0jCCAboCAQAwgYwxCzAJBgNVBAYTAktSMQ4wDAYDVQQIDAVTZW91bDERMA8G 3 | A1UEBwwIR3lvZW5nZ2kxEjAQBgNVBAoMCWNvbXBhbnlTSDEMMAoGA1UECwwDUm5E 4 | MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAiBgkqhkiG9w0BCQEWFWFkbWluQGNvbXBh 5 | bnlTSC5jby5rcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOfv7gse 6 | ORFIWBRO4gm72rJftfLaCetCId4CIHQ6CZzokiWgnyLAhG3dwEcgw+eKdLH+Oy8H 7 | BJr/vwuLPGJAVf8fbuAzxGdf1I/zsSrgGlbhFFAZ0r6bBm+uGlsZGcVlmO9EQ3M8 8 | uDgXgr9xXyXgBPLxFbkLr+7X7DKFwylEdcUwKIdX4tzbe+bqNzndLBnj9py0hDjo 9 | 8V/UyBngiiYd1J0E+Tkhe2NOM5PNjXDEsy9BbVdVcVOA6PPEj2IUVVFHvzV8/pgm 10 | iHFgkK0/GNBCPVpWB2KjKSytYOpAmmbpR2kBd5C414XWn6c6SjYbIfNmktcaRUOP 11 | qZfsSyeiH0rRXEECAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCcY2Pc7L4fb6l5 12 | 6Bx0F4AI7+HoPY34Uom+9X2OB7qPOANoW56cpB6Jas5lmWvVPIEl7/3kZzvuCMQq 13 | k3KnvlYVIpuKozOM0zo5oxSYwOuhdHGSqUrKbTwDKdVM8SXCSK2jNCm4FpLNM9so 14 | mbJDvRHJvOYEfXLeugw4KNlFECGBjn4NBjKbkYCIqb9tgDQqaZogC2tWh9iOQ3KY 15 | x3JYrN0sTsSgBGxWwwMcc9qTE5bEFd9/fbS8Lpn4fyqrUYtme6LE+5xFeMnPBaTF 16 | WTqyBy1F2/egCsBBXj+u4spzyJOzKcJyXUyzJwhrszzKERkGT2JRm/yJ6nKfLxez 17 | v9+tJkjf 18 | -----END CERTIFICATE REQUEST----- 19 | -------------------------------------------------------------------------------- /private.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDn7+4LHjkRSFgU 3 | TuIJu9qyX7Xy2gnrQiHeAiB0Ogmc6JIloJ8iwIRt3cBHIMPninSx/jsvBwSa/78L 4 | izxiQFX/H27gM8RnX9SP87Eq4BpW4RRQGdK+mwZvrhpbGRnFZZjvRENzPLg4F4K/ 5 | cV8l4ATy8RW5C6/u1+wyhcMpRHXFMCiHV+Lc23vm6jc53SwZ4/actIQ46PFf1MgZ 6 | 4IomHdSdBPk5IXtjTjOTzY1wxLMvQW1XVXFTgOjzxI9iFFVRR781fP6YJohxYJCt 7 | PxjQQj1aVgdioyksrWDqQJpm6UdpAXeQuNeF1p+nOko2GyHzZpLXGkVDj6mX7Esn 8 | oh9K0VxBAgMBAAECggEAAP6znkZUkTV0lbR/4MVrhiL4A1zaKrxyUqiFw6OccY3e 9 | Me4VJ6GeC6NNL5cvb0Eu930x33NsV87qQswRf4wjGqYxhZEJixTZMxoZ0REuQJ0n 10 | xybLd65e6PVMaNyss+MdgnwHAHqXVO3rJnJj4VDBpsPr5huSo83/ZrDGz7d2rmOu 11 | lGgX4eAhTA8cUMjmb1CmbUJPmrSWla4OJcKEbYLgIEVzl1datE8YE77M7n52q1ym 12 | QFiKiQjnPchocWAwiijkTntGn0NjMRFC8k3IY6wpAQDTsYu+maVisZ+qK1aIq+cl 13 | YBosviUAhZorOLhj70dIT2G8Cjh0ro5AzMEHD0OQgQKBgQDxuMkVDJVD/HgrWb0w 14 | l5IoP7qjkZSFPTiXKbmxLW2JMuYlKGsc4lJK1Y7knVg9VjMlYXr40WUcPl+GtiOa 15 | IMhOC7hUBuE62taEntHy08QidBQg3RBLhPjcHvqTvc0vbW7X/hjId2PAoVwiSHjf 16 | M+qbGSpKIdEbAl8ho5FUgjOy2QKBgQD1oy+ZlLeSF4aH0EovanKV6LJNKNtdKbVK 17 | hjuAf2FxAwMpBRUcN5sw/GV59U+HRM+utISgFxa30BUC7glvLAbla7Zbw59lPt3P 18 | ex1VcCd+9Q91qaOFDK1R/U7ELwCHeJx3PYRJrZosOxVjdNYptfuC0Q8mzYRTx7Gy 19 | xhp2vf3DqQKBgQDejqmt1MEWML2gBGcZ92Rd5Jd+hMq/hqe1HnjXdiE1QoT+T2GX 20 | 3ZWxS0HeojSdfOFomIE12O4EfDVN/iN3hJmIqmfUDeWQX+9FekmKD4q1wjTKMWAQ 21 | eGT9nxRNtWLXOSXmfxDoemyA7tC6zAlmURHALgJu8QXrnVpjyYtEyQC6uQKBgQDm 22 | g5Oh7vwub0FipsdXo++QWuUon9Tsor1tCHdCaUfKRGds0UY0SsKqv9GDGADgEmVL 23 | sEBd9AzvxqhRLY1Q9OIr3l8t0nD9FHgXw5ONoEiQTe2KH/5CV9k2/h4y4WD/wOIk 24 | zGgetHngVDoIMZbhYdR7uTEc2vT5oodSG7KuCDHisQKBgQDpaF3A9VGim4pVP/Ip 25 | xKC0OkO4LETZAOV2IiinC2QwRnrflVcUK4WeKKmXjnvuq5rsvCQvvOSA3Bpcg7dp 26 | TiTK9TBoqBZU5iHHAmp7sQ1LNKvyncQcR8zAMRUzicsdXYbX6DGmZgkaAw7rqrkV 27 | vb8dairuuGZAfE4sflncFZJyMw== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const path = require('path'); 4 | const http = require('http'); 5 | const https = require('https'); 6 | const cors = require('cors'); 7 | const bodyParser = require('body-parser'); 8 | const fs = require('fs'); 9 | 10 | const api = require('./utils/api'); 11 | const env = require('./config/index'); 12 | const HTTPS_PORT = 8443; 13 | 14 | const options = { 15 | key: fs.readFileSync('./private.key'), 16 | cert: fs.readFileSync('./private.crt'), 17 | ca: fs.readFileSync('./private.csr'), 18 | }; 19 | const server = http.createServer(app); 20 | const httpsServer = https.createServer(options, app); 21 | 22 | const socketApi = require('./utils/socket'); 23 | 24 | // client에서 post 요청 시 몇몇 standard header 값들만 보이는데 25 | // 아래처럼 추가해주면 원하는 헤더 값을 추가 가능 26 | app.use( 27 | cors({ 28 | exposedHeaders: ['x-tenant-id', 'x-authenticated-session'], 29 | }) 30 | ); 31 | 32 | app.use(bodyParser.urlencoded({ extended: true })); 33 | app.use(bodyParser.json()); 34 | 35 | // build 폴더에 존재하는 static 파일들을 사용 36 | // __dirname : 파일명을 제외한 절대 경로 37 | // path.join('/foo', '/bar') => /foo/bar 38 | 39 | if (process.env?.NODE_ENV === 'development') { 40 | app.use(express.static(path.join(__dirname, '../frontend/build'))); 41 | } 42 | // GET, POST, DELETE, PUT, PATCH 요청이 오면 43 | // getDataFromApiServer 함수를 실행한다. 44 | 45 | app.get('/favicon.ico', (req, res) => { 46 | res.sendStatus(200); 47 | }); 48 | 49 | app.use(express.static(path.join(__dirname, 'public'))); 50 | 51 | app.get('/manual.pdf', function (req, res) { 52 | const file = path.resolve(__dirname, 'public/NerverStop_v1.0_Manual.pdf'); 53 | res.sendFile(file); 54 | }); 55 | 56 | app.get('*', async (req, res) => { 57 | res.send(await api.getDataFromApiServer(req, 'get', '')); 58 | }); 59 | app.post('*', async (req, res) => { 60 | res.send(await api.getDataFromApiServer(req, 'post', req.body)); 61 | }); 62 | app.delete('*', async (req, res) => { 63 | res.send(await api.getDataFromApiServer(req, 'delete', req.body)); 64 | }); 65 | app.put('*', async (req, res) => { 66 | res.send(await api.getDataFromApiServer(req, 'put', req.body)); 67 | }); 68 | app.patch('*', async (req, res) => { 69 | res.send(await api.getDataFromApiServer(req, 'patch', req.body)); 70 | }); 71 | 72 | // 모든 HTTP 요청, 경로에 대해 index.html 을 보여준다. 73 | app.use('*', (req, res, next) => { 74 | if (process.env.NODE_ENV === 'development') { 75 | res.send(express.static(path.join(__dirname, '../frontend/build/', 'index.html'))); 76 | } 77 | }); 78 | 79 | socketApi.io.attach(process.env?.NODE_ENV === 'production' ? httpsServer : server, { 80 | cors: { 81 | origin: '*', 82 | credentials: true, 83 | }, 84 | transports: ['websocket'], 85 | path: '/socket.io', 86 | }); 87 | 88 | server.listen(env.port, () => { 89 | console.log(`node server running ${env.port}`); 90 | }); 91 | 92 | // Create an HTTPS server. 93 | httpsServer.listen(HTTPS_PORT, () => { 94 | console.log(`8443 running`); 95 | }); 96 | -------------------------------------------------------------------------------- /utils/api.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const env = require('../config/index'); 3 | const { parseErrorMessage, langMessageCode } = require('../utils/common'); 4 | 5 | const EventCodeMessages = require('../event-code/cdm_event_code_message.json'); 6 | const EventCode = require('../event-code/cdm_event_code.json'); 7 | 8 | // 중복제거 9 | const _deleteDuplication = (data) => { 10 | console.log(data); 11 | if (!data) return data; 12 | 13 | const uniqueData = data.filter((item, index, arr) => arr.findIndex(({ code }) => code === item.code) === index); 14 | 15 | return uniqueData; 16 | }; 17 | 18 | const _handleApiError = (error) => { 19 | if (!error?.response) { 20 | return { data: 'error occurred', status: 500, headers: 'headers' }; 21 | } 22 | 23 | const [messageCode, errorCode] = error.response.data.message.code.split(':'); 24 | const parsedMessageCode = langMessageCode(messageCode); 25 | const parsedErrorMessage = parseErrorMessage(errorCode, error.response.data.message?.contents); 26 | 27 | const data = { 28 | message: { 29 | originalCode: error.response.data.message.code, 30 | code: parsedMessageCode, 31 | contents: error.response.data.message?.contents ?? '-', 32 | error_message: parsedErrorMessage, 33 | }, 34 | }; 35 | 36 | return { 37 | data, 38 | status: error.response.status, 39 | headers: error.response.headers, 40 | }; 41 | }; 42 | 43 | const _handleAuth = async (req) => { 44 | try { 45 | const { data, status, headers } = await axios(`http://${env.API_SERVER_URL}${req.originalUrl}`, { 46 | method: 'post', 47 | data: req.body, 48 | }); 49 | return { data, status, headers }; 50 | } catch (error) { 51 | return _handleApiError(error); 52 | } 53 | }; 54 | 55 | const _handleNotificationEvents = (data) => { 56 | const messageCode = EventCodeMessages.cdm_event_code_message.find((v) => v.code === data.message.code); 57 | // 화면에 뿌려주는 data 58 | const parseEvents = data.events.map((event) => { 59 | // event.code를 brief로 바꿔서 리턴 60 | const code = EventCodeMessages.cdm_event_code_message.find((v) => v.code === event.code); 61 | 62 | // solution, level, class_1, class_3 data 63 | const values = EventCode.cdm_event_code.find((v) => v.code === event.code); 64 | return { 65 | ...event, 66 | code: code?.detail ?? event.code, 67 | solution: values?.solution ?? '-', 68 | level: values?.level ?? '-', 69 | class_1: values?.class_1 ?? '-', 70 | class_3: values?.class_3 ?? '-', 71 | }; 72 | }); 73 | 74 | return { 75 | ...data, 76 | events: parseEvents, 77 | message: { ...data.message, code: messageCode.brief }, 78 | }; 79 | }; 80 | 81 | const _handleNotificationEventDetail = (data) => { 82 | const messageCode = EventCodeMessages.cdm_event_code_message.find((v) => v.code === data.message.code); 83 | // 화면에 뿌려주는 data 84 | const code = EventCodeMessages.cdm_event_code_message.find((v) => v.code === data.event.code); 85 | // solution, level, class_1, class_3 data 86 | const values = EventCode.cdm_event_code.find((v) => v.code === data.event.code); 87 | // code를 brief로 변환 88 | return { 89 | ...data, 90 | event: { 91 | ...data.event, 92 | code: code?.detail ?? data.event?.code, 93 | solution: values?.solution ?? '-', 94 | level: values?.level ?? '-', 95 | class_1: values?.class_1 ?? '-', 96 | class_3: values?.class_3 ?? '-', 97 | event_error: parseErrorMessage(data.event?.event_error, data.event?.contents), 98 | contents: data.event?.event_error ?? '-', 99 | }, 100 | message: { ...data.message, code: messageCode.brief }, 101 | }; 102 | }; 103 | 104 | const _handleReports = (data) => { 105 | const parsedData = data; 106 | console.log(parsedData); 107 | 108 | const __parseCode = (reasons) => { 109 | return reasons.map((item) => { 110 | const code = EventCodeMessages.cdm_event_code_message.find((v) => v.code === item.code); 111 | 112 | return { 113 | ...item, 114 | code: code?.detail ?? item.code, 115 | }; 116 | }); 117 | }; 118 | 119 | const __parseFailedReason = (reasons, field) => { 120 | return reasons.map((item) => { 121 | if (!item.failed_reason) return item; 122 | 123 | const code = EventCodeMessages.cdm_event_code_message.find((v) => v.code === item.failed_reason.code); 124 | 125 | return { 126 | ...item, 127 | failed_reason: { 128 | ...item.failed_reason, 129 | code: code?.detail ?? item.failed_reason.code, 130 | }, 131 | }; 132 | }); 133 | }; 134 | 135 | // 화면에 뿌려주는 data 136 | parsedData.report?.task_logs && 137 | Object.assign(parsedData, { 138 | report: { 139 | ...parsedData.report, 140 | task_logs: __parseCode(parsedData.report.task_logs), 141 | }, 142 | }); 143 | 144 | // 실패 사유 이벤트 코드 변환 145 | parsedData.report?.failed_reasons && 146 | Object.assign(parsedData, { 147 | report: { 148 | ...parsedData.report, 149 | failed_reasons: __parseCode(parsedData.report.failed_reasons), 150 | }, 151 | }); 152 | 153 | // 인스턴스 실패 사유 이벤트 코드 변환 154 | parsedData.report?.instances && 155 | Object.assign(parsedData, { 156 | report: { 157 | ...parsedData.report, 158 | instances: __parseFailedReason(parsedData.report.instances), 159 | }, 160 | }); 161 | 162 | // 볼륨 실패 사유 이벤트 코드 변환 163 | parsedData.report?.volumes && 164 | Object.assign(parsedData, { 165 | report: { 166 | ...parsedData.report, 167 | volumes: __parseFailedReason(parsedData.report.volumes), 168 | }, 169 | }); 170 | 171 | return parsedData; 172 | }; 173 | 174 | const _handleRecoveryGroupPlan = (data) => { 175 | const __parseCode = (reasons) => { 176 | return reasons.map((item) => { 177 | const code = EventCodeMessages.cdm_event_code_message.find((v) => v.code === item.code); 178 | 179 | return { 180 | ...item, 181 | code: code?.detail ?? item.code, 182 | }; 183 | }); 184 | }; 185 | 186 | const __parse = (value) => __parseCode(value); 187 | 188 | const parsedPlans = data.plans.map((plan) => { 189 | if (Object.keys(plan.abnormal_state_reasons).length <= 0) return plan; 190 | const keys = Object.keys(plan.abnormal_state_reasons); 191 | const plans = { 192 | ...plan, 193 | abnormal_state_reasons: { 194 | ...plan.abnormal_state_reasons, 195 | }, 196 | }; 197 | keys.forEach((key) => { 198 | plans.abnormal_state_reasons[key] = __parse(plans.abnormal_state_reasons[key]); 199 | }); 200 | 201 | return plans; 202 | }); 203 | 204 | return { 205 | ...data, 206 | plans: parsedPlans, 207 | }; 208 | }; 209 | 210 | // 모든 요청에 대해서 처리하는 함수 211 | const getDataFromApiServer = async (req, method, body) => { 212 | // Handle login request 213 | if (req.originalUrl === '/identity/auth' && req.method === 'POST') return _handleAuth(req); 214 | 215 | // Handle other requests 216 | try { 217 | const session = req.headers['x-authenticated-session']; 218 | const tenantId = req.headers['x-tenant-id']; 219 | const { data, status, headers } = await axios(`http://${env.API_SERVER_URL}${req.originalUrl}`, { 220 | method, 221 | headers: { 222 | 'X-Tenant-Id': tenantId, 223 | 'X-Authenticated-Session': session, 224 | }, 225 | data: body, 226 | }); 227 | 228 | // event 데이터는 여기서 변환해서 react로 전송해준다. 229 | if (status === 204) return { data: null, status: 204, headers }; 230 | 231 | if (status === 200 || status === 201) { 232 | let parsedData = data; 233 | 234 | if (req._parsedUrl.pathname === '/notification/events') { 235 | // 이벤트 목록이면 236 | // api call에 대한 message코드 237 | parsedData = _handleNotificationEvents(data); 238 | } else if (req._parsedUrl.pathname.includes('/notification/events/')) { 239 | // 이벤트 상세조회 240 | // api call에 대한 message 코드 241 | parsedData = _handleNotificationEventDetail(data); 242 | } else if (req._parsedUrl.pathname.includes('/reports/') && req.method === 'GET') { 243 | // 복구결과 상세 244 | parsedData = _handleReports(data, parsedData); 245 | } else if (req._parsedUrl.pathname.match(/^\/recovery\/groups\/\d{1,}\/plans$/g) && req.method === 'GET') { 246 | // 복구계획 목록 조회 일 때\ 247 | parsedData = _handleRecoveryGroupPlan(data); 248 | } 249 | 250 | console.log(parsedData); 251 | return { data: parsedData, status, headers }; 252 | } 253 | } catch (error) { 254 | return _handleApiError(error); 255 | } 256 | }; 257 | 258 | module.exports = { getDataFromApiServer }; 259 | -------------------------------------------------------------------------------- /utils/common.js: -------------------------------------------------------------------------------- 1 | const EventCodeMessages = require('../event-code/cdm_event_code_message.json'); 2 | const EventErrors = require('../event-code/cdm_event_error.json'); 3 | 4 | // 에러 메세지를 파싱하는 만드는 함수 5 | const parseErrorMessage = (errorCode, errorParameter) => { 6 | // errorDetail => required_parameter 7 | if (errorCode === undefined) { 8 | return ''; 9 | } 10 | const errorDetail = EventErrors.cdm_event_error.find( 11 | (v) => v.code === errorCode 12 | // (v) => v.code === 'required_parameter' 13 | ); 14 | 15 | // api call message에 포함된 error parameter 16 | if (errorParameter && errorParameter !== 'null' && errorDetail?.contents) { 17 | const errorParams = JSON.parse(errorParameter); 18 | 19 | // errorDeatil.contents는 <%= =%>이 포함된 문자열 20 | let errorContents = errorDetail.contents; 21 | 22 | // errorParams의 key 값으로 순회하면서 해당 key의 value값으로 대체하여 23 | // 새로운 문자열을 만든다. 24 | Object.keys(errorParams).map((key) => { 25 | errorContents = errorContents.replace(`<%= ${key} %>`, errorParams[key]); 26 | }); 27 | 28 | return errorContents; 29 | } else { 30 | // error parameter가 없는 경우 31 | return errorDetail?.contents ?? ''; 32 | } 33 | }; 34 | 35 | // message.code를 파싱하는 함수 36 | const langMessageCode = (messageCode) => { 37 | const parsedMsg = EventCodeMessages.cdm_event_code_message.find((v) => v.code === messageCode); 38 | // const parsedMsg = EventCodeMessages.cdm_event_code_message.find( 39 | // (v) => v.code === 'cdm-dr.manager.add_protection_group.failure-add' 40 | // ); 41 | return parsedMsg?.detail ?? messageCode; 42 | }; 43 | 44 | module.exports = { parseErrorMessage, langMessageCode }; 45 | -------------------------------------------------------------------------------- /utils/socket.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws'); 2 | const io = require('socket.io')(); 3 | 4 | const EventCodeMessages = require('../event-code/cdm_event_code_message.json'); 5 | const EventCode = require('../event-code/cdm_event_code.json'); 6 | const socketApi = { io }; 7 | const env = require('../config/index'); 8 | 9 | const eventNsp = io.of('/events'); 10 | const monitoringNsp = io.of('/monitoring'); 11 | 12 | eventNsp.on('connection', (socket) => { 13 | let wsNewEvents; 14 | socket.on('newEvents', (data) => { 15 | const url = `ws://${env.API_SERVER_URL}/notification/monitor?X-Authenticated-Session=${data.session}&X-Tenant-Id=${data.tenant}&interval=${data.interval}`; 16 | // express - api 간의 소켓 인스턴스 생성 17 | // 새로고침 할 때마다 새로운 웹 소켓 인스턴스 생성 18 | // 19 | wsNewEvents = new WebSocket(url); 20 | // express - api 간 소켓이 열렸을 때 21 | wsNewEvents.onopen = () => { 22 | console.log('newEvent Socket Open@@@'); 23 | }; 24 | 25 | // express - api 간 소켓이 통신중일 때 26 | wsNewEvents.onmessage = (value) => { 27 | const data1 = JSON.parse(value.data.toString()); 28 | 29 | const parsedEvents = data1.events.map((event) => { 30 | // 해당하는 code를 json에서 찾음 31 | const code = EventCodeMessages.cdm_event_code_message.find((v) => v.code === event.code); 32 | 33 | // level data 추가 34 | const values = EventCode.cdm_event_code.find((v) => v.code === event.code); 35 | // 36 | return { 37 | ...event, 38 | code: code?.detail ?? event.code, 39 | level: values?.level ?? '', 40 | isRead: false, 41 | }; 42 | }); 43 | const parsedData = { 44 | events: parsedEvents, 45 | }; 46 | if (data1) { 47 | socket.emit('newEvents', parsedData); 48 | } 49 | }; 50 | 51 | // express - api 간 소켓에서 에러가 발생했을 때 52 | wsNewEvents.onerror = (error) => { 53 | socket.emit('conntect_error', error.message); 54 | console.log(error.message); 55 | }; 56 | 57 | // express - api 간 소켓이 닫혔을 때 58 | wsNewEvents.onclose = () => { 59 | socket.emit('forceDisconnect', () => { 60 | console.log('diconnect'); 61 | // express - api socket도 disconnect 62 | }); 63 | console.log(`server - api gateway socket close ...`); 64 | }; 65 | }); 66 | socket.conn.on('close', (reason) => { 67 | // 새로고침 하면 이 함수가 실행되기는 함. 68 | if (wsNewEvents !== null) { 69 | console.log('websocket close'); 70 | wsNewEvents.close(); 71 | } 72 | console.log('connection close'); 73 | }); 74 | socket.on('end', () => { 75 | console.log('socket disconnect'); 76 | socket.disconnect(); 77 | }); 78 | }); 79 | 80 | monitoringNsp.on('connection', (socket) => { 81 | console.log('client - server socket open @@'); 82 | let wsJobMonitor = null; 83 | socket.conn.on('close', (reason) => { 84 | console.log('success disconnect socket (react - express)'); 85 | if (wsJobMonitor !== null) { 86 | console.log('4. close wsJobMonitor(express - api gateway)'); 87 | wsJobMonitor.close(); 88 | } 89 | }); 90 | socket.on('monitoringEnd', () => { 91 | socket.disconnect(); 92 | }); 93 | 94 | // 재해복구작업 모니터링 95 | socket.on('recoveryJobMonitor', (data) => { 96 | const url = `ws://${env.API_SERVER_URL}/recovery/groups/${data.groupID}/jobs/${data.jobID}/monitors?X-Authenticated-Session=${data.session}&X-Tenant-Id=${data.tenant}&interval=${data.interval}`; 97 | // express - api 간의 소켓 98 | wsJobMonitor = new WebSocket(url); 99 | // express - api 간 소켓이 열렸을 때 100 | wsJobMonitor.onopen = () => { 101 | console.log('@@@@@@@@@@@@@@@@ recoveryJobMonitor Socket Open !!'); 102 | }; 103 | // express - api 간 소켓이 통신중일 때 104 | wsJobMonitor.onmessage = (value) => { 105 | const data = JSON.parse(value.data.toString()); 106 | console.log(data); 107 | let parsedData; 108 | if (data?.status?.failed_reasons) { 109 | let parsedReasons = data?.status?.failed_reasons.map((reason) => { 110 | const code = EventCodeMessages.cdm_event_code_message.find((v) => v.code === reason.code); 111 | 112 | return { 113 | ...reason, 114 | code: code?.detail ?? reason.code, 115 | }; 116 | }); 117 | parsedData = { 118 | ...data, 119 | status: { 120 | ...data.status, 121 | failed_reasons: parsedReasons, 122 | }, 123 | }; 124 | } else { 125 | parsedData = data; 126 | } 127 | 128 | socket.emit('recoveryJobMonitor', parsedData); 129 | }; 130 | 131 | // express - api 간 소켓에서 에러가 발생했을 때 132 | wsJobMonitor.onerror = (error) => { 133 | console.log(error); 134 | socket.emit('recoveryJobMonitor', error.message); 135 | }; 136 | 137 | // express - api 간 소켓이 닫혔을 때 138 | wsJobMonitor.onclose = () => { 139 | console.log('@@@@@@@@@@@@@ recoveryJobMonitor Socket Close ...'); 140 | }; 141 | }); 142 | }); 143 | 144 | module.exports = socketApi; 145 | --------------------------------------------------------------------------------