package io.loli.sc.server.action;
import io.loli.sc.server.entity.ClientToken;
import io.loli.sc.server.entity.Gallery;
import io.loli.sc.server.entity.UploadedImage;
import io.loli.sc.server.entity.User;
import io.loli.sc.server.service.BucketService;
import io.loli.sc.server.service.ClientTokenService;
import io.loli.sc.server.service.FileFetchService;
import io.loli.sc.server.service.GalleryService;
import io.loli.sc.server.service.UploadedImageService;
import io.loli.sc.server.service.UserService;
import io.loli.sc.server.storage.StorageUploader;
import io.loli.util.string.MD5Util;
import io.loli.util.string.ShortUrl;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartFile;
/**
* 负责客户端登录验证和图片上传的类
*
* @author choco
*
*/
@Named
@RequestMapping(value = { "/api" })
public class ImageClientUpload {
@Inject
private ClientTokenService cts;
@Inject
@Named("userService")
private UserService us;
@Inject
private UploadedImageService uic;
@Inject
private GalleryService gs;
@Inject
@Named("fileFetchService")
private FileFetchService ffs;
private Logger logger = Logger.getLogger(ImageClientUpload.class);
private static final String LOCAL_HOST = "127.0.0.1";
@RequestMapping(value = { "/token" }, method = { RequestMethod.GET, RequestMethod.POST })
@ResponseStatus(HttpStatus.OK)
public @ResponseBody ClientToken requestToken(@RequestParam(required = true) String email,
@RequestParam(required = true) String password) {
User trueUser = us.findByEmail(email);
String token = null;
ClientToken ct = null;
// 验证密码是否正确
if (trueUser != null && trueUser.getPassword().equalsIgnoreCase(password)) {
ct = cts.findByEmail(email);
if (ct != null) {
// 当已有该email的token时,把token返回
token = ct.getToken();
logger.info(email + "已有token,将已经存在的token返回");
} else {
// 当没有该email的token时,新建一个token保存至数据库,然后返回
ct = new ClientToken();
// 用于md5加密的密文
String word = trueUser.getEmail() + new java.util.Date().getTime();
try {
token = MD5Util.hash(word);
} catch (NoSuchAlgorithmException e) {
logger.error(e);
}
ct.setToken(token);
ct.setUser(trueUser);
cts.save(ct);
logger.info(email + "生成新token");
}
return ct;
}
return new ClientToken();
}
@Inject
private BucketService bucketService;
@Inject
private UserService userService;
@RequestMapping(value = { "/upload" }, method = { RequestMethod.POST })
@ResponseStatus(HttpStatus.OK)
public @ResponseBody UploadedImage upload(@RequestParam(value = "token", required = false) String token,
@RequestParam(value = "email", required = false) String email,
@RequestParam(value = "desc", required = false) String desc,
@RequestParam(value = "image", required = true) MultipartFile imageFile, HttpServletRequest request,
@RequestParam(value = "type", required = false) String type,
@RequestParam(value = "gid", required = false) Integer gid) {
UploadedImage imageObj = new UploadedImage();
imageObj.setDate(new Date());
if (email == null && desc == null && token == null) {
imageObj.setDesc(imageFile.getOriginalFilename());
} else {
if (!cts.checkTokenBelongToUser(token, email)) {
logger.info(email + "使用错误的token上传");
return new UploadedImage();
} else {
imageObj.setUser(userService.findByEmail(email));
}
imageObj.setOriginName(desc);
}
User user = null;
if ((user = (User) request.getSession().getAttribute("user")) != null) {
imageObj.setUser(user);
}
if (gid != null) {
Gallery gal = gs.findById(gid);
imageObj.setGallery(gal);
}
String ip = request.getRemoteAddr();
if (ip != null && LOCAL_HOST.equals(ip)) {
ip = request.getHeader("X-Real-IP");
}
imageObj.setIp(ip);
imageObj.setUa(request.getHeader("user-agent"));
String contentType = imageFile.getContentType();
if (StringUtils.isNotBlank(contentType)) {
imageObj.setContentType(contentType);
}
String fileName = "";
fileName = getFileName(imageFile);
File file = saveImage(imageFile, fileName);
String ref = null;
if (StringUtils.isNotBlank(type)) {
} else if ((ref = request.getHeader("REFERER")) != null) {
if (ref.contains("file")) {
imageObj.setStorageBucket(bucketService.randomFileBucket());
} else {
imageObj.setStorageBucket(bucketService.randomImageBucket());
}
} else {
imageObj.setStorageBucket(bucketService.randomImageBucket());
}
StorageUploader uploader = StorageUploader.newInstance(imageObj.getStorageBucket());
imageObj.setPath(uploader.upload(file));
imageObj.setOriginName(imageFile.getOriginalFilename());
imageObj.setGeneratedName(file.getName());
imageObj.setRedirectCode(file.getName());
imageObj.setGeneratedCode(file.getName().contains(".") ? file.getName().substring(0,
file.getName().indexOf(".")) : file.getName());
imageObj.setInternalPath(imageObj.getStorageBucket().getInternalUrl() + "/" + file.getName());
uic.save(imageObj);
if (imageObj.getUser() == null) {
logger.info("匿名上传文件:" + imageObj.getOriginName() + ", 链接为" + imageObj.getPath());
} else {
logger.info(imageObj.getUser().getEmail() + "上传文件:" + imageObj.getOriginName() + ", 链接为"
+ imageObj.getPath());
}
service.execute(() -> {
uic.updateThumbnail(imageObj, file, uploader);
});
return imageObj;
}
private String getFileName(MultipartFile imageFile) {
String str = null;
try {
String[] urls = ShortUrl.shortText(new Date().getTime() + imageFile.getOriginalFilename(), 6);
for (String url : urls) {
if (!uic.checkExists(url)) {
return url;
}
}
str = MD5Util.hash(String.valueOf(System.nanoTime()));
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
private ExecutorService service = Executors.newFixedThreadPool(50);
@ResponseBody
@RequestMapping(value = { "/fetch" }, method = { RequestMethod.POST })
public String fetch(@RequestParam(value = "path") String path, HttpServletRequest request) {
if (StringUtils.isBlank(path)) {
return "{\"origin\":\"" + path + "\",\"error\":\"" + "图片url不能为空" + "\",\"redirect\":\"" + "\"}";
}
File file = null;
Future<File> future = service.submit(() -> {
return ffs.fetch(path);
});
try {
file = future.get(20, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
logger.error("Fetch image timeout:" + e);
return "{\"origin\":\"" + path + "\",\"error\":\"" + e.getMessage() + "\",\"redirect\":\"" + "\"}";
}
if (file == null) {
return "";
}
try {
User user = null;
UploadedImage imageObj = new UploadedImage();
if ((user = (User) request.getSession().getAttribute("user")) != null) {
imageObj.setUser(user);
}
String ip = request.getRemoteAddr();
if (ip != null && ip.equals("127.0.0.1")) {
ip = request.getHeader("X-Real-IP");
}
imageObj.setIp(ip);
imageObj.setUa(request.getHeader("user-agent"));
String ref = null;
if ((ref = request.getHeader("REFERER")) != null) {
if (ref.contains("file")) {
imageObj.setStorageBucket(bucketService.randomFileBucket());
} else {
imageObj.setStorageBucket(bucketService.randomImageBucket());
}
} else {
imageObj.setStorageBucket(bucketService.randomImageBucket());
}
StorageUploader uploader = StorageUploader.newInstance(imageObj.getStorageBucket());
imageObj.setPath(uploader.upload(file));
imageObj.setOriginName(file.getName());
imageObj.setGeneratedName(file.getName());
imageObj.setRedirectCode(file.getName());
imageObj.setGeneratedCode(file.getName().contains(".") ? file.getName().substring(0,
file.getName().indexOf(".")) : file.getName());
imageObj.setInternalPath(imageObj.getStorageBucket().getInternalUrl() + "/" + file.getName());
uic.save(imageObj);
if (imageObj.getUser() == null) {
logger.info("匿名上传文件:" + imageObj.getOriginName() + ", 链接为" + imageObj.getPath());
} else {
logger.info(imageObj.getUser().getEmail() + "上传文件:" + imageObj.getOriginName() + ", 链接为"
+ imageObj.getPath());
}
return "{\"origin\":\"" + path + "\",\"error\":\"" + "\",\"redirect\":\"" + imageObj.getRedirectCode()
+ "\"}";
} catch (Exception e) {
return "{\"origin\":\"" + path + "\",\"error\":\"" + e.getMessage() + "\",\"redirect\":\"" + "\"}";
}
}
/**
* 将一个图片保存起来
*
* @param image
* @return 保存后的图片File对象
*/
private File saveImage(MultipartFile image, String fileName) {
if (image.getOriginalFilename().contains(".")) {
// 获取图片扩展名,jpg,png
fileName += "."
+ image.getOriginalFilename().substring(image.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
}
File file = new File(System.getProperty("java.io.tmpdir"), fileName);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdir();
}
try {
FileUtils.writeByteArrayToFile(file, image.getBytes());
} catch (IOException e) {
e.printStackTrace();
logger.error(e);
}
return file;
}
}