From 1dc9320ad73bb09acecce3dc0a96df4703d67720 Mon Sep 17 00:00:00 2001
From: unknown <1371033826@qq.com>
Date: Wed, 11 Jun 2025 16:01:13 +0800
Subject: [PATCH] add-img-store
---
ejs/projects.ejs | 5 +-
icons/store.svg | 1 +
img/store/.gitignore | 8 +++
js/projects.js | 116 ++++++++++++++++++++++++++++++++++++++++++-
mixio.js | 79 +++++++++++++++++++++++++++++
5 files changed, 207 insertions(+), 2 deletions(-)
create mode 100644 icons/store.svg
create mode 100644 img/store/.gitignore
diff --git a/ejs/projects.ejs b/ejs/projects.ejs
index 5808dab..d5d9049 100644
--- a/ejs/projects.ejs
+++ b/ejs/projects.ejs
@@ -122,8 +122,11 @@
+
-
+ 存储空间
+
+
Copyright© Mixly Team @ BNU, CHINA
diff --git a/icons/store.svg b/icons/store.svg
new file mode 100644
index 0000000..c727aca
--- /dev/null
+++ b/icons/store.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/img/store/.gitignore b/img/store/.gitignore
new file mode 100644
index 0000000..e28792d
--- /dev/null
+++ b/img/store/.gitignore
@@ -0,0 +1,8 @@
+*.txt
+*.png
+*.bmp
+*.jpg
+*.jpeg
+*.gif
+*.svg
+*.ico
\ No newline at end of file
diff --git a/js/projects.js b/js/projects.js
index 44e70c8..40b351b 100644
--- a/js/projects.js
+++ b/js/projects.js
@@ -809,6 +809,7 @@ function view_project(projectName, projectType) {
$("#accordionSidebar").remove()
$("#sidebarToggleTop").remove()
$("#connect_span").removeAttr("hidden")
+ $("#storage_space").removeAttr("hidden")
init_layout()
$("#projMode").click(function() {
if (globalProjectType != PROJ_MODE) {
@@ -4202,4 +4203,117 @@ setInterval(function(){
save_layout(false, true)
isChanged = false
}
-}, 30000)
\ No newline at end of file
+}, 30000)
+
+
+function open_storage(){
+ var editForm = $('')
+ editForm.append($(''))
+ editForm.append($('所有发送到/storage主题下的消息和图片会被自动保存
'))
+ var messagesContainer = $('')
+ var sync_stor = function(){
+ messagesContainer.empty()
+ var sampleMessages = [
+ ]
+ $.getJSON('getImgStore', {
+ 'projectName': globalProjectName
+ }, function(res) {
+ if(res.length==0)
+ {
+ messagesContainer.append($('暂无存储
'))
+ }
+ for (let ri = 0; ri < res.length; ri++) {
+ {
+ let url = "img/store/" + globalUserName + "/" + globalProjectName + "/" + res[ri]
+ if (url.endsWith('.txt')) {
+ sampleMessages.push({ type: 'text', content: url })
+ } else{
+ sampleMessages.push({ type: 'image', content: url })
+ }
+ }
+ }
+ for(let ji = 0; ji < sampleMessages.length; ji++) {
+ let msg = sampleMessages[ji]
+ let messageBox = $('')
+
+ if (msg.type === 'text') {
+ $.ajax({
+ url: msg.content,
+ success: function(res) {
+ messageBox.append($('').text(res))
+ // Add timestamp (sample)
+ let timeStamp = parseInt(msg.content.split("/")[msg.content.split("/").length - 1].split(".")[0])
+ let timeString = new Date(timeStamp).toLocaleString()
+ let btdiv = $('')
+ btdiv.append("" + timeString +"")
+ let deletebtn = $('')
+ deletebtn.click(function(){
+ $.getJSON('deleteImgStore', {
+ 'projectName': globalProjectName,
+ 'filename': msg.content.split("/")[msg.content.split("/").length - 1]
+ }, function(){
+ sync_stor()
+ })
+ })
+ btdiv.append(deletebtn)
+ messageBox.append(btdiv)
+ }
+ })
+ } else if (msg.type === 'image') {
+ messageBox.append($('
'))
+ // Add timestamp (sample)
+ let timeStamp = parseInt(msg.content.split("/")[msg.content.split("/").length - 1].split(".")[0])
+ let timeString = new Date(timeStamp).toLocaleString()
+ let btdiv = $('')
+ btdiv.append("" + timeString +"")
+ let viewbtn = $('')
+ viewbtn.click(function(){
+ // 全屏显示图片,点击任意退出
+ let fullDialog = dialog({
+ content: $('')[0],
+ cancel: true,
+ cancelValue: '关闭'
+ })
+ fullDialog.showModal()
+
+ })
+ let deletebtn = $('')
+ deletebtn.click(function(){
+ $.getJSON('deleteImgStore', {
+ 'projectName': globalProjectName,
+ 'filename': msg.content.split("/")[msg.content.split("/").length - 1]
+ }, function(){
+ sync_stor()
+ })
+ })
+ btdiv.append(viewbtn)
+ btdiv.append(deletebtn)
+ messageBox.append(btdiv)
+ }
+ messagesContainer.prepend(messageBox)
+ }
+ })
+ }
+ editForm.append(messagesContainer)
+ sync_stor()
+ client.on('message', function(topic, msg) {
+ if(topic.split("/")[2] == "storage")
+ sync_stor()
+ })
+ // Bottom section
+ var bottomDiv = $('')
+ var cancelEdit = $('')
+ bottomDiv.append(cancelEdit)
+ editForm.append(bottomDiv)
+
+ var modifyDia = dialog({
+ content: editForm[0],
+ cancel: false
+ })
+
+ cancelEdit.click(function() {
+ modifyDia.close().remove()
+ })
+
+ modifyDia.showModal()
+}
\ No newline at end of file
diff --git a/mixio.js b/mixio.js
index b4e75c3..3914146 100644
--- a/mixio.js
+++ b/mixio.js
@@ -830,6 +830,30 @@ var mixioServer = async function() {
var topic = packet.topic.split('/')
var payload = String(packet.payload)
if (topic.length == 3) {
+ if(topic[2] == 'storage') {
+ // 判断是否是base64, 开头为data:image/***;base64, ***可以为png,bmp,jpg,jpeg,gif,svg,ico
+ const allowFormats = ['png', 'bmp', 'jpg', 'jpeg', 'gif', 'svg', 'ico'];
+ const base64Reg = /^data:image\/(\w+);base64,/;
+ const match = payload.match(base64Reg);
+ if (match && allowFormats.includes(match[1])) {
+ // 是base64
+ const format = match[1];
+ const timeStamp = Date.now();
+ const fileName = `${timeStamp}.${format}`;
+ const filePath = path.join(__dirname, 'img', 'store', topic[0], topic[1], fileName);
+ const base64Data = payload.replace(base64Reg, '');
+ const buffer = Buffer.from(base64Data, 'base64');
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ fs.writeFileSync(filePath, buffer);
+ } else {
+ // 全部明文存为txt
+ const timeStamp = Date.now();
+ const fileName = `${timeStamp}.txt`;
+ const filePath = path.join(__dirname, 'img', 'store', topic[0], topic[1], fileName);
+ fs.mkdirSync(path.dirname(filePath), { recursive: true});
+ fs.writeFileSync(filePath, payload);
+ }
+ }
if (topic[2] == 'b640a0ce465fa2a4150c36b305c1c11b') {
if (STORAGE_ENGINE == "sqlite")
db.run("insert or ignore into devices (userName, clientid) values (?,?)", [topic[0], payload])
@@ -1323,6 +1347,61 @@ var mixioServer = async function() {
res.redirect('/')
})
+ app.get('/getImgStore', function(req, res) {
+ if (req.session.userName && req.query.projectName){
+ var projectName = req.query.projectName
+ // img/store/username/projectName
+ var imgStorePath = path.join(__dirname, 'img', 'store', req.session.userName, projectName)
+ // 文件名发送列表
+ fs.readdir(imgStorePath, function(err, files) {
+ res.send(files || [])
+ })
+ } else
+ res.redirect('/')
+ })
+
+ app.get('/clearImgStore', function(req, res) {
+ if (req.session.userName && req.query.projectName){
+ var projectName = req.query.projectName
+ // img/store/username/projectName
+ var imgStorePath = path.join(__dirname, 'img', 'store', req.session.userName, projectName)
+ // 清空文件
+ fs.readdir(imgStorePath, function(err, files) {
+ files.forEach(function(file) {
+ fs.unlink(path.join(imgStorePath, file), function(err) {
+ if (err) {
+ console.log(err)
+ }
+ })
+ })
+ })
+ res.send({
+ "status": "success"
+ })
+ } else
+ res.redirect('/')
+ })
+
+ app.get('/deleteImgStore', function(req, res) {
+ if (req.session.userName && req.query.projectName && req.query.filename){
+ var projectName = req.query.projectName
+ var filename = req.query.filename
+ // img/store/username/projectName
+ var imgStorePath = path.join(__dirname, 'img', 'store', req.session.userName, projectName)
+ // 删除文件
+ fs.unlink(path.join(imgStorePath, filename), function(err) {
+ if (err) {
+ console.log(err)
+ }
+ })
+ res.send({
+ "status": "success"
+ }
+ )
+ } else
+ res.redirect('/')
+ })
+
app.get('/projects', function(req, res) {
if (req.session.userName) {
ejs.renderFile(__dirname + '/ejs/projects.ejs', {