Browse Source

Merge branch 'feature/implement-logic-edit-reply-messages' of https://github.com/PhillipLangMartinez/qortal-ui into feature/implement-UI-edit-reply-messages

q-apps
Justin Ferrari 2 years ago
parent
commit
dc489b35f3
  1. 3
      qortal-ui-core/language/us.json
  2. 3
      qortal-ui-plugins/build-config.js
  3. 4
      qortal-ui-plugins/package.json
  4. 71
      qortal-ui-plugins/plugins/core/components/ChatPage.js
  5. 83
      qortal-ui-plugins/plugins/core/components/computePowWorker.js
  6. 93
      qortal-ui-plugins/plugins/core/components/computePowWorkerImage.js
  7. 60
      qortal-ui-plugins/plugins/utils/publish-image.js

3
qortal-ui-core/language/us.json

@ -488,7 +488,8 @@
"cchange26": "File size exceeds 5 MB", "cchange26": "File size exceeds 5 MB",
"cchange27": "A registered name is required to send images", "cchange27": "A registered name is required to send images",
"cchange28": "This file is not an image", "cchange28": "This file is not an image",
"cchange29": "Cancel" "cchange29": "Maximum message size is 1000 bytes",
"cchange30": "Cancel"
}, },
"welcomepage": { "welcomepage": {
"wcchange1": "Welcome to Q-Chat", "wcchange1": "Welcome to Q-Chat",

3
qortal-ui-plugins/build-config.js

@ -8,6 +8,8 @@ const commonjs = require('@rollup/plugin-commonjs');
const alias = require('@rollup/plugin-alias'); const alias = require('@rollup/plugin-alias');
const { terser } = require('rollup-plugin-terser'); const { terser } = require('rollup-plugin-terser');
const babel = require('@rollup/plugin-babel'); const babel = require('@rollup/plugin-babel');
const webWorkerLoader = require('rollup-plugin-web-worker-loader');
const aliases = {}; const aliases = {};
@ -40,6 +42,7 @@ const generateRollupConfig = (inputFile, outputFile) => {
commonjs(), commonjs(),
globals(), globals(),
progress(), progress(),
webWorkerLoader(),
babel.babel({ babel.babel({
babelHelpers: 'bundled', babelHelpers: 'bundled',
exclude: 'node_modules/**', exclude: 'node_modules/**',

4
qortal-ui-plugins/package.json

@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"@material/mwc-list": "0.27.0", "@material/mwc-list": "0.27.0",
"@material/mwc-select": "0.27.0", "@material/mwc-select": "0.27.0",
"asmcrypto.js": "2.3.2",
"compressorjs": "^1.1.1", "compressorjs": "^1.1.1",
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js", "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js",
"localforage": "^1.10.0", "localforage": "^1.10.0",
@ -60,7 +61,8 @@
"rollup": "2.79.1", "rollup": "2.79.1",
"rollup-plugin-node-globals": "1.4.0", "rollup-plugin-node-globals": "1.4.0",
"rollup-plugin-progress": "1.1.2", "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": { "engines": {
"node": ">=16.15.0" "node": ">=16.15.0"

71
qortal-ui-plugins/plugins/core/components/ChatPage.js

@ -21,7 +21,10 @@ import '@material/mwc-dialog'
import '@material/mwc-icon' import '@material/mwc-icon'
import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js'; import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js';
import { publishData } from '../../utils/publish-image.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({ const messagesCache = localForage.createInstance({
name: "messages-cache", name: "messages-cache",
}); });
@ -516,7 +519,7 @@ class ChatPage extends LitElement {
this.imageFile = null this.imageFile = null
}} }}
> >
${translate("chatpage.cchange29")} ${translate("chatpage.cchange30")}
</mwc-button> </mwc-button>
<mwc-button <mwc-button
slot="primaryAction" slot="primaryAction"
@ -1429,8 +1432,6 @@ class ChatPage extends LitElement {
}) })
}) })
try { try {
await publishData({ await publishData({
registeredName: userName , registeredName: userName ,
file : compressedFile , file : compressedFile ,
@ -1439,10 +1440,14 @@ class ChatPage extends LitElement {
parentEpml, parentEpml,
metaData: undefined, metaData: undefined,
uploadType: 'file', uploadType: 'file',
selectedAddress: this.selectedAddress selectedAddress: this.selectedAddress,
worker: new WebWorkerImage()
}) })
} catch (error) { } catch (error) {
console.error(error); console.error(error)
this.isLoading = false;
this.chatEditor.enable();
return
} }
typeMessage = 'edit'; typeMessage = 'edit';
let chatReference = outSideMsg.editedMessageObj.reference; let chatReference = outSideMsg.editedMessageObj.reference;
@ -1504,6 +1509,7 @@ class ChatPage extends LitElement {
this.chatEditor.enable(); this.chatEditor.enable();
return; return;
} }
try {
await publishData({ await publishData({
registeredName: userName, registeredName: userName,
file : compressedFile, file : compressedFile,
@ -1512,9 +1518,15 @@ class ChatPage extends LitElement {
parentEpml, parentEpml,
metaData: undefined, metaData: undefined,
uploadType: 'file', uploadType: 'file',
selectedAddress: this.selectedAddress selectedAddress: this.selectedAddress,
worker: new WebWorkerImage()
}) })
} catch (error) {
console.error(error)
this.isLoading = false;
this.chatEditor.enable();
return
}
const messageObject = { const messageObject = {
messageText: outSideMsg.caption, messageText: outSideMsg.caption,
images: [{ images: [{
@ -1528,7 +1540,6 @@ class ChatPage extends LitElement {
} }
const stringifyMessageObject = JSON.stringify(messageObject) const stringifyMessageObject = JSON.stringify(messageObject)
this.sendMessage(stringifyMessageObject, typeMessage); this.sendMessage(stringifyMessageObject, typeMessage);
} else if(outSideMsg && outSideMsg.type === 'reaction'){ } else if(outSideMsg && outSideMsg.type === 'reaction'){
typeMessage = 'edit' typeMessage = 'edit'
let chatReference = outSideMsg.editedMessageObj.reference let chatReference = outSideMsg.editedMessageObj.reference
@ -1583,10 +1594,10 @@ class ChatPage extends LitElement {
} else if (/^\s*$/.test(trimmedMessage)) { } else if (/^\s*$/.test(trimmedMessage)) {
this.isLoading = false; this.isLoading = false;
this.chatEditor.enable(); this.chatEditor.enable();
} else if (trimmedMessage.length >= 256) { } else if (this.chatMessageSize >= 1000) {
this.isLoading = false; this.isLoading = false;
this.chatEditor.enable(); this.chatEditor.enable();
let err1string = get("chatpage.cchange24"); let err1string = get("chatpage.cchange29");
parentEpml.request('showSnackBar', `${err1string}`); parentEpml.request('showSnackBar', `${err1string}`);
} else if (this.repliedToMessageObj) { } else if (this.repliedToMessageObj) {
let chatReference = this.repliedToMessageObj.reference let chatReference = this.repliedToMessageObj.reference
@ -1688,23 +1699,33 @@ class ChatPage extends LitElement {
}; };
const _computePow = async (chatBytes) => { 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 difficulty = this.balance === 0 ? 12 : 8;
const workBufferLength = 8 * 1024 * 1024; const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap); const worker = new WebWorker();
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty); 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', { let _response = await parentEpml.request('sign_chat', {
nonce: this.selectedAddress.nonce, nonce: this.selectedAddress.nonce,
chatBytesArray: chatBytesArray, chatBytesArray: chatBytesArray,
chatNonce: nonce chatNonce: nonce
}); });
getSendChatResponse(_response); getSendChatResponse(_response);
}; };
@ -1951,22 +1972,23 @@ class ChatPage extends LitElement {
if (e.type === 'paste') { if (e.type === 'paste') {
e.preventDefault(); e.preventDefault();
const item_list = await navigator.clipboard.read(); const item_list = await navigator.clipboard.read();
console.log({item_list})
let image_type; // we will feed this later let image_type; // we will feed this later
const item = item_list.find( item => // choose the one item holding our image 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/')) { if (type.startsWith( 'image/')) {
image_type = type; // store which kind of image type it is image_type = type;
return true; return true;
} }
}) })
); );
if(item){
const blob = item && await item.getType( image_type ); const blob = item && await item.getType( image_type );
var file = new File([blob], "name", { var file = new File([blob], "name", {
type: image_type type: image_type
}); });
editorConfig.insertImage(file) editorConfig.insertImage(file)
} else {
navigator.clipboard.readText().then(clipboardText => { navigator.clipboard.readText().then(clipboardText => {
let escapedText = editorConfig.escape(clipboardText); let escapedText = editorConfig.escape(clipboardText);
editor.insertText(escapedText); editor.insertText(escapedText);
@ -1975,6 +1997,9 @@ class ChatPage extends LitElement {
let textData = (e.originalEvent || e).clipboardData.getData('text/plain'); let textData = (e.originalEvent || e).clipboardData.getData('text/plain');
editor.insertText(textData); editor.insertText(textData);
}) })
}
return false; return false;
} }

83
qortal-ui-plugins/plugins/core/components/computePowWorker.js

@ -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
}

93
qortal-ui-plugins/plugins/core/components/computePowWorkerImage.js

@ -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
}

60
qortal-ui-plugins/plugins/utils/publish-image.js

@ -14,9 +14,9 @@ export const publishData = async ({
service, service,
identifier, identifier,
parentEpml, parentEpml,
metaData,
uploadType, uploadType,
selectedAddress, selectedAddress,
worker
}) => { }) => {
const validateName = async (receiverName) => { const validateName = async (receiverName) => {
let nameRes = await parentEpml.request("apiCall", { let nameRes = await parentEpml.request("apiCall", {
@ -47,35 +47,23 @@ export const publishData = async ({
const convertedBytes = const convertedBytes =
window.parent.Base58.decode(convertedBytesBase58) window.parent.Base58.decode(convertedBytesBase58)
const _convertedBytesArray = Object.keys(convertedBytes).map( let nonce = null
function (key) { const computPath =window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
return convertedBytes[key] await new Promise((res, rej) => {
worker.postMessage({convertedBytes, path: computPath});
worker.onmessage = e => {
worker.terminate()
nonce = e.data.nonce
res()
} }
) })
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 response = await parentEpml.request("sign_arbitrary", { let response = await parentEpml.request("sign_arbitrary", {
nonce: selectedAddress.nonce, nonce: selectedAddress.nonce,
arbitraryBytesBase58: transactionBytesBase58, arbitraryBytesBase58: transactionBytesBase58,
@ -131,18 +119,7 @@ export const publishData = async ({
postBody = Buffer.from(fileBuffer).toString("base64") 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()}` let uploadDataUrl = `/arbitrary/${service}/${registeredName}${urlSuffix}?apiKey=${getApiKey()}`
if (identifier != null && identifier.trim().length > 0) { if (identifier != null && identifier.trim().length > 0) {
@ -157,5 +134,10 @@ export const publishData = async ({
return uploadDataRes return uploadDataRes
} }
} }
try {
await validate() await validate()
} catch (error) {
throw new Error(error.message)
}
} }

Loading…
Cancel
Save