wabbajack/Wabbajack.Common/Utils.cs

298 lines
9.1 KiB
C#
Raw Normal View History

2019-07-21 22:47:17 +00:00
using ICSharpCode.SharpZipLib.BZip2;
using IniParser;
2019-07-21 04:40:54 +00:00
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
2019-07-21 04:40:54 +00:00
using System.IO;
using System.Linq;
2019-07-23 04:27:26 +00:00
using System.Net.Http;
2019-07-21 04:40:54 +00:00
using System.Security.Cryptography;
using System.Text;
2019-08-02 23:04:04 +00:00
using System.Threading;
2019-07-21 04:40:54 +00:00
using System.Threading.Tasks;
namespace Wabbajack.Common
{
public static class Utils
{
/// <summary>
/// MurMur3 hashes the file pointed to by this string
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static string FileSHA256(this string file)
{
var sha = new SHA256Managed();
using (var o = new CryptoStream(Stream.Null, sha, CryptoStreamMode.Write))
{
using (var i = File.OpenRead(file))
i.CopyTo(o);
}
return sha.Hash.ToBase64();
}
2019-07-26 20:59:14 +00:00
public static string SHA256(this byte[] data)
{
return new SHA256Managed().ComputeHash(data).ToBase64();
}
2019-07-21 04:40:54 +00:00
/// <summary>
/// Returns a Base64 encoding of these bytes
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static string ToBase64(this byte[] data)
{
return Convert.ToBase64String(data);
}
2019-07-23 04:27:26 +00:00
/// <summary>
/// Returns data from a base64 stream
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] FromBase64(this string data)
{
return Convert.FromBase64String(data);
}
2019-07-21 04:40:54 +00:00
/// <summary>
/// Executes the action for every item in coll
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="coll"></param>
/// <param name="f"></param>
public static void Do<T>(this IEnumerable<T> coll, Action<T> f)
{
foreach (var i in coll) f(i);
}
/// <summary>
/// Loads INI data from the given filename and returns a dynamic type that
/// can use . operators to navigate the INI.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static dynamic LoadIniFile(this string file)
{
return new DynamicIniData(new FileIniDataParser().ReadFile(file));
}
public static void ToJSON<T>(this T obj, string filename)
{
File.WriteAllText(filename, JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings() {TypeNameHandling = TypeNameHandling.Auto}));
}
2019-07-31 03:59:19 +00:00
public static string ToJSON<T>(this T obj)
{
return JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });
}
2019-07-21 04:40:54 +00:00
public static T FromJSON<T>(this string filename)
{
2019-07-31 03:59:19 +00:00
return JsonConvert.DeserializeObject<T>(File.ReadAllText(filename), new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });
}
public static T FromJSONString<T>(this string data)
{
return JsonConvert.DeserializeObject<T>(data, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });
2019-07-21 04:40:54 +00:00
}
2019-07-23 04:27:26 +00:00
public static T FromJSON<T>(this Stream data)
{
var s = Encoding.UTF8.GetString(data.ReadAll());
return JsonConvert.DeserializeObject<T>(s);
}
2019-07-21 04:40:54 +00:00
public static bool FileExists(this string filename)
{
return File.Exists(filename);
}
public static string RelativeTo(this string file, string folder)
{
return file.Substring(folder.Length + 1);
}
2019-07-21 22:47:17 +00:00
/// <summary>
/// Returns the string compressed via BZip2
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] BZip2String(this string data)
{
using (var os = new MemoryStream())
{
using (var bz = new BZip2OutputStream(os))
{
using (var bw = new BinaryWriter(bz))
bw.Write(data);
}
return os.ToArray();
}
}
/// <summary>
/// Returns the string compressed via BZip2
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static string BZip2String(this byte[] data)
{
using (var s = new MemoryStream(data))
{
using (var bz = new BZip2InputStream(s))
{
using (var bw = new BinaryReader(bz))
return bw.ReadString();
}
}
}
2019-07-22 03:36:25 +00:00
public static byte[] ReadAll(this Stream ins)
{
using (var ms = new MemoryStream())
{
ins.CopyTo(ms);
return ms.ToArray();
}
}
2019-07-22 22:17:46 +00:00
public static List<TR> PMap<TI, TR>(this IEnumerable<TI> coll, Func<TI, TR> f)
{
2019-08-02 23:04:04 +00:00
var colllst = coll.ToList();
Interlocked.Add(ref WorkQueue.MaxQueueSize, colllst.Count);
//WorkQueue.CurrentQueueSize = 0;
2019-08-02 23:04:04 +00:00
2019-08-10 15:21:50 +00:00
int remaining_tasks = colllst.Count;
2019-07-22 22:17:46 +00:00
var tasks = coll.Select(i =>
{
TaskCompletionSource<TR> tc = new TaskCompletionSource<TR>();
WorkQueue.QueueTask(() =>
{
try
{
tc.SetResult(f(i));
}
catch (Exception ex)
{
tc.SetException(ex);
}
2019-08-02 23:04:04 +00:00
Interlocked.Increment(ref WorkQueue.CurrentQueueSize);
2019-08-10 15:21:50 +00:00
Interlocked.Decrement(ref remaining_tasks);
2019-08-02 23:04:04 +00:00
WorkQueue.ReportNow();
2019-07-22 22:17:46 +00:00
});
return tc.Task;
}).ToList();
2019-08-10 15:21:50 +00:00
// To avoid thread starvation, we'll start to help out in the work queue
if (WorkQueue.WorkerThread)
while(remaining_tasks > 0)
{
if(WorkQueue.Queue.TryTake(out var a, 500))
{
a();
}
}
if (WorkQueue.CurrentQueueSize == WorkQueue.MaxQueueSize)
{
WorkQueue.MaxQueueSize = 0;
WorkQueue.MaxQueueSize = 0;
}
2019-07-22 22:17:46 +00:00
return tasks.Select(t =>
{
t.Wait();
2019-07-26 20:59:14 +00:00
if (t.IsFaulted)
throw t.Exception;
2019-07-22 22:17:46 +00:00
return t.Result;
}).ToList();
}
public static void PMap<TI>(this IEnumerable<TI> coll, Action<TI> f)
{
2019-08-10 15:21:50 +00:00
coll.PMap<TI, bool>(i =>
2019-07-22 22:17:46 +00:00
{
2019-08-10 15:21:50 +00:00
f(i);
return false;
});
2019-07-22 22:17:46 +00:00
return;
}
2019-07-23 04:27:26 +00:00
public static HttpResponseMessage GetSync(this HttpClient client, string url)
{
var result = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
result.Wait();
return result.Result;
}
public static string GetStringSync(this HttpClient client, string url)
{
var result = client.GetStringAsync(url);
result.Wait();
return result.Result;
}
public static Stream GetStreamSync(this HttpClient client, string url)
{
var result = client.GetStreamAsync(url);
result.Wait();
return result.Result;
}
public static string ExceptionToString(this Exception ex)
{
StringBuilder sb = new StringBuilder();
while (ex != null)
{
sb.AppendLine(ex.Message);
var st = new StackTrace(ex, true);
foreach (var frame in st.GetFrames())
{
sb.AppendLine($"{frame.GetFileName()}:{frame.GetMethod().Name}:{frame.GetFileLineNumber()}:{frame.GetFileColumnNumber()}");
}
ex = ex.InnerException;
}
return sb.ToString();
}
public static void CrashDump(Exception e)
{
File.WriteAllText($"{DateTime.Now.ToString("yyyyMMddTHHmmss_crash_log.txt")}", ExceptionToString(e));
}
public static IEnumerable<T> DistinctBy<T, V>(this IEnumerable<T> vs, Func<T, V> select)
{
HashSet<V> set = new HashSet<V>();
foreach (var v in vs) {
var key = select(v);
if (set.Contains(key)) continue;
yield return v;
}
}
public static T Last<T>(this T[] a)
{
if (a == null || a.Length == 0)
throw new InvalidDataException("null or empty array");
return a[a.Length - 1];
}
public static V GetOrDefault<K, V>(this IDictionary<K, V> dict, K key)
{
if (dict.TryGetValue(key, out V v)) return v;
return default(V);
}
2019-07-21 04:40:54 +00:00
}
}