/// <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;
        }
Beispiel #2
0
        public void HandlePushFile(PushFile_A req, StreamReader sr, StreamWriter sw, ConnectionHandler connHandler)
        {
            // Controllo degli argomenti
            if (String.IsNullOrEmpty(req.Name))
                throw new PushFileException("Il nome del file è invalido.");
            if (String.IsNullOrEmpty(req.Path))
                throw new PushFileException("Il path del file invalido.");
            if (req.Name.StartsWith("/"))
                throw new PushFileException("Il nome del file non può iniziare per slash.");
            if (!req.Path.StartsWith("\\") || !req.Path.EndsWith("\\"))
                throw new PushFileException("Il Path deve iniziare con slash e deve terminare con un backslash.");
            if (req.Name.Contains("/") || req.Name.Contains("\\"))
                throw new PushFileException("Carattere non valido nel nome del file.");
            lock (this)
            {
                try
                {
                    // Controlla che lo user sia sincronizzato.
                    SQLiteConnection conn;
                    string dir;
                    string db = UserManager.Instance.GetUserDbPath(this.Id, out dir);
                    using (conn = new SQLiteConnection(String.Format("Data Source={0};Version=3;", db)))
                    {
                        conn.Open();
                        using (SQLiteTransaction tr = conn.BeginTransaction())
                        {
                            try
                            {
                                using (SQLiteCommand cmd = conn.CreateCommand())
                                {
                                    PushFile_Abis pAbis = null;
                                    PushFile_B pB = null;
                                    PushFile_C pC = null;
                                    IEnumerable<VChunk> neededChunks = null;
                                    long vfsversion = -1;
                                    long version = -1;
                                    long fid = -1;

                                    // Gestione richiesta PushFileA
                                    try
                                    {
                                        // Controlla che lo user sia allineato in termini di versione del vfs
                                        cmd.CommandText = "SELECT ifnull(max(vfsversion),-1) FROM files WHERE iduser = $iduser";
                                        cmd.Parameters.AddWithValue("iduser", this.Id);
                                        long currver = (long)cmd.ExecuteScalar();

                                        //se non è allineato, sollevare un'eccezzione di tipo needed sync
                                        cmd.Parameters.Clear();

                                        if (currver > req.ClientVfsVersion)
                                            throw new NotSynchedException("La versione del client " + req.ClientVfsVersion + " non corrisponde all'ultima del server " + currver + ", perciò il push di qualsiasi file è disabilitato.");

                                        // Se lo user è allineato controlla se il file è nuovo, ovvero se esiste già un file con medesimo path e nome
                                        cmd.CommandText = "SELECT ifnull(id,-1) "
                                                            + "FROM files "
                                                            + "WHERE name = $name AND path=$path AND iduser=$iduser ";

                                        cmd.Parameters.AddWithValue("name", req.Name);
                                        cmd.Parameters.AddWithValue("path", req.Path);
                                        cmd.Parameters.AddWithValue("iduser", this.Id);

                                        bool exists = false;

                                        using (SQLiteDataReader r = cmd.ExecuteReader())
                                        {
                                            if (r.Read())
                                            {
                                                fid = r.GetInt64(0);
                                                exists = true;
                                            }
                                            else
                                            {
                                                //qui devo discriminare un file spostato, da un file rinominato, da un file creato a partire da una copia già esistente.
                                                fid = -1;
                                                exists = false;
                                            }
                                        }

                                        bool delete = req.SubCmd == ProtocolStrings.SUBCMD_DELETE;
                                        if (delete && (req.Nchunk > 0 || req.Dimension > 0))
                                            throw new PushFileException("Incoerenza: si è specificato il subcmd di tipo deleted ma nchunk o dimensione del file sono maggiori di 0.");

                                        // Se il file non esisteva, procedo all'inserimento
                                        //N.B. cado in questo caso anche quando sposto o rinomino un file
                                        if (!exists)
                                        {
                                            // Non si possono eliminare file inesistenti :)
                                            if (delete)
                                                throw new FileNotFoundException("Non è possibile eliminare un file che non esiste!");

                                            // Non posso inserire un file contenuto in una cartella se la cartella non esiste.

                                            // TODO
                                            // Devo selezionare la cartella parent relativa al file che voglio pushare
                                            // Se la cartella esiste, return true -> posso andare avanti
                                            // Altrimenti throw new exception().
                                            cmd.Parameters.Clear();
                                            cmd.CommandText = "SELECT path from directories WHERE path=$path AND iduser=$iduser ";
                                            cmd.Parameters.AddWithValue("path",req.Path);
                                            cmd.Parameters.AddWithValue("iduser", this.Id);

                                            using (SQLiteDataReader r = cmd.ExecuteReader()) {
                                                if (!r.Read())
                                                    throw new PushFileException("Il file "+req.Name+" non può essere inserito perchè non è stata ancora inserita la cartella parent a cui appartiene: "+req.Path);
                                            }

                                            // Battezzo un fileid per l'inserimento
                                            cmd.CommandText = "SELECT ifnull(max(id),-1), ifnull(max(vfsversion),-1) "
                                                            + "FROM files "
                                                            + "WHERE iduser=$iduser ";

                                            cmd.Parameters.AddWithValue("iduser", this.Id);

                                            using (SQLiteDataReader r = cmd.ExecuteReader())
                                            {
                                                if (!r.Read())
                                                    throw new PushFileException("Errore durante query nel db");
                                                fid = r.GetInt64(0);
                                                vfsversion = r.GetInt64(1);
                                            }

                                            fid++;
                                        }
                                        else
                                        {

                                            // Se il file esiste già, ne recupero l'ultima versione
                                            cmd.CommandText = "SELECT max(version), max(vfsversion) "
                                                            + "FROM files "
                                                            + "WHERE iduser=$iduser AND id=$id";

                                            cmd.Parameters.AddWithValue("iduser", this.Id);
                                            cmd.Parameters.AddWithValue("id", fid);

                                            using (SQLiteDataReader r = cmd.ExecuteReader())
                                            {
                                                if (!r.Read())
                                                    throw new PushFileException("Errore durante query nel db");
                                                version = r.GetInt64(0);
                                            }

                                            cmd.Parameters.Clear();
                                            cmd.CommandText = "SELECT max(vfsversion) "
                                                            + "FROM files "
                                                            + "WHERE iduser=$iduser";
                                            cmd.Parameters.AddWithValue("iduser", this.Id);

                                            using (SQLiteDataReader r = cmd.ExecuteReader())
                                            {
                                                if (!r.Read())
                                                    throw new PushFileException("Errore durante query nel db");
                                                vfsversion = r.GetInt64(0);
                                            }
                                        }

                                        //Se il file è nuovo, neededChunks conterrà tutti i chunk che formano il nuovo file
                                        neededChunks = exists ? GetNeededChunks(fid, version, req) : req.ListChunk;

                                        /* L'utente si PUO' FARE I FOTTUTI CAZZI SUA.
                                        //TODO
                                        //Se il file che il client mi ha mandato è esattamente lo stesso file che il server aveva già, lancia un'eccezzione!
                                        if (neededChunks.Count() == 0)
                                        {
                                            // Controllo
                                            cmd.Parameters.Clear();
                                            cmd.CommandText = "SELECT nchunk, name, path, dimension, lastupdate, hash "
                                                            + "FROM files "
                                                            + "WHERE id=$id AND version=$version AND iduser=$iduser";
                                            cmd.Parameters.AddWithValue("id", fid);
                                            cmd.Parameters.AddWithValue("version", version);
                                            cmd.Parameters.AddWithValue("iduser", this.Id);

                                            using (SQLiteDataReader r = cmd.ExecuteReader())
                                            {
                                                // Non dovrebbe mai accadere
                                                if (r.Read())
                                                {
                                                    // Solo se il file esisteva, controlla se i metadati sono cambiati.
                                                    long nchunks = r.GetInt64(0);
                                                    string name = r.GetString(1);
                                                    string path = r.GetString(2);
                                                    long dimension = r.GetInt64(3);
                                                    DateTime dt = DateTime.Parse(r.GetString(4));
                                                    string hash = r.GetString(5);

                                                    // Se nessuna di queste informazioni è cambiata, non ha senso continuare nell'inserimento! Il file è uguale!
                                                    if (nchunks == req.Nchunk && name == req.Name && path == req.Path && dimension == req.Dimension && dt == req.LastUpdate && hash == req.Hash)
                                                        throw new PushFileException("Si sta tentando di inserire un file identico a quello precedente.");

                                                }

                                            }
                                        }
                                        */
                                        string deletedhash = null;
                                        // Se è stata richiesta una eliminazione, devo recuperare l'ultimo hash del file ed inserire quello nel record
                                        // del file eliminato
                                        if (delete)
                                        {
                                            cmd.Parameters.Clear();
                                            cmd.CommandText = "SELECT hash "
                                                            + "FROM files  "
                                                            + "WHERE id=$id AND version=$version AND iduser=$iduser";
                                            cmd.Parameters.AddWithValue("id", fid);
                                            cmd.Parameters.AddWithValue("version", version);
                                            cmd.Parameters.AddWithValue("iduser", this.Id);
                                            deletedhash = (string)cmd.ExecuteScalar();
                                        }

                                        // In ogni caso incremento la versione.
                                        version++;
                                        vfsversion++;
                                        // A questo punto ho il fileid, la versione del file e la vfsversion popolate.

                                        // Controllo la coerenza della richiesta: il numero di chunk deve essere compatibile con il nostro sistema immgazzinamento.
                                        if (req.Nchunk != Math.Ceiling((double)((double)req.Dimension / (double)ProtocolStrings.CHUNK_SIZE)))
                                        {
                                            throw new PushFileException("Numero di chunk ricevuti incoerente!");
                                        }

                                        // Procedo con l'inserimento nella tabella files
                                        cmd.Parameters.Clear();
                                        cmd.CommandText = "INSERT INTO files(id, version, vfsversion, nchunk, name, path, dimension, lastupdate, deleted, hash, iduser) "
                                                        + "VALUES($id,$version,$vfsversion, $nchunk, $name, $path, $dimension, $dt, $deleted, $hash, $iduser) ";

                                        cmd.Parameters.AddWithValue("id", fid);
                                        cmd.Parameters.AddWithValue("version", version);
                                        cmd.Parameters.AddWithValue("vfsversion", vfsversion);
                                        cmd.Parameters.AddWithValue("nchunk", delete ? 0 : req.Nchunk); //size/nchunk
                                        cmd.Parameters.AddWithValue("name", req.Name);
                                        cmd.Parameters.AddWithValue("path", req.Path);
                                        cmd.Parameters.AddWithValue("dimension", req.Dimension);
                                        cmd.Parameters.AddWithValue("dt", req.LastUpdate);
                                        cmd.Parameters.AddWithValue("deleted", delete ? 1 : 0);
                                        cmd.Parameters.AddWithValue("hash", delete ? deletedhash : req.Hash);
                                        cmd.Parameters.AddWithValue("iduser", this.Id);
                                        if (cmd.ExecuteNonQuery() != 1)
                                        {
                                            throw new PushFileException("Errore durante query nel db");
                                        }

                                        //Setto il timeout sullo stream reader e writer perché il send e receive di messaggi
                                        //tra client e server potrebbe fallire
                                        //TODO ripristinare dopo test
                                        sr.BaseStream.ReadTimeout = (int)Properties.Settings.Default.READER_TIMEOUT;
                                        sw.BaseStream.WriteTimeout = (int)Properties.Settings.Default.WRITER_TIMEOUT;

                                        //TODO
                                        pAbis = new PushFile_Abis(String.Format("Sono necessari {0} chunks per quest operazione.", neededChunks.Count()), neededChunks.Count());
                                        sw.WriteLine(pAbis.toJSON());
                                        sw.Flush();
                                    }
                                    catch (FileNotFoundException e) {
                                        // Se ho ricevuto un qualsiasi errore, mando un esito negativo
                                        // che a questo livello del protocollo si traduce con una risposta PushFile_Abis
                                        pAbis = new PushFile_Abis(404,"Il client ha richiesto l'eliminazione di un file non presente sul server",-1);
                                        sw.WriteLine(pAbis.toJSON());
                                        sw.Flush();
                                    }
                                    catch (Exception e)
                                    {
                                        // Se ho ricevuto un qualsiasi errore, mando un esito negativo
                                        // che a questo livello del protocollo si traduce con una risposta PushFile_Abis
                                        pAbis = new PushFile_Abis("Si è verificato un errore durante la gestione della prima parte del protocollo di push: " + e.Message, -1, false);
                                        sw.WriteLine(pAbis.toJSON());
                                        sw.Flush();

                                        // A questo punto rilancia al chiamante.
                                        throw e;
                                    }

                                    // TODO: eventuale gestione di pushfileC/D in caso di errore. Non riesco a vedere immediate situazioni di anomalia, quindi
                                    // per il momento posticipiamo queste gestioni.
                                    for (int i = 0; i < neededChunks.Count(); i++)
                                    {
                                        VChunk chnk = neededChunks.ElementAt(i);
                                        // Invio una richiesta di trasferimento chunk
                                        pB = new PushFile_B("Mandami il chunk " + i, chnk.Id, i == neededChunks.Count() - 1); // Nota, I == ID.
                                        sw.WriteLine(pB.toJSON());
                                        sw.Flush();

                                        // Leggo la risposta dal client
                                        string str = sr.ReadLine();
                                        pC = PushFile_C.fromJson(str);
                                        string hashchunk = GetHash(pC.Data,(int)pC.Length);
                                        if (hashchunk != chnk.Hash)
                                        {
                                            throw new PushFileException("L'hash ricevuto non è conforme a quello appena calcolato");
                                        }
                                        if (chnk.Dim != pC.Length)
                                            throw new PushFileException("Dimensioni incoerenti tra PushA e PushC");

                                        cmd.Parameters.Clear();
                                        cmd.CommandText = "INSERT INTO chunks(id, idfile, version, hash, dimension, lastupdate, data) "
                                                    + "VALUES($id,$idfile,$version, $hash, $dimension, $lastupdate, $data) ";

                                        cmd.Parameters.AddWithValue("id", i);
                                        cmd.Parameters.AddWithValue("idfile", fid);
                                        cmd.Parameters.AddWithValue("version", version); //prima versione del file
                                        cmd.Parameters.AddWithValue("hash", hashchunk);
                                        cmd.Parameters.AddWithValue("dimension", pC.Length);
                                        cmd.Parameters.AddWithValue("lastupdate", chnk.LastUpdate);
                                        cmd.Parameters.AddWithValue("data", pC.Data);
                                        if (cmd.ExecuteNonQuery() != 1)
                                        {
                                            throw new PushFileException("Errore durante query nel db");
                                        }

                                    }
                                    //abbiamo ricevuto tutti i chunk
                                    PushFile_D pD = new PushFile_D("File sincronizzato. Invio il nuovo vfsVersion.", vfsversion);
                                    sw.WriteLine(pD.toJSON());
                                    sw.Flush();

                                    // Se tutto è andato bene, committa la transazione.
                                    tr.Commit();

                                    _nCounter++;
                                    Monitor.PulseAll(this);
                                }
                            }
                            catch (Exception e)
                            {
                                // ROLLBACK THE ENTIRE WORLD
                                tr.Rollback();
                                throw e;
                            }
                            finally {
                                //Resetto i valori di timeout all'infinito.
                                sr.BaseStream.ReadTimeout = sr.BaseStream.ReadTimeout = System.Threading.Timeout.Infinite;
                                sw.BaseStream.WriteTimeout = sr.BaseStream.ReadTimeout = System.Threading.Timeout.Infinite;
                            }
                        }
                    }
                }
                catch (Exception e) {
                    throw new PushFileException(e.Message);
                }
            }
        }
        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);
            }
        }
Beispiel #4
0
        private IEnumerable<VChunk> GetNeededChunks(long fid, long fversion, PushFile_A req)
        {
            // NOTA BENE: Il lock deve essere acquisito dal chiamante.

            // Recupero tutti i chunks dell'ultima versione del file
            IEnumerable<VChunk> all = GetFileChunks(fid, fversion);
            List<VChunk> res = new List<VChunk>();

            if (req.ListChunk.Count() > all.Count())
            {
                // Il client ha esteso il file
                // Filtro solo quelli che sono cambiati
                for (int i = 0; i < req.ListChunk.Count() && i<all.Count(); i++)
                {
                    if (all.ElementAt(i).Hash.CompareTo(req.ListChunk.ElementAt(i).Hash) != 0)
                        res.Add(req.ListChunk.ElementAt(i));
                }
                // Aggiungo i restanti
                for (int i = all.Count(); i < req.ListChunk.Count(); i++)
                    res.Add(req.ListChunk.ElementAt(i));
            }
            else
            {
                // Il client ha ridotto il file
                // Filtro solo quelli che sono cambiati
                for (int i = 0; i < req.ListChunk.Count(); i++)
                {
                    if (all.ElementAt(i).Hash.CompareTo(req.ListChunk.ElementAt(i).Hash) != 0)
                        res.Add(req.ListChunk.ElementAt(i));
                }
            }
            return res;
        }