UNPKG

sonofs

Version:

sono nodejs distributed file system

137 lines (113 loc) 4.56 kB
const path = require('path'); function uuid() { var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''), uuid = '', rnd = 0, len = 36, r; for (var i = 0; i < len; i++) { if (i == 8 || i == 13 || i == 18 || i == 23) { uuid += '-'; } else if (i == 14) { uuid += '4'; } else { if (rnd <= 0x02) rnd = 0x2000000 + (Math.random() * 0x1000000) | 0; r = rnd & 0xf; rnd >>= 4; uuid += chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } return uuid; } const fileNameEncodeChars = '0ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789._'; const fileNameDecodeMap = { "0": 0, "1": 53, "2": 54, "3": 55, "4": 56, "5": 57, "6": 58, "7": 59, "8": 60, "9": 61, "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "H": 8, "I": 9, "J": 10, "K": 11, "L": 12, "M": 13, "N": 14, "O": 15, "P": 16, "Q": 17, "R": 18, "S": 19, "T": 20, "U": 21, "V": 22, "W": 23, "X": 24, "Y": 25, "Z": 26, "a": 27, "b": 28, "c": 29, "d": 30, "e": 31, "f": 32, "g": 33, "h": 34, "i": 35, "j": 36, "k": 37, "l": 38, "m": 39, "n": 40, "o": 41, "p": 42, "q": 43, "r": 44, "s": 45, "t": 46, "u": 47, "v": 48, "w": 49, "x": 50, "y": 51, "z": 52, ".": 62, "_": 63 }; const i2s = (i) => { let num = i; let result = ''; while (i != null) { if (num < 64) { result = fileNameEncodeChars[num] + result; break; } else { result = fileNameEncodeChars[num % 64] + result; } num = num >> 6; } return result; }; const s2i = (s) => { if (!s) return null; let result = fileNameDecodeMap[s[s.length - 1]]; let end = s.length - 1; let i = 1; while (i <= end) { result += fileNameDecodeMap[s[end - i]] << (6 * i); i++; } return result; }; const pad = (origin, num) => { return ('000000000000000000000000' + origin).slice(-num); }; const parseFileName = fileName => { const groupId = fileNameDecodeMap[fileName[0]]; const serverId = fileNameDecodeMap[fileName[1]]; const bundleId = s2i(fileName.slice(2, 6)); const dir = pad((bundleId >> 16).toString(16), 2); const subDir = pad(((bundleId & 65535) >> 8).toString(16), 2); const file = pad((bundleId & 255).toString(16), 2); const mime = fileNameDecodeMap[fileName.slice(6, 7)]; const fileStart = s2i(fileName.slice(7, 12)); const fileSize = s2i(fileName.slice(12, 17)); return { fileName, bundleId, groupId, serverId, dir, subDir, file: file + '.snf', mime, fileStart, fileSize }; }; const MAX_FILE_SIZE = 1024 * 1024 * 1024 - 1; const formatFile = ({ groupId, serverId, dir, subDir, file, mime, fileStart, fileSize }) => { if (groupId < 0 || groupId >= 64) throw new Error('`groupId`必须在0-63之间!'); if (serverId < 0 || serverId >= 64) throw new Error('`serverId`必须在0-63之间!'); if (typeof dir === 'string') dir = parseInt(dir, 16); if (dir < 0 || dir >= 256) throw new Error('`dir`必须在0-255之间!'); if (typeof subDir === 'string') subDir = parseInt(subDir, 16); if (subDir < 0 || subDir >= 256) throw new Error('`subDir`必须在0-255之间!'); if (typeof file === 'string') file = parseInt(file.replace('.snf', ''), 16); if (file < 0 || file >= 256) throw new Error('`file`必须在0-255之间!'); if (mime < 0 || mime >= 64) throw new Error('`mime`必须在0-63之间!'); if (fileStart < 0 || fileStart >= MAX_FILE_SIZE) throw new Error('`fileStart`必须在0-' + (MAX_FILE_SIZE - 1) + '之间!'); if (fileSize < 0 || fileSize > MAX_FILE_SIZE) throw new Error('`fileSize`必须在0-' + MAX_FILE_SIZE + '之间!'); const fileName = i2s(groupId) + i2s(serverId) + pad(i2s((dir << 16) + (subDir << 8) + file), 4) + fileNameEncodeChars[mime] + pad(i2s(fileStart), 5) + pad(i2s(fileSize), 5); return fileName; }; function getBundlePath(root, bundleId) { const dirId = bundleId >> 16; const subDirId = (bundleId & 65535) >> 8; const fileId = bundleId & 255; const dir = pad(dirId.toString(16), 2); const subDir = pad(subDirId.toString(16), 2); const bundleName = pad(fileId.toString(16), 2) + '.snf'; return path.join(root, dir, subDir, bundleName); } module.exports = { uuid, pad, s2i, i2s, parseFileName, getBundlePath, formatFile };