Compare commits
No commits in common. "master" and "feature/max-artifact-size" have entirely different histories.
master
...
feature/ma
17 changed files with 23 additions and 145 deletions
26
.drone.yml
26
.drone.yml
|
@ -74,13 +74,12 @@ steps:
|
||||||
- ls -al
|
- ls -al
|
||||||
- cd web/fling
|
- cd web/fling
|
||||||
- npm install && npm run build
|
- npm install && npm run build
|
||||||
- npm install --no-cache @fling/flingclient # make sure flingclient is not cached
|
|
||||||
- tar czf fling-web-$VERSION.tar.gz build/
|
- tar czf fling-web-$VERSION.tar.gz build/
|
||||||
- curl --user "$NEXUS_USER:$NEXUS_PASSWORD"
|
- curl --user "$NEXUS_USER:$NEXUS_PASSWORD"
|
||||||
--upload-file ./fling-web-$VERSION.tar.gz
|
--upload-file ./fling-web-$VERSION.tar.gz
|
||||||
https://nexus.friedl.net/repository/build-artifacts/fling-web-$VERSION.tar.gz
|
https://nexus.friedl.net/repository/build-artifacts/fling-web-$VERSION.tar.gz
|
||||||
|
|
||||||
- name: publish branch
|
- name: publish
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
settings:
|
settings:
|
||||||
username:
|
username:
|
||||||
|
@ -93,29 +92,6 @@ steps:
|
||||||
tags: 0.1.0-snapshot
|
tags: 0.1.0-snapshot
|
||||||
build_args:
|
build_args:
|
||||||
- VERSION=0.1.0-snapshot
|
- VERSION=0.1.0-snapshot
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
exclude:
|
|
||||||
- master
|
|
||||||
|
|
||||||
- name: publish master
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
username:
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
dockerfile: container/Dockerfile
|
|
||||||
context: ./container
|
|
||||||
repo: arminfriedl/fling
|
|
||||||
tags:
|
|
||||||
- 0.1.0-snapshot
|
|
||||||
- latest
|
|
||||||
build_args:
|
|
||||||
- VERSION=0.1.0-snapshot
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: m2-cache
|
- name: m2-cache
|
||||||
|
|
68
README.md
68
README.md
|
@ -1,68 +0,0 @@
|
||||||
**12.01.2021: Fling has moved to the attic**
|
|
||||||
|
|
||||||
Fling was a good learning experiment for a non-trivial React app with a REST
|
|
||||||
backend. However, it never really got any traction and I'm not using it anymore.
|
|
||||||
Other projects are more important to me and maintaining Fling does not make any
|
|
||||||
sense. As of now docker containers are deleted and the artifacts are not
|
|
||||||
distributed anymore. You are free to fork and build your own version but no more
|
|
||||||
work will be done in this repository.
|
|
||||||
|
|
||||||
Alternatives:
|
|
||||||
- If you are looking for mature self-hosted file sharing solution,
|
|
||||||
[ownCloud](https://owncloud.com/) is in many ways similar to Fling and then
|
|
||||||
some.
|
|
||||||
- If you want an even simpler solution for sharing files over http,
|
|
||||||
[dirl](https://github.com/arminfriedl/dirl) might meet your needs.
|
|
||||||
|
|
||||||
# Fling
|
|
||||||
Fling is a self-hosted file share. It is simple like USB without missing out on
|
|
||||||
the good parts of a web app:
|
|
||||||
- Just drop files on a Fling and share the URL
|
|
||||||
- Choose your own name for your share-URL
|
|
||||||
- Share a direct download link
|
|
||||||
- Let others upload files
|
|
||||||
- Protect your fling by a password - no registration required
|
|
||||||
- Let a fling expire after a date or a number of clicks
|
|
||||||
|
|
||||||
# API
|
|
||||||
Fling is distributed as both, a backend service and a web interface. You can use
|
|
||||||
the backend on its own with any [HTTP client](examples).
|
|
||||||
|
|
||||||
Per default Fling publishes a Swagger UI page and an OpenAPI spec. You can find
|
|
||||||
them here:
|
|
||||||
|
|
||||||
``` http
|
|
||||||
http://<host>:<port>/swagger-ui.html
|
|
||||||
http://<host>:<port>/v3/api-docs
|
|
||||||
```
|
|
||||||
|
|
||||||
If starting the fling container locally, the default `<host>:<port>` is
|
|
||||||
http://localhost:3000. You can also find a recent version of it via
|
|
||||||
https://fling.friedl.net/swagger-ui.html and
|
|
||||||
https://fling.friedl.net/v3/api-docs.
|
|
||||||
|
|
||||||
# Starting Fling from Docker
|
|
||||||
A Fling container is provided at https://hub.docker.com/repository/docker/arminfriedl/fling.
|
|
||||||
|
|
||||||
1. Run `docker run --rm -p3000:3000 arminfriedl/fling`
|
|
||||||
2. Go to the default http://localhost:3000
|
|
||||||
3. Log in with `adminName:adminPassword`.
|
|
||||||
|
|
||||||
## Configuring Fling
|
|
||||||
The Fling container can be configured by environment variables.
|
|
||||||
|
|
||||||
The web interface configuration ([config.js](web/fling/public/config.js)/[config.js.template](container/var/www/fling/config.js.template)) will be
|
|
||||||
filled by `envsubst` when the container starts up.
|
|
||||||
``` sh
|
|
||||||
# The base URL of the Fling API service
|
|
||||||
FLING_API_BASE=http://localhost:3000
|
|
||||||
# Log level of the application
|
|
||||||
FLING_LOG_LEVEL=warn
|
|
||||||
# Max. upload size in bytes. Checked on client side.
|
|
||||||
FLING_FILESIZE=209715200
|
|
||||||
```
|
|
||||||
|
|
||||||
The Fling service configuration is a standard spring configuration. It can be
|
|
||||||
set by environement variables or any other [configuration externalization supported by spring boot]
|
|
||||||
(https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config)).
|
|
||||||
Refer to the [application-prod.yml](service/fling/src/main/resources/application-prod.yml) for configuration options.
|
|
|
@ -2,11 +2,7 @@ FROM alpine:latest
|
||||||
|
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
|
|
||||||
ENV FLING_API_BASE http://localhost:3000
|
RUN apk add --update --no-cache nginx openjdk11-jre && \
|
||||||
ENV FLING_LOG_LEVEL warn
|
|
||||||
ENV FLING_FILESIZE 209715200
|
|
||||||
|
|
||||||
RUN apk add --update --no-cache nginx openjdk11-jre gettext && \
|
|
||||||
mkdir -p /var/fling/files && \
|
mkdir -p /var/fling/files && \
|
||||||
mkdir -p /tmp/fling && \
|
mkdir -p /tmp/fling && \
|
||||||
wget -O /tmp/fling/service.jar "https://nexus.friedl.net/service/rest/v1/search/assets/download?sort=version&maven.groupId=net.friedl&maven.artifactId=fling&maven.baseVersion=$(echo -n $VERSION | tr [:lower:] [:upper:])&maven.extension=jar" && \
|
wget -O /tmp/fling/service.jar "https://nexus.friedl.net/service/rest/v1/search/assets/download?sort=version&maven.groupId=net.friedl&maven.artifactId=fling&maven.baseVersion=$(echo -n $VERSION | tr [:lower:] [:upper:])&maven.extension=jar" && \
|
||||||
|
@ -18,8 +14,7 @@ RUN apk add --update --no-cache nginx openjdk11-jre gettext && \
|
||||||
mv /tmp/fling/service.jar ./service.jar
|
mv /tmp/fling/service.jar ./service.jar
|
||||||
|
|
||||||
COPY ./etc/nginx/conf.d /etc/nginx/conf.d
|
COPY ./etc/nginx/conf.d /etc/nginx/conf.d
|
||||||
COPY ./var/www/fling/config.js.template /var/www/fling/config.js.template
|
COPY ./entrypoint.sh ./usr/local/bin/entrypoint.sh
|
||||||
COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
||||||
|
|
||||||
VOLUME /var/fling/
|
VOLUME /var/fling/
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,4 @@ mkdir /var/run/nginx # nginx fails with /var/run/nginx/nginx.pid not found in al
|
||||||
|
|
||||||
nginx
|
nginx
|
||||||
|
|
||||||
cat /var/www/fling/config.js.template | envsubst > /var/www/fling/config.js
|
|
||||||
|
|
||||||
java ${FL_JVM_OPTS} -jar service.jar
|
java ${FL_JVM_OPTS} -jar service.jar
|
||||||
|
|
|
@ -61,23 +61,6 @@ server {
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
|
|
||||||
# handle openapi requests by openapi servlet
|
|
||||||
location /swagger-ui {
|
|
||||||
proxy_pass http://localhost:8080;
|
|
||||||
|
|
||||||
proxy_set_header X-Forwarded-Host $host:$server_port;
|
|
||||||
proxy_set_header X-Forwarded-Server $host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
|
|
||||||
# Required for web sockets to function
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
}
|
|
||||||
|
|
||||||
# always respond with index.html for unknown paths
|
# always respond with index.html for unknown paths
|
||||||
# (routing is client side)
|
# (routing is client side)
|
||||||
location / {
|
location / {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
window['flingconfig'] = {
|
|
||||||
API_BASE: "${FLING_API_BASE}",
|
|
||||||
LOG_LEVEL: "${FLING_LOG_LEVEL}",
|
|
||||||
FILESIZE: "${FLING_FILESIZE}"
|
|
||||||
}
|
|
|
@ -20,8 +20,7 @@ fling:
|
||||||
archive.filesystem.archive-path: "/var/fling/files"
|
archive.filesystem.archive-path: "/var/fling/files"
|
||||||
security:
|
security:
|
||||||
allowed-origins:
|
allowed-origins:
|
||||||
- "https://fling.friedl.net"
|
- "https://friedl.net"
|
||||||
- "http://localhost:3000"
|
|
||||||
- "http://localhost:3000"
|
- "http://localhost:3000"
|
||||||
- "http://localhost:5000"
|
- "http://localhost:5000"
|
||||||
- "http://10.0.2.2:5000"
|
- "http://10.0.2.2:5000"
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
REACT_APP_API=http://localhost:3000
|
REACT_APP_API=https://fling.friedl.net
|
||||||
REACT_APP_LOGLEVEL=warn
|
REACT_APP_LOGLEVEL=warn
|
||||||
REACT_APP_FILESIZE=209715200
|
REACT_APP_FILESIZE=209715200
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
window['flingconfig'] = {
|
|
||||||
API_BASE: "http://localhost:8080",
|
|
||||||
LOG_LEVEL: "warn",
|
|
||||||
FILESIZE: 209715200
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="shortcut icon" href="%PUBLIC_URL%/fling.ico">
|
<link rel="shortcut icon" href="%PUBLIC_URL%/fling.ico">
|
||||||
<script src="%PUBLIC_URL%/config.js"></script>
|
|
||||||
<!--
|
<!--
|
||||||
Notice the use of %PUBLIC_URL% in the tag above.
|
Notice the use of %PUBLIC_URL% in the tag above.
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
|
|
@ -22,7 +22,7 @@ function FlingArtifactControl(props) {
|
||||||
// the browser downloads the file fine, it also reloads the page, hence
|
// the browser downloads the file fine, it also reloads the page, hence
|
||||||
// loosing all logs and state
|
// loosing all logs and state
|
||||||
let frame = document.createElement("iframe");
|
let frame = document.createElement("iframe");
|
||||||
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/artifacts/${props.artifact.id}/data?derivedToken=${token}`;
|
let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/artifacts/${props.artifact.id}/data?derivedToken=${token}`;
|
||||||
log.trace(`Generated download url: ${url}`);
|
log.trace(`Generated download url: ${url}`);
|
||||||
frame.src = url;
|
frame.src = url;
|
||||||
iframeContainer.current.appendChild(frame);
|
iframeContainer.current.appendChild(frame);
|
||||||
|
|
|
@ -23,6 +23,12 @@ export default function Navbar() {
|
||||||
Fling
|
Fling
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
|
<section className="navbar-center">
|
||||||
|
<div className="input-group input-inline">
|
||||||
|
<input className="form-input input-sm" type="text" placeholder="Search" />
|
||||||
|
<button className="btn btn-sm btn-link input-group-btn"><i className="icon icon-search"/></button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
<section className="navbar-section navbar-control">
|
<section className="navbar-section navbar-control">
|
||||||
<button className="btn btn-sm btn-link" onClick={handleOnClick}><i className="icon icon-plus"/> New</button>
|
<button className="btn btn-sm btn-link" onClick={handleOnClick}><i className="icon icon-plus"/> New</button>
|
||||||
<a className="btn btn-sm btn-link" href="/admin/login"><i className="icon icon-shutdown"/> Logout</a>
|
<a className="btn btn-sm btn-link" href="/admin/login"><i className="icon icon-shutdown"/> Logout</a>
|
||||||
|
|
|
@ -82,7 +82,7 @@ export default function Upload() {
|
||||||
stopEvent(ev);
|
stopEvent(ev);
|
||||||
ev.persist();
|
ev.persist();
|
||||||
|
|
||||||
let maxSize = window['flingconfig'].FILESIZE;
|
let maxSize = process.env.REACT_APP_FILESIZE;
|
||||||
let evFiles = fileListToArray(ev.dataTransfer.files);
|
let evFiles = fileListToArray(ev.dataTransfer.files);
|
||||||
|
|
||||||
for (let i = evFiles.length - 1; i >= 0; i--) {
|
for (let i = evFiles.length - 1; i >= 0; i--) {
|
||||||
|
@ -211,7 +211,7 @@ export default function Upload() {
|
||||||
</div>
|
</div>
|
||||||
<div className="upload-command-line m-2">
|
<div className="upload-command-line m-2">
|
||||||
<span className="total-upload">Total Size: {totalSize()}</span>
|
<span className="total-upload">Total Size: {totalSize()}</span>
|
||||||
<span className="total-upload">{`Max: ${prettifyBytes(window['flingconfig'].FILESIZE)}`}</span>
|
<span className="total-upload">{`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}</span>
|
||||||
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
|
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default function FlingUser(props) {
|
||||||
let authClient = new AuthClient();
|
let authClient = new AuthClient();
|
||||||
authClient.deriveToken({ singleUse: true })
|
authClient.deriveToken({ singleUse: true })
|
||||||
.then(token => {
|
.then(token => {
|
||||||
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
|
let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
|
||||||
log.trace(`Generated download url for link: ${url}`);
|
log.trace(`Generated download url for link: ${url}`);
|
||||||
setDownloadUrl(url);
|
setDownloadUrl(url);
|
||||||
})
|
})
|
||||||
|
@ -28,7 +28,7 @@ export default function FlingUser(props) {
|
||||||
// the browser downloads the file fine, it also reloads the page, hence
|
// the browser downloads the file fine, it also reloads the page, hence
|
||||||
// loosing all logs and state
|
// loosing all logs and state
|
||||||
let frame = document.createElement("iframe");
|
let frame = document.createElement("iframe");
|
||||||
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
|
let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
|
||||||
log.trace(`Generated download url: ${url}`);
|
log.trace(`Generated download url: ${url}`);
|
||||||
frame.src = url;
|
frame.src = url;
|
||||||
iframeContainer.current.appendChild(frame);
|
iframeContainer.current.appendChild(frame);
|
||||||
|
|
|
@ -123,7 +123,7 @@ function Upload(props) {
|
||||||
stopEvent(ev);
|
stopEvent(ev);
|
||||||
ev.persist();
|
ev.persist();
|
||||||
|
|
||||||
let maxSize = window['flingconfig'].FILESIZE;
|
let maxSize = process.env.REACT_APP_FILESIZE;
|
||||||
let evFiles = fileListToArray(ev.dataTransfer.files);
|
let evFiles = fileListToArray(ev.dataTransfer.files);
|
||||||
|
|
||||||
for (let i = evFiles.length - 1; i >= 0; i--) {
|
for (let i = evFiles.length - 1; i >= 0; i--) {
|
||||||
|
@ -252,7 +252,7 @@ function Upload(props) {
|
||||||
</div>
|
</div>
|
||||||
<div className="upload-command-line m-2">
|
<div className="upload-command-line m-2">
|
||||||
<span className="total-upload">Total Size: {totalSize()}</span>
|
<span className="total-upload">Total Size: {totalSize()}</span>
|
||||||
<span className="total-upload">{`Max: ${prettifyBytes(window['flingconfig'].FILESIZE)}`}</span>
|
<span className="total-upload">{`Max: ${prettifyBytes(process.env.REACT_APP_FILESIZE)}`}</span>
|
||||||
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
|
<button className="btn btn-primary btn-upload" onClick={handleUpload}>Upload</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -290,7 +290,7 @@ export default function FlingUserList(props) {
|
||||||
// the browser downloads the file fine, it also reloads the page, hence
|
// the browser downloads the file fine, it also reloads the page, hence
|
||||||
// loosing all logs and state
|
// loosing all logs and state
|
||||||
let frame = document.createElement("iframe");
|
let frame = document.createElement("iframe");
|
||||||
let url = `${window['flingconfig'].API_BASE.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
|
let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
|
||||||
log.trace(`Generated download url: ${url}`);
|
log.trace(`Generated download url: ${url}`);
|
||||||
frame.src = url;
|
frame.src = url;
|
||||||
setInProgress(false);
|
setInProgress(false);
|
||||||
|
|
|
@ -21,8 +21,8 @@ import * as serviceWorker from './serviceWorker';
|
||||||
|
|
||||||
/* Logging Setup */
|
/* Logging Setup */
|
||||||
log.setDefaultLevel(log.levels.TRACE);
|
log.setDefaultLevel(log.levels.TRACE);
|
||||||
if (window['flingconfig'].LOG_LEVEL) {
|
if (process.env.REACT_APP_LOGLEVEL) {
|
||||||
log.setLevel(window['flingconfig'].LOG_LEVEL);
|
log.setLevel(process.env.REACT_APP_LOGLEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store setup */
|
/* Store setup */
|
||||||
|
|
|
@ -9,7 +9,7 @@ import * as fc from '@fling/flingclient';
|
||||||
*/
|
*/
|
||||||
let clientConfig = (token) => {
|
let clientConfig = (token) => {
|
||||||
let config = new fc.ApiClient();
|
let config = new fc.ApiClient();
|
||||||
config.basePath = window['flingconfig'].API_BASE.replace(/\/+$/, '');
|
config.basePath = process.env.REACT_APP_API.replace(/\/+$/, '');
|
||||||
|
|
||||||
token = token || sessionStorage.getItem('token');
|
token = token || sessionStorage.getItem('token');
|
||||||
if (token) { config.authentications['bearer'].accessToken = token; }
|
if (token) { config.authentications['bearer'].accessToken = token; }
|
||||||
|
|
Loading…
Reference in a new issue