Skip to content

Commit

Permalink
Merge pull request #3 from Heng-Bian/dev
Browse files Browse the repository at this point in the history
optimize the ui and README
  • Loading branch information
Heng-Bian committed Mar 23, 2023
2 parents 9b891b4 + c7e59a9 commit 2919b09
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 94 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Host: localhost:8080
```

### response example (Not showing all)
File ending with "/" means directory

```json
{
Expand Down Expand Up @@ -118,6 +119,10 @@ For help info
Start the service with port 8080
`./archive-server -port 8080`

### Access in a browser
After runing the archive-server,
visit `http://localhost:8080`

## Mechanism
archiver-proxy offers an random access to archive item before download the entire
file. archiver-proxy itself do not cache any data and erverything is based on stream. The archive file on the network MUST support HTTP Range request. Fortunately, the common server such as nginx and Minio support it.
Expand Down
17 changes: 13 additions & 4 deletions pkg/archive/rar.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"io"
"sort"
"strings"

"github.com/Heng-Bian/httpreader"
rardecode "github.com/nwaples/rardecode/v2"
Expand All @@ -26,7 +27,11 @@ func ListRarFiles(r *httpreader.Reader) (files []string, err error) {
return fileNames, err
}
}
fileNames = append(fileNames, header.Name)
if header.IsDir && !strings.HasSuffix(header.Name, "/") {
fileNames = append(fileNames, header.Name+"/")
} else {
fileNames = append(fileNames, header.Name)
}
}
}

Expand Down Expand Up @@ -92,9 +97,13 @@ func RarToZip(w io.Writer, r *httpreader.Reader, names []string) error {
return err
}
}
if Exists(names, header.Name) {
z, err := zipWriter.Create(header.Name)
if err == nil {
name := header.Name
if header.IsDir && !strings.HasSuffix(header.Name, "/") {
name = name + "/"
}
if Exists(names, name) {
z, err := zipWriter.Create(name)
if err == nil && !strings.HasSuffix(header.Name, "/") {
io.Copy(z, rarReader)
}
}
Expand Down
18 changes: 14 additions & 4 deletions pkg/archive/sevenZ.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/zip"
"io"
"sort"
"strings"

"github.com/Heng-Bian/httpreader"
"github.com/saracen/go7z"
Expand All @@ -26,7 +27,12 @@ func List7zFiles(r *httpreader.Reader) (files []string, err error) {
return fileNames, err
}
}
fileNames = append(fileNames, header.Name)
//dir
if header.Attrib == 16 && !strings.HasSuffix(header.Name, "/") {
fileNames = append(fileNames, header.Name+"/")
} else {
fileNames = append(fileNames, header.Name)
}
}
}

Expand Down Expand Up @@ -96,9 +102,13 @@ func SevenZToZip(w io.Writer, r *httpreader.Reader, names []string) error {
return err
}
}
if Exists(names, header.Name) {
z, err := zipWriter.Create(header.Name)
if err == nil {
name := header.Name
if header.Attrib == 16 && !strings.HasSuffix(header.Name, "/") {
name = name + "/"
}
if Exists(names, name) {
z, err := zipWriter.Create(name)
if err == nil && !strings.HasSuffix(header.Name, "/") {
io.Copy(z, sevenZ)
}
}
Expand Down
31 changes: 17 additions & 14 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,24 @@ <h1>
</h1>

<div class="description">
An archive proxy written in Go language
An archive proxy written in Go language supporting zip, tar, 7z, rar(including rar5).
<br>
<br>
For more information <a href="https://github.com/Heng-Bian/archive-proxy/blob/main/README.md">https://github.com/Heng-Bian/archive-proxy/blob/main/README.md</a>
<hr>
</div>

<h2>Read a remote file</h2>

<ol id="demo-container">
<li>
<label>
<div class="sub-div">
<span class="form-label">Paste a URL</span>
<input type="text" id="url-input" onchange="clearFiles()">
</label>
<input type="text" id="url-input">
</div>
</li>
<li id="encoding-item">
<label>
<div class="sub-div">
<span class="form-label">Select the encoding of names</span>
<select id="encoding-input">
<option>utf-8</option>
Expand Down Expand Up @@ -73,27 +76,27 @@ <h2>Read a remote file</h2>
<option>x-mac-cyrillic</option>
<option>x-user-defined</option>
</select>
</label>
</div>
</li>
<li>
<label>
<div class="sub-div">
<span class="form-label">List the remote archive files</span>
<button id="read" onclick="read()">Read</button>
</label>
<button id="read">Read</button>
</div>
</li>
<li>
<label>
<div class="sub-div">
<span class="form-label">Select multiple files</span>
<select id="download-entries" style="height: 400px;" multiple="multiple">

</select>
</label>
</div>
</li>
<li>
<label>
<div class="sub-div">
<span class="form-label">Download the selected files</span>
<button id="download" onclick="download()">Download</button>
</label>
<button id="download">Download</button>
</div>
</li>
</ol>

Expand Down
2 changes: 1 addition & 1 deletion web/static/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ body {
margin-right: 10px;
}

label {
.sub-div {
display: flex;
}

Expand Down
153 changes: 82 additions & 71 deletions web/static/index.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,90 @@
function read() {
let remoteUrl = document.getElementById("url-input").value
let charset = document.getElementById("encoding-input").value
try {
new URL(remoteUrl)
let queryParams = new URLSearchParams()
queryParams.set("charset", charset)
queryParams.set("url", remoteUrl)
fetch("/list" + "?" + queryParams.toString())
.then(res => {
if (res.status == 500) {
res.text().then(message => {
alert(message)
})
} else {
res.json().then(
json => {
files = json["Files"]
let entries = document.getElementById("download-entries");
entries.innerHTML = ""
for (let i in files) {
let option = document.createElement("option")
option.appendChild(document.createTextNode(files[i]));
option.setAttribute("value", files[i]);
entries.appendChild(option);
(() => {
const remoteUrl = document.getElementById("url-input")
const charset = document.getElementById("encoding-input")
const entries = document.getElementById("download-entries")

const readButton = document.getElementById("read")
const downloadButton = document.getElementById("download")
const urlInput = document.getElementById("url-input")

function read() {
try {
new URL(remoteUrl.value)
let queryParams = new URLSearchParams()
queryParams.set("charset", charset.value)
queryParams.set("url", remoteUrl.value)
fetch("/list" + "?" + queryParams.toString())
.then(res => {
if (res.status == 500) {
res.text().then(message => {
alert(message)
})
} else {
res.json().then(
json => {
files = json["Files"]
let entries = document.getElementById("download-entries");
entries.innerHTML = ""
for (let i in files) {
let option = document.createElement("option")
option.appendChild(document.createTextNode(files[i]));
option.setAttribute("value", files[i]);
entries.appendChild(option);
}
}
}
)
}
})
} catch (error) {
alert(error)
)
}
})
} catch (error) {
alert(errovaluer)
}
}
}

function download() {
let remoteUrl = document.getElementById("url-input").value
let charset = document.getElementById("encoding-input").value
let options = document.getElementById("download-entries").options
let files = []
for (let i in options) {
if (options[i].selected) {
files.push(options[i].value)
function download() {
let files = []
let options = entries.options
for (let i in options) {
if (options[i].selected) {
files.push(options[i].value)
}
}
if (files.length == 0) {
alert("no seleted files!")
return
}
let queryParams = new URLSearchParams()
queryParams.set("charset", charset.value)
queryParams.set("url", remoteUrl.value)
fetch("/pack" + "?" + queryParams.toString(), {
method: 'POST',
body: JSON.stringify(files),
}).then(res => {
if (res.status == 500) {
res.text().then(message => {
alert(message)
})
} else {
const fileStream = streamSaver.createWriteStream("package.zip")
const readableStream = res.body;
if (window.WritableStream && readableStream.pipeTo) {
return readableStream.pipeTo(fileStream).then(() => {

})
}
window.writer = fileStream.getWriter();
const reader = res.body.getReader();
const pump = () => reader.read().then(res => res.done ? window.writer.close() : window.writer.write(res.value).then(pump))
pump()
}
})
}
if (files.length == 0) {
alert("no seleted files!")
return

function clearFiles() {
entries.innerHTML = ""
}
let queryParams = new URLSearchParams()
queryParams.set("charset", charset)
queryParams.set("url", remoteUrl)
fetch("/pack" + "?" + queryParams.toString(), {
method: 'POST',
body: JSON.stringify(files),
}).then(res => {
if (res.status == 500) {
res.text().then(message => {
alert(message)
})
} else {
const fileStream = streamSaver.createWriteStream("pack.zip")
const readableStream = res.body;
if (window.WritableStream && readableStream.pipeTo) {
return readableStream.pipeTo(fileStream).then(() => {

})
}
window.writer = fileStream.getWriter();
const reader = res.body.getReader();
const pump = () => reader.read().then(res => res.done ? window.writer.close() : window.writer.write(res.value).then(pump))
pump()
}
})
}
readButton.addEventListener("click", read)
downloadButton.addEventListener("click", download)
urlInput.addEventListener("change", clearFiles)
})()

function clearFiles() {
document.getElementById("download-entries").innerHTML = ""
}

0 comments on commit 2919b09

Please sign in to comment.