'init'
This commit is contained in:
303
app/utils/utils.ts
Normal file
303
app/utils/utils.ts
Normal file
@@ -0,0 +1,303 @@
|
||||
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<string>((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<string>((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<string> {
|
||||
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<Blob> {
|
||||
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<string> {
|
||||
const img = new Image();
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
return new Promise<string>((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;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user