Compare commits
1 Commits
master
...
use_file_e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
363c7a8dd5 |
60
Makefile
60
Makefile
@ -3,27 +3,18 @@
|
||||
######################################################################
|
||||
|
||||
# Path to nodemcu-uploader (https://github.com/kmpm/nodemcu-uploader)
|
||||
NODEMCU-UPLOADER?=python ../nodemcu-uploader/nodemcu-uploader.py
|
||||
|
||||
# Path to LUA cross compiler (part of the nodemcu firmware; only needed to compile the LFS image yourself)
|
||||
LUACC?=../nodemcu-firmware/luac.cross
|
||||
NODEMCU-UPLOADER=../nodemcu-uploader/nodemcu-uploader.py
|
||||
|
||||
# Serial port
|
||||
PORT?=$(shell ls /dev/cu.SLAB_USBtoUART /dev/ttyUSB* 2>/dev/null|head -n1)
|
||||
SPEED?=115200
|
||||
PORT=/dev/cu.SLAB_USBtoUART
|
||||
SPEED=115200
|
||||
|
||||
define _upload
|
||||
@$(NODEMCU-UPLOADER) -b $(SPEED) --start_baud $(SPEED) -p $(PORT) upload $^
|
||||
endef
|
||||
NODEMCU-COMMAND=$(NODEMCU-UPLOADER) -b $(SPEED) --start_baud $(SPEED) -p $(PORT) upload
|
||||
|
||||
######################################################################
|
||||
|
||||
LFS_IMAGE ?= lfs.img
|
||||
HTTP_FILES := $(wildcard http/*)
|
||||
WIFI_CONFIG := $(wildcard *conf*.lua)
|
||||
SERVER_FILES := $(filter-out $(WIFI_CONFIG), $(wildcard srv/*.lua) $(wildcard *.lua))
|
||||
LFS_FILES := $(LFS_IMAGE) $(filter-out $(WIFI_CONFIG), $(wildcard *.lua))
|
||||
FILE ?=
|
||||
LUA_FILES := $(wildcard *.lua)
|
||||
|
||||
# Print usage
|
||||
usage:
|
||||
@ -31,40 +22,21 @@ usage:
|
||||
@echo "make upload_http to upload files to be served"
|
||||
@echo "make upload_server to upload the server code and init.lua"
|
||||
@echo "make upload_all to upload all"
|
||||
@echo "make upload_lfs to upload lfs based server code"
|
||||
@echo "make upload_all_lfs to upload all (LFS based)"
|
||||
@echo $(TEST)
|
||||
|
||||
# Upload one file only
|
||||
upload: $(FILE)
|
||||
$(_upload)
|
||||
# Upload one files only
|
||||
upload:
|
||||
@python $(NODEMCU-COMMAND) $(FILE)
|
||||
|
||||
# Upload HTTP files only
|
||||
upload_http: $(HTTP_FILES)
|
||||
$(_upload)
|
||||
@python $(NODEMCU-COMMAND) $(foreach f, $^, $(f))
|
||||
|
||||
# Upload httpserver lua files
|
||||
upload_server: $(SERVER_FILES)
|
||||
$(_upload)
|
||||
# Upload httpserver lua files (init and server module)
|
||||
upload_server: $(LUA_FILES)
|
||||
@python $(NODEMCU-COMMAND) $(foreach f, $^, $(f))
|
||||
|
||||
# Upload wifi configuration
|
||||
upload_wifi_config: $(WIFI_CONFIG)
|
||||
$(_upload)
|
||||
# Upload all
|
||||
upload_all: $(LUA_FILES) $(HTTP_FILES)
|
||||
@python $(NODEMCU-COMMAND) $(foreach f, $^, $(f))
|
||||
|
||||
# Upload lfs image
|
||||
upload_lfs: $(LFS_FILES)
|
||||
$(_upload)
|
||||
|
||||
$(LFS_IMAGE):
|
||||
$(LUACC) -f -o $(LFS_IMAGE) srv/*.lua
|
||||
|
||||
# Upload all non-lfs files
|
||||
upload_all: $(HTTP_FILES) $(SERVER_FILES) $(WIFI_CONFIG)
|
||||
$(_upload)
|
||||
|
||||
# Upload all lfs files
|
||||
upload_all_lfs: $(HTTP_FILES) $(LFS_FILES) $(WIFI_CONFIG)
|
||||
$(_upload)
|
||||
|
||||
.ENTRY: usage
|
||||
.PHONY: usage upload_http upload_server upload_wifi_config \
|
||||
upload_lfs upload_all upload_all_lfs
|
||||
|
||||
22
README.md
22
README.md
@ -38,10 +38,6 @@ Let the abuse begin.
|
||||
|
||||
make upload_server
|
||||
|
||||
If you only want to update wifi configuration, type:
|
||||
|
||||
make upload_wifi_config
|
||||
|
||||
And if you only want to upload just the files that can be served:
|
||||
|
||||
make upload_http
|
||||
@ -60,7 +56,7 @@ Let the abuse begin.
|
||||
3. Visit your server from a web browser.
|
||||
|
||||
__Example:__ Say the IP for your ESP8266 is 2.2.2.2 and the server is
|
||||
running in the default port 80. Go to <http://2.2.2.2/index.html> using your web browser.
|
||||
running in the default port 80. Go to (http://2.2.2.2/index.html)[http://2.2.2.2/index.html] using your web browser.
|
||||
The ESP8266 will serve you with the contents of the file "http/index.html" (if it exists). If you visit the root (/)
|
||||
then index.html is served. By the way, unlike most HTTP servers, nodemcu_httpserver treats the URLs in a
|
||||
case-sensitive manner.
|
||||
@ -92,20 +88,6 @@ Let the abuse begin.
|
||||
For example, if the client requests _http://2.2.2.2/foo.lua?color=red_ then the server will execute the function
|
||||
in your Lua script _foo.lua_ and pass in _connection_ and _args_, where _args.color = "red"_.
|
||||
|
||||
## [LFS](https://nodemcu.readthedocs.io/en/master/lfs/) support.
|
||||
|
||||
NodeMCU allows to run Lua scripts from LFS in order to save RAM resources.
|
||||
*nodemcu-httpserver* makes it easy to move your code to LFS.
|
||||
In order to run *nodemcu-httpserver* from LFS:
|
||||
|
||||
1. move your code to `srv` folder (if you want it to be included in LFS image)
|
||||
|
||||
1. Compile contents of `srv` into LFS image. There's a [cloud service](https://blog.ellisons.org.uk/article/nodemcu/a-lua-cross-compile-web-service/) and [docker image](https://github.com/marcelstoer/docker-nodemcu-build) that will help you with that.
|
||||
|
||||
1. Upload image file under `lfs.img` name. You may use Makefile rules `upload_lfs` and `upload_all_lfs` for this.
|
||||
|
||||
1. Reboot you NodeMCU. Init script will pick up image and apply it for you.
|
||||
|
||||
### Example: Garage door opener
|
||||
|
||||
#### Purpose
|
||||
@ -154,7 +136,7 @@ Let the abuse begin.
|
||||
|
||||
* Other methods: HEAD, DELETE, TRACE, OPTIONS, CONNECT, PATCH
|
||||
* Encryption / SSL
|
||||
* Old nodemcu-firmware versions prior to January 2021) because I don't bother to test them.
|
||||
* Old nodemcu-firmware versions prior to January 2017) because I don't bother to test them.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
@ -1,19 +1,21 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Nice cars</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Nice cars!</h1>
|
||||
<p>
|
||||
This page loads "large" images of fancy cars. It is meant to serve as a stress test for nodemcu-httpserver.<br>
|
||||
It works with three embedded images of cars, but the server crashes with four. Edit this file and try it yourself.<br>
|
||||
Whoever manages to modify nodemcu-httpserver to load all four images without crashing wins a prize!
|
||||
</p>
|
||||
<figure><img src="cars-ferrari.jpg" /><figcaption>Ferrari</figcaption></figure>
|
||||
<figure><img src="cars-lambo.jpg" /><figcaption>Lamborghini</figcaption></figure>
|
||||
<figure><img src="cars-mas.jpg" /><figcaption>Maserati</figcaption></figure>
|
||||
<figure><img src="cars-porsche.jpg" /><figcaption>Porsche</figcaption></figure>
|
||||
</body>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Nice cars</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Nice cars!</h1>
|
||||
<p>
|
||||
This page loads "large" images of fancy cars. It is meant to serve as a stress test for nodemcu-httpserver.<br>
|
||||
It works with three embedded images of cars, but the server crashes with four. Edit this file and try it yourself.<br>
|
||||
Whoever manages to modify nodemcu-httpserver to load all four images without crashing wins a prize!
|
||||
</p>
|
||||
<figure><img src="cars-ferrari.jpg" /><figcaption>Ferrari</figcaption></figure>
|
||||
<figure><img src="cars-lambo.jpg" /><figcaption>Lamborghini</figcaption></figure>
|
||||
<figure><img src="cars-mas.jpg" /><figcaption>Maserati</figcaption></figure>
|
||||
<figure><img src="cars-porsche.jpg" /><figcaption>Porsche</figcaption></figure>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
return function (connection, req, args)
|
||||
|
||||
local function showCars(nr)
|
||||
if not nr then return end
|
||||
connection:send([===[<figure><img src="cars-ferrari.jpg" /><figcaption>Ferrari</figcaption></figure>]===])
|
||||
if nr == "1" then return end
|
||||
connection:send([===[<figure><img src="cars-lambo.jpg" /><figcaption>Lamborghini</figcaption></figure>]===])
|
||||
if nr == "2" then return end
|
||||
connection:send([===[<figure><img src="cars-mas.jpg" /><figcaption>Maserati</figcaption></figure>]===])
|
||||
if nr == "3" then return end
|
||||
connection:send([===[<figure><img src="cars-porsche.jpg" /><figcaption>Porsche</figcaption></figure>]===])
|
||||
if nr == "4" then return end
|
||||
connection:send([===[<figure><img src="cars-bugatti.jpg" /><figcaption>Bugatti</figcaption></figure>]===])
|
||||
if nr == "5" then return end
|
||||
connection:send([===[<figure><img src="cars-mercedes.jpg" /><figcaption>Mercedes</figcaption></figure>]===])
|
||||
end
|
||||
|
||||
|
||||
dofile("httpserver-header.lc")(connection, 200, 'html')
|
||||
connection:send([===[
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Nice cars</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Nice cars!</h1>
|
||||
<p>
|
||||
This page loads "large" images of fancy cars. It is meant to serve as a stress test for nodemcu-httpserver.<br>
|
||||
It works with three embedded images of cars, but the server crashes with four. Select the number of cars you want to see below.<br>
|
||||
Whoever manages to modify nodemcu-httpserver to load all four images without crashing wins a prize!
|
||||
</p>
|
||||
<p>
|
||||
OK I guess I win the prize, as now you can load five cars.<br>
|
||||
Cheers HHHartmann
|
||||
</p>
|
||||
<p>
|
||||
choose: <a href="?n=1">show one car</a>
|
||||
<a href="?n=2">show two cars</a>
|
||||
<a href="?n=3">show three cars</a>
|
||||
<a href="?n=4">show four cars</a>
|
||||
<a href="?n=5">show five cars</a>
|
||||
<a href="?n=6">show six cars</a>
|
||||
</p>
|
||||
]===])
|
||||
|
||||
showCars(args.n)
|
||||
|
||||
connection:send([===[
|
||||
</body>
|
||||
</html>
|
||||
]===])
|
||||
end
|
||||
|
||||
@ -1,22 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Counter</title>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function ()
|
||||
{
|
||||
var number = window.location.search;
|
||||
if ( number == '') number = 0;
|
||||
else number = number.substring(1,);
|
||||
number = parseInt(number) + 1;
|
||||
document.getElementById('count').innerHTML = number;
|
||||
window.location.search = '?' + number;
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<br>This page reloads itself as fast as it can to test the server.<br>
|
||||
<br>It is meant as a stress test to see when and if the server fails.<br>
|
||||
<h1 id="count" class="countclass">-</h1>
|
||||
</body>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function ()
|
||||
{
|
||||
var number = window.location.search;
|
||||
if ( number == '') number = 0;
|
||||
else number = number.substring(1,);
|
||||
|
||||
number = parseInt(number) + 1;
|
||||
document.getElementById('count').innerHTML = number;
|
||||
window.location.search = '?' + number;
|
||||
}
|
||||
)
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<br>This page reloads itself as fast as it can to test the server.</br>
|
||||
<br>It is meant as a stress test to see when and if the server fails.</br>
|
||||
<h1 id="count" class="countclass">
|
||||
</h1>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -16,7 +16,7 @@ return function (connection, req, args)
|
||||
connection:send("<b>Flash Address: </b> " .. flashAddress .. " bytes<br/>\n" ..
|
||||
"<b>Flash Size: </b> " .. flashSize .. " bytes<br/>\n")
|
||||
|
||||
connection:send("<b>Files:</b><br/>\n<ul>\n")
|
||||
connection:send("<p>\n<b>Files:</b><br/>\n<ul>\n")
|
||||
for name, size in pairs(file.list()) do
|
||||
local isHttpFile = string.match(name, "(http/)") ~= nil
|
||||
if isHttpFile then
|
||||
@ -24,6 +24,6 @@ return function (connection, req, args)
|
||||
connection:send(' <li><a href="' .. url .. '">' .. url .. "</a> (" .. size .. " bytes)</li>\n")
|
||||
end
|
||||
end
|
||||
connection:send("</ul>\n</body></html>")
|
||||
connection:send("</ul>\n</p>\n</body></html>")
|
||||
end
|
||||
|
||||
|
||||
@ -1,31 +1,32 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Garage control</title>
|
||||
<style>
|
||||
div{
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h2>Door 1</h2>
|
||||
<form action="garage_door.lua" method="post">
|
||||
<input type="hidden" name="door" value="1">
|
||||
<input type="submit" name="action" value="status">
|
||||
<input type="submit" name="action" value="open">
|
||||
<input type="submit" name="action" value="close">
|
||||
<input type="submit" name="action" value="toggle">
|
||||
</form>
|
||||
<h2>Door 2</h2>
|
||||
<form action="garage_door.lua" method="post">
|
||||
<input type="hidden" name="door" value="2">
|
||||
<input type="submit" name="action" value="status">
|
||||
<input type="submit" name="action" value="open">
|
||||
<input type="submit" name="action" value="close">
|
||||
<input type="submit" name="action" value="toggle">
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
<html>
|
||||
<head>
|
||||
<title>Garage control</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<h2>Door 1</h2>
|
||||
|
||||
<form action="garage_door.lua" method="post"/>
|
||||
<input type="hidden" name="door" value="1"/>
|
||||
<input type="submit" name="action" value="status"/>
|
||||
<input type="submit" name="action" value="open"/>
|
||||
<input type="submit" name="action" value="close"/>
|
||||
<input type="submit" name="action" value="toggle"/>
|
||||
</form>
|
||||
|
||||
<h2>Door 2</h2>
|
||||
|
||||
<form action="garage_door.lua" method="post"/>
|
||||
<input type="hidden" name="door" value="2"/>
|
||||
<input type="submit" name="action" value="status"/>
|
||||
<input type="submit" name="action" value="open"/>
|
||||
<input type="submit" name="action" value="close"/>
|
||||
<input type="submit" name="action" value="toggle"/>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="garage_door_control.css">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<meta charset="UTF-8">
|
||||
<title>Garage Remote</title>
|
||||
<script>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="garage_door_control.css">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<meta charset="UTF-8">
|
||||
<title>Garage Remote</title>
|
||||
</head>
|
||||
<script>
|
||||
var xmlHttp = null;
|
||||
|
||||
function pushTheButton(door)
|
||||
@ -67,22 +68,17 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #777;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="remote">
|
||||
<div id="label" class="start"></div>
|
||||
<a href="#" onclick="pushTheButton(1);" class="button button-1">
|
||||
<span>I</span>
|
||||
</a>
|
||||
<a href="#" onclick="pushTheButton(2); " class="button button-2">
|
||||
<span>II</span>
|
||||
</a>
|
||||
<div id="spacer"></div>
|
||||
</div>
|
||||
<body bgcolor="#777777">
|
||||
<div id="remote">
|
||||
<div id="label" class="start"></div>
|
||||
<a href="#" onclick="pushTheButton(1);" class="button button-1">
|
||||
<span>I</span>
|
||||
</a>
|
||||
<a href="#" onclick="pushTheButton(2); " class="button button-2">
|
||||
<span>II</span>
|
||||
</a>
|
||||
<div id="spacer"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@ -1,33 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Served by an ESP8266</title>
|
||||
<style>
|
||||
div{
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<div>
|
||||
<img alt="under construction" src="underconstruction.gif">
|
||||
</div>
|
||||
<p>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Served by an ESP8266</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<div align="center">
|
||||
<img src="underconstruction.gif">
|
||||
</div>
|
||||
<p>
|
||||
This page is served by <b>nodemcu-httpserver</b> running on an ESP8266 that uses the <a href="https://github.com/nodemcu/nodemcu-firmware">NodeMCU</a> firmware.
|
||||
NodeMCU puts a <a href="http://www.lua.org">Lua</a> interpreter inside the ESP8266. This is surely one of the smallest web servers to date!
|
||||
</p>
|
||||
</p>
|
||||
|
||||
<h3>Where's the source code?</h3>
|
||||
<p>You can find the Lua code for nodemcu-httpserver in <a href="https://github.com/marcoskirsch/nodemcu-httpserver">GitHub</a></p>
|
||||
<h3>Where's the source code?</h3>
|
||||
<p>You can find the Lua code for nodemcu-httpserver in <a href="https://github.com/marcoskirsch/nodemcu-httpserver">GitHub</a></p>
|
||||
|
||||
<h3>Serve me some pages!</h3>
|
||||
<ul>
|
||||
<h3>Serve me some pages!</h3>
|
||||
<ul>
|
||||
<li><a href="index.html">Index</a>: This page (static)</li>
|
||||
<li><a href="hello_world.txt">A text file</a>: Simple text, to verify MIME type is ok. (static)</li>
|
||||
<li><a href="cars.html">Nice cars</a>: Stress test, loads several "large" images. Makes the chip panic and restart :( (static)</li>
|
||||
<li><a href="cars.lua">Nice cars</a>: Stress test, loads several "large" images. Makes the chip panic and restart :( (dynamic to change number of cars)</li>
|
||||
<li><a href="counter.html">Count Requests</a>: Stress test, loads the same page over and over, counting every load. (static)</li>
|
||||
<li><a href="zipped.html">Zipped</a>: File is actually saved as zipped.html.gz. A compressed file! (static but gzipped)</li>
|
||||
<li><a href="zipped.html.gz">Zipped</a>: Same exact file as served above. Server is smart enough to treat the .gz extension correctly (static but gzipped)</li>
|
||||
@ -38,6 +32,6 @@
|
||||
<li><a href="file_list.lua">List all server files</a>: Displays a list of all the server files. (Lua)</li>
|
||||
<li><a href="upload.html">Upload</a>: Update, remove, list files on the server. Beware security implications. By <a href="https://github.com/ATAMAH">ATAMAH</a>.</li>
|
||||
<li><a href="foo.html">Foo</a>: A file that doesn't exist. Should error (404 error)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
205
http/upload.css
205
http/upload.css
@ -1,205 +0,0 @@
|
||||
html{
|
||||
background-color:#ebebec;
|
||||
|
||||
background-image:-webkit-radial-gradient(center, #ebebec, #b4b4b4);
|
||||
background-image:-moz-radial-gradient(center, #ebebec, #b4b4b4);
|
||||
background-image:radial-gradient(center, #ebebec, #b4b4b4);
|
||||
}
|
||||
|
||||
body{
|
||||
font:15px/1.3 Arial, sans-serif;
|
||||
color: #4f4f4f;
|
||||
margin:0;
|
||||
padding:0;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
outline:none;
|
||||
color:#389dc1;
|
||||
}
|
||||
|
||||
a:hover{
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
section, footer, header, aside{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropBox {width:100vw; height:100vh; margin-top: -200px; padding-top: 200px;}
|
||||
|
||||
#uploaddir{
|
||||
background-color: #2E3134;
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
color:#7f858a;
|
||||
padding: 40px 50px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
#uploaddir a{
|
||||
background-color:#007a96;
|
||||
padding:12px 26px;
|
||||
color:#fff;
|
||||
font-size:14px;
|
||||
border-radius:2px;
|
||||
cursor:pointer;
|
||||
margin-top:12px;
|
||||
line-height:1;
|
||||
margin-left: 10px;
|
||||
}
|
||||
#selectedDir {
|
||||
margin-top:20px;
|
||||
}
|
||||
#upload{
|
||||
font-family:'PT Sans Narrow', sans-serif;
|
||||
background-color:#373a3d;
|
||||
|
||||
background-image:-webkit-linear-gradient(top, #373a3d, #313437);
|
||||
background-image:-moz-linear-gradient(top, #373a3d, #313437);
|
||||
background-image:linear-gradient(top, #373a3d, #313437);
|
||||
|
||||
width:450px;
|
||||
padding:30px;
|
||||
border-radius:3px;
|
||||
|
||||
margin:10px auto 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
#drop{
|
||||
background-color: #2E3134;
|
||||
padding: 40px 50px;
|
||||
margin-bottom: 30px;
|
||||
border: 20px solid rgba(0, 0, 0, 0);
|
||||
border-radius: 3px;
|
||||
/* no external files */
|
||||
border-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0MUU5RTNGRDk4QjFFMjExODE0NkUyMUJBNERDNDk0NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo0OEZGM0JBREI3RTcxMUUyODFDRkE4MTU1MDRCRkVBRCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0OEZGM0JBQ0I3RTcxMUUyODFDRkE4MTU1MDRCRkVBRCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MUU5RTNGRDk4QjFFMjExODE0NkUyMUJBNERDNDk0NyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MUU5RTNGRDk4QjFFMjExODE0NkUyMUJBNERDNDk0NyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PmuiwCwAAAF7SURBVHja7NpRSsMwAIDhZJbdoNLhdXwSvIBPg11CUBS9h7AnbyYr9hAxfRmIfRDdlqx8P2SwPqwjH01gS7y+uV2GEJ7yWOdxFf5RSikMfb9/H2MMbdeFYzWj+33ksc3jtckvL3ncB5VsfBAe8rhY5JeN+aimzQjSmodqahfmoK6aqYufu93BNsFDfdYc73e5Wv245gmpLCBABASIgAARECACAkRABASI/lRzyp+r9b2pufeEWLIE5Jz2kKm/Ee0rp8lfuJYsAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiILPM2d6COdtryRKQc99DnO0tl7O9liwBASIgQAQEiIAICBABASIgQAQEiIAICBABASIgs8zZ3oI522vJEpBz30Oc7S2Xs72WLAEBIiBABASIgAgIEAEBIiBzrZm6OPWz8G9KKYWh7/fvY4yh7bqjffk53s8TUuGSNZiGahpGkDfzUE3bcQ95zmOZx10enTkp0rgxvefx+CXAAFXjX+IoV9pGAAAAAElFTkSuQmCC') 25 repeat;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
color:#7f858a;
|
||||
}
|
||||
|
||||
#drop a{
|
||||
background-color:#007a96;
|
||||
padding:12px 26px;
|
||||
color:#fff;
|
||||
font-size:14px;
|
||||
border-radius:2px;
|
||||
cursor:pointer;
|
||||
display:block;
|
||||
margin-top:12px;
|
||||
line-height:1;
|
||||
width:100px;
|
||||
margin-left: 75px;
|
||||
}
|
||||
|
||||
#drop a:hover{
|
||||
background-color:#0986a3;
|
||||
}
|
||||
|
||||
#drop input{
|
||||
display:none;
|
||||
}
|
||||
|
||||
#upload ul{
|
||||
list-style:none;
|
||||
margin:0 -30px;
|
||||
border-top:1px solid #2b2e31;
|
||||
border-bottom:1px solid #3d4043;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#upload ul li{
|
||||
|
||||
background-color:#333639;
|
||||
|
||||
background-image:-webkit-linear-gradient(top, #333639, #303335);
|
||||
background-image:-moz-linear-gradient(top, #333639, #303335);
|
||||
background-image:linear-gradient(top, #333639, #303335);
|
||||
|
||||
border-top:1px solid #3d4043;
|
||||
border-bottom:1px solid #2b2e31;
|
||||
padding:15px;
|
||||
height: 52px;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#upload ul li input{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#upload ul li p{
|
||||
width: 300px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
color: #EEE;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#upload ul li i{
|
||||
font-weight: normal;
|
||||
font-style:normal;
|
||||
color:#7f7f7f;
|
||||
display:block;
|
||||
}
|
||||
|
||||
#upload ul li canvas{
|
||||
top: 5px;
|
||||
left: 20px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.delete:after{
|
||||
color: #ff0000;
|
||||
content: "\2718";
|
||||
}
|
||||
|
||||
.uploaded:after{
|
||||
color: #00ff00;
|
||||
content: "\2714";
|
||||
}
|
||||
|
||||
#upload ul li span{
|
||||
width: 15px;
|
||||
height: 12px;
|
||||
cursor:pointer;
|
||||
position: absolute;
|
||||
top: 34px;
|
||||
right: 33px;
|
||||
font-size:18px;
|
||||
}
|
||||
|
||||
#upload ul li.working span{
|
||||
height: 16px;
|
||||
background-position: 0 -12px;
|
||||
}
|
||||
|
||||
#upload ul li.error p{
|
||||
color:red;
|
||||
}
|
||||
|
||||
.chart {
|
||||
position:relative;
|
||||
margin:0px;
|
||||
width:48px; height:48px;
|
||||
}
|
||||
|
||||
.fileInfo {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #7f858a;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
591
http/upload.html
591
http/upload.html
@ -1,31 +1,568 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Upload</title>
|
||||
<link rel="stylesheet" type="text/css" href="upload.css"/>
|
||||
<script src="upload.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="dropbox" class="dropBox">
|
||||
<div id="upload">
|
||||
<div id="uploaddir" class="uploadDir">
|
||||
<a onclick='UploadDir("");'>/</a>
|
||||
<a onclick='UploadDir("http");'>/http</a>
|
||||
<div id="selectedDir">selected Directory: <div id = "dir">bla</div></div></div>
|
||||
<div id="drop">
|
||||
Drop Here
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
html{
|
||||
background-color:#ebebec;
|
||||
|
||||
<a onclick='document.getElementById("browseInput").click();'>Browse</a>
|
||||
<a onclick='UploadFiles();'>Upload</a>
|
||||
<form><input id="browseInput" type="file" name="upl" onclick="this.form.reset();" onchange="handleFiles(this.files);" multiple /></form>
|
||||
</div>
|
||||
background-image:-webkit-radial-gradient(center, #ebebec, #b4b4b4);
|
||||
background-image:-moz-radial-gradient(center, #ebebec, #b4b4b4);
|
||||
background-image:radial-gradient(center, #ebebec, #b4b4b4);
|
||||
}
|
||||
|
||||
<ul id="fileList">
|
||||
</ul>
|
||||
<div class="fileInfo">Files on device:</div>
|
||||
<ul id="fileInfo">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
body{
|
||||
font:15px/1.3 Arial, sans-serif;
|
||||
color: #4f4f4f;
|
||||
margin:0;
|
||||
padding:0;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
outline:none;
|
||||
color:#389dc1;
|
||||
}
|
||||
|
||||
a:hover{
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
section, footer, header, aside{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropBox {width:100vw; height:100vh; margin-top: -200px; padding-top: 200px;}
|
||||
|
||||
#upload{
|
||||
font-family:'PT Sans Narrow', sans-serif;
|
||||
background-color:#373a3d;
|
||||
|
||||
background-image:-webkit-linear-gradient(top, #373a3d, #313437);
|
||||
background-image:-moz-linear-gradient(top, #373a3d, #313437);
|
||||
background-image:linear-gradient(top, #373a3d, #313437);
|
||||
|
||||
width:450px;
|
||||
padding:30px;
|
||||
border-radius:3px;
|
||||
|
||||
margin:10px auto 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
#drop{
|
||||
background-color: #2E3134;
|
||||
padding: 40px 50px;
|
||||
margin-bottom: 30px;
|
||||
border: 20px solid rgba(0, 0, 0, 0);
|
||||
border-radius: 3px;
|
||||
/* no external files */
|
||||
border-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0MUU5RTNGRDk4QjFFMjExODE0NkUyMUJBNERDNDk0NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo0OEZGM0JBREI3RTcxMUUyODFDRkE4MTU1MDRCRkVBRCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0OEZGM0JBQ0I3RTcxMUUyODFDRkE4MTU1MDRCRkVBRCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MUU5RTNGRDk4QjFFMjExODE0NkUyMUJBNERDNDk0NyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MUU5RTNGRDk4QjFFMjExODE0NkUyMUJBNERDNDk0NyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PmuiwCwAAAF7SURBVHja7NpRSsMwAIDhZJbdoNLhdXwSvIBPg11CUBS9h7AnbyYr9hAxfRmIfRDdlqx8P2SwPqwjH01gS7y+uV2GEJ7yWOdxFf5RSikMfb9/H2MMbdeFYzWj+33ksc3jtckvL3ncB5VsfBAe8rhY5JeN+aimzQjSmodqahfmoK6aqYufu93BNsFDfdYc73e5Wv245gmpLCBABASIgAARECACAkRABASI/lRzyp+r9b2pufeEWLIE5Jz2kKm/Ee0rp8lfuJYsAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiILPM2d6COdtryRKQc99DnO0tl7O9liwBASIgQAQEiIAICBABASIgQAQEiIAICBABASIgs8zZ3oI522vJEpBz30Oc7S2Xs72WLAEBIiBABASIgAgIEAEBIiBzrZm6OPWz8G9KKYWh7/fvY4yh7bqjffk53s8TUuGSNZiGahpGkDfzUE3bcQ95zmOZx10enTkp0rgxvefx+CXAAFXjX+IoV9pGAAAAAElFTkSuQmCC') 25 repeat;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
color:#7f858a;
|
||||
}
|
||||
|
||||
#drop a{
|
||||
background-color:#007a96;
|
||||
padding:12px 26px;
|
||||
color:#fff;
|
||||
font-size:14px;
|
||||
border-radius:2px;
|
||||
cursor:pointer;
|
||||
display:block;
|
||||
margin-top:12px;
|
||||
line-height:1;
|
||||
width:100px;
|
||||
margin-left: 75px;
|
||||
}
|
||||
|
||||
#drop a:hover{
|
||||
background-color:#0986a3;
|
||||
}
|
||||
|
||||
#drop input{
|
||||
display:none;
|
||||
}
|
||||
|
||||
#upload ul{
|
||||
list-style:none;
|
||||
margin:0 -30px;
|
||||
border-top:1px solid #2b2e31;
|
||||
border-bottom:1px solid #3d4043;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#upload ul li{
|
||||
|
||||
background-color:#333639;
|
||||
|
||||
background-image:-webkit-linear-gradient(top, #333639, #303335);
|
||||
background-image:-moz-linear-gradient(top, #333639, #303335);
|
||||
background-image:linear-gradient(top, #333639, #303335);
|
||||
|
||||
border-top:1px solid #3d4043;
|
||||
border-bottom:1px solid #2b2e31;
|
||||
padding:15px;
|
||||
height: 52px;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#upload ul li input{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#upload ul li p{
|
||||
width: 300px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
color: #EEE;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#upload ul li i{
|
||||
font-weight: normal;
|
||||
font-style:normal;
|
||||
color:#7f7f7f;
|
||||
display:block;
|
||||
}
|
||||
|
||||
#upload ul li canvas{
|
||||
top: 5px;
|
||||
left: 20px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#upload ul li span{
|
||||
width: 15px;
|
||||
height: 12px;
|
||||
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAaCAYAAABozQZiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFQUY1MzY0QUU3QjdFMjExODE0NkUyMUJBNERDNDk0NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCOTc5MTBDQ0I3RUYxMUUyOUVBQkNFOURERDIzQkU4NSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCOTc5MTBDQkI3RUYxMUUyOUVBQkNFOURERDIzQkU4NSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFQUY1MzY0QUU3QjdFMjExODE0NkUyMUJBNERDNDk0NyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFQUY1MzY0QUU3QjdFMjExODE0NkUyMUJBNERDNDk0NyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvX6SiYAAAGjSURBVHjanJRPRMRREMfbNtE19hQlolNdomsRaZUiIlHKdiml7CpFolU6pEOWTUTRJZKIakmHsqQ99UedOiT2lG6xRPSdzFtjGi+/ho99836/78z8Zt7bUN3VfElAKwcRkC/9h/AAPIKmsgDCMNgB3ezvB8m8BQZ4/QkmSVwJbsCcR7gOYrz+Av0gQ2WfgWaGvimphEsgLvwRcEQLypxVLy4KP678cbDnHMqc4GZMiQBU2huX62wWbMqSXLenWeDKW1alr4A13QjZ7YT1AmwDLFhd1KOi0naFf8lVmWYdklHuQTXo8g3eOiT07UOgFXy4zcPB2wpTjAdpcA8iVgbs0yTe8dsi90N3NdEUfifYfwBtPCZn9CzF6wJXlGt8Of3JXCVebAAXfOXIxoTQfVJYlk3n9NgIQGc9LfYpaxRcSzHdkD4jwKoStqujXOy2FUBnzPpGRQHODfErePprzjHVHGf1qom/xCTcVlXkPFMoiocNYQ/PM+MLQOIZJexlUUGsZYBOKaYRPAvhieq0DJCUt45uVZ5LrLXGIQJ0uP8uZ98CDADM9WkEBoK0xwAAAABJRU5ErkJggg==') no-repeat;
|
||||
position: absolute;
|
||||
top: 34px;
|
||||
right: 33px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#upload ul li.working span{
|
||||
height: 16px;
|
||||
background-position: 0 -12px;
|
||||
}
|
||||
|
||||
#upload ul li.error p{
|
||||
color:red;
|
||||
}
|
||||
|
||||
.chart {
|
||||
position:relative;
|
||||
margin:0px;
|
||||
width:48px; height:48px;
|
||||
}
|
||||
|
||||
.fileInfo {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #7f858a;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var files = [];
|
||||
var sendingOffset = 0;
|
||||
var lastRequest = '';
|
||||
var dataView;
|
||||
var filesCount = 0;
|
||||
var currentUploadingFile = 0;
|
||||
var uploadOrder = [];
|
||||
var uploadingInProgress = 0;
|
||||
var fileUploadRequest;
|
||||
|
||||
var chunkSize = 128;
|
||||
var totalUploaded = 0;
|
||||
|
||||
var tpl = '<li class="working" id="file%filenum%"><div class="chart" id="graph%filenum%" data-percent="0"></div><p>%filename%<i>%filesize%</i></p><span id="fileStatus%filenum%" onclick="DeleteFiles(%filenum%);"></span></li>';
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var dropbox;
|
||||
|
||||
dropbox = document.getElementById("dropbox");
|
||||
dropbox.addEventListener("dragenter", dragenter, false);
|
||||
dropbox.addEventListener("dragover", dragover, false);
|
||||
dropbox.addEventListener("drop", drop, false);
|
||||
|
||||
UpdateFileList();
|
||||
});
|
||||
|
||||
function dragenter(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function dragover(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function drop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
var dt = e.dataTransfer;
|
||||
|
||||
handleFiles(dt.files);
|
||||
}
|
||||
|
||||
function handleFiles(tfiles) {
|
||||
var filesCount = tfiles.length;
|
||||
files = tfiles;
|
||||
currentUploadingFile = 0;
|
||||
uploadOrder = [];
|
||||
|
||||
sendingOffset = 0;
|
||||
lastRequest = '';
|
||||
|
||||
document.getElementById('fileList').innerHTML = '';
|
||||
|
||||
var fileNames = {};
|
||||
|
||||
for (var i = 0; i < filesCount; i++) {
|
||||
fileNames[tfiles[i].name] = i;
|
||||
}
|
||||
|
||||
Keys(fileNames).sort(function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c<d?-1:c>d?1:0}).forEach(function(item) {
|
||||
var i = fileNames[item];
|
||||
|
||||
var append = tpl.replace(/%filename%/g, tfiles[i].name);
|
||||
append = append.replace(/%filesize%/g, formatFileSize(tfiles[i].size));
|
||||
append = append.replace(/%filenum%/g, i);
|
||||
|
||||
document.getElementById('fileList').insertAdjacentHTML('beforeend', append);
|
||||
|
||||
UpdateGraph(0, i);
|
||||
|
||||
uploadOrder.push(i);
|
||||
});
|
||||
}
|
||||
|
||||
function DeleteFiles(filenum) {
|
||||
var elem = document.getElementById('file' + filenum.toString());
|
||||
elem.parentNode.removeChild(elem);
|
||||
|
||||
if (uploadingInProgress) {
|
||||
if (parseInt(filenum) != uploadOrder[currentUploadingFile]) {
|
||||
for (var i = 0; i < uploadOrder.length; i++) {
|
||||
if (uploadOrder[i] == filenum) {
|
||||
delete uploadOrder[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uploadingInProgress = 0;
|
||||
|
||||
RemoveFile(files[uploadOrder[currentUploadingFile]].name + '.dnl');
|
||||
|
||||
for (var i = 0; i < uploadOrder.length; i++) {
|
||||
if (uploadOrder[i] == filenum) {
|
||||
delete uploadOrder[i];
|
||||
}
|
||||
}
|
||||
|
||||
currentUploadingFile++;
|
||||
totalUploaded = 0;
|
||||
sendingOffset = 0;
|
||||
|
||||
lastRequest = '';
|
||||
fileUploadRequest.abort();
|
||||
fileUploadRequest = 0;
|
||||
|
||||
UploadFiles();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < uploadOrder.length; i++) {
|
||||
if (uploadOrder[i] == filenum) {
|
||||
delete uploadOrder[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UploadFiles() {
|
||||
if (uploadOrder[currentUploadingFile] === undefined) {
|
||||
uploadingInProgress = 0;
|
||||
|
||||
if (currentUploadingFile < files.length - 1) {
|
||||
currentUploadingFile++;
|
||||
|
||||
UploadFiles();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var fileNum = uploadOrder[currentUploadingFile];
|
||||
var file = files[fileNum];
|
||||
var chunkLen = 0;
|
||||
var filedata = '';
|
||||
|
||||
uploadingInProgress = 1;
|
||||
|
||||
var fr = new FileReader();
|
||||
|
||||
fr.onload = function() {
|
||||
dataView = null;
|
||||
dataView = new Uint8Array(fr.result);
|
||||
|
||||
if (file.size <= chunkSize) {
|
||||
sendingOffset = 0;
|
||||
chunkLen = file.size;
|
||||
|
||||
for (var i = 0; i < dataView.length; i++) {
|
||||
if (dataView[i] < 16) {
|
||||
filedata += '0';
|
||||
}
|
||||
|
||||
filedata += dataView[i].toString(16).toUpperCase();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dataView.length - sendingOffset > chunkSize) {
|
||||
chunkLen = chunkSize;
|
||||
}
|
||||
else {
|
||||
chunkLen = dataView.length - sendingOffset;
|
||||
}
|
||||
|
||||
|
||||
for (var i = sendingOffset; i < sendingOffset + chunkLen; i++) {
|
||||
if (dataView[i] < 16) {
|
||||
filedata += '0';
|
||||
}
|
||||
|
||||
filedata += dataView[i].toString(16).toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
fileUploadRequest = new XMLHttpRequest();
|
||||
|
||||
fileUploadRequest.onreadystatechange = function() {
|
||||
if (fileUploadRequest.readyState != 4) return;
|
||||
|
||||
if (fileUploadRequest.status == 200) {
|
||||
if (chunkLen + sendingOffset < dataView.length) {
|
||||
totalUploaded += chunkSize;
|
||||
|
||||
UpdateGraph(Math.round((totalUploaded / file.size) * 100), uploadOrder[currentUploadingFile]);
|
||||
|
||||
sendingOffset += chunkSize;
|
||||
UploadFiles();
|
||||
}
|
||||
else {
|
||||
var statusElement = document.getElementById('fileStatus' + uploadOrder[currentUploadingFile]);
|
||||
|
||||
sendingOffset = 0;
|
||||
|
||||
UpdateGraph(100, uploadOrder[currentUploadingFile]);
|
||||
|
||||
uploadingInProgress = 0;
|
||||
|
||||
UpdateFileList();
|
||||
|
||||
totalUploaded = 0;
|
||||
|
||||
if (statusElement) {
|
||||
statusElement.style["background-position"] = "0 3px";
|
||||
}
|
||||
|
||||
if (currentUploadingFile < files.length) {
|
||||
currentUploadingFile++;
|
||||
UploadFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
UploadFiles();
|
||||
}
|
||||
|
||||
fileUploadRequest = 0;
|
||||
}
|
||||
|
||||
lastRequest = 'upload.lua?cmd=upload&filename=' + file.name + '&filesize=' + file.size + '&len=' + chunkLen + '&offset=' + sendingOffset + '&data=' + filedata;
|
||||
|
||||
fileUploadRequest.timeout = 5000;
|
||||
fileUploadRequest.open('GET', lastRequest, true);
|
||||
fileUploadRequest.send();
|
||||
};
|
||||
|
||||
fr.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function formatFileSize(bytes) {
|
||||
if (typeof bytes !== 'number') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (bytes >= 1073741824) {
|
||||
return (bytes / 1073741824).toFixed(2) + ' GB';
|
||||
}
|
||||
|
||||
if (bytes >= 1048576) {
|
||||
return (bytes / 1048576).toFixed(2) + ' MB';
|
||||
}
|
||||
|
||||
return (bytes / 1024).toFixed(2) + ' KB';
|
||||
}
|
||||
|
||||
function UpdateGraph(percent, id) {
|
||||
var el = document.getElementById('graph' + id); // get canvas
|
||||
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = {
|
||||
percent: el.getAttribute('data-percent') || 0,
|
||||
size: el.getAttribute('data-size') || 48,
|
||||
lineWidth: el.getAttribute('data-line') || 8,
|
||||
rotate: el.getAttribute('data-rotate') || 0
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
|
||||
if (typeof(G_vmlCanvasManager) !== 'undefined') {
|
||||
G_vmlCanvasManager.initElement(canvas);
|
||||
}
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
canvas.width = canvas.height = options.size;
|
||||
|
||||
el.appendChild(canvas);
|
||||
|
||||
ctx.translate(options.size / 2, options.size / 2); // change center
|
||||
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
|
||||
|
||||
var radius = (options.size - options.lineWidth) / 2;
|
||||
|
||||
function drawCircle(color, lineWidth, percent) {
|
||||
if (percent) {
|
||||
percent = Math.min(Math.max(0, percent), 1);
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineCap = 'round'; // butt, round or square
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
options.percent = percent;
|
||||
|
||||
drawCircle('#2e3134', options.lineWidth + 1, 100 / 100);
|
||||
drawCircle('#007a96', options.lineWidth, options.percent / 100);
|
||||
}
|
||||
|
||||
function Keys(obj) {
|
||||
var keys = [];
|
||||
|
||||
for(var key in obj){
|
||||
if(obj.hasOwnProperty(key)){
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
function UpdateFileList() {
|
||||
var fileListRequest = new XMLHttpRequest();
|
||||
|
||||
fileListRequest.onreadystatechange = function() {
|
||||
if (fileListRequest.readyState != 4) return;
|
||||
|
||||
if (fileListRequest.status == 200) {
|
||||
var fileInfo = JSON.parse(fileListRequest.responseText);
|
||||
var fileList = fileInfo['files'];
|
||||
|
||||
document.getElementById('fileInfo').innerHTML = '';
|
||||
|
||||
var tpl = '<li class="working"><p style="left: 30px;">%filenamelink%<i>%filesize%</i></p><span id="fileStatus" onclick="RemoveFile(\'%filename%\');"></span></li>';
|
||||
var tplTotal = '<li class="working"><p style="left: 30px;">Used:<i>%used%</i></p></li><li class="working"><p style="left: 30px;">Free:<i>%free%</i></p></li><li class="working"><p style="left: 30px;">Total:<i>%total%</i></p></li>';
|
||||
|
||||
var append, link;
|
||||
|
||||
Keys(fileList).sort(function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c<d?-1:c>d?1:0}).forEach(function(item) {
|
||||
if (!(item.match(/\.lc$/ig))) {
|
||||
link = item.replace(/\.gz$/g, '');
|
||||
append = tpl.replace(/%filenamelink%/g, '<a href="' + link + '" target="_blank">' + item + '</a>');
|
||||
}
|
||||
else {
|
||||
append = tpl.replace(/%filenamelink%/g, item);
|
||||
}
|
||||
|
||||
append = append.replace(/%filename%/g, item);
|
||||
append = append.replace(/%filesize%/g, formatFileSize(parseInt(fileList[item])));
|
||||
document.getElementById('fileInfo').insertAdjacentHTML('beforeend', append);
|
||||
});
|
||||
|
||||
append = tplTotal.replace(/%used%/g, formatFileSize(parseInt(fileInfo['used'])));
|
||||
append = append.replace(/%free%/g, formatFileSize(parseInt(fileInfo['free'])));
|
||||
append = append.replace(/%total%/g, formatFileSize(parseInt(fileInfo['total'])));
|
||||
|
||||
document.getElementById('fileInfo').insertAdjacentHTML('beforeend', append);
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
|
||||
fileListRequest = null;
|
||||
}
|
||||
|
||||
fileListRequest.open('GET', 'upload.lua?cmd=list', true);
|
||||
fileListRequest.send();
|
||||
}
|
||||
|
||||
function RemoveFile(name) {
|
||||
var fileRemoveRequest = new XMLHttpRequest();
|
||||
|
||||
fileRemoveRequest.onreadystatechange = function() {
|
||||
if (fileRemoveRequest.readyState != 4) return;
|
||||
|
||||
if (fileRemoveRequest.status == 200) {
|
||||
UpdateFileList();
|
||||
}
|
||||
}
|
||||
|
||||
fileRemoveRequest.open('GET', 'upload.lua?cmd=remove&filename=' + name, true);
|
||||
fileRemoveRequest.send();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="dropbox" class="dropBox">
|
||||
<div id="upload">
|
||||
<div id="drop">
|
||||
Drop Here
|
||||
|
||||
<a onclick='document.getElementById("browseInput").click();'>Browse</a>
|
||||
<a onclick='UploadFiles();'>Upload</a>
|
||||
<input id="browseInput" type="file" name="upl" onchange="handleFiles(this.files);" multiple />
|
||||
</div>
|
||||
|
||||
<ul id="fileList">
|
||||
</ul>
|
||||
<div class="fileInfo">Files on device:</div>
|
||||
<ul id="fileInfo">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
380
http/upload.js
380
http/upload.js
@ -1,380 +0,0 @@
|
||||
var files = [];
|
||||
var sendingOffset = 0;
|
||||
var lastRequest = '';
|
||||
var dataView;
|
||||
var filesCount = 0;
|
||||
var currentUploadingFile = 0;
|
||||
var uploadOrder = [];
|
||||
var uploadingInProgress = 0;
|
||||
var fileUploadRequest;
|
||||
|
||||
var chunkSize = 128;
|
||||
var totalUploaded = 0;
|
||||
|
||||
var tpl = '<li class="working" id="file%filenum%"><div class="chart" id="graph%filenum%" data-percent="0"></div><p>%filename%<i>%filesize%</i></p><span class="delete" id="fileStatus%filenum%" onclick="DeleteFiles(%filenum%);"></span></li>';
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var dropbox;
|
||||
|
||||
dropbox = document.getElementById("dropbox");
|
||||
dropbox.addEventListener("dragenter", dragenter, false);
|
||||
dropbox.addEventListener("dragover", dragover, false);
|
||||
dropbox.addEventListener("drop", drop, false);
|
||||
|
||||
UpdateFileList();
|
||||
|
||||
UploadDir("http");
|
||||
});
|
||||
|
||||
function dragenter(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function dragover(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function drop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
var dt = e.dataTransfer;
|
||||
|
||||
handleFiles(dt.files);
|
||||
}
|
||||
|
||||
function handleFiles(tfiles) {
|
||||
var filesCount = tfiles.length;
|
||||
files = tfiles;
|
||||
currentUploadingFile = 0;
|
||||
uploadOrder = [];
|
||||
|
||||
sendingOffset = 0;
|
||||
lastRequest = '';
|
||||
|
||||
document.getElementById('fileList').innerHTML = '';
|
||||
|
||||
var fileNames = {};
|
||||
|
||||
for (var i = 0; i < filesCount; i++) {
|
||||
fileNames[uploadDir + tfiles[i].name] = i;
|
||||
}
|
||||
|
||||
Keys(fileNames).sort(function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c<d?-1:c>d?1:0}).forEach(function(item) {
|
||||
var i = fileNames[item];
|
||||
|
||||
var append = tpl.replace(/%filename%/g, uploadDir + tfiles[i].name);
|
||||
append = append.replace(/%filesize%/g, formatFileSize(tfiles[i].size));
|
||||
append = append.replace(/%filenum%/g, i);
|
||||
|
||||
document.getElementById('fileList').insertAdjacentHTML('beforeend', append);
|
||||
|
||||
UpdateGraph(0, i);
|
||||
|
||||
uploadOrder.push(i);
|
||||
});
|
||||
}
|
||||
|
||||
function DeleteFiles(filenum) {
|
||||
var elem = document.getElementById('file' + filenum.toString());
|
||||
elem.parentNode.removeChild(elem);
|
||||
|
||||
if (uploadingInProgress) {
|
||||
if (parseInt(filenum) != uploadOrder[currentUploadingFile]) {
|
||||
for (var i = 0; i < uploadOrder.length; i++) {
|
||||
if (uploadOrder[i] == filenum) {
|
||||
delete uploadOrder[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uploadingInProgress = 0;
|
||||
|
||||
RemoveFile(files[uploadOrder[currentUploadingFile]].name + '.dnl');
|
||||
|
||||
for (var i = 0; i < uploadOrder.length; i++) {
|
||||
if (uploadOrder[i] == filenum) {
|
||||
delete uploadOrder[i];
|
||||
}
|
||||
}
|
||||
|
||||
currentUploadingFile++;
|
||||
totalUploaded = 0;
|
||||
sendingOffset = 0;
|
||||
|
||||
lastRequest = '';
|
||||
fileUploadRequest.abort();
|
||||
fileUploadRequest = 0;
|
||||
|
||||
UploadFiles();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < uploadOrder.length; i++) {
|
||||
if (uploadOrder[i] == filenum) {
|
||||
delete uploadOrder[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UploadFiles() {
|
||||
if (uploadOrder[currentUploadingFile] === undefined) {
|
||||
uploadingInProgress = 0;
|
||||
|
||||
if (currentUploadingFile < files.length - 1) {
|
||||
currentUploadingFile++;
|
||||
|
||||
UploadFiles();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var fileNum = uploadOrder[currentUploadingFile];
|
||||
var file = files[fileNum];
|
||||
var chunkLen = 0;
|
||||
var filedata = '';
|
||||
|
||||
uploadingInProgress = 1;
|
||||
|
||||
var fr = new FileReader();
|
||||
|
||||
fr.onload = function() {
|
||||
dataView = null;
|
||||
dataView = new Uint8Array(fr.result);
|
||||
|
||||
if (file.size <= chunkSize) {
|
||||
sendingOffset = 0;
|
||||
chunkLen = file.size;
|
||||
|
||||
for (var i = 0; i < dataView.length; i++) {
|
||||
if (dataView[i] < 16) {
|
||||
filedata += '0';
|
||||
}
|
||||
|
||||
filedata += dataView[i].toString(16).toUpperCase();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dataView.length - sendingOffset > chunkSize) {
|
||||
chunkLen = chunkSize;
|
||||
}
|
||||
else {
|
||||
chunkLen = dataView.length - sendingOffset;
|
||||
}
|
||||
|
||||
|
||||
for (var i = sendingOffset; i < sendingOffset + chunkLen; i++) {
|
||||
if (dataView[i] < 16) {
|
||||
filedata += '0';
|
||||
}
|
||||
|
||||
filedata += dataView[i].toString(16).toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
fileUploadRequest = new XMLHttpRequest();
|
||||
|
||||
fileUploadRequest.onreadystatechange = function() {
|
||||
if (fileUploadRequest.readyState != 4) return;
|
||||
|
||||
if (fileUploadRequest.status == 200) {
|
||||
if (chunkLen + sendingOffset < dataView.length) {
|
||||
totalUploaded += chunkSize;
|
||||
|
||||
UpdateGraph(Math.round((totalUploaded / file.size) * 100), uploadOrder[currentUploadingFile]);
|
||||
|
||||
sendingOffset += chunkSize;
|
||||
UploadFiles();
|
||||
}
|
||||
else {
|
||||
var statusElement = document.getElementById('fileStatus' + uploadOrder[currentUploadingFile]);
|
||||
|
||||
sendingOffset = 0;
|
||||
|
||||
UpdateGraph(100, uploadOrder[currentUploadingFile]);
|
||||
|
||||
uploadingInProgress = 0;
|
||||
|
||||
UpdateFileList();
|
||||
|
||||
totalUploaded = 0;
|
||||
|
||||
if (statusElement) {
|
||||
statusElement.classList.add("uploaded");
|
||||
}
|
||||
|
||||
if (currentUploadingFile < files.length) {
|
||||
currentUploadingFile++;
|
||||
UploadFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
UploadFiles();
|
||||
}
|
||||
|
||||
fileUploadRequest = 0;
|
||||
}
|
||||
|
||||
lastRequest = 'upload.lua?cmd=upload&filename=' + uploadDir + file.name + '&filesize=' + file.size + '&len=' + chunkLen + '&offset=' + sendingOffset + '&data=' + filedata;
|
||||
|
||||
fileUploadRequest.timeout = 5000;
|
||||
fileUploadRequest.open('GET', lastRequest, true);
|
||||
fileUploadRequest.send();
|
||||
};
|
||||
|
||||
fr.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function UploadDir(dir) {
|
||||
if (uploadingInProgress == 0) {
|
||||
document.getElementById('dir').innerHTML = "/" + dir;
|
||||
uploadDir = dir;
|
||||
if (!(uploadDir == "")) {
|
||||
uploadDir += "/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatFileSize(bytes) {
|
||||
if (typeof bytes !== 'number') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (bytes >= 1073741824) {
|
||||
return (bytes / 1073741824).toFixed(2) + ' GB';
|
||||
}
|
||||
|
||||
if (bytes >= 1048576) {
|
||||
return (bytes / 1048576).toFixed(2) + ' MB';
|
||||
}
|
||||
|
||||
return (bytes / 1024).toFixed(2) + ' KB';
|
||||
}
|
||||
|
||||
function UpdateGraph(percent, id) {
|
||||
var el = document.getElementById('graph' + id); // get canvas
|
||||
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = {
|
||||
percent: el.getAttribute('data-percent') || 0,
|
||||
size: el.getAttribute('data-size') || 48,
|
||||
lineWidth: el.getAttribute('data-line') || 8,
|
||||
rotate: el.getAttribute('data-rotate') || 0
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
|
||||
if (typeof(G_vmlCanvasManager) !== 'undefined') {
|
||||
G_vmlCanvasManager.initElement(canvas);
|
||||
}
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
canvas.width = canvas.height = options.size;
|
||||
|
||||
el.appendChild(canvas);
|
||||
|
||||
ctx.translate(options.size / 2, options.size / 2); // change center
|
||||
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
|
||||
|
||||
var radius = (options.size - options.lineWidth) / 2;
|
||||
|
||||
function drawCircle(color, lineWidth, percent) {
|
||||
if (percent) {
|
||||
percent = Math.min(Math.max(0, percent), 1);
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineCap = 'round'; // butt, round or square
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
options.percent = percent;
|
||||
|
||||
drawCircle('#2e3134', options.lineWidth + 1, 100 / 100);
|
||||
drawCircle('#007a96', options.lineWidth, options.percent / 100);
|
||||
}
|
||||
|
||||
function Keys(obj) {
|
||||
var keys = [];
|
||||
|
||||
for(var key in obj){
|
||||
if(obj.hasOwnProperty(key)){
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
function UpdateFileList() {
|
||||
var fileListRequest = new XMLHttpRequest();
|
||||
|
||||
fileListRequest.onreadystatechange = function() {
|
||||
if (fileListRequest.readyState != 4) return;
|
||||
|
||||
if (fileListRequest.status == 200) {
|
||||
var fileInfo = JSON.parse(fileListRequest.responseText);
|
||||
var fileList = fileInfo['files'];
|
||||
|
||||
document.getElementById('fileInfo').innerHTML = '';
|
||||
|
||||
var tpl = '<li class="working"><p style="left: 30px;">%filenamelink%<i>%filesize%</i></p><span class="delete" id="fileStatus" onclick="RemoveFile(\'%filename%\');"></span></li>';
|
||||
var tplTotal = '<li class="working"><p style="left: 30px;">Used:<i>%used%</i></p></li><li class="working"><p style="left: 30px;">Free:<i>%free%</i></p></li><li class="working"><p style="left: 30px;">Total:<i>%total%</i></p></li>';
|
||||
|
||||
var append, link;
|
||||
|
||||
Keys(fileList).sort(function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c<d?-1:c>d?1:0}).forEach(function(item) {
|
||||
if (!item.match(/\.lc$/ig) && item.match(/^http\//ig)) {
|
||||
link = item.replace(/\.gz$/g, '').replace(/^http\//g, '');
|
||||
append = tpl.replace(/%filenamelink%/g, '<a href="' + link + '" target="_blank">' + item + '</a>');
|
||||
}
|
||||
else {
|
||||
append = tpl.replace(/%filenamelink%/g, item);
|
||||
}
|
||||
|
||||
append = append.replace(/%filename%/g, item);
|
||||
append = append.replace(/%filesize%/g, formatFileSize(parseInt(fileList[item])));
|
||||
document.getElementById('fileInfo').insertAdjacentHTML('beforeend', append);
|
||||
});
|
||||
|
||||
append = tplTotal.replace(/%used%/g, formatFileSize(parseInt(fileInfo['used'])));
|
||||
append = append.replace(/%free%/g, formatFileSize(parseInt(fileInfo['free'])));
|
||||
append = append.replace(/%total%/g, formatFileSize(parseInt(fileInfo['total'])));
|
||||
|
||||
document.getElementById('fileInfo').insertAdjacentHTML('beforeend', append);
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
|
||||
fileListRequest = null;
|
||||
}
|
||||
|
||||
fileListRequest.open('GET', 'upload.lua?cmd=list', true);
|
||||
fileListRequest.send();
|
||||
}
|
||||
|
||||
function RemoveFile(name) {
|
||||
var fileRemoveRequest = new XMLHttpRequest();
|
||||
|
||||
fileRemoveRequest.onreadystatechange = function() {
|
||||
if (fileRemoveRequest.readyState != 4) return;
|
||||
|
||||
if (fileRemoveRequest.status == 200) {
|
||||
UpdateFileList();
|
||||
}
|
||||
}
|
||||
|
||||
fileRemoveRequest.open('GET', 'upload.lua?cmd=remove&filename=' + name, true);
|
||||
fileRemoveRequest.send();
|
||||
}
|
||||
@ -48,22 +48,23 @@ return function (connection, req, args)
|
||||
|
||||
if (mbCmd == 'upload') then
|
||||
if (fieldsCount > 5) then
|
||||
if (mbFilename ~= 'http/upload.lua') then
|
||||
if (mbFilename ~= 'upload.lua') then
|
||||
connection:send('"offset":"' .. mbOffset .. '",')
|
||||
connection:send('"len":"' .. mbLen .. '",')
|
||||
connection:send('"filename":"' .. mbFilename .. '"')
|
||||
|
||||
|
||||
mbFilename = 'http/' .. mbFilename
|
||||
|
||||
for i=1,string.len(mbData),2 do
|
||||
currentByte = tonumber(string.sub(mbData, i, i + 1), 16)
|
||||
binaryData = binaryData .. string.char(currentByte)
|
||||
end
|
||||
|
||||
local mbTmpFilename = string.sub(mbFilename, 0, 27) .. '.dnl'
|
||||
|
||||
if (mbOffset > 0) then
|
||||
file.open(mbTmpFilename,'a+')
|
||||
file.open(mbFilename .. '.dnl','a+')
|
||||
else
|
||||
file.remove(mbTmpFilename)
|
||||
file.open(mbTmpFilename,'w+')
|
||||
file.remove(mbFilename .. '.dnl')
|
||||
file.open(mbFilename .. '.dnl','w+')
|
||||
end
|
||||
file.seek("set", mbOffset)
|
||||
file.write(binaryData)
|
||||
@ -73,9 +74,9 @@ return function (connection, req, args)
|
||||
|
||||
if (fileSize == mbLen + mbOffset) then
|
||||
file.remove(mbFilename)
|
||||
file.rename(mbTmpFilename, mbFilename)
|
||||
file.remove(mbTmpFilename)
|
||||
|
||||
file.rename(mbFilename .. '.dnl', mbFilename)
|
||||
file.remove(mbFilename .. '.dnl')
|
||||
|
||||
if (string.sub(mbFilename, -4) == '.lua') then
|
||||
file.remove(string.sub(mbFilename, 0, -3) .. "lc")
|
||||
node.compile(mbFilename)
|
||||
@ -88,34 +89,39 @@ return function (connection, req, args)
|
||||
local remaining, used, total=file.fsinfo()
|
||||
|
||||
local headerExist = 0
|
||||
|
||||
|
||||
connection:send('"files":{')
|
||||
|
||||
|
||||
for name, size in pairs(file.list()) do
|
||||
if (headerExist > 0) then
|
||||
connection:send(',')
|
||||
end
|
||||
|
||||
local url = string.match(name, ".*/(.*)")
|
||||
url = name
|
||||
connection:send('"' .. url .. '":"' .. size .. '"')
|
||||
|
||||
headerExist = 1
|
||||
local isHttpFile = string.match(name, "(http/)") ~= nil
|
||||
|
||||
if isHttpFile then
|
||||
if (headerExist > 0) then
|
||||
connection:send(',')
|
||||
end
|
||||
|
||||
local url = string.match(name, ".*/(.*)")
|
||||
|
||||
connection:send('"' .. url .. '":"' .. size .. '"')
|
||||
|
||||
headerExist = 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
connection:send('},')
|
||||
|
||||
|
||||
connection:send('"total":"' .. total .. '",')
|
||||
connection:send('"used":"' .. used .. '",')
|
||||
connection:send('"free":"' .. remaining .. '"')
|
||||
elseif (mbCmd == 'remove') then
|
||||
if (fieldsCount > 1) then
|
||||
if (mbFilename ~= 'http/upload.lua') and (mbFilename ~= 'http/upload.lc') and (mbFilename ~= 'http/upload.html.gz') then
|
||||
file.remove(mbFilename)
|
||||
if (mbFilename ~= 'upload.lua') and (mbFilename ~= 'upload.lc') and (mbFilename ~= 'upload.html.gz') then
|
||||
file.remove('http/' .. mbFilename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
connection:send('}')
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
|
||||
4
srv/httpserver-b64decode.lua → httpserver-b64decode.lua
Normal file → Executable file
4
srv/httpserver-b64decode.lua → httpserver-b64decode.lua
Normal file → Executable file
@ -37,14 +37,14 @@ end
|
||||
|
||||
-- logic OR for number values
|
||||
local function lor(x,y)
|
||||
local result = 0
|
||||
result = 0
|
||||
for p=1,8 do result = result + (((bit(x,p) or bit(y,p)) == true) and uipow(2, (p-1)) or 0) end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Character decoding table
|
||||
local function toBase64Byte(char)
|
||||
local ascii = string.byte(char, 1)
|
||||
ascii = string.byte(char, 1)
|
||||
if ascii >= string.byte('A', 1) and ascii <= string.byte('Z', 1) then return ascii - string.byte('A', 1)
|
||||
elseif ascii >= string.byte('a', 1) and ascii <= string.byte('z', 1) then return ascii - string.byte('a', 1) + 26
|
||||
elseif ascii >= string.byte('0', 1) and ascii <= string.byte('9', 1) then return ascii + 4
|
||||
@ -2,7 +2,7 @@
|
||||
-- Part of nodemcu-httpserver, authenticates a user using http basic auth.
|
||||
-- Author: Sam Dieck
|
||||
|
||||
local basicAuth = {}
|
||||
basicAuth = {}
|
||||
|
||||
-- Returns true if the user/password match one of the users/passwords in httpserver-conf.lua.
|
||||
-- Returns false otherwise.
|
||||
@ -18,7 +18,7 @@ end
|
||||
-- Returns the username if header contains valid credentials,
|
||||
-- nil otherwise.
|
||||
function basicAuth.authenticate(header)
|
||||
local conf = dofile("httpserver-conf.lua")
|
||||
local conf = dofile("httpserver-conf.lc")
|
||||
local credentials_enc = header:match("Authorization: Basic ([A-Za-z0-9+/=]+)")
|
||||
if not credentials_enc then
|
||||
return nil
|
||||
@ -35,7 +35,7 @@ function basicAuth.authenticate(header)
|
||||
end
|
||||
|
||||
function basicAuth.authErrorHeader()
|
||||
local conf = dofile("httpserver-conf.lua")
|
||||
local conf = dofile("httpserver-conf.lc")
|
||||
return "WWW-Authenticate: Basic realm=\"" .. conf.auth.realm .. "\""
|
||||
end
|
||||
|
||||
@ -4,37 +4,30 @@
|
||||
|
||||
local compileAndRemoveIfNeeded = function(f)
|
||||
if file.exists(f) then
|
||||
local newf = f:gsub("%w+/", "")
|
||||
file.rename(f, newf)
|
||||
print('Compiling:', newf)
|
||||
node.compile(newf)
|
||||
file.remove(newf)
|
||||
print('Compiling:', f)
|
||||
node.compile(f)
|
||||
file.remove(f)
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
|
||||
local serverFiles = {
|
||||
'srv/httpserver.lua',
|
||||
'srv/httpserver-b64decode.lua',
|
||||
'srv/httpserver-basicauth.lua',
|
||||
'srv/httpserver-buffer.lua',
|
||||
'srv/httpserver-connection.lua',
|
||||
'srv/httpserver-error.lua',
|
||||
'srv/httpserver-header.lua',
|
||||
'srv/httpserver-init.lua',
|
||||
'srv/httpserver-request.lua',
|
||||
'srv/httpserver-static.lua',
|
||||
'srv/httpserver-wifi.lua',
|
||||
}
|
||||
|
||||
local lfsFiles = {
|
||||
'srv/_init.lua',
|
||||
'srv/dummy_strings.lua',
|
||||
'httpserver.lua',
|
||||
'httpserver-b64decode.lua',
|
||||
'httpserver-basicauth.lua',
|
||||
'httpserver-compile.lua',
|
||||
'httpserver-conf.lua',
|
||||
'httpserver-connection.lua',
|
||||
'httpserver-error.lua',
|
||||
'httpserver-header.lua',
|
||||
'httpserver-init.lua',
|
||||
'httpserver-request.lua',
|
||||
'httpserver-static.lua',
|
||||
'httpserver-wifi.lua',
|
||||
}
|
||||
for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end
|
||||
for i, f in ipairs(lfsFiles) do file.remove(f) end
|
||||
|
||||
compileAndRemoveIfNeeded = nil
|
||||
serverFiles = nil
|
||||
lfsFiles = nil
|
||||
collectgarbage()
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
-- flush() and for closing the connection.
|
||||
-- Author: Philip Gladstone, Marcos Kirsch
|
||||
|
||||
local BufferedConnection = {}
|
||||
BufferedConnection = {}
|
||||
|
||||
-- parameter is the nodemcu-firmware connection
|
||||
function BufferedConnection:new(connection)
|
||||
@ -15,7 +15,7 @@ return function(connection, code, extension, isGzipped, extraHeaders)
|
||||
-- A few MIME types. Keep list short. If you need something that is missing, let's add it.
|
||||
local mt = {css = "text/css", gif = "image/gif", html = "text/html", ico = "image/x-icon", jpeg = "image/jpeg",
|
||||
jpg = "image/jpeg", js = "application/javascript", json = "application/json", png = "image/png", xml = "text/xml"}
|
||||
if mt[ext] then return mt[ext] else return "application/octet-stream" end
|
||||
if mt[ext] then return mt[ext] else return "text/plain" end
|
||||
end
|
||||
|
||||
local mimeType = getMimeType(extension)
|
||||
@ -5,7 +5,7 @@
|
||||
-- Function for starting the server.
|
||||
-- If you compiled the mdns module, then it will also register with mDNS.
|
||||
local startServer = function(ip)
|
||||
local conf = dofile('httpserver-conf.lua')
|
||||
local conf = dofile('httpserver-conf.lc')
|
||||
if (dofile("httpserver.lc")(conf['general']['port'])) then
|
||||
print("nodemcu-httpserver running at:")
|
||||
print(" http://" .. ip .. ":" .. conf['general']['port'])
|
||||
@ -21,8 +21,7 @@ local function uri_decode(input)
|
||||
end
|
||||
|
||||
local function parseArgs(args)
|
||||
local r = {}
|
||||
local i = 1
|
||||
local r = {}; i=1
|
||||
if args == nil or args == "" then return r end
|
||||
for arg in string.gmatch(args, "([^&]+)") do
|
||||
local name, value = string.match(arg, "(.*)=(.*)")
|
||||
@ -47,10 +46,6 @@ local function getRequestData(payload)
|
||||
local requestData
|
||||
return function ()
|
||||
--print("Getting Request Data")
|
||||
-- for backward compatibility before v2.1
|
||||
if (sjson == nil) then
|
||||
sjson = cjson
|
||||
end
|
||||
if requestData then
|
||||
return requestData
|
||||
else
|
||||
@ -65,7 +60,7 @@ local function getRequestData(payload)
|
||||
--print("body = [" .. body .. "]")
|
||||
if mimeType == "application/json" then
|
||||
--print("JSON: " .. body)
|
||||
requestData = sjson.decode(body)
|
||||
requestData = cjson.decode(body)
|
||||
elseif mimeType == "application/x-www-form-urlencoded" then
|
||||
requestData = parseFormData(body)
|
||||
else
|
||||
@ -84,7 +79,7 @@ local function parseUri(uri)
|
||||
|
||||
if uri == nil then return r end
|
||||
if uri == "/" then uri = "/index.html" end
|
||||
local questionMarkPos, b, c, d, e, f = uri:find("?")
|
||||
questionMarkPos, b, c, d, e, f = uri:find("?")
|
||||
if questionMarkPos == nil then
|
||||
r.file = uri:sub(1, questionMarkPos)
|
||||
r.args = {}
|
||||
@ -116,7 +111,6 @@ return function (request)
|
||||
if not e then return nil end
|
||||
local line = request:sub(1, e - 1)
|
||||
local r = {}
|
||||
local _, i
|
||||
_, i, r.method, r.request = line:find("^([A-Z]+) (.-) HTTP/[1-9]+.[0-9]+$")
|
||||
if not (r.method and r.request) then
|
||||
--print("invalid request: ")
|
||||
27
httpserver-static.lua
Normal file
27
httpserver-static.lua
Normal file
@ -0,0 +1,27 @@
|
||||
-- httpserver-static.lua
|
||||
-- Part of nodemcu-httpserver, handles sending static files to client.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
return function (connection, req, args)
|
||||
dofile("httpserver-header.lc")(connection, 200, args.ext, args.isGzipped)
|
||||
-- Send file in little chunks
|
||||
local bytesRemaining = file.list()[args.file]
|
||||
-- Chunks larger than 1024 don't work.
|
||||
-- https://github.com/nodemcu/nodemcu-firmware/issues/1075
|
||||
local chunkSize = 1024
|
||||
local fileHandle = file.open(args.file)
|
||||
while bytesRemaining > 0 do
|
||||
local bytesToRead = 0
|
||||
if bytesRemaining > chunkSize then bytesToRead = chunkSize else bytesToRead = bytesRemaining end
|
||||
local chunk = fileHandle:read(bytesToRead)
|
||||
connection:send(chunk)
|
||||
bytesRemaining = bytesRemaining - #chunk
|
||||
--print(args.file .. ": Sent "..#chunk.. " bytes, " .. bytesRemaining .. " to go.")
|
||||
chunk = nil
|
||||
collectgarbage()
|
||||
end
|
||||
-- print("Finished sending: ", args.file)
|
||||
fileHandle:close()
|
||||
fileHandle = nil
|
||||
collectgarbage()
|
||||
end
|
||||
@ -2,7 +2,12 @@
|
||||
-- Part of nodemcu-httpserver, configures NodeMCU's WiFI in boot.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
local conf = dofile("httpserver-conf.lua")
|
||||
local conf = nil
|
||||
if file.exists("httpserver-conf.lc") then
|
||||
conf = dofile("httpserver-conf.lc")
|
||||
else
|
||||
conf = dofile("httpserver-conf.lua")
|
||||
end
|
||||
|
||||
wifi.setmode(conf.wifi.mode)
|
||||
|
||||
@ -13,7 +13,6 @@ return function (port)
|
||||
-- We do it in a separate thread because we need to send in little chunks and wait for the onSent event
|
||||
-- before we can send more, or we risk overflowing the mcu's buffer.
|
||||
local connectionThread
|
||||
local fileInfo
|
||||
|
||||
local allowStatic = {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false}
|
||||
|
||||
@ -27,10 +26,6 @@ return function (port)
|
||||
end
|
||||
end
|
||||
|
||||
local function startServingStatic(connection, req, args)
|
||||
fileInfo = dofile("httpserver-static.lc")(connection, req, args)
|
||||
end
|
||||
|
||||
local function startServing(fileServeFunction, connection, req, args)
|
||||
connectionThread = coroutine.create(function(fileServeFunction, bufferedConnection, req, args)
|
||||
fileServeFunction(bufferedConnection, req, args)
|
||||
@ -45,7 +40,6 @@ return function (port)
|
||||
|
||||
local BufferedConnectionClass = dofile("httpserver-connection.lc")
|
||||
local bufferedConnection = BufferedConnectionClass:new(connection)
|
||||
BufferedConnectionClass = nil
|
||||
local status, err = coroutine.resume(connectionThread, fileServeFunction, bufferedConnection, req, args)
|
||||
if not status then
|
||||
log(connection, "Error: "..err)
|
||||
@ -56,7 +50,7 @@ return function (port)
|
||||
end
|
||||
end
|
||||
|
||||
local function handleRequest(connection, req, handleError)
|
||||
local function handleRequest(connection, req)
|
||||
collectgarbage()
|
||||
local method = req.method
|
||||
local uri = req.uri
|
||||
@ -90,8 +84,7 @@ return function (port)
|
||||
else
|
||||
if allowStatic[method] then
|
||||
uri.args = {file = uri.file, ext = uri.ext, isGzipped = uri.isGzipped}
|
||||
startServingStatic(connection, req, uri.args)
|
||||
return
|
||||
fileServeFunction = dofile("httpserver-static.lc")
|
||||
else
|
||||
uri.args = {code = 405, errorString = "Method not supported", logFunction = log}
|
||||
fileServeFunction = dofile("httpserver-error.lc")
|
||||
@ -102,8 +95,8 @@ return function (port)
|
||||
end
|
||||
|
||||
local function onReceive(connection, payload)
|
||||
-- collectgarbage()
|
||||
local conf = dofile("httpserver-conf.lua")
|
||||
collectgarbage()
|
||||
local conf = dofile("httpserver-conf.lc")
|
||||
local auth
|
||||
local user = "Anonymous"
|
||||
|
||||
@ -169,27 +162,6 @@ return function (port)
|
||||
connectionThread = nil
|
||||
collectgarbage()
|
||||
end
|
||||
elseif fileInfo then
|
||||
local fileSize = file.list()[fileInfo.file]
|
||||
-- Chunks larger than 1024 don't work.
|
||||
-- https://github.com/nodemcu/nodemcu-firmware/issues/1075
|
||||
local chunkSize = 512
|
||||
local fileHandle = file.open(fileInfo.file)
|
||||
if fileSize > fileInfo.sent then
|
||||
fileHandle:seek("set", fileInfo.sent)
|
||||
local chunk = fileHandle:read(chunkSize)
|
||||
fileHandle:close()
|
||||
fileHandle = nil
|
||||
fileInfo.sent = fileInfo.sent + #chunk
|
||||
connection:send(chunk)
|
||||
-- print(fileInfo.file .. ": Sent "..#chunk.. " bytes, " .. fileSize - fileInfo.sent .. " to go.")
|
||||
chunk = nil
|
||||
else
|
||||
log(connection, "closing connetion", "Finished sending: "..fileInfo.file)
|
||||
connection:close()
|
||||
fileInfo = nil
|
||||
end
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
|
||||
@ -200,10 +172,6 @@ return function (port)
|
||||
connectionThread = nil
|
||||
collectgarbage()
|
||||
end
|
||||
if fileInfo then
|
||||
fileInfo = nil
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
|
||||
connection:on("receive", onReceive)
|
||||
23
init.lua
23
init.lua
@ -1,27 +1,10 @@
|
||||
-- check/flash/use LFS support, if possible
|
||||
if node.getpartitiontable().lfs_size > 0 then
|
||||
if file.exists("lfs.img") then
|
||||
if file.exists("lfs_lock") then
|
||||
file.remove("lfs_lock")
|
||||
file.remove("lfs.img")
|
||||
else
|
||||
local f = file.open("lfs_lock", "w")
|
||||
f:flush()
|
||||
f:close()
|
||||
file.remove("httpserver-compile.lua")
|
||||
node.LFS.reload("lfs.img")
|
||||
end
|
||||
end
|
||||
pcall(node.flashindex("_init"))
|
||||
end
|
||||
|
||||
-- Compile freshly uploaded nodemcu-httpserver lua files.
|
||||
if file.exists("httpserver-compile.lua") then
|
||||
if file.exists("httpserver-compile.lc") then
|
||||
dofile("httpserver-compile.lc")
|
||||
else
|
||||
dofile("httpserver-compile.lua")
|
||||
file.remove("httpserver-compile.lua")
|
||||
end
|
||||
|
||||
|
||||
-- Set up NodeMCU's WiFi
|
||||
dofile("httpserver-wifi.lc")
|
||||
|
||||
|
||||
@ -1,96 +0,0 @@
|
||||
--
|
||||
-- File: _init.lua
|
||||
--[[
|
||||
|
||||
This is a template for the LFS equivalent of the SPIFFS init.lua.
|
||||
|
||||
It is a good idea to such an _init.lua module to your LFS and do most of the LFS
|
||||
module related initialisaion in this. This example uses standard Lua features to
|
||||
simplify the LFS API.
|
||||
|
||||
For Lua 5.1, the first section adds a 'LFS' table to _G and uses the __index
|
||||
metamethod to resolve functions in the LFS, so you can execute the main
|
||||
function of module 'fred' by executing LFS.fred(params), etc.
|
||||
It also implements some standard readonly properties:
|
||||
|
||||
LFS._time The Unix Timestamp when the luac.cross was executed. This can be
|
||||
used as a version identifier.
|
||||
|
||||
LFS._config This returns a table of useful configuration parameters, hence
|
||||
print (("0x%6x"):format(LFS._config.lfs_base))
|
||||
gives you the parameter to use in the luac.cross -a option.
|
||||
|
||||
LFS._list This returns a table of the LFS modules, hence
|
||||
print(table.concat(LFS._list,'\n'))
|
||||
gives you a single column listing of all modules in the LFS.
|
||||
|
||||
For Lua 5.3 LFS table is populated by the LFS implementation in C so this part
|
||||
of the code is skipped.
|
||||
---------------------------------------------------------------------------------]]
|
||||
|
||||
local lfsindex = node.LFS and node.LFS.get or node.flashindex
|
||||
local G=_ENV or getfenv()
|
||||
local lfs_t
|
||||
if _VERSION == 'Lua 5.1' then
|
||||
lfs_t = {
|
||||
__index = function(_, name)
|
||||
local fn_ut, ba, ma, size, modules = lfsindex(name)
|
||||
if not ba then
|
||||
return fn_ut
|
||||
elseif name == '_time' then
|
||||
return fn_ut
|
||||
elseif name == '_config' then
|
||||
local fs_ma, fs_size = file.fscfg()
|
||||
return {lfs_base = ba, lfs_mapped = ma, lfs_size = size,
|
||||
fs_mapped = fs_ma, fs_size = fs_size}
|
||||
elseif name == '_list' then
|
||||
return modules
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end,
|
||||
|
||||
__newindex = function(_, name, value) -- luacheck: no unused
|
||||
error("LFS is readonly. Invalid write to LFS." .. name, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
setmetatable(lfs_t,lfs_t)
|
||||
G.module = nil -- disable Lua 5.0 style modules to save RAM
|
||||
package.seeall = nil
|
||||
else
|
||||
lfs_t = node.LFS
|
||||
end
|
||||
G.LFS = lfs_t
|
||||
|
||||
--[[-------------------------------------------------------------------------------
|
||||
The second section adds the LFS to the require searchlist, so that you can
|
||||
require a Lua module 'jean' in the LFS by simply doing require "jean". However
|
||||
note that this is at the search entry following the FS searcher, so if you also
|
||||
have jean.lc or jean.lua in SPIFFS, then this SPIFFS version will get loaded into
|
||||
RAM instead of using. (Useful, for development).
|
||||
|
||||
See docs/en/lfs.md and the 'loaders' array in app/lua/loadlib.c for more details.
|
||||
|
||||
---------------------------------------------------------------------------------]]
|
||||
|
||||
package.loaders[3] = function(module) -- loader_flash
|
||||
return lfs_t[module]
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------------
|
||||
These replace the builtins loadfile & dofile with ones which preferentially
|
||||
load from the filesystem and fall back to LFS. Flipping the search order
|
||||
is an exercise left to the reader.-
|
||||
------------------------------------------------------------------------------]]
|
||||
|
||||
local lf = loadfile
|
||||
G.loadfile = function(n)
|
||||
if file.exists(n) then return lf(n) end
|
||||
local mod = n:match("(.*)%.l[uc]a?$")
|
||||
local fn = mod and lfsindex(mod)
|
||||
return (fn or error (("Cannot find '%s' in FS or LFS"):format(n))) and fn
|
||||
end
|
||||
|
||||
-- Lua's dofile (luaB_dofile) reaches directly for luaL_loadfile; shim instead
|
||||
G.dofile = function(n) return assert(loadfile(n))() end
|
||||
@ -1,37 +0,0 @@
|
||||
--
|
||||
-- File: LFS_dummy_strings.lua
|
||||
--[[
|
||||
luac.cross -f generates a ROM string table which is part of the compiled LFS
|
||||
image. This table includes all strings referenced in the loaded modules.
|
||||
|
||||
If you want to preload other string constants, then one way to achieve this is
|
||||
to include a dummy module in the LFS that references the strings that you want
|
||||
to load. You never need to call this module; it's inclusion in the LFS image is
|
||||
enough to add the strings to the ROM table. Your application can use any strings
|
||||
in the ROM table without incuring any RAM or Lua Garbage Collector (LGC)
|
||||
overhead.
|
||||
|
||||
The local preload example is a useful starting point. However, if you call the
|
||||
following code in your application during testing, then this will provide a
|
||||
listing of the current RAM string table.
|
||||
|
||||
do
|
||||
local a=debug.getstrings'RAM'
|
||||
for i =1, #a do a[i] = ('%q'):format(a[i]) end
|
||||
print ('local preload='..table.concat(a,','))
|
||||
end
|
||||
|
||||
This will exclude any strings already in the ROM table, so the output is the list
|
||||
of putative strings that you should consider adding to LFS ROM table.
|
||||
|
||||
---------------------------------------------------------------------------------]]
|
||||
|
||||
local preload = "?.lc;?.lua", "/\n;\n?\n!\n-", "@init.lua", "_G", "_LOADED",
|
||||
"_LOADLIB", "__add", "__call", "__concat", "__div", "__eq", "__gc", "__index",
|
||||
"__le", "__len", "__lt", "__mod", "__mode", "__mul", "__newindex", "__pow",
|
||||
"__sub", "__tostring", "__unm", "collectgarbage", "cpath", "debug", "file",
|
||||
"file.obj", "file.vol", "flash", "getstrings", "index", "ipairs", "list", "loaded",
|
||||
"loader", "loaders", "loadlib", "module", "net.tcpserver", "net.tcpsocket",
|
||||
"net.udpsocket", "newproxy", "package", "pairs", "path", "preload", "reload",
|
||||
"require", "seeall", "wdclr", "not enough memory", "sjson.decoder","sjson.encoder",
|
||||
"tmr.timer"
|
||||
@ -1,48 +0,0 @@
|
||||
-- httpserver-buffer
|
||||
-- Part of nodemcu-httpserver, provides a buffer that behaves like a connection object
|
||||
-- that can handle multiple consecutive send() calls, and buffers small payloads up to 1400 bytes.
|
||||
-- This is primarily user to collect the send requests done by the head script.
|
||||
-- The owner is responsible to call getBuffer and send its result
|
||||
-- Author: Gregor Hartmann
|
||||
|
||||
local Buffer = {}
|
||||
|
||||
-- parameter is the nodemcu-firmware connection
|
||||
function Buffer:new()
|
||||
local newInstance = {}
|
||||
newInstance.size = 0
|
||||
newInstance.data = {}
|
||||
|
||||
-- Returns true if there was any data to be sent.
|
||||
function newInstance:getBuffer()
|
||||
local buffer = table.concat(self.data, "")
|
||||
self.data = {}
|
||||
self.size = 0
|
||||
return buffer
|
||||
end
|
||||
|
||||
function newInstance:getpeer()
|
||||
return "no peer"
|
||||
end
|
||||
|
||||
function newInstance:send(payload)
|
||||
local flushThreshold = 1400
|
||||
if (not payload) then print("nop payload") end
|
||||
local newSize = self.size + payload:len()
|
||||
if newSize >= flushThreshold then
|
||||
print("Buffer is full. Cutting off "..newSize-flushThreshold.." chars")
|
||||
--STEP1: cut out piece from payload to complete threshold bytes in table
|
||||
local pieceSize = flushThreshold - self.size
|
||||
if pieceSize then
|
||||
payload = payload:sub(1, pieceSize)
|
||||
end
|
||||
end
|
||||
table.insert(self.data, payload)
|
||||
self.size = self.size + #payload
|
||||
end
|
||||
|
||||
return newInstance
|
||||
|
||||
end
|
||||
|
||||
return Buffer
|
||||
@ -1,13 +0,0 @@
|
||||
-- httpserver-static.lua
|
||||
-- Part of nodemcu-httpserver, handles sending static files to client.
|
||||
-- Author: Gregor Hartmann
|
||||
|
||||
return function (connection, req, args)
|
||||
|
||||
local buffer = dofile("httpserver-buffer.lc"):new()
|
||||
dofile("httpserver-header.lc")(buffer, req.code or 200, args.ext, args.isGzipped)
|
||||
-- Send header and return fileInfo
|
||||
connection:send(buffer:getBuffer())
|
||||
|
||||
return { file = args.file, sent = 0}
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user