import { MantineColor } from "@mantine/core"; import { MESSAGE_MAX_TIME_TO_DELEVERED_S } from "../constants"; import { decode, encode } from "blurhash"; export function generateRandomKey(length: number): string { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; const charactersLength = characters.length; for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } export function murmurHash3_32_gc(key: string, seed: number = 0): number { let remainder = key.length & 3; let bytes = key.length - remainder; let h1 = seed; let c1 = 0xcc9e2d51; let c2 = 0x1b873593; let i = 0; while (i < bytes) { let k1 = ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(++i) & 0xff) << 8) | ((key.charCodeAt(++i) & 0xff) << 16) | ((key.charCodeAt(++i) & 0xff) << 24); ++i; k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; k1 = (k1 << 15) | (k1 >>> 17); k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; h1 ^= k1; h1 = (h1 << 13) | (h1 >>> 19); let h1b = (((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16)) & 0xffffffff; h1 = ((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16); } let k1 = 0; switch (remainder) { case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16; case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8; case 1: k1 ^= (key.charCodeAt(i) & 0xff); k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; k1 = (k1 << 15) | (k1 >>> 17); k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; h1 ^= k1; } h1 ^= key.length; h1 ^= h1 >>> 16; h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; h1 ^= h1 >>> 13; h1 = (((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)) & 0xffffffff; h1 ^= h1 >>> 16; return h1 >>> 0; } export function generateRandomKeyFormSeed(length: number, seed: string): string { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; const charactersLength = characters.length; let seedHash = murmurHash3_32_gc(seed, 1028); let state = Math.abs(seedHash); for (let i = 0; i < length; i++) { state = (state * 1664525 + 1013904223) % 4294967296; const randomIndex = state % charactersLength; result += characters.charAt(randomIndex); } return result; } function hashCode(input: string) { let hash = 0; for (let i = 0; i < input.length; i += 1) { const char = input.charCodeAt(i); hash = (hash << 5) - hash + char; hash |= 0; } return hash; } const defaultColors: MantineColor[] = [ 'blue', 'cyan', 'grape', 'green', 'indigo', 'lime', 'orange', 'pink', 'red', 'teal', 'violet', ]; export function getInitialsColor(name: string, colors: MantineColor[] = defaultColors) { const hash = hashCode(name); const index = Math.abs(hash) % colors.length; return colors[index]; } export function isMessageDeliveredByTime(messageTime: number, attachmentsCount: number): boolean { let maxMessageDeliveredTime = MESSAGE_MAX_TIME_TO_DELEVERED_S * 1000;; //((props.time && (Date.now() - props.time * 1000 > ((MESSAGE_MAX_TIME_TO_DELEVERED * 1000) * props.attachmentsCount || 1)) if (attachmentsCount == 0) { let t = Date.now() - messageTime < maxMessageDeliveredTime; return t; } return Date.now() - messageTime < (maxMessageDeliveredTime * attachmentsCount); } export function filePrapareForNetworkTransfer(file : File){ return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { if(!reader.result){ reject(); return; } resolve(reader.result.toString()); } reader.readAsDataURL(file); }) } export function humanFilesize(size: number) { const suffixes = ['B', 'KB', 'MB', 'GB']; if(size >= (1024 * 1024 * 1024)){ return Math.floor(size / (1024 * 1024 * 1024)) + suffixes[3]; } if(size >= (1024 * 1024)){ return Math.floor(size / (1024 * 1024)) + suffixes[2]; } if(size >= 1024){ return Math.floor(size / 1024) + suffixes[1]; } return size + suffixes[0]; } export function imagePrepareForNetworkTransfer(file: File) { /** * Нужно приводить все изображения к одному формату (png) чтобы избежать проблем с отображением * в разных платформах (ios, android, web) */ return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = async () => { if (!reader.result) { reject(); return; } let base64 = reader.result.toString(); if (file.type === 'image/png') { resolve(base64); return; } try { const jpegBlob = file; const pngBlob = await convertJpegBlobToPngBlob(jpegBlob); const pngBase64 = await blobToBase64(pngBlob); resolve(pngBase64); } catch (error) { reject(error); } }; reader.readAsDataURL(file); }); } export function blobToBase64(blob: Blob): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => { if (reader.result && typeof reader.result === "string") { resolve(reader.result); } else { reject("Failed to convert blob to base64"); } }; reader.onerror = reject; reader.readAsDataURL(blob); }); } export function createBlobFromBase64Image(base64Image: string): Blob { // Split the data URL to get the MIME type and the base64 data const parts = base64Image.split(';'); const mimeType = parts[0].split(':')[1]; const base64 = parts[1].split(',')[1]; // Decode the base64 string const byteCharacters = atob(base64); const byteNumbers = new Array(byteCharacters.length); // Convert to a Uint8Array for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); // Create the Blob const blob = new Blob([byteArray], { type: mimeType }); return blob; } export function convertJpegBlobToPngBlob(jpegBlob: Blob): Promise { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); ctx?.drawImage(img, 0, 0); // Convert the canvas content to a PNG Blob canvas.toBlob((pngBlob) => { if (pngBlob) { resolve(pngBlob); } else { reject(new Error('Failed to create PNG blob.')); } }, 'image/png', 1); }; img.onerror = (error) => reject(error); img.src = URL.createObjectURL(jpegBlob); }); } export function dotMessageIfNeeded(message: string, maxLength: number): string { if (message.length <= maxLength) { return message; } return message.substring(0, maxLength).trim() + '...'; } export function dotCenterIfNeeded(message: string, maxLength : number, viewSymbols : number = 3) { if(message.length <= maxLength){ return message; } return message.slice(0, viewSymbols) + "..." + message.slice(-viewSymbols) } export function isImage(blob : string) : boolean { if(!blob){ return false; } return blob.startsWith('data:image/'); } export function blurhashToBase64Image(blurhash: string, width: number, height: number): string { const pixels = decode(blurhash, width, height); const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); const imageData = ctx?.createImageData(width, height); if (imageData) { imageData.data.set(pixels); ctx?.putImageData(imageData, 0, 0); return canvas.toDataURL(); } return ''; } export function base64ImageToBlurhash(base64Image: string): Promise { const img = new Image(); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); return new Promise((resolve, reject) => { img.onload = () => { canvas.width = img.width; canvas.height = img.height; ctx?.drawImage(img, 0, 0); const imageData = ctx?.getImageData(0, 0, canvas.width, canvas.height); if (imageData) { const blurhash = encode( imageData.data, imageData.width, imageData.height, 4, 4 ); resolve(blurhash); } else { reject('Failed to get image data from canvas.'); } }; img.onerror = (error) => reject(error); img.src = base64Image; }); }