private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { //ServicePointManager.ServerCertificateValidationCallback=delegate //{ // return true; //}; RemoteCertificateValidationCallback certificateCallback=new RemoteCertificateValidationCallback(ValidateServerCertificate); string syncFolder=Globals.Options.GetElementAsString("xml.Options.Paths.SyncFolder"); string ftpServer=Globals.Options.GetElementAsString("xml.Options.FTP.Server"); string ftpUser=Globals.Options.GetElementAsString("xml.Options.FTP.User"); string ftpPassword=Globals.Options.GetElementAsString("xml.Options.FTP.Password"); string ftpProtocol=Globals.Options.GetElementAsString("xml.Options.FTP.Protocol"); if(FileSystem.ExistsDirectory(syncFolder)) { if(ftpServer!=""&&ftpUser!=""&ftpPassword!=""&ftpProtocol!="") { //Connect FTPSClient client=new FTPSClient(); //NetworkCredital NetworkCredential credential=new NetworkCredential(ftpUser, ftpPassword); //client.Connect(ftpServer, credential, ESSLSupportMode.ControlAndDataChannelsRequired); client.Connect(ftpServer, credential, ESSLSupportMode.ControlAndDataChannelsRequired, certificateCallback); #region Verzeichnisstruktur überprüfen und nach Bedarf anlegen //Test auf leeres Verzeichnis IList<DirectoryListItem> files=client.GetDirectoryList(); bool existXData=false; bool existHData=false; bool existLData=false; bool existCData=false; bool existMData=false; bool existRData=false; bool existCfsInfo=false; foreach(DirectoryListItem file in files) { if(file.IsDirectory) { switch(file.Name) { case "x-data": { existXData=true; break; } case "h-data": { existHData=true; break; } case "l-data": { existLData=true; break; } case "c-data": { existCData=true; break; } case "m-data": { existMData=true; break; } case "r-data": { existRData=true; break; } } } else //File { switch(file.Name) { case "cfsinfo": { existCfsInfo=true; break; } } } } //CfsInfo anlegen if(existCfsInfo==false) { List<string> version=new List<string>(); version.Add("1"); //Repository Version string versionFilenameLocal=FileSystem.TempPath+"cfsinfo-"+Various.GetTimeID(); File.WriteAllLines(versionFilenameLocal, version.ToArray()); client.PutFile(versionFilenameLocal, "cfsinfo"); } else //Version überprüfen { string versionFilenameLocal=FileSystem.TempPath+"cfsinfo-"+Various.GetTimeID(); client.GetFile("cfsinfo", versionFilenameLocal); string[] cfsinfo=File.ReadAllLines(versionFilenameLocal); int version=Convert.ToInt32(cfsinfo[0]); if(version!=1) { MessageBox.Show("CloudFileSync ist nicht mit der Version des Repositories kompatibel!", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } } if(existXData==false) client.MakeDir("x-data"); //Datenordner if(existHData==false) client.MakeDir("h-data"); //Hashdaten if(existLData==false) client.MakeDir("l-data"); //Lockdaten if(existCData==false) client.MakeDir("c-data"); //Createdaten if(existMData==false) client.MakeDir("m-data"); //Modifieddaten if(existRData==false) client.MakeDir("r-data"); //Removedaten //Überprüfen ob meine Clientverzeichnisse existieren CheckAndCreateClientFolder(client, "c-data"); CheckAndCreateClientFolder(client, "m-data"); CheckAndCreateClientFolder(client, "r-data"); #endregion //Init Datenbestand (Sync) UpdateFromRemote(client, syncFolder); //Neu erzeugte oder geänderte Dateien ermitteln List<string> syncFolderFiles=FileSystem.GetFiles(syncFolder, true); //Neue Lokale Dateien hochladen foreach(string file in syncFolderFiles) { string relFilename=FileSystem.GetRelativePath(file, syncFolder, true); string hashRemote=GetHistoryHash(client, relFilename); string hashLocal=Hash.SHA1.HashFile(file); if(hashRemote!=hashLocal) { filesCreated.Add(file); } } //gelöschte Dateien ermitteln List<string> hashFiles=GetHashFiles(client); foreach(string hashFile in hashFiles) { string filenameToTest=FileSystem.GetPathWithPathDelimiter(syncFolder)+hashFile.Replace('\\', FileSystem.PathDelimiter); syncFolderFiles.Remove(filenameToTest); } foreach(string file in syncFolderFiles) { if(filesCreated.IndexOf(file)==-1) //Datei soll nicht hochgeladen werden, sondern wurde wirklich auf einem anderen Client gelöscht { string relFilename=FileSystem.GetRelativePath(file, syncFolder, true); FileSystem.RemoveFile(file); Globals.Log.Add(LogLevel.Information, "Lokal: Datei {0} wurde gelöscht.", relFilename); } } //FilesystemWatcher aktivieren fileSystemWatcher.Path=syncFolder; fileSystemWatcher.EnableRaisingEvents=true; #region Endlosschleife für Syncronisation while(true) { if(e.Cancel==true) return; List<string> fileToRemoveFromList=new List<string>(); //Dateien hochladen #region Created files lock(filesCreated) { foreach(string fileCreated in filesCreated) { string relFilename=FileSystem.GetRelativePath(fileCreated, syncFolder, true); relFilename=relFilename.Replace("\\", "/"); bool locked=GetFileLock(client, relFilename); if(locked) { if(FileSystem.IsDirectory(fileCreated)) //Directory { client.CreateDirectory("x-data/"+relFilename); fileToRemoveFromList.Add(fileCreated); Globals.Log.Add(LogLevel.Information, "Remote: Verzeichnis {0} wurde erstellt (x-data).", relFilename); //In Created Verzeichnisse legen AddFileToUpdateFolder(client, "c-data", relFilename, EFileType.Directory); //Globals.Log.Add(LogLevel.Information, "Updatedatei {0} wurde hochgeladen (c-data).", relFilename); } else //File { //Hashdatei ändern AddHistoryHash(client, fileCreated, relFilename); Globals.Log.Add(LogLevel.Information, "Remote: Hash für {0} wurde geändert (x-data).", relFilename); //Datei hochladen CreateFTPDirectories(client, "x-data/"+relFilename); client.PutFile(fileCreated, "x-data/"+relFilename); fileToRemoveFromList.Add(fileCreated); Globals.Log.Add(LogLevel.Information, "Remote: Datei {0} wurde hochgeladen (x-data).", relFilename); //In Created Verzeichnisse legen AddFileToUpdateFolder(client, "c-data", relFilename, EFileType.File); //Globals.Log.Add(LogLevel.Information, "Updatedatei {0} wurde hochgeladen (c-data).", relFilename); } } RemoveFileLock(client, relFilename); } foreach(string rFile in fileToRemoveFromList) { filesCreated.Remove(rFile); } } fileToRemoveFromList.Clear(); #endregion #region Changed Files lock(filesChanged) { foreach(string fileChanged in filesChanged) { string relFilename=FileSystem.GetRelativePath(fileChanged, syncFolder, true); relFilename=relFilename.Replace("\\", "/"); bool locked=GetFileLock(client, relFilename); if(locked) { if(FileSystem.IsDirectory(fileChanged)) //Directory { //Sollte bei Verzeichnissen ignoriert werden } else //File { //Hashdatei ändern AddHistoryHash(client, fileChanged, relFilename); Globals.Log.Add(LogLevel.Information, "Remote: Hash für {0} wurde geändert (x-data).", relFilename); //Datei hochladen client.PutFile(fileChanged, "x-data/"+relFilename); fileToRemoveFromList.Add(fileChanged); Globals.Log.Add(LogLevel.Information, "Remote: Datei {0} wurde modifiziert (x-data).", relFilename); //In Created Verzeichnisse legen AddFileToUpdateFolder(client, "m-data", relFilename, EFileType.File); } } RemoveFileLock(client, relFilename); } foreach(string rFile in fileToRemoveFromList) { filesChanged.Remove(rFile); } } fileToRemoveFromList.Clear(); #endregion #region Deleted Files lock(filesDeleted) { foreach(string fileDeleted in filesDeleted) { string relFilename=FileSystem.GetRelativePath(fileDeleted, syncFolder, true); relFilename=relFilename.Replace("\\", "/"); bool locked=GetFileLock(client, relFilename); if(locked) { if(FileSystem.IsDirectory(fileDeleted)) //Directory { client.RemoveDir(fileDeleted); //client.PutFile(fileChanged, "x-data/"+relFilename); fileToRemoveFromList.Add(fileDeleted); Globals.Log.Add(LogLevel.Information, "Remote: Verzeichnis {0} wurde gelöscht (x-data).", relFilename); //In Created Verzeichnisse legen AddFileToUpdateFolder(client, "r-data", relFilename, EFileType.File); } else //File { //Hashdatei löchen RemoveHistoryHash(client, relFilename); Globals.Log.Add(LogLevel.Information, "Remote: Hash für {0} wurde gelöscht (x-data).", relFilename); //Datei löschen client.DeleteFile("x-data/"+relFilename); fileToRemoveFromList.Add(fileDeleted); Globals.Log.Add(LogLevel.Information, "Remote: Datei {0} wurde gelöscht (x-data).", relFilename); //In Created Verzeichnisse legen AddFileToUpdateFolder(client, "r-data", relFilename, EFileType.File); } } RemoveFileLock(client, relFilename); } foreach(string rFile in fileToRemoveFromList) { filesDeleted.Remove(rFile); } } fileToRemoveFromList.Clear(); #endregion //Neue Dateien herunterladen bzw. gelöscht Dateien löschen UpdateFromRemote(client, syncFolder); //Halbe Sekunde warten Thread.Sleep(500); } #endregion //string fileInfo=Globals.Options.GetElementAsString("xml.Sync.Filesystem.Test.txt"); //client.PutFile("D:\\AlexFTPS_bin_1.0.2.zip", "xxx.xxx"); } } }
/// <summary> /// Gibt die Updatedateien eines Verzeichnisses zurück /// </summary> /// <param name="client"></param> /// <param name="folder"></param> /// <returns></returns> public List<FileReturn> GetFilesFromUpdateFolder(FTPSClient client, string folder) { List<FileReturn> ret=new List<FileReturn>(); //In Update Verzeichniss legen string updateFolder=folder+"/"+Globals.ClientID+"/"; IList<DirectoryListItem> updateFiles=client.GetDirectoryList(updateFolder); //TODO evt FTPException abfangen //Sicherheitspause falls gerade noch eine Datei angelegt wurde Thread.Sleep(500); //Updatedatei herunterladen und auswerten foreach(DirectoryListItem dli in updateFiles) { string filenameLocal=FileSystem.TempPath+dli.Name; client.GetFile(updateFolder+dli.Name, filenameLocal); string[] lines=File.ReadAllLines(filenameLocal); string filename=lines[0]; //Datei hinzufügen EFileType fileType=GetFileType(lines[1]); //Updatedatei löschen client.DeleteFile(updateFolder+dli.Name); } return ret; }
public bool RemoveHistoryHash(FTPSClient client, string file) { file=file.Replace("/", "\\"); file="h-data/"+file; try { client.DeleteFile(file); return true; } catch { return false; } }
static void Main(string[] args) { #region Init if(args.Length!=1) { Console.WriteLine("Argument fehlt:"); Console.WriteLine("z.B. mono autoupdate.exe autoupdate.xml"); return; } if(!FileSystem.ExistsFile(args[0])) { Console.WriteLine("Angegebene Datei existiert nicht."); return; } XmlData config; try { config=new XmlData(args[0]); } catch(Exception e) { Console.WriteLine("Konfiguration konnte nicht gelesen werden."); Console.WriteLine(e.ToString()); return; } Console.WriteLine("Autoupdate 1.2.1 wurde gestartet..."); string workfolder_original=Directory.GetCurrentDirectory(); string misc_servername=config.GetElementAsString("xml.misc.servername"); string ftp_data_server=config.GetElementAsString("xml.ftp.data.server"); string ftp_data_user=config.GetElementAsString("xml.ftp.data.user"); string ftp_data_password=config.GetElementAsString("xml.ftp.data.password"); bool irc_active=false; string irc_network=""; string irc_channel=""; if(config.GetElementAsString("xml.irc.active")!="") { irc_active=Convert.ToBoolean(config.GetElementAsString("xml.irc.active")); irc_network=config.GetElementAsString("xml.irc.network"); irc_channel=config.GetElementAsString("xml.irc.channel"); } string ftp_update_server=config.GetElementAsString("xml.ftp.update.server"); string ftp_update_user=config.GetElementAsString("xml.ftp.update.user"); string ftp_update_password=config.GetElementAsString("xml.ftp.update.password"); bool activate_data=Convert.ToBoolean(config.GetElementAsString("xml.activate.data")); bool activate_update=Convert.ToBoolean(config.GetElementAsString("xml.activate.update")); string path_temp_folder=FileSystem.GetPathWithPathDelimiter(config.GetElementAsString("xml.path.temp")); string path_repostiory_trunk=FileSystem.GetPathWithPathDelimiter(config.GetElementAsString("xml.path.repository.trunk")); string path_repostiory_server=path_repostiory_trunk+"server/"; string path_repostiory_data=path_repostiory_trunk+"data/"; string path_repostiory_data_scripts=path_repostiory_data+"/scripts/"; string path_repostiory_data_maps=path_repostiory_data+"/maps/"; string path_server_root=FileSystem.GetPathWithPathDelimiter(config.GetElementAsString("xml.path.server.root")); string path_server_data=path_server_root+"data/"; string path_server_data_scripts=path_server_data+"scripts/"; string path_server_data_maps=path_server_data+"maps/"; string path_server_start_script=path_server_root+"start-server.sh"; string path_server_stop_script=path_server_root+"stop-server.sh"; List<string> ExcludesDirsClient=new List<string>(); ExcludesDirsClient.Add("maps_templates"); ExcludesDirsClient.Add("maps_rules"); ExcludesDirsClient.Add("scripts"); ExcludesDirsClient.Add(".git"); List<string> ExcludesDirsServer=new List<string>(); ExcludesDirsServer.Add("maps_templates"); ExcludesDirsServer.Add("maps_rules"); ExcludesDirsServer.Add("graphics"); ExcludesDirsServer.Add("music"); ExcludesDirsServer.Add("sfx"); ExcludesDirsServer.Add(".git"); List<string> ExcludeFiles=new List<string>(); ExcludeFiles.Add("CMakeLists.txt"); #endregion #region IRC Message absetzen if(irc_active) { Console.WriteLine("Sende IRC Nachricht..."); irc.SendDelay=200; irc.AutoRetry=true; irc.ActiveChannelSyncing=true; string[] serverlist=new string[] { irc_network }; int port=6667; irc.Connect(serverlist, port); irc.Login("Autoupdate", "Autoupdate", 0, "AutoupdateIRC"); irc.RfcJoin("#invertika"); Random rnd=new Random(); string funkyWord=FunkyWords[rnd.Next(FunkyWords.Length)]; irc.SendMessage(SendType.Message, irc_channel, String.Format("Autoupdate wurde auf dem Server {0} gestartet. {1}", misc_servername, funkyWord)); new Thread(new ThreadStart(StartIRCListen)).Start(); } #endregion #region Repository updaten Console.WriteLine("Update Repository..."); Directory.SetCurrentDirectory(path_repostiory_data); ProcessHelpers.StartProcess("git", "pull", true); #endregion #region Server stoppen und Serverdaten löschen Console.WriteLine("Stoppe Server..."); Directory.SetCurrentDirectory(path_server_root); ProcessHelpers.StartProcess(path_server_stop_script, "", false); Console.WriteLine("Lösche Serverdaten..."); if(FileSystem.ExistsDirectory(path_server_data)) { FileSystem.RemoveDirectory(path_server_data, true, true); } Console.WriteLine("Lösche temporäres Verzeichnis..."); if(FileSystem.ExistsDirectory(path_temp_folder)) { FileSystem.RemoveDirectory(path_temp_folder, true, true); } #endregion #region Neue Serverdaten kopieren Directory.SetCurrentDirectory(path_server_root); Console.WriteLine("Kopiere neue Serverdaten..."); FileSystem.CreateDirectory(path_server_data_maps, true); FileSystem.CopyDirectory(path_repostiory_data, path_server_data, true, ExcludesDirsServer, ExcludeFiles); #endregion #region Clientdaten Console.WriteLine("Erzeuge Verzeichnis mit Clientdaten..."); string clientPath=path_temp_folder+"clientdata"+FileSystem.PathDelimiter; FileSystem.CreateDirectory(clientPath, true); FileSystem.CreateDirectory(clientPath+"data"+FileSystem.PathDelimiter, true); FileSystem.CopyDirectory(path_repostiory_data, clientPath+"data"+FileSystem.PathDelimiter, true, ExcludesDirsClient); List<string> clientDataFiles=FileSystem.GetFiles(clientPath, true); #endregion #region Clientdaten Update erzeugen und hochladen if(activate_update) { Console.WriteLine("Erstelle Zip Datei für Update..."); clientPath=clientPath+"data"+FileSystem.PathDelimiter; //Zip erstellen string zipFilename=path_temp_folder+"update-"+Various.GetTimeID()+".zip"; ZipFile z=ZipFile.Create(zipFilename); z.BeginUpdate(); int fivePercent=clientDataFiles.Count/20; int countZipFiles=0; foreach(string i in clientDataFiles) { countZipFiles++; if(FileSystem.GetExtension(i).ToLower()=="ogg") { Console.WriteLine("Datei {0} aus dem Update ausgeschlossen.", FileSystem.GetFilename(i)); continue; } string rel=FileSystem.GetRelativePath(i, clientPath, true); z.Add(i, rel); if(countZipFiles%fivePercent==0) { Console.Write("."); } } z.CommitUpdate(); z.Close(); //adler 32 ICSharpCode.SharpZipLib.Checksums.Adler32 adler=new ICSharpCode.SharpZipLib.Checksums.Adler32(); FileStream fs=new FileStream(zipFilename, FileMode.Open, FileAccess.Read); BinaryReader br=new BinaryReader(fs); byte[] textToHash=br.ReadBytes((int)fs.Length); adler.Reset(); adler.Update(textToHash); string adler32=String.Format("{0:x}", adler.Value); //Ressources string resFile=path_temp_folder+FileSystem.PathDelimiter+"resources2.txt"; StreamWriter sw=new StreamWriter(resFile); sw.WriteLine("{0} {1}", FileSystem.GetFilename(zipFilename), adler32); sw.Close(); //Newsfile string newsFile=path_temp_folder+FileSystem.PathDelimiter+"news.txt"; sw=new StreamWriter(newsFile); sw.WriteLine("##3 Serenity"); sw.WriteLine("##0"); sw.WriteLine("##0 Entwicklerserver des Invertika Projektes"); sw.WriteLine("##0 Automatisches Update wird nach jedem"); sw.WriteLine("##0 Commit im Repository vorgenommen."); sw.WriteLine("##0"); sw.WriteLine("##0 Status: in Betrieb"); sw.WriteLine("##0 Autoupdate vom {0}, {1} Uhr.", DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString()); sw.WriteLine("##0"); sw.WriteLine("##2 Das Invertika Development Team"); sw.WriteLine("##0"); sw.Close(); //Upload Console.WriteLine("Beginne FTP Upload der Update Dateien..."); FTPSClient Client=new FTPSClient(); NetworkCredential networkCredential=new NetworkCredential(); networkCredential.Domain=ftp_update_server; networkCredential.UserName=ftp_update_user; networkCredential.Password=ftp_update_password; Console.WriteLine("Verbinde mich mit FTP {0} mittels des Nutzers {1}.", ftp_update_server, ftp_update_user); Client.Connect(networkCredential.Domain, networkCredential, ESSLSupportMode.ClearText); List<string> currentFTPFiles=Client.GetDirectoryFiles(""); //TODO muss getestet werden Console.WriteLine("Lösche bestehende Updatedateien auf dem FTP Server..."); foreach(string i in currentFTPFiles) { if(i.IndexOf("update")!=-1) { Client.DeleteFile(i); } } Console.WriteLine("Lade Updatedatei hoch..."); Client.PutFile(zipFilename, FileSystem.GetFilename(zipFilename)); Client.PutFile(resFile, FileSystem.GetFilename(resFile)); Client.PutFile(newsFile, FileSystem.GetFilename(newsFile)); Client.Close(); } #endregion #region Server wieder starten Console.WriteLine("Starte Server neu..."); Directory.SetCurrentDirectory(path_server_root); ProcessHelpers.StartProcess(path_server_start_script, "", false); #endregion #region Clientdaten Data erzeugen und hochladen if(activate_data) { //Upload Console.WriteLine("Beginne FTP Upload der Data Dateien..."); FTPSClient ClientData=new FTPSClient(); NetworkCredential networkCredential=new NetworkCredential(); networkCredential.Domain=ftp_data_server; networkCredential.UserName=ftp_data_user; networkCredential.Password=ftp_data_password; Console.WriteLine("Verbinde mich mit FTP {0} mittels des Nutzers {1}.", ftp_data_server, ftp_data_user); ClientData.Connect(networkCredential.Domain, networkCredential, ESSLSupportMode.ClearText); Console.WriteLine("Lade Data Dateien hoch..."); foreach(string ftpfile in clientDataFiles) { string relativeName=FileSystem.GetRelativePath(ftpfile, clientPath); string dirToCreate=FileSystem.GetPath(relativeName, true); if(dirToCreate!="") { string[] folders=dirToCreate.Split(FileSystem.PathDelimiter); string dirTemp=""; foreach(string i in folders) { if(i.Trim()=="") continue; if(i=="/") continue; dirTemp+=i+FileSystem.PathDelimiter; try { ClientData.CreateDirectory(dirTemp); } catch { } } } Console.WriteLine("Datei {0} wird hochgeladen...", relativeName); ClientData.PutFile(ftpfile, relativeName); } ClientData.Close(); } #endregion #region IRC Message absetzen und aus Channel verschwinden if(irc_active) { Console.WriteLine("Sende IRC Nachricht..."); irc.SendMessage(SendType.Message, irc_channel, String.Format("Autoupdate wurde auf dem Server {0} beendet und manaserv wieder gestartet.", misc_servername)); Thread.Sleep(15000); irc.Disconnect(); } #endregion #region Ende Console.WriteLine("Autoupdate beenden"); #endregion }