/// <summary> /// La funzione deve gestire la creazione di un nuovo file. /// </summary> public override bool Handle() { if(this.Stopped) return false; if (String.IsNullOrEmpty(base.FullPath)){ throw new Exception("Path e nome del file non validi."); } using(TcpClient connection = new TcpClient()){ connection.Connect(UserCredentials.Instance.Host, UserCredentials.Instance.Port); using (StreamReader sr = new StreamReader(connection.GetStream())) using (StreamWriter sw = new StreamWriter(connection.GetStream())) { //sr.BaseStream.ReadTimeout = 10000; //sw.BaseStream.WriteTimeout = 10000; /************************************ Inizio della funzione ***************************************/ string username = UserCredentials.Instance.Username; string accesstoken = UserCredentials.Instance.AccessToken; string allPath = this.FullPath; string subcmd = ProtocolStrings.SUBCMD_CREATE_MODIFY; long client_vfsversion = SyncToken.Instance.VFSVersion; try { string syncroPath = UserUtils.GetRootPath(); if (!allPath.StartsWith(syncroPath)) throw new Exception("File o root non validi."); string relativePath = allPath.Replace(syncroPath, "/"); //controlli if (String.IsNullOrEmpty(username) || String.IsNullOrEmpty(accesstoken)) { throw new Exception("Lo username o l'accesstoken non può essere nullo."); } if (!relativePath.StartsWith("/")) { throw new Exception("Il path deve iniziare con uno slash."); } if (!File.Exists(allPath)) { throw new Exception("Il path assoluto non esiste in questo file system"); } string name = Path.GetFileName(relativePath); string path = Path.GetDirectoryName(relativePath).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar; DateTime lastUpdate = File.GetLastWriteTime(allPath); FileInfo file = new FileInfo(allPath); long dim = file.Length; string hashFile = UserUtils.GetFileHash(allPath); if (String.IsNullOrEmpty(name) || name.StartsWith("\\")) { throw new Exception("Il nome del file non può essere nullo e non può iniziare con uno slash."); } if (String.IsNullOrEmpty(hashFile)) { throw new Exception("L'hash del file non può essere vuoto o nullo."); } if (dim < 0) { throw new Exception("La dimensione del file non può essere negativa."); } long nchunkUser = (long)Math.Ceiling(((double)file.Length / (double)ProtocolStrings.CHUNK_SIZE)); if (nchunkUser < 0) { throw new Exception("Il numero di chunk del file non può essere negativo."); } //la lista di chunk da inviare al server List<VChunk> listChunk = new List<VChunk>(); PushFile_D pD = null; //primo controllo da fare if (this.Stopped) return false; //apro il file e calcolo il numero di chunk using (FileStream fs = new FileStream(allPath, FileMode.Open, FileAccess.Read, FileShare.Delete)) { byte[] c = new byte[ProtocolStrings.CHUNK_SIZE]; string hashChunk; VChunk vc = null; for (long i = 0; i < nchunkUser; i++) { if (this.Stopped) return false; int l = fs.Read(c, 0, c.Count()); hashChunk = UserUtils.GetHash(c, l); vc = new VChunk(i, -1, -1, hashChunk, l, lastUpdate); listChunk.Add(vc); } if (this.Stopped) return false; //invio la richiesta PushFile_A req = new PushFile_A(username, accesstoken, subcmd, name, path, lastUpdate, hashFile, dim, nchunkUser, client_vfsversion, listChunk); UserUtils.NetworkWriteLine(sw, req.ToJSON()); //attendo la risposta del server string rec = UserUtils.NetworkReadLine(sr); Response r = Response.fromJson(rec); if (r.Result == 401) { //problemi con la login T (token) throw new UserLoginException(BadLoginResponse.fromJson(rec).Msg); } else if (r.Result != 200) { throw new Exception(BadPushFileResponse.fromJson(rec).Msg); } if (this.Stopped) return false; PushFile_Abis pAbis = PushFile_Abis.fromJson(rec); //ora il server mi deve mandare la lista di chunk che gli devo inviare //N.B. se la lista è vuota devo andare direttamente all'ultima operazione. if (pAbis.NChunk > 0) { PushFile_B pB = null; byte[] filledChunk = new byte[ProtocolStrings.CHUNK_SIZE]; long id = -1; fs.Seek(0, SeekOrigin.Begin); do { if (this.Stopped) return false; pB = PushFile_B.fromJson(UserUtils.NetworkReadLine(sr)); id = pB.IdChunk; fs.Seek(id * (ProtocolStrings.CHUNK_SIZE), SeekOrigin.Begin); int l = fs.Read(filledChunk, 0, (int)ProtocolStrings.CHUNK_SIZE); //TODO con l'ultimo chunk sprechiamo byte(inviamo byte inutili). PushFile_C pC = new PushFile_C(filledChunk, l); UserUtils.NetworkWriteLine(sw, pC.toJSON()); } while (!pB.Done); } pD = PushFile_D.fromJson(UserUtils.NetworkReadLine(sr)); /** N.B. da qui in poi non dobbiamo più stoppare il thread perché il server ha committato **/ } //ora devo andare a salvare il synctoken (che poi sarebbe il vfsversion) SyncToken.Instance.VFSVersion = pD.NewVfsversion; } catch (SocketException e) { throw new NetworkException("Si è verificato un errore di rete.", e); } catch (UserLoginException e) { throw e; } catch (IOException e) { if ((uint)e.HResult == FILE_IN_USE) { throw new FileInUseException("Il file è in uso da un altro processo, verrà gestito più tardi."); } } catch (Exception e) { throw new PushFileExceptionU(e.Message); } /**************************************** Fine della funzione ***************************************/ } } return true; }
public static long DoPushFile(string username, string accesstoken, string allPath, string subcmd, long client_vfsversion, StreamWriter sw, StreamReader sr) { try { string syncroPath = GetRootPath(); if (!allPath.StartsWith(syncroPath)) throw new Exception("File o root non validi."); string relativePath = allPath.Replace(syncroPath, "/"); //controlli if(String.IsNullOrEmpty(username) || String.IsNullOrEmpty(accesstoken)){ throw new Exception("Lo username o l'accesstoken non può essere nullo."); } if (!relativePath.StartsWith("/")) { throw new Exception("Il path deve iniziare con uno slash."); } File.Exists(allPath); string name = Path.GetFileName(relativePath); string path = Path.GetDirectoryName(relativePath); path = path.TrimEnd(Path.DirectorySeparatorChar); path += Path.DirectorySeparatorChar; DateTime lastUpdate = File.GetLastWriteTime(allPath); FileInfo file = new FileInfo(allPath); long dim = file.Length; string hashFile = GetFileHash(allPath); if(String.IsNullOrEmpty(name) || name.StartsWith("\\")){ throw new Exception("Il nome del file non può essere nullo e non può iniziare con uno slash."); } if(String.IsNullOrEmpty(hashFile)){ throw new Exception("L'hash del file non può essere vuoto o nullo."); } if(dim<0){ throw new Exception("La dimensione del file non può essere negativa."); } FileInfo finfo = new FileInfo(allPath); long nchunkUser = (long)Math.Ceiling(((double)finfo.Length / (double)ProtocolStrings.CHUNK_SIZE)); if(nchunkUser<0){ throw new Exception("Il numero di chunk del file non può essere negativo."); } //la lista di chunk da inviare al server List<VChunk> listChunk = new List<VChunk>(); PushFile_D pD = null; //apro il file e calcolo il numero di chunk using (FileStream fs = File.OpenRead(allPath)) { byte[] c = new byte[ProtocolStrings.CHUNK_SIZE]; string hashChunk; VChunk vc = null; for (long i = 0; i < nchunkUser; i++) { int l = fs.Read(c, 0, c.Count()); hashChunk = GetHash(c,l); vc = new VChunk(i, -1, -1, hashChunk, l, lastUpdate); listChunk.Add(vc); } //invio la richiesta PushFile_A req = new PushFile_A(username, accesstoken, subcmd, name, path, lastUpdate, hashFile, dim, nchunkUser, client_vfsversion, listChunk); NetworkWriteLine(sw, req.ToJSON()); //attendo la risposta del server string rec = NetworkReadLine(sr); Response r = Response.fromJson(rec); if (r.Result == 401) { //problemi con la login T (token) throw new UserLoginException(BadLoginResponse.fromJson(rec).Msg); } else if(r.Result != 200){ throw new Exception(BadPushFileResponse.fromJson(rec).Msg); } PushFile_Abis pAbis = PushFile_Abis.fromJson(rec); //ora il server mi deve mandare la lista di chunk che gli devo inviare //N.B. se la lista è vuota devo andare direttamente all'ultima operazione. if (pAbis.NChunk > 0) { PushFile_B pB = null; byte[] filledChunk = new byte[ProtocolStrings.CHUNK_SIZE]; long id = -1; fs.Seek(0, SeekOrigin.Begin); do { pB = PushFile_B.fromJson(NetworkReadLine(sr)); id = pB.IdChunk; fs.Seek(id * (ProtocolStrings.CHUNK_SIZE), SeekOrigin.Begin); int l = fs.Read(filledChunk, 0, (int)ProtocolStrings.CHUNK_SIZE); //TODO con l'ultimo chunk sprechiamo byte(inviamo byte inutili). PushFile_C pC = new PushFile_C(filledChunk, l); NetworkWriteLine(sw, pC.toJSON()); } while (!pB.Done); } pD = PushFile_D.fromJson(NetworkReadLine(sr)); } //ora devo andare a salvare il synctoken (che poi sarebbe il vfsversion) return pD.NewVfsversion; } catch (NetworkException e) { throw e; } catch (UserLoginException e) { throw e; } catch (Exception e) { throw new PushFileExceptionU(e.Message); } }