intel_cache_lib/
lib_backend.rs

1mod models;
2mod schema;
3
4use diesel::prelude::*;
5use diesel_migrations::embed_migrations;
6use libloading::Library;
7use ipfs_api_backend_hyper::{IpfsApi, IpfsClient};
8use futures::executor::block_on;
9use sha2::{Sha512,Sha256, Digest};
10
11use std::io::{Write,Cursor};
12use std::process::{Command,Stdio};
13use std::time::{SystemTime,UNIX_EPOCH};
14use std::str;
15use std::fs::File;
16use std::fs;
17use std::error::Error;
18
19use self::models::{EntryTag,NewEntryTag,NewEntry, Entry, NewDirTag, DirTag, Tag, NewTag, Dir, NewDir,NewUser,User};
20use crate::ic_types::{IcError,IcLoginDetails,IcPacket,IcExecute,IcConnection};
21use crate::IcModule;
22use futures::TryStreamExt;
23use tar::Archive;
24
25
26embed_migrations!("migrations/");
27
28pub fn delete_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
29	//let url = format!("mysql://{}:{}@localhost/",username,password);
30	let p = format!("--password={}",password);
31	let echo =
32		Command::new("echo")
33		//Make intelcache user/pass
34		.arg("DROP DATABASE IntelCache;DROP USER 'intelcache'@'localhost'")
35		.stdout(Stdio::piped())
36		.stderr(Stdio::piped())
37		.spawn()?;
38	
39	//let mut mysqldelete =
40	//	Command::new("mysql")
41	//	.args(["-u",username])
42	//	.arg(p)
43	//	.stdin(echo.stdout.unwrap())
44	//	.stdout(stdio::piped())
45	//	.stderr(stdio::piped()).spawn().unwrap().wait();
46	Command::new("mysql")
47		.args(["-u",username])
48		.arg(p)
49		.stdin(echo.stdout.unwrap())
50		.stdout(Stdio::piped())
51		.stderr(Stdio::piped()).spawn()?.wait()?;
52	Ok(())
53}
54
55pub fn delete_testing_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
56	//let url = format!("mysql://{}:{}@localhost/",username,password);
57	let p = format!("--password={}",password);
58	let echo =
59		Command::new("echo")
60		//Make intelcache user/pass
61		.arg("DROP DATABASE IntelCache_testing;DROP USER 'intelcache_tester'@'localhost'")
62		.stdout(Stdio::piped())
63		.stderr(Stdio::piped())
64		.spawn()?;
65	
66	//let mut mysqldelete =
67	Command::new("mysql")
68		.args(["-u",username])
69		.arg(p)
70		.stdin(echo.stdout.unwrap())
71		.stdout(Stdio::piped())
72		.stderr(Stdio::piped()).spawn()?.wait()?;
73	Ok(())
74}
75
76pub fn build_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
77	//let url = format!("mysql://{}:{}@localhost/",username,password);
78	let p = format!("--password={}",password);
79	let echo =
80		Command::new("echo")
81		//Make intelcache user/pass
82		.arg("CREATE DATABASE IntelCache;CREATE USER IF NOT EXISTS 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache`.* TO 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';")
83		.stdout(Stdio::piped())
84		.stderr(Stdio::piped())
85		.spawn()?;
86	
87	//let mut mysqlcreate =
88	Command::new("mysql")
89		.args(["-u",username])
90		.arg(p)
91		.stdin(echo.stdout.unwrap())
92		.stdout(Stdio::piped())
93		.stderr(Stdio::piped())
94		.spawn()?.wait()?;
95	
96	let con = establish_connection()?;
97	embedded_migrations::run(&con)?;
98	Ok(())
99}
100pub fn build_testing_sql(username: &str,password: &str) -> Result<(),Box<dyn Error>>{
101	//let url = format!("mysql://{}:{}@localhost/",username,password);
102	let p = format!("--password={}",password);
103	let echo =
104		Command::new("echo")
105		//Make intelcache user/pass
106		.arg("CREATE DATABASE IntelCache_testing;CREATE USER IF NOT EXISTS 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache_testing`.* TO 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';")
107		.stdout(Stdio::piped())
108		.stderr(Stdio::piped())
109		.spawn()?;
110	
111	//let mut mysqlcreate =
112	Command::new("mysql")
113		.args(["-u",username])
114		.arg(p)
115		.stdin(echo.stdout.unwrap())
116		.stdout(Stdio::piped())
117		.stderr(Stdio::piped())
118		.spawn()?.wait()?;
119	
120	let con = establish_testing_connection()?;
121	embedded_migrations::run(&con)?;
122	Ok(())
123}
124
125pub fn export_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
126	//let url = format!("mysql://{}:{}@localhost/",username,password);
127	let p = format!("--password={}",password);
128	
129	//let mut mysqlexportoutput =
130	Command::new("mysqldump")
131		.args(["-u",username])
132		.arg(p)
133		.arg("IntelCache")
134		.stdout(File::create(filename)?)
135		.spawn()?.wait()?;
136	Ok(())
137}
138pub fn export_testing_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
139	//let url = format!("mysql://{}:{}@localhost/",username,password);
140	let p = format!("--password={}",password);
141	
142	//let mut mysqlexportoutput =
143	Command::new("mysqldump")
144		.args(["-u",username])
145		.arg(p)
146		.arg("IntelCache_testing")
147		.stdout(File::create(filename)?)
148		.spawn()?.wait()?;
149	Ok(())
150}
151
152pub fn import_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
153	//let url = format!("mysql://{}:{}@localhost/",username,password);
154	let p = format!("--password={}",password);
155	let mut mysqlcreate =
156		Command::new("mysql")
157		.args(["-u",username])
158		.arg(&p)
159		.stdin(Stdio::piped())
160		.stdout(Stdio::piped())
161		.stderr(Stdio::piped())
162		.spawn()?;
163	mysqlcreate.stdin.as_mut().unwrap().write(b"CREATE DATABASE IntelCache;CREATE USER IF NOT EXISTS 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache`.* TO 'intelcache'@'localhost' IDENTIFIED BY 'intelcache';")?;
164	mysqlcreate.wait()?;
165	
166	//let mut mysqlimport =
167	Command::new("mysql")
168		.args(["-u",username])
169		.arg(&p)
170		.arg("IntelCache")
171		.stdin(File::open(filename)?)
172		.stdout(Stdio::piped())
173		.stderr(Stdio::piped())
174		.spawn()?.wait()?;
175	Ok(())
176}
177
178pub fn import_testing_sql(username: &str,password: &str,filename: &str) -> Result<(),Box<dyn Error>>{
179	//let url = format!("mysql://{}:{}@localhost/",username,password);
180	let p = format!("--password={}",password);
181	let mut mysqlcreate =
182		Command::new("mysql")
183		.args(["-u",username])
184		.arg(&p)
185		.stdin(Stdio::piped())
186		.stdout(Stdio::piped())
187		.stderr(Stdio::piped())
188		.spawn()?;
189	mysqlcreate.stdin.as_mut().unwrap().write(b"CREATE DATABASE IntelCache_testing;CREATE USER IF NOT EXISTS 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';GRANT ALL ON `IntelCache_testing`.* TO 'intelcache_tester'@'localhost' IDENTIFIED BY 'intelcache';")?;
190	mysqlcreate.wait()?;
191	
192	//let mut mysqlimport =
193	Command::new("mysql")
194		.args(["-u",username])
195		.arg(&p)
196		.arg("IntelCache_testing")
197		.stdin(File::open(filename)?)
198		.stdout(Stdio::piped())
199		.stderr(Stdio::piped())
200		.spawn()?.wait()?;
201	
202	Ok(())
203}
204
205pub fn establish_connection() -> Result<MysqlConnection,Box<dyn Error>> {
206	let u = "mysql://intelcache:intelcache@localhost/IntelCache"; 
207	let ret: MysqlConnection;
208	match MysqlConnection::establish(&u) {
209		Ok(v) => ret = v,
210		Err(e) => panic!("{:?}",e),
211	}
212	Ok(ret)
213}
214
215pub fn establish_testing_connection() -> Result<MysqlConnection,Box<dyn Error>> {
216	let u = "mysql://intelcache_tester:intelcache@localhost/IntelCache_testing"; 
217	let ret: MysqlConnection;
218	match MysqlConnection::establish(&u) {
219		Ok(v) => ret = v,
220		Err(e) => panic!("{:?}",e),
221	}
222	Ok(ret)
223}
224
225pub fn create_dir(conn: &MysqlConnection, name: &str, loc: Option<i32>, public: bool,id: &String) -> Result<Dir,IcError> {
226	use schema::dir;
227	
228	let l: Option<i32>;
229	if loc != None {
230		l = if loc.unwrap() == 0 {None} else {Some(loc.unwrap())};
231	} else {l = None}
232	let new_dir = NewDir { name,loc: l,visibility: public,owner: id.to_string() };
233	
234	match diesel::insert_into(dir::table).values(&new_dir).execute(conn) {
235	Ok(_v) => (),
236	//Err(_err) => return Err(IcError("Error creating new directory.".to_string())),}
237	Err(_err) => panic!("{:?}",_err),}
238	
239	Ok(dir::table.order(dir::id.desc()).first(conn).unwrap())
240}
241
242pub fn delete_dir(conn: &MysqlConnection,dirid: i32) -> Result<(),IcError>{
243	use self::schema::dir::dsl::*;
244	let rv = match validate_dir(conn,dirid) {
245		Some(_v) => dirid,
246		None => {return Err(IcError("Error deleting directory.".to_string()))}
247	};
248	diesel::delete(dir.filter(id.eq(rv))).execute(conn).unwrap();
249	Ok(())
250}
251pub fn update_dir(conn: &MysqlConnection,dirid: i32,iddest: Option<i32>,new_name: Option<&str>) -> Result<(),IcError>{
252	use schema::dir;
253	if new_name == None {
254		if iddest != None {
255			let rv = diesel::update(dir::table.filter(dir::id.eq(dirid))).set(dir::loc.eq(&iddest)).execute(conn);
256			match rv {
257				Ok(_v) => return Ok(()),
258				Err(_err) => return Err(IcError("Failed to update directory.".to_string())),
259			};
260		} else {return Err(IcError("Failed to update directory.".to_string()))}
261	} else {  
262		if iddest != None {
263			let rv = diesel::update(dir::table.filter(dir::id.eq(dirid))).set((dir::loc.eq(&iddest),dir::name.eq(&new_name.unwrap()))).execute(conn);
264			match rv {
265				Ok(_v) => return Ok(()),
266				Err(_err) => return Err(IcError("Failed to update directory.".to_string())),
267			};
268		} else {
269			let rv = diesel::update(dir::table.filter(dir::id.eq(dirid))).set(dir::name.eq(&new_name.unwrap())).execute(conn);
270			match rv {
271				Ok(_v) => return Ok(()),
272				Err(_err) => return Err(IcError("Failed to update directory.".to_string())),
273			};
274		}
275	}
276}
277
278pub fn show_dirs(conn: &MysqlConnection,by_id: Option<i32>,o: &String,owned_only: bool) -> String{
279	use self::schema::dir::dsl::*;
280	use schema::dir;
281	let results: Vec<Dir>;
282	if by_id != None {
283		if by_id.unwrap() != 0 {
284			results = dir.filter(dir::loc.eq(by_id.unwrap()).and(dir::owner.eq(o))).load::<Dir>(conn).expect("Error loading dirs");
285		} else {
286			results = dir.filter(dir::loc.is_null().and(dir::owner.eq(o))).load::<Dir>(conn).expect("Error loading dirs");
287		}
288	} else { //SHOW ALL DIRS (Non public)
289		results = dir.filter(dir::owner.eq(o)).load::<Dir>(conn).expect("Error loading dirs");
290	}
291	let mut retstr = String::new();
292	
293	for d in results {
294		let location = if d.loc.unwrap_or(-1) == -1 {"ROOT".to_string()} else {dir::table.filter(dir::id.eq(d.loc.unwrap())).select(dir::name).get_result::<String>(conn).unwrap()};
295		let tags = get_dir_tags(conn,d.id);
296		retstr.push_str(format!("{} {} ({}) {}\n",d.id,d.name, location, tags).as_str())
297	}
298	if ! owned_only {
299		let public_results = dir.filter(dir::visibility.eq(true)).load::<Dir>(conn).expect("Error loading dirs");
300		for d in public_results {
301			let location = if d.loc.unwrap_or(-1) == -1 {"ROOT".to_string()} else {dir::table.filter(dir::id.eq(d.loc.unwrap())).select(dir::name).get_result::<String>(conn).unwrap()};
302			let tags = get_dir_tags(conn,d.id);
303			retstr.push_str(format!("{} {} ({}) {} -> {} {}\n",d.id,d.name, location, tags,d.owner,if d.visibility {"PUBLIC"} else {"PRIVATE"}).as_str())
304		}
305	}
306	retstr
307}
308
309pub fn show_tags(conn: &MysqlConnection, _display: Option<bool>) -> String {
310	use self::schema::tag::dsl::*;
311	let results = tag.load::<Tag>(conn).expect("Error loading tags");
312	let mut retstr = String::new();
313	for d in results {
314		retstr.push_str(&format!("{} {}\n",d.id,&d.name));
315	}
316	retstr
317}
318
319pub fn rename_tag(conn: &IcConnection,tagid: i32, tagname: &str) -> Result<(),Box<dyn Error>> {
320	use schema::tag;
321	match diesel::update(tag::table.filter(tag::id.eq(tagid))).set(tag::name.eq(tagname)).execute(&conn.backend_con) {
322		Ok(_v) => return Ok(()),
323		Err(e) => return Err(Box::new(e)),
324	}
325}
326
327pub fn create_tag(conn: &IcConnection, name: &str,public: bool) -> Tag {
328	use schema::tag;
329	
330	let new_tag = NewTag { name,visibility: public,owner: &conn.login.as_ref().unwrap().id };
331	
332	diesel::insert_into(tag::table)
333		.values(&new_tag).execute(&conn.backend_con).expect("Error saving draft");
334	
335	tag::table.order(tag::id.desc()).first(&conn.backend_con).unwrap()
336}
337
338pub fn delete_tag(conn: &MysqlConnection,tagid: i32) -> Result<(),IcError>{
339	use self::schema::tag::dsl::*;
340	let rv = match validate_tag(conn,tagid) {
341		Some(_v) => tagid,
342		None => {return Err(IcError("Error deleting tag.".to_string()))}
343	};
344	diesel::delete(tag.filter(id.eq(rv))).execute(conn).unwrap();
345	Ok(())
346}
347
348pub fn tag_dir(conn: &MysqlConnection, dir_id: i32,tag_id: i32) -> Result<DirTag ,IcError>{
349	use schema::dir_tags;
350	
351	let new_dir_tag = NewDirTag { dirid: dir_id,tagid: tag_id };
352	
353	let res = diesel::insert_into(dir_tags::table).values(&new_dir_tag).execute(conn);
354	match res {
355	Ok(_e) => (),
356	Err(_e) => {return Err(IcError("Invalid dir id or tag id.".to_string()))},
357	}
358
359	Ok(dir_tags::table.filter(dir_tags::tagid.eq(tag_id)).filter(dir_tags::dirid.eq(dir_id)).limit(1).get_result::<DirTag>(conn).unwrap())
360}
361
362pub fn untag_dir(conn: &MysqlConnection,dir_id: i32, tag_id: i32) {
363	use schema::dir_tags;
364	
365	diesel::delete(dir_tags::table.filter(dir_tags::dirid.eq(dir_id)).filter(dir_tags::tagid.eq(tag_id))).execute(conn).expect("Error untaging directory.");
366}
367
368pub fn get_dir_tags(conn: &MysqlConnection, dir_id: i32) -> String {
369	use schema::dir_tags;
370	use schema::tag;
371	use schema::dir;
372	use self::schema::dir::dsl::*;
373	let results = dir.left_join(dir_tags::table).left_join(tag::table.on(dir_tags::tagid.eq(tag::id))).filter(dir::id.eq(dir_id)).select(tag::name.nullable()).load::<Option<String>>(conn).unwrap();
374	let mut retstr = String::new();
375	retstr.push_str(if results.len() <= 1 && results[0].as_ref().unwrap_or(&"NONE".to_string()) == &"NONE".to_string() {""} else {"["});
376	let rl = results.len();
377	let mut rlv = String::new();
378	rlv.push_str(&results[0].as_ref().unwrap_or(&"NONE".to_string()));
379	if rlv != "NONE".to_string() {
380		let mut c = 0;
381		for t in results {
382			c += 1;
383			let p = t.unwrap_or("".to_string());
384			retstr.push_str(&p);
385			retstr.push_str(if p == "".to_string() || (p != "".to_string() && c == rl) {""} else {", "});
386		}
387	}
388	retstr.push_str(if rl <= 1 && rlv == "NONE".to_string() {""} else {"]"});
389	retstr
390}
391
392pub fn show_entries(conn: &MysqlConnection, _display: Option<bool>, shortened: Option<bool>, under_id: Option<i32>,o: &String,owned_only: bool) -> String {
393	use self::schema::entry::dsl::*;
394	use schema::entry;
395	let results: Vec<Entry>;
396	if under_id != None && under_id.unwrap() == 0 { //Load entries at null
397		results = entry.filter(entry::loc.is_null().and(entry::owner.eq(o))).load::<Entry>(conn).expect("Error loading entries");
398	} else if under_id == None { //Show all entries
399		results = entry.filter(entry::owner.eq(o)).load::<Entry>(conn).expect("Error loading entries");
400	} else { //ID present
401		results = entry.filter(entry::loc.eq(under_id.unwrap()).and(entry::owner.eq(o))).load::<Entry>(conn).expect("Error loading entries");
402	}
403	
404	let mut retstr = String::new();
405	if ! shortened.unwrap_or(false) { 
406		for e in results {
407			if e.owner == *o || (owned_only && e.visibility){
408				let tags = get_entry_tags(conn,e.id);
409				let text = match str::from_utf8(&e.data) {
410					Ok(v) => v,
411					Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
412				};
413				retstr.push_str(format!("{} {} ({}) {} [{}]\n{}\n",e.id,e.name,e.type_,e.loc.unwrap_or(0),tags,text).as_str());
414			}
415		}
416	} else {
417		for e in results {
418			if e.owner == *o || (owned_only && e.visibility){
419				let tags = get_entry_tags(conn,e.id);
420				retstr.push_str(format!("{} {} ({}) {} {}\n",e.id,e.name,e.type_,e.loc.unwrap_or(0),tags).as_str());
421			}
422		}
423	}
424	retstr
425}
426
427#[tokio::main]
428pub async fn delete_entry(conn: &MysqlConnection,entryid: i32) -> Result<(),IcError>{
429	use self::schema::entry::dsl::*;
430	if get_entry_by_id(conn,entryid) != None {
431		let e = get_entry_by_id(conn,entryid).unwrap();
432		if e.type_ == "ipfs_file" {
433			let ipfsclient = IpfsClient::default();
434			block_on(ipfsclient.pin_rm(str::from_utf8(&e.data).unwrap(),true)).unwrap();
435		} 
436		diesel::delete(entry.filter(id.eq(entryid))).execute(conn).unwrap();
437		return Ok(());
438	} else { return Err(IcError("Entry id not found".to_string())) } 
439}
440
441#[tokio::main]
442pub async fn get_entry(conn: &mut IcConnection,id: i32,name: &str) -> IcPacket{
443	let e = get_entry_by_id(&conn.backend_con,id).unwrap();
444	
445	if e.type_ == "ipfs_file" {
446		let client = IpfsClient::default();
447		//TODO: 1
448		match block_on(client
449		    .get(str::from_utf8(&e.data).unwrap())
450		    .map_ok(|chunk| chunk.to_vec())
451		    .try_concat())
452		{
453		    Ok(res) => {
454			fs::write(name,res).unwrap();
455
456		    }
457		    Err(e) => return IcPacket::new(Some(format!("ERR: error getting file: {}", e)),None)
458		}
459		let mut archive = Archive::new(File::open(name).unwrap());
460		archive.unpack(".").unwrap();
461		fs::rename(str::from_utf8(&e.data).unwrap(),name).unwrap();
462		let p = IcPacket::new_cached(Some("OK!".to_string()),Some(name.as_bytes().to_vec())); 
463		println!("RETURNING PACKET TO SEND: {} ({:?})",&p.header.as_ref().unwrap(),&p.body.as_ref().unwrap());
464		return p;
465	}else if e.type_ == "text" {
466		return IcPacket::new(Some("OK!".to_string()),Some(e.data));
467	} else { return IcPacket::new(Some("ERR: Type unknown".to_string()),None) }
468}
469
470pub fn tag_entry(conn: &MysqlConnection, entry_id: i32,tag_id: i32) -> Result<EntryTag,IcError>{
471	use schema::entry_tags;
472	
473	let new_entry_tag = NewEntryTag { entryid: entry_id,tagid: tag_id };
474	
475	let res = diesel::insert_into(entry_tags::table).values(&new_entry_tag).execute(conn);
476	match res {
477	Ok(_e) => (),
478	Err(_err) => {return Err(IcError("Error tagging entry.".to_string()))}
479	};
480	Ok(entry_tags::table.filter(entry_tags::tagid.eq(tag_id)).filter(entry_tags::entryid.eq(entry_id)).limit(1).get_result::<EntryTag>(conn).unwrap())
481}
482
483pub fn untag_entry(conn: &MysqlConnection,entry_id: i32, tag_id: i32) {
484	use schema::entry_tags;
485	
486	diesel::delete(entry_tags::table.filter(entry_tags::entryid.eq(entry_id)).filter(entry_tags::tagid.eq(tag_id))).execute(conn).expect("Error saving draft");
487}
488
489pub fn get_entry_tags(conn: &MysqlConnection, entry_id: i32) -> String {
490	use schema::entry_tags;
491	use schema::tag;
492	use schema::entry;
493	use self::schema::entry::dsl::*;
494	let results = entry.left_join(entry_tags::table).left_join(tag::table.on(entry_tags::tagid.eq(tag::id))).filter(entry::id.eq(entry_id)).select(tag::name.nullable()).load::<Option<String>>(conn).unwrap();
495	let mut retstr = String::new();
496	retstr.push_str(if results.len() <= 1 && results[0].as_ref().unwrap_or(&"NONE".to_string()) == &"NONE".to_string() {""} else {"["});
497	let rl = results.len();
498	let mut rlv = String::new();
499	rlv.push_str(&results[0].as_ref().unwrap_or(&"NONE".to_string()));
500	if rlv != "NONE".to_string() {
501		let mut c = 0;
502		for t in results {
503			c += 1;
504			let p = t.unwrap_or("".to_string());
505			retstr.push_str(&p);
506			retstr.push_str(if p == "".to_string() || (p != "".to_string() && c == rl) {""} else {", "});
507		}
508	}
509	retstr.push_str(if rl <= 1 && rlv == "NONE".to_string() {""} else {"]"});
510	retstr
511}
512
513#[tokio::main]
514pub async fn make_file_entry(conn: &IcConnection,name: &str,dt: Vec<u8>,location: Option<i32>,lbl: Option<&str>,public: bool,cached: bool) -> Result<Entry,IcError> {
515	use schema::entry;
516
517	let ipfsclient = IpfsClient::default();
518	let l = if (location != None && location.unwrap() <= 0) || location == None {None} else {Some(location.unwrap())}; 
519	if ! cached {
520		if dt.len() < 65535 {
521			let new_entry = NewEntry { name: name,data: &dt,type_: "text",loc: l,label: lbl, visibility: public,owner: &conn.login.as_ref().unwrap().id };
522			
523			let query = diesel::insert_into(entry::table).values(&new_entry);
524			//let debug = diesel::debug_query::<diesel::mysql::Mysql, _>(&query);
525			//println!("The insert query: {:?}", debug);
526			//let res = diesel::insert_into(entry::table).values(&new_entry).execute(&conn.backend_con);
527			let res = query.execute(&conn.backend_con);
528			match res {
529				Ok(_e) => (),
530				Err(_err) => panic!("{}",_err),//return Err(IcError("Error making new entry in the IntelCache.".to_string())),
531			}
532		} else {
533			let hash: String;
534			match block_on(ipfsclient.add(Cursor::new(dt))) {
535				Ok(res) => hash = res.hash,
536				Err(_e) => return Err(IcError("Error inserting file in IPFS.".to_string())),
537			}
538			let new_entry = NewEntry { name: name,data: hash.as_bytes(),type_: "ipfs_file",loc: l,label: lbl, visibility: public, owner: &conn.login.as_ref().unwrap().id };
539			
540			let res = diesel::insert_into(entry::table).values(&new_entry).execute(&conn.backend_con);
541			match res {
542				Ok(_e) => (),
543				Err(_err) => return Err(IcError("Error making new IPFS entry in the IntelCache.".to_string())),
544			}
545			
546		}
547		Ok(entry::table.order(entry::id.desc()).first(&conn.backend_con).unwrap())
548	} else {
549		let b = match str::from_utf8(&dt) {
550			Ok(v) => v,
551			Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
552		};
553		let f = match File::open(b) {
554			Ok(v) => v,
555			Err(e) => panic!("Invalid File: {}", e),
556		};
557		
558		let hash: String;
559		match block_on(ipfsclient.add(f)) {
560			Ok(res) => hash = res.hash,
561			Err(_e) => return Err(IcError("Error inserting file in IPFS.".to_string())),
562		}
563		let new_entry = NewEntry { name: name,data: hash.as_bytes(),type_: "ipfs_file",loc: l,label: lbl, visibility: public, owner: &conn.login.as_ref().unwrap().id };
564		
565		let res = diesel::insert_into(entry::table).values(&new_entry).execute(&conn.backend_con);
566		match res {
567			Ok(_e) => (),
568			Err(_err) => return Err(IcError("Error making new IPFS entry in the IntelCache.".to_string())),
569		}
570		
571		Ok(entry::table.order(entry::id.desc()).first(&conn.backend_con).unwrap())
572	}
573}
574
575pub async fn update_entry(conn: &MysqlConnection,uid: i32,dt: Option<Vec<u8>>,n: Option<&str>,l: Option<i32>,_lbl: Option<&str>) -> Result<(),IcError>{
576	use schema::entry;
577
578	let ipfsclient = IpfsClient::default();
579	if get_entry_by_id(conn,uid) != None {
580		//if 0, 0. if none, do not change.
581		let e = get_entry_by_id(conn,uid).unwrap();
582		if l == None {
583			println!("L IS NONE");
584			if dt != None {
585				println!("DT IS NOT NONE");
586				if dt.as_ref().unwrap().len() < 65535 {
587					diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(&dt.unwrap()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)))).execute(conn).expect("Error updating entry.");
588					Ok(())
589				} else {
590					let hash;
591					match block_on(ipfsclient.add(Cursor::new(dt.unwrap()))) {
592						Ok(res) => hash = res.hash,
593						Err(_e) => return Err(IcError("Error adding updated entry data.".to_string())),
594					};
595					diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(hash.as_bytes()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)))).execute(conn).expect("Error updating entry.");
596					Ok(())
597				}
598			} else {
599				println!("DT IS NONE");
600				diesel::update(entry::table.filter(entry::id.eq(uid))).set(entry::name.eq(n.unwrap_or(&e.name))).execute(conn).expect("Error updating entry.");
601				Ok(())
602			}
603		} else {
604			println!("L IS NOT NONE");
605			let nl: Option<i32> = if l.unwrap() == 0 {None} else {Some(l.unwrap())};
606			
607			if dt != None {
608				println!("DT IS NOT NONE");
609				if dt.as_ref().unwrap().len() < 65535 {
610					diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(&dt.unwrap()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)),entry::loc.eq(nl))).execute(conn).expect("Error updating entry.");
611					Ok(())
612				} else {
613					let hash;
614					match block_on(ipfsclient.add(Cursor::new(dt.unwrap()))) {
615						Ok(res) => hash = res.hash,
616						Err(_e) => return Err(IcError("Error adding updated entry data.".to_string())),
617					};
618					diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::data.eq(hash.as_bytes()),entry::type_.eq("text"),entry::name.eq(n.unwrap_or(&e.name)),entry::loc.eq(nl))).execute(conn).expect("Error updating entry.");
619					Ok(())
620				}
621			} else {
622				println!("DT IS NONE");
623				diesel::update(entry::table.filter(entry::id.eq(uid))).set((entry::name.eq(n.unwrap_or(&e.name)),entry::loc.eq(nl))).execute(conn).expect("Error updating entry.");
624				Ok(())
625			}
626		}
627	} else {return Err(IcError("Error getting entry for update".to_string()))}
628}
629
630#[tokio::main]
631pub async fn get_pip() -> Option<String> {
632	match block_on(public_ip::addr()) {
633		Some(ip) => return Some(format!("{:?}", ip)),
634		None => return None,
635	}
636}
637
638pub fn get_entry_by_id(conn: &MysqlConnection,entryid: i32) -> Option<Entry> {
639	use schema::entry;
640	
641	let r = entry::table.filter(entry::id.eq(entryid)).get_result::<Entry>(conn);
642	return match r {
643		Ok(entry) => Some(entry),
644		Err(_e) => None,
645	} 
646}
647
648pub fn validate_dir(conn: &MysqlConnection,dirid: i32) -> Option<String> {
649	use schema::dir;
650	let d: Result<Vec<String>,diesel::result::Error>;
651	if dirid > 0 {
652		d = dir::table.filter(dir::id.eq(dirid)).select(dir::name).load::<String>(conn);
653	} else if dirid == 0 {
654		d = Ok(vec!("ROOT".to_string()));
655	} else { return None };
656	
657	match d {
658		Ok(n) => return if n.len() as i32 >= 0 {Some(n[0].clone())} else {None},
659		Err(_e) => return None,
660	}
661}
662pub fn validate_tag(conn: &MysqlConnection,tagid: i32) -> Option<String> {
663	use schema::tag;
664	let d = tag::table.filter(tag::id.eq(tagid)).select(tag::name).load::<String>(conn);
665	match d {
666	Ok(n) => return if n.len() > 0 {Some(n[0].clone())} else {None},
667	Err(_e) => return None,
668	}
669}
670
671pub fn register(conn: &MysqlConnection,username: String,password: String,id: String) -> Result<(),IcError> {
672	use schema::user;
673	let user = NewUser{ global_id: id, username: username, password: password };
674		let res = diesel::insert_into(user::table).values(&user).execute(conn);
675
676		match res {
677		Ok(_e) => (),
678		Err(_err) => return Err(IcError("Error making new user.".to_string())),
679		}
680	
681	Ok(())
682}
683
684pub fn login(conn: &MysqlConnection,login: &mut Option<IcLoginDetails>,id: String,password: String) -> Result<String,IcError> {
685	use schema::user;
686	let d = user::table.filter(user::global_id.eq(&id)).load::<User>(conn);
687	match d {
688	Ok(n) => {
689		if n.len() == 0 || n[0].password != password {
690			return Err(IcError("Error: wrong user/password.".to_string()));
691		} else {
692			//Make cookie and fill login
693			let start = SystemTime::now();
694			let since_the_epoch = start
695				.duration_since(UNIX_EPOCH)
696				.expect("Time went backwards")
697				.as_secs().to_string();
698			let mut hasher = Sha256::new();
699			let gid = (&id).to_string()+&password+&since_the_epoch;
700			hasher.update(&gid);
701			let cookie = format!("{:x}",hasher.finalize());
702			if *login == None {
703				*login = Some(IcLoginDetails{username: n[0].username.clone(),id: id.clone(),cookie: cookie.clone()});
704				return Ok(cookie);
705			} else { return Ok(cookie); }
706		}
707	}
708	Err(_e) => return Err(IcError("Error getting user.".to_string())),
709	}
710}
711
712pub fn parse_ic_packet(packet: IcPacket,modules: &(Vec<Library>,Vec<Box<dyn IcModule>>)) -> Result<(Vec::<String>,Box<dyn IcExecute<Connection = IcConnection>>),IcError> {
713	let mut cmd = packet.parse_header();
714	if cmd.len() == 0 {
715		cmd = Vec::new();
716		cmd.push("CORE".to_string());
717		cmd.push("NULL".to_string());
718	}
719	for m in &modules.1 {
720		if m.icm_get_name() == cmd[0] {
721			match m.icm_get_command(cmd[1..].to_vec()) {
722				Ok(v) => return Ok((cmd[1..].to_vec(),v)),
723				Err(e) => return Err(e),
724			}
725		}
726		
727	}
728	Err(IcError("NOT IMPLEMENTED".to_string()))
729}
730
731pub fn fetch_users(conn: &MysqlConnection,username: String) -> Vec<String> {
732	use schema::user;
733	let mut ret = Vec::<String>::new();
734	let d = user::table.filter(user::username.eq(&username)).load::<User>(conn);
735	match d {
736		Ok(v) => {
737			for user in v {
738				ret.push(user.global_id);
739			}
740		},
741		Err(_e) => (),
742	}
743	return ret
744}
745
746pub fn rename_account(conn: &mut IcConnection,new_name: &str) -> Result<String,Box<dyn Error>> {
747	use schema::user;
748	match diesel::update(user::table.filter(user::global_id.eq(&conn.login.as_ref().unwrap().id))).set(user::username.eq(new_name)).execute(&conn.backend_con) {
749		Ok(_v) => {
750			conn.login.as_mut().unwrap().username = new_name.to_string();
751			return Ok("OK!".to_string())
752		},
753		Err(e) => return Err(Box::new(e)),
754	}
755}
756
757pub fn change_password(conn: &mut IcConnection,password: &str) -> Result<String,Box<dyn Error>> {
758	use schema::user;
759	//HASH PASSWORD BEFORE UPDATING
760	let mut hasher = Sha512::new();
761	hasher.update(password);
762	let hp = format!("{:x}",hasher.finalize());
763	match diesel::update(user::table.filter(user::global_id.eq(&conn.login.as_ref().unwrap().id))).set(user::password.eq(hp)).execute(&conn.backend_con) {
764		Ok(_v) => {
765			return Ok("OK!".to_string())
766		},
767		Err(e) => return Err(Box::new(e)),
768	}
769}
770
771pub fn logout(conn: &mut IcConnection) -> Result<String,Box<dyn Error>> {
772	conn.login = None;
773	Ok("OK!".to_string())
774}
775
776pub fn validate_user(conn: &mut IcConnection,cookie: &str) -> Result<String,Box<dyn Error>> {
777	match &conn.login {
778		Some(l) => if l.cookie == cookie { return Ok(l.username.clone()) } 
779			else { return Err(Box::new(IcError("WRONG COOKIE".to_string()))) },
780		None => return Err(Box::new(IcError("NO LOGIN.".to_string()))),
781	};
782}