Merge branch 'feature/implement-logic-edit-reply-messages' of https://github.com/PhillipLangMartinez/qortal-ui into feature/implement-UI-edit-reply-messages
This commit is contained in:
commit
dc489b35f3
@ -488,7 +488,8 @@
|
||||
"cchange26": "File size exceeds 5 MB",
|
||||
"cchange27": "A registered name is required to send images",
|
||||
"cchange28": "This file is not an image",
|
||||
"cchange29": "Cancel"
|
||||
"cchange29": "Maximum message size is 1000 bytes",
|
||||
"cchange30": "Cancel"
|
||||
},
|
||||
"welcomepage": {
|
||||
"wcchange1": "Welcome to Q-Chat",
|
||||
|
@ -8,6 +8,8 @@ const commonjs = require('@rollup/plugin-commonjs');
|
||||
const alias = require('@rollup/plugin-alias');
|
||||
const { terser } = require('rollup-plugin-terser');
|
||||
const babel = require('@rollup/plugin-babel');
|
||||
const webWorkerLoader = require('rollup-plugin-web-worker-loader');
|
||||
|
||||
|
||||
const aliases = {};
|
||||
|
||||
@ -40,6 +42,7 @@ const generateRollupConfig = (inputFile, outputFile) => {
|
||||
commonjs(),
|
||||
globals(),
|
||||
progress(),
|
||||
webWorkerLoader(),
|
||||
babel.babel({
|
||||
babelHelpers: 'bundled',
|
||||
exclude: 'node_modules/**',
|
||||
|
@ -19,6 +19,7 @@
|
||||
"dependencies": {
|
||||
"@material/mwc-list": "0.27.0",
|
||||
"@material/mwc-select": "0.27.0",
|
||||
"asmcrypto.js": "2.3.2",
|
||||
"compressorjs": "^1.1.1",
|
||||
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js",
|
||||
"localforage": "^1.10.0",
|
||||
@ -60,7 +61,8 @@
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-node-globals": "1.4.0",
|
||||
"rollup-plugin-progress": "1.1.2",
|
||||
"rollup-plugin-terser": "7.0.2"
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"rollup-plugin-web-worker-loader": "^1.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.15.0"
|
||||
|
@ -21,7 +21,10 @@ import '@material/mwc-dialog'
|
||||
import '@material/mwc-icon'
|
||||
import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js';
|
||||
import { publishData } from '../../utils/publish-image.js';
|
||||
import WebWorker from 'web-worker:./computePowWorker.js';
|
||||
import WebWorkerImage from 'web-worker:./computePowWorkerImage.js';
|
||||
|
||||
// hello
|
||||
const messagesCache = localForage.createInstance({
|
||||
name: "messages-cache",
|
||||
});
|
||||
@ -516,7 +519,7 @@ class ChatPage extends LitElement {
|
||||
this.imageFile = null
|
||||
}}
|
||||
>
|
||||
${translate("chatpage.cchange29")}
|
||||
${translate("chatpage.cchange30")}
|
||||
</mwc-button>
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
@ -1429,20 +1432,22 @@ class ChatPage extends LitElement {
|
||||
})
|
||||
})
|
||||
try {
|
||||
|
||||
|
||||
await publishData({
|
||||
registeredName: userName,
|
||||
file : compressedFile,
|
||||
service: 'IMAGE',
|
||||
identifier : identifier,
|
||||
parentEpml,
|
||||
metaData: undefined,
|
||||
uploadType: 'file',
|
||||
selectedAddress: this.selectedAddress
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await publishData({
|
||||
registeredName: userName ,
|
||||
file : compressedFile ,
|
||||
service: 'IMAGE',
|
||||
identifier : identifier,
|
||||
parentEpml,
|
||||
metaData: undefined,
|
||||
uploadType: 'file',
|
||||
selectedAddress: this.selectedAddress,
|
||||
worker: new WebWorkerImage()
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.isLoading = false;
|
||||
this.chatEditor.enable();
|
||||
return
|
||||
}
|
||||
typeMessage = 'edit';
|
||||
let chatReference = outSideMsg.editedMessageObj.reference;
|
||||
@ -1504,31 +1509,37 @@ class ChatPage extends LitElement {
|
||||
this.chatEditor.enable();
|
||||
return;
|
||||
}
|
||||
await publishData({
|
||||
registeredName: userName,
|
||||
file : compressedFile,
|
||||
service: 'IMAGE',
|
||||
identifier : identifier,
|
||||
parentEpml,
|
||||
metaData: undefined,
|
||||
uploadType: 'file',
|
||||
selectedAddress: this.selectedAddress
|
||||
})
|
||||
|
||||
const messageObject = {
|
||||
messageText: outSideMsg.caption,
|
||||
images: [{
|
||||
service: "IMAGE",
|
||||
name: userName,
|
||||
identifier: identifier
|
||||
}],
|
||||
isImageDeleted: false,
|
||||
repliedTo: '',
|
||||
version: 1
|
||||
}
|
||||
const stringifyMessageObject = JSON.stringify(messageObject)
|
||||
this.sendMessage(stringifyMessageObject, typeMessage);
|
||||
|
||||
try {
|
||||
await publishData({
|
||||
registeredName: userName,
|
||||
file : compressedFile,
|
||||
service: 'IMAGE',
|
||||
identifier : identifier,
|
||||
parentEpml,
|
||||
metaData: undefined,
|
||||
uploadType: 'file',
|
||||
selectedAddress: this.selectedAddress,
|
||||
worker: new WebWorkerImage()
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.isLoading = false;
|
||||
this.chatEditor.enable();
|
||||
return
|
||||
}
|
||||
const messageObject = {
|
||||
messageText: outSideMsg.caption,
|
||||
images: [{
|
||||
service: "IMAGE",
|
||||
name: userName,
|
||||
identifier: identifier
|
||||
}],
|
||||
isImageDeleted: false,
|
||||
repliedTo: '',
|
||||
version: 1
|
||||
}
|
||||
const stringifyMessageObject = JSON.stringify(messageObject)
|
||||
this.sendMessage(stringifyMessageObject, typeMessage);
|
||||
} else if(outSideMsg && outSideMsg.type === 'reaction'){
|
||||
typeMessage = 'edit'
|
||||
let chatReference = outSideMsg.editedMessageObj.reference
|
||||
@ -1583,10 +1594,10 @@ class ChatPage extends LitElement {
|
||||
} else if (/^\s*$/.test(trimmedMessage)) {
|
||||
this.isLoading = false;
|
||||
this.chatEditor.enable();
|
||||
} else if (trimmedMessage.length >= 256) {
|
||||
} else if (this.chatMessageSize >= 1000) {
|
||||
this.isLoading = false;
|
||||
this.chatEditor.enable();
|
||||
let err1string = get("chatpage.cchange24");
|
||||
let err1string = get("chatpage.cchange29");
|
||||
parentEpml.request('showSnackBar', `${err1string}`);
|
||||
} else if (this.repliedToMessageObj) {
|
||||
let chatReference = this.repliedToMessageObj.reference
|
||||
@ -1688,23 +1699,33 @@ class ChatPage extends LitElement {
|
||||
};
|
||||
|
||||
const _computePow = async (chatBytes) => {
|
||||
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
|
||||
const chatBytesArray = new Uint8Array(_chatBytesArray);
|
||||
const chatBytesHash = new window.parent.Sha256().process(chatBytesArray).finish().result;
|
||||
const hashPtr = window.parent.sbrk(32, window.parent.heap);
|
||||
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
|
||||
hashAry.set(chatBytesHash);
|
||||
|
||||
const difficulty = this.balance === 0 ? 12 : 8;
|
||||
const workBufferLength = 8 * 1024 * 1024;
|
||||
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
|
||||
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty);
|
||||
const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
|
||||
const worker = new WebWorker();
|
||||
let nonce = null
|
||||
let chatBytesArray = null
|
||||
await new Promise((res, rej) => {
|
||||
console.log({chatBytes})
|
||||
worker.postMessage({chatBytes, path, difficulty});
|
||||
|
||||
worker.onmessage = e => {
|
||||
|
||||
|
||||
worker.terminate()
|
||||
chatBytesArray = e.data.chatBytesArray
|
||||
nonce = e.data.nonce
|
||||
res()
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
let _response = await parentEpml.request('sign_chat', {
|
||||
nonce: this.selectedAddress.nonce,
|
||||
chatBytesArray: chatBytesArray,
|
||||
chatNonce: nonce
|
||||
});
|
||||
|
||||
|
||||
getSendChatResponse(_response);
|
||||
};
|
||||
|
||||
@ -1951,30 +1972,34 @@ class ChatPage extends LitElement {
|
||||
if (e.type === 'paste') {
|
||||
e.preventDefault();
|
||||
const item_list = await navigator.clipboard.read();
|
||||
console.log({item_list})
|
||||
let image_type; // we will feed this later
|
||||
const item = item_list.find( item => // choose the one item holding our image
|
||||
item.types.some( type => { // does this item have our type
|
||||
item.types.some( type => {
|
||||
if (type.startsWith( 'image/')) {
|
||||
image_type = type; // store which kind of image type it is
|
||||
image_type = type;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
);
|
||||
const blob = item && await item.getType( image_type );
|
||||
if(item){
|
||||
const blob = item && await item.getType( image_type );
|
||||
var file = new File([blob], "name", {
|
||||
type: image_type
|
||||
});
|
||||
|
||||
editorConfig.insertImage(file)
|
||||
navigator.clipboard.readText().then(clipboardText => {
|
||||
let escapedText = editorConfig.escape(clipboardText);
|
||||
editor.insertText(escapedText);
|
||||
}).catch(err => {
|
||||
// Fallback if everything fails...
|
||||
let textData = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||
editor.insertText(textData);
|
||||
})
|
||||
} else {
|
||||
navigator.clipboard.readText().then(clipboardText => {
|
||||
let escapedText = editorConfig.escape(clipboardText);
|
||||
editor.insertText(escapedText);
|
||||
}).catch(err => {
|
||||
// Fallback if everything fails...
|
||||
let textData = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||
editor.insertText(textData);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,83 @@
|
||||
import { Sha256 } from 'asmcrypto.js'
|
||||
|
||||
|
||||
function sbrk(size, heap){
|
||||
let brk = 512 * 1024 // stack top
|
||||
let old = brk
|
||||
brk += size
|
||||
|
||||
if (brk > heap.length)
|
||||
throw new Error('heap exhausted')
|
||||
|
||||
return old
|
||||
}
|
||||
|
||||
|
||||
|
||||
self.addEventListener('message', async e => {
|
||||
console.log({data: e.data})
|
||||
const response = await computePow(e.data.chatBytes, e.data.path, e.data.difficulty)
|
||||
postMessage(response)
|
||||
|
||||
})
|
||||
|
||||
|
||||
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
||||
const heap = new Uint8Array(memory.buffer)
|
||||
|
||||
|
||||
|
||||
const computePow = async (chatBytes, path, difficulty) => {
|
||||
|
||||
let response = null
|
||||
|
||||
await new Promise((resolve, reject)=> {
|
||||
|
||||
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
|
||||
const chatBytesArray = new Uint8Array(_chatBytesArray);
|
||||
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result;
|
||||
const hashPtr = sbrk(32, heap);
|
||||
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32);
|
||||
hashAry.set(chatBytesHash);
|
||||
|
||||
|
||||
const workBufferLength = 8 * 1024 * 1024;
|
||||
const workBufferPtr = sbrk(workBufferLength, heap);
|
||||
|
||||
|
||||
|
||||
const importObject = {
|
||||
env: {
|
||||
memory: memory
|
||||
},
|
||||
};
|
||||
|
||||
function loadWebAssembly(filename, imports) {
|
||||
// Fetch the file and compile it
|
||||
return fetch(filename)
|
||||
.then(response => response.arrayBuffer())
|
||||
.then(buffer => WebAssembly.compile(buffer))
|
||||
.then(module => {
|
||||
|
||||
// Create the instance.
|
||||
return new WebAssembly.Instance(module, importObject);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
loadWebAssembly(path)
|
||||
.then(wasmModule => {
|
||||
response = {
|
||||
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
||||
chatBytesArray
|
||||
}
|
||||
|
||||
resolve()
|
||||
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
|
||||
return response
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
import { Sha256 } from 'asmcrypto.js'
|
||||
|
||||
|
||||
|
||||
function sbrk(size, heap){
|
||||
let brk = 512 * 1024 // stack top
|
||||
let old = brk
|
||||
brk += size
|
||||
|
||||
if (brk > heap.length)
|
||||
throw new Error('heap exhausted')
|
||||
|
||||
return old
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
self.addEventListener('message', async e => {
|
||||
console.log({data: e.data})
|
||||
const response = await computePow(e.data.convertedBytes, e.data.path)
|
||||
postMessage(response)
|
||||
|
||||
})
|
||||
|
||||
|
||||
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
||||
const heap = new Uint8Array(memory.buffer)
|
||||
|
||||
|
||||
|
||||
const computePow = async (convertedBytes, path) => {
|
||||
|
||||
|
||||
let response = null
|
||||
|
||||
await new Promise((resolve, reject)=> {
|
||||
|
||||
const _convertedBytesArray = Object.keys(convertedBytes).map(
|
||||
function (key) {
|
||||
return convertedBytes[key]
|
||||
}
|
||||
)
|
||||
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
|
||||
const convertedBytesHash = new Sha256()
|
||||
.process(convertedBytesArray)
|
||||
.finish().result
|
||||
const hashPtr = sbrk(32, heap)
|
||||
const hashAry = new Uint8Array(
|
||||
memory.buffer,
|
||||
hashPtr,
|
||||
32
|
||||
)
|
||||
|
||||
hashAry.set(convertedBytesHash)
|
||||
const difficulty = 14
|
||||
const workBufferLength = 8 * 1024 * 1024
|
||||
const workBufferPtr = sbrk(
|
||||
workBufferLength,
|
||||
heap
|
||||
)
|
||||
|
||||
const importObject = {
|
||||
env: {
|
||||
memory: memory
|
||||
},
|
||||
};
|
||||
|
||||
function loadWebAssembly(filename, imports) {
|
||||
return fetch(filename)
|
||||
.then(response => response.arrayBuffer())
|
||||
.then(buffer => WebAssembly.compile(buffer))
|
||||
.then(module => {
|
||||
return new WebAssembly.Instance(module, importObject);
|
||||
});
|
||||
}
|
||||
|
||||
console.log({path})
|
||||
loadWebAssembly(path)
|
||||
.then(wasmModule => {
|
||||
response = {
|
||||
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
||||
|
||||
}
|
||||
resolve()
|
||||
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
|
||||
return response
|
||||
}
|
@ -14,9 +14,9 @@ export const publishData = async ({
|
||||
service,
|
||||
identifier,
|
||||
parentEpml,
|
||||
metaData,
|
||||
uploadType,
|
||||
selectedAddress,
|
||||
worker
|
||||
}) => {
|
||||
const validateName = async (receiverName) => {
|
||||
let nameRes = await parentEpml.request("apiCall", {
|
||||
@ -47,35 +47,23 @@ export const publishData = async ({
|
||||
|
||||
const convertedBytes =
|
||||
window.parent.Base58.decode(convertedBytesBase58)
|
||||
const _convertedBytesArray = Object.keys(convertedBytes).map(
|
||||
function (key) {
|
||||
return convertedBytes[key]
|
||||
}
|
||||
)
|
||||
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
|
||||
const convertedBytesHash = new window.parent.Sha256()
|
||||
.process(convertedBytesArray)
|
||||
.finish().result
|
||||
const hashPtr = window.parent.sbrk(32, window.parent.heap)
|
||||
const hashAry = new Uint8Array(
|
||||
window.parent.memory.buffer,
|
||||
hashPtr,
|
||||
32
|
||||
)
|
||||
|
||||
hashAry.set(convertedBytesHash)
|
||||
const difficulty = 14
|
||||
const workBufferLength = 8 * 1024 * 1024
|
||||
const workBufferPtr = window.parent.sbrk(
|
||||
workBufferLength,
|
||||
window.parent.heap
|
||||
)
|
||||
let nonce = window.parent.computePow(
|
||||
hashPtr,
|
||||
workBufferPtr,
|
||||
workBufferLength,
|
||||
difficulty
|
||||
)
|
||||
let nonce = null
|
||||
const computPath =window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
|
||||
await new Promise((res, rej) => {
|
||||
|
||||
worker.postMessage({convertedBytes, path: computPath});
|
||||
|
||||
worker.onmessage = e => {
|
||||
|
||||
worker.terminate()
|
||||
|
||||
nonce = e.data.nonce
|
||||
res()
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
let response = await parentEpml.request("sign_arbitrary", {
|
||||
nonce: selectedAddress.nonce,
|
||||
arbitraryBytesBase58: transactionBytesBase58,
|
||||
@ -131,18 +119,7 @@ export const publishData = async ({
|
||||
postBody = Buffer.from(fileBuffer).toString("base64")
|
||||
}
|
||||
|
||||
// Optional metadata
|
||||
|
||||
// let title = encodeURIComponent(metaData.title || "")
|
||||
// let description = encodeURIComponent(metaData.description || "")
|
||||
// let category = encodeURIComponent(metaData.category || "")
|
||||
// let tag1 = encodeURIComponent(metaData.tag1 || "")
|
||||
// let tag2 = encodeURIComponent(metaData.tag2 || "")
|
||||
// let tag3 = encodeURIComponent(metaData.tag3 || "")
|
||||
// let tag4 = encodeURIComponent(metaData.tag4 || "")
|
||||
// let tag5 = encodeURIComponent(metaData.tag5 || "")
|
||||
|
||||
// let metadataQueryString = `title=${title}&description=${description}&category=${category}&tags=${tag1}&tags=${tag2}&tags=${tag3}&tags=${tag4}&tags=${tag5}`
|
||||
|
||||
|
||||
let uploadDataUrl = `/arbitrary/${service}/${registeredName}${urlSuffix}?apiKey=${getApiKey()}`
|
||||
if (identifier != null && identifier.trim().length > 0) {
|
||||
@ -157,5 +134,10 @@ export const publishData = async ({
|
||||
return uploadDataRes
|
||||
}
|
||||
}
|
||||
await validate()
|
||||
try {
|
||||
await validate()
|
||||
} catch (error) {
|
||||
throw new Error(error.message)
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user