You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Clean up
This commit is contained in:
		| @@ -29,6 +29,7 @@ import { reg } from 'lib/registry.js'; | ||||
| import { FsDriverNode } from './fs-driver-node.js'; | ||||
| import { filename, basename } from 'lib/path-utils.js'; | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { shimInit } from 'lib/shim-init-node.js'; | ||||
| import { _ } from 'lib/locale.js'; | ||||
| import os from 'os'; | ||||
| import fs from 'fs-extra'; | ||||
| @@ -104,7 +105,8 @@ commands.push({ | ||||
| 		}; | ||||
|  | ||||
| 		try { | ||||
| 			await Note.save(note); | ||||
| 			note = await Note.save(note); | ||||
| 			Note.updateGeolocation(note.id); | ||||
| 		} catch (error) { | ||||
| 			this.log(error); | ||||
| 		} | ||||
| @@ -512,42 +514,54 @@ commands.push({ | ||||
| 	description: 'Synchronizes with remote storage.', | ||||
| 	options: [ | ||||
| 		['--random-failures', 'For debugging purposes. Do not use.'], | ||||
| 		['--stats', 'Displays stats about synchronization.'], | ||||
| 	], | ||||
| 	action: async function(args, end) { | ||||
|  | ||||
| 		let options = { | ||||
| 			onProgress: (report) => { | ||||
| 				let line = []; | ||||
| 				if (report.remotesToUpdate) line.push(_('Items to upload: %d/%d.', report.createRemote + report.updateRemote, report.remotesToUpdate)); | ||||
| 				if (report.remotesToDelete) line.push(_('Remote items to delete: %d/%d.', report.deleteRemote, report.remotesToDelete)); | ||||
| 				if (report.localsToUdpate) line.push(_('Items to download: %d/%d.', report.createLocal + report.updateLocal, report.localsToUdpate)); | ||||
| 				if (report.localsToDelete) line.push(_('Local items to delete: %d/%d.', report.deleteLocal, report.localsToDelete)); | ||||
| 				if (line.length) vorpalUtils.redraw(line.join(' ')); | ||||
| 			}, | ||||
| 			onMessage: (msg) => { | ||||
| 				vorpalUtils.redrawDone(); | ||||
| 				this.log(msg); | ||||
| 			}, | ||||
| 			randomFailures: args.options['random-failures'] === true, | ||||
| 		}; | ||||
| 		if (args.options.stats) { | ||||
| 			const report = await BaseItem.stats(); | ||||
| 			for (let n in report.items) { | ||||
| 				if (!report.items.hasOwnProperty(n)) continue; | ||||
| 				const r = report.items[n]; | ||||
| 				this.log(_('%s: %d/%d', n, r.synced, r.total)) | ||||
| 			} | ||||
| 			this.log(_('Total: %d/%d', report.total.synced, report.total.total)); | ||||
| 		} else { | ||||
| 			let options = { | ||||
| 				onProgress: (report) => { | ||||
| 					let line = []; | ||||
| 					if (report.remotesToUpdate) line.push(_('Items to upload: %d/%d.', report.createRemote + report.updateRemote, report.remotesToUpdate)); | ||||
| 					if (report.remotesToDelete) line.push(_('Remote items to delete: %d/%d.', report.deleteRemote, report.remotesToDelete)); | ||||
| 					if (report.localsToUdpate) line.push(_('Items to download: %d/%d.', report.createLocal + report.updateLocal, report.localsToUdpate)); | ||||
| 					if (report.localsToDelete) line.push(_('Local items to delete: %d/%d.', report.deleteLocal, report.localsToDelete)); | ||||
| 					if (line.length) vorpalUtils.redraw(line.join(' ')); | ||||
| 				}, | ||||
| 				onMessage: (msg) => { | ||||
| 					vorpalUtils.redrawDone(); | ||||
| 					this.log(msg); | ||||
| 				}, | ||||
| 				randomFailures: args.options['random-failures'] === true, | ||||
| 			}; | ||||
|  | ||||
| 		this.log(_('Synchronization target: %s', Setting.value('sync.target'))); | ||||
| 			this.log(_('Synchronization target: %s', Setting.value('sync.target'))); | ||||
|  | ||||
| 		let sync = await synchronizer(Setting.value('sync.target')); | ||||
| 		if (!sync) { | ||||
| 			end(); | ||||
| 			return; | ||||
| 			let sync = await synchronizer(Setting.value('sync.target')); | ||||
| 			if (!sync) { | ||||
| 				end(); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			try { | ||||
| 				this.log(_('Starting synchronization...')); | ||||
| 				await sync.start(options); | ||||
| 			} catch (error) { | ||||
| 				this.log(error); | ||||
| 			} | ||||
|  | ||||
| 			vorpalUtils.redrawDone(); | ||||
| 			this.log(_('Done.')); | ||||
| 		} | ||||
|  | ||||
| 		try { | ||||
| 			this.log(_('Starting synchronization...')); | ||||
| 			await sync.start(options); | ||||
| 		} catch (error) { | ||||
| 			this.log(error); | ||||
| 		} | ||||
|  | ||||
| 		vorpalUtils.redrawDone(); | ||||
| 		this.log(_('Done.')); | ||||
| 		end(); | ||||
| 	}, | ||||
| 	cancel: async function() { | ||||
| @@ -904,64 +918,7 @@ vorpalUtils.initialize(vorpal); | ||||
|  | ||||
| async function main() { | ||||
|  | ||||
| 	shim.fetchBlob = async function(url, options) { | ||||
| 		if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
| 		if (!options.method) options.method = 'GET'; | ||||
|  | ||||
| 		const urlParse = require('url').parse; | ||||
|  | ||||
| 		url = urlParse(url.trim()); | ||||
| 		const http = url.protocol.toLowerCase() == 'http:' ? require('follow-redirects').http : require('follow-redirects').https; | ||||
| 		const headers = options.headers ? options.headers : {}; | ||||
| 		const method = options.method ? options.method : 'GET'; | ||||
| 		if (method != 'GET') throw new Error('Only GET is supported'); | ||||
| 		const filePath = options.path; | ||||
|  | ||||
| 		function makeResponse(response) { | ||||
| 			return { | ||||
| 				ok: response.statusCode < 400, | ||||
| 				path: filePath, | ||||
| 				text: () => { return response.statusMessage; }, | ||||
| 				json: () => { return { message: response.statusCode + ': ' + response.statusMessage }; }, | ||||
| 				status: response.statusCode, | ||||
| 				headers: response.headers, | ||||
| 			}; | ||||
| 		} | ||||
|  | ||||
| 		const requestOptions = { | ||||
| 			protocol: url.protocol, | ||||
| 			host: url.host, | ||||
| 			port: url.port, | ||||
| 			method: method, | ||||
| 			path: url.path + (url.query ? '?' + url.query : ''), | ||||
| 			headers: headers, | ||||
| 		}; | ||||
|  | ||||
| 		return new Promise((resolve, reject) => { | ||||
| 			try { | ||||
| 				// Note: relative paths aren't supported | ||||
| 				const file = fs.createWriteStream(filePath); | ||||
|  | ||||
| 				const request = http.get(requestOptions, function(response) { | ||||
| 					response.pipe(file); | ||||
|  | ||||
| 					file.on('finish', function() { | ||||
| 						file.close(() => { | ||||
| 							resolve(makeResponse(response)); | ||||
| 						}); | ||||
| 					}); | ||||
| 				}) | ||||
|  | ||||
| 				request.on('error', function(error) { | ||||
| 					fs.unlink(filePath); | ||||
| 					reject(error); | ||||
| 				}); | ||||
| 			} catch(error) { | ||||
| 				fs.unlink(filePath); | ||||
| 				reject(error); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 	shimInit(); | ||||
|  | ||||
| 	for (let commandIndex = 0; commandIndex < commands.length; commandIndex++) { | ||||
| 		let c = commands[commandIndex]; | ||||
| @@ -1046,9 +1003,6 @@ async function main() { | ||||
|  | ||||
| 	// If we still have arguments, pass it to Vorpal and exit | ||||
| 	if (argv.length) { | ||||
| 		//vorpal.delimiter(' AAAAAAAAAAAAAAAAAAAAA'); | ||||
| 		//console.info(vorpal.ui.inquirer); | ||||
| 		//vorpal.show(); | ||||
| 		let cmd = shellArgsToString(argv); | ||||
| 		await vorpal.exec(cmd); | ||||
| 		await vorpal.exec('exit'); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     "url": "https://github.com/laurent22/joplin" | ||||
|   }, | ||||
|   "url": "git://github.com/laurent22/joplin.git", | ||||
|   "version": "0.8.30", | ||||
|   "version": "0.8.31", | ||||
|   "bin": { | ||||
|     "joplin": "./main_launcher.js" | ||||
|   }, | ||||
|   | ||||
							
								
								
									
										28
									
								
								ReactNativeClient/lib/geolocation-node.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								ReactNativeClient/lib/geolocation-node.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| import { shim } from 'lib/shim.js' | ||||
| import { netUtils } from 'lib/net-utils.js'; | ||||
|  | ||||
| class GeolocationNode { | ||||
|  | ||||
| 	static async currentPosition(options = null) { | ||||
| 		if (!options) options = {}; | ||||
|  | ||||
| 		const ip = await netUtils.ip(); | ||||
|  | ||||
| 		let response = await shim.fetch('https://freegeoip.net/json/' + ip); | ||||
| 		if (!response.ok) throw new Error('Could not get geolocation: ' + await response.text()); | ||||
|  | ||||
| 		response = await response.json(); | ||||
|  | ||||
| 		return { | ||||
| 			timestamp: (new Date()).getTime(), | ||||
| 			coords: { | ||||
| 				longitude: response.longitude, | ||||
| 				altitude: 0, | ||||
| 				latitude: response.latitude | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| export { GeolocationNode }; | ||||
| @@ -29,13 +29,40 @@ class BaseItem extends BaseModel { | ||||
| 		} | ||||
|  | ||||
| 		throw new Error('Invalid class name: ' + name); | ||||
| 	} | ||||
|  | ||||
| 		// if (!this.classes_) this.classes_ = {}; | ||||
| 		// if (this.classes_[name]) return this.classes_[name]; | ||||
| 		// let filename = name.toLowerCase(); | ||||
| 		// if (name == 'NoteTag') filename = 'note-tag'; | ||||
| 		// this.classes_[name] = require('lib/models/' + filename + '.js')[name]; | ||||
| 		// return this.classes_[name]; | ||||
| 	static async stats() { | ||||
| 		let output = { | ||||
| 			items: {}, | ||||
| 			total: {}, | ||||
| 		}; | ||||
|  | ||||
| 		let itemCount = 0; | ||||
| 		let syncedCount = 0; | ||||
| 		for (let i = 0; i < BaseItem.syncItemDefinitions_.length; i++) { | ||||
| 			let d = BaseItem.syncItemDefinitions_[i]; | ||||
| 			let ItemClass = this.getClass(d.className); | ||||
| 			let o = { | ||||
| 				total: await ItemClass.count(), | ||||
| 				synced: await ItemClass.syncedCount(), | ||||
| 			}; | ||||
| 			output.items[d.className] = o; | ||||
| 			itemCount += o.total; | ||||
| 			syncedCount += o.synced; | ||||
| 		} | ||||
|  | ||||
| 		output.total = { | ||||
| 			total: itemCount, | ||||
| 			synced: syncedCount, | ||||
| 		}; | ||||
|  | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| 	static async syncedCount() { | ||||
| 		const ItemClass = this.itemClass(this.modelType()); | ||||
| 		const r = await this.db().selectOne('SELECT count(*) as total FROM `' + ItemClass.tableName() + '` WHERE updated_time > sync_time'); | ||||
| 		return r.total; | ||||
| 	} | ||||
|  | ||||
| 	static systemPath(itemOrId) { | ||||
| @@ -248,12 +275,6 @@ class BaseItem extends BaseModel { | ||||
|  | ||||
| } | ||||
|  | ||||
| // import { Note } from 'lib/models/note.js'; | ||||
| // import { Folder } from 'lib/models/folder.js'; | ||||
| // import { Resource } from 'lib/models/resource.js'; | ||||
| // import { Tag } from 'lib/models/tag.js'; | ||||
| // import { NoteTag } from 'lib/models/note-tag.js'; | ||||
|  | ||||
| // Also update: | ||||
| // - itemsThatNeedSync() | ||||
| // - syncedItems() | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| import { BaseModel } from 'lib/base-model.js'; | ||||
| import { Log } from 'lib/log.js'; | ||||
| import { Folder } from 'lib/models/folder.js'; | ||||
| import { GeolocationReact } from 'lib/geolocation-react.js'; | ||||
| import { BaseItem } from 'lib/models/base-item.js'; | ||||
| import { Setting } from 'lib/models/setting.js'; | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import moment from 'moment'; | ||||
| import lodash  from 'lodash'; | ||||
|  | ||||
| @@ -96,11 +96,11 @@ class Note extends BaseItem { | ||||
| 	} | ||||
|  | ||||
| 	static updateGeolocation(noteId) { | ||||
| 		Log.info('Updating lat/long of note ' + noteId); | ||||
| 		this.logger().info('Updating lat/long of note ' + noteId); | ||||
|  | ||||
| 		let geoData = null; | ||||
| 		return GeolocationReact.currentPosition().then((data) => { | ||||
| 			Log.info('Got lat/long'); | ||||
| 		return shim.Geolocation.currentPosition().then((data) => { | ||||
| 			this.logger().info('Got lat/long'); | ||||
| 			geoData = data; | ||||
| 			return Note.load(noteId); | ||||
| 		}).then((note) => { | ||||
| @@ -110,7 +110,7 @@ class Note extends BaseItem { | ||||
| 			note.altitude = geoData.coords.altitude; | ||||
| 			return Note.save(note); | ||||
| 		}).catch((error) => { | ||||
| 			Log.info('Cannot get location:', error); | ||||
| 			this.logger().warn('Cannot get location:', error); | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										15
									
								
								ReactNativeClient/lib/net-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ReactNativeClient/lib/net-utils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import { shim } from 'lib/shim.js' | ||||
|  | ||||
| const netUtils = {}; | ||||
|  | ||||
| netUtils.ip = async () => { | ||||
| 	let response = await shim.fetch('https://api.ipify.org/?format=json'); | ||||
| 	if (!response.ok) { | ||||
| 		throw new Error('Could not retrieve IP: ' + await response.text()); | ||||
| 	} | ||||
|  | ||||
| 	let ip = await response.json(); | ||||
| 	return ip.ip; | ||||
| } | ||||
|  | ||||
| export { netUtils }; | ||||
							
								
								
									
										67
									
								
								ReactNativeClient/lib/shim-init-node.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								ReactNativeClient/lib/shim-init-node.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { GeolocationNode } from 'lib/geolocation-node.js'; | ||||
|  | ||||
| function shimInit() { | ||||
| 	shim.Geolocation = GeolocationNode; | ||||
|  | ||||
| 	shim.fetchBlob = async function(url, options) { | ||||
| 		if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
| 		if (!options.method) options.method = 'GET'; | ||||
|  | ||||
| 		const urlParse = require('url').parse; | ||||
|  | ||||
| 		url = urlParse(url.trim()); | ||||
| 		const http = url.protocol.toLowerCase() == 'http:' ? require('follow-redirects').http : require('follow-redirects').https; | ||||
| 		const headers = options.headers ? options.headers : {}; | ||||
| 		const method = options.method ? options.method : 'GET'; | ||||
| 		if (method != 'GET') throw new Error('Only GET is supported'); | ||||
| 		const filePath = options.path; | ||||
|  | ||||
| 		function makeResponse(response) { | ||||
| 			return { | ||||
| 				ok: response.statusCode < 400, | ||||
| 				path: filePath, | ||||
| 				text: () => { return response.statusMessage; }, | ||||
| 				json: () => { return { message: response.statusCode + ': ' + response.statusMessage }; }, | ||||
| 				status: response.statusCode, | ||||
| 				headers: response.headers, | ||||
| 			}; | ||||
| 		} | ||||
|  | ||||
| 		const requestOptions = { | ||||
| 			protocol: url.protocol, | ||||
| 			host: url.host, | ||||
| 			port: url.port, | ||||
| 			method: method, | ||||
| 			path: url.path + (url.query ? '?' + url.query : ''), | ||||
| 			headers: headers, | ||||
| 		}; | ||||
|  | ||||
| 		return new Promise((resolve, reject) => { | ||||
| 			try { | ||||
| 				// Note: relative paths aren't supported | ||||
| 				const file = fs.createWriteStream(filePath); | ||||
|  | ||||
| 				const request = http.get(requestOptions, function(response) { | ||||
| 					response.pipe(file); | ||||
|  | ||||
| 					file.on('finish', function() { | ||||
| 						file.close(() => { | ||||
| 							resolve(makeResponse(response)); | ||||
| 						}); | ||||
| 					}); | ||||
| 				}) | ||||
|  | ||||
| 				request.on('error', function(error) { | ||||
| 					fs.unlink(filePath); | ||||
| 					reject(error); | ||||
| 				}); | ||||
| 			} catch(error) { | ||||
| 				fs.unlink(filePath); | ||||
| 				reject(error); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export { shimInit } | ||||
							
								
								
									
										42
									
								
								ReactNativeClient/lib/shim-init-react.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								ReactNativeClient/lib/shim-init-react.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { GeolocationReact } from 'lib/geolocation-react.js'; | ||||
|  | ||||
| function shimInit() { | ||||
| 	shim.Geolocation = GeolocationReact; | ||||
|  | ||||
| 	shim.fetchBlob = async function(url, options) { | ||||
| 		if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
| 		if (!options.method) options.method = 'GET'; | ||||
|  | ||||
| 		let headers = options.headers ? options.headers : {}; | ||||
| 		let method = options.method ? options.method : 'GET'; | ||||
|  | ||||
| 		let dirs = RNFetchBlob.fs.dirs; | ||||
| 		let localFilePath = options.path; | ||||
| 		if (localFilePath.indexOf('/') !== 0) localFilePath = dirs.DocumentDir + '/' + localFilePath; | ||||
|  | ||||
| 		delete options.path; | ||||
|  | ||||
| 		try { | ||||
| 			let response = await RNFetchBlob.config({ | ||||
| 				path: localFilePath | ||||
| 			}).fetch(method, url, headers); | ||||
|  | ||||
| 			// Returns an object that's roughtly compatible with a standard Response object | ||||
| 			let output = { | ||||
| 				ok: response.respInfo.status < 400, | ||||
| 				path: response.data, | ||||
| 				text: response.text, | ||||
| 				json: response.json, | ||||
| 				status: response.respInfo.status, | ||||
| 				headers: response.respInfo.headers, | ||||
| 			}; | ||||
|  | ||||
| 			return output; | ||||
| 		} catch (error) { | ||||
| 			throw new Error('fetchBlob: ' + method + ' ' + url + ': ' + error.toString()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export { shimInit } | ||||
| @@ -1,5 +1,14 @@ | ||||
| let shim = {}; | ||||
|  | ||||
| shim.isNode = () => { | ||||
| 	if (typeof process === 'undefined') return false; | ||||
| 	return process.title = 'node'; | ||||
| }; | ||||
|  | ||||
| shim.isReactNative = () => { | ||||
| 	return !shim.isNode(); | ||||
| }; | ||||
|  | ||||
| shim.fetch = typeof fetch !== 'undefined' ? fetch : null; | ||||
| shim.FormData = typeof FormData !== 'undefined' ? FormData : null; | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import { createStore } from 'redux'; | ||||
| import { combineReducers } from 'redux'; | ||||
| import { StackNavigator } from 'react-navigation'; | ||||
| import { addNavigationHelpers } from 'react-navigation'; | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { shimInit } from 'lib/shim-init-react.js'; | ||||
| import { Log } from 'lib/log.js' | ||||
| import { Logger } from 'lib/logger.js' | ||||
| import { Note } from 'lib/models/note.js' | ||||
| @@ -225,42 +225,10 @@ let initializationState_ = 'waiting'; | ||||
| async function initialize(dispatch) { | ||||
| 	if (initializationState_ != 'waiting') return; | ||||
|  | ||||
| 	shimInit(); | ||||
|  | ||||
| 	initializationState_ = 'in_progress'; | ||||
|  | ||||
| 	shim.fetchBlob = async function(url, options) { | ||||
| 		if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
| 		if (!options.method) options.method = 'GET'; | ||||
|  | ||||
| 		let headers = options.headers ? options.headers : {}; | ||||
| 		let method = options.method ? options.method : 'GET'; | ||||
|  | ||||
| 		let dirs = RNFetchBlob.fs.dirs; | ||||
| 		let localFilePath = options.path; | ||||
| 		if (localFilePath.indexOf('/') !== 0) localFilePath = dirs.DocumentDir + '/' + localFilePath; | ||||
|  | ||||
| 		delete options.path; | ||||
|  | ||||
| 		try { | ||||
| 			let response = await RNFetchBlob.config({ | ||||
| 				path: localFilePath | ||||
| 			}).fetch(method, url, headers); | ||||
|  | ||||
| 			// Returns an object that's roughtly compatible with a standard Response object | ||||
| 			let output = { | ||||
| 				ok: response.respInfo.status < 400, | ||||
| 				path: response.data, | ||||
| 				text: response.text, | ||||
| 				json: response.json, | ||||
| 				status: response.respInfo.status, | ||||
| 				headers: response.respInfo.headers, | ||||
| 			}; | ||||
|  | ||||
| 			return output; | ||||
| 		} catch (error) { | ||||
| 			throw new Error('fetchBlob: ' + method + ' ' + url + ': ' + error.toString()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	Setting.setConstant('env', __DEV__ ? 'dev' : 'prod'); | ||||
| 	Setting.setConstant('appId', 'net.cozic.joplin'); | ||||
| 	Setting.setConstant('appType', 'mobile'); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user