minor fixes

master
subhra74 2019-07-05 13:26:10 +02:00
parent e472260de0
commit 678d1b444f
14 changed files with 747 additions and 718 deletions

View File

@ -1,312 +1,317 @@
/**
*
*/
package webshell.app;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import webshell.app.config.ConfigManager;
import webshell.app.files.FileOperations;
import webshell.app.files.FileService;
import webshell.app.files.FileTransfer;
import webshell.app.files.PosixPermission;
import webshell.app.files.copy.FileCopyProgressResponse;
import webshell.app.files.copy.FileCopyRequest;
import webshell.app.files.search.SearchResult;
import webshell.app.terminal.PtySession;
/**
* @author subhro
*
*/
@RestController
@CrossOrigin(allowCredentials = "true")
@RequestMapping("/api")
public class AppController {
@Autowired
private FileService service;
@Autowired
private FileOperations fs;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@PostMapping("/app/terminal/{appId}/resize")
public void resizePty(@PathVariable String appId,
@RequestBody Map<String, Integer> body) {
AppContext.INSTANCES.get(appId).resizePty(body.get("row"),
body.get("col"));
}
@PostMapping("/app/terminal")
public Map<String, String> createTerminal() throws Exception {
PtySession pty = new PtySession();
AppContext.INSTANCES.put(pty.getId(), pty);
Map<String, String> map = new HashMap<String, String>();
map.put("id", pty.getId());
return map;
}
@GetMapping("/app/files/home")
public Map<String, Object> listHome() throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("files", service.list(System.getProperty("user.home")));
map.put("folder", System.getProperty("user.home"));
map.put("folderName",
new File(System.getProperty("user.home")).getName());
return map;
}
@GetMapping("/app/files/list/{path}")
public Map<String, Object> list(@PathVariable String path)
throws Exception {
Map<String, Object> map = new HashMap<>();
String folder = null;
if (path == null) {
folder = System.getProperty("user.home");
} else {
folder = new String(Base64.getDecoder().decode(path), "utf-8");
}
System.out.println("base64: " + path + " " + folder);
map.put("files", service.list(folder));
map.put("folder", folder);
map.put("folderName", new File(folder).getName());
return map;
}
@GetMapping("/app/files/up/{path}")
public Map<String, Object> up(@PathVariable String path) throws Exception {
Map<String, Object> map = new HashMap<>();
path = new String(Base64.getDecoder().decode(path), "utf-8");
if (!path.equals("/")) {
path = new File(path).getParent();
}
map.put("files", service.list(path));
map.put("folder", path);
map.put("folderName", new File(path).getName());
return map;
}
@PostMapping("/app/upload/{folder}/{relativePath}")
public void upload(@PathVariable String folder,
@PathVariable String relativePath, HttpServletRequest request)
throws Exception {
System.out.println("uploading...");
try {
folder = new String(Base64.getDecoder().decode(folder), "utf-8");
relativePath = new String(Base64.getDecoder().decode(relativePath),
"utf-8");
FileTransfer fs = new FileTransfer(false);
fs.transferFile(relativePath, folder, request.getInputStream());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@GetMapping("/app/folder/tree/home")
public List<Map<String, ?>> listTreeHome() {
List<Map<String, ?>> list = new ArrayList<>();
File f = new File(System.getProperty("user.home"));
File[] files = f.listFiles();
if (files != null && files.length > 0) {
for (File file : files) {
Map<String, Object> entry = new HashMap<>();
entry.put("name", file.getName());
entry.put("path", file.getAbsolutePath());
entry.put("leafNode", !file.isDirectory());
list.add(entry);
}
}
return list;
}
@GetMapping("/app/folder/tree/path/{encodedPath}")
public List<Map<String, ?>> listTreePath(@PathVariable String encodedPath)
throws Exception {
String path = new String(Base64.getDecoder().decode(encodedPath),
"utf-8");
List<Map<String, ?>> list = new ArrayList<>();
File f = new File(path);
File[] files = f.listFiles();
if (files != null && files.length > 0) {
for (File file : files) {
Map<String, Object> entry = new HashMap<>();
entry.put("name", file.getName());
entry.put("path", file.getAbsolutePath());
entry.put("leafNode", !file.isDirectory());
list.add(entry);
}
}
return list;
}
@GetMapping("/app/folder/tree/fs")
public List<Map<String, ?>> listFsRoots() throws Exception {
List<Map<String, ?>> list = new ArrayList<>();
File[] files = File.listRoots();
if (files != null && files.length > 0) {
for (File file : files) {
Map<String, Object> entry = new HashMap<>();
System.out.println("Root: " + file.getName());
entry.put("name", file.getAbsolutePath());
entry.put("path", file.getAbsolutePath());
entry.put("leafNode", !file.isDirectory());
list.add(entry);
}
}
return list;
}
@PostMapping("/app/fs/{mode}")
public Map<String, String> startCopyOrMove(@PathVariable String mode,
@RequestBody FileCopyRequest request) {
List<String> sourceFile = request.getSourceFile();
String targetFolder = request.getTargetFolder();
Map<String, String> map = new HashMap<>();
String id = fs.createFileCopyTask(sourceFile, targetFolder,
"move".equals(mode));
map.put("id", id);
map.put("name", fs.getOpName(id));
return map;
}
@PostMapping("/app/fs/progress")
public List<FileCopyProgressResponse> getProgress(
@RequestBody List<String> idList) {
return fs.getProgress(idList);
}
@PostMapping("/app/fs/cancel/{id}")
public void cancel(@PathVariable String id) {
fs.cancelTask(id);
}
@PostMapping("/app/fs/rename")
public void rename(@RequestBody Map<String, String> body)
throws IOException {
fs.rename(body.get("oldName"), body.get("newName"), body.get("folder"));
}
@PostMapping("/app/fs/delete")
public void delete(@RequestBody List<String> body) throws IOException {
fs.deleteFiles(body);
}
@GetMapping("/app/fs/files/{encodedPath}")
public String getText(@PathVariable String encodedPath) throws Exception {
return service
.getText(new String(Base64.getDecoder().decode(encodedPath)));
}
@PostMapping("/app/fs/files/{encodedPath}")
public void setText(@PathVariable String encodedPath,
@RequestBody String body) throws Exception {
service.setText(new String(Base64.getDecoder().decode(encodedPath)),
body);
}
@PostMapping("/app/fs/search")
public Map<String, String> initSearch(
@RequestBody Map<String, String> request) {
String id = service.createSearch(request.get("folder"),
request.get("searchText"));
Map<String, String> response = new HashMap<String, String>();
response.put("id", id);
return response;
}
@DeleteMapping("/app/fs/search/{id}")
public void cancelSearch(@PathVariable String id) {
this.service.cancelSearch(id);
}
@GetMapping("/app/fs/search/{id}")
public SearchResult getSearchResult(@PathVariable String id,
@RequestParam(defaultValue = "0", required = false) int fileIndex,
@RequestParam(defaultValue = "0", required = false) int folderIndex) {
return this.service.getSearchResult(id, fileIndex, folderIndex);
}
@GetMapping("/app/fs/posix/{encodedPath}")
public PosixPermission getPosixPerm(@PathVariable String encodedPath)
throws Exception {
return this.fs.getPosixPermission(
new String(Base64.getDecoder().decode(encodedPath), "utf-8"));
}
@PostMapping("/app/fs/posix/{encodedPath}")
public void setPosixPerm(@PathVariable String encodedPath,
@RequestBody PosixPermission perm) throws Exception {
this.fs.setPosixPermission(
new String(Base64.getDecoder().decode(encodedPath), "utf-8"),
perm);
}
@GetMapping("/app/config")
public Map<String, String> getConfig() {
Map<String, String> map = new HashMap<>();
map.put("app.default-user", System.getProperty("app.default-user"));
map.put("app.default-pass", System.getProperty("app.default-pass"));
map.put("app.default-shell", System.getProperty("app.default-shell"));
return map;
}
@PostMapping("/app/config")
public void setConfig(@RequestBody Map<String, String> map)
throws IOException {
for (String key : map.keySet()) {
String val = map.get(key);
if (val != null && val.length() > 0) {
if (key.equals("app.default-pass")) {
System.setProperty(key, passwordEncoder.encode(val));
} else {
System.setProperty(key, val);
}
}
}
ConfigManager.saveUserDetails();
}
@PostMapping("/app/fs/mkdir")
public void mkdir(@RequestBody Map<String, String> map) throws Exception {
String dir = map.get("dir");
String name = map.get("name");
Path path = Paths.get(dir, name);
Files.createDirectories(path);
}
@PostMapping("/app/fs/touch")
public void touch(@RequestBody Map<String, String> map) throws Exception {
String dir = map.get("dir");
String name = map.get("name");
Path path = Paths.get(dir, name);
Files.createFile(path);
}
}
/**
*
*/
package webshell.app;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import webshell.app.config.ConfigManager;
import webshell.app.files.FileOperations;
import webshell.app.files.FileService;
import webshell.app.files.FileTransfer;
import webshell.app.files.PosixPermission;
import webshell.app.files.copy.FileCopyProgressResponse;
import webshell.app.files.copy.FileCopyRequest;
import webshell.app.files.search.SearchResult;
import webshell.app.terminal.PtySession;
/**
* @author subhro
*
*/
@RestController
@CrossOrigin(allowCredentials = "true")
@RequestMapping("/api")
public class AppController {
@Autowired
private FileService service;
@Autowired
private FileOperations fs;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@PostMapping("/app/terminal/{appId}/resize")
public void resizePty(@PathVariable String appId,
@RequestBody Map<String, Integer> body) {
AppContext.INSTANCES.get(appId).resizePty(body.get("row"),
body.get("col"));
}
@PostMapping("/app/terminal")
public Map<String, String> createTerminal() throws Exception {
PtySession pty = new PtySession();
AppContext.INSTANCES.put(pty.getId(), pty);
Map<String, String> map = new HashMap<String, String>();
map.put("id", pty.getId());
return map;
}
@GetMapping("/app/files/home")
public Map<String, Object> listHome() throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("files", service.list(System.getProperty("user.home")));
map.put("folder", System.getProperty("user.home"));
map.put("folderName",
new File(System.getProperty("user.home")).getName());
return map;
}
@GetMapping("/app/files/list/{path}")
public Map<String, Object> list(@PathVariable String path)
throws Exception {
Map<String, Object> map = new HashMap<>();
String folder = null;
if (path == null) {
folder = System.getProperty("user.home");
} else {
folder = new String(Base64.getDecoder().decode(path), "utf-8");
}
System.out.println("base64: " + path + " " + folder);
map.put("files", service.list(folder));
map.put("folder", folder);
map.put("folderName", new File(folder).getName());
return map;
}
@GetMapping("/app/files/up/{path}")
public Map<String, Object> up(@PathVariable String path) throws Exception {
Map<String, Object> map = new HashMap<>();
path = new String(Base64.getDecoder().decode(path), "utf-8");
if (!path.equals("/")) {
path = new File(path).getParent();
}
map.put("files", service.list(path));
map.put("folder", path);
map.put("folderName", new File(path).getName());
return map;
}
@PostMapping("/app/upload/{folder}/{relativePath}")
public void upload(@PathVariable String folder,
@PathVariable String relativePath, HttpServletRequest request)
throws Exception {
System.out.println("uploading...");
try {
folder = new String(Base64.getDecoder().decode(folder), "utf-8");
relativePath = new String(Base64.getDecoder().decode(relativePath),
"utf-8");
FileTransfer fs = new FileTransfer(false);
fs.transferFile(relativePath, folder, request.getInputStream());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
@GetMapping("/app/folder/tree/home")
public List<Map<String, ?>> listTreeHome() {
List<Map<String, ?>> list = new ArrayList<>();
File f = new File(System.getProperty("user.home"));
File[] files = f.listFiles();
if (files != null && files.length > 0) {
for (File file : files) {
if (!file.isDirectory()) {
continue;
}
Map<String, Object> entry = new HashMap<>();
entry.put("name", file.getName());
entry.put("path", file.getAbsolutePath());
entry.put("leafNode", !file.isDirectory());
list.add(entry);
}
}
return list;
}
@GetMapping("/app/folder/tree/path/{encodedPath}")
public List<Map<String, ?>> listTreePath(@PathVariable String encodedPath)
throws Exception {
String path = new String(Base64.getDecoder().decode(encodedPath),
"utf-8");
List<Map<String, ?>> list = new ArrayList<>();
File f = new File(path);
File[] files = f.listFiles();
if (files != null && files.length > 0) {
for (File file : files) {
if (file.isDirectory()) {
Map<String, Object> entry = new HashMap<>();
entry.put("name", file.getName());
entry.put("path", file.getAbsolutePath());
entry.put("leafNode", !file.isDirectory());
list.add(entry);
}
}
}
return list;
}
@GetMapping("/app/folder/tree/fs")
public List<Map<String, ?>> listFsRoots() throws Exception {
List<Map<String, ?>> list = new ArrayList<>();
File[] files = File.listRoots();
if (files != null && files.length > 0) {
for (File file : files) {
Map<String, Object> entry = new HashMap<>();
System.out.println("Root: " + file.getName());
entry.put("name", file.getAbsolutePath());
entry.put("path", file.getAbsolutePath());
entry.put("leafNode", !file.isDirectory());
list.add(entry);
}
}
return list;
}
@PostMapping("/app/fs/{mode}")
public Map<String, String> startCopyOrMove(@PathVariable String mode,
@RequestBody FileCopyRequest request) {
List<String> sourceFile = request.getSourceFile();
String targetFolder = request.getTargetFolder();
Map<String, String> map = new HashMap<>();
String id = fs.createFileCopyTask(sourceFile, targetFolder,
"move".equals(mode));
map.put("id", id);
map.put("name", fs.getOpName(id));
return map;
}
@PostMapping("/app/fs/progress")
public List<FileCopyProgressResponse> getProgress(
@RequestBody List<String> idList) {
return fs.getProgress(idList);
}
@PostMapping("/app/fs/cancel/{id}")
public void cancel(@PathVariable String id) {
fs.cancelTask(id);
}
@PostMapping("/app/fs/rename")
public void rename(@RequestBody Map<String, String> body)
throws IOException {
fs.rename(body.get("oldName"), body.get("newName"), body.get("folder"));
}
@PostMapping("/app/fs/delete")
public void delete(@RequestBody List<String> body) throws IOException {
fs.deleteFiles(body);
}
@GetMapping("/app/fs/files/{encodedPath}")
public String getText(@PathVariable String encodedPath) throws Exception {
return service
.getText(new String(Base64.getDecoder().decode(encodedPath)));
}
@PostMapping("/app/fs/files/{encodedPath}")
public void setText(@PathVariable String encodedPath,
@RequestBody String body) throws Exception {
service.setText(new String(Base64.getDecoder().decode(encodedPath)),
body);
}
@PostMapping("/app/fs/search")
public Map<String, String> initSearch(
@RequestBody Map<String, String> request) {
String id = service.createSearch(request.get("folder"),
request.get("searchText"));
Map<String, String> response = new HashMap<String, String>();
response.put("id", id);
return response;
}
@DeleteMapping("/app/fs/search/{id}")
public void cancelSearch(@PathVariable String id) {
this.service.cancelSearch(id);
}
@GetMapping("/app/fs/search/{id}")
public SearchResult getSearchResult(@PathVariable String id,
@RequestParam(defaultValue = "0", required = false) int fileIndex,
@RequestParam(defaultValue = "0", required = false) int folderIndex) {
return this.service.getSearchResult(id, fileIndex, folderIndex);
}
@GetMapping("/app/fs/posix/{encodedPath}")
public PosixPermission getPosixPerm(@PathVariable String encodedPath)
throws Exception {
return this.fs.getPosixPermission(
new String(Base64.getDecoder().decode(encodedPath), "utf-8"));
}
@PostMapping("/app/fs/posix/{encodedPath}")
public void setPosixPerm(@PathVariable String encodedPath,
@RequestBody PosixPermission perm) throws Exception {
this.fs.setPosixPermission(
new String(Base64.getDecoder().decode(encodedPath), "utf-8"),
perm);
}
@GetMapping("/app/config")
public Map<String, String> getConfig() {
Map<String, String> map = new HashMap<>();
map.put("app.default-user", System.getProperty("app.default-user"));
map.put("app.default-pass", System.getProperty("app.default-pass"));
map.put("app.default-shell", System.getProperty("app.default-shell"));
return map;
}
@PostMapping("/app/config")
public void setConfig(@RequestBody Map<String, String> map)
throws IOException {
for (String key : map.keySet()) {
String val = map.get(key);
if (val != null && val.length() > 0) {
if (key.equals("app.default-pass")) {
System.setProperty(key, passwordEncoder.encode(val));
} else {
System.setProperty(key, val);
}
}
}
ConfigManager.saveUserDetails();
}
@PostMapping("/app/fs/mkdir")
public void mkdir(@RequestBody Map<String, String> map) throws Exception {
String dir = map.get("dir");
String name = map.get("name");
Path path = Paths.get(dir, name);
Files.createDirectories(path);
}
@PostMapping("/app/fs/touch")
public void touch(@RequestBody Map<String, String> map) throws Exception {
String dir = map.get("dir");
String name = map.get("name");
Path path = Paths.get(dir, name);
Files.createFile(path);
}
}

View File

@ -1,48 +1,45 @@
/**
*
*/
package webshell.app.files;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import webshell.app.files.search.SearchResult;
import webshell.app.files.search.SearchTask;
/**
* @author subhro
*
*/
@Component
public class SearchOperations {
private final Map<String, SearchTask> pendingOperations = new ConcurrentHashMap<>();
private final ExecutorService threadPool = Executors.newFixedThreadPool(5);
public String createSearchTask(String folder, String searchText) {
SearchTask task = new SearchTask(folder, searchText);
pendingOperations.put(task.getId(), task);
threadPool.submit(task);
return task.getId();
}
public SearchResult getSearchResult(String id, int fileIndex,
int folderIndex) {
SearchTask task = pendingOperations.get(id);
SearchResult res = new SearchResult(task.isDone(),
task.getFiles().stream().skip(fileIndex)
.collect(Collectors.toList()),
task.getFolders().stream().skip(folderIndex)
.collect(Collectors.toList()));
return res;
}
public void cancelSearch(String id) {
SearchTask task = pendingOperations.get(id);
task.stop();
}
}
/**
*
*/
package webshell.app.files;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import webshell.app.files.search.SearchResult;
import webshell.app.files.search.SearchTask;
/**
* @author subhro
*
*/
@Component
public class SearchOperations {
private final Map<String, SearchTask> pendingOperations = new ConcurrentHashMap<>();
private final ExecutorService threadPool = Executors.newFixedThreadPool(5);
public String createSearchTask(String folder, String searchText) {
SearchTask task = new SearchTask(folder, searchText);
pendingOperations.put(task.getId(), task);
threadPool.submit(task);
return task.getId();
}
public SearchResult getSearchResult(String id, int fileIndex,
int folderIndex) {
SearchTask task = pendingOperations.get(id);
SearchResult res = new SearchResult(task.isDone(), task.getFiles()
.stream().skip(fileIndex).collect(Collectors.toList()));
return res;
}
public void cancelSearch(String id) {
SearchTask task = pendingOperations.get(id);
task.stop();
}
}

View File

@ -1,71 +1,57 @@
/**
*
*/
package webshell.app.files.search;
import java.util.ArrayList;
import java.util.List;
/**
* @author subhro
*
*/
public class SearchResult {
/**
* @param isDone
* @param files
* @param folders
*/
public SearchResult(boolean isDone, List<String> files,
List<String> folders) {
super();
this.isDone = isDone;
this.files = files;
this.folders = folders;
}
private boolean isDone;
private List<String> files = new ArrayList<>(), folders = new ArrayList<>();
/**
* @return the isDone
*/
public boolean isDone() {
return isDone;
}
/**
* @param isDone the isDone to set
*/
public void setDone(boolean isDone) {
this.isDone = isDone;
}
/**
* @return the files
*/
public List<String> getFiles() {
return files;
}
/**
* @param files the files to set
*/
public void setFiles(List<String> files) {
this.files = files;
}
/**
* @return the folders
*/
public List<String> getFolders() {
return folders;
}
/**
* @param folders the folders to set
*/
public void setFolders(List<String> folders) {
this.folders = folders;
}
}
/**
*
*/
package webshell.app.files.search;
import java.util.ArrayList;
import java.util.List;
import webshell.app.files.FileInfo;
/**
* @author subhro
*
*/
public class SearchResult {
/**
* @param isDone
* @param files
* @param folders
*/
public SearchResult(boolean isDone, List<FileInfo> files) {
super();
this.isDone = isDone;
this.files = files;
}
private boolean isDone;
private List<FileInfo> files = new ArrayList<>();
/**
* @return the isDone
*/
public boolean isDone() {
return isDone;
}
/**
* @param isDone the isDone to set
*/
public void setDone(boolean isDone) {
this.isDone = isDone;
}
/**
* @return the files
*/
public List<FileInfo> getFiles() {
return files;
}
/**
* @param files the files to set
*/
public void setFiles(List<FileInfo> files) {
this.files = files;
}
}

View File

@ -1,206 +1,215 @@
/**
*
*/
package webshell.app.files.search;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author subhro
*
*/
public class SearchTask implements Runnable {
/**
* @param folder
* @param searchText
*/
public SearchTask(String folder, String searchText) {
super();
this.id = UUID.randomUUID().toString();
this.folder = folder;
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
}
private String id;
private AtomicBoolean isDone = new AtomicBoolean(false);
private List<String> files = new ArrayList<>(), folders = new ArrayList<>();
private String folder;
private String searchText;
private AtomicBoolean stopRequested = new AtomicBoolean(false);
/**
* @return the isDone
*/
public boolean isDone() {
return isDone.get();
}
/**
* @param isDone the isDone to set
*/
public void setDone(boolean isDone) {
this.isDone.set(isDone);
}
/**
* @return the files
*/
public List<String> getFiles() {
return files;
}
/**
* @param files the files to set
*/
public void setFiles(List<String> files) {
this.files = files;
}
/**
* @return the folders
*/
public List<String> getFolders() {
return folders;
}
/**
* @param folders the folders to set
*/
public void setFolders(List<String> folders) {
this.folders = folders;
}
/**
* @return the stopRequested
*/
public AtomicBoolean getStopRequested() {
return stopRequested;
}
/**
*
*/
public void stop() {
System.out.println("Stopping...");
this.stopRequested.set(true);
}
@Override
public void run() {
try {
System.out.println("Search start");
Files.walkFileTree(Paths.get(folder), new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
//System.out.println("Search: " + dir.toString());
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
if (isMatch(dir, searchText)) {
folders.add(dir.toAbsolutePath().toString());
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
//System.out.println("Search: " + file);
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
if (isMatch(file, searchText)) {
files.add(file.toAbsolutePath().toString());
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) throws IOException {
//System.out.println("visit failed: " + file);
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) throws IOException {
//System.out.println("post visit failed: " + dir);
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
private boolean isMatch(Path path, String text) {
String name = path.toString();
return name.toLowerCase(Locale.ENGLISH).contains(text);
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Search finished");
isDone.set(true);
}
/**
* @return the searchText
*/
public String getSearchText() {
return searchText;
}
/**
* @param searchText the searchText to set
*/
public void setSearchText(String searchText) {
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
}
/**
* @return the folder
*/
public String getFolder() {
return folder;
}
/**
* @param folder the folder to set
*/
public void setFolder(String folder) {
this.folder = folder;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
}
/**
*
*/
package webshell.app.files.search;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import webshell.app.files.FileInfo;
/**
* @author subhro
*
*/
public class SearchTask implements Runnable {
private boolean posix;
/**
* @param folder
* @param searchText
*/
public SearchTask(String folder, String searchText) {
super();
this.id = UUID.randomUUID().toString();
if (this.folder == null || this.folder.length() < 1) {
this.folder = System.getProperty("user.home");
} else {
this.folder = folder;
}
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
posix = !System.getProperty("os.name").toLowerCase()
.contains("windows");
}
private String id;
private AtomicBoolean isDone = new AtomicBoolean(false);
private List<FileInfo> files = Collections
.synchronizedList(new ArrayList<>());
private String folder;
private String searchText;
private AtomicBoolean stopRequested = new AtomicBoolean(false);
/**
* @return the isDone
*/
public boolean isDone() {
return isDone.get();
}
/**
* @param isDone the isDone to set
*/
public void setDone(boolean isDone) {
this.isDone.set(isDone);
}
/**
* @return the files
*/
public List<FileInfo> getFiles() {
return files;
}
/**
* @param files the files to set
*/
public void setFiles(List<FileInfo> files) {
this.files = files;
}
/**
* @return the stopRequested
*/
public AtomicBoolean getStopRequested() {
return stopRequested;
}
/**
*
*/
public void stop() {
System.out.println("Stopping...");
this.stopRequested.set(true);
}
@Override
public void run() {
try {
System.out.println("Search start");
Files.walkFileTree(Paths.get(folder), new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
// System.out.println("Search: " + dir.toString());
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
if (isMatch(dir, searchText)) {
File fdir = dir.toFile();
FileInfo info = new FileInfo(fdir.getName(),
fdir.getAbsolutePath(), "", "", "Directory", 0,
0, null, posix);
files.add(info);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
// System.out.println("Search: " + file);
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
if (isMatch(file, searchText)) {
File f = file.toFile();
FileInfo info = new FileInfo(f.getName(),
f.getAbsolutePath(), "", "", "File", 0, 0, null,
posix);
files.add(info);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) throws IOException {
// System.out.println("visit failed: " + file);
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) throws IOException {
// System.out.println("post visit failed: " + dir);
if (stopRequested.get()) {
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
private boolean isMatch(Path path, String text) {
String name = path.toString();
return name.toLowerCase(Locale.ENGLISH).contains(text);
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Search finished");
isDone.set(true);
}
/**
* @return the searchText
*/
public String getSearchText() {
return searchText;
}
/**
* @param searchText the searchText to set
*/
public void setSearchText(String searchText) {
this.searchText = searchText.toLowerCase(Locale.ENGLISH);
}
/**
* @return the folder
*/
public String getFolder() {
return folder;
}
/**
* @param folder the folder to set
*/
public void setFolder(String folder) {
this.folder = folder;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
}

View File

@ -11,6 +11,7 @@ import { EditorContext } from './model/editor-context';
import { FileOperationItem } from './model/file-operation-item';
import { SearchContext } from './model/search-context';
import { PosixPermissions } from './model/posix-permissions';
import { FileItem } from './model/file-item';
const MAX_ACTIVE_UPLOAD = 5;
@ -61,7 +62,7 @@ export class DataService {
leafNode: false
};
posix:boolean;
posix: boolean;
tabs: FolderTab[] = [];
selectedTab: number;
@ -73,6 +74,10 @@ export class DataService {
fileOpMonitor: any;
fileOpenRequests = new Subject<FileItem>();
currentViewChanger = new Subject<string>();
terminalSession: TerminalSession;
constructor(private http: HttpClient) {
@ -99,7 +104,7 @@ export class DataService {
return this.http.get<any>(environment.BASE_URL + "app/files/home");
}
public downloadFiles(folder: string, files: string, tempToken:string) {
public downloadFiles(folder: string, files: string, tempToken: string) {
window.location.href = environment.BIN_URL + "download?folder=" + btoa(folder) + "&files=" + btoa(files) + "&token=" + tempToken;
}
@ -393,7 +398,7 @@ export class DataService {
return this.http.post<any>(environment.BASE_URL + "app/fs/touch", { name, dir });
}
getTempToken():Observable<any> {
getTempToken(): Observable<any> {
return this.http.get<any>(environment.BASE_URL + "token/temp");
}

View File

@ -340,13 +340,13 @@
</div>
<!-- dropdown context menu end -->
<app-image-viewer [url]="getSelectedFile().path" *ngIf="previewer=='image'" (componentClosed)="previewer=null">
<app-image-viewer [url]="fileToOpen.path" *ngIf="previewer=='image'" (componentClosed)="previewer=null">
</app-image-viewer>
<app-media-player [url]="getSelectedFile().path" *ngIf="previewer=='video'" (componentClosed)="previewer=null">
<app-media-player [url]="fileToOpen.path" *ngIf="previewer=='video'" (componentClosed)="previewer=null">
</app-media-player>
<app-unsupported-content-viewer [url]="getSelectedFile().path" [file]="getSelectedFile().name"
<app-unsupported-content-viewer [url]="fileToOpen.path" [file]="fileToOpen.name"
*ngIf="previewer=='unsupported'" (componentClosed)="previewer=null" (onDownload)="downloadFiles()"
(onOpen)="openAsText();previewer=null">
(onOpen)="openWithTextEditor(fileToOpen.path);previewer=null">
</app-unsupported-content-viewer>
<div *ngIf="toastVisible"

View File

@ -36,6 +36,8 @@ export class FilesComponent implements OnInit, OnDestroy {
@Output()
viewChanged = new EventEmitter<string>();
fileToOpen:FileItem;
uploadPopup: boolean;
hoverIndex: number = -1;
showRenameDialog: boolean = false;
@ -57,6 +59,15 @@ export class FilesComponent implements OnInit, OnDestroy {
ngOnInit() {
console.log("File browser init")
this.posix = this.service.posix;
this.service.fileOpenRequests.subscribe((file: FileItem) => {
if (file.type == "Directory") {
this.navigateTo(file.path);
}else{
this.openItem(file);
}
});
if (this.service.tabs.length < 1) {
this.loading = true;
this.service.listHome().subscribe((data: any) => {
@ -105,6 +116,7 @@ export class FilesComponent implements OnInit, OnDestroy {
openItem(fileItem: FileItem) {
let file: string = fileItem.path;
this.loading = true;
this.fileToOpen=fileItem;
console.log("Opening file: " + file)
if (fileItem.type.startsWith("image")) {
this.previewer = "image";
@ -141,16 +153,16 @@ export class FilesComponent implements OnInit, OnDestroy {
});
}
openAsText() {
let file: string;
for (let i = 0; i < this.service.tabs[this.service.selectedTab].files.length; i++) {
if (this.service.tabs[this.service.selectedTab].files[i].selected) {
file = this.service.tabs[this.service.selectedTab].files[i].path;
this.openWithTextEditor(file);
break;
}
}
}
// openAsText() {
// let file: string;
// for (let i = 0; i < this.service.tabs[this.service.selectedTab].files.length; i++) {
// if (this.service.tabs[this.service.selectedTab].files[i].selected) {
// file = this.service.tabs[this.service.selectedTab].files[i].path;
// this.openWithTextEditor(file);
// break;
// }
// }
// }
navigateTo(file: string) {
this.loading = true;
@ -507,7 +519,7 @@ export class FilesComponent implements OnInit, OnDestroy {
}
}
this.loading = true;
if(!confirm("Are you sure, you want to delete?")){
if (!confirm("Are you sure, you want to delete?")) {
this.loading = false;
return;
}
@ -755,7 +767,7 @@ export class FilesComponent implements OnInit, OnDestroy {
return 'fa fa-file-pdf-o';
}
else if (file.type.startsWith("application/javascript") ||
file.type.includes("application/json")||
file.type.includes("application/json") ||
file.type.includes("application/xml")) {
return 'fa fa-file-text-o';
}

View File

@ -82,8 +82,10 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy {
}
onClick() {
console.log("tree clicked: " + this.model.path);
this.openInTab();
if (this.model.path) {
console.log("tree clicked: " + this.model.path);
this.openInTab();
}
}
onContextMenu(a: any, c: any) {
@ -140,5 +142,4 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy {
copyPath() {
console.log("copyPath " + this.model.path);
}
}

View File

@ -48,6 +48,9 @@ export class HomeComponent implements OnInit {
constructor(private router: Router, public service: DataService) { }
ngOnInit() {
this.service.currentViewChanger.subscribe((view: string) => {
this.view = view;
})
if (!this.service.terminalSession) {
this.service.connect().subscribe((data: any) => {
console.log("terminal created on server: " + JSON.stringify(data));
@ -62,7 +65,7 @@ export class HomeComponent implements OnInit {
let ws: WebSocket = instance.createSocket(data.id, this.service.getJwtToken());
ws.addEventListener('open', listener);
ws.addEventListener('error', err => {
console.log("Error: "+JSON.stringify(err));
console.log("Error: " + JSON.stringify(err));
});
});
} else {

View File

@ -37,18 +37,24 @@
</div>
<div *ngIf="ctx.searching" style="flex: 1; overflow: auto;">
<div>
<div *ngFor="let file of ctx.files" style="cursor: pointer;" (click)="openFile(file)">
<span style="padding: 5px; padding-left: 10px;"><i class="fa fa-file" aria-hidden="true"></i></span>
<span style="padding: 5px;">{{file}}</span>
<div *ngFor="let file of ctx.files" style="cursor: pointer; padding: 10px; overflow: hidden;" (click)="openFile(file)">
<div>
<span style="padding: 5px;" *ngIf="file.type=='Directory'"><i class="fa fa-folder" aria-hidden="true"></i></span>
<span style="padding: 5px;" *ngIf="file.type!='Directory'"><i class="fa fa-file" aria-hidden="true"></i></span>
<span style="padding: 5px;">{{file.name}}</span>
</div>
<div>
<span style="padding: 5px;">{{file.path}}</span>
</div>
</div>
<div *ngFor="let folder of ctx.folders" style="cursor: pointer;" (click)="openFolder(folder)">
<!-- <div *ngFor="let folder of ctx.folders" style="cursor: pointer;" (click)="openFolder(folder)">
<span style="padding: 5px; padding-left: 10px;">
<i class="fa fa-folder" aria-hidden="true"></i>
</span>
<span style="padding: 5px;">
{{folder}}
</span>
</div>
</div> -->
</div>
</div>
</div>

View File

@ -4,6 +4,7 @@ import { SearchContext } from 'src/app/model/search-context';
import { EditorContext } from 'src/app/model/editor-context';
import { utility } from '../../utility/utils';
import { Router } from '@angular/router';
import { FileItem } from 'src/app/model/file-item';
@Component({
selector: 'app-search',
@ -78,31 +79,33 @@ export class SearchComponent implements OnInit, OnDestroy {
});
}
openFile(file: string) {
this.loading = true;
console.log("Opening file: " + file)
this.service.getText(file).subscribe((text: string) => {
this.service.selectedEditorTab = file;
let ctx = new EditorContext(utility.getFileName(file), file, text);
ctx.session.setUseWrapMode(false);
this.service.editorContexts[file] = ctx;
this.loading = false;
console.log("before route init of editor: " + JSON.stringify(Object.keys(this.service.editorContexts)))
this.router.navigate(["/app/editor"]);
});
openFile(file: FileItem) {
this.service.fileOpenRequests.next(file);
this.service.currentViewChanger.next(null);
// this.loading = true;
// console.log("Opening file: " + file)
// this.service.getText(file).subscribe((text: string) => {
// this.service.selectedEditorTab = file;
// let ctx = new EditorContext(utility.getFileName(file), file, text);
// ctx.session.setUseWrapMode(false);
// this.service.editorContexts[file] = ctx;
// this.loading = false;
// console.log("before route init of editor: " + JSON.stringify(Object.keys(this.service.editorContexts)));
// this.router.navigate(["/app/editor"]);
// });
}
openFolder(folder: string) {
this.service.tabs.push({
files: null,
currentDirectory: folder,
selected: true,
folderName: utility.getFileName(folder),
posix: false
});
this.service.selectedTab = this.service.tabs.length - 1;
this.router.navigate(["/app/files"]);
}
// openFolder(folder: string) {
// this.service.tabs.push({
// files: null,
// currentDirectory: folder,
// selected: true,
// folderName: utility.getFileName(folder),
// posix: false
// });
// this.service.selectedTab = this.service.tabs.length - 1;
// this.router.navigate(["/app/files"]);
// }
getItemCount() {
let count = 0;

View File

@ -1,9 +1,11 @@
export class SearchContext {
id: string;
searchText: string;
files: string[]=[];
folders: string[]=[];
searching: boolean;
isDone: boolean;
folder: string;
import { FileItem } from './file-item';
export class SearchContext {
id: string;
searchText: string;
files: FileItem[]=[];
folders: FileItem[]=[];
searching: boolean;
isDone: boolean;
folder: string;
}

View File

@ -1,22 +1,22 @@
const GB = 1024 * 1024 * 1024;
const MB = 1024 * 1024;
const KB = 1024;
export const utility = {
getFileName(path: string): string {
let fragments = path.split(/\\|\//);
return fragments.pop();
},
formatSize(sz: number): string {
if (sz > GB) {
return (sz / GB).toFixed(1) + " GB";
} else if (sz > MB) {
return (sz / MB).toFixed(1) + " MB";
} else if (sz > KB) {
return (sz / KB).toFixed(1) + " KB";
} else {
return sz + " B";
}
}
const GB = 1024 * 1024 * 1024;
const MB = 1024 * 1024;
const KB = 1024;
export const utility = {
getFileName(path: string): string {
let fragments = path.split(/\\|\//);
return fragments.pop();
},
formatSize(sz: number): string {
if (sz > GB) {
return (sz / GB).toFixed(1) + " GB";
} else if (sz > MB) {
return (sz / MB).toFixed(1) + " MB";
} else if (sz > KB) {
return (sz / KB).toFixed(1) + " KB";
} else {
return sz + " B";
}
}
}

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebShellJs</title>
<title>Easy Web Shell</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">