/// <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;
        }
Example #2
0
        /// <summary>
        /// Dato un fileid, una versione del file partenza ed una di arrivo, questa funzione calcola tutti i chunk modificati
        /// che è necessario aggiornare e li ritorna in una lista.
        /// </summary>
        /// <param name="fileId"></param>
        /// <param name="startVersion"></param>
        /// <param name="targetVersion"></param>
        /// <returns></returns>
        public IEnumerable<VChunk> GetFileChunksUpdates(long fileId, long client_vfsversion, long fileTargetVersion)
        {
            if (fileTargetVersion < 0)
            {
                throw new JsonRequestException("TargetVersion non può essere negativo.");
            }

            /*
            if (startVersion > targetVersion)
                throw new JsonRequestException("Start version non può essere maggiore di targetVersion.");
            */
            //startVersion = Math.Min(startVersion, targetVersion);

            lock (this)
            {
                List<VChunk> res = new List<VChunk>();
                try
                {
                    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 (SQLiteCommand cmd = conn.CreateCommand())
                        {
                            // Recupero gli nchunk per il file id dato.
                            cmd.CommandText = "SELECT ifnull(nchunk,0) FROM files WHERE id = $fileid AND version = $targetVersion AND iduser = $iduser";
                            cmd.Parameters.AddWithValue("fileid", fileId);
                            cmd.Parameters.AddWithValue("targetVersion", fileTargetVersion);
                            cmd.Parameters.AddWithValue("iduser", this.Id);
                            long nchunk = -1;
                            long clientFileVersion = -1;
                            using (SQLiteDataReader r = cmd.ExecuteReader()) {
                                if (!r.Read())
                                    throw new UserDonwloadFilException("Non è stato trovato alcun match per i parametri specificati. Si prega di controllare la versione e l'id del file.");
                                else
                                {
                                    nchunk = r.GetInt64(0);
                                }
                            }

                            cmd.Parameters.Clear();
                            // RECUPERIAMO LA VERSIONE DEL FILE CHE IL CLIENT HA, DATO IL SUO VFSVERSION
                            cmd.CommandText = "SELECT IFNULL(MAX(version),-1) FROM files "
                                             +"WHERE iduser = $iduser AND id=$fileid "
                                             +"AND vfsversion<=$client_vfsversion";
                            cmd.Parameters.AddWithValue("iduser",this.Id);
                            cmd.Parameters.AddWithValue("fileid",fileId);
                            cmd.Parameters.AddWithValue("client_vfsversion", client_vfsversion);

                            using (SQLiteDataReader r = cmd.ExecuteReader()) {
                                if (r.Read())
                                    clientFileVersion = r.GetInt64(0);
                                else
                                    clientFileVersion = -1;
                            }
                            cmd.Parameters.Clear();
                            // Eseguimo la query TOP
                            cmd.CommandText = "SELECT id, idfile,version,hash,dimension,lastupdate FROM chunks "
                                               + "WHERE idfile = $idfile AND version >$m AND version <= (SELECT MAX(C1.version) FROM chunks C1 WHERE C1.id = id AND version <=$n) "
                                               + "GROUP BY id "
                                               + "HAVING id<$nchunk";

                            cmd.Parameters.AddWithValue("idfile", fileId);
                            cmd.Parameters.AddWithValue("m", clientFileVersion);
                            cmd.Parameters.AddWithValue("n", fileTargetVersion);
                            cmd.Parameters.AddWithValue("nchunk", nchunk);

                            using (var r = cmd.ExecuteReader())
                            {
                                while (r.Read())
                                {
                                    long id = r.GetInt64(0);
                                    long idfile = r.GetInt64(1);
                                    long version = r.GetInt64(2);
                                    string hash = r.GetString(3);
                                    long dim = r.GetInt64(4);
                                    DateTime lastupdate = DateTime.Parse(r.GetString(5));

                                    VChunk tmp = new VChunk(id, idfile, version, hash, dim, lastupdate);
                                    res.Add(tmp);
                                }
                            }
                            return res;
                        }

                    }
                }
                catch (Exception e)
                {
                    throw new UserDonwloadFilException(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);
            }
        }
Example #4
0
        /// <summary>
        /// Dato un fileid ed una versione del file da ottenere, questa funzione ritorna l'intera lista di chunk che descrive il file.
        /// Con questa lista è quindi possibile recuperare tutto il file alla versione specificata.
        /// </summary>
        /// <param name="fileId"></param>
        /// <param name="targetVersion"></param>
        /// <returns></returns>
        public IEnumerable<VChunk> GetFileChunks(long fid, long tVer, bool donotlock = false)
        {
            if (tVer < 0)
            {
                throw new JsonRequestException("TargetVersion non può essere negativo.");
            }

            Del d = delegate(long fileId, long targetVersion)
            #region
            {
                List<VChunk> res = new List<VChunk>();
                try
                {
                    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 (SQLiteCommand cmd = conn.CreateCommand())
                        {
                            // Recupero gli nchunk per il file id dato.
                            cmd.CommandText = "SELECT ifnull(nchunk,0) FROM files WHERE id = $fileid AND version = $targetVersion AND iduser = $iduser";
                            cmd.Parameters.AddWithValue("fileid", fileId);
                            cmd.Parameters.AddWithValue("targetVersion", targetVersion);
                            cmd.Parameters.AddWithValue("iduser", this.Id);
                            long nchunk = (long)cmd.ExecuteScalar();

                            cmd.Parameters.Clear();
                            cmd.CommandText = "SELECT id,idfile,version,hash,dimension,lastupdate "
                                                + "FROM chunks "
                                                + "WHERE idfile = $fileid AND version <= (SELECT MAX(C1.version) FROM chunks C1 WHERE C1.id = id AND version <=$n) "
                                                + "GROUP BY id "
                                                + "HAVING id<$nchunk "
                                                + "ORDER BY id ASC ";

                            cmd.Parameters.AddWithValue("fileid", fileId);
                            cmd.Parameters.AddWithValue("n", targetVersion);
                            cmd.Parameters.AddWithValue("nchunk", nchunk);

                            using (var r = cmd.ExecuteReader())
                            {
                                while (r.Read())
                                {
                                    long id = r.GetInt64(0);
                                    long idfile = r.GetInt64(1);
                                    long version = r.GetInt64(2);
                                    string hash = r.GetString(3);
                                    long dim = r.GetInt64(4);
                                    DateTime lastupdate = DateTime.Parse(r.GetString(5));

                                    VChunk tmp = new VChunk(id, idfile, version, hash, dim, lastupdate);
                                    res.Add(tmp);
                                }
                            }
                            return res;
                        }

                    }
                }
                catch (Exception e)
                {
                    throw new UserDonwloadFilException(e.Message);
                }
            };
            #endregion

            if (donotlock)
            {
                return d(fid, tVer);
            }
            else
            {
                lock (this)
                {
                    return d(fid, tVer);
                }
            }
        }