all src in same repo
parent
13163f2108
commit
2cf1f3804b
@ -1,3 +1,7 @@
|
||||
bit4sat
|
||||
db-storage
|
||||
file-storage
|
||||
node_modules
|
||||
dist
|
||||
.cache
|
||||
yarn-error.log
|
||||
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"presets": [
|
||||
"env"
|
||||
]
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
// https://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:vue/essential'
|
||||
],
|
||||
rules: {
|
||||
'no-console': 'off'
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
v10.15.3
|
@ -0,0 +1,76 @@
|
||||
# bit4sat
|
||||
|
||||
## Installation
|
||||
|
||||
- init/install the right node version in `.nvmrc`
|
||||
|
||||
```
|
||||
nvm install $(cat .nvmrc)
|
||||
nvm use
|
||||
```
|
||||
|
||||
- install yarn (optional)
|
||||
|
||||
`sudo apt update && sudo apt install -y yarn`
|
||||
|
||||
- install deps
|
||||
|
||||
`yarn`
|
||||
|
||||
or with npm
|
||||
|
||||
`npm install`
|
||||
|
||||
|
||||
## start dev server
|
||||
|
||||
With yarn:
|
||||
|
||||
`yarn run start`
|
||||
|
||||
or with npm
|
||||
|
||||
`npm start`
|
||||
|
||||
## Backend Server
|
||||
|
||||
Run:
|
||||
|
||||
```
|
||||
> git submodule init
|
||||
> git submodule update
|
||||
```
|
||||
|
||||
The go server will be find in the server folder. To Run it use:
|
||||
```
|
||||
> cd server
|
||||
> make
|
||||
> ./bit4sat
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
These are the currently available API endpoints:
|
||||
|
||||
- `POST` on `/upload`:
|
||||
Accept a form with content type `application/json` with following structure:
|
||||
``` json
|
||||
{
|
||||
"files": {
|
||||
"name": "this is the name/path of file (required)",
|
||||
"size": "size of file (not required)",
|
||||
"sha256": "sha256 (not required)"
|
||||
},
|
||||
"timestamp": "timestamp as in Date().toJSON() in js"
|
||||
}
|
||||
```
|
||||
|
||||
Example API call:
|
||||
``` bash
|
||||
curl -sX POST \ Fri 19:10
|
||||
--header 'content-type: application/json' 'localhost:8880/upload/' \
|
||||
--data '{"files":[], "timestamp": "2012-04-23T18:25:43.511Z" }'
|
||||
|
||||
```
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
</div>
|
||||
|
||||
<script src="./src/index.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "bits4sat",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"repository": "git@git.sp4ke.com:sp4ke/bits4sat.git",
|
||||
"author": "spike",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@vue/component-compiler-utils": "^2.6.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"eslint": ">=5.0.0",
|
||||
"eslint-plugin-vue": "^5.2.2",
|
||||
"parcel-bundler": ">=1.11.0",
|
||||
"parcel-plugin-eslint": "^1.0.7",
|
||||
"vue-template-compiler": "^2.6.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"vue": "^2.6.8",
|
||||
"vue-hot-reload-api": "^2.3.3"
|
||||
},
|
||||
"alias": {
|
||||
"vue": "./node_modules/vue/dist/vue.common.js"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "parcel index.html"
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<upload></upload>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script charset="utf-8">
|
||||
import Upload from './upload.vue';
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
data() {
|
||||
return {
|
||||
msg: 'Hello World'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Upload,
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,95 @@
|
||||
import 'babel-polyfill';
|
||||
|
||||
let apiPort = '8880'
|
||||
if (process.env.API_PORT !== undefined) {
|
||||
apiPort = process.env.API_PORT;
|
||||
}
|
||||
|
||||
function getEndpoint (path) {
|
||||
return new URL(path, apiEndpoint).toString()
|
||||
}
|
||||
|
||||
const endPoints = {
|
||||
get upload () {
|
||||
return getEndpoint('upload/')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const apiEndpoint = function() {
|
||||
let currentLoc = self.location;
|
||||
let endpoint = new URL(currentLoc);
|
||||
|
||||
endpoint.port = apiPort;
|
||||
|
||||
return endpoint.toString()
|
||||
}()
|
||||
|
||||
class Upload {
|
||||
|
||||
constructor(filesMetadata, fileObjects) {
|
||||
this.filesMetadata = Array.from(filesMetadata)
|
||||
this.fileObjects = fileObjects
|
||||
this.timestamp = new Date()
|
||||
}
|
||||
|
||||
get uploadMetadata() {
|
||||
|
||||
return {
|
||||
files: this.filesMetadata,
|
||||
timestamp: this.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
async create() {
|
||||
let req = new Request(endPoints.upload , {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(this.uploadMetadata)
|
||||
})
|
||||
|
||||
//let result = await fetch(req);
|
||||
let res = await fetch(req)
|
||||
.catch((e) => { console.error(e) })
|
||||
|
||||
|
||||
if (!res.ok) {
|
||||
throw(`${res.status}: ` + (await res.json()).error)
|
||||
}
|
||||
|
||||
return res.json().then(data => {
|
||||
let { result: { id: id } } = data
|
||||
this.uploadId = id
|
||||
return data
|
||||
})
|
||||
}
|
||||
|
||||
async send(){
|
||||
console.log(`Sending with id ${this.uploadId}`)
|
||||
|
||||
let formData = new FormData();
|
||||
for (let file of this.fileObjects) {
|
||||
console.log(file)
|
||||
formData.append('upload[]', file)
|
||||
}
|
||||
|
||||
|
||||
let req = new Request(endPoints.upload + this.uploadId, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
})
|
||||
|
||||
let res = await fetch(req)
|
||||
.catch((e) => {console.error(e)})
|
||||
|
||||
if (!res.ok){
|
||||
throw(`${res.status}: ` + (await res.json()).error)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
endpoint: apiEndpoint,
|
||||
endPoints: endPoints,
|
||||
Upload: Upload
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import './styles/index.css';
|
||||
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import GetWorker from './workerInterface.js'
|
||||
|
||||
|
||||
|
||||
window.app = new Vue({
|
||||
el: '#app',
|
||||
template: '<App/>',
|
||||
components: { App }
|
||||
});
|
||||
|
||||
window.worker = GetWorker('main');
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
@import './variables.css';
|
||||
|
||||
body {
|
||||
font-size: var(--test);
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
:root{
|
||||
--test: 16px;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div id="upload">
|
||||
<input v-on:change="fileChange($event)" type="file" multiple />
|
||||
<p>selected {{fileCount}} files</p>
|
||||
<ul>
|
||||
<li v-bind:files="files" v-for="file in files">
|
||||
{{ file.name }}
|
||||
<ul>
|
||||
<li>size: {{ file.size / 1000 }} kB </li>
|
||||
<li>type: {{ file.type }} </li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script charset="utf-8">
|
||||
import GetWorker from './workerInterface.js';
|
||||
const w = GetWorker('main');
|
||||
|
||||
w.listenTo('upload-id', (e) => {
|
||||
console.log('vue received upload id ', e.data.id)
|
||||
})
|
||||
|
||||
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
fileCount: 0,
|
||||
files: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fileChange(event) {
|
||||
// reset
|
||||
this.files = []
|
||||
|
||||
|
||||
this.fileCount = event.target.files.length
|
||||
this.files = event.target.files
|
||||
|
||||
w.post({
|
||||
msg: 'new-upload',
|
||||
payload: [...this.files],
|
||||
})
|
||||
|
||||
// Get sha256 of files
|
||||
// for (let file of this.files) {
|
||||
// w.post({
|
||||
// msg: 'file-sha256',
|
||||
// payload: file
|
||||
// })
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
@ -0,0 +1,87 @@
|
||||
//This worker will be used for cryptographic, long running and API calls
|
||||
//to keep the UI free
|
||||
|
||||
import Api from './api.js'
|
||||
|
||||
const name = 'main'
|
||||
|
||||
function hexString(buffer) {
|
||||
const byteArray = new Uint8Array(buffer);
|
||||
|
||||
const hexCodes = [...byteArray].map(value => {
|
||||
const hexCode = value.toString(16);
|
||||
const paddedHexCode = hexCode.padStart(2, '0');
|
||||
return paddedHexCode;
|
||||
});
|
||||
|
||||
return hexCodes.join('');
|
||||
}
|
||||
|
||||
async function getSHA256(file){
|
||||
|
||||
// Read as array buffer
|
||||
let fileReader = new FileReaderSync();
|
||||
let buffer = fileReader.readAsArrayBuffer(file);
|
||||
|
||||
// Return hex encoded sha256
|
||||
return crypto.subtle.digest('SHA-256', buffer)
|
||||
.then(v => { return hexString(v) })
|
||||
|
||||
}
|
||||
|
||||
async function newUpload(files){
|
||||
let filesMetadata = await Promise.all(files.map(async (f) => {
|
||||
return {
|
||||
lastModified: f.lastModified,
|
||||
type: f.type,
|
||||
name: f.name,
|
||||
size: f.size,
|
||||
sha256: await getSHA256(f)
|
||||
}
|
||||
}))
|
||||
|
||||
// Get sha256
|
||||
//for (let file of files) {
|
||||
// let sha256 = getSHA256(file)
|
||||
// file.sha256 = sha256
|
||||
// console.log(files)
|
||||
|
||||
//}
|
||||
|
||||
let upload = new Api.Upload(filesMetadata, files)
|
||||
|
||||
await upload.create()
|
||||
.then(data => {
|
||||
// Get the upload id
|
||||
let { result: { id: id } } = data
|
||||
|
||||
// Notify the UI
|
||||
postMessage({msg: 'upload-id', id: id})
|
||||
|
||||
// Send the files
|
||||
upload.send()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
self.onmessage = e => {
|
||||
|
||||
switch (e.data.msg) {
|
||||
case 'init':
|
||||
console.log(`initialized ${name} worker`);
|
||||
break;
|
||||
|
||||
case 'file-sha256':
|
||||
getSHA256(e.data.payload)
|
||||
break;
|
||||
|
||||
case 'new-upload':
|
||||
newUpload(e.data.payload)
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(`${name} worker: need {msg: "message type", ... }`)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
|
||||
class Worker {
|
||||
|
||||
constructor(script) {
|
||||
if (window.Worker) {
|
||||
this.worker = new window.Worker(script);
|
||||
this.worker.onmessage = this.onmessage()
|
||||
this.listeners = {}
|
||||
|
||||
this.post({
|
||||
msg: 'init'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
listenTo(ev, callback) {
|
||||
this.listeners[ev] = callback
|
||||
}
|
||||
|
||||
|
||||
onmessage() {
|
||||
let self = this
|
||||
return function(e) {
|
||||
if ((e.data.msg in self.listeners) === true) {
|
||||
self.listeners[e.data.msg](e)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post(m) {
|
||||
this.worker.postMessage(m)
|
||||
}
|
||||
}
|
||||
|
||||
const workers = {
|
||||
'main': new Worker('./worker.js')
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function getWorker(name){
|
||||
if (name in workers) {
|
||||
return workers[name];
|
||||
} else {
|
||||
console.log(`unknown worker ${name}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default getWorker;
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue