├── .gitignore ├── LICENSE ├── README.md ├── docs └── index.html ├── lib ├── ICSharpCode.SharpZipLib.dll ├── LumenWorks.Framework.IO.dll ├── Microsoft.Data.Tools.Schema.Sql.dll ├── Microsoft.Data.Tools.Utilities.dll ├── Microsoft.SqlServer.Dac.Extensions.dll ├── Microsoft.SqlServer.Dac.dll ├── Microsoft.SqlServer.TransactSql.ScriptDom.dll ├── Microsoft.SqlServer.Types.dll └── Microsoft.WindowsAzure.Storage.dll └── src ├── App.config ├── DoIt.config.xml ├── DoIt.csproj ├── DoIt.csproj.user ├── DoIt.sln ├── Extensions.cs ├── Functions ├── ConditionFunctions.cs ├── CsvFunctions.cs ├── DataTableFunctions.cs ├── DatabaseFunctions.cs ├── ExceptionFunctions.cs ├── ForEachFunctions.cs ├── FtpFunctions.cs ├── FunctionsNodeHandlerBase.cs ├── HttpFunctions.cs ├── LocalDiskFunctions.cs ├── LogFunctions.cs ├── MailFunctions.cs ├── ProcessFunctions.cs ├── SetValueFunctions.cs ├── SleepFunctions.cs ├── SqlFunctions.cs ├── StorageFunctions.cs ├── TryFunctions.cs └── ZipFunctions.cs ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── RijndaelEnhanced.cs ├── StaticRandom.cs └── Util.cs /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /src/bin/AnyCPU/Debug 6 | /src/bin/AnyCPU/Release 7 | /src/bin/x64/Debug 8 | /src/bin/x64/Release 9 | /src/obj/ 10 | /src/.vs/DoIt/FileContentIndex 11 | /src/.vs/DoIt/v17 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 ForLogic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/ICSharpCode.SharpZipLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/ICSharpCode.SharpZipLib.dll -------------------------------------------------------------------------------- /lib/LumenWorks.Framework.IO.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/LumenWorks.Framework.IO.dll -------------------------------------------------------------------------------- /lib/Microsoft.Data.Tools.Schema.Sql.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/Microsoft.Data.Tools.Schema.Sql.dll -------------------------------------------------------------------------------- /lib/Microsoft.Data.Tools.Utilities.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/Microsoft.Data.Tools.Utilities.dll -------------------------------------------------------------------------------- /lib/Microsoft.SqlServer.Dac.Extensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/Microsoft.SqlServer.Dac.Extensions.dll -------------------------------------------------------------------------------- /lib/Microsoft.SqlServer.Dac.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/Microsoft.SqlServer.Dac.dll -------------------------------------------------------------------------------- /lib/Microsoft.SqlServer.TransactSql.ScriptDom.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/Microsoft.SqlServer.TransactSql.ScriptDom.dll -------------------------------------------------------------------------------- /lib/Microsoft.SqlServer.Types.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/Microsoft.SqlServer.Types.dll -------------------------------------------------------------------------------- /lib/Microsoft.WindowsAzure.Storage.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/lib/Microsoft.WindowsAzure.Storage.dll -------------------------------------------------------------------------------- /src/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/DoIt.config.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForLogic/doit/29bcb33e295149a704958a1fd62a9e3d33e0852f/src/DoIt.config.xml -------------------------------------------------------------------------------- /src/DoIt.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {724B6B98-D177-4860-9D1D-952B8EECD807} 8 | Exe 9 | Properties 10 | DoIt 11 | DoIt 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\AnyCPU\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\AnyCPU\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | true 37 | bin\x86\Debug\ 38 | DEBUG;TRACE 39 | full 40 | x86 41 | prompt 42 | MinimumRecommendedRules.ruleset 43 | true 44 | 45 | 46 | bin\x86\Release\ 47 | TRACE 48 | true 49 | pdbonly 50 | x86 51 | prompt 52 | MinimumRecommendedRules.ruleset 53 | true 54 | 55 | 56 | true 57 | bin\x64\Debug\ 58 | DEBUG;TRACE 59 | full 60 | x64 61 | prompt 62 | MinimumRecommendedRules.ruleset 63 | true 64 | 65 | 66 | bin\x64\Release\ 67 | TRACE 68 | true 69 | pdbonly 70 | x64 71 | prompt 72 | MinimumRecommendedRules.ruleset 73 | true 74 | 75 | 76 | 77 | ..\lib\ICSharpCode.SharpZipLib.dll 78 | 79 | 80 | ..\lib\LumenWorks.Framework.IO.dll 81 | 82 | 83 | False 84 | ..\lib\Microsoft.Data.Tools.Schema.Sql.dll 85 | 86 | 87 | False 88 | ..\lib\Microsoft.Data.Tools.Utilities.dll 89 | 90 | 91 | False 92 | ..\lib\Microsoft.SqlServer.Dac.dll 93 | 94 | 95 | False 96 | ..\lib\Microsoft.SqlServer.Dac.Extensions.dll 97 | 98 | 99 | False 100 | ..\lib\Microsoft.SqlServer.TransactSql.ScriptDom.dll 101 | 102 | 103 | False 104 | ..\lib\Microsoft.SqlServer.Types.dll 105 | 106 | 107 | False 108 | ..\lib\Microsoft.WindowsAzure.Storage.dll 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | Designer 152 | 153 | 154 | 155 | 156 | PreserveNewest 157 | Designer 158 | 159 | 160 | 161 | 168 | -------------------------------------------------------------------------------- /src/DoIt.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ProjectFiles 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/DoIt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoIt", "DoIt.csproj", "{724B6B98-D177-4860-9D1D-952B8EECD807}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Debug|x64.ActiveCfg = Debug|x64 21 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Debug|x64.Build.0 = Debug|x64 22 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Debug|x86.ActiveCfg = Debug|x86 23 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Debug|x86.Build.0 = Debug|x86 24 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Release|x64.ActiveCfg = Release|x64 27 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Release|x64.Build.0 = Release|x64 28 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Release|x86.ActiveCfg = Release|x86 29 | {724B6B98-D177-4860-9D1D-952B8EECD807}.Release|x86.Build.0 = Release|x86 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(CodealikeProperties) = postSolution 35 | SolutionGuid = 7769ccf6-a193-40a0-8030-81a673b7c3cb 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /src/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace DoIt 10 | { 11 | public static class Extensions 12 | { 13 | public static Boolean IsMatch(this String str, String pattern) 14 | { 15 | if (String.IsNullOrEmpty(str)) 16 | return false; 17 | return Regex.IsMatch(str, pattern, RegexOptions.IgnoreCase); 18 | } 19 | 20 | public static Boolean IsNumber(this Object obj) 21 | { 22 | if (obj is Int16 || obj is Int32 || obj is Int64) 23 | return true; 24 | if (obj is Decimal || obj is Single || obj is Double) 25 | return true; 26 | if (obj is String && !String.IsNullOrEmpty(obj as String) && (obj as String).IsMatch("^((\\+|\\-)?[0-9]+([0-9]*(\\.|\\" + NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + ")?[0-9]+)?)?$")) 27 | return true; 28 | return false; 29 | } 30 | 31 | public static String Concat(this IEnumerable lst, Func valueFunction, String separator = ", ", String format = null, String defaultValue = null, Boolean distinct = true) 32 | { 33 | if (lst == null || lst.Count() == 0) 34 | return defaultValue; 35 | var newlst = (distinct ? lst.Select(item => valueFunction(item)).Distinct() : lst.Select(item => valueFunction(item))).ToList(); 36 | var str = new StringBuilder(); 37 | foreach (var value in newlst) 38 | { 39 | var valuestr = Convert.ToString(value); 40 | if (!String.IsNullOrEmpty(valuestr)) 41 | str.Append(String.IsNullOrEmpty(format) ? valuestr + separator : String.Format("{0:" + format + "}", value) + separator); 42 | } 43 | return String.IsNullOrEmpty(str.ToString()) ? null : str.Remove(str.Length - separator.Length, separator.Length).ToString(); 44 | } 45 | 46 | public static String GetFullMessage(this Exception ex, Boolean stackTrace = true, Int32 counter = 1) 47 | { 48 | if (ex == null) 49 | return ""; 50 | 51 | var msg = ""; 52 | if (ex.InnerException != null) 53 | { 54 | msg += GetFullMessage(ex.InnerException, stackTrace, counter + 1); 55 | msg += Environment.NewLine + Environment.NewLine; 56 | } 57 | msg += counter + " - " + ex.GetType().FullName + ": " + ex.Message + Environment.NewLine; 58 | if (stackTrace) 59 | msg += ex.StackTrace; 60 | return msg; 61 | } 62 | 63 | static String ReplaceAll(this String str, List oldChars, List newChars) 64 | { 65 | if (String.IsNullOrEmpty(str) || oldChars == null || newChars == null) 66 | return str; 67 | var builder = new StringBuilder(str); 68 | foreach (var c in oldChars) 69 | builder.Replace(c, newChars[oldChars.FindIndex(cc => cc == c)]); 70 | return builder.ToString(); 71 | } 72 | 73 | public static int Count(this string str, string strToCount) 74 | { 75 | var index = str.IndexOf(strToCount); 76 | var count = 0; 77 | while (index != -1){ 78 | count++; 79 | str = str.Remove(index, strToCount.Length); 80 | index = str.IndexOf(strToCount, index); 81 | } 82 | return count; 83 | } 84 | 85 | public static bool StartsWith(this string str, params string[] list) 86 | { 87 | if (str == null || list == null) 88 | return false; 89 | foreach (var item in list) 90 | if (str.StartsWith(item)) 91 | return true; 92 | return false; 93 | } 94 | 95 | public static String RemoveAccents(this String str) 96 | { 97 | if (String.IsNullOrEmpty(str)) 98 | return str; 99 | 100 | String lst1 = "áéíóúàèìòùäëïöüãõâêîôûçÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÃÕÂÊÎÔÛÇ"; 101 | String lst2 = "aeiouaeiouaeiouaoaeioucAEIOUAEIOUAEIOUAOAEIOUC"; 102 | return str.ReplaceAll(lst1.ToCharArray().ToList(), lst2.ToCharArray().ToList()); 103 | } 104 | 105 | public static String OnlyPathChars(this String str, Boolean toLower = false) 106 | { 107 | if (String.IsNullOrEmpty(str)) 108 | return str; 109 | var charsToKeep = "0123456789abcdefghijklmnopqrstuvxwyzABCDEFGHIJKLMNOPQRSTUVXWYZ_- ()."; 110 | var result = str.RemoveAccents().OnlyChars(charsToKeep, "_"); 111 | return toLower? result.ToLower() : result; 112 | } 113 | 114 | public static String GetFileName(this String str, Boolean toLower = false, Boolean onlyPathChars = true) 115 | { 116 | if (String.IsNullOrEmpty(str)) 117 | return str; 118 | var dirSeparators = new char[] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; 119 | var array = str.Split(dirSeparators, StringSplitOptions.RemoveEmptyEntries); 120 | var filename = array.LastOrDefault(); 121 | if (onlyPathChars) 122 | filename = filename.OnlyPathChars(); 123 | return toLower ? filename.ToLower() : filename; 124 | } 125 | 126 | public static String GetFileExtension(this String str, Boolean toLower = false) 127 | { 128 | if (String.IsNullOrEmpty(str)) 129 | return null; 130 | var index = str.LastIndexOf('.'); 131 | if (index == -1 || index == str.Length - 1) 132 | return null; 133 | var extension = str.Substring(index).OnlyPathChars(); 134 | return toLower ? extension.ToLower() : extension; 135 | } 136 | 137 | public static String OnlyChars(this String str, String charListToKeep, String replaceFor = null) 138 | { 139 | if (String.IsNullOrEmpty(str)) 140 | return str; 141 | var newStr = new StringBuilder(); 142 | foreach (var c in str) 143 | if (charListToKeep.Any(cc => cc == c)) 144 | newStr.Append(c); 145 | else if (!String.IsNullOrEmpty(replaceFor)) 146 | newStr.Append(replaceFor); 147 | return newStr.ToString(); 148 | } 149 | 150 | public static String OnlyNumbers(this String str) 151 | { 152 | return str.OnlyChars("0123456789"); 153 | } 154 | 155 | public static String OnlyChars(this String str) 156 | { 157 | return str.OnlyChars("abcdefghijklmnopqrstuvxwyzABCDEFGHIJKLMNOPQRSTUVXWYZ"); 158 | } 159 | 160 | public static String OnlyCharsAndNumbers(this String str) 161 | { 162 | return str.OnlyChars("0123456789abcdefghijklmnopqrstuvxwyzABCDEFGHIJKLMNOPQRSTUVXWYZ"); 163 | } 164 | 165 | public static StringBuilder Append(this StringBuilder sb, params String[] strValues) 166 | { 167 | if (strValues == null || strValues.Length == 0) 168 | return sb; 169 | foreach (var str in strValues) 170 | sb.Append(str); 171 | return sb; 172 | } 173 | 174 | public static StringBuilder AppendLine(this StringBuilder sb, params Object[] strValues) 175 | { 176 | if (strValues == null || strValues.Length == 0) 177 | return sb; 178 | foreach (var str in strValues) 179 | sb.Append(str); 180 | sb.AppendLine(); 181 | return sb; 182 | } 183 | 184 | public static Boolean In(this T obj, params T[] values) 185 | { 186 | if (obj == null || values == null || values.Length == 0) 187 | return false; 188 | foreach (var v in values) 189 | if (obj.Equals(v)) 190 | return true; 191 | return false; 192 | } 193 | 194 | public static bool Remove(this List list, Func func) 195 | { 196 | if (list == null || list.Count == 0) 197 | return false; 198 | foreach (var obj in list) 199 | if(func(obj)){ 200 | list.Remove(obj); 201 | return true; 202 | } 203 | return false; 204 | } 205 | 206 | public static bool RemoveKey(this Dictionary list, T1 key) 207 | { 208 | if (list == null || list.Count == 0) 209 | return false; 210 | if (!list.ContainsKey(key)) 211 | return false; 212 | list.Remove(key); 213 | return true; 214 | } 215 | 216 | public static string Encrypt(this string plainText, string key) 217 | { 218 | var r = new RijndaelEnhanced(key); 219 | return r.Encrypt(plainText); 220 | } 221 | 222 | public static string Decrypt(this string cipherText, string key) 223 | { 224 | var r = new RijndaelEnhanced(key); 225 | return r.Decrypt(cipherText); 226 | } 227 | 228 | #region datatable serializers 229 | static DataColumn[] GetColumns(DataTable dt, params string[] columns) 230 | { 231 | if (dt == null) 232 | return new DataColumn[0]; 233 | return columns == null || columns.Length == 0 ? 234 | dt.Columns.Cast().ToArray(): 235 | dt.Columns.Cast().Where(c1 => columns.Any(c2 => c2.ToLower() == c1.ColumnName.ToLower())).ToArray(); 236 | } 237 | 238 | static string[] GetColumns(DataRow row, params string[] columns) 239 | { 240 | if (row == null) 241 | return new string[0]; 242 | if(row.Table == null){ 243 | var rs = new string[row.ItemArray.Length]; 244 | for(var x=0; x().Select(c => c.ColumnName).ToArray() : 250 | row.Table.Columns.Cast().Where(c1 => columns.Any(c2 => c2.ToLower() == c1.ColumnName.ToLower())).Select(c => c.ColumnName).ToArray(); 251 | } 252 | 253 | public static String ToCSV(this DataRow row, params string[] columns) 254 | { 255 | var lstColumns = GetColumns(row, columns); 256 | var sb = new StringBuilder(); 257 | for (var x = 0; x < lstColumns.Length; x++) 258 | sb.Append("\"" + lstColumns[x], x < lstColumns.Length - 1 ? "\";" : "\""); 259 | sb.AppendLine(); 260 | for (var y = 0; y < lstColumns.Length; y++) 261 | sb.Append("\"" + GetValueToCSV(row[y]), y < lstColumns.Length - 1 ? "\";" : "\""); 262 | sb.AppendLine(); 263 | return sb.ToString(); 264 | } 265 | 266 | public static String ToCSV(this DataTable dt, params string[] columns) 267 | { 268 | var lstColumns = GetColumns(dt, columns); 269 | var sb = new StringBuilder(); 270 | for (var x = 0; x < lstColumns.Length; x++) 271 | sb.Append("\"" + lstColumns[x].ColumnName, x < lstColumns.Length - 1 ? "\";" : "\""); 272 | sb.AppendLine(); 273 | for (var x = 0; x < dt.Rows.Count; x++){ 274 | for (var y = 0; y < lstColumns.Length; y++) 275 | sb.Append("\"" + GetValueToCSV(dt.Rows[x][y]), y < lstColumns.Length - 1 ? "\";" : "\""); 276 | sb.AppendLine(); 277 | } 278 | return sb.ToString(); 279 | } 280 | 281 | public static String ToJSON(this DataRow row, params string[] columns) 282 | { 283 | var lstColumns = GetColumns(row, columns); 284 | var sb = new StringBuilder(); 285 | sb.Append("{"); 286 | for (var y = 0; y < lstColumns.Length; y++) 287 | sb.Append("\"", lstColumns[y], "\":", GetValueToJS(row[y]), y < lstColumns.Length - 1 ? "," : ""); 288 | sb.AppendLine("}"); 289 | return sb.ToString(); 290 | } 291 | 292 | public static String ToJSON(this DataTable dt, params string[] columns) 293 | { 294 | var lstColumns = GetColumns(dt, columns); 295 | var sb = new StringBuilder(); 296 | sb.AppendLine("["); 297 | for (var x = 0; x < dt.Rows.Count; x++){ 298 | sb.Append("{"); 299 | for (var y = 0; y < lstColumns.Length; y++) 300 | sb.Append("\"", lstColumns[y].ColumnName, "\":", GetValueToJS(dt.Rows[x][y]), y < lstColumns.Length - 1 ? "," : ""); 301 | sb.Append("}", x < dt.Rows.Count - 1 ? "," : ""); 302 | sb.AppendLine(); 303 | } 304 | sb.AppendLine("]"); 305 | return sb.ToString(); 306 | } 307 | 308 | public static String ToXML(this DataRow row, params string[] columns) 309 | { 310 | var lstColumns = GetColumns(row, columns); 311 | var sb = new StringBuilder(); 312 | sb.AppendLine(""); 313 | for (var y = 0; y < lstColumns.Length; y++){ 314 | var value = row[y]; 315 | if (value == DBNull.Value || value == null) 316 | sb.AppendLine("<", lstColumns[y], "/>"); 317 | else 318 | sb.Append("<", lstColumns[y], ">", GetValueToXML(value), ""); 319 | } 320 | sb.AppendLine(""); 321 | return sb.ToString(); 322 | } 323 | 324 | public static String ToXML(this DataTable dt, params string[] columns) 325 | { 326 | var lstColumns = GetColumns(dt, columns); 327 | var sb = new StringBuilder(); 328 | sb.AppendLine(""); 329 | for (var x = 0; x < dt.Rows.Count; x++){ 330 | sb.AppendLine(""); 331 | for (var y = 0; y < lstColumns.Length; y++){ 332 | var value = dt.Rows[x][y]; 333 | if (value == DBNull.Value || value == null) 334 | sb.AppendLine("<", lstColumns[y].ColumnName, "/>"); 335 | else 336 | sb.AppendLine("<", lstColumns[y].ColumnName, ">", GetValueToXML(value), ""); 337 | } 338 | sb.AppendLine(""); 339 | } 340 | sb.AppendLine(""); 341 | return sb.ToString(); 342 | } 343 | 344 | static String GetValueToCSV(Object data) 345 | { 346 | if (data == null || data == DBNull.Value) 347 | return null; 348 | if (data is Int16 || data is Int32 || data is Int64 || data is Nullable || data is Nullable || data is Nullable) 349 | return Convert.ToString(data); 350 | if (data is Decimal || data is Single || data is Double || data is Nullable || data is Nullable || data is Nullable) 351 | return Convert.ToString(Convert.ToDecimal(Convert.ToDouble(data))).Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberGroupSeparator, "").Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "."); 352 | if (data is DateTime || data is Nullable){ 353 | var date = Convert.ToDateTime(data); 354 | return date.Hour != 0 || date.Minute != 0 || date.Second != 0 ? Convert.ToDateTime(data).ToString("yyyy-MM-dd HH:mm:ss") : Convert.ToDateTime(data).ToString("yyyy-MM-dd"); 355 | } 356 | if (data is Boolean || data is Nullable) 357 | return Convert.ToBoolean(data) ? "True" : "False"; 358 | return Convert.ToString(data).Replace("\"", "\\\"").Replace(Environment.NewLine, " ").Replace("\r\n", " ").Replace("\n", " "); 359 | } 360 | 361 | static String GetValueToXML(Object data) 362 | { 363 | var str = GetValueToCSV(data); 364 | return System.Security.SecurityElement.Escape(str); 365 | } 366 | 367 | public static string GetValueToJS(Object data) 368 | { 369 | if (data == null || data == DBNull.Value) 370 | return "null"; 371 | if (data is Int16 || data is Int32 || data is Int64 || data is Nullable || data is Nullable || data is Nullable) 372 | return Convert.ToString(data); 373 | if (data is Decimal || data is Single || data is Double || data is Nullable || data is Nullable || data is Nullable) 374 | return Convert.ToString(Convert.ToDecimal(Convert.ToDouble(data))).Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberGroupSeparator, "").Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "."); 375 | if (data is DateTime || data is Nullable){ 376 | var date = Convert.ToDateTime(data); 377 | return date.Hour != 0 || date.Minute != 0 || date.Second != 0 ? String.Format("\"{0:yyyy-MM-dd HH:mm:ss}\"", date) : String.Format("\"{0:yyyy-MM-dd}\"", date); 378 | } 379 | if (data is Boolean || data is Nullable) 380 | return Convert.ToBoolean(data) ? "true" : "false"; 381 | return "\"" + Convert.ToString(data).Replace("\"", "\\\"") + "\""; 382 | } 383 | #endregion 384 | 385 | #region sql 386 | public static String GetSQL(this String sql, params Object[] parameters) 387 | { 388 | if (String.IsNullOrEmpty(sql) || parameters == null || parameters.Length == 0) 389 | return sql; 390 | 391 | var index = -1; 392 | var sqlAux = sql.Replace("?", "@?@"); 393 | var counter = 0; 394 | while (true) 395 | { 396 | index = sqlAux.IndexOf("@?@", index + 1); 397 | if (index == -1 || counter >= parameters.Length) 398 | return sqlAux.Replace("@?@", "?"); 399 | 400 | var curValue = parameters[counter]; 401 | var strValue = null as String; 402 | if (curValue == null) 403 | strValue = "null"; 404 | else if (curValue is String) 405 | { 406 | var str = Convert.ToString(curValue); 407 | strValue = String.IsNullOrEmpty(str) ? "null" : "'" + str.Replace("'", "''") + "'"; 408 | } 409 | else if (curValue.IsNumber()) 410 | { 411 | var number = Convert.ToString(curValue); 412 | strValue = number.Replace(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "."); 413 | } 414 | else if (curValue is DateTime) 415 | { 416 | var date = Convert.ToDateTime(curValue); 417 | strValue = "'" + (date.Hour == 0 && date.Minute == 0 && date.Second == 0 && date.Millisecond == 0 ? date.ToString("MM/dd/yyyy") : date.ToString("MM/dd/yyyy HH:mm:ss.fff")) + "'"; 418 | } 419 | else if (curValue is Boolean) 420 | { 421 | var boolean = Convert.ToInt32(curValue); 422 | strValue = (boolean == 0 ? "0" : "1"); 423 | } 424 | 425 | sqlAux = sqlAux.Remove(index, 3); 426 | sqlAux = sqlAux.Insert(index, strValue); 427 | counter++; 428 | } 429 | } 430 | #endregion 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /src/Functions/ConditionFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using Microsoft.WindowsAzure.Storage; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Xml; 11 | 12 | namespace DoIt.Functions 13 | { 14 | internal class ConditionFunctions : FunctionsNodeHandlerBase 15 | { 16 | public ConditionFunctions(XmlNode node):base(node){} 17 | 18 | public override bool Execute() 19 | { 20 | if (Node == null) 21 | return false; 22 | var type = Util.GetStr(Node, "type", "").ToLower(); 23 | switch(type){ 24 | case "has-disk-space": return HasDiskSpace(Node); 25 | case "file-exists": return FileExists(Node); 26 | case "folder-exists": return FolderExists(Node); 27 | case "has-rows": return HasRows(Node); 28 | case "is-datetime": return IsDateTime(Node); 29 | case "if": return If(Node); 30 | } 31 | return false; 32 | } 33 | 34 | 35 | // has disk space 36 | bool HasDiskSpace(XmlNode node){ 37 | var min = Util.GetStr(node, "min", "0"); 38 | if (!min.IsMatch("^\\d+$")) 39 | return false; 40 | var freeSpace = Util.GetFreeSpace(Util.GetStr(node, "drive", "C:\\")); 41 | var conditionNode = Util.GetChildNode(node, freeSpace / 1024 / 1024 >= Convert.ToInt64(min) ? "True" : "False"); 42 | return Program.Shared.ExecuteCommands(conditionNode); 43 | } 44 | 45 | // file exists 46 | bool FileExists(XmlNode node){ 47 | var path = Util.GetStr(node, "path", ""); 48 | if (string.IsNullOrEmpty(path)) 49 | return false; 50 | var conditionNode = Util.GetChildNode(node, File.Exists(Program.Shared.ReplaceTags(path)) ? "True" : "False"); 51 | return Program.Shared.ExecuteCommands(conditionNode); 52 | } 53 | 54 | // folder exists 55 | bool FolderExists(XmlNode node){ 56 | var path = Util.GetStr(node, "path", ""); 57 | if (string.IsNullOrEmpty(path)) 58 | return false; 59 | var conditionNode = Util.GetChildNode(node, Directory.Exists(Program.Shared.ReplaceTags(path)) ? "True" : "False"); 60 | return Program.Shared.ExecuteCommands(conditionNode); 61 | } 62 | 63 | // has rows 64 | bool HasRows(XmlNode node){ 65 | var data = Util.GetStr(node, "data"); 66 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 67 | var conditionNode = Util.GetChildNode(node, dt != null && dt.Rows.Count > 0 ? "True" : "False"); 68 | return Program.Shared.ExecuteCommands(conditionNode); 69 | } 70 | 71 | // is date/time 72 | bool IsDateTime(XmlNode node){ 73 | var days = Util.GetStr(node, "days", "all"); 74 | var time = Util.GetStr(node, "time"); 75 | var conditionNode = Util.GetChildNode(node, Util.IsTodayInList(days) && Util.IsTimeToRun(time) ? "True" : "False"); 76 | return Program.Shared.ExecuteCommands(conditionNode); 77 | } 78 | 79 | // if 80 | bool If(XmlNode node){ 81 | var value1 = Program.Shared.ReplaceTags(Util.GetStr(node, "value1")); 82 | var value2 = Program.Shared.ReplaceTags(Util.GetStr(node, "value2")); 83 | var comparison = Util.GetStr(node, "comparison", "equals").ToLower(); 84 | var valueType = Util.GetStr(node, "valueType", "string").ToLower(); 85 | var result = false; 86 | if(valueType == "string"){ 87 | switch (comparison){ 88 | case "equals": result = string.Compare(value1, value2) == 0; break; 89 | case "less": result = string.Compare(value1, value2) < 0; break; 90 | case "greater": result = string.Compare(value1, value2) > 0; break; 91 | } 92 | }else if (valueType == "numeric"){ 93 | var v1 = string.IsNullOrEmpty(value1) || !value1.IsNumber() ? null : new Nullable(Convert.ToDecimal(value1)); 94 | var v2 = string.IsNullOrEmpty(value2) || !value2.IsNumber() ? null : new Nullable(Convert.ToDecimal(value2)); 95 | switch (comparison){ 96 | case "equals": result = v1 == v2; break; 97 | case "less": result = v1 < v2; break; 98 | case "greater": result = v1 > v2; break; 99 | } 100 | }else if (valueType == "date"){ 101 | var v1 = Util.ParseDateTime(value1); 102 | var v2 = Util.ParseDateTime(value2); 103 | switch (comparison){ 104 | case "equals": result = v1 == v2; break; 105 | case "less": result = v1 < v2; break; 106 | case "greater": result = v1 > v2; break; 107 | } 108 | } 109 | return Program.Shared.ExecuteCommands(Util.GetChildNode(node, result ? "True" : "False")); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Functions/CsvFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Xml; 12 | 13 | namespace DoIt.Functions 14 | { 15 | internal class CsvFunctions : FunctionsNodeHandlerBase 16 | { 17 | public CsvFunctions(XmlNode node):base(node){} 18 | 19 | public override bool Execute() 20 | { 21 | if (Node == null) 22 | return false; 23 | var path = Program.Shared.ReplaceTags(Util.GetStr(Node, "path")); 24 | var separator = Util.GetStr(Node, "separator", ";"); 25 | if (string.IsNullOrEmpty(path)) 26 | return false; 27 | var lstNodes = Util.GetChildNodes(Node, "WriteLine", "WriteData", "Load"); 28 | foreach (var n in lstNodes) 29 | switch (n.Name.ToLower()){ 30 | case "writeline": WriteLine(path, separator, n); break; 31 | case "writedata": WriteData(path, separator, n); break; 32 | case "load": Load(path, separator, n); break; 33 | } 34 | return true; 35 | } 36 | 37 | // write line 38 | void WriteLine(string path, string separator, XmlNode n){ 39 | var append = Util.GetStr(n, "append", "true").ToLower() == "true"; 40 | var lstColumns = Util.GetChildNodes(n, "Column").Select(n2 => Program.Shared.ReplaceTags(n2.InnerXml)).ToArray(); 41 | if (!Directory.Exists(Path.GetDirectoryName(path))) 42 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 43 | using (var fw = new FileStream(path, append ? FileMode.Append : FileMode.Create, FileAccess.Write)) 44 | using (var sw = new StreamWriter(fw, Encoding.Default)){ 45 | for (var x=0; x().ToDictionary(c => c.ColumnName, c => c.ColumnName) : 68 | columnsNodes.Select(n2 => new { Header = Util.GetStr(n2, "header"), Value = Program.Shared.ReplaceTags(n2.InnerXml) }).Where(n2 => !string.IsNullOrEmpty(n2.Value)).ToDictionary(n2 => n2.Header, n2 => n2.Value); 69 | var lastColumn = lstColumns.Keys.LastOrDefault(); 70 | if (!Directory.Exists(Path.GetDirectoryName(path))) 71 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 72 | using (var fw = new FileStream(path, append ? FileMode.Append : FileMode.Create, FileAccess.Write)) 73 | using (var sw = new StreamWriter(fw, Encoding.Default)){ 74 | foreach (var c in lstColumns.Keys){ 75 | sw.Write("\""+c.Replace("\"","\"\"")+"\""); 76 | if (c != lastColumn) 77 | sw.Write(separator); 78 | } 79 | sw.WriteLine(); 80 | var lstRows = string.IsNullOrEmpty(where) ? datatable.Rows.Cast().ToArray() : datatable.Select(where, sort); 81 | foreach (DataRow r in lstRows){ 82 | foreach (var c in lstColumns.Keys){ 83 | sw.Write("\""+ (r[c] == null || r[c] == DBNull.Value ? "" : Convert.ToString(r[c]).Replace("\"","\"\"")) +"\""); 84 | if (c != lastColumn) 85 | sw.Write(separator); 86 | } 87 | sw.WriteLine(); 88 | } 89 | } 90 | } 91 | 92 | // load 93 | void Load(string path, string separator, XmlNode n){ 94 | var to = Program.Shared.ReplaceTags(Util.GetStr(n, "to")); 95 | if (string.IsNullOrEmpty(to)) 96 | return; 97 | var hasHeaders = Util.GetStr(n, "hasHeaders", "true").ToLower() == "true"; 98 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 99 | var dt = new DataTable(); 100 | using (var sr = new StreamReader(path, Encoding.Default)) 101 | using (var csv = new CsvReader(sr, hasHeaders, separator[0])){ 102 | if (hasHeaders) 103 | foreach (var h in csv.GetFieldHeaders()) 104 | dt.Columns.Add(h); 105 | if (dt.Columns.Count == 0) 106 | for (var x = 0; x < csv.FieldCount; x++) 107 | dt.Columns.Add("Column" + (x+1)); 108 | while (csv.ReadNextRecord()){ 109 | var rowData = new string[csv.FieldCount]; 110 | for (var x = 0; x < rowData.Length; x++) 111 | rowData[x] = csv[x]; 112 | dt.Rows.Add(rowData); 113 | } 114 | } 115 | lock (Program.Shared.LockDataTables){ 116 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/Functions/DataTableFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml; 8 | 9 | namespace DoIt.Functions 10 | { 11 | internal class DataTableFunctions : FunctionsNodeHandlerBase 12 | { 13 | public DataTableFunctions(XmlNode node):base(node){} 14 | 15 | public override bool Execute() 16 | { 17 | if (Node == null) 18 | return false; 19 | var lstNodes = Util.GetChildNodes(Node, "Count", "Sum", "Avg", "Max", "Min", "SetRowValue", "GetDataRow", "Diff", "Join", "Intersect", "RemoveRows", "InsertRow", "Filter", "Copy"); 20 | foreach (var n in lstNodes) 21 | switch (n.Name.ToLower()){ 22 | case "count": Count(n); break; 23 | case "sum": Sum(n); break; 24 | case "avg": Avg(n); break; 25 | case "max": Max(n); break; 26 | case "min": Min(n); break; 27 | case "setrowvalue": SetRowValue(n); break; 28 | case "getdatarow": GetDataRow(n); break; 29 | case "diff": Diff(n); break; 30 | case "join": Join(n); break; 31 | case "intersect": Intersect(n); break; 32 | case "removerows": RemoveRows(n); break; 33 | case "insertrow": InsertRow(n); break; 34 | case "filter": Filter(n); break; 35 | case "copy": Copy(n); break; 36 | } 37 | return true; 38 | } 39 | 40 | // count 41 | void Count(XmlNode n){ 42 | var data = Util.GetStr(n, "data"); 43 | var where = Util.GetStr(n, "where"); 44 | var to = Util.GetStr(n, "to"); 45 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 46 | var count = string.IsNullOrEmpty(where) ? dt.Rows.Count : dt.Select(where).Length; 47 | lock (Program.Shared.LockVariables){ 48 | Program.Shared.Variables[to+";"+ Program.Shared.GetSequence()] = count; 49 | } 50 | Program.Shared.WriteLogLine(string.Format("Count set from \"{0}\" where \"{1}\" to variable \"{2}\" (count = {3})", data, where, to, count)); 51 | } 52 | 53 | // sum 54 | void Sum(XmlNode n){ 55 | var data = Util.GetStr(n, "data"); 56 | var column = Util.GetStr(n, "column"); 57 | var where = Util.GetStr(n, "where"); 58 | var to = Util.GetStr(n, "to"); 59 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 60 | var lstRows = string.IsNullOrEmpty(where) ? dt.Rows.Cast().ToList() : dt.Select(where).ToList(); 61 | var sum = lstRows.Where(r => r[column] != DBNull.Value).Sum(r => Convert.ToDecimal(r[column])); 62 | lock (Program.Shared.LockVariables){ 63 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = sum; 64 | } 65 | Program.Shared.WriteLogLine(string.Format("Sum set from \"{0}.{1}\" where \"{2}\" to variable \"{3}\" (sum = {4}).", data, column, where, to, sum)); 66 | } 67 | 68 | // avg 69 | void Avg(XmlNode n){ 70 | var data = Util.GetStr(n, "data"); 71 | var column = Util.GetStr(n, "column"); 72 | var where = Util.GetStr(n, "where"); 73 | var to = Util.GetStr(n, "to"); 74 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 75 | var lstRows = string.IsNullOrEmpty(where) ? dt.Rows.Cast().ToList() : dt.Select(where).ToList(); 76 | var avg = lstRows.Where(r => r[column] != DBNull.Value).Average(r => Convert.ToDecimal(r[column])); 77 | lock (Program.Shared.LockVariables){ 78 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = avg; 79 | } 80 | Program.Shared.WriteLogLine(string.Format("Avg set from \"{0}.{1}\" where \"{2}\" to variable \"{3}\" (avg = {4})", data, column, where, to, avg)); 81 | } 82 | 83 | // max 84 | void Max(XmlNode n){ 85 | var data = Util.GetStr(n, "data"); 86 | var column = Util.GetStr(n, "column"); 87 | var where = Util.GetStr(n, "where"); 88 | var to = Util.GetStr(n, "to"); 89 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 90 | var lstRows = string.IsNullOrEmpty(where) ? dt.Rows.Cast().ToList() : dt.Select(where).ToList(); 91 | var cType = dt.Columns[column].DataType.Name; 92 | var max = null as object; 93 | if (cType.In("Byte","Int16","Int32","Int64","Decimal","Single","Double")) 94 | max = lstRows.Where(r => r[column] != DBNull.Value).Max(r => Convert.ToDecimal(r[column])); 95 | else if (cType.In("DateTime")) 96 | max = lstRows.Where(r => r[column] != DBNull.Value).Max(r => Convert.ToDateTime(r[column])); 97 | else 98 | max = lstRows.Where(r => r[column] != DBNull.Value).Max(r => Convert.ToString(r[column])); 99 | lock (Program.Shared.LockVariables){ 100 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = max; 101 | } 102 | Program.Shared.WriteLogLine(string.Format("Max set from \"{0}.{1}\" where \"{2}\" to variable \"{3}\" (max = {4})", data, column, where, to, max)); 103 | } 104 | 105 | // min 106 | void Min(XmlNode n){ 107 | var data = Util.GetStr(n, "data"); 108 | var column = Util.GetStr(n, "column"); 109 | var where = Util.GetStr(n, "where"); 110 | var to = Util.GetStr(n, "to"); 111 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 112 | var lstRows = string.IsNullOrEmpty(where) ? dt.Rows.Cast().ToList() : dt.Select(where).ToList(); 113 | var cType = dt.Columns[column].DataType.Name; 114 | var min = null as object; 115 | if (cType.In("Byte","Int16","Int32","Int64","Decimal","Single","Double")) 116 | min = lstRows.Where(r => r[column] != DBNull.Value).Min(r => Convert.ToDecimal(r[column])); 117 | else if (cType.In("DateTime")) 118 | min = lstRows.Where(r => r[column] != DBNull.Value).Min(r => Convert.ToDateTime(r[column])); 119 | else 120 | min = lstRows.Where(r => r[column] != DBNull.Value).Min(r => Convert.ToString(r[column])); 121 | lock (Program.Shared.LockVariables){ 122 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = min; 123 | } 124 | Program.Shared.WriteLogLine(string.Format("Min set from \"{0}.{1}\" where \"{2}\" to variable \"{3}\" (min = {4})", data, column, where, to, min)); 125 | } 126 | 127 | // set row value 128 | void SetRowValue(XmlNode n){ 129 | var data = Util.GetStr(n, "data"); 130 | var row = Util.GetStr(n, "row"); 131 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 132 | var lstColumns = Util.GetChildNodes(n, "Column").Select(n2 => new { Name = Util.GetStr(n2, "name"), Type = Util.GetStr(n2, "type"), Value = Program.Shared.ReplaceTags(n2.InnerXml) }).ToArray(); 133 | var dt = string.IsNullOrEmpty(data) ? null : Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 134 | var r1 = string.IsNullOrEmpty(row) ? null : Program.Shared.GetVariable(Program.Shared.ThreadID(), row) as Dictionary; 135 | var r2 = string.IsNullOrEmpty(row) ? null : Program.Shared.GetCurrentRow(Program.Shared.ThreadID(), row); 136 | if (dt == null) 137 | return; 138 | if (r1 != null) 139 | lock (Program.Shared.LockDataTables){ 140 | var index = Convert.ToInt32(r1["$RowIndex"]); 141 | var r = index < dt.Rows.Count ? dt.Rows[index] : null; 142 | if (r != null) 143 | foreach (var c in lstColumns){ 144 | if (!dt.Columns.Contains(c.Name)) 145 | dt.Columns.Add(c.Name, Util.GetType(c.Type)); 146 | var value = Util.GetValue(c.Value, c.Type) ?? DBNull.Value; 147 | r[c.Name] = r1[c.Name] = value; 148 | } 149 | } 150 | if (r2 != null) 151 | lock (Program.Shared.LockDataTables) 152 | foreach (var c in lstColumns){ 153 | if (!dt.Columns.Contains(c.Name)) 154 | dt.Columns.Add(c.Name, Util.GetType(c.Type)); 155 | r2[c.Name] = Util.GetValue(c.Value, c.Type) ?? DBNull.Value; 156 | } 157 | if (r1 == null && r2 == null){ 158 | var lstRows = string.IsNullOrEmpty(where) ? dt.Rows.Cast().ToArray() : dt.Select(where); 159 | foreach (var c in lstColumns){ 160 | lock (Program.Shared.LockDataTables){ 161 | if (!dt.Columns.Contains(c.Name)) 162 | dt.Columns.Add(c.Name, Util.GetType(c.Type)); 163 | foreach (DataRow r in lstRows) 164 | r[c.Name] = Util.GetValue(c.Value, c.Type) ?? DBNull.Value; 165 | } 166 | } 167 | } 168 | } 169 | 170 | // get datarow 171 | void GetDataRow(XmlNode n){ 172 | var fromData = Util.GetStr(n, "fromData"); 173 | var to = Util.GetStr(n, "to"); 174 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 175 | var sort = Program.Shared.ReplaceTags(Util.GetStr(n, "sort")); 176 | var index = Util.GetStr(n, "index", "0"); 177 | var lst = new Dictionary(); 178 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), fromData); 179 | var rows = dt.Select(where, sort); 180 | var x = index.ToLower() == "last" ? rows.Length - 1 : Convert.ToInt32(index); 181 | var r = rows.Length == 0 || x > rows.Length - 1 ? null : rows[x]; 182 | foreach (DataColumn c in dt.Columns) 183 | lst[c.ColumnName] = r == null ? null : r[c]; 184 | lst["$RowIndex"] = r == null ? -1 : dt.Rows.IndexOf(r); 185 | lock (Program.Shared.LockVariables){ 186 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = lst; 187 | } 188 | } 189 | 190 | // diff 191 | void Diff(XmlNode n){ 192 | var to = Util.GetStr(n, "to"); 193 | var inData = Util.GetStr(n, "inData"); 194 | var notInData = Util.GetStr(n, "notInData"); 195 | var columns = Util.GetStr(n, "columns"); 196 | var lstColumns = columns.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); 197 | var inDT = Program.Shared.DataTables[inData + ";" + Program.Shared.GetSequence()]; 198 | var notInDT = Program.Shared.DataTables[notInData + ";" + Program.Shared.GetSequence()]; 199 | var dt = new DataTable(); 200 | foreach (DataColumn c in inDT.Columns) 201 | dt.Columns.Add(c.ColumnName, c.DataType); 202 | var lstRows = inDT.Rows.Cast().Where(r1 => !notInDT.Rows.Cast().Any(r2 => lstColumns.All(c => Convert.ToString(r1[c]) == Convert.ToString(r2[c])))).ToList(); 203 | foreach (DataRow r in lstRows) 204 | dt.Rows.Add(r.ItemArray); 205 | lock (Program.Shared.LockDataTables){ 206 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 207 | } 208 | Program.Shared.WriteLogLine("DataTable diff to \"{0}\" comparing columns \"{1}\", in data \"{2}\" / not in data \"{3}\" - Resulting Rows: {4}", to, columns, inData, notInData, dt.Rows.Count); 209 | } 210 | 211 | // join 212 | void Join(XmlNode n){ 213 | var data = Util.GetStr(n, "data"); 214 | var to = Util.GetStr(n, "to"); 215 | var lstData = data.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); 216 | var lstDT = new DataTable[lstData.Length]; 217 | for (var x = 0; x < lstData.Length; x++) 218 | lstDT[x] = Program.Shared.GetDataTable(Program.Shared.ThreadID(), lstData[x]); 219 | var dt = new DataTable(); 220 | foreach (DataTable d in lstDT) 221 | foreach (DataColumn c in d.Columns) 222 | if (!dt.Columns.Contains(c.ColumnName)) 223 | dt.Columns.Add(c.ColumnName, c.DataType); 224 | foreach (DataTable d in lstDT) 225 | foreach (DataRow r in d.Rows){ 226 | var newRow = dt.NewRow(); 227 | foreach (DataColumn c in d.Columns) 228 | newRow[c.ColumnName] = r[c.ColumnName]; 229 | dt.Rows.Add(newRow); 230 | } 231 | lock (Program.Shared.LockDataTables){ 232 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 233 | } 234 | Program.Shared.WriteLogLine("DataTable join to \"{0}\", from data \"{1}\" - Resulting Rows: {2}", to, data, dt.Rows.Count); 235 | } 236 | 237 | // intersect 238 | void Intersect(XmlNode n){ 239 | var data = Util.GetStr(n, "data"); 240 | var to = Util.GetStr(n, "to"); 241 | var columns = Util.GetStr(n, "columns"); 242 | var rowsFrom = Convert.ToInt32(Util.GetStr(n, "rowsFrom", "0")); 243 | var lstData = data.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); 244 | var lstColumns = columns.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); 245 | if (lstData.Length == 0 || lstColumns.Length == 0) 246 | return; 247 | var lstDT = new DataTable[lstData.Length]; 248 | for (var x = 0; x < lstData.Length; x++) 249 | lstDT[x] = Program.Shared.GetDataTable(Program.Shared.ThreadID(), lstData[x]); 250 | var dt = new DataTable(); 251 | foreach (DataColumn c in lstDT[rowsFrom].Columns) 252 | if (!dt.Columns.Contains(c.ColumnName)) 253 | dt.Columns.Add(c.ColumnName, c.DataType); 254 | var lstRows = lstDT[rowsFrom].Rows.Cast().ToArray(); 255 | foreach (var r in lstRows){ 256 | var rowMatch = true; 257 | for (var x = 0; x < lstDT.Length; x++){ 258 | if (x == rowsFrom) 259 | continue; 260 | if(!lstDT[x].Rows.Cast().Any(r2 => lstColumns.All(c => Convert.ToString(r2[c])== Convert.ToString(r[c])))){ 261 | rowMatch = false; 262 | break; 263 | } 264 | } 265 | if (rowMatch){ 266 | var newRow = dt.NewRow(); 267 | foreach (DataColumn col in dt.Columns) 268 | newRow[col.ColumnName] = r[col.ColumnName]; 269 | dt.Rows.Add(newRow); 270 | } 271 | } 272 | lock (Program.Shared.LockDataTables){ 273 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 274 | } 275 | Program.Shared.WriteLogLine("DataTable intersect to \"{0}\", from data \"{1}\" comparing columns \"{2}\" - Resulting Rows: {3}", to, data, columns, dt.Rows.Count); 276 | } 277 | 278 | // remove rows 279 | void RemoveRows(XmlNode n){ 280 | var from = Util.GetStr(n, "from"); 281 | if (string.IsNullOrEmpty(from)) 282 | return; 283 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 284 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), from); 285 | if (dt == null) 286 | return; 287 | if (string.IsNullOrEmpty(where)){ 288 | dt.Rows.Clear(); 289 | return; 290 | } 291 | var lstRows = dt.Select(where); 292 | foreach (var r in lstRows) 293 | dt.Rows.Remove(r); 294 | } 295 | 296 | // insert a new row 297 | void InsertRow(XmlNode n){ 298 | var to = Util.GetStr(n, "to"); 299 | if (string.IsNullOrEmpty(to)) 300 | return; 301 | var lstColumns = Util.GetChildNodes(n, "Column").Select(n2 => new {Name=Util.GetStr(n2, "name"), Type=Util.GetStr(n2, "type"), Value=Program.Shared.ReplaceTags(n2.InnerXml)}).ToArray(); 302 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), to); 303 | if (dt == null) 304 | return; 305 | var r = dt.NewRow(); 306 | foreach (var c in lstColumns){ 307 | if (!dt.Columns.Contains(c.Name)) 308 | dt.Columns.Add(c.Name, Util.GetType(c.Type)); 309 | r[c.Name] = Util.GetValue(c.Value, c.Type); 310 | } 311 | dt.Rows.Add(r); 312 | } 313 | 314 | // filter rows 315 | void Filter(XmlNode n){ 316 | var data = Util.GetStr(n, "data"); 317 | if (string.IsNullOrEmpty(data)) 318 | return; 319 | var to = Util.GetStr(n, "to", data); 320 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 321 | var sort = Program.Shared.ReplaceTags(Util.GetStr(n, "sort")); 322 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 323 | if (dt == null) 324 | return; 325 | var newDT = new DataTable(){TableName=dt.TableName}; 326 | foreach (DataColumn c in dt.Columns.Cast().Where(col => string.IsNullOrEmpty(col.Expression)).ToArray()) 327 | newDT.Columns.Add(c.ColumnName, c.DataType); 328 | var lstRows = dt.Select(where, sort); 329 | foreach (var r in lstRows) 330 | newDT.Rows.Add(r.ItemArray); 331 | lock (Program.Shared.LockDataTables){ 332 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = newDT; 333 | } 334 | } 335 | 336 | // copy datatable 337 | void Copy(XmlNode n) 338 | { 339 | var data = Util.GetStr(n, "data"); 340 | if (string.IsNullOrEmpty(data)) 341 | return; 342 | var to = Util.GetStr(n, "to"); 343 | if (string.IsNullOrEmpty(to)) 344 | return; 345 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), data); 346 | if (dt == null) 347 | return; 348 | var newDT = dt.Copy(); 349 | lock (Program.Shared.LockDataTables){ 350 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = newDT; 351 | } 352 | } 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /src/Functions/DatabaseFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Xml; 12 | 13 | namespace DoIt.Functions 14 | { 15 | internal class DatabaseFunctions : FunctionsNodeHandlerBase 16 | { 17 | public DatabaseFunctions(XmlNode node):base(node){} 18 | 19 | public override bool Execute() 20 | { 21 | if (Node == null) 22 | return false; 23 | var id = Util.GetStr(Node, "id"); 24 | var lstNodes = Util.GetChildNodes(Node, "Backup", "BackupLog"); 25 | foreach (var n in lstNodes) 26 | switch (n.Name.ToLower()) 27 | { 28 | case "backup": Backup(n, id); break; 29 | case "backuplog": BackupLog(n, id); break; 30 | } 31 | return true; 32 | } 33 | 34 | void Backup(XmlNode n, string id) 35 | { 36 | var toFile = Program.Shared.ReplaceTags(Util.GetStr(n, "toFile")); 37 | var type = Program.Shared.ReplaceTags(Util.GetStr(n, "type", "bacpac")); 38 | var connStr = Program.Shared.Databases[id]; 39 | var dbName = Util.GetConfigData(connStr, "Initial Catalog"); 40 | Program.Shared.WriteLogLine("Starting Database Backup."); 41 | if (type.ToLower() == "bacpac"){ 42 | var ds = new Microsoft.SqlServer.Dac.DacServices(connStr); 43 | ds.ExportBacpac(toFile, dbName); 44 | }else if (type.ToLower() == "bak"){ 45 | var timeout = Util.GetStr(n, "timeout", "1800").IsNumber()?Convert.ToInt32(Util.GetStr(n, "timeout", "1800")):1800; 46 | var withOptions = Util.GetStr(n, "withOptions"); 47 | Util.Execute("backup database " + dbName + " to disk='" + toFile + "' " + withOptions, connStr, timeout); 48 | } 49 | Program.Shared.DbBackups.Add(toFile); 50 | var toVar = Util.GetStr(n, "toVar"); 51 | if (!string.IsNullOrEmpty(toVar)) 52 | lock (Program.Shared.LockVariables) { Program.Shared.Variables[toVar + ";" + Program.Shared.GetSequence()] = toFile; } 53 | Program.Shared.WriteLogLine(String.Format("Finished Database Backup (File: {0}; Size: {1}).", toFile, Util.GetFileSize(new FileInfo(toFile).Length))); 54 | } 55 | 56 | void BackupLog(XmlNode n, string id) 57 | { 58 | var toFile = Program.Shared.ReplaceTags(Util.GetStr(n, "toFile")); 59 | var connStr = Program.Shared.Databases[id]; 60 | var dbName = Util.GetConfigData(connStr, "Initial Catalog"); 61 | Program.Shared.WriteLogLine("Starting Database Log Backup."); 62 | var timeout = Util.GetStr(n, "timeout", "1800").IsNumber()?Convert.ToInt32(Util.GetStr(n, "timeout", "1800")):1800; 63 | var withOptions = Util.GetStr(n, "withOptions"); 64 | Util.Execute("backup log " + dbName + " to disk='" + toFile + "' " + withOptions, connStr, timeout); 65 | Program.Shared.DbBackups.Add(toFile); 66 | var toVar = Util.GetStr(n, "toVar"); 67 | if (!string.IsNullOrEmpty(toVar)) 68 | lock (Program.Shared.LockVariables) { Program.Shared.Variables[toVar + ";" + Program.Shared.GetSequence()] = toFile; } 69 | Program.Shared.WriteLogLine(String.Format("Finished Database Log Backup (File: {0}; Size: {1}).", toFile, Util.GetFileSize(new FileInfo(toFile).Length))); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Functions/ExceptionFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Xml; 9 | 10 | namespace DoIt.Functions 11 | { 12 | internal class ExceptionFunctions : FunctionsNodeHandlerBase 13 | { 14 | public ExceptionFunctions(XmlNode node):base(node){} 15 | 16 | public override bool Execute() 17 | { 18 | if (Node == null) 19 | return false; 20 | var assembly = Util.GetStr(Node, "assembly"); 21 | var type = Util.GetStr(Node, "type", "System.Exception"); 22 | var message = Util.GetStr(Node, "message"); 23 | var asm = null as Assembly; 24 | if (string.IsNullOrEmpty(assembly)) 25 | asm = Assembly.GetExecutingAssembly(); 26 | else{ 27 | var asmName = Assembly.GetExecutingAssembly().GetReferencedAssemblies().FirstOrDefault(item => item.Name.ToLower() == assembly.ToLower()); 28 | asm = asmName != null ? Assembly.Load(asmName) : Assembly.LoadFrom(Path.IsPathRooted(assembly) ? assembly : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assembly)); 29 | } 30 | if (asm == null) 31 | return false; 32 | var exType = Type.GetType(type) ?? asm.GetType(type); 33 | var ctor = exType.GetConstructor(new[]{typeof(string)}); 34 | throw ctor.Invoke(new object[]{message}) as Exception; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Functions/ForEachFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using System.Xml; 13 | 14 | namespace DoIt.Functions 15 | { 16 | internal class ForEachFunctions : FunctionsNodeHandlerBase 17 | { 18 | public ForEachFunctions(XmlNode node):base(node){} 19 | 20 | public override bool Execute() 21 | { 22 | var itemFrom = Program.Shared.ReplaceTags(Util.GetStr(Node, "itemFrom")); 23 | if (string.IsNullOrEmpty(itemFrom)) 24 | return false; 25 | var where = Program.Shared.ReplaceTags(Util.GetStr(Node, "where")); 26 | var sort = Program.Shared.ReplaceTags(Util.GetStr(Node, "sort")); 27 | var parallel = Convert.ToInt32(Util.GetStr(Node, "parallel", "1")); 28 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), itemFrom); 29 | if (dt == null) 30 | return false; 31 | var lstRows = string.IsNullOrEmpty(where) && string.IsNullOrEmpty(sort) ? dt.Rows.Cast().ToArray() : dt.Select(where, sort); 32 | if(parallel > 1){ 33 | var parentSequence = Program.Shared.GetSequence(); 34 | Task task = Task.Run(() => Parallel.ForEach(lstRows, new ParallelOptions{MaxDegreeOfParallelism=parallel}, (r, state) => { 35 | var sequence = parentSequence + "." + Program.Shared.ThreadID(); 36 | lock (Program.Shared.LockSequence){ 37 | if (Thread.CurrentThread.Name == null){ 38 | Thread.CurrentThread.Name = sequence; 39 | Program.Shared.ThreadSequence.Add(sequence); 40 | } 41 | } 42 | var itemID = itemFrom+";"+sequence; 43 | lock(Program.Shared.LockCurrentRows){ 44 | Program.Shared.CurrentRows[itemID] = r; 45 | } 46 | var stop = Program.Shared.ExecuteCommands(Node); 47 | lock(Program.Shared.LockCurrentRows){ 48 | Program.Shared.CurrentRows.RemoveKey(itemID); 49 | } 50 | if (stop) 51 | state.Stop(); 52 | })); 53 | task.Wait(); 54 | }else{ 55 | var itemID = itemFrom+";"+ Program.Shared.GetSequence(); 56 | foreach (DataRow r in lstRows){ 57 | lock(Program.Shared.LockCurrentRows) 58 | Program.Shared.CurrentRows[itemID] = r; 59 | if (Program.Shared.ExecuteCommands(Node)) 60 | break; 61 | } 62 | lock(Program.Shared.LockCurrentRows) 63 | Program.Shared.CurrentRows.RemoveKey(itemID); 64 | } 65 | return true; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Functions/FtpFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Text; 11 | using System.Text.RegularExpressions; 12 | using System.Threading.Tasks; 13 | using System.Xml; 14 | 15 | namespace DoIt.Functions 16 | { 17 | internal class FtpFunctions : FunctionsNodeHandlerBase 18 | { 19 | public FtpFunctions(XmlNode node):base(node){} 20 | 21 | public override bool Execute() 22 | { 23 | if (Node == null) 24 | return false; 25 | var host = Program.Shared.ReplaceTags(Util.GetStr(Node, "host")); 26 | var port = Program.Shared.ReplaceTags(Util.GetStr(Node, "port", "21")); 27 | var user = Program.Shared.ReplaceTags(Util.GetStr(Node, "user")); 28 | var pass = Program.Shared.ReplaceTags(Util.GetStr(Node, "password")); 29 | var lstNodes = Util.GetChildNodes(Node, "List", "Download", "Upload", "CreateFolder", "DeleteFolder", "DeleteFile"); 30 | foreach (var n in lstNodes) 31 | switch (n.Name.ToLower()) 32 | { 33 | case "list": List(n, host, port, user, pass); break; 34 | case "download": Download(n, host, port, user, pass); break; 35 | case "upload": Upload(n, host, port, user, pass); break; 36 | case "createfolder": CreateFolder(n, host, port, user, pass); break; 37 | case "deletefolder": DeleteFolder(n, host, port, user, pass); break; 38 | case "deletefile": DeleteFile(n, host, port, user, pass); break; 39 | } 40 | return true; 41 | } 42 | 43 | void List(XmlNode n, string host, string port, string user, string pass) 44 | { 45 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 46 | var dt = GetList(host, port, user, pass, path); 47 | var to = Program.Shared.ReplaceTags(Util.GetStr(n, "to")); 48 | lock (Program.Shared.LockDataTables) 49 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 50 | } 51 | 52 | void Download(XmlNode n, string host, string port, string user, string pass) 53 | { 54 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 55 | var toFile = Program.Shared.ReplaceTags(Util.GetStr(n, "toFile")); 56 | var rqt = GetFtpRequest(host, port, user, pass, WebRequestMethods.Ftp.DownloadFile, path); 57 | using (var rs = rqt.GetResponse() as FtpWebResponse) 58 | using (var stream = rs.GetResponseStream()) 59 | using (var fs = new FileStream(toFile, FileMode.Create, FileAccess.Write)) 60 | stream.CopyTo(fs); 61 | } 62 | 63 | void Upload(XmlNode n, string host, string port, string user, string pass) 64 | { 65 | var file = Program.Shared.ReplaceTags(Util.GetStr(n, "file")); 66 | var toPath = Program.Shared.ReplaceTags(Util.GetStr(n, "toPath")); 67 | var path = GetPathFromURL(host); 68 | host = host.Replace(path, ""); 69 | var filename = Path.GetFileName(toPath); 70 | path = CombinePaths(path, toPath.Replace(filename, "")); 71 | CreateFolder(host, port, user, pass, path); 72 | path = CombinePaths(path, filename); 73 | var rqt = GetFtpRequest(host, port, user, pass, WebRequestMethods.Ftp.UploadFile, path); 74 | using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read)) 75 | using (var rs = rqt.GetRequestStream()) 76 | fs.CopyTo(rs); 77 | Program.Shared.WriteLogLine($"Ftp file uploaded: {file} to host/path {host}/{toPath}"); 78 | } 79 | 80 | void CreateFolder(XmlNode n, string host, string port, string user, string pass) 81 | { 82 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 83 | CreateFolder(host, port, user, pass, path); 84 | } 85 | 86 | void DeleteFolder(XmlNode n, string host, string port, string user, string pass) 87 | { 88 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 89 | var rqt = GetFtpRequest(host, port, user, pass, WebRequestMethods.Ftp.RemoveDirectory, path); 90 | using (var rs = rqt.GetResponse() as FtpWebResponse) 91 | Program.Shared.WriteLogLine($"Ftp folder deleted: {path} - Response status code: {rs.StatusCode}"); 92 | } 93 | 94 | void DeleteFile(XmlNode n, string host, string port, string user, string pass) 95 | { 96 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 97 | var rqt = GetFtpRequest(host, port, user, pass, WebRequestMethods.Ftp.DeleteFile, path); 98 | using (var rs = rqt.GetResponse() as FtpWebResponse) 99 | Program.Shared.WriteLogLine($"Ftp folder deleted: {path} - Response status code: {rs.StatusCode}"); 100 | } 101 | 102 | DataTable GetList(string host, string port, string user, string pass, string path) 103 | { 104 | var rqt = GetFtpRequest(host, port, user, pass, WebRequestMethods.Ftp.ListDirectoryDetails, path); 105 | var str = null as string; 106 | using (var rs = rqt.GetResponse() as FtpWebResponse) 107 | using (var stream = rs.GetResponseStream()) 108 | using (var sr = new StreamReader(stream)) 109 | str = sr.ReadToEnd(); 110 | 111 | var lst = str.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); 112 | var pattern = @"^(?\d+-\d+-\d+\s+\d+:\d+(?:AM|PM))\s+(?|\d+)\s+(?.+)$"; 113 | var dt = new DataTable(); 114 | dt.Columns.Add("name", typeof(string)); 115 | dt.Columns.Add("type", typeof(string)); 116 | dt.Columns.Add("length", typeof(long)); 117 | dt.Columns.Add("datetime", typeof(DateTime)); 118 | foreach (var item in lst){ 119 | var m = Regex.Match(item, pattern); 120 | if (!m.Success) 121 | continue; 122 | var d = m.Groups["datetime"].Value.Replace("\t", " ").Replace(" ", " "); 123 | var l = m.Groups["length"].Value; 124 | 125 | var name = m.Groups["name"].Value; 126 | var type = l == "" ? "folder" : "file"; 127 | var len = l == "" ? null : new Nullable(Convert.ToInt64(l)); 128 | var date = DateTime.ParseExact("08-10-18 06:57PM", "MM-dd-yy hh:mmtt", System.Globalization.CultureInfo.InvariantCulture); 129 | dt.Rows.Add(name, type, len, date); 130 | } 131 | return dt; 132 | } 133 | 134 | FtpWebRequest GetFtpRequest(string host, string port, string user, string pass, string method, string path) 135 | { 136 | var uri = GetUri(host, port, user, pass, path); 137 | var rqt = FtpWebRequest.Create(uri) as FtpWebRequest; 138 | rqt.Method = method; 139 | rqt.EnableSsl = host.ToLower().StartsWith("ftps:"); 140 | rqt.Credentials = new NetworkCredential(user, pass); 141 | return rqt; 142 | } 143 | 144 | void CreateFolder(string host, string port, string user, string pass, string path) 145 | { 146 | var lstPaths = path.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); 147 | for (var x = 0; x < lstPaths.Length; x++) 148 | { 149 | var basePath = lstPaths.Where((string str, int index) => index < x).Concat(str => str, "/") ?? "/"; 150 | var newFolder = lstPaths[x]; 151 | var dt = GetList(host, port, user, pass, basePath); 152 | var rows = dt.Select($"type='folder' and name='{newFolder}'"); 153 | if (rows.Length > 0) 154 | continue; 155 | var rqt = GetFtpRequest(host, port, user, pass, WebRequestMethods.Ftp.MakeDirectory, basePath + "/" + newFolder); 156 | using (var rs = rqt.GetResponse() as FtpWebResponse) 157 | Program.Shared.WriteLogLine($"Ftp folder created: {path} - Response status code: {rs.StatusCode}"); 158 | } 159 | } 160 | 161 | string GetPathFromURL(string url) 162 | { 163 | var uri = new Uri(url); 164 | return uri.AbsolutePath; 165 | } 166 | 167 | string CombinePaths(params string[] paths) 168 | { 169 | if (paths == null || paths.Length == 0) 170 | return null; 171 | var rs = ""; 172 | foreach (var str in paths) 173 | rs += (rs.EndsWith("/") || str.StartsWith("/") ? "" : "/") + str; 174 | return rs; 175 | } 176 | 177 | Uri GetUri(string host, string port, string user, string pass, string path) 178 | { 179 | var uri = new Uri(host); 180 | if (!string.IsNullOrEmpty(path)) 181 | { 182 | var builder = new UriBuilder(uri); 183 | builder.Path = path; 184 | uri = builder.Uri; 185 | } 186 | if (!string.IsNullOrEmpty(port) && port.IsMatch("^\\d+$") && port != "21") 187 | { 188 | var value = Convert.ToInt32(port); 189 | var builder = new UriBuilder(uri); 190 | builder.Port = value; 191 | uri = builder.Uri; 192 | } 193 | if (!string.IsNullOrEmpty(uri.Scheme) && uri.Scheme.ToLower() == "ftps") 194 | { 195 | var builder = new UriBuilder(uri); 196 | builder.Scheme = "ftp"; 197 | uri = builder.Uri; 198 | } 199 | return uri; 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/Functions/FunctionsNodeHandlerBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml; 3 | 4 | namespace DoIt.Functions 5 | { 6 | internal abstract class FunctionsNodeHandlerBase 7 | { 8 | public XmlNode Node { get; set; } 9 | 10 | public FunctionsNodeHandlerBase(XmlNode node) 11 | { 12 | Node = node; 13 | } 14 | 15 | public abstract bool Execute(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Functions/HttpFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Xml; 8 | 9 | namespace DoIt.Functions 10 | { 11 | internal class HttpFunctions : FunctionsNodeHandlerBase 12 | { 13 | public HttpFunctions(XmlNode node):base(node){} 14 | 15 | public override bool Execute() 16 | { 17 | if (Node == null) 18 | return false; 19 | var lstNodes = Util.GetChildNodes(Node, "Request"); 20 | foreach (var n in lstNodes) 21 | switch (n.Name.ToLower()) { 22 | case "request": Request(n); break; 23 | } 24 | return true; 25 | } 26 | 27 | void Request(XmlNode n) 28 | { 29 | var method = Program.Shared.ReplaceTags(Util.GetStr(n, "method", "get")); 30 | var url = Program.Shared.ReplaceTags(Util.GetStr(n, "url")); 31 | var toFile = Program.Shared.ReplaceTags(Util.GetStr(n, "toFile")); 32 | var toVar = Program.Shared.ReplaceTags(Util.GetStr(n, "toVar")); 33 | var hasTo = !string.IsNullOrEmpty(toFile) || !string.IsNullOrEmpty(toVar); 34 | if (string.IsNullOrEmpty(url) || !hasTo) 35 | return; 36 | 37 | var headersNode = Util.GetChildNode(n, "Headers"); 38 | var lstHeaders = Util.GetChildNodes(headersNode, "Header"); 39 | var bodyNode = Util.GetChildNode(n, "Body"); 40 | 41 | var m = GetMethod(method); 42 | using (var msg = new HttpRequestMessage(m, url)) 43 | using (var http = new HttpClient()) 44 | { 45 | if (lstHeaders != null) 46 | foreach (var hNode in lstHeaders) 47 | { 48 | var headerName = Util.GetStr(hNode, "name"); 49 | if (!string.IsNullOrEmpty(headerName)) 50 | msg.Headers.Add(headerName, hNode.InnerXml); 51 | } 52 | 53 | if (bodyNode != null) 54 | { 55 | var bType = Util.GetStr(bodyNode, "type"); 56 | msg.Content = new StringContent(bodyNode.InnerXml, Encoding.UTF8, bType); 57 | } 58 | 59 | var task = http.SendAsync(msg); 60 | task.Wait(); 61 | var rs = task.Result; 62 | if (!string.IsNullOrEmpty(toVar)) 63 | { 64 | var t2 = rs.Content.ReadAsStringAsync(); 65 | t2.Wait(); 66 | lock (Program.Shared.LockVariables) 67 | Program.Shared.Variables[toVar + ";" + Program.Shared.GetSequence()] = t2.Result; 68 | } 69 | if (!string.IsNullOrEmpty(toFile)) 70 | { 71 | var t2 = rs.Content.ReadAsStreamAsync(); 72 | t2.Wait(); 73 | using (var fs = new FileStream(toFile, FileMode.Create, FileAccess.Write)) 74 | t2.Result.CopyTo(fs); 75 | } 76 | } 77 | } 78 | 79 | HttpMethod GetMethod(string method) 80 | { 81 | if (string.IsNullOrWhiteSpace(method)) 82 | return HttpMethod.Get; 83 | switch (method.ToLower().Trim()) 84 | { 85 | case "get": return HttpMethod.Get; 86 | case "post": return HttpMethod.Post; 87 | case "put": return HttpMethod.Put; 88 | case "delete": return HttpMethod.Delete; 89 | } 90 | return HttpMethod.Get; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Functions/LocalDiskFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Text.RegularExpressions; 11 | using System.Threading.Tasks; 12 | using System.Xml; 13 | 14 | namespace DoIt.Functions 15 | { 16 | internal class LocalDiskFunctions : FunctionsNodeHandlerBase 17 | { 18 | public LocalDiskFunctions(XmlNode node):base(node){} 19 | 20 | public override bool Execute() 21 | { 22 | if (Node == null) 23 | return false; 24 | var lstNodes = Util.GetChildNodes(Node, "ListFiles", "MoveFile", "MoveFolder", "CopyFile", "DeleteFile", "DeleteFolder"); 25 | foreach (var n in lstNodes) 26 | switch (n.Name.ToLower()){ 27 | case "listfiles": ListFiles(n); break; 28 | case "movefile": MoveFile(n); break; 29 | case "movefolder": MoveFolder(n); break; 30 | case "copyfile": CopyFile(n); break; 31 | case "deletefile": DeleteFile(n); break; 32 | case "deletefolder": DeleteFolder(n); break; 33 | } 34 | return true; 35 | } 36 | 37 | // list files 38 | void ListFiles(XmlNode n){ 39 | var to = Util.GetStr(n, "to"); 40 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 41 | if (string.IsNullOrEmpty(path)) 42 | return; 43 | var searchPattern = Util.GetStr(n, "searchPattern"); 44 | var allDirectories = Util.GetStr(n, "allDirectories", "false") == "true"; 45 | var fetchAttributes = Util.GetStr(n, "fetchAttributes", "false") == "true"; 46 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 47 | var sort = Util.GetStr(n, "sort"); 48 | var regex = Util.GetStr(n, "regex"); 49 | var dt = new DataTable(); 50 | dt.Columns.Add("full_path", typeof(string)); 51 | dt.Columns.Add("directory", typeof(string)); 52 | dt.Columns.Add("filename", typeof(string)); 53 | dt.Columns.Add("extension", typeof(string)); 54 | dt.Columns.Add("creation_time", typeof(DateTime)); 55 | dt.Columns.Add("last_write_time", typeof(DateTime)); 56 | dt.Columns.Add("length", typeof(long)); 57 | if (Directory.Exists(path)){ 58 | var lst = Directory.GetFiles(path, searchPattern, allDirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); 59 | if (!string.IsNullOrEmpty(regex)) 60 | lst = lst.Where(file => Regex.IsMatch(file, regex)).ToArray(); 61 | foreach (var file in lst){ 62 | var lstData = new List(){file, Path.GetDirectoryName(file), Path.GetFileName(file), Path.GetExtension(file)}; 63 | if(fetchAttributes){ 64 | var fi = new FileInfo(file); 65 | lstData.AddRange(new object[]{fi.CreationTime, fi.LastWriteTime, fi.Length}); 66 | } 67 | dt.Rows.Add(lstData.ToArray()); 68 | } 69 | if (!string.IsNullOrEmpty(where)||!string.IsNullOrEmpty(sort)){ 70 | var lstRows = dt.Select(where, sort); 71 | var lstRowsToRemove = dt.Rows.Cast().Where(r => !lstRows.Contains(r)).ToList(); 72 | foreach (var r in lstRowsToRemove) 73 | dt.Rows.Remove(r); 74 | } 75 | } 76 | lock (Program.Shared.LockDataTables){ 77 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 78 | } 79 | } 80 | 81 | // move file 82 | void MoveFile(XmlNode n){ 83 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 84 | var to = Program.Shared.ReplaceTags(Util.GetStr(n, "to")); 85 | if (!string.IsNullOrEmpty(path) && File.Exists(path)){ 86 | var dir = Path.GetDirectoryName(to); 87 | if (!Directory.Exists(dir)) 88 | Directory.CreateDirectory(dir); 89 | File.Move(path, to); 90 | } 91 | } 92 | 93 | // move folder 94 | void MoveFolder(XmlNode n){ 95 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 96 | var to = Program.Shared.ReplaceTags(Util.GetStr(n, "to")); 97 | if (!string.IsNullOrEmpty(path) && File.Exists(path)) 98 | Directory.Move(path, to); 99 | } 100 | 101 | // copy file 102 | void CopyFile(XmlNode n){ 103 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 104 | var to = Program.Shared.ReplaceTags(Util.GetStr(n, "to")); 105 | var overwrite = Util.GetStr(n, "overwrite", "true").ToLower() == "true"; 106 | if (!string.IsNullOrEmpty(path) && File.Exists(path)){ 107 | var folder = Path.GetDirectoryName(path); 108 | if (!Directory.Exists(folder)) 109 | Directory.CreateDirectory(folder); 110 | File.Copy(path, to, overwrite); 111 | } 112 | } 113 | 114 | // delete file 115 | void DeleteFile(XmlNode n){ 116 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 117 | if (!string.IsNullOrEmpty(path) && File.Exists(path)) 118 | File.Delete(path); 119 | } 120 | 121 | // delete folder 122 | void DeleteFolder(XmlNode n){ 123 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 124 | var recursive = Util.GetStr(n, "recursive", "false").ToLower() == "true"; 125 | if (!string.IsNullOrEmpty(path) && Directory.Exists(path)) 126 | Directory.Delete(path, recursive); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/Functions/LogFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Xml; 12 | 13 | namespace DoIt.Functions 14 | { 15 | internal class LogFunctions : FunctionsNodeHandlerBase 16 | { 17 | public LogFunctions(XmlNode node):base(node){} 18 | 19 | public override bool Execute() 20 | { 21 | if (Node == null) 22 | return false; 23 | 24 | var str = Program.Shared.ReplaceTags(Node.InnerXml); 25 | Program.Shared.IsLogEnabled = Util.GetStr(Node, "enabled", "true").ToLower() == "true"; 26 | Program.Shared.WriteLogLine(str); 27 | Console.WriteLine(str); 28 | return true; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Functions/MailFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Net.Mail; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | using System.Xml; 14 | using static DoIt.Program; 15 | 16 | namespace DoIt.Functions 17 | { 18 | internal class MailFunctions : FunctionsNodeHandlerBase 19 | { 20 | public MailFunctions(XmlNode node):base(node){} 21 | 22 | public override bool Execute() 23 | { 24 | var smtp1 = Util.GetStr(Node, "smtp"); 25 | var smtp2 = Util.GetStr(Node, "server"); 26 | var smtp = ""; 27 | if (!string.IsNullOrEmpty(smtp1)) 28 | smtp = smtp1; 29 | else if (!string.IsNullOrEmpty(smtp2) && Shared.MailServers.ContainsKey(smtp2)) 30 | smtp = Shared.MailServers[smtp2]; 31 | if (string.IsNullOrEmpty(smtp)) 32 | return false; 33 | var to = Util.GetStr(Node, "to"); 34 | var cc = Util.GetStr(Node, "cc"); 35 | var bcc = Util.GetStr(Node, "bcc"); 36 | var host = Util.GetConfigData(smtp, "host"); 37 | if (String.IsNullOrEmpty(to) || String.IsNullOrEmpty(host)) 38 | return false; 39 | var subject = Util.GetStr(Node, "subject", "DoIt - Task Script").Trim(); 40 | var body = Program.Shared.ReplaceTags(Util.GetStr(Node, "Body")); 41 | var from = Util.GetConfigData(smtp, "from"); 42 | var port = Convert.ToInt32(Util.GetConfigData(smtp,"port",false,"25")); 43 | var ssl = Util.GetConfigData(smtp, "ssl") == "true"; 44 | var user = Util.GetConfigData(smtp, "user"); 45 | var pass = Util.GetConfigData(smtp, "pass"); 46 | var mail = new MailMessage(); 47 | var lstFilesSent = new List(); 48 | var lstFilesToDelete = new List(); 49 | var attachmentsNode = Util.GetChildNode(Node, "Attachments"); 50 | if (attachmentsNode != null) 51 | foreach (XmlNode n in Util.GetChildNodes(attachmentsNode, "File", "SqlQuery")){ 52 | var tagName = String.IsNullOrWhiteSpace(n.Name) ? null : n.Name.ToLower(); 53 | var required = Util.GetStr(n, "required", "false").ToLower() == "true"; 54 | var deleteSource = Util.GetStr(n, "deleteSource", "false") == "true"; 55 | var zip = Util.GetStr(n, "zip", "false").ToLower() == "true"; 56 | var filename = null as String; 57 | if (tagName == "file"){ 58 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 59 | if (required && !File.Exists(path)) 60 | continue; 61 | filename = Util.GetFileToSend(path, zip); 62 | if (zip) 63 | lstFilesToDelete.Add(filename); 64 | if (deleteSource) 65 | lstFilesToDelete.Add(path); 66 | }else if (tagName == "sqlquery"){ 67 | var sql = n.InnerXml; 68 | var database = Util.GetStr(n, "database", Program.Shared.Databases.Keys.FirstOrDefault()); 69 | var dt = Util.Select(sql, Program.Shared.Databases[database]); 70 | if (required && dt.Rows.Count == 0) 71 | continue; 72 | var dataFormat = Util.GetStr(n, "dataFormat", "csv").ToLower(); 73 | if(!dataFormat.In("csv", "xml", "json")) 74 | dataFormat = "csv"; 75 | var tempFile = Util.GetTempFileName(dataFormat); 76 | using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write)) 77 | using (var sw = new StreamWriter(fs, Encoding.Default)) 78 | switch (dataFormat){ 79 | case "csv": sw.Write(dt.ToCSV()); break; 80 | case "xml": sw.Write(dt.ToXML()); break; 81 | case "json": sw.Write(dt.ToJSON()); break; 82 | } 83 | var zipEntryName = Util.GetStr(n, "zipEntryName", tempFile); 84 | filename = Util.GetFileToSend(tempFile, Util.GetStr(n, "zip", "false").ToLower() == "true", zipEntryName); 85 | lstFilesToDelete.Add(tempFile); 86 | lstFilesToDelete.Add(filename); 87 | } 88 | lstFilesSent.Add(filename); 89 | var attachmentName = Util.GetStr(n, "attachmentName", Path.GetFileName(filename)); 90 | var sr = new FileStream(filename, FileMode.Open, FileAccess.Read); 91 | mail.Attachments.Add(new Attachment(sr, attachmentName, Util.GetContentType(attachmentName))); 92 | } 93 | mail.From = new MailAddress(from); 94 | if (!string.IsNullOrEmpty(to)) 95 | foreach (var m in to.Split(new String[]{",",";"," "}, StringSplitOptions.RemoveEmptyEntries)) 96 | mail.To.Add(new MailAddress(m)); 97 | if (!string.IsNullOrEmpty(cc)) 98 | foreach (var m in cc.Split(new String[] { ",", ";", " " }, StringSplitOptions.RemoveEmptyEntries)) 99 | mail.CC.Add(new MailAddress(m)); 100 | if (!string.IsNullOrEmpty(bcc)) 101 | foreach (var m in bcc.Split(new String[] { ",", ";", " " }, StringSplitOptions.RemoveEmptyEntries)) 102 | mail.Bcc.Add(new MailAddress(m)); 103 | mail.Subject = subject; 104 | mail.Body = body; 105 | var smtpClient = new SmtpClient(host, port); 106 | smtpClient.EnableSsl = ssl; 107 | smtpClient.Credentials = new NetworkCredential(user, pass); 108 | smtpClient.Send(mail); 109 | foreach (var at in mail.Attachments){ 110 | at.ContentStream.Dispose(); 111 | at.Dispose(); 112 | } 113 | Program.Shared.WriteLogLine(String.Format("Mail Sent: {0}; To: {1}; {2};", subject, to, lstFilesSent.Count > 0 ? "Attachments: " + lstFilesSent.Concat(f => f) : "No Attachments")); 114 | foreach (var f in lstFilesToDelete) 115 | if (File.Exists(f)) 116 | File.Delete(f); 117 | return true; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/Functions/ProcessFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.Diagnostics; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Xml; 13 | 14 | namespace DoIt.Functions 15 | { 16 | internal class ProcessFunctions : FunctionsNodeHandlerBase 17 | { 18 | public ProcessFunctions(XmlNode node):base(node){} 19 | 20 | public override bool Execute() 21 | { 22 | if (Node == null) 23 | return false; 24 | var lstNodes = Util.GetChildNodes(Node, "Start", "Kill", "List"); 25 | foreach (var n in lstNodes) 26 | switch (n.Name.ToLower()){ 27 | case "start": Start(n); break; 28 | case "kill": Kill(n); break; 29 | case "list": List(n); break; 30 | } 31 | return true; 32 | } 33 | 34 | void Start(XmlNode n) 35 | { 36 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 37 | var args = Program.Shared.ReplaceTags(Util.GetStr(n, "args")); 38 | var wait = Util.GetStr(n, "wait", "true").ToLower() == "true"; 39 | var timeSpan = Util.GetTimeSpan(Util.GetStr(n, "time")); 40 | var process = Process.Start(path, args); 41 | if (wait){ 42 | var ms = Convert.ToInt32(timeSpan.TotalMilliseconds); 43 | if (ms > 0) 44 | process.WaitForExit(ms); 45 | else 46 | process.WaitForExit(); 47 | } 48 | } 49 | 50 | void Kill(XmlNode n) 51 | { 52 | var id = Convert.ToInt32(Program.Shared.ReplaceTags(Util.GetStr(n, "id", "0"))); 53 | var name = Program.Shared.ReplaceTags(Util.GetStr(n, "name")); 54 | if (id > 0) 55 | Process.GetProcessById(id); 56 | if (!string.IsNullOrEmpty(name)){ 57 | var lst = Process.GetProcessesByName(name); 58 | foreach (var p in lst) 59 | p.Kill(); 60 | } 61 | } 62 | 63 | void List(XmlNode n) 64 | { 65 | var name = Program.Shared.ReplaceTags(Util.GetStr(n, "name")); 66 | var regex = Program.Shared.ReplaceTags(Util.GetStr(n, "regex")); 67 | var machine = Program.Shared.ReplaceTags(Util.GetStr(n, "machine")); 68 | var to = Util.GetStr(n, "to"); 69 | var lst = string.IsNullOrEmpty(name) ? 70 | (string.IsNullOrEmpty(machine) ? Process.GetProcesses() : Process.GetProcesses(machine)): 71 | (string.IsNullOrEmpty(machine) ? Process.GetProcessesByName(name) : Process.GetProcessesByName(name, machine)); 72 | if (!string.IsNullOrEmpty(regex)) 73 | lst = lst.Where(p => p.ProcessName.IsMatch(regex)).ToArray(); 74 | var dt = new DataTable(); 75 | dt.Columns.Add("id", typeof(int)); 76 | dt.Columns.Add("session_id", typeof(int)); 77 | dt.Columns.Add("name", typeof(string)); 78 | dt.Columns.Add("machine", typeof(string)); 79 | dt.Columns.Add("start", typeof(DateTime)); 80 | dt.Columns.Add("filename", typeof(string)); 81 | foreach (var p in lst) 82 | dt.Rows.Add(p.Id, p.SessionId, p.ProcessName, p.MachineName, p.StartTime, p.MainModule.FileName); 83 | lock (Program.Shared.LockDataTables){ 84 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Functions/SetValueFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using Microsoft.WindowsAzure.Storage; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using System.Threading.Tasks; 11 | using System.Xml; 12 | 13 | namespace DoIt.Functions 14 | { 15 | internal class SetValueFunctions : FunctionsNodeHandlerBase 16 | { 17 | public SetValueFunctions(XmlNode node):base(node){} 18 | 19 | public override bool Execute() 20 | { 21 | if (Node == null) 22 | return false; 23 | var lstNodes = Util.GetChildNodes(Node, "FileProp", "BlobProp", "Calc", "CalcDate", "String", "Date", "Coalesce"); 24 | foreach (var n in lstNodes) 25 | switch (n.Name.ToLower()){ 26 | case "fileprop": FileProp(n); break; 27 | case "blobprop": BlobProp(n); break; 28 | case "calc": Calc(n); break; 29 | case "calcdate": CalcDate(n); break; 30 | case "string": String(n); break; 31 | case "date": Date(n); break; 32 | case "coalesce": Coalesce(n); break; 33 | } 34 | return true; 35 | } 36 | 37 | // file properties 38 | void FileProp(XmlNode n){ 39 | var path = Program.Shared.ReplaceTags(Util.GetStr(n, "path")); 40 | var prop = Util.GetStr(n, "prop", ""); 41 | var to = Util.GetStr(n, "to"); 42 | var length = 0L; 43 | var creation = null as DateTime?; 44 | var modification = null as DateTime?; 45 | var lstProps=prop.ToLower().Split(new string[]{",",";"," "}, StringSplitOptions.RemoveEmptyEntries); 46 | var lstTo=to.ToLower().Split(new string[]{",",";"," "}, StringSplitOptions.RemoveEmptyEntries); 47 | if (File.Exists(path)){ 48 | var fi = new FileInfo(path); 49 | length = fi.Length; 50 | creation = fi.CreationTime; 51 | modification = fi.LastWriteTime; 52 | } 53 | for (var x=0;x(blob.Properties.LastModified.Value.DateTime); 81 | } 82 | var lstProps=prop.ToLower().Split(new string[]{",",";"," "}, StringSplitOptions.RemoveEmptyEntries); 83 | var lstTo=to.ToLower().Split(new string[]{",",";"," "}, StringSplitOptions.RemoveEmptyEntries); 84 | for (var x=0;x().Any(m => m.Success)) 165 | value = ""; 166 | 167 | var index = -1; 168 | foreach (Match m in lstMatches) 169 | { 170 | if (!m.Success) 171 | continue; 172 | 173 | index++; 174 | if (mIndex != null && mIndex != index) 175 | continue; 176 | 177 | if (m.Groups.Count > 0) 178 | { 179 | var g = string.IsNullOrEmpty(regexGroup) ? 180 | m.Groups[0] : 181 | (isRegexGroupInt ? m.Groups[regexGroupInt] : m.Groups[regexGroup]); 182 | value = g?.Value ?? ""; 183 | } 184 | else 185 | value = m.Value; 186 | } 187 | } 188 | lock (Program.Shared.LockVariables) 189 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = value; 190 | Program.Shared.WriteLogLine(string.Format("String variable named \"{0}\" was set to \"{1}\"", to, value)); 191 | } 192 | 193 | // date 194 | void Date(XmlNode n){ 195 | var value = Program.Shared.ReplaceTags(Util.GetStr(n, "value", "{now}")); 196 | var to = Util.GetStr(n, "to"); 197 | var date = Util.ParseDateTime(value); 198 | lock (Program.Shared.LockVariables){ 199 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = date; 200 | } 201 | Program.Shared.WriteLogLine(string.Format("Date variable named \"{0}\" was set to \"{1}\"", to, value)); 202 | } 203 | 204 | // coalesce 205 | void Coalesce(XmlNode n) 206 | { 207 | var values = Program.Shared.ReplaceTags(Util.GetStr(n, "values")); 208 | var to = Util.GetStr(n, "to"); 209 | var array = values?.Split(new string[]{",",";"},StringSplitOptions.RemoveEmptyEntries); 210 | var value = null as object; 211 | if (array != null) 212 | foreach (var k in array){ 213 | value = Program.Shared.GetVariable(Program.Shared.ThreadID(), k); 214 | if (value != null) 215 | break; 216 | } 217 | lock (Program.Shared.LockVariables){ 218 | Program.Shared.Variables[to+";"+Program.Shared.GetSequence()] = value; 219 | } 220 | Program.Shared.WriteLogLine(string.Format("Coalesce: variable named \"{0}\" was set to \"{1}\"", to, value)); 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/Functions/SleepFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using System.Xml; 13 | 14 | namespace DoIt.Functions 15 | { 16 | internal class SleepFunctions : FunctionsNodeHandlerBase 17 | { 18 | public SleepFunctions(XmlNode node):base(node){} 19 | 20 | public override bool Execute() 21 | { 22 | if (Node == null) 23 | return false; 24 | var time = Util.GetStr(Node, "time", "0"); 25 | var timeSpan = Util.GetTimeSpan(time); 26 | if (timeSpan == TimeSpan.Zero) 27 | return false; 28 | Program.Shared.WriteLogLine("Current thread is sleeping for {0}...", time); 29 | Thread.Sleep(timeSpan); 30 | return true; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Functions/SqlFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.Data.SqlClient; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Xml; 13 | 14 | namespace DoIt.Functions 15 | { 16 | internal class SqlFunctions : FunctionsNodeHandlerBase 17 | { 18 | public SqlFunctions(XmlNode node):base(node){} 19 | 20 | public override bool Execute() 21 | { 22 | if (Node == null) 23 | return false; 24 | Action> runSQL = (SqlConnection conn, bool startTransaction, List lstNodes) => { 25 | using (var trans = startTransaction ? conn.BeginTransaction() : null){ 26 | var commit = false; 27 | foreach (XmlNode n in lstNodes){ 28 | var tagName = String.IsNullOrWhiteSpace(n.Name) ? null : n.Name.ToLower(); 29 | if(tagName == "execute") 30 | commit = Execute(conn, trans, n); 31 | else if(tagName == "scalar") 32 | commit = Scalar(conn, trans, n); 33 | else if(tagName == "select") 34 | Select(conn, trans, n); 35 | } 36 | if (trans != null){ 37 | if (commit) trans.Commit(); 38 | else trans.Rollback(); 39 | } 40 | } 41 | }; 42 | var database = Util.GetStr(Node, "database"); 43 | var transaction = Util.GetStr(Node, "transaction", "true").ToLower() == "true"; 44 | using (var conn = new SqlConnection(Program.Shared.Databases[database])){ 45 | conn.Open(); 46 | runSQL(conn, transaction, Node.ChildNodes.Cast().ToList()); 47 | conn.Close(); 48 | } 49 | foreach (XmlNode transNode in Node.ChildNodes.Cast().Where(n2 => n2.Name.ToLower() == "trans")){ 50 | var tDatabase = Util.GetStr(transNode, "database", database); 51 | using (var conn = new SqlConnection(Program.Shared.Databases[tDatabase])){ 52 | conn.Open(); 53 | runSQL(conn, true, transNode.ChildNodes.Cast().ToList()); 54 | conn.Close(); 55 | } 56 | } 57 | return true; 58 | } 59 | 60 | void Select(SqlConnection conn, SqlTransaction trans, XmlNode n) 61 | { 62 | var to = Util.GetStr(n, "to"); 63 | var cmdNode = Util.GetChildNode(n, "Cmd"); 64 | var parametersNode = Util.GetChildNode(n, "Params"); 65 | var lstParameters = GetParameters(parametersNode); 66 | var sql = Program.Shared.ReplaceTags(cmdNode == null && parametersNode == null ? n.InnerText : cmdNode.InnerText); 67 | var timeout = Util.GetStr(n, "timeout"); 68 | //Program.Shared.WriteLogLine("SQL Select: {0}", sql); 69 | var dt = Util.Select(sql, conn, trans, lstParameters, string.IsNullOrEmpty(timeout) || !timeout.IsMatch("\\d+") ? null : new Nullable(Convert.ToInt32(timeout))); 70 | lock (Program.Shared.LockDataTables){ 71 | Program.Shared.DataTables[to + ";" + Program.Shared.GetSequence()] = dt; 72 | } 73 | //Program.Shared.WriteLogLine("SQL Select: {0} row(s) found", dt.Rows.Count); 74 | } 75 | 76 | bool Scalar(SqlConnection conn, SqlTransaction trans, XmlNode n) 77 | { 78 | var to = Util.GetStr(n, "to"); 79 | var cmdNode = Util.GetChildNode(n, "Cmd"); 80 | var parametersNode = Util.GetChildNode(n, "Params"); 81 | var lstParameters = GetParameters(parametersNode); 82 | var sql = Program.Shared.ReplaceTags(cmdNode == null && parametersNode == null ? n.InnerText : cmdNode.InnerText); 83 | var timeout = Util.GetStr(n, "timeout"); 84 | //Program.Shared.WriteLogLine("SQL Scalar: {0}", sql); 85 | var obj = Util.Scalar(sql, conn, trans, lstParameters, string.IsNullOrEmpty(timeout) || !timeout.IsMatch("\\d+") ? null : new Nullable(Convert.ToInt32(timeout))); 86 | lock (Program.Shared.LockVariables){ 87 | Program.Shared.Variables[to + ";" + Program.Shared.GetSequence()] = obj; 88 | } 89 | //Program.Shared.WriteLogLine("SQL Scalar: Value returned is \"{0}\"", obj == null || obj == DBNull.Value ? "null" : Convert.ToString(obj)); 90 | return true; 91 | } 92 | 93 | bool Execute(SqlConnection conn, SqlTransaction trans, XmlNode n) 94 | { 95 | var to = Util.GetStr(n, "to"); 96 | var cmdNode = Util.GetChildNode(n, "Cmd"); 97 | var parametersNode = Util.GetChildNode(n, "Params"); 98 | var lstParameters = GetParameters(parametersNode); 99 | var sql = Program.Shared.ReplaceTags(cmdNode == null && parametersNode == null ? n.InnerText : cmdNode.InnerText); 100 | var timeout = Util.GetStr(n, "timeout"); 101 | //Program.Shared.WriteLogLine("SQL Execute: {0}", sql); 102 | var rows = Util.Execute(sql, conn, trans, lstParameters, string.IsNullOrEmpty(timeout) || !timeout.IsMatch("\\d+") ? null : new Nullable(Convert.ToInt32(timeout))); 103 | if (!string.IsNullOrEmpty(to)) 104 | lock (Program.Shared.LockVariables){ 105 | Program.Shared.Variables[to + ";" + Program.Shared.GetSequence()] = rows; 106 | } 107 | //Program.Shared.WriteLogLine("SQL Execute: {0} row(s) affected", rows); 108 | return true; 109 | } 110 | 111 | SqlParameter[] GetParameters(XmlNode node) 112 | { 113 | if (node == null) 114 | return null; 115 | var lstNodes = Util.GetChildNodes(node); 116 | var lst = new List(); 117 | foreach (var n in lstNodes){ 118 | var type = Util.GetStr(n, "type"); 119 | var str = Program.Shared.ReplaceTags(n.InnerText); 120 | var value = GetParameterValue(str, type); 121 | lst.Add(new SqlParameter(n.Name, value)); 122 | } 123 | return lst.ToArray(); 124 | } 125 | 126 | object GetParameterValue(string value, string type) 127 | { 128 | if (string.IsNullOrEmpty(value)) 129 | return DBNull.Value; 130 | if (string.IsNullOrEmpty(type)) 131 | return value; 132 | type = type.ToLower(); 133 | if (type == "int") 134 | return Convert.ToInt32(value); 135 | if (type == "long") 136 | return Convert.ToInt64(value); 137 | if (type == "date" || type == "datetime") 138 | return Util.ParseDateTime(value); 139 | if (type == "datetimeoffset") 140 | return Util.ParseDateTimeOffset(value); 141 | return value; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/Functions/StorageFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using LumenWorks.Framework.IO.Csv; 3 | using Microsoft.WindowsAzure.Storage; 4 | using Microsoft.WindowsAzure.Storage.Blob; 5 | using Microsoft.WindowsAzure.Storage.RetryPolicies; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Data; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Text.RegularExpressions; 13 | using System.Threading.Tasks; 14 | using System.Xml; 15 | using static DoIt.Program; 16 | 17 | namespace DoIt.Functions 18 | { 19 | internal class StorageFunctions : FunctionsNodeHandlerBase 20 | { 21 | public StorageFunctions(XmlNode node):base(node){} 22 | 23 | public override bool Execute() 24 | { 25 | if (Node == null) 26 | return false; 27 | var id = Util.GetStr(Node, "id"); 28 | //if (string.IsNullOrEmpty(id)) 29 | // return false; 30 | var lstNodes = Util.GetChildNodes(Node, "Upload", "Download", "ListBlobs", "ListContainers", "Copy", "SetMetadata", "Snapshot", "DeleteMultipleBlobs", "DeleteBlob", "DeleteSnapshot", "DeleteContainers"); 31 | foreach (var n in lstNodes) 32 | switch (n.Name.ToLower()){ 33 | case "upload": Upload(id, n); break; 34 | case "download": Download(id, n); break; 35 | case "listblobs": ListBlobs(id, n); break; 36 | case "listcontainers": ListContainers(id, n); break; 37 | case "copy": Copy(id, n); break; 38 | case "setmetadata": SetMetadata(id, n); break; 39 | case "snapshot": Snapshot(id, n); break; 40 | case "deletemultipleblobs": DeleteMultipleBlobs(id, n); break; 41 | case "deleteblob": DeleteBlob(id, n); break; 42 | case "deletesnapshot": DeleteSnapshot(id, n); break; 43 | case "deletecontainers": DeleteContainers(id, n); break; 44 | } 45 | return true; 46 | } 47 | 48 | // upload 49 | void Upload(string id, XmlNode n){ 50 | var file = Program.Shared.ReplaceTags(Util.GetStr(n, "file")); 51 | var folder = Program.Shared.ReplaceTags(Util.GetStr(n, "folder")); 52 | var toBlob = Program.Shared.ReplaceTags(Util.GetStr(n, "toBlob")); 53 | var toFolder = Program.Shared.ReplaceTags(Util.GetStr(n, "toFolder")); 54 | var pattern = Util.GetStr(n, "pattern", "*.*"); 55 | var deleteSource = Util.GetStr(n, "deleteSource", "false").ToLower() == "true"; 56 | var async = Util.GetStr(n, "async", "false").ToLower() == "true"; 57 | var lstFiles = string.IsNullOrEmpty(file) && !string.IsNullOrEmpty(folder) ? Util.GetFiles(folder, pattern) : new string[]{file}; 58 | var timeout = Util.GetStr(n, "timeout", "0"); 59 | var retryTime = Util.GetStr(n, "retryTime", "30s"); 60 | var retryAttempts = Util.GetStr(n, "retryAttempts", "0"); 61 | var options = null as BlobRequestOptions; 62 | if (timeout != "0" || retryAttempts != "0") { 63 | options = new BlobRequestOptions(); 64 | if (timeout != "0") 65 | options.MaximumExecutionTime = Util.GetTimeSpan(timeout); 66 | if (retryAttempts != "0") 67 | options.RetryPolicy = new LinearRetry(Util.GetTimeSpan(retryTime), Convert.ToInt32(retryAttempts)); 68 | } 69 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 70 | var blobContainer = blobClient.GetContainerReference((toBlob??toFolder).Remove(toBlob.IndexOf("/"))); 71 | if (blobContainer.CreateIfNotExists()) 72 | blobContainer.SetPermissions(new BlobContainerPermissions(){PublicAccess=BlobContainerPublicAccessType.Off}); 73 | foreach (var f in lstFiles){ 74 | if (!File.Exists(f)){ 75 | Program.Shared.WriteLogLine(String.Format("File Not Found: {0}.", f)); 76 | continue; 77 | } 78 | var blobName = string.IsNullOrEmpty(toBlob) ? toFolder.Substring(toFolder.IndexOf("/") + 1) + "/" + Path.GetFileName(f) : toBlob.Substring(toBlob.IndexOf("/") + 1) + (string.IsNullOrEmpty(file) && !string.IsNullOrEmpty(folder) ? "/" + Path.GetFileName(f) : null); 79 | var blob = blobContainer.GetBlockBlobReference(blobName); 80 | blob.Properties.ContentType = Util.GetContentType(f); 81 | Program.Shared.WriteLogLine(String.Format("Sending File To Storage (File: {0}; Size: {1}).", Path.GetFileName(f), Util.GetFileSize(new FileInfo(f).Length))); 82 | if (async){ 83 | var task = blob.UploadFromFileAsync(f, null, options, null); 84 | Program.Shared.StorageUploadTasks.Add(task); 85 | task.ContinueWith(t => { 86 | if (deleteSource && File.Exists(f)){ 87 | File.Delete(f); 88 | Program.Shared.WriteLogLine(String.Format("File Deleted: {0}.", f)); 89 | } 90 | }); 91 | }else{ 92 | blob.UploadFromFile(f, null, options); 93 | if (deleteSource && File.Exists(f)){ 94 | File.Delete(f); 95 | Program.Shared.WriteLogLine(String.Format("File Deleted: {0}.", f)); 96 | } 97 | } 98 | } 99 | } 100 | 101 | // download 102 | void Download(string id, XmlNode n){ 103 | var blobName = Program.Shared.ReplaceTags(Util.GetStr(n, "blob")); 104 | var blobUri = Program.Shared.ReplaceTags(Util.GetStr(n, "uri")); 105 | var toFile = Program.Shared.ReplaceTags(Util.GetStr(n, "toFile")); 106 | var sas = Program.Shared.ReplaceTags(Util.GetStr(n, "sharedAccessSignature")); 107 | var snapshotTime = Util.ParseDateTimeOffset(Program.Shared.ReplaceTags(Util.GetStr(n, "snapshotTime"))); 108 | var timeout = Util.GetStr(n, "timeout", "0"); 109 | var retryTime = Util.GetStr(n, "retryTime", "30s"); 110 | var retryAttempts = Util.GetStr(n, "retryAttempts", "0"); 111 | var options = new BlobRequestOptions() { DisableContentMD5Validation = true }; 112 | if (timeout != "0") 113 | options.MaximumExecutionTime = Util.GetTimeSpan(timeout); 114 | if (retryAttempts != "0") 115 | options.RetryPolicy = new LinearRetry(Util.GetTimeSpan(retryTime), Convert.ToInt32(retryAttempts)); 116 | 117 | if (!string.IsNullOrEmpty(blobName)){ 118 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 119 | var blobContainer = blobClient.GetContainerReference(blobName.Remove(blobName.IndexOf("/"))); 120 | var blob = GetBlobReference(blobContainer, blobName.Substring(blobName.IndexOf("/") + 1), sas, snapshotTime); 121 | if (blob.Exists()){ 122 | var dir = Path.GetDirectoryName(toFile); 123 | if (!Directory.Exists(dir)) 124 | Directory.CreateDirectory(dir); 125 | blob.DownloadToFile(toFile, FileMode.Create, null, options); 126 | } 127 | } 128 | if(!string.IsNullOrEmpty(blobUri)){ 129 | var blob = GetBlobReference(blobUri, sas, snapshotTime); 130 | if (blob.Exists()){ 131 | var dir = Path.GetDirectoryName(toFile); 132 | if (!Directory.Exists(dir)) 133 | Directory.CreateDirectory(dir); 134 | blob.DownloadToFile(toFile, FileMode.Create, null, options); 135 | } 136 | } 137 | } 138 | 139 | CloudBlockBlob GetBlobReference(CloudBlobContainer container, string blobName, string sasKey = null, DateTimeOffset? snapshotTime = null) 140 | { 141 | if (container == null || string.IsNullOrEmpty(blobName)) 142 | return null; 143 | var sasString = !string.IsNullOrEmpty(sasKey) && Program.Shared.SharedAccessSignatures.ContainsKey(sasKey) ? Program.Shared.SharedAccessSignatures[sasKey] : ""; 144 | return snapshotTime == null ? 145 | container.GetBlockBlobReference(blobName + sasString): 146 | container.GetBlockBlobReference(blobName + sasString, snapshotTime); 147 | } 148 | 149 | CloudBlockBlob GetBlobReference(string blobUri, string sasKey = null, DateTimeOffset? snapshotTime = null) 150 | { 151 | var snapshotString = snapshotTime == null ? "" : string.Format("?snapshot={0:yyyy-MM-ddTHH:mm:ss.fffffffZ}", snapshotTime.Value.UtcDateTime); 152 | var sasString = string.IsNullOrEmpty(sasKey) || !Program.Shared.SharedAccessSignatures.ContainsKey(sasKey) ? "" : Program.Shared.SharedAccessSignatures[sasKey]; 153 | if (!string.IsNullOrEmpty(snapshotString) && !string.IsNullOrEmpty(sasString) && sasString.StartsWith("?")) 154 | sasString = "&" + sasString.Remove(0, 1); 155 | var uri = new Uri(blobUri + snapshotString + sasString); 156 | return new CloudBlockBlob(uri); 157 | } 158 | 159 | // list blobs 160 | void ListBlobs(string id, XmlNode n){ 161 | var to = Util.GetStr(n, "to"); 162 | var container = Program.Shared.ReplaceTags(Util.GetStr(n, "container")); 163 | var uri = Program.Shared.ReplaceTags(Util.GetStr(n, "uri")); 164 | var prefix = Program.Shared.ReplaceTags(Util.GetStr(n, "prefix")); 165 | var fetchAttributes = Util.GetStr(n, "fetchAttributes", "false").ToLower() == "true"; 166 | var details = Util.GetEnumValue(Util.GetStr(n, "details", "none"), BlobListingDetails.None); 167 | var flat = Util.GetStr(n, "flat", details.HasFlag(BlobListingDetails.Snapshots) ? "true" : "false").ToLower() == "true"; 168 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 169 | var sort = Program.Shared.ReplaceTags(Util.GetStr(n, "sort")); 170 | var regex = Program.Shared.ReplaceTags(Util.GetStr(n, "regex")); 171 | var sas = Program.Shared.ReplaceTags(Util.GetStr(n, "sharedAccessSignature")); 172 | var timeout = Util.GetStr(n, "timeout", "0"); 173 | var retryTime = Util.GetStr(n, "retryTime", "30s"); 174 | var retryAttempts = Util.GetStr(n, "retryAttempts", "0"); 175 | var options = null as BlobRequestOptions; 176 | if (timeout != "0" || retryAttempts != "0") { 177 | options = new BlobRequestOptions(); 178 | if (timeout != "0") 179 | options.MaximumExecutionTime = Util.GetTimeSpan(timeout); 180 | if (retryAttempts != "0") 181 | options.RetryPolicy = new LinearRetry(Util.GetTimeSpan(retryTime), Convert.ToInt32(retryAttempts)); 182 | } 183 | 184 | var lst = null as CloudBlob[]; 185 | var blobClient = null as CloudBlobClient; 186 | var blobContainer = null as CloudBlobContainer; 187 | if (string.IsNullOrEmpty(uri)){ 188 | blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 189 | blobContainer = string.IsNullOrEmpty(container) ? null : blobClient.GetContainerReference(container + (!string.IsNullOrEmpty(sas) && Program.Shared.SharedAccessSignatures.ContainsKey(sas) ? Program.Shared.SharedAccessSignatures[sas] : null)); 190 | lst = (blobContainer == null ? blobClient.ListBlobs(prefix, flat, details, options) : (blobContainer.Exists() ? blobContainer.ListBlobs(prefix, flat, details, options) : new CloudBlob[0])).Where(b => b is CloudBlob).Cast().ToArray(); 191 | } else { 192 | blobContainer = new CloudBlobContainer(new Uri(uri + (Program.Shared.SharedAccessSignatures.ContainsKey(sas) ? Program.Shared.SharedAccessSignatures[sas] : null))); 193 | lst = blobContainer.ListBlobs(prefix, flat, details, options).Where(b => b is CloudBlob).Cast().ToArray(); 194 | } 195 | if (!string.IsNullOrEmpty(regex)) 196 | lst = lst.Where(b => Regex.IsMatch(b.Uri.PathAndQuery, regex)).ToArray(); 197 | var lstMetadata = Util.GetChildNodes(n, "Metadata").Select(n2 => new { Name = Util.GetStr(n2, "name"), Type = Util.GetStr(n2, "type"), Format = n2.InnerXml }).Where(m => !string.IsNullOrEmpty(m.Name) && !string.IsNullOrEmpty(m.Type)).ToArray(); 198 | var dt = new DataTable(); 199 | dt.Columns.Add("blob_name", typeof(string)); 200 | dt.Columns.Add("blob_extension", typeof(string)); 201 | dt.Columns.Add("blob_container", typeof(string)); 202 | dt.Columns.Add("blob_uri", typeof(string)); 203 | dt.Columns.Add("blob_length", typeof(long)); 204 | dt.Columns.Add("blob_last_modified", typeof(DateTimeOffset)); 205 | dt.Columns.Add("blob_last_modified_utc", typeof(DateTime)); 206 | dt.Columns.Add("blob_content_type", typeof(string)); 207 | dt.Columns.Add("blob_content_md5", typeof(string)); 208 | dt.Columns.Add("blob_is_snapshot", typeof(bool)); 209 | dt.Columns.Add("blob_snapshot_time", typeof(DateTimeOffset)); 210 | foreach (var blob in lst){ 211 | if (fetchAttributes){ 212 | blob.FetchAttributes(); 213 | Program.Shared.WriteLogLine("Fetching blob attributes: " + blob.Uri.ToString()); 214 | } 215 | var lstRowData = new List(){blob.Name, blob.Name.GetFileExtension(), blob.Container.Name, blob.Uri.ToString(), blob.Properties.Length, blob.Properties.LastModified, blob.Properties.LastModified?.UtcDateTime, blob.Properties.ContentType, blob.Properties.ContentMD5, blob.IsSnapshot, blob.SnapshotTime}; 216 | if(blob.Metadata != null){ 217 | foreach (var k in blob.Metadata.Keys) 218 | if (!dt.Columns.Contains("metadata_" + k)){ 219 | var metadata = lstMetadata.FirstOrDefault(m => m.Name == k); 220 | if (metadata == null){ 221 | dt.Columns.Add("metadata_" + k, typeof(string)); 222 | continue; 223 | } 224 | switch (metadata.Type.ToLower()){ 225 | case "datetime": dt.Columns.Add("metadata_" + k, typeof(DateTime)); break; 226 | case "datetimeoffset": dt.Columns.Add("metadata_" + k, typeof(DateTimeOffset)); break; 227 | case "short": dt.Columns.Add("metadata_" + k, typeof(short)); break; 228 | case "int": dt.Columns.Add("metadata_" + k, typeof(int)); break; 229 | case "long": dt.Columns.Add("metadata_" + k, typeof(long)); break; 230 | case "decimal": dt.Columns.Add("metadata_" + k, typeof(decimal)); break; 231 | case "float": dt.Columns.Add("metadata_" + k, typeof(float)); break; 232 | case "double": dt.Columns.Add("metadata_" + k, typeof(double)); break; 233 | case "bool": dt.Columns.Add("metadata_" + k, typeof(bool)); break; 234 | } 235 | } 236 | foreach (var k in blob.Metadata.Keys){ 237 | var metadata = lstMetadata.FirstOrDefault(m => m.Name == k); 238 | if (metadata == null){ 239 | lstRowData.Add(blob.Metadata[k]); 240 | continue; 241 | } 242 | switch (metadata.Type.ToLower()){ 243 | case "datetime": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(DateTime.ParseExact(blob.Metadata[k], metadata.Format, null))); break; 244 | case "datetimeoffset": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(DateTimeOffset.ParseExact(blob.Metadata[k], metadata.Format, null))); break; 245 | case "short": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(Convert.ToInt16(blob.Metadata[k]))); break; 246 | case "int": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(Convert.ToInt32(blob.Metadata[k]))); break; 247 | case "long": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(Convert.ToInt64(blob.Metadata[k]))); break; 248 | case "decimal": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(Convert.ToDecimal(blob.Metadata[k]))); break; 249 | case "float": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(Convert.ToSingle(blob.Metadata[k]))); break; 250 | case "double": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(Convert.ToDouble(blob.Metadata[k]))); break; 251 | case "bool": lstRowData.Add(string.IsNullOrEmpty(blob.Metadata[k]) ? null : new Nullable(Convert.ToBoolean(blob.Metadata[k]))); break; 252 | } 253 | } 254 | } 255 | dt.Rows.Add(lstRowData.ToArray()); 256 | } 257 | if (!string.IsNullOrEmpty(where)||!string.IsNullOrEmpty(sort)){ 258 | var lstRows = dt.Select(where, sort); 259 | var lstRowsToRemove = dt.Rows.Cast().Where(r => !lstRows.Contains(r)).ToList(); 260 | foreach (var r in lstRowsToRemove) 261 | dt.Rows.Remove(r); 262 | } 263 | lock (Program.Shared.LockDataTables){ 264 | Program.Shared.DataTables[to+";"+Program.Shared.GetSequence()] = dt; 265 | } 266 | Program.Shared.WriteLogLine("List blobs completed: {0} - {1} blob(s) found{2}", blobContainer == null ? blobClient.BaseUri.ToString() : blobContainer.Uri.ToString(), lst.Length, string.IsNullOrEmpty(where) ? null : " and "+dt.Rows.Count+" match(es) the \"where\" condition"); 267 | } 268 | 269 | // listcontainers 270 | void ListContainers(string id, XmlNode n) 271 | { 272 | var to = Util.GetStr(n, "to"); 273 | var prefix = Program.Shared.ReplaceTags(Util.GetStr(n, "prefix")); 274 | var listingDetails = Util.GetEnumValue(Util.GetStr(n, "listingDetails", "none"), ContainerListingDetails.None); 275 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 276 | var sort = Program.Shared.ReplaceTags(Util.GetStr(n, "sort")); 277 | var regex = Program.Shared.ReplaceTags(Util.GetStr(n, "regex")); 278 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 279 | 280 | var dt = new DataTable(); 281 | dt.Columns.Add("name", typeof(string)); 282 | dt.Columns.Add("public_access", typeof(string)); 283 | dt.Columns.Add("etag", typeof(string)); 284 | dt.Columns.Add("last_modified", typeof(DateTimeOffset)); 285 | dt.Columns.Add("uri", typeof(string)); 286 | 287 | var lst = blobClient.ListContainers(prefix, listingDetails); 288 | var totalCount = lst.Count(); 289 | if (!string.IsNullOrEmpty(regex)) 290 | lst = lst.Where(c => Regex.IsMatch(c.Name, regex)).ToArray(); 291 | foreach (var c in lst) 292 | dt.Rows.Add(c.Name, c.Properties?.PublicAccess, c.Properties?.ETag, c.Properties?.LastModified, c.Uri.ToString()); 293 | if (!string.IsNullOrEmpty(where) || !string.IsNullOrEmpty(sort)) 294 | { 295 | var lstRows = dt.Select(where, sort); 296 | var dt2 = dt.Clone(); 297 | foreach (var r in lstRows) 298 | dt2.Rows.Add(r.ItemArray); 299 | dt = dt2; 300 | } 301 | 302 | lock (Program.Shared.LockDataTables) 303 | Program.Shared.DataTables[to + ";" + Program.Shared.GetSequence()] = dt; 304 | Program.Shared.WriteLogLine("List containers completed: {0} - {1} containers(s) found{2}", blobClient.BaseUri.ToString(), totalCount, string.IsNullOrEmpty(where) && string.IsNullOrEmpty(regex) ? null : " and " + dt.Rows.Count + " matched the conditions"); 305 | } 306 | 307 | // copy 308 | void Copy(string id, XmlNode n){ 309 | var blob = Program.Shared.ReplaceTags(Util.GetStr(n, "blob")); 310 | var toBlob = Program.Shared.ReplaceTags(Util.GetStr(n, "toBlob")); 311 | var toStorage = Util.GetStr(n, "toStorage"); 312 | var time = Util.GetStr(n, "sleep", "0"); 313 | var timeSpan = Util.GetTimeSpan(time); 314 | var log = Util.GetStr(Node, "log", "true") == "true"; 315 | var blobClient1 = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 316 | var blobContainer1 = blobClient1.GetContainerReference(blob.Remove(blob.IndexOf("/"))); 317 | var blob1 = blobContainer1.GetBlockBlobReference(blob.Substring(blob.IndexOf("/") + 1)); 318 | if (!blob1.Exists()) 319 | return; 320 | var blobClient2 = CloudStorageAccount.Parse(Program.Shared.Storages[toStorage]).CreateCloudBlobClient(); 321 | var blobContainer2 = blobClient2.GetContainerReference(toBlob.Remove(toBlob.IndexOf("/"))); 322 | if (blobContainer2.CreateIfNotExists()) 323 | blobContainer2.SetPermissions(new BlobContainerPermissions() { PublicAccess = BlobContainerPublicAccessType.Off }); 324 | var blob2 = blobContainer2.GetBlockBlobReference(toBlob.Substring(toBlob.IndexOf("/") + 1)); 325 | var exists = blob2.Exists(); 326 | if (exists && blob1.Properties != null && blob2.Properties != null && blob2.Properties.Length == blob1.Properties.Length && blob2.Properties.ContentMD5 == blob1.Properties.ContentMD5) 327 | return; 328 | var sig = blob1.GetSharedAccessSignature(new SharedAccessBlobPolicy() { SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(30), Permissions = SharedAccessBlobPermissions.Read }); 329 | blob2.StartCopy(new Uri(blob1.Uri.AbsoluteUri + sig)); 330 | if (log) 331 | Program.Shared.WriteLogLine("Copy blob: {0} -> {1}", blob1.Uri.ToString(), blob2.Uri.ToString()); 332 | if (timeSpan != TimeSpan.Zero) 333 | System.Threading.Thread.Sleep(timeSpan); 334 | } 335 | 336 | // set metadata 337 | void SetMetadata(string id, XmlNode n){ 338 | var fromBlob = Program.Shared.ReplaceTags(Util.GetStr(n, "fromBlob")); 339 | var clear = Util.GetStr(n, "clear", "false").ToLower() == "true"; 340 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 341 | var blobContainer = blobClient.GetContainerReference(fromBlob.Remove(fromBlob.IndexOf("/"))); 342 | var blobRef = blobContainer.GetBlockBlobReference(fromBlob.Substring(fromBlob.IndexOf("/") + 1)); 343 | if (!blobRef.Exists()) 344 | return; 345 | var lstMetadata = Util.GetChildNodes(n, "Field").Select(n2 => new { Name = Util.GetStr(n2, "name"), Value = Extensions.OnlyChars(Extensions.RemoveAccents(Program.Shared.ReplaceTags(n2.InnerXml)), "0123456789abcdefghijklmnopqrstuvxwyzABCDEFGHIJKLMNOPQRSTUVXWYZ_- ().:/", "_")}).Where(n2 => !string.IsNullOrEmpty(n2.Value)).ToDictionary(n2 => n2.Name, n2 => n2.Value); 346 | if (!clear) 347 | blobRef.FetchAttributes(); 348 | foreach (var k in lstMetadata.Keys) 349 | blobRef.Metadata[k] = lstMetadata[k]; 350 | blobRef.SetMetadata(); 351 | //WriteLogLine("Metadata was set for blob: {0}", blobRef.Uri.ToString()); 352 | } 353 | 354 | // snapshot 355 | void Snapshot(string id, XmlNode n){ 356 | var blob = Program.Shared.ReplaceTags(Util.GetStr(n, "blob")); 357 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 358 | var blobContainer = blobClient.GetContainerReference(blob.Remove(blob.IndexOf("/"))); 359 | var blobRef = blobContainer.GetBlockBlobReference(blob.Substring(blob.IndexOf("/") + 1)); 360 | var lstMetadata = Util.GetChildNodes(n, "Metadata").Select(n2 => new { Name = Util.GetStr(n2, "name"), Value = Extensions.OnlyChars(Extensions.RemoveAccents(Program.Shared.ReplaceTags(n2.InnerXml)), "0123456789abcdefghijklmnopqrstuvxwyzABCDEFGHIJKLMNOPQRSTUVXWYZ_- ().:/", "_")}).Where(n2 => !string.IsNullOrEmpty(n2.Value)).ToDictionary(n2 => n2.Name, n2 => n2.Value); 361 | if (!blobRef.Exists()) 362 | return; 363 | var snapshot = blobRef.CreateSnapshot(lstMetadata.Count == 0 ? null : lstMetadata); 364 | Program.Shared.WriteLogLine("Snapshot time: {0:yyyy-MM-dd HH:mm:ss.fffffff zzz}", snapshot.SnapshotTime); 365 | //var snapshot = blobRef.Snapshot(lstMetadata.Count == 0 ? null : lstMetadata); 366 | var snapshotTimeToVar = Program.Shared.ReplaceTags(Util.GetStr(n, "snapshotTimeToVar")); 367 | var snapshotTimeToRow = Program.Shared.ReplaceTags(Util.GetStr(n, "snapshotTimeToRow")); 368 | if (!string.IsNullOrEmpty(snapshotTimeToVar)) 369 | lock (Program.Shared.LockVariables) 370 | Program.Shared.Variables[snapshotTimeToVar + ";" + Program.Shared.GetSequence()] = snapshot.SnapshotTime; 371 | if (!string.IsNullOrEmpty(snapshotTimeToRow)){ 372 | var lstRows = Program.Shared.GetCurrentRows(Program.Shared.ThreadID()); 373 | var index = snapshotTimeToRow.IndexOf("."); 374 | if (index == -1) 375 | return; 376 | var table = snapshotTimeToRow.Remove(index); 377 | var column = snapshotTimeToRow.Substring(index+1); 378 | var dt = Program.Shared.GetDataTable(Program.Shared.ThreadID(), table); 379 | lock (Program.Shared.LockDataTables){ 380 | if (!dt.Columns.Contains(column)) 381 | dt.Columns.Add(column, typeof(DateTimeOffset)); 382 | lstRows[table][column] = snapshot.SnapshotTime; 383 | } 384 | } 385 | } 386 | 387 | // delete multiple blobs 388 | void DeleteMultipleBlobs(string id, XmlNode n){ 389 | var regex = Program.Shared.ReplaceTags(Util.GetStr(n, "regex")); 390 | var container = Program.Shared.ReplaceTags(Util.GetStr(n, "container")); 391 | var name = Program.Shared.ReplaceTags(Util.GetStr(n, "name")); 392 | var prefix = Util.GetStr(n, "prefix"); 393 | var olderThan = Util.GetStr(n, "olderThan"); 394 | var limit = Util.GetDateTimeOffset(olderThan); 395 | var regexDateGroup = Util.GetStr(n, "regexDateGroup"); 396 | var regexDateFormat = Util.GetStr(n, "regexDateFormat"); 397 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 398 | var blobContainer = blobClient.GetContainerReference(container); 399 | var lstBlobs = string.IsNullOrEmpty(name) ? ((string.IsNullOrEmpty(container) ? blobClient.ListBlobs(prefix, true) : (blobContainer.Exists() ? blobContainer.ListBlobs(prefix, true) : new CloudBlob[0])).Where(b => b is CloudBlob).Cast().ToList()) : new List(){blobContainer.GetBlockBlobReference(name)}; 400 | if (!string.IsNullOrEmpty(regex)){ 401 | lstBlobs = lstBlobs.Where(item => { 402 | var m = Regex.Match(item.Uri.PathAndQuery, regex); 403 | if (string.IsNullOrEmpty(regexDateGroup) || string.IsNullOrEmpty(regexDateFormat) || m.Groups[regexDateGroup] == null || string.IsNullOrEmpty(m.Groups[regexDateGroup].Value)) 404 | return m.Success; 405 | return m.Success && DateTime.ParseExact(m.Groups[regexDateGroup].Value, regexDateFormat, null) < limit; 406 | }).ToList(); 407 | } 408 | Parallel.ForEach(lstBlobs, blob => { 409 | if(!string.IsNullOrEmpty(regex) && !string.IsNullOrEmpty(regexDateGroup) && !string.IsNullOrEmpty(regexDateFormat)){ 410 | if (blob.DeleteIfExists()) 411 | Program.Shared.WriteLogLine($"Blob deleted: {blob.Uri.ToString()}"); 412 | }else{ 413 | blob.FetchAttributes(); 414 | var modified = blob.Properties.LastModified == null ? DateTime.Now : blob.Properties.LastModified.Value; 415 | if (modified < limit) 416 | if (blob.DeleteIfExists()) 417 | Program.Shared.WriteLogLine($"Blob deleted: {blob.Uri.ToString()}"); 418 | } 419 | }); 420 | } 421 | 422 | // delete blob 423 | void DeleteBlob(string id, XmlNode n) 424 | { 425 | var container = Program.Shared.ReplaceTags(Util.GetStr(n, "container")); 426 | var blobName = Program.Shared.ReplaceTags(Util.GetStr(n, "name")); 427 | if (string.IsNullOrEmpty(container) || string.IsNullOrEmpty(blobName)) 428 | return; 429 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 430 | var blobContainer = blobClient.GetContainerReference(container); 431 | var blob = blobContainer.GetBlobReference(blobName); 432 | blob.DeleteIfExists(); 433 | } 434 | 435 | // delete snapshot 436 | void DeleteSnapshot(string id, XmlNode n){ 437 | var container = Program.Shared.ReplaceTags(Util.GetStr(n, "container")); 438 | var name = Program.Shared.ReplaceTags(Util.GetStr(n, "name")); 439 | var time = Util.ParseDateTime(Program.Shared.ReplaceTags(Util.GetStr(n, "time"))); 440 | if (container == null || name == null || time == null) 441 | return; 442 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 443 | var blobContainer = blobClient.GetContainerReference(container); 444 | var blob = blobContainer.GetBlockBlobReference(name, new DateTimeOffset(time.Value)); 445 | if (blob.IsSnapshot && blob.Exists()) 446 | blob.Delete(); 447 | } 448 | 449 | // delete containers 450 | void DeleteContainers(string id, XmlNode n){ 451 | var prefix = Util.GetStr(n, "prefix"); 452 | var regex = Program.Shared.ReplaceTags(Util.GetStr(n, "regex")); 453 | var name = Program.Shared.ReplaceTags(Util.GetStr(n, "name")); 454 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[id]).CreateCloudBlobClient(); 455 | var lstContainers = new List(); 456 | if (string.IsNullOrEmpty(name)) 457 | lstContainers.AddRange(blobClient.ListContainers(prefix)); 458 | else 459 | lstContainers.Add(blobClient.GetContainerReference(name)); 460 | if (!string.IsNullOrEmpty(regex)) 461 | lstContainers.Remove(c => Regex.IsMatch(c.Name, regex)); 462 | foreach (var c in lstContainers) 463 | if (c.Exists()) 464 | c.Delete(); 465 | } 466 | } 467 | } 468 | -------------------------------------------------------------------------------- /src/Functions/TryFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Xml; 9 | 10 | namespace DoIt.Functions 11 | { 12 | internal class TryFunctions : FunctionsNodeHandlerBase 13 | { 14 | public TryFunctions(XmlNode node):base(node){} 15 | 16 | public override bool Execute() 17 | { 18 | if (Node == null) 19 | return false; 20 | var retry = Convert.ToInt32(Util.GetStr(Node, "retry", "1")); 21 | var sleep = Util.GetStr(Node, "sleep", "1 second"); 22 | var lstExceptions = Util.GetChildNodes(Util.GetChildNode(Node, "Catch"), "Exception"); 23 | if (lstExceptions == null){ 24 | var n = Program.Shared.Document.CreateElement("Exception"); 25 | n.SetAttribute("type", "System.Exception"); 26 | n.SetAttribute("withMessage", ""); 27 | lstExceptions = new XmlNode[]{n}; 28 | } 29 | var lst = lstExceptions.Select(n => new {Type=Util.GetStr(n, "type"), WithMessage=Util.GetStr(n, "withMessage")}).ToArray(); 30 | var success = false; 31 | for(var x=0; x item.Type.ToLower() == ex.GetType().FullName.ToLower() && (string.IsNullOrEmpty(item.WithMessage) || string.IsNullOrEmpty(ex.Message) || ex.Message.ToLower().Contains(item.WithMessage.ToLower())))){ 37 | Program.Shared.WriteLogLine("Try command has caught exception {0} - Exception Message: {1} (Retry {2}; Sleep {3}ms)", ex.GetType().FullName, ex.Message, x + 1, sleep); 38 | Thread.Sleep(Util.GetTimeSpan(sleep)); 39 | } 40 | } 41 | Program.Shared.ExecuteCommands(success ? Util.GetChildNode(Node, "Success") : Util.GetChildNode(Node, "Fail")); 42 | return true; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Functions/ZipFunctions.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using Microsoft.WindowsAzure.Storage; 3 | using Microsoft.WindowsAzure.Storage.Blob; 4 | using Microsoft.WindowsAzure.Storage.RetryPolicies; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Data; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Xml; 13 | 14 | namespace DoIt.Functions 15 | { 16 | internal class ZipFunctions : FunctionsNodeHandlerBase 17 | { 18 | public ZipFunctions(XmlNode node):base(node){} 19 | 20 | public override bool Execute() 21 | { 22 | if (Node == null) 23 | return false; 24 | var path = Program.Shared.ReplaceTags(Util.GetStr(Node, "path")); 25 | var mode = Util.GetStr(Node, "mode", "write").ToLower(); 26 | var toVar = Util.GetStr(Node, "toVar"); 27 | if (!string.IsNullOrEmpty(toVar)) 28 | lock (Program.Shared.LockVariables) { Program.Shared.Variables[toVar + ";" + Program.Shared.GetSequence()] = path; } 29 | switch (mode){ 30 | case "read": ReadFile(path, Node); break; 31 | case "write": WriteFile(path, Node); break; 32 | } 33 | return true; 34 | } 35 | 36 | void ReadFile(string path, XmlNode node){ 37 | if (!File.Exists(path)) 38 | return; 39 | foreach (var n in Util.GetChildNodes(node, "Extract")){ 40 | var toFolder = Program.Shared.ReplaceTags(Util.GetStr(n, "toFolder")); 41 | var counter = 0; 42 | using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 43 | using (var zipStream = new ZipInputStream(fs)){ 44 | var entry = zipStream.GetNextEntry(); 45 | while (entry != null){ 46 | var file = Path.Combine(toFolder, entry.Name); 47 | var folder = Path.GetDirectoryName(file); 48 | if (!Directory.Exists(folder)) 49 | Directory.CreateDirectory(folder); 50 | using (var newFs = File.Create(file)) 51 | zipStream.CopyTo(newFs); 52 | entry = zipStream.GetNextEntry(); 53 | counter++; 54 | } 55 | } 56 | Program.Shared.WriteLogLine("Zip file extracted to folder {0} (Files: {1})", toFolder, counter); 57 | } 58 | } 59 | 60 | void WriteFile(string path, XmlNode node){ 61 | if (File.Exists(path)) 62 | File.Delete(path); 63 | Program.Shared.WriteLogLine("Creating zip file: {0}", path); 64 | using (var zipStream = new ZipOutputStream(File.Create(path))){ 65 | 66 | // folder 67 | //foreach (var n in GetChildNodes(node, "Folder")){ 68 | // var name = ReplaceTags(GetStr(n, "name")); 69 | // var toFile = ReplaceTags(GetStr(n, "toFile")); 70 | // var toFolder = ReplaceTags(GetStr(n, "toFolder")); 71 | // var pattern = GetStr(n, "pattern") ?? "*.*"; 72 | // var deleteSource = GetStr(n, "deleteSource", "false").ToLower() == "true"; 73 | // var multiFiles = GetStr(n, "multiFiles") == "true"; 74 | // var lstZipFiles = ZipFolderAs(name, toFile, toFolder, multiFiles, pattern, deleteSource); 75 | // foreach (var zip in lstZipFiles){ 76 | // ZipFiles.Add(zip); 77 | // WriteLogLine(String.Format("Finished Zipping Folder (Folder: {0}; ZipFile: {1}; Size: {2}).", name, zip, GetFileSize(new FileInfo(zip).Length))); 78 | // } 79 | //} 80 | 81 | var lstNodes = Util.GetChildNodes(node, "AddFile", "AddBlob"); 82 | foreach (var n in lstNodes) 83 | switch (n.Name.ToLower()){ 84 | case "addfile": AddFile(zipStream, n); break; 85 | case "addblob": AddBlob(zipStream, n); break; 86 | } 87 | 88 | zipStream.Finish(); 89 | } 90 | Program.Shared.WriteLogLine("Finished creating zip file {0} (Size: {1})", path, Util.GetFileSize(new FileInfo(path).Length)); 91 | } 92 | 93 | string GetZipEntry(XmlNode n, Dictionary lstCurrentRows, string defaultValue){ 94 | var zipEntry = Program.Shared.ReplaceTags(Util.GetStr(n, "zipEntry"), lstCurrentRows); 95 | var zipFolder = Program.Shared.ReplaceTags(Util.GetStr(n, "zipFolder"), lstCurrentRows); 96 | var zipFilename = Program.Shared.ReplaceTags(Util.GetStr(n, "zipFilename"), lstCurrentRows); 97 | var dirSeparators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; 98 | if (!string.IsNullOrEmpty(zipEntry)) 99 | zipEntry = zipEntry.Split(dirSeparators, StringSplitOptions.RemoveEmptyEntries).Select(s => s.OnlyPathChars()).Concat(s => s, "/"); 100 | else if (!string.IsNullOrEmpty(zipFilename)){ 101 | if(!string.IsNullOrEmpty(zipFolder)) 102 | zipFolder = zipFolder.Split(dirSeparators, StringSplitOptions.RemoveEmptyEntries).Select(s => s.OnlyPathChars()).Concat(s => s, "/"); 103 | zipEntry = string.IsNullOrEmpty(zipFolder) ? zipFilename : zipFolder+"/"+zipFilename.OnlyPathChars(); 104 | } 105 | if (string.IsNullOrEmpty(zipEntry)) 106 | zipEntry = defaultValue; 107 | if (string.IsNullOrEmpty(zipEntry)) 108 | return null; 109 | return string.Join("/", zipEntry.Split(dirSeparators, StringSplitOptions.RemoveEmptyEntries).Select(str => str.OnlyPathChars())); 110 | } 111 | 112 | void AddFile(ZipOutputStream zipStream, XmlNode n){ 113 | var forEach = Util.GetStr(n, "forEach"); 114 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 115 | var dt = string.IsNullOrEmpty(forEach) ? null : Program.Shared.GetDataTable(Program.Shared.ThreadID(), forEach); 116 | var lstRows = dt==null ? new DataRow[0] : string.IsNullOrEmpty(where) ? dt.Rows.Cast().ToArray() : dt.Select(where); 117 | var rowsCount = dt == null ? 1 : lstRows.Length; 118 | for(var x=0; x(){{forEach,lstRows[x]}}; 120 | var name = Program.Shared.ReplaceTags(Util.GetStr(n, "name"), lstCurrentRows); 121 | var deleteSource = Util.GetStr(n, "deleteSource", "false").ToLower() == "true"; 122 | var zipEntry = GetZipEntry(n, lstCurrentRows, Path.GetFileName(name)); 123 | var fi = new FileInfo(name); 124 | zipStream.PutNextEntry(new ZipEntry(zipEntry){DateTime=fi.LastWriteTime, Size=fi.Length}); 125 | using (var fs = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 126 | fs.CopyTo(zipStream); 127 | if (deleteSource) 128 | File.Delete(name); 129 | Program.Shared.WriteLogLine(String.Format("Add File to Zip (File: {0}; File Size: {1}).", name, Util.GetFileSize(fi.Length))); 130 | } 131 | } 132 | 133 | void AddBlob(ZipOutputStream zipStream, XmlNode n){ 134 | var fromStorage = Util.GetStr(n, "fromStorage"); 135 | var forEach = Util.GetStr(n, "forEach"); 136 | var where = Program.Shared.ReplaceTags(Util.GetStr(n, "where")); 137 | var timeout = Util.GetStr(n, "timeout", "0"); 138 | var retryTime = Util.GetStr(n, "retryTime", "30s"); 139 | var retryAttempts = Util.GetStr(n, "retryAttempts", "0"); 140 | var options = new BlobRequestOptions() { DisableContentMD5Validation = true }; 141 | if (timeout != "0") 142 | options.MaximumExecutionTime = Util.GetTimeSpan(timeout); 143 | if (retryAttempts != "0") 144 | options.RetryPolicy = new LinearRetry(Util.GetTimeSpan(retryTime), Convert.ToInt32(retryAttempts)); 145 | 146 | var dt = string.IsNullOrEmpty(forEach) ? null : Program.Shared.GetDataTable(Program.Shared.ThreadID(), forEach); 147 | var lstRows = dt==null ? new DataRow[0] : string.IsNullOrEmpty(where) ? dt.Rows.Cast().ToArray() : dt.Select(where); 148 | var rowsCount = dt == null ? 1 : lstRows.Length; 149 | for(var x=0; x(){{forEach,lstRows[x]}}; 151 | var snapshotTime = Util.ParseDateTimeOffset(Program.Shared.ReplaceTags(Util.GetStr(n, "snapshotTime"), lstCurrentRows)); 152 | var blobClient = CloudStorageAccount.Parse(Program.Shared.Storages[fromStorage]).CreateCloudBlobClient(); 153 | var blobName = Program.Shared.ReplaceTags(Util.GetStr(n, "name"), lstCurrentRows); 154 | var blobContainer = blobClient.GetContainerReference(blobName.Remove(blobName.IndexOf("/"))); 155 | var blob = snapshotTime == null ? 156 | blobContainer.GetBlockBlobReference(blobName.Substring(blobName.IndexOf("/") + 1)): 157 | blobContainer.GetBlockBlobReference(blobName.Substring(blobName.IndexOf("/") + 1), snapshotTime.Value); 158 | var dateTime = Util.ParseDateTimeOffset(Program.Shared.ReplaceTags(Util.GetStr(n, "dateTime"), lstCurrentRows)); 159 | var size = Convert.ToInt64(Program.Shared.ReplaceTags(Util.GetStr(n, "size", "0"), lstCurrentRows)); 160 | var zipEntry = GetZipEntry(n, lstCurrentRows, blob.Name); 161 | if (!blob.Exists()) 162 | continue; 163 | if (size == 0){ 164 | blob.FetchAttributes(); 165 | dateTime = blob.Properties.LastModified.Value.DateTime; 166 | size = blob.Properties.Length; 167 | } 168 | zipStream.PutNextEntry(new ZipEntry(zipEntry){DateTime=(dateTime??DateTimeOffset.Now).DateTime, Size=size}); 169 | Program.Shared.WriteLogLine(String.Format("Add Blob to Zip ({0}/{1}; Blob: {2}; Blob Size: {3}).", x + 1, rowsCount, blob.Uri.ToString(), Util.GetFileSize(size))); 170 | blob.DownloadToStream(zipStream, null, options); 171 | } 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.Mail; 8 | using System.Reflection; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Xml; 12 | using DoIt.Functions; 13 | using System.Diagnostics; 14 | using System.Security.Principal; 15 | 16 | namespace DoIt 17 | { 18 | class Program 19 | { 20 | static Program() 21 | { 22 | Thread.CurrentThread.Name = "."+Shared.ThreadID(); 23 | } 24 | 25 | static void Main(string[] args) 26 | { 27 | var configFile = Util.GetArg(args, "config") ?? Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DoIt.config.xml"); 28 | if (!File.Exists(configFile)) 29 | return; 30 | 31 | // load xml 32 | var xml = Shared.Document = new XmlDocument(); 33 | xml.PreserveWhitespace = true; 34 | xml.Load(configFile); 35 | var configNode = Util.GetChildNode(xml, "Configuration"); 36 | if (configNode == null){ 37 | Console.WriteLine("Configuration node not found."); 38 | return; 39 | } 40 | 41 | // settings 42 | var cryptKey = Util.GetArg(args, "cryptKey"); 43 | LoadSettings(configNode, cryptKey); 44 | 45 | var version = Assembly.GetExecutingAssembly().GetName().Version; 46 | var user = WindowsIdentity.GetCurrent(); 47 | var process = Process.GetCurrentProcess(); 48 | var encryptionKey = Util.GetArg(args, "encryptionKey"); 49 | var decryptionKey = Util.GetArg(args, "decryptionKey"); 50 | if (!string.IsNullOrEmpty(encryptionKey) || !string.IsNullOrEmpty(decryptionKey)){ 51 | LogStart(args, process, version, user); 52 | var lstConnStrNode = xml.SelectNodes("Configuration/Settings/ConnectionStrings"); 53 | if (lstConnStrNode != null) 54 | foreach(XmlNode connStrNode in lstConnStrNode){ 55 | foreach (XmlElement n in Util.GetChildNodes(connStrNode, "Database", "Storage", "MailServer", "SharedAccessSignature")) 56 | if (!string.IsNullOrEmpty(n.InnerXml)){ 57 | if (!string.IsNullOrEmpty(encryptionKey) && Util.GetStr(n, "encrypted", "false").ToLower() != "true"){ 58 | n.InnerXml = System.Security.SecurityElement.Escape(n.InnerXml.Encrypt(encryptionKey)); 59 | n.SetAttribute("encrypted", "true"); 60 | } 61 | if (!string.IsNullOrEmpty(decryptionKey) && Util.GetStr(n, "encrypted", "false").ToLower() == "true"){ 62 | n.InnerXml = n.InnerXml.Decrypt(decryptionKey); 63 | n.RemoveAttribute("encrypted"); 64 | } 65 | } 66 | } 67 | if (!string.IsNullOrEmpty(encryptionKey)){ 68 | Shared.WriteLogLine("Configuration file was encrypted."); 69 | Console.WriteLine("Configuration file was encrypted."); 70 | } 71 | if (!string.IsNullOrEmpty(decryptionKey)){ 72 | Shared.WriteLogLine("Configuration file was decrypted."); 73 | Console.WriteLine("Configuration file was decrypted."); 74 | } 75 | xml.Save(configFile); 76 | LogEnd(args, process, version, user); 77 | return; 78 | } 79 | 80 | // execute 81 | LogStart(args, process, version, user); 82 | Shared.ExecuteCommands(Util.GetChildNode(configNode, "Execute")); 83 | System.Threading.Tasks.Task.WaitAll(Shared.StorageUploadTasks.ToArray()); 84 | LogEnd(args, process, version, user); 85 | } 86 | 87 | static void LogStart(string[] args, Process process, Version version, WindowsIdentity user) 88 | { 89 | Shared.WriteLogLine("*******************"); 90 | Shared.WriteLogLine(String.Format("Application Started: \"{0}{1}\" v{2}{3}", process.ProcessName, args==null || args.Length==0 ? null : " " + args.Concat(arg => arg, " "), version.ToString(), user == null ? null : " (User: "+user.Name+")")); 91 | } 92 | 93 | static void LogEnd(string[] args, Process process, Version version, WindowsIdentity user) 94 | { 95 | Shared.WriteLogLine(String.Format("Application Finished: \"{0}\" v{1}{2}", process.ProcessName, version.ToString(), user == null ? null : " (User: " + user.Name + ")")); 96 | Shared.WriteLogLine(); 97 | Shared.WriteLogLine(); 98 | } 99 | 100 | static void LoadSettings(XmlNode configNode, string cryptKey) 101 | { 102 | var settingsNode = Util.GetChildNode(configNode, "Settings"); 103 | if (settingsNode == null) 104 | return; 105 | 106 | // settings: logFile 107 | var logFile = Util.GetChildNode(settingsNode, "LogFile"); 108 | if (logFile == null) 109 | Shared.IsLogEnabled = false; 110 | else { 111 | Shared.LogFile = Shared.ReplaceTags(logFile.InnerText); 112 | var toVar = Util.GetStr(logFile, "toVar"); 113 | if (!string.IsNullOrEmpty(toVar)) 114 | lock (Shared.LockVariables) { Shared.Variables[toVar + ";" + Shared.GetSequence()] = Shared.LogFile; } 115 | if (!Directory.Exists(Path.GetDirectoryName(Shared.LogFile))) 116 | Directory.CreateDirectory(Path.GetDirectoryName(Shared.LogFile)); 117 | } 118 | 119 | // settings: connectionStrings 120 | var connectionStrings = Util.GetChildNode(settingsNode, "ConnectionStrings"); 121 | if (connectionStrings != null) 122 | foreach (XmlNode n in Util.GetChildNodes(connectionStrings, "Database", "Storage", "MailServer", "SharedAccessSignature")){ 123 | switch (n.Name.ToLower()){ 124 | case "database": Shared.Databases[Util.GetStr(n, "id", "1")] = string.IsNullOrEmpty(cryptKey) || string.IsNullOrEmpty(n.InnerText) || Util.GetStr(n, "encrypted", "false").ToLower()!="true" ? n.InnerText : new System.Security.SecurityElement("element", n.InnerXml.Decrypt(cryptKey)).Text; break; 125 | case "storage": Shared.Storages[Util.GetStr(n, "id", "1")] = string.IsNullOrEmpty(cryptKey) || string.IsNullOrEmpty(n.InnerText) || Util.GetStr(n, "encrypted", "false").ToLower()!="true" ? n.InnerText : new System.Security.SecurityElement("element", n.InnerXml.Decrypt(cryptKey)).Text; break; 126 | case "mailserver": Shared.MailServers[Util.GetStr(n, "id", "1")] = string.IsNullOrEmpty(cryptKey) || string.IsNullOrEmpty(n.InnerText) || Util.GetStr(n, "encrypted", "false").ToLower()!="true" ? n.InnerText : new System.Security.SecurityElement("element", n.InnerXml.Decrypt(cryptKey)).Text; break; 127 | case "sharedaccesssignature": Shared.SharedAccessSignatures[Util.GetStr(n, "id", "1")] = string.IsNullOrEmpty(cryptKey) || string.IsNullOrEmpty(n.InnerText) || Util.GetStr(n, "encrypted", "false").ToLower()!="true" ? n.InnerText : new System.Security.SecurityElement("element", n.InnerXml.Decrypt(cryptKey)).Text; break; 128 | } 129 | } 130 | 131 | 132 | // settings: exceptions 133 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 134 | var exceptions = Util.GetChildNode(settingsNode, "Exceptions"); 135 | if (exceptions != null){ 136 | var smtp1 = Util.GetStr(exceptions, "smtp"); 137 | var smtp2 = Util.GetStr(exceptions, "mailServer"); 138 | if (!string.IsNullOrEmpty(smtp1)) 139 | Shared.Smtp = smtp1; 140 | else if (!string.IsNullOrEmpty(smtp2) && Shared.MailServers.ContainsKey(smtp2)) 141 | Shared.Smtp = Shared.MailServers[smtp2]; 142 | Shared.MailSubject = Util.GetStr(exceptions, "mailSubject"); 143 | Shared.AttachLogFile = Util.GetStr(exceptions, "attachLogFile") == "true"; 144 | foreach (XmlNode n in exceptions.SelectNodes("Mail")) 145 | Shared.Emails.Add(n.InnerText); 146 | } 147 | } 148 | 149 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 150 | { 151 | WriteExceptionData(e.ExceptionObject as Exception); 152 | } 153 | 154 | static void WriteExceptionData(Exception ex) 155 | { 156 | var str = String.Format("Exception: {0}", ex.GetFullMessage(true)); 157 | Console.WriteLine(str); 158 | Shared.WriteLogLine(str); 159 | 160 | if (String.IsNullOrEmpty(Shared.Smtp) || Shared.Emails == null || Shared.Emails.Count == 0) 161 | return; 162 | var mail = new MailMessage(); 163 | mail.From = new MailAddress(Util.GetConfigData(Shared.Smtp, "from")); 164 | foreach (var m in Shared.Emails) 165 | mail.To.Add(new MailAddress(m)); 166 | mail.Subject = string.IsNullOrEmpty(Shared.MailSubject) ? "DoIt: " + ex.Message : Shared.MailSubject; 167 | mail.Body = str; 168 | var zipLogFile = null as String; 169 | if (Shared.AttachLogFile && File.Exists(Shared.LogFile)){ 170 | zipLogFile = Util.GetFileToSend(Shared.LogFile, true); 171 | mail.Attachments.Add(new Attachment(zipLogFile)); 172 | } 173 | var smtp = new SmtpClient(Util.GetConfigData(Shared.Smtp,"host"), Convert.ToInt32(Util.GetConfigData(Shared.Smtp,"port",false,"25"))); 174 | smtp.EnableSsl = Util.GetConfigData(Shared.Smtp, "ssl") == "true"; 175 | smtp.Credentials = new NetworkCredential(Util.GetConfigData(Shared.Smtp, "user"), Util.GetConfigData(Shared.Smtp, "pass")); 176 | smtp.Send(mail); 177 | if (!String.IsNullOrEmpty(zipLogFile) && File.Exists(zipLogFile)) 178 | File.Delete(zipLogFile); 179 | Shared.WriteLogLine(String.Format("Exception Mail Sent To: {0}", Shared.Emails.Concat(m => m))); 180 | } 181 | 182 | internal static class Shared 183 | { 184 | public static String LogFile { get; set; } 185 | public static string Smtp { get; set; } 186 | public static string MailSubject { get; set; } 187 | public static bool AttachLogFile { get; set; } 188 | public static Dictionary Storages { get; set; } 189 | public static Dictionary Databases { get; set; } 190 | public static Dictionary MailServers { get; set; } 191 | public static Dictionary SharedAccessSignatures { get; set; } 192 | public static List DbBackups { get; set; } 193 | public static List ZipFiles { get; set; } 194 | public static List Emails { get; set; } 195 | public static Dictionary DataTables { get; set; } 196 | public static Dictionary CurrentRows { get; set; } 197 | public static Dictionary Variables { get; set; } 198 | public static List StorageUploadTasks { get; set; } 199 | public static int MainThreadID { get; set; } 200 | public static object LockDataTables { get; set; } 201 | public static object LockCurrentRows { get; set; } 202 | public static object LockVariables { get; set; } 203 | public static object LockSequence { get; set; } 204 | public static List ThreadSequence { get; set; } 205 | public static bool IsLogEnabled { get; set; } 206 | public static XmlDocument Document { get; set; } 207 | 208 | static Shared() 209 | { 210 | Emails = new List(); 211 | Storages = new Dictionary(); 212 | Databases = new Dictionary(); 213 | MailServers = new Dictionary(); 214 | SharedAccessSignatures = new Dictionary(); 215 | DbBackups = new List(); 216 | ZipFiles = new List(); 217 | DataTables = new Dictionary(); 218 | CurrentRows = new Dictionary(); 219 | Variables = new Dictionary(); 220 | StorageUploadTasks = new List(); 221 | LockDataTables = new object(); 222 | LockCurrentRows = new object(); 223 | LockVariables = new object(); 224 | LockSequence = new object(); 225 | MainThreadID = Shared.ThreadID(); 226 | ThreadSequence = new List(){Thread.CurrentThread.Name}; 227 | IsLogEnabled = true; 228 | } 229 | 230 | public static bool ExecuteCommands(XmlNode node) 231 | { 232 | if (node == null) 233 | return false; 234 | foreach (XmlNode subNode in node.ChildNodes){ 235 | if (subNode.Name == "#comment" || subNode.Name == "#whitespace") 236 | continue; 237 | switch (subNode.Name.ToLower()){ 238 | case "database": new DatabaseFunctions(subNode).Execute(); break; 239 | case "zip": new ZipFunctions(subNode).Execute(); break; 240 | case "process": new ProcessFunctions(subNode).Execute(); break; 241 | case "sql": new SqlFunctions(subNode).Execute(); break; 242 | case "mail": new MailFunctions(subNode).Execute(); break; 243 | case "condition": if (new ConditionFunctions(subNode).Execute()) return true; break; 244 | case "setvalue": new SetValueFunctions(subNode).Execute(); break; 245 | case "datatable": new DataTableFunctions(subNode).Execute(); break; 246 | case "foreach": new ForEachFunctions(subNode).Execute(); break; 247 | case "csv": new CsvFunctions(subNode).Execute(); break; 248 | case "log": new LogFunctions(subNode).Execute(); break; 249 | case "storage": new StorageFunctions(subNode).Execute(); break; 250 | case "localdisk": new LocalDiskFunctions(subNode).Execute(); break; 251 | case "sleep": new SleepFunctions(subNode).Execute(); break; 252 | case "try": new TryFunctions(subNode).Execute(); break; 253 | case "exception": new ExceptionFunctions(subNode).Execute(); break; 254 | case "http": new HttpFunctions(subNode).Execute(); break; 255 | case "ftp": new FtpFunctions(subNode).Execute(); break; 256 | case "stop": return true; 257 | } 258 | } 259 | return false; 260 | } 261 | 262 | public static void WriteLogLine() 263 | { 264 | WriteLogLine(false, null, null); 265 | } 266 | 267 | public static void WriteLogLine(String line = null, params object[] args) 268 | { 269 | WriteLogLine(true, line, args); 270 | } 271 | 272 | public static void WriteLogLine(bool addDateTimeInfo = true, String line = null, params object[] args) 273 | { 274 | if (!IsLogEnabled) 275 | return; 276 | using (var fs = new FileStream(LogFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)) 277 | using (var sw = new StreamWriter(fs, Encoding.Default)) { 278 | if (addDateTimeInfo && !string.IsNullOrWhiteSpace(line)) 279 | sw.Write(string.Format("[{0:yyyy-MM-dd HH:mm:ss.fff} - Thread {1}] ", DateTime.Now, ThreadID())); 280 | if (!string.IsNullOrEmpty(line) && args != null && args.Length > 0) 281 | line = string.Format(line, args); 282 | sw.WriteLine(line); 283 | sw.Flush(); 284 | } 285 | } 286 | 287 | public static void WriteLog(String line = null, params object[] args) 288 | { 289 | WriteLog(true, line, args); 290 | } 291 | 292 | public static void WriteLog(bool addDateTimeInfo = true, String line = null, params object[] args) 293 | { 294 | if (!IsLogEnabled) 295 | return; 296 | using (var fs = new FileStream(LogFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)) 297 | using (var sw = new StreamWriter(fs, Encoding.Default)){ 298 | if (addDateTimeInfo && !string.IsNullOrWhiteSpace(line)) 299 | sw.Write(string.Format("[{0:yyyy-MM-dd HH:mm:ss.fff} - Thread {1}] ", DateTime.Now, ThreadID())); 300 | if (!string.IsNullOrEmpty(line) && args != null && args.Length > 0) 301 | line = string.Format(line, args); 302 | sw.Write(line); 303 | sw.Flush(); 304 | } 305 | } 306 | 307 | public static String ReplaceTags(String str, Dictionary lstCurrentRows = null) 308 | { 309 | if (String.IsNullOrEmpty(str)) 310 | return null; 311 | str = str 312 | .Replace("%logFile%", LogFile) 313 | .Replace("%app%", Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory)) 314 | .Replace("%programdata%", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)) 315 | .Replace("%appdata%", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)) 316 | .Replace("%temp%", Path.GetDirectoryName(Path.GetTempPath())) 317 | .Replace("%windir%", Environment.GetFolderPath(Environment.SpecialFolder.Windows)) 318 | .Replace("%windows%", Environment.GetFolderPath(Environment.SpecialFolder.Windows)) 319 | .Replace("%system%", Environment.GetFolderPath(Environment.SpecialFolder.System)) 320 | .Replace("%programs%", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)) 321 | .Replace("%programfiles%", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)) 322 | .Replace("%documents%", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)) 323 | .Replace("%desktop%", Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); 324 | str = Util.GetStrData(str, "now", DateTime.Now); 325 | str = Util.GetStrData(str, "today", DateTime.Today); 326 | str = Util.GetStrData(str, "guid", Guid.NewGuid()); 327 | str = Util.GetStrData(str, "rand", null); 328 | for (var x=0;x, string> replaceRowsData = (string str2, Dictionary lstRows) => { 337 | foreach (var k in lstRows.Keys){ 338 | var r = lstRows[k]; 339 | var dt = GetDataTable(ThreadID(), k); 340 | var index = dt.Rows.IndexOf(r); 341 | str2 = Util.GetStrData(str2, k+".$RowsCount", dt.Rows.Count); 342 | str2 = Util.GetStrData(str2, k+".$RowIndex0", index); 343 | str2 = Util.GetStrData(str2, k+".$RowIndex1", index+1); 344 | foreach (DataColumn c in dt.Columns){ 345 | str2 = Util.GetStrData(str2, k+"."+c.ColumnName, r[c.ColumnName]); 346 | } 347 | } 348 | return str2; 349 | }; 350 | if (lstCurrentRows != null) 351 | str = replaceRowsData(str, GetCurrentRows(ThreadID(), lstCurrentRows)); 352 | str = replaceRowsData(str, GetCurrentRows(ThreadID())); 353 | var lstVariables = GetVariables(ThreadID()); 354 | foreach (var k in lstVariables.Keys){ 355 | var v = lstVariables[k]; 356 | if (v is Dictionary){ 357 | var lst = v as Dictionary; 358 | foreach (var k2 in lst.Keys) 359 | str = Util.GetStrData(str, k+"."+k2, lst[k2]); 360 | }else 361 | str = Util.GetStrData(str, k, lstVariables[k]); 362 | } 363 | return str; 364 | } 365 | 366 | public static string GetSequence() 367 | { 368 | return Thread.CurrentThread.Name; 369 | } 370 | 371 | public static int ThreadID() 372 | { 373 | return Thread.CurrentThread.ManagedThreadId; 374 | } 375 | 376 | public static Dictionary GetCurrentRows(int threadID, Dictionary lstRows = null) 377 | { 378 | if (lstRows == null) 379 | lstRows = CurrentRows; 380 | var lst = new Dictionary(); 381 | lock (LockCurrentRows){ 382 | var sequence = GetSequence(); 383 | foreach (var data in lstRows.Keys) 384 | if (!data.Contains(';')) 385 | lst[data] = lstRows[data]; 386 | else { 387 | var s = data.Substring(data.IndexOf(';')+1); 388 | if (sequence == s || sequence.Contains(s)) 389 | lst[data.Remove(data.LastIndexOf(';'))] = lstRows[data]; 390 | } 391 | } 392 | return lst; 393 | } 394 | 395 | public static DataRow GetCurrentRow(int threadID, string data, Dictionary lstRows = null) 396 | { 397 | var lst = GetCurrentRows(threadID, lstRows); 398 | return lst.ContainsKey(data) ? lst[data] : null; 399 | } 400 | 401 | public static Dictionary GetDataTables(int threadID) 402 | { 403 | var lst = new Dictionary(); 404 | lock (LockDataTables){ 405 | var sequence = GetSequence(); 406 | foreach (var data in DataTables.Keys) 407 | if (!data.Contains(';')) 408 | lst[data] = DataTables[data]; 409 | else { 410 | var s = data.Substring(data.IndexOf(';')+1); 411 | if (sequence == s || sequence.Contains(s)) 412 | lst[data.Remove(data.LastIndexOf(';'))] = DataTables[data]; 413 | } 414 | } 415 | return lst; 416 | } 417 | 418 | public static DataTable GetDataTable(string data) 419 | { 420 | return GetDataTable(ThreadID(), data); 421 | } 422 | 423 | public static DataTable GetDataTable(int threadID, string data) 424 | { 425 | var lst = GetDataTables(threadID); 426 | return lst.ContainsKey(data) ? lst[data] : null; 427 | } 428 | 429 | public static Dictionary GetVariables(int threadID) 430 | { 431 | var lst = new Dictionary(); 432 | lock (LockVariables){ 433 | var sequence = GetSequence(); 434 | foreach (var name in Variables.Keys) 435 | if (!name.Contains(';')) 436 | lst[name] = Variables[name]; 437 | else { 438 | var s = name.Substring(name.IndexOf(';')+1); 439 | if (sequence == s || sequence.Contains(s)) 440 | lst[name.Remove(name.LastIndexOf(';'))] = Variables[name]; 441 | } 442 | } 443 | return lst; 444 | } 445 | 446 | public static object GetVariable(int threadID, string name) 447 | { 448 | var lst = GetVariables(threadID); 449 | return lst.ContainsKey(name) ? lst[name] : null; 450 | } 451 | } 452 | } 453 | } 454 | -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DoIt - Task Script")] 9 | [assembly: AssemblyDescription("This tool runs a xml script to automate recurring tasks.")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("ForLogic Software")] 12 | [assembly: AssemblyProduct("DoIt")] 13 | [assembly: AssemblyCopyright("© ForLogic Software 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2620b343-0156-40fa-a313-d8af6f456b02")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("2018.09.28.0")] 36 | [assembly: AssemblyFileVersion("2018.09.28.0")] 37 | -------------------------------------------------------------------------------- /src/StaticRandom.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace DoIt 5 | { 6 | public static class StaticRandom 7 | { 8 | static int seed = Environment.TickCount * Thread.CurrentThread.ManagedThreadId; 9 | static readonly ThreadLocal random = new ThreadLocal(() => new Random(Interlocked.Increment(ref seed))); 10 | 11 | public static int Next(int min, int max) 12 | { 13 | return random.Value.Next(min, max); 14 | } 15 | 16 | public static int Next(int max) 17 | { 18 | return random.Value.Next(max); 19 | 20 | } 21 | public static int Next() 22 | { 23 | return random.Value.Next(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml; 3 | using System.Linq; 4 | using System.IO; 5 | using System.Collections.Generic; 6 | using System.Text.RegularExpressions; 7 | using System.Data.SqlClient; 8 | using System.Data; 9 | using ICSharpCode.SharpZipLib.Zip; 10 | using System.Text; 11 | 12 | namespace DoIt 13 | { 14 | internal class Util 15 | { 16 | public static String GetFileSize(Int64 lengthInBytes, Int32 decimalPlaces = 2) 17 | { 18 | var value = Convert.ToDecimal(lengthInBytes); 19 | if (value < 1024) 20 | return Math.Round(value, decimalPlaces) + " bytes"; 21 | value /= 1024m; 22 | if (value < 1024) 23 | return Math.Round(value, decimalPlaces) + " KB"; 24 | value /= 1024m; 25 | if (value < 1024) 26 | return Math.Round(value, decimalPlaces) + " MB"; 27 | value /= 1024m; 28 | return Math.Round(value, decimalPlaces) + " GB"; 29 | } 30 | 31 | public static T GetEnumValue(string value, T defaultValue) where T:struct 32 | { 33 | if (string.IsNullOrEmpty(value)) 34 | return defaultValue; 35 | var lstValues1 = value.Split(new char[]{',',';','|',' '}, StringSplitOptions.RemoveEmptyEntries); 36 | var lstValues2 = Enum.GetNames(typeof(T)); 37 | if (!lstValues1.All(v => lstValues2.Any(s => s.ToLower() == v.ToLower()))) 38 | return defaultValue; 39 | return (T)Enum.Parse(typeof(T), string.Join(",", lstValues1), true); 40 | } 41 | 42 | public static XmlNode[] GetChildNodes(XmlNode node, params string[] childNames) 43 | { 44 | if (node == null) 45 | return null; 46 | if(childNames == null || childNames.Length == 0 || childNames.All(n => string.IsNullOrEmpty(n))) 47 | return node.ChildNodes.Cast().Where(n => n.Name != "#comment" && n.Name != "#whitespace").ToArray(); 48 | return node.ChildNodes.Cast().Where(n => childNames.Any(n2 => n2 != null && n.Name.ToLower() == n2.ToLower())).ToArray(); 49 | } 50 | 51 | public static XmlNode GetChildNode(XmlNode node, params string[] childNames) 52 | { 53 | var lst = GetChildNodes(node, childNames); 54 | return lst == null ? null : lst.FirstOrDefault(); 55 | } 56 | 57 | public static String GetStr(XmlNode node, String dataName, String defaultValue = null) 58 | { 59 | if (node == null) 60 | return defaultValue; 61 | var atr = node.Attributes[dataName]; 62 | if (atr != null && !String.IsNullOrEmpty(atr.Value)) 63 | return atr.Value; 64 | var subn = GetChildNode(node, dataName); 65 | return (subn == null || String.IsNullOrEmpty(subn.InnerText)) ? defaultValue : subn.InnerText; 66 | } 67 | 68 | public static String GetContentType(String filename, Boolean isExtension = false) 69 | { 70 | var ext = isExtension ? filename : Path.GetExtension(filename); 71 | switch (ext.ToLower()){ 72 | case ".pdf": return "application/pdf"; 73 | case ".zip": return "application/zip"; 74 | case ".js": return "application/javascript"; 75 | case ".gif": return "image/gif"; 76 | case ".jpg": return "image/jpeg"; 77 | case ".jpeg": return "image/jpeg"; 78 | case ".png": return "image/png"; 79 | case ".ico": return "image/x-icon"; 80 | case ".tif": return "image/tiff"; 81 | case ".tiff": return "image/tiff"; 82 | case ".eml": return "message/rfc822"; 83 | case ".mp4": return "video/mp4"; 84 | case ".mp3": return "audio/mpeg"; 85 | case ".mov": return "video/quicktime"; 86 | case ".mpg": return "video/mpeg"; 87 | case ".avi": return "video/x-msvideo"; 88 | case ".wmv": return "video/x-ms-wmv"; 89 | case ".xls": return "application/vnd.ms-excel"; 90 | case ".doc": return "application/msword"; 91 | case ".ppt": return "application/vnd.ms-powerpoint"; 92 | case ".pps": return "application/vnd.ms-powerpoint"; 93 | case ".xlsx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; 94 | case ".docx": return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; 95 | case ".pptx": return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; 96 | case ".xltx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.template"; 97 | case ".dotx": return "application/vnd.openxmlformats-officedocument.wordprocessingml.template"; 98 | case ".ppsx": return "application/vnd.openxmlformats-officedocument.presentationml.slideshow"; 99 | case ".rtf": return "application/rtf"; 100 | case ".css": return "text/css"; 101 | case ".csv": return "text/csv"; 102 | case ".txt": return "text/plain"; 103 | case ".xml": return "text/xml"; 104 | case ".htm": return "text/html"; 105 | case ".html": return "text/html"; 106 | } 107 | return "application/octet-stream"; 108 | } 109 | 110 | public static String GetTempFileName(String extension = null) 111 | { 112 | var temp = Path.GetTempFileName(); 113 | if (String.IsNullOrEmpty(extension)) 114 | return temp; 115 | var filename = Path.GetFileNameWithoutExtension(temp); 116 | return Path.Combine(Path.GetDirectoryName(temp), filename + (extension.StartsWith(".") ? extension : "." + extension)); 117 | } 118 | 119 | public static string GetConfigData(string configStr, string dataType, bool toLower = false, string defaultValue = null) 120 | { 121 | if (String.IsNullOrEmpty(configStr) || String.IsNullOrEmpty(dataType)) 122 | return null; 123 | var allData = configStr.Split(new Char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); 124 | foreach (var str in allData) 125 | if (str.Trim().ToLower().StartsWith(dataType.ToLower() + "=")){ 126 | var data = str.Split(new Char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); 127 | if (data.Length == 2){ 128 | var value = data[1]; 129 | if (String.IsNullOrEmpty(value)) 130 | return defaultValue; 131 | return toLower ? value.ToLower() : value; 132 | } 133 | } 134 | return null; 135 | } 136 | 137 | public static string GetArg(string[] args, string key, bool toLower = false) 138 | { 139 | if (args == null || args.Length == 0) 140 | return null; 141 | foreach (var arg in args){ 142 | if (String.IsNullOrEmpty(arg)) 143 | continue; 144 | var str = arg; 145 | if (!str.StartsWith("/") && !str.StartsWith("-") && !str.StartsWith("--")) 146 | continue; 147 | if (str.StartsWith("/")) 148 | str = arg.Remove(0, 1); 149 | if (str.StartsWith("--")) 150 | str = arg.Remove(0, 2); 151 | if (str.StartsWith("-")) 152 | str = arg.Remove(0, 1); 153 | if (!str.StartsWith(key, StringComparison.InvariantCultureIgnoreCase)) 154 | continue; 155 | var index = str.IndexOf("="); 156 | if (index == -1 || index == str.Length - 1) 157 | return toLower ? key.ToLower() : key; 158 | var value = str.Substring(index + 1); 159 | if (String.IsNullOrEmpty(value)) 160 | return value; 161 | value = value.Trim(new Char[] { '"', ' ' }); 162 | return toLower ? value.ToLower() : value; 163 | } 164 | return null; 165 | } 166 | 167 | public static object GetValue(object value, string type) 168 | { 169 | if (value == null || string.IsNullOrEmpty(type)) 170 | return value; 171 | var str = Convert.ToString(value); 172 | switch(type.ToLower()){ 173 | case "byte": return Convert.ToByte(value); 174 | case "short": return Convert.ToInt16(value); 175 | case "int": return Convert.ToInt32(value); 176 | case "long": return Convert.ToInt64(value); 177 | case "decimal": return Convert.ToDecimal(value); 178 | case "float": return Convert.ToSingle(value); 179 | case "double": return Convert.ToDouble(value); 180 | case "string": return Convert.ToString(value); 181 | case "datetime": return value is DateTime ? new Nullable(Convert.ToDateTime(value)) : ParseDateTime(Convert.ToString(value)); 182 | case "datetimeoffset": 183 | return value is DateTime ? 184 | new Nullable(new DateTimeOffset(Convert.ToDateTime(value))) : 185 | value is string && !string.IsNullOrEmpty(str) && Regex.IsMatch(str,@"^\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}\.\d{7}$") ? 186 | new Nullable(new DateTimeOffset(DateTime.ParseExact(str, "yyyy-MM-dd HH:mm:ss.fffffff", null), TimeSpan.Zero)) : 187 | value is string && !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}\.\d{7} (\+|\-)?\d{2}:\d{2}$") ? 188 | new Nullable(DateTimeOffset.ParseExact(str, "yyyy-MM-dd HH:mm:ss.fffffff zzz", null)) : 189 | ParseDateTimeOffset(str); 190 | case "bool": return Convert.ToBoolean(value); 191 | } 192 | return value; 193 | } 194 | 195 | public static Type GetType(string type) 196 | { 197 | if (string.IsNullOrEmpty(type)) 198 | return typeof(object); 199 | switch(type.ToLower()){ 200 | case "byte": return typeof(byte); 201 | case "short": return typeof(short); 202 | case "int": return typeof(int); 203 | case "long": return typeof(long); 204 | case "decimal": return typeof(decimal); 205 | case "float": return typeof(float); 206 | case "double": return typeof(double); 207 | case "string": return typeof(string); 208 | case "datetime": return typeof(DateTime); 209 | case "datetimeoffset": return typeof(DateTimeOffset); 210 | case "bool": return typeof(bool); 211 | } 212 | return typeof(object); 213 | } 214 | 215 | public static string GetStrData(string str, string tag, object data) 216 | { 217 | var pattern = "\\{(?" + tag.Replace("$", "\\$").Replace(".", "\\.") + ")(?\\:+.+?)*\\}"; 218 | var tagLower = tag.ToLower(); 219 | var m = Regex.Match(str, pattern); 220 | var oldData = data; 221 | while (m != null && m.Success){ 222 | data = oldData; 223 | var p = m.Groups["params"]; 224 | if (!p.Success){ 225 | var valueStr = null as string; 226 | if (data is DateTimeOffset) 227 | valueStr = Util.GetDateTimeOffsetString((DateTimeOffset)data); 228 | else if (data is DateTime) 229 | valueStr = Util.GetDateTimeString((DateTime)data); 230 | else 231 | valueStr = Convert.ToString(data); 232 | str = str 233 | .Remove(m.Index, m.Length) 234 | .Insert(m.Index, tagLower == "rand" ? Util.Random(15) : valueStr); 235 | m = Regex.Match(str, pattern); 236 | continue; 237 | } 238 | 239 | var array = p.Value.Split(new char[] { ':' }, StringSplitOptions.None); 240 | if (tag == "rand"){ 241 | var len = array.Length >= 2 && Regex.IsMatch(array[1], "^\\d+$") ? Convert.ToInt32(array[1]) : 15; 242 | var chars = array.Length == 3 && !string.IsNullOrEmpty(array[2]) ? array[2] : "0123456789ABCDEFGHIJKLMNOPQRSTUVXWYZabcdefghijklmnopqrstuvxwyz"; 243 | if (chars.Length == 7 || chars.Length == 5) 244 | switch (chars.ToLower()){ 245 | case "numbers": chars = "0123456789"; break; 246 | case "upper": chars = "ABCDEFGHIJKLMNOPQRSTUVXWYZ"; break; 247 | case "lower": chars = "abcdefghijklmnopqrstuvxwyz"; break; 248 | } 249 | var rand = Util.Random(len, chars); 250 | str = str 251 | .Remove(m.Index, m.Length) 252 | .Insert(m.Index, rand); 253 | m = Regex.Match(str, pattern); 254 | continue; 255 | } 256 | 257 | foreach (var v in array) 258 | if (!string.IsNullOrEmpty(v) && !v.StartsWith(">")) 259 | switch (v.ToLower()){ 260 | case "onlypathchars": data = Convert.ToString(data).OnlyPathChars(); break; 261 | case "filename": data = Convert.ToString(data).GetFileName(); break; 262 | case "fileextension": data = Convert.ToString(data).GetFileExtension(); break; 263 | case "bytes": data = GetBytes(Convert.ToDecimal(data)); break; 264 | default: data = string.Format($"{{0:{v}}}", data); break; 265 | } 266 | 267 | var value = null as string; //data is DateTimeOffset ? string.Format("{0:yyyy-MM-dd HH:mm:ss.fffffff zzz}", data) : Convert.ToString(data); 268 | if (data is DateTimeOffset) 269 | value = string.Format("{0:yyyy-MM-dd HH:mm:ss.fffffff zzz}", data); 270 | else 271 | value = Convert.ToString(data); 272 | 273 | if (string.IsNullOrEmpty(value)) { 274 | var last = array.Length > 0 ? array[array.Length - 1] : null; 275 | if (!string.IsNullOrEmpty(last) && last.StartsWith(">")) 276 | value = last.Remove(0, 1); 277 | } 278 | 279 | str = str 280 | .Remove(m.Index, m.Length) 281 | .Insert(m.Index, value); 282 | m = Regex.Match(str, pattern); 283 | } 284 | return str; 285 | } 286 | 287 | static string GetBytes(decimal bytes) 288 | { 289 | if (bytes < 1024m) 290 | return bytes + " bytes"; 291 | bytes = bytes / 1024m; 292 | if (bytes < 1024m) 293 | return Math.Round(bytes, 1) + " KB"; 294 | bytes = bytes / 1024m; 295 | if (bytes < 1024) 296 | return Math.Round(bytes, 1) + " MB"; 297 | bytes = bytes / 1024m; 298 | if (bytes < 1024) 299 | return Math.Round(bytes, 1) + " GB"; 300 | bytes = bytes / 1024m; 301 | return Math.Round(bytes, 1) + " TB"; 302 | } 303 | 304 | static string[] GetTagParameters(string str, string tag) 305 | { 306 | var lst = new List(); 307 | var strLower = str.ToLower(); 308 | var tagLower = tag.ToLower(); 309 | while (true){ 310 | var index1 = strLower.IndexOf("{" + tagLower + ":"); 311 | var index2 = strLower.IndexOf("}", index1 + 1); 312 | if (index1 == -1 || index2 == -1) 313 | break; 314 | var parameter = str.Substring(index1 + tag.Length + 2, index2 - index1 - (tag.Length + 2)); 315 | if (!string.IsNullOrEmpty(parameter)) 316 | lst.Add(parameter); 317 | str = str.Remove(index1, index2 - index1 + 1); 318 | } 319 | return lst.ToArray(); 320 | } 321 | 322 | public static string Random(int charCount, string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVXWYZabcdefghijklmnopqrstuvxwyz") 323 | { 324 | var sb = new StringBuilder(); 325 | for (var x = 0; x < charCount; x++){ 326 | var rValue = StaticRandom.Next(chars.Length); 327 | sb.Append(chars[rValue]); 328 | } 329 | return sb.ToString(); 330 | } 331 | 332 | public static string GetDateTimeString(DateTime date) 333 | { 334 | if (date.Hour == 0 && date.Minute == 0 && date.Second == 0 && date.Millisecond == 0) 335 | return date.ToString("yyyy-MM-dd"); 336 | if(date.Millisecond == 0) 337 | return date.ToString("yyyy-MM-dd HH:mm:ss"); 338 | return date.ToString("yyyy-MM-dd HH:mm:ss.fffffff"); 339 | } 340 | 341 | public static string GetDateTimeOffsetString(DateTimeOffset date) 342 | { 343 | if (date.Hour == 0 && date.Minute == 0 && date.Second == 0 && date.Millisecond == 0) 344 | return date.ToString("yyyy-MM-dd"); 345 | if(date.Millisecond == 0) 346 | return date.ToString("yyyy-MM-dd HH:mm:sszzz"); 347 | return date.ToString("yyyy-MM-dd HH:mm:ss.fffffffzzz"); 348 | } 349 | 350 | public static DateTime? ParseDateTime(string value) 351 | { 352 | if (string.IsNullOrEmpty(value)) 353 | return null; 354 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2} \\d{2}\\:\\d{2}:\\d{2}\\.\\d{7}$")) 355 | return DateTime.ParseExact(value, "yyyy-MM-dd HH:mm:ss.fffffff", null); 356 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2} \\d{2}\\:\\d{2}:\\d{2}\\.\\d{3}$")) 357 | return DateTime.ParseExact(value, "yyyy-MM-dd HH:mm:ss.fff", null); 358 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2} \\d{2}\\:\\d{2}:\\d{2}$")) 359 | return DateTime.ParseExact(value, "yyyy-MM-dd HH:mm:ss", null); 360 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2}$")) 361 | return DateTime.ParseExact(value, "yyyy-MM-dd", null); 362 | return null; 363 | } 364 | 365 | public static DateTimeOffset? ParseDateTimeOffset(string value) 366 | { 367 | if (string.IsNullOrEmpty(value)) 368 | return null; 369 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2} \\d{2}\\:\\d{2}:\\d{2}\\.\\d{7}(\\+|\\-)\\d{2}:\\d{2}$")) 370 | return DateTimeOffset.ParseExact(value, "yyyy-MM-dd HH:mm:ss.fffffffzzz", null); 371 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2} \\d{2}\\:\\d{2}:\\d{2}\\.\\d{3}(\\+|\\-)\\d{2}:\\d{2}$")) 372 | return DateTimeOffset.ParseExact(value, "yyyy-MM-dd HH:mm:ss.fffzzz", null); 373 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2} \\d{2}\\:\\d{2}:\\d{2}(\\+|\\-)\\d{2}:\\d{2}$")) 374 | return DateTime.ParseExact(value, "yyyy-MM-dd HH:mm:sszzz", null); 375 | if (value.IsMatch("^\\d{4}-\\d{2}-\\d{2}$")) 376 | return DateTime.ParseExact(value, "yyyy-MM-dd", null); 377 | return null; 378 | } 379 | 380 | public static bool IsTodayInList(String days) 381 | { 382 | if (String.IsNullOrEmpty(days)) 383 | return false; 384 | var array = days.ToLower().Split(new string[] { ",", ";", "|" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).ToArray(); 385 | if (array.Contains("all") || array.Contains(Convert.ToString(DateTime.Today.Day))) 386 | return true; 387 | var lst1 = new List() { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; 388 | var lst2 = new List() { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" }; 389 | var currentIndex = Convert.ToInt32(DateTime.Today.DayOfWeek); 390 | if (array.Select(item => lst1.IndexOf(item)).Any(index => index == currentIndex) || 391 | array.Select(item => lst2.IndexOf(item)).Any(index => index == currentIndex)) 392 | return true; 393 | 394 | foreach (var item in array) 395 | { 396 | var m1 = Regex.Match(item, "^(?\\d{4})-(?\\d{2})-(?\\d{2})$"); 397 | if (m1.Success) { 398 | var y = Convert.ToInt32(m1.Groups["year"].Value); 399 | var m = Convert.ToInt32(m1.Groups["month"].Value); 400 | var d = Convert.ToInt32(m1.Groups["day"].Value); 401 | var date = new DateTime(y, m, d); 402 | if (date.CompareTo(DateTime.Today) == 0) 403 | return true; 404 | continue; 405 | } 406 | var m2 = Regex.Match(item, "^(?1st|first|2nd|second|3rd|third|4th|fourth|last) (?sun|sunday|mon|monday|tue|tuesday|wed|wednesday|thu|thursday|fri|friday|sat|saturday)$", RegexOptions.IgnoreCase); 407 | if (!m2.Success) 408 | continue; 409 | var index = m2.Groups["g1"].Value; 410 | var dayOfWeek = m2.Groups["g2"].Value; 411 | if (IsDayOfWeek(dayOfWeek, index)) 412 | return true; 413 | } 414 | return false; 415 | } 416 | 417 | public static bool IsDayOfWeek(string dayOfWeek, string index) 418 | { 419 | var m1 = Regex.Match(dayOfWeek, "^(?sun|sunday)|(?mon|monday)|(?tue|tuesday)|(?wed|wednesday)|(?thu|thursday)|(?fri|friday)|(?sat|saturday)$", RegexOptions.IgnoreCase); 420 | var m2 = Regex.Match(index, "^(?1st|first)|(?2nd|second)|(?3rd|third)|(?4th|fourth)|(?last)$", RegexOptions.IgnoreCase); 421 | if (!m1.Success || !m2.Success) 422 | return false; 423 | 424 | var g1Name = ""; 425 | for (var x = 0; x < 7; x++) 426 | if (m1.Groups["g" + x].Success){ 427 | g1Name = "g" + x; 428 | break; 429 | } 430 | var g2Name = ""; 431 | for (var x = 1; x < 6; x++) 432 | if (m2.Groups["g" + x].Success){ 433 | g2Name = "g" + x; 434 | break; 435 | } 436 | 437 | var g1 = m1.Groups[g1Name]; 438 | var g2 = m2.Groups[g2Name]; 439 | 440 | var d1 = Convert.ToInt32(g1Name.Remove(0, 1)); 441 | var i1 = Convert.ToInt32(g2Name.Remove(0, 1)); 442 | 443 | var d = DateTime.Today; 444 | var dw = Convert.ToInt32(d.DayOfWeek); 445 | if (dw != d1) 446 | return false; 447 | 448 | var dwIndex = GetDayOfWeekMonthIndex(d); 449 | var isLastDW = IsLastDayOfWeekInMonth(d); 450 | 451 | return 452 | (i1 < 5 && i1 == dwIndex) || 453 | (i1 == 5 && isLastDW); 454 | } 455 | 456 | public static int GetDayOfWeekMonthIndex(DateTime date) 457 | { 458 | var m = date.Month; 459 | var counter = 0; 460 | while (date.Month == m){ 461 | date = date.AddDays(-7); 462 | counter++; 463 | } 464 | return counter; 465 | } 466 | 467 | public static bool IsLastDayOfWeekInMonth(DateTime date) 468 | { 469 | var m = date.Month; 470 | date = date.AddDays(7); 471 | return date.Month != m; 472 | } 473 | 474 | public static DateTime GetDateTime(string timespan, DateTime? date = null) 475 | { 476 | return GetDateTimeOffset(timespan, new DateTimeOffset(date == null ? DateTime.Now : date.Value)).DateTime; 477 | } 478 | 479 | public static DateTimeOffset GetDateTimeOffset(string timespan, DateTimeOffset? date = null) 480 | { 481 | if (date == null) 482 | date = DateTimeOffset.Now; 483 | if (string.IsNullOrEmpty(timespan)) 484 | return date.Value; 485 | timespan = timespan.ToLower(); 486 | var m = Regex.Match(timespan, "^(?\\-|\\+)?\\s*(?\\d+)\\s*(?millisecond|second|minute|hour|day|week|month|year)s?$"); 487 | if (!m.Success) 488 | throw new ArgumentException($"Invalid GetDate parameter \"{timespan}\""); 489 | var operation = m.Groups["operation"].Success ? m.Groups["operation"].Value : "+"; 490 | var value = Convert.ToInt32(m.Groups["value"].Value) * (operation == "+" ? 1 : -1); 491 | var measure = m.Groups["measure"].Value; 492 | switch(measure){ 493 | case "millisecond": return date.Value.AddMilliseconds(value); 494 | case "second": return date.Value.AddSeconds(value); 495 | case "minute": return date.Value.AddMinutes(value); 496 | case "hour": return date.Value.AddHours(value); 497 | case "day": return date.Value.AddDays(value); 498 | case "week": return date.Value.AddDays(value*7); 499 | case "month": return date.Value.AddMonths(value); 500 | case "year": return date.Value.AddYears(value); 501 | } 502 | return date.Value; 503 | } 504 | 505 | public static TimeSpan GetTimeSpan(string timespan) 506 | { 507 | if (string.IsNullOrEmpty(timespan) || timespan.Trim() == "0") 508 | return TimeSpan.Zero; 509 | timespan = timespan.ToLower(); 510 | var m = Regex.Match(timespan, "^(?\\d+)\\s*(?ms|millisecond|s|second|min|minute|h|hour|day|week|month)s?$"); 511 | if (!m.Success) 512 | throw new ArgumentException($"Invalid GetTimeSpan parameter \"{timespan}\""); 513 | var value = Convert.ToInt32(m.Groups["value"].Value); 514 | var measure = m.Groups["measure"].Value; 515 | switch(measure){ 516 | case "ms": 517 | case "millisecond": return TimeSpan.FromMilliseconds(value); 518 | case "s": 519 | case "second": return TimeSpan.FromSeconds(value); 520 | case "min": 521 | case "minute": return TimeSpan.FromMinutes(value); 522 | case "h": 523 | case "hour": return TimeSpan.FromHours(value); 524 | case "day": return TimeSpan.FromDays(value); 525 | case "week": return TimeSpan.FromDays(value * 7); 526 | case "month": return TimeSpan.FromDays(value * 30); 527 | } 528 | return TimeSpan.Zero; 529 | } 530 | 531 | public static Boolean IsTimeToRun(String time) 532 | { 533 | if (String.IsNullOrEmpty(time)) 534 | return true; 535 | if (Regex.IsMatch(time, "^\\d+$") && Convert.ToInt32(time) == DateTime.Now.Hour) 536 | return true; 537 | if (Regex.IsMatch(time, "^\\d+\\-\\d+$")){ 538 | var array = time.Split('-'); 539 | var h1 = Convert.ToInt32(array[0]); 540 | var h2 = Convert.ToInt32(array[1]); 541 | var h = DateTime.Now.Hour; 542 | return (h1<=h2 && h>=h1 && h<=h2) || (h1>=h2 && (h>h1 || h(); 558 | var lstPatterns = (searchPattern??"*.*").Split(new char[]{'|'}, StringSplitOptions.RemoveEmptyEntries); 559 | foreach (var pattern in lstPatterns) 560 | lstAllFiles.AddRange(Directory.GetFiles(path, pattern, searchOption)); 561 | return lstAllFiles.ToArray(); 562 | } 563 | 564 | public static string GetFileToSend(String filename, Boolean zipFile, String zipEntryName = null) 565 | { 566 | if (!zipFile) 567 | return filename; 568 | var zipFilename = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + ".zip"); 569 | if (File.Exists(zipFilename)) 570 | File.Delete(zipFilename); 571 | if (string.IsNullOrEmpty(zipEntryName)) 572 | zipEntryName = Path.GetFileName(filename); 573 | using (var zipStream = new ZipOutputStream(File.Create(zipFilename))){ 574 | var fi = new FileInfo(filename); 575 | zipStream.PutNextEntry(new ZipEntry(zipEntryName) {DateTime=fi.LastWriteTime, Size=fi.Length}); 576 | using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 577 | fs.CopyTo(zipStream); 578 | } 579 | return zipFilename; 580 | } 581 | 582 | #region database helpers 583 | public static DataTable Select(string sql, string dbConnectionString, Int32? commandTimeout = null) 584 | { 585 | using (var conn = new SqlConnection(dbConnectionString)){ 586 | conn.Open(); 587 | var dt = new DataTable(); 588 | using (var cmd = new SqlCommand(sql, conn)){ 589 | if (commandTimeout != null) 590 | cmd.CommandTimeout = commandTimeout.Value; 591 | return Select(cmd); 592 | } 593 | } 594 | } 595 | 596 | public static DataTable Select(string sql, SqlConnection connection, SqlTransaction transaction, SqlParameter[] parameters = null, Int32? commandTimeout = null) 597 | { 598 | using (var cmd = new SqlCommand(sql, connection, transaction)){ 599 | if (commandTimeout != null) 600 | cmd.CommandTimeout = commandTimeout.Value; 601 | if (parameters != null) 602 | foreach (var p in parameters) 603 | cmd.Parameters.Add(p); 604 | return Select(cmd); 605 | } 606 | } 607 | 608 | public static DataTable Select(SqlCommand cmd) 609 | { 610 | if (cmd == null){ 611 | Console.WriteLine("SQL Select: null SqlCommand reference."); 612 | Program.Shared.WriteLogLine("SQL Select: null SqlCommand reference."); 613 | return new DataTable(); 614 | } 615 | var sql = GetCommandString(cmd).Trim(); 616 | Console.WriteLine($"SQL Select: {sql}"); 617 | Program.Shared.WriteLogLine($"SQL Select: {sql}"); 618 | var dt = new DataTable(); 619 | using (var da = new SqlDataAdapter(cmd)) 620 | da.Fill(dt); 621 | Console.WriteLine($"SQL Select: {dt.Rows.Count} row(s) found"); 622 | Program.Shared.WriteLogLine($"SQL Select: {dt.Rows.Count} row(s) found"); 623 | return dt; 624 | } 625 | 626 | public static object Scalar(string sql, string dbConnectionString, Int32? commandTimeout = null) 627 | { 628 | using (var conn = new SqlConnection(dbConnectionString)){ 629 | conn.Open(); 630 | using (var cmd = new SqlCommand(sql, conn)){ 631 | if (commandTimeout != null) 632 | cmd.CommandTimeout = commandTimeout.Value; 633 | return Scalar(cmd); 634 | } 635 | } 636 | } 637 | 638 | public static object Scalar(string sql, SqlConnection connection, SqlTransaction transaction, SqlParameter[] parameters = null, Int32? commandTimeout = null) 639 | { 640 | using (var cmd = new SqlCommand(sql, connection, transaction)){ 641 | if (commandTimeout != null) 642 | cmd.CommandTimeout = commandTimeout.Value; 643 | if (parameters != null) 644 | foreach (var p in parameters) 645 | cmd.Parameters.Add(p); 646 | return Scalar(cmd); 647 | } 648 | } 649 | 650 | public static object Scalar(SqlCommand cmd) 651 | { 652 | if (cmd == null){ 653 | Console.WriteLine("SQL Scalar: null SqlCommand reference."); 654 | Program.Shared.WriteLogLine("SQL Scalar: null SqlCommand reference."); 655 | return 0; 656 | } 657 | var sql = GetCommandString(cmd).Trim(); 658 | Console.WriteLine($"SQL Scalar: {sql}"); 659 | Program.Shared.WriteLogLine($"SQL Scalar: {sql}"); 660 | var obj = cmd.ExecuteScalar(); 661 | Console.WriteLine($"SQL Scalar: Result is \"{(obj == DBNull.Value ? "null" : Convert.ToString(obj))}\""); 662 | Program.Shared.WriteLogLine($"SQL Scalar: Result is \"{(obj == DBNull.Value ? "null" : Convert.ToString(obj))}\""); 663 | return obj; 664 | } 665 | 666 | public static int Execute(string sql, string dbConnectionString, Int32? commandTimeout = null) 667 | { 668 | using (var conn = new SqlConnection(dbConnectionString)){ 669 | conn.Open(); 670 | using (var cmd = new SqlCommand(sql, conn)){ 671 | if (commandTimeout != null) 672 | cmd.CommandTimeout = commandTimeout.Value; 673 | return Execute(cmd); 674 | } 675 | } 676 | } 677 | 678 | public static int Execute(string sql, SqlConnection connection, SqlTransaction transaction, SqlParameter[] parameters = null, Int32? commandTimeout = null) 679 | { 680 | using (var cmd = new SqlCommand(sql, connection, transaction)){ 681 | if (commandTimeout != null) 682 | cmd.CommandTimeout = commandTimeout.Value; 683 | if (parameters != null) 684 | foreach (var p in parameters) 685 | cmd.Parameters.Add(p); 686 | return Execute(cmd); 687 | } 688 | } 689 | 690 | public static int Execute(SqlCommand cmd) 691 | { 692 | if (cmd == null){ 693 | Console.WriteLine("SQL Execute: null SqlCommand reference."); 694 | Program.Shared.WriteLogLine("SQL Execute: null SqlCommand reference."); 695 | return 0; 696 | } 697 | var sql = GetCommandString(cmd).Trim(); 698 | Console.WriteLine($"SQL Execute: {sql}"); 699 | Program.Shared.WriteLogLine($"SQL Execute: {sql}"); 700 | var rows = cmd.ExecuteNonQuery(); 701 | Console.WriteLine($"SQL Execute: {rows} row(s) affected"); 702 | Program.Shared.WriteLogLine($"SQL Execute: {rows} row(s) affected"); 703 | return rows; 704 | } 705 | #endregion 706 | 707 | 708 | public static string GetCommandString(SqlCommand cmd) 709 | { 710 | var s = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; 711 | Func fnGetString = (SqlParameter p) => { 712 | if (p.Value == null || p.Value == DBNull.Value) 713 | return "null"; 714 | switch (p.SqlDbType){ 715 | case SqlDbType.Char: 716 | case SqlDbType.VarChar: 717 | case SqlDbType.NChar: 718 | case SqlDbType.NVarChar: 719 | case SqlDbType.Text: 720 | case SqlDbType.NText: 721 | return $"'{Convert.ToString(p.Value).Replace("'", "''")}'"; 722 | case SqlDbType.Date: 723 | return $"'{Convert.ToDateTime(p.Value).ToString("yyyy-MM-dd")}'"; 724 | case SqlDbType.DateTime: 725 | case SqlDbType.DateTime2: 726 | var v1 = Convert.ToDateTime(p.Value); 727 | return $"'{v1.ToString("yyyy-MM-dd" + (v1.Hour == 0 && v1.Minute == 0 && v1.Second == 0 && v1.Millisecond == 0 ? null : " HH:mm:ss.fff"))}'"; 728 | case SqlDbType.DateTimeOffset: 729 | var v2 = (DateTimeOffset)p.Value; 730 | return $"'{v2.ToString("yyyy-MM-dd HH:mm:ss.fffffff zzz")}'"; 731 | case SqlDbType.Bit: 732 | return Convert.ToBoolean(p.Value) ? "1" : "0"; 733 | case SqlDbType.TinyInt: 734 | case SqlDbType.SmallInt: 735 | case SqlDbType.Int: 736 | case SqlDbType.BigInt: 737 | return Convert.ToString(p.Value); 738 | case SqlDbType.Decimal: 739 | case SqlDbType.Float: 740 | case SqlDbType.Real: 741 | var v3 = Convert.ToDecimal(p.Value); 742 | return Convert.ToString(v3).Replace(s, "."); 743 | } 744 | return $"'{Convert.ToString(p.Value).Replace("'", "''")}'"; 745 | }; 746 | var sql = cmd.CommandText; 747 | foreach (SqlParameter p in cmd.Parameters) 748 | sql = ReplaceSQLParameter(sql, "@" + p.ParameterName, fnGetString(p)); 749 | return sql; 750 | } 751 | 752 | public static string ReplaceSQLParameter(string sql, string paramName, string paramValue) 753 | { 754 | var index = -1; 755 | while (true){ 756 | index = index >= sql.Length ? -1 : sql.IndexOf(paramName, index + 1); 757 | if (index == -1) 758 | return sql; 759 | var replace = sql.Length == index + paramName.Length || !System.Text.RegularExpressions.Regex.IsMatch(Convert.ToString(sql[index + paramName.Length]), "[a-zA-Z0-9_]+"); 760 | if (replace){ 761 | sql = sql.Remove(index, paramName.Length).Insert(index, paramValue); 762 | index += paramValue.Length; 763 | } 764 | else 765 | index += paramName.Length; 766 | } 767 | } 768 | 769 | } 770 | } 771 | --------------------------------------------------------------------------------