Compare commits

..

10 commits

Author SHA1 Message Date
909606a996
Archive Fling
Update README, make Swagger UI page accessible
2021-01-12 04:29:09 +01:00
3b047f4b56
Update README, make Swagger UI page accessible
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-29 19:25:41 +02:00
5c6bd1b1ad
Merge branch 'master' of git.friedl.net:incubator/fling
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-29 01:53:31 +02:00
ab005b28e7
Use local URL, add Readme
Use local url in prod config. The local url works if docker is started
on localhost. If the container is deployed to a domain, the base URL
must be specified via REACT_APP_API environment variable.
2020-07-29 01:50:42 +02:00
0cfccffb1e Merge pull request 'Read configuration from environment' (#3) from dynamic-config into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: incubator/fling#3
2020-07-28 23:04:08 +00:00
987c8ccba5
Read configuration from environment
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2020-07-29 00:59:59 +02:00
894c85bab9
Use local URL, add Readme
All checks were successful
continuous-integration/drone/push Build is passing
Use local url in prod config. The local url works if docker is started
on localhost. If the container is deployed to a domain, the base URL
must be specified via REACT_APP_API environment variable.
2020-07-27 21:14:06 +02:00
e03a0fd233
Tag master with latest
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-26 19:17:28 +02:00
1b81629ea2 Merge branch 'feature/max-artifact-size' of incubator/fling into master
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-26 08:36:43 +00:00
9b7426287f Merge branch '0.1' of incubator/fling into master
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-26 00:51:52 +00:00
17 changed files with 145 additions and 23 deletions

View file

@ -74,12 +74,13 @@ 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 - name: publish branch
image: plugins/docker image: plugins/docker
settings: settings:
username: username:
@ -92,6 +93,29 @@ 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 Normal file
View file

@ -0,0 +1,68 @@
**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.

View file

@ -2,7 +2,11 @@ FROM alpine:latest
ARG VERSION ARG VERSION
RUN apk add --update --no-cache nginx openjdk11-jre && \ ENV FLING_API_BASE http://localhost:3000
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" && \
@ -14,7 +18,8 @@ RUN apk add --update --no-cache nginx openjdk11-jre && \
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 ./entrypoint.sh ./usr/local/bin/entrypoint.sh COPY ./var/www/fling/config.js.template /var/www/fling/config.js.template
COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
VOLUME /var/fling/ VOLUME /var/fling/

View file

@ -6,4 +6,6 @@ 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

View file

@ -61,6 +61,23 @@ 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 / {

View file

@ -0,0 +1,5 @@
window['flingconfig'] = {
API_BASE: "${FLING_API_BASE}",
LOG_LEVEL: "${FLING_LOG_LEVEL}",
FILESIZE: "${FLING_FILESIZE}"
}

View file

@ -20,7 +20,8 @@ fling:
archive.filesystem.archive-path: "/var/fling/files" archive.filesystem.archive-path: "/var/fling/files"
security: security:
allowed-origins: allowed-origins:
- "https://friedl.net" - "https://fling.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"
@ -31,4 +32,4 @@ fling:
api: api:
version: "0.1.0-snapshot" version: "0.1.0-snapshot"
server-url: "http://localhost:8080" server-url: "http://localhost:8080"
server-description: "API server for dev" server-description: "API server for dev"

View file

@ -1,3 +1,3 @@
REACT_APP_API=https://fling.friedl.net REACT_APP_API=http://localhost:3000
REACT_APP_LOGLEVEL=warn REACT_APP_LOGLEVEL=warn
REACT_APP_FILESIZE=209715200 REACT_APP_FILESIZE=209715200

View file

@ -0,0 +1,5 @@
window['flingconfig'] = {
API_BASE: "http://localhost:8080",
LOG_LEVEL: "warn",
FILESIZE: 209715200
}

View file

@ -4,6 +4,7 @@
<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.

View file

@ -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 = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/artifacts/${props.artifact.id}/data?derivedToken=${token}`; let url = `${window['flingconfig'].API_BASE.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);

View file

@ -23,12 +23,6 @@ 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>

View file

@ -82,7 +82,7 @@ export default function Upload() {
stopEvent(ev); stopEvent(ev);
ev.persist(); ev.persist();
let maxSize = process.env.REACT_APP_FILESIZE; let maxSize = window['flingconfig'].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(process.env.REACT_APP_FILESIZE)}`}</span> <span className="total-upload">{`Max: ${prettifyBytes(window['flingconfig'].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>

View file

@ -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 = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`; let url = `${window['flingconfig'].API_BASE.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 = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`; let url = `${window['flingconfig'].API_BASE.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);

View file

@ -123,7 +123,7 @@ function Upload(props) {
stopEvent(ev); stopEvent(ev);
ev.persist(); ev.persist();
let maxSize = process.env.REACT_APP_FILESIZE; let maxSize = window['flingconfig'].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(process.env.REACT_APP_FILESIZE)}`}</span> <span className="total-upload">{`Max: ${prettifyBytes(window['flingconfig'].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 = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`; let url = `${window['flingconfig'].API_BASE.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);

View file

@ -21,8 +21,8 @@ import * as serviceWorker from './serviceWorker';
/* Logging Setup */ /* Logging Setup */
log.setDefaultLevel(log.levels.TRACE); log.setDefaultLevel(log.levels.TRACE);
if (process.env.REACT_APP_LOGLEVEL) { if (window['flingconfig'].LOG_LEVEL) {
log.setLevel(process.env.REACT_APP_LOGLEVEL); log.setLevel(window['flingconfig'].LOG_LEVEL);
} }
/* Store setup */ /* Store setup */

View file

@ -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 = process.env.REACT_APP_API.replace(/\/+$/, ''); config.basePath = window['flingconfig'].API_BASE.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; }