feat: filegw frontend
This commit is contained in:
parent
93b34dcc85
commit
12058ed403
@ -7,7 +7,6 @@ stages:
|
|||||||
cache: &global_cache
|
cache: &global_cache
|
||||||
key:
|
key:
|
||||||
files:
|
files:
|
||||||
- axum-websockify/Cargo.toml
|
|
||||||
- webrdp/Cargo.toml
|
- webrdp/Cargo.toml
|
||||||
paths:
|
paths:
|
||||||
- .cargo/bin
|
- .cargo/bin
|
||||||
|
19
docker-compose.yml
Normal file
19
docker-compose.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
websockify:
|
||||||
|
build:
|
||||||
|
context: ./websockify
|
||||||
|
command: ["${HOSTNAME}", "${PORT}"]
|
||||||
|
ports:
|
||||||
|
- 8081:8081
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
|
|
||||||
|
filegateway:
|
||||||
|
build:
|
||||||
|
context: ./filegateway
|
||||||
|
command: ["${HOSTNAME}"]
|
||||||
|
ports:
|
||||||
|
- 8082:8082
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
@ -11,7 +11,6 @@ if (!host) {
|
|||||||
console.error("Please provide a host as a command line argument.");
|
console.error("Please provide a host as a command line argument.");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const client = new smb2.Client(host);
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
@ -29,12 +28,14 @@ app.post("/", async (req, res) => {
|
|||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
const domain = req.body.domain;
|
const domain = req.body.domain;
|
||||||
|
|
||||||
|
const client = new smb2.Client(host);
|
||||||
const session = await client.authenticate({ username, password, domain });
|
const session = await client.authenticate({ username, password, domain });
|
||||||
const sessionId = crypto.randomUUID();
|
const sessionId = crypto.randomUUID();
|
||||||
session.trees = {}
|
session.trees = {}
|
||||||
|
|
||||||
sessionPool.createSession(sessionId, session, async (session) => await session.logoff());
|
sessionPool.createSession(sessionId, session, async (session) => await session.logoff());
|
||||||
|
|
||||||
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||||
res.end(JSON.stringify({
|
res.end(JSON.stringify({
|
||||||
"error": null,
|
"error": null,
|
||||||
"sessionId": sessionId
|
"sessionId": sessionId
|
||||||
@ -59,10 +60,11 @@ app.get("/:sessionId/:shareName/*", async (req, res) => {
|
|||||||
|
|
||||||
if (filePath.endsWith("/")) {
|
if (filePath.endsWith("/")) {
|
||||||
const entries = await tree.readDirectory(filePath);
|
const entries = await tree.readDirectory(filePath);
|
||||||
res.end(JSON.stringify({
|
res.json({
|
||||||
error: null,
|
error: null,
|
||||||
entries
|
entries
|
||||||
}));
|
});
|
||||||
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
const readStream = await tree.createFileReadStream(filePath);
|
const readStream = await tree.createFileReadStream(filePath);
|
||||||
readStream.pipe(res);
|
readStream.pipe(res);
|
||||||
@ -88,28 +90,28 @@ app.post("/:sessionId/:shareName/*", async (req, res) => {
|
|||||||
const session = sessionPool.getSession(sessionId);
|
const session = sessionPool.getSession(sessionId);
|
||||||
const tree = await utility.getTree(session, shareName);
|
const tree = await utility.getTree(session, shareName);
|
||||||
|
|
||||||
// Get the uploaded file from the request
|
|
||||||
const file = req.files.file;
|
|
||||||
|
|
||||||
// Check if the file already exists
|
// Check if the file already exists
|
||||||
const fileExists = await tree.exists(filePath);
|
const fileExists = await tree.exists(filePath);
|
||||||
|
|
||||||
// Check if the force parameter is provided in the form
|
// Check if the force parameter is provided in the form
|
||||||
const force = req.body.force;
|
const force = req.query.force;
|
||||||
|
|
||||||
if (fileExists && !force) {
|
if (fileExists && !force) {
|
||||||
res.status(200).json({ error: null, exists: true });
|
res.status(200).json({ error: null, exists: true });
|
||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
// Create a write stream to the destination file
|
// Create a write stream to the destination file
|
||||||
|
if (!fileExists)
|
||||||
|
await tree.createFile(filePath);
|
||||||
const writeStream = await tree.createFileWriteStream(filePath);
|
const writeStream = await tree.createFileWriteStream(filePath);
|
||||||
|
console.log("stream created")
|
||||||
// Pipe the uploaded file to the write stream
|
// Pipe the uploaded file to the write stream
|
||||||
file.pipe(writeStream);
|
req.pipe(writeStream);
|
||||||
|
|
||||||
// Handle events for the write stream
|
// Handle events for the write stream
|
||||||
writeStream.on("finish", () => {
|
writeStream.on("finish", () => {
|
||||||
res.end(JSON.stringify({ error: null }));
|
res.json({ error: null });
|
||||||
|
res.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
writeStream.on("error", (error) => {
|
writeStream.on("error", (error) => {
|
||||||
@ -118,6 +120,7 @@ app.post("/:sessionId/:shareName/*", async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error("upload error", error);
|
||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
@ -142,7 +145,8 @@ app.put("/:sessionId/:shareName/*", async (req, res) => {
|
|||||||
} else {
|
} else {
|
||||||
// Create the folder
|
// Create the folder
|
||||||
await tree.createDirectory(filePath);
|
await tree.createDirectory(filePath);
|
||||||
res.end(JSON.stringify({ error: null }));
|
res.json({ error: null });
|
||||||
|
res.end();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
|
@ -61,7 +61,11 @@ class SessionPool {
|
|||||||
for (const [key, session] of this.sessions) {
|
for (const [key, session] of this.sessions) {
|
||||||
if (session.expiration <= now) {
|
if (session.expiration <= now) {
|
||||||
this.sessions.delete(key);
|
this.sessions.delete(key);
|
||||||
await session.off(session.value)
|
try {
|
||||||
|
await session.off(session.value)
|
||||||
|
} catch(e) {
|
||||||
|
console.error("cleanupSessions: ", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
109
webrdp/assets/file.js
Normal file
109
webrdp/assets/file.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
window.filegatewayUrl = "/filegw/"
|
||||||
|
function initFile() {
|
||||||
|
window.fileShareName = "drive_c$";
|
||||||
|
window.currentPath = [];
|
||||||
|
listFile();
|
||||||
|
setInterval(listFile, 20000);
|
||||||
|
}
|
||||||
|
function getCurrentPath() { return window.filegatewayUrl + window.fileSessionId + "/" + encodeURI(window.fileShareName) + "/" + encodeURI(window.currentPath.join("/")) + "/" }
|
||||||
|
function getSize(fileSize) {
|
||||||
|
var size = parseFloat(fileSize);
|
||||||
|
var units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
while (size >= 1024 && i < units.length - 1) {
|
||||||
|
size /= 1024;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size.toFixed(2) + ' ' + units[i];
|
||||||
|
}
|
||||||
|
function listFile() {
|
||||||
|
$.ajax({
|
||||||
|
url: getCurrentPath(),
|
||||||
|
method: "GET",
|
||||||
|
success: function (response) {
|
||||||
|
var data = response;
|
||||||
|
var table = document.getElementById("filesharelist");
|
||||||
|
table.innerHTML = "";
|
||||||
|
if (window.currentPath.length > 0) {
|
||||||
|
var row = table.insertRow();
|
||||||
|
var cell1 = row.insertCell(0);
|
||||||
|
var cell2 = row.insertCell(1);
|
||||||
|
cell1.innerHTML = "<a href='#' onclick='window.currentPath=window.currentPath.slice(0,-1);updatePathText();listFile();false'>↑🔝🔝🔝↑</a>";
|
||||||
|
cell2.innerHTML = "向上";
|
||||||
|
}
|
||||||
|
for (var i = 0; i < data.entries.length; i++) {
|
||||||
|
if (data.entries[i].fileAttributes.indexOf("Hidden") != -1) continue;
|
||||||
|
var row = table.insertRow();
|
||||||
|
var cell1 = row.insertCell(0);
|
||||||
|
var cell2 = row.insertCell(1);
|
||||||
|
var filename = data.entries[i].filename.slice(2);
|
||||||
|
if (data.entries[i].type == "Directory") {
|
||||||
|
cell1.innerHTML = "<a href='#' onclick='onClickOpenDir(this)'>" + filename + "</a>";
|
||||||
|
cell2.innerHTML = "目录";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cell1.innerHTML = "<a href='" + getCurrentPath() + encodeURI(filename) +"'>" + filename + "</a>";
|
||||||
|
cell2.innerHTML = getSize(data.entries[i].fileSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
alert("文件夹列出失败,可能没有权限或者凭证过期,刷新网页后再试");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
function uploadFile(force) {
|
||||||
|
var fileInput = document.getElementById('fileupload');
|
||||||
|
var file = fileInput.files[0];
|
||||||
|
var suffix = "";
|
||||||
|
var blob = new Blob([file], { type: "application/octet-stream" });
|
||||||
|
if (force)
|
||||||
|
suffix="?force=1"
|
||||||
|
$.ajax({
|
||||||
|
url: getCurrentPath() + encodeURI(file.name) + suffix,
|
||||||
|
method: "POST",
|
||||||
|
data: blob,
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
success: function (response) {
|
||||||
|
if (response.exist && !force) {
|
||||||
|
if (confirm("文件已存在,是否覆盖?")) {
|
||||||
|
uploadFile(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!response.exist && !response.error)
|
||||||
|
alert("上传成功");
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
alert("上传失败,可能没有权限访问。")
|
||||||
|
console.error("upload error", xhr, status, error)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function mkdir() {
|
||||||
|
var dirName = prompt("请输入文件夹名称");
|
||||||
|
if (dirName) {
|
||||||
|
$.ajax({
|
||||||
|
url: getCurrentPath() + encodeURI(dirName),
|
||||||
|
method: "PUT",
|
||||||
|
success: function (response) {
|
||||||
|
if (!response.error)
|
||||||
|
alert("创建成功");
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
alert("创建文件夹失败,可能是没有权限");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onClickOpenDir(element) {
|
||||||
|
window.currentPath = window.currentPath.concat(element.innerHTML);
|
||||||
|
updatePathText();
|
||||||
|
listFile();
|
||||||
|
}
|
||||||
|
function updatePathText() {
|
||||||
|
$("#currentPath").text("/"+window.fileShareName+"/"+window.currentPath.join("/")+"/")
|
||||||
|
}
|
@ -139,7 +139,16 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filesharelist {
|
#filesharelist {
|
||||||
|
width: 295px;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
border: 1px dotted #000;
|
border: 1px dotted #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tbody {
|
||||||
|
display: block;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: scroll;
|
||||||
|
height: inherit;
|
||||||
|
width: inherit;
|
||||||
}
|
}
|
@ -26,7 +26,6 @@
|
|||||||
overscroll-behavior: none;
|
overscroll-behavior: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="./jquery-3.6.1.min.js" type="text/javascript"></script>
|
|
||||||
<script type="module" defer>
|
<script type="module" defer>
|
||||||
import initWASM from "/webrdp.js";
|
import initWASM from "/webrdp.js";
|
||||||
async function wasm() {
|
async function wasm() {
|
||||||
@ -35,8 +34,6 @@
|
|||||||
window.wasm = wasm;
|
window.wasm = wasm;
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
filegateway_url="/filegw";
|
|
||||||
function initFile(){}
|
|
||||||
function jsExportedCredentials(key) {
|
function jsExportedCredentials(key) {
|
||||||
console.log("requested key", key)
|
console.log("requested key", key)
|
||||||
if (jsExportedCredentials[key]) {
|
if (jsExportedCredentials[key]) {
|
||||||
@ -47,36 +44,13 @@
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function connect(user, password, event) {
|
function wrongCredential() {
|
||||||
jsExportedCredentials.user = user;
|
disconnectedAndRefresh("用户名或密码错误!")
|
||||||
jsExportedCredentials.password = password;
|
}
|
||||||
$.ajax({
|
|
||||||
url: filegateway_url,
|
function disconnectedAndRefresh(msg) {
|
||||||
method: "POST",
|
alert(msg ?? "抱歉,与服务器连接断开。");
|
||||||
data: {
|
window.location.reload();
|
||||||
username: jsExportedCredentials.user,
|
|
||||||
password: jsExportedCredentials.password,
|
|
||||||
domain: jsExportedCredentials.domain
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
var sessionId = response.sessionId;
|
|
||||||
window.fileSessionId = sessionId;
|
|
||||||
initFile();
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
alert(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.wasm().then(() => {
|
|
||||||
$('#login_container').hide();
|
|
||||||
$('#rdp_container').show();
|
|
||||||
}).catch((err) => {
|
|
||||||
alert(err);
|
|
||||||
});
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
@ -123,113 +97,18 @@
|
|||||||
<div>分享:<select name="" id="">
|
<div>分享:<select name="" id="">
|
||||||
<option value="drive_c$">drive_c$</option>
|
<option value="drive_c$">drive_c$</option>
|
||||||
</select></div>
|
</select></div>
|
||||||
<ul class="filesharelist">
|
<table id="filesharelist">
|
||||||
<li><a>Program Files</a></li>
|
</table>
|
||||||
<li><a>Program Files (x86)</a></li>
|
<div><button onclick="mkdir()">新建文件夹</button><button onclick="listFile()">刷新</button></div>
|
||||||
<li><a>Perflogs</a></li>
|
<div><input type="file" name="文件上传" id="fileupload"><input type="submit" name="上传" id="filesubmit" onclick="uploadFile()"></div>
|
||||||
<li><a>Windows</a></li>
|
|
||||||
<li><a>Users</a></li>
|
|
||||||
</ul>
|
|
||||||
<div><button>新建文件夹</button></div>
|
|
||||||
<div><input type="file" name="文件上传" id="fileupload"><input type="submit" name="上传" id="filesubmit"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
<script src="./jquery-3.6.1.min.js" type="text/javascript"></script>
|
||||||
|
<script type="text/javascript" src="./ui.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript" src="./rdp.js"></script>
|
||||||
function wrongCredential() {
|
<script type="text/javascript" src="./file.js"></script>
|
||||||
disconnectedAndRefresh("用户名或密码错误!")
|
|
||||||
}
|
|
||||||
|
|
||||||
function disconnectedAndRefresh(msg) {
|
|
||||||
alert(msg ?? "抱歉,与服务器连接断开。");
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/javascript" defer>
|
|
||||||
|
|
||||||
$("#clipboardbtn").attr("open1", 0);
|
|
||||||
$("#clipboardbtn").click(
|
|
||||||
function (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (($("#clipboardbtn")).attr("open1") == 0) {
|
|
||||||
clipboard_open();
|
|
||||||
} else {
|
|
||||||
clipboard_close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$(".clipboardback").click(function () {
|
|
||||||
clipboard_close();
|
|
||||||
})
|
|
||||||
$(".clipboard").click(function () {
|
|
||||||
event.stopPropagation();
|
|
||||||
})
|
|
||||||
function clipboard_open() {
|
|
||||||
$("#clipboardbtn").attr("open1", 1);
|
|
||||||
$("#clipboardbtn").html(">")
|
|
||||||
$(".clipboard").toggleClass("clipboard-open");
|
|
||||||
$(".clipboardback").toggleClass("clipboardback-open");
|
|
||||||
$(".clipboardback").css("pointer-events", "auto");
|
|
||||||
}
|
|
||||||
|
|
||||||
function clipboard_close() {
|
|
||||||
$("#clipboardbtn").attr("open1", 0);
|
|
||||||
$("#clipboardbtn").html("«")
|
|
||||||
$(".clipboard").toggleClass("clipboard-open");
|
|
||||||
$(".clipboardback").toggleClass("clipboardback-open");
|
|
||||||
$(".clipboardback").css("pointer-events", "none");
|
|
||||||
}
|
|
||||||
|
|
||||||
function setClipBoard(s) {
|
|
||||||
$("#clipboardtxt").val(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getClipBoard() {
|
|
||||||
return $("#clipboardtxt").val();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$("#filesharebtn").attr("open1", 0);
|
|
||||||
$("#filesharebtn").click(
|
|
||||||
function (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (($("#filesharebtn")).attr("open1") == 0) {
|
|
||||||
fileshare_open();
|
|
||||||
} else {
|
|
||||||
fileshare_close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$(".fileshareback").click(function () {
|
|
||||||
fileshare_close();
|
|
||||||
})
|
|
||||||
$(".fileshare").click(function () {
|
|
||||||
event.stopPropagation();
|
|
||||||
})
|
|
||||||
function fileshare_open() {
|
|
||||||
$("#filesharebtn").attr("open1", 1);
|
|
||||||
$("#filesharebtn").html("<")
|
|
||||||
$(".fileshare").toggleClass("fileshare-open");
|
|
||||||
$(".fileshareback").toggleClass("fileshareback-open");
|
|
||||||
$(".fileshareback").css("pointer-events", "auto");
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileshare_close() {
|
|
||||||
$("#filesharebtn").attr("open1", 0);
|
|
||||||
$("#filesharebtn").html("»")
|
|
||||||
$(".fileshare").toggleClass("fileshare-open");
|
|
||||||
$(".fileshareback").toggleClass("fileshareback-open");
|
|
||||||
$(".fileshareback").css("pointer-events", "none");
|
|
||||||
}
|
|
||||||
|
|
||||||
// canvas 防止触屏滑动事件
|
|
||||||
$("#canvas").on("touchmove", function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</body>
|
32
webrdp/assets/rdp.js
Normal file
32
webrdp/assets/rdp.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
function connect(user, password, event) {
|
||||||
|
jsExportedCredentials.user = user;
|
||||||
|
jsExportedCredentials.password = password;
|
||||||
|
$.ajax({
|
||||||
|
url: window.filegatewayUrl,
|
||||||
|
method: "POST",
|
||||||
|
data: {
|
||||||
|
username: jsExportedCredentials.user,
|
||||||
|
password: jsExportedCredentials.password,
|
||||||
|
domain: jsExportedCredentials.domain
|
||||||
|
},
|
||||||
|
success: function (response) {
|
||||||
|
var data = response;
|
||||||
|
var sessionId = data.sessionId;
|
||||||
|
window.fileSessionId = sessionId;
|
||||||
|
initFile();
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
alert("文件服务登录失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.wasm().then(() => {
|
||||||
|
$('#login_container').hide();
|
||||||
|
$('#rdp_container').show();
|
||||||
|
}).catch((err) => {
|
||||||
|
alert(err);
|
||||||
|
});
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
79
webrdp/assets/ui.js
Normal file
79
webrdp/assets/ui.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
$("#clipboardbtn").attr("open1", 0);
|
||||||
|
$("#clipboardbtn").click(
|
||||||
|
function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (($("#clipboardbtn")).attr("open1") == 0) {
|
||||||
|
clipboard_open();
|
||||||
|
} else {
|
||||||
|
clipboard_close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$(".clipboardback").click(function () {
|
||||||
|
clipboard_close();
|
||||||
|
})
|
||||||
|
$(".clipboard").click(function () {
|
||||||
|
event.stopPropagation();
|
||||||
|
})
|
||||||
|
function clipboard_open() {
|
||||||
|
$("#clipboardbtn").attr("open1", 1);
|
||||||
|
$("#clipboardbtn").html(">")
|
||||||
|
$(".clipboard").toggleClass("clipboard-open");
|
||||||
|
$(".clipboardback").toggleClass("clipboardback-open");
|
||||||
|
$(".clipboardback").css("pointer-events", "auto");
|
||||||
|
}
|
||||||
|
|
||||||
|
function clipboard_close() {
|
||||||
|
$("#clipboardbtn").attr("open1", 0);
|
||||||
|
$("#clipboardbtn").html("«")
|
||||||
|
$(".clipboard").toggleClass("clipboard-open");
|
||||||
|
$(".clipboardback").toggleClass("clipboardback-open");
|
||||||
|
$(".clipboardback").css("pointer-events", "none");
|
||||||
|
}
|
||||||
|
|
||||||
|
function setClipBoard(s) {
|
||||||
|
$("#clipboardtxt").val(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getClipBoard() {
|
||||||
|
return $("#clipboardtxt").val();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$("#filesharebtn").attr("open1", 0);
|
||||||
|
$("#filesharebtn").click(
|
||||||
|
function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (($("#filesharebtn")).attr("open1") == 0) {
|
||||||
|
fileshare_open();
|
||||||
|
} else {
|
||||||
|
fileshare_close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$(".fileshareback").click(function () {
|
||||||
|
fileshare_close();
|
||||||
|
})
|
||||||
|
$(".fileshare").click(function () {
|
||||||
|
event.stopPropagation();
|
||||||
|
})
|
||||||
|
function fileshare_open() {
|
||||||
|
$("#filesharebtn").attr("open1", 1);
|
||||||
|
$("#filesharebtn").html("<")
|
||||||
|
$(".fileshare").toggleClass("fileshare-open");
|
||||||
|
$(".fileshareback").toggleClass("fileshareback-open");
|
||||||
|
$(".fileshareback").css("pointer-events", "auto");
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileshare_close() {
|
||||||
|
$("#filesharebtn").attr("open1", 0);
|
||||||
|
$("#filesharebtn").html("»")
|
||||||
|
$(".fileshare").toggleClass("fileshare-open");
|
||||||
|
$(".fileshareback").toggleClass("fileshareback-open");
|
||||||
|
$(".fileshareback").css("pointer-events", "none");
|
||||||
|
}
|
||||||
|
|
||||||
|
// canvas 防止触屏滑动事件
|
||||||
|
$("#canvas").on("touchmove", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
@ -1,20 +1,13 @@
|
|||||||
# 使用 Node.js 18 镜像作为基础
|
|
||||||
FROM node:18-slim
|
FROM node:18-slim
|
||||||
|
|
||||||
# 设置工作目录
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 将 package.json 和 package-lock.json 复制到容器中
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
# 将应用程序代码复制到容器中
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# 暴露应用程序的端口
|
|
||||||
EXPOSE 8081
|
EXPOSE 8081
|
||||||
|
|
||||||
# 运行应用程序
|
ENTRYPOINT [ "node", "index.js" ]
|
||||||
CMD [ "node", "index.js" ]
|
|
@ -60,6 +60,11 @@ async function handleClient(ws) {
|
|||||||
ws.send(data, { binary: true });
|
ws.send(data, { binary: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
upgradedStatus.secureSocket.on('error', (error) => {
|
||||||
|
log("Upgraded to SSL. error:", error);
|
||||||
|
ws.close();
|
||||||
|
});
|
||||||
|
|
||||||
ws.on('message', (msg) => {
|
ws.on('message', (msg) => {
|
||||||
log("Upgraded to SSL. Send socket:", msg);
|
log("Upgraded to SSL. Send socket:", msg);
|
||||||
upgradedStatus.secureSocket.write(msg);
|
upgradedStatus.secureSocket.write(msg);
|
||||||
|
Loading…
Reference in New Issue
Block a user