Files
desktop-app/node_modules/file.js
2015-12-18 16:50:34 +08:00

749 lines
20 KiB
JavaScript

var db = require('db');
var dbClient = require('db_client');
var fs = require('fs');
var crypto = require('crypto');
var needle = require('needle');
var path = require('path');
var Evt = require('evt');
var User = require('user');
var Common = require('common');
var Images = dbClient.images;
var Attachs = db.attachs;
var Web = require('web');
function log(o) {
console.trace(o);
}
/*
type File struct {
FileId bson.ObjectId `bson:"_id,omitempty"` //
UserId bson.ObjectId `bson:"UserId"`
AlbumId bson.ObjectId `bson:"AlbumId"`
Name string `Name` // file name
Title string `Title` // file name or user defined for search
Size int64 `Size` // file size (byte)
Type string `Type` // file type, "" = image, "doc" = word
Path string `Path` // the file path
IsDefaultAlbum bool `IsDefaultAlbum`
CreatedTime time.Time `CreatedTime`
FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
}
*/
// 文件服务
var File = {
// 将base64字符串写入文件中, 为导入笔记
writeBase64: function(data, isImage, type, fileTitle, callback) {
var me = this;
var filename = Common.uuid() + '.' + type;
if(isImage) {
var basePath = User.getCurUserImagesPath();
} else {
var basePath = User.getCurUserAttachsPath();
}
var filePath = basePath + '/' + filename;
// test
// return callback && callback({FileId: Common.objectId(), IsImage: true});
// return;
try {
var bf = new Buffer(data, 'base64');
var err = fs.writeFileSync(filePath, bf);
if(err) {
return callback(false);
}
// 得到文件的hash
var hash = crypto.createHash('md5');
hash.setEncoding('hex');
hash.write(bf);
hash.end();
var fileHash = hash.read();
if(isImage) {
me._addImage(Common.objectId(), filePath, function(newImg) {
newImg.IsImage = true;
newImg.hash = fileHash;
callback && callback(newImg);
});
} else {
me._addAttach(filePath, fileTitle, function(attach) {
attach.hash = fileHash;
callback && callback(attach);
});
}
/*
// var buf = new Buffer(data, 'utf-8');
// 读出来
var err = fs.writeFile(filePath, data, 'ascii');
if(err) {
console.log(err);
callback(false);
return;
}
*/
/*
var exec = require('child_process').exec,
last = exec('"/Users/life/Documents/kuaipan/go/go-study/bin/file2" "' + txtPath + '" "' + filePath + '"');
// last = exec('ls /');
// last.stdout.on('data', function (data) {
// console.log('标准输出:' + data);
// });
last.on('exit', function (code) {
console.log('子进程已关闭,代码:' + code);
fs.unlink(txtPath);
if(!code) {
if(isImage) {
me._addImage(Common.objectId(), filePath, function(newImg) {
newImg.IsImage = true;
callback && callback(newImg);
});
} else {
me._addAttach(filePath, fileTitle, callback)
}
} else {
callback(false);
}
});
*/
/*
// console.log(txtPath);
// console.log(filePath);
// 先写到txt中去, 然后调用命令将.txt -> img
var txtPath = filePath + '.txt';
var err = fs.writeFileSync(txtPath, data);
Common.cmd([txtPath, filePath], function(code) {
// console.log('子进程已关闭,代码:' + code);
// fs.unlink(txtPath);
if(!code) {
try {
if(isImage) {
me._addImage(Common.objectId(), filePath, function(newImg) {
newImg.IsImage = true;
callback && callback(newImg);
});
} else {
me._addAttach(filePath, fileTitle, callback)
}
} catch(e) {
console.log(e);
callback(false);
}
} else {
callback(false);
}
});
*/
// return callback && callback({FileId: Common.objectId(), IsImage: true});
} catch(e) {
console.log("error!!!");
console.error(e);
}
},
getFileBase64: function(filePath) {
try {
// read binary data
var bitmap = fs.readFileSync(filePath);
if (!bitmap) {
return '';
}
return new Buffer(bitmap).toString('base64');
} catch(e) {
return '';
}
},
getFileBase64AndMd5: function(filePath) {
try {
// read binary data
var bitmap = fs.readFileSync(filePath);
if (!bitmap) {
return '';
}
var base64 = new Buffer(bitmap).toString('base64');
var hash = crypto.createHash('md5');
hash.setEncoding('hex');
hash.write(bitmap);
hash.end();
var md5 = hash.read();
return {base64: base64, md5: md5}
} catch(e) {
return '';
}
},
getFileMd5: function (filePath) {
try {
var bitmap = fs.readFileSync(filePath);
if (!bitmap) {
return;
}
var hash = crypto.createHash('md5');
hash.setEncoding('hex');
hash.write(bitmap);
hash.end();
return hash.read();
} catch(e) {
return '';
}
},
mines: {
"gif": "image/gif",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"css": "text/css",
"html": "text/html",
"ico": "image/x-icon",
"js": "text/javascript",
"json": "application/json",
"pdf": "application/pdf",
"svg": "image/svg+xml",
"swf": "application/x-shockwave-flash",
"tiff": "image/tiff",
"txt": "text/plain",
"wav": "audio/x-wav",
"wma": "audio/x-ms-wma",
"wmv": "video/x-ms-wmv",
"xml": "text/xml"
},
getFileType: function (ext) {
if (!ext) {
return;
}
ext = ext.toLowerCase();
var type = this.mines[ext];
if (type) {
return type;
}
return ext;
},
_addAttach: function(filePath, fileTitle, callback) {
try {
var fileStat = fs.statSync(filePath);
} catch(e) {
callback(false);
return;
}
var paths = filePath.split(Common.getPathSep()); // windows的filePath不同
var name = paths[paths.length-1];
// Web.alertWeb(name);
var names = name.split('.');
var ext = names[names.length-1];
var attach = {
FileId: Common.objectId(),
ServerFileId: '',
Path: filePath,
NoteId: '',
Name: name,
UserId: User.getCurActiveUserId(),
Title: fileTitle,
IsDirty: true, // 先添加的肯定是dirty, 什么时候不是dirty ? sync 和 send changes后
Type: ext,
Size: fileStat && fileStat.size,
IsDirty: true, // 本地是新添加的, ServerFileId = 0
CreatedTime: new Date()
};
db.attachs.insert(attach);
callback && callback(attach);
},
// data在web端获取到, 在nodejs端会有错误!!
pasteImage2: function(data, callback) {
var me = this;
data = data.replace(/^data:image\/\w+;base64,/, "");
// log(User.getCurUserImagesPath());
var filename = Common.uuid() + '.png';
var filePath = User.getCurUserImagesPath() + '/' + filename;
console.log(filePath);
// return;
fs.writeFile(filePath, new Buffer(data, 'base64'), function(err) {
if(err) {
console.log(err);
return;
}
// return;
// 保存
// var relativePath = User.getCurUserImagesAppPath() + '/' + filename;
// 保存到数据库中
me._addImage(Common.objectId(), filePath, function(newImg) {
callback && callback(Evt.getImageLocalUrl(newImg.FileId));
});
});
},
// FileReaderWeb 是 web上的FileReader, 可能与nodejs这个有冲突
pasteImage: function(event, FileReaderWeb, callback) {
var me = this;
var items = (event.clipboardData || event.originalEvent.clipboardData).items; // 可能有多个file, 找到属于图片的file
// find pasted image among pasted items
var blob;
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") === 0) {
blob = items[i].getAsFile();
}
}
// console.log("paste images");
console.log(blob);
// load image if there is a pasted image
if (blob) {
try {
// console.log("??");
var reader = new FileReaderWeb();
// console.log(">>")
// return;
// console.log(">>")
/*
reader.onloadend = function() {
console.log(reader);
// 这个事件在读取结束后,无论成功或者失败都会触发
if (reader.error) {
console.log(reader.error);
} else {
}
};
console.log("-----------");
reader.onload = function(e) {
// alert(3);
console.log('haha');
return;
// 上传之
// log('result');
// log(reader.result);
var ret = reader.result;
ret = ret.replace(/^data:image\/\w+;base64,/, "");
console.log(ret);
return;
// log(User.getCurUserImagesPath());
var filename = Common.uuid() + '.png';
var filePath = User.getCurUserImagesPath() + '/' + filename;
console.log(filePath);
return;
fs.writeFile(filePath, new Buffer(ret, 'base64'), function(err) {
if(err) {
log(err);
return;
}
// 保存
// var relativePath = User.getCurUserImagesAppPath() + '/' + filename;
// 保存到数据库中
File.addImage(filePath, function(newImg) {
callback && callback(Evt.getImageLocalUrl(newImg.FileId));
// callback && callback('app://leanote/' + relativePath);
});
});
};
*/
console.log(reader);
console.log("??");
reader.onloadend = function() {
console.log('end');
console.log(reader.result);
};
reader.readAsDataURL(blob);
} catch(e) {
console.log(e);
}
};
},
// path是相对于项目路径
addImage: function(path, callback) {
var me = this;
var absolutePath = Evt.getBasePath() + '/' + path;
me._addImage(Common.objectId(), absolutePath, callback);
},
_addImage: function(fileId, absolutePath, callback, isForce) {
// var absolutePath = Evt.getBasePath() + '/' + path;
// 得到文件大小
var stat = fs.statSync(absolutePath);
var paths = absolutePath.split('/');
var name = paths[paths.length-1];
var names = name.split('.');
var ext = names[names.length-1];
var image = {
FileId: fileId,
ServerFileId: '',
Path: absolutePath,
Name: name,
UserId: User.getCurActiveUserId(),
Title: name,
Type: ext,
Size: stat && stat.size,
IsDirty: true, // 本地是新添加的
CreatedTime: new Date()
};
if(isForce) {
image.ServerFileId = fileId;
}
dbClient.images.insert(image, function(err, doc) {
console.log(err);
console.log(doc);
if(err) {
callback && callback(false);
} else {
callback && callback(doc);
}
})
},
// 从服务器上把文件download下来后
// 这里的fileId是serverFileId, 本地的FileId也保存为该值
addImageForce: function(fileId, path, callback) {
var me = this;
// 先删除之, 可能是本地有记录, 但是文件没了
dbClient.images.remove({FileId: fileId}, function() {
me._addImage(fileId, path, callback, true);
});
},
// 获取图片本地路径
// 通过FileId可ServerFileId来查找
// 因为图片的链接 有可能是本地添加的, 又有可能是远程的
// 如果是远程的, FileId == ServerFileId, 是一样的, 所以不要Or
getImageLocalPath: function(fileId, callback) {
// dbClient.images.findOne({$or: {FileId: fileId}, {ServerFileId: fileId}}, function(err, doc) {
dbClient.images.findOne({FileId: fileId}, function(err, doc) {
if(!err && doc && doc.Path) { // FileLocalPath是相对于项目的路径
callback(true, doc.Path);
} else {
callback(false, false);
}
});
},
getImageInfo: function(fileId, callback) {
dbClient.images.findOne({FileId: fileId}, function(err, doc) {
if(!err && doc && doc.Path) {
callback(true, doc);
} else {
callback(false, false);
}
});
},
getAttachInfo: function(fileId, callback) {
db.attachs.findOne({FileId: fileId}, function(err, doc) {
if(!err && doc && doc.Path) {
callback(true, doc);
} else {
callback(false, false);
}
});
},
// 得到fileIds所有的images, 为了发送到服务器上
getAllImages: function(fileIds, callback) {
var me = this;
dbClient.images.find({$or:[{FileId: {$in: fileIds}}, {ServerFileId: {$in: fileIds}}]}, function(err, images) {
if(err || !images) {
return callback(false);
}
callback(images);
});
},
// 笔记添加/修改后会有LocalFileId <=> FileId映射
// 这个只对image有用
updateImageForce: function(files) {
if(!files) {
// callback && callback(false);
return;
}
for(var i in files) {
var file = files[i];
if(file.IsAttach) {
continue;
}
if(!file.FileId || !file.LocalFileId) {
continue;
}
dbClient.images.update({FileId: file.LocalFileId}, {$set: {ServerFileId: file.FileId, IsDirty: false}});
}
},
// tinymce 或 mceeditor上传图片
// callback({FileId: "xx"})
uploadImage: function(imagePath, callback) {
var me = this;
// 读取文件, 查看是否是图片
var filePathAttr = Common.splitFile(imagePath);
var ext = filePathAttr.ext;
if(!Common.isImageExt(ext)) {
return callback(false, 'Please select a image');
}
var fileId = Common.objectId();
// 复制到图片文件夹
filePathAttr.nameNotExt = fileId + '_cp_';
var newFilename = fileId + '.' + ext;
var newFilePath = User.getCurUserImagesPath() + '/' + newFilename;
// 复制之, 并写入到数据库中
Common.copyFile(imagePath, newFilePath, function(ret) {
if(ret) {
me._addImage(fileId, newFilePath, callback);
} else {
callback(false);
}
});
},
// 处理用户图片
getImage: function(fileId, callback) {
var me = this;
if(!fileId) {
return callback(false);
}
var Api = require('api');
// 访问api, 得到图片
function getImageFromApi() {
// console.log('fetch servers image ' + fileId);
Api.getImage(fileId, function(fileLocalPath, filename) {
if(fileLocalPath) {
// console.log('save image to local');
// 保存到本地数据库中
me.addImageForce(fileId, fileLocalPath, function(doc) {
if(doc) {
// console.log('save image to local success');
} else {
// console.log('save image to local error');
}
callback(fileLocalPath);
// return me.retImage(fileLocalPath, res);
});
} else {
// 远程取不到图片, 是没有网络? 还是远程真的没有了
// TODO
// console.log("cann't get server's image" + fileId);
callback(false);
// return me.e404(res);
}
});
}
// 先查看本地是否有该文件
// has表示本地数据库有记录
me.getImageLocalPath(fileId, function(has, fileLocalPath) {
// 本地有
// console.log('re img')
// console.log(fileLocalPath);
// console.log(fs.exists(fileLocalPath));
if(has && fileLocalPath) {
fs.exists(fileLocalPath, function(exists) {
if(exists) {
// console.log('本地存在');
callback(fileLocalPath);
// me.retImage(fileLocalPath, res);
} else {
getImageFromApi();
}
});
} else {
getImageFromApi();
}
});
},
// 下载, 复制一份文件
download: function(srcPath, toPath, callback) {
var srcIsExists = fs.existsSync(srcPath);
if(!srcIsExists) {
return callback(false, 'File Not Exists');
}
// console.log(srcPath);
// console.log(toPath);
var toIsExists = fs.existsSync(toPath);
function cp() {
Common.copyFile(srcPath, toPath, function(ok) {
callback && callback(ok);
});
}
if(toIsExists) {
fs.unlink(toPath, function(error) {
if(!error) {
cp();
} else {
callback && callback(false, 'The Target File Cannot Overwrite');
}
});
} else {
cp();
}
},
// 附件操作
addAttach: function(filePaths, noteId, callback) {
if(!noteId || !filePaths || filePaths.length == 0) {
return callback && callback(false);
}
// filePaths = filePaths.split(';');
// 复制每一个文件, 保存到数据库中
var targets = [];
for(var i in filePaths) {
var filePath = filePaths[i];
var fileStat = fs.statSync(filePath);
var paths = filePath.split(Common.getPathSep()); // windows的filePath不同
var name = paths[paths.length-1];
// Web.alertWeb(name);
var names = name.split('.');
var ext = names[names.length-1];
var rename = Common.uuid() + "." + ext;
var distPath = User.getCurUserAttachsPath() + '/' + rename;
var readable = fs.createReadStream(filePath);
// 创建写入流
var writable = fs.createWriteStream(distPath);
// 通过管道来传输流
readable.pipe(writable);
var attach = {
FileId: Common.objectId(),
ServerFileId: '',
Path: distPath,
NoteId: noteId,
Name: rename,
UserId: User.getCurActiveUserId(),
Title: name,
IsDirty: true, // 先添加的肯定是dirty, 什么时候不是dirty ? sync 和 send changes后
Type: ext,
Size: fileStat && fileStat.size,
IsDirty: true, // 本地是新添加的, ServerFileId = 0
CreatedTime: new Date()
};
db.attachs.insert(attach);
targets.push(attach);
}
callback && callback(targets);
},
// 删除不存在的attachs
deleteNotExistsAttach: function(noteId, attachs) {
var me = this;
// console.log('--');
db.attachs.find({NoteId: noteId}, function(err, everAttachs) {
if(err) {
return;
}
var nowMap = {};
for(var i in attachs) {
nowMap[attachs[i].FileId] = attachs[i];
}
var fileBasePath = User.getCurUserAttachsPath();
for(var i in everAttachs) {
var attach = everAttachs[i];
if(!nowMap[attach.FileId]) { // 如果不在, 则删除之
db.attachs.remove({FileId: attach.FileId});
// 删除源文件, 别删错了啊
if(attach.Path.indexOf(fileBasePath) >= 0) {
fs.unlink(attach.Path);
}
}
}
});
},
// 下载图片, 本地的, 或外站的
downloadImg: function(src, callback) {
var me = this;
// 本地的
if(src.indexOf('http://127.0.0.1') != -1 || src.indexOf('leanote://') != -1) {
var ret = /fileId=([a-zA-Z0-9]{24})/.exec(src);
if(ret && ret.length == 2) {
var fileId = ret[1];
me.getImage(fileId, function(filePath) {
callback(filePath);
});
} else {
callback();
}
} else {
// 远程的图片
needle.get(src, function(err, resp) {
// console.log(resp);
/*
{ 'accept-ranges': 'bytes',
'content-disposition': 'inline; filename="logo.png"',
'content-length': '8583',
'content-type': 'image/png',
date: 'Mon, 19 Jan 2015 15:01:47 GMT',
*/
// log(resp.headers);
if(err || !resp || resp.statusCode != 200) {
callback(false);
return;
} else {
// 当图片没有时候还是执行这一步
var typeStr = resp.headers['content-type'];
var type = 'png';
if(typeStr) {
var typeArr = typeStr.split('/');
if(typeStr.length > 1) {
type = typeArr[1];
}
}
// 返回的是字符串, 肯定是403之类的
if (typeof resp.body === 'string') {
callback(false);
return;
}
var filename = Common.uuid() + '.' + type;
var imagePath = User.getCurUserImagesPath();
var imagePathAll = imagePath + '/' + filename;
fs.writeFile(imagePathAll, resp.body, function(err) {
if(err) {
callback(false);
} else {
callback(imagePathAll);
}
});
}
});
}
},
// 复制外站图片
copyOtherSiteImage: function(src, callback) {
var me = this;
console.log('copyOtherSiteImage');
console.log(src);
me.downloadImg(src, function (filePath) {
console.log(filePath);
if (filePath) {
me._addImage(Common.objectId(), filePath, function(file) {
if (file) {
callback(Evt.getImageLocalUrl(file.FileId));
}
else {
callback(false);
}
});
}
else {
callback(false);
}
});
}
};
module.exports = File;