Merge pull request #29 from xetorthio/drag_and_drop_uploads

Allow to drag & drop file uploads to instances
This commit is contained in:
Marcos Nils
2017-07-10 19:00:49 -03:00
committed by GitHub
8 changed files with 66 additions and 15 deletions

View File

@@ -2,3 +2,4 @@ export PS1='\e[1m\e[31m[\h] \e[32m($(docker-prompt)) \e[34m\u@$(hostname -i)\e[3
alias vi='vim'
export PATH=$PATH:/root/go/bin
cat /etc/motd
echo $BASHPID > /var/run/cwd

View File

@@ -4,6 +4,7 @@ import (
"io"
"log"
"net/http"
"path/filepath"
"github.com/gorilla/mux"
)
@@ -20,7 +21,10 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) {
// has a url query parameter, ignore body
if url := req.URL.Query().Get("url"); url != "" {
err := core.InstanceUploadFromUrl(i, req.URL.Query().Get("url"))
_, fileName := filepath.Split(url)
err := core.InstanceUploadFromUrl(i, fileName, "", req.URL.Query().Get("url"))
if err != nil {
log.Println(err)
rw.WriteHeader(http.StatusInternalServerError)
@@ -35,6 +39,8 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusBadRequest)
return
}
path := req.URL.Query().Get("path")
for {
p, err := red.NextPart()
if err == io.EOF {
@@ -48,12 +54,13 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) {
if p.FileName() == "" {
continue
}
err = core.InstanceUploadFromReader(i, p.FileName(), p)
err = core.InstanceUploadFromReader(i, p.FileName(), path, p)
if err != nil {
log.Println(err)
rw.WriteHeader(http.StatusInternalServerError)
return
}
log.Printf("Uploaded [%s] to [%s]\n", p.FileName(), i.Name)
}
rw.WriteHeader(http.StatusOK)

View File

@@ -1,6 +1,7 @@
package pwd
import (
"bytes"
"fmt"
"io"
"log"
@@ -59,7 +60,7 @@ func (p *pwd) InstanceAttachTerminal(instance *types.Instance) error {
return nil
}
func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, url string) error {
func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, fileName, dest string, url string) error {
defer observeAction("InstanceUploadFromUrl", time.Now())
log.Printf("Downloading file [%s]\n", url)
resp, err := http.Get(url)
@@ -71,9 +72,7 @@ func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, url string) error
return fmt.Errorf("Could not download file [%s]. Status code: %d\n", url, resp.StatusCode)
}
_, fileName := filepath.Split(url)
copyErr := p.docker.CopyToContainer(instance.Name, "/var/run/pwd/uploads", fileName, resp.Body)
copyErr := p.docker.CopyToContainer(instance.Name, dest, fileName, resp.Body)
if copyErr != nil {
return fmt.Errorf("Error while downloading file [%s]. Error: %s\n", url, copyErr)
@@ -82,10 +81,36 @@ func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, url string) error
return nil
}
func (p *pwd) InstanceUploadFromReader(instance *types.Instance, fileName string, reader io.Reader) error {
func (p *pwd) getInstanceCWD(instance *types.Instance) (string, error) {
b := bytes.NewBufferString("")
if c, err := p.docker.ExecAttach(instance.Name, []string{"bash", "-c", `pwdx $(</var/run/cwd)`}, b); c > 0 {
log.Println(b.String())
return "", fmt.Errorf("Error %d trying to get CWD", c)
} else if err != nil {
return "", err
}
cwd := strings.TrimSpace(strings.Split(b.String(), ":")[1])
return cwd, nil
}
func (p *pwd) InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error {
defer observeAction("InstanceUploadFromReader", time.Now())
copyErr := p.docker.CopyToContainer(instance.Name, "/var/run/pwd/uploads", fileName, reader)
var finalDest string
if filepath.IsAbs(dest) {
finalDest = dest
} else {
if cwd, err := p.getInstanceCWD(instance); err != nil {
return err
} else {
finalDest = fmt.Sprintf("%s/%s", cwd, dest)
}
}
copyErr := p.docker.CopyToContainer(instance.Name, finalDest, fileName, reader)
if copyErr != nil {
return fmt.Errorf("Error while uploading file [%s]. Error: %s\n", fileName, copyErr)

View File

@@ -60,8 +60,8 @@ type PWDApi interface {
InstanceNew(session *types.Session, conf InstanceConfig) (*types.Instance, error)
InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error
InstanceAttachTerminal(instance *types.Instance) error
InstanceUploadFromUrl(instance *types.Instance, url string) error
InstanceUploadFromReader(instance *types.Instance, filename string, reader io.Reader) error
InstanceUploadFromUrl(instance *types.Instance, fileName, dest, url string) error
InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error
InstanceGet(session *types.Session, name string) *types.Instance
InstanceFindByIP(ip string) *types.Instance
InstanceFindByAlias(sessionPrefix, alias string) *types.Instance

View File

@@ -5,6 +5,7 @@ import (
"log"
"math"
"path"
"path/filepath"
"strings"
"sync"
"time"
@@ -152,13 +153,15 @@ func (p *pwd) SessionDeployStack(s *types.Session) error {
log.Printf("Error creating instance for stack [%s]: %s\n", s.Stack, err)
return err
}
err = p.InstanceUploadFromUrl(i, s.Stack)
_, fileName := filepath.Split(s.Stack)
err = p.InstanceUploadFromUrl(i, fileName, "/var/run/pwd/uploads", s.Stack)
if err != nil {
log.Printf("Error uploading stack file [%s]: %s\n", s.Stack, err)
return err
}
fileName := path.Base(s.Stack)
fileName = path.Base(s.Stack)
file := fmt.Sprintf("/var/run/pwd/uploads/%s", fileName)
cmd := fmt.Sprintf("docker swarm init --advertise-addr eth0 && docker-compose -f %s pull && docker stack deploy -c %s %s", file, file, s.StackName)

View File

@@ -1,7 +1,7 @@
(function() {
'use strict';
var app = angular.module('DockerPlay', ['ngMaterial']);
var app = angular.module('DockerPlay', ['ngMaterial', 'ngFileUpload']);
// Automatically redirects user to a new session when bypassing captcha.
// Controller keeps code/logic separate from the HTML
@@ -19,7 +19,7 @@
}
}
app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', '$window', 'TerminalService', 'KeyboardShortcutService', 'InstanceService', 'SessionService', function($scope, $log, $http, $location, $timeout, $mdDialog, $window, TerminalService, KeyboardShortcutService, InstanceService, SessionService) {
app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', '$window', 'TerminalService', 'KeyboardShortcutService', 'InstanceService', 'SessionService', 'Upload', function($scope, $log, $http, $location, $timeout, $mdDialog, $window, TerminalService, KeyboardShortcutService, InstanceService, SessionService, Upload) {
$scope.sessionId = SessionService.getCurrentSessionId();
$scope.instances = [];
$scope.idx = {};
@@ -32,6 +32,14 @@
$scope.deleteInstanceBtnText = 'Delete';
$scope.isInstanceBeingDeleted = false;
$scope.uploadFiles = function (files) {
if (files && files.length) {
for (var i = 0; i < files.length; i++) {
Upload.upload({url: '/sessions/' + $scope.sessionId + '/instances/' + $scope.selectedInstance.name + '/uploads', data: {file: files[i]}, method: 'POST'});
}
}
}
var selectedKeyboardShortcuts = KeyboardShortcutService.getCurrentShortcuts();
angular.element($window).bind('resize', function() {

View File

@@ -62,3 +62,7 @@ md-input-container .md-errors-spacer {
.md-mini {
min-width: 24px;
}
.dragover {
opacity: 0.5;
}

View File

@@ -72,7 +72,7 @@
<div flex></div>
</md-content>
<md-content flex layout="column" ng-repeat="instance in instances" ng-show="instance.name == selectedInstance.name">
<md-content flex layout="column" ng-repeat="instance in instances" ng-show="instance.name == selectedInstance.name" ngf-drop="uploadFiles($files)" class="drop-box" ngf-drag-over-class="'dragover'" ngf-multiple="true">
<md-card class="stats" md-theme="default" md-theme-watch>
<md-card-title>
<md-card-title-text>
@@ -272,6 +272,9 @@
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/danialfarid-angular-file-upload/12.2.13/ng-file-upload-all.min.js" integrity="sha256-LrZq3efIkFX0BooX7x/rjWyYDvMKfFV2HJpy6HBw7cE=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.js"></script>
<script src="/assets/app.js"></script>
<script src="/assets/xterm.js"></script>