mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-28 18:18:55 +01:00 
			
		
		
		
	 9ba49bdc5f
			
		
	
	
		9ba49bdc5f
		
	
	
	
	
		
			
			git-subtree-dir: apps/web-clipper git-subtree-mainline: b0e519071893ce9434dd3bb3a568b3e41332c718 git-subtree-split: 786d249a6effe0262859d05e6cb1737e5fc8bdd8
		
			
				
	
	
		
			226 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const PROTOCOL_VERSION_MAJOR = 1;
 | |
| 
 | |
| function isDevEnv() {
 | |
| 	const manifest = browser.runtime.getManifest();
 | |
| 
 | |
| 	return manifest.name.endsWith('(dev)');
 | |
| }
 | |
| 
 | |
| class TriliumServerFacade {
 | |
| 	constructor() {
 | |
| 		this.triggerSearchForTrilium();
 | |
| 
 | |
| 		// continually scan for changes (if e.g. desktop app is started after browser)
 | |
| 		setInterval(() => this.triggerSearchForTrilium(), 60 * 1000);
 | |
| 	}
 | |
| 
 | |
| 	async sendTriliumSearchStatusToPopup() {
 | |
| 		try {
 | |
| 			await browser.runtime.sendMessage({
 | |
| 				name: "trilium-search-status",
 | |
| 				triliumSearch: this.triliumSearch
 | |
| 			});
 | |
| 		}
 | |
| 		catch (e) {} // nothing might be listening
 | |
| 	}
 | |
| 	async sendTriliumSearchNoteToPopup(){
 | |
| 		try{
 | |
| 			await browser.runtime.sendMessage({
 | |
| 				name: "trilium-previously-visited",
 | |
| 				searchNote: this.triliumSearchNote
 | |
| 			})
 | |
| 
 | |
| 		}
 | |
| 		catch (e) {} // nothing might be listening
 | |
| 	}
 | |
| 
 | |
| 	setTriliumSearchNote(st){
 | |
| 		this.triliumSearchNote = st;
 | |
| 		this.sendTriliumSearchNoteToPopup();
 | |
| 	}
 | |
| 
 | |
| 	setTriliumSearch(ts) {
 | |
| 		this.triliumSearch = ts;
 | |
| 
 | |
| 		this.sendTriliumSearchStatusToPopup();
 | |
| 	}
 | |
| 
 | |
| 	setTriliumSearchWithVersionCheck(json, resp) {
 | |
| 		const [major, minor] = json.protocolVersion
 | |
| 			.split(".")
 | |
| 			.map(chunk => parseInt(chunk));
 | |
| 
 | |
| 		// minor version is intended to be used to dynamically limit features provided by extension
 | |
| 		// if some specific Trilium API is not supported. So far not needed.
 | |
| 
 | |
| 		if (major !== PROTOCOL_VERSION_MAJOR) {
 | |
| 			this.setTriliumSearch({
 | |
| 				status: 'version-mismatch',
 | |
| 				extensionMajor: PROTOCOL_VERSION_MAJOR,
 | |
| 				triliumMajor: major
 | |
| 			});
 | |
| 		}
 | |
| 		else {
 | |
| 			this.setTriliumSearch(resp);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	async triggerSearchForTrilium() {
 | |
| 		this.setTriliumSearch({ status: 'searching' });
 | |
| 
 | |
| 		try {
 | |
| 			const port = await this.getPort();
 | |
| 
 | |
| 			console.debug('Trying port ' + port);
 | |
| 
 | |
| 			const resp = await fetch(`http://127.0.0.1:${port}/api/clipper/handshake`);
 | |
| 
 | |
| 			const text = await resp.text();
 | |
| 
 | |
| 			console.log("Received response:", text);
 | |
| 
 | |
| 			const json = JSON.parse(text);
 | |
| 
 | |
| 			if (json.appName === 'trilium') {
 | |
| 				this.setTriliumSearchWithVersionCheck(json, {
 | |
| 					status: 'found-desktop',
 | |
| 					port: port,
 | |
| 					url: 'http://127.0.0.1:' + port
 | |
| 				});
 | |
| 
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 		catch (error) {
 | |
| 			// continue
 | |
| 		}
 | |
| 
 | |
| 		const {triliumServerUrl} = await browser.storage.sync.get("triliumServerUrl");
 | |
| 		const {authToken} = await browser.storage.sync.get("authToken");
 | |
| 
 | |
| 		if (triliumServerUrl && authToken) {
 | |
| 			try {
 | |
| 				const resp = await fetch(triliumServerUrl + '/api/clipper/handshake', {
 | |
| 					headers: {
 | |
| 						Authorization: authToken
 | |
| 					}
 | |
| 				});
 | |
| 
 | |
| 				const text = await resp.text();
 | |
| 
 | |
| 				console.log("Received response:", text);
 | |
| 
 | |
| 				const json = JSON.parse(text);
 | |
| 
 | |
| 				if (json.appName === 'trilium') {
 | |
| 					this.setTriliumSearchWithVersionCheck(json, {
 | |
| 						status: 'found-server',
 | |
| 						url: triliumServerUrl,
 | |
| 						token: authToken
 | |
| 					});
 | |
| 
 | |
| 					return;
 | |
| 				}
 | |
| 			}
 | |
| 			catch (e) {
 | |
| 				console.log("Request to the configured server instance failed with:", e);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// if all above fails it's not found
 | |
| 		this.setTriliumSearch({ status: 'not-found' });
 | |
| 	}
 | |
| 
 | |
| 	async triggerSearchNoteByUrl(noteUrl) {
 | |
| 		const resp = await triliumServerFacade.callService('GET', 'notes-by-url/' + encodeURIComponent(noteUrl))
 | |
| 		let newStatus = {
 | |
| 			status: 'not-found',
 | |
| 			noteId: null
 | |
| 		}
 | |
| 		if (resp && resp.noteId) {
 | |
| 			newStatus.noteId = resp.noteId;
 | |
| 			newStatus.status = 'found';
 | |
| 		}
 | |
| 		this.setTriliumSearchNote(newStatus);
 | |
| 	}
 | |
| 	async waitForTriliumSearch() {
 | |
| 		return new Promise((res, rej) => {
 | |
| 			const checkStatus = () => {
 | |
| 				if (this.triliumSearch.status === "searching") {
 | |
| 					setTimeout(checkStatus, 500);
 | |
| 				}
 | |
| 				else if (this.triliumSearch.status === 'not-found') {
 | |
| 					rej(new Error("Trilium instance has not been found."));
 | |
| 				}
 | |
| 				else {
 | |
| 					res();
 | |
| 				}
 | |
| 			};
 | |
| 
 | |
| 			checkStatus();
 | |
| 		});
 | |
| 	}
 | |
| 
 | |
| 	async getPort() {
 | |
| 		const {triliumDesktopPort} = await browser.storage.sync.get("triliumDesktopPort");
 | |
| 
 | |
| 		if (triliumDesktopPort) {
 | |
| 			return parseInt(triliumDesktopPort);
 | |
| 		}
 | |
| 		else {
 | |
| 			return isDevEnv() ? 37740 : 37840;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	async callService(method, path, body) {
 | |
| 		const fetchOptions = {
 | |
| 			method: method,
 | |
| 			headers: {
 | |
| 				'Content-Type': 'application/json'
 | |
| 			},
 | |
| 		};
 | |
| 
 | |
| 		if (body) {
 | |
| 			fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
 | |
| 		}
 | |
| 
 | |
| 		try {
 | |
| 			await this.waitForTriliumSearch();
 | |
| 
 | |
| 			fetchOptions.headers.Authorization = this.triliumSearch.token || "";
 | |
| 			fetchOptions.headers['trilium-local-now-datetime'] = this.localNowDateTime();
 | |
| 
 | |
| 			const url = this.triliumSearch.url + "/api/clipper/" + path;
 | |
| 
 | |
| 			console.log(`Sending ${method} request to ${url}`);
 | |
| 
 | |
| 			const response = await fetch(url, fetchOptions);
 | |
| 
 | |
| 			if (!response.ok) {
 | |
| 				throw new Error(await response.text());
 | |
| 			}
 | |
| 
 | |
| 			return await response.json();
 | |
| 		}
 | |
| 		catch (e) {
 | |
| 			console.log("Sending request to trilium failed", e);
 | |
| 
 | |
| 			toast('Your request failed because we could not contact Trilium instance. Please make sure Trilium is running and is accessible.');
 | |
| 
 | |
| 			return null;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	localNowDateTime() {
 | |
| 		const date = new Date();
 | |
| 		const off = date.getTimezoneOffset();
 | |
| 		const absoff = Math.abs(off);
 | |
| 		return (new Date(date.getTime() - off * 60 * 1000).toISOString().substr(0,23).replace("T",  " ") +
 | |
| 			(off > 0 ? '-' : '+') +
 | |
| 			(absoff / 60).toFixed(0).padStart(2,'0') + ':' +
 | |
| 			(absoff % 60).toString().padStart(2,'0'));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| window.triliumServerFacade = new TriliumServerFacade();
 |