Browse Source

commit: import project

HOME 4 năm trước cách đây
mục cha
commit
1cce07c51f

+ 49 - 0
D3NsCore/BasicServ.cs

@@ -0,0 +1,49 @@
+using System;
+using D3NsCore.Models;
+
+namespace D3NsCore
+{
+    public abstract class BasicServ
+    {
+        public abstract void Start();
+
+        public abstract void Stop();
+
+        public event EventHandler<LogEventArgs> Log;
+
+        protected virtual void OnLog(LogEventArgs e)
+        {
+            Log?.Invoke(this, e);
+        }
+
+        protected void LogDebug(string message)
+        {
+            OnLog(new LogEventArgs { Level = LogLevel.Debug, Log = message });
+        }
+
+        protected void LogTrace(string message)
+        {
+            OnLog(new LogEventArgs { Level = LogLevel.Trace, Log = message });
+        }
+
+        protected void LogInfo(string message)
+        {
+            OnLog(new LogEventArgs { Level = LogLevel.Info, Log = message });
+        }
+
+        protected void LogWarning(string message)
+        {
+            OnLog(new LogEventArgs { Level = LogLevel.Warning, Log = message });
+        }
+
+        protected void LogError(string message)
+        {
+            OnLog(new LogEventArgs { Level = LogLevel.Error, Log = message });
+        }
+
+        protected void LogFatal(string message)
+        {
+            OnLog(new LogEventArgs { Level = LogLevel.Fatal, Log = message });
+        }
+    }
+}

+ 103 - 0
D3NsCore/D3NsClient.cs

@@ -0,0 +1,103 @@
+using D3NsCore.Models;
+using D3NsCore.Tools;
+using System.Linq;
+using System.Net;
+using System.Threading;
+
+namespace D3NsCore
+{
+    public class D3NsClient : BasicServ
+    {
+        private ConfigAdapter _conf;
+        private HttpAccess _http;
+        private bool _isRunning;
+        private Thread _thread;
+
+        public string Domain => _conf.DnsRecordName + "." + _conf.Domain;
+
+        public D3NsClient(string dbFile)
+        {
+            _conf = new ConfigAdapter(new DataAccess(dbFile).GetConfigs());
+            _http = new HttpAccess();
+        }
+
+        public override void Start()
+        {
+            _isRunning = true;
+            _thread = new Thread(Run) { IsBackground = true };
+            _thread.Start();
+        }
+
+        public override void Stop()
+        {
+            _isRunning = false;
+            _thread.Join();
+        }
+
+        private void Run()
+        {
+            var key = _conf.Key;
+            var sec = _conf.Secret;
+
+            if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(sec))
+            {
+                LogFatal("Please fill configs.");
+                return;
+            }
+
+            string myIp, dnsIp;
+
+            while (_isRunning) //TODO: Error handle
+            {
+                //Get my ip
+                //Get dns ip
+                //cmp
+                // + put my ip to dns
+                // - do nothing
+                //sleep
+
+                try
+                {
+                    LogTrace("Getting my ip...");
+                    myIp = GetMyIp();
+                    LogInfo($"My ip is: {myIp}");
+                    LogTrace("Getting dns ip...");
+                    dnsIp = GetDnsIp();
+                    LogInfo($"Dns ip is: {dnsIp}");
+
+                    if (myIp != dnsIp)
+                    {
+                        LogInfo("Updating dns record...");
+                        PutDnsIp(myIp);
+                    }
+                    else
+                    {
+                        LogTrace("Nothing to do.");
+                    }
+                }
+                catch (WebException e)
+                {
+                    LogError(e.Message);
+                }
+
+                LogTrace("Sleeping...");
+                for (var i = 0; i < 600; i++)
+                {
+                    if (_isRunning == false) break;
+                    Thread.Sleep(1000);
+                }
+                LogTrace("Wake up.");
+            }
+
+            LogInfo("Exit.");
+        }
+
+        // ---- utilitys ----
+
+        private string GetMyIp() => _http.GetJsonAnon(new { REMOTE_ADDR = "" }, _conf.GetMyIp).REMOTE_ADDR;
+
+        private string GetDnsIp() => _http.GetJsonAnon(new[] { new { data = "" } }, $"https://api.godaddy.com/v1/domains/{_conf.Domain}/records/A/{_conf.DnsRecordName}", new HttpHeader("Accept", "application/json"), new HttpHeader("Authorization", $"sso-key {_conf.Key}:{_conf.Secret}")).Select(p => p.data).Single();
+
+        private void PutDnsIp(string ip) => _http.PutString($"https://api.godaddy.com/v1/domains/{_conf.Domain}/records/A/{_conf.DnsRecordName}", $"[{{\"data\":\"{ip}\",\"ttl\":600}}]", "application/json", new HttpHeader("Authorization", $"sso-key {_conf.Key}:{_conf.Secret}"));
+    }
+}

+ 110 - 0
D3NsCore/D3NsCore.csproj

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="C:\NuGetLocalRepo\SQLite.Native.3.12.3\build\net45\SQLite.Native.props" Condition="Exists('C:\NuGetLocalRepo\SQLite.Native.3.12.3\build\net45\SQLite.Native.props')" />
+  <Import Project="C:\NuGetLocalRepo\ILRepack.2.0.13\build\ILRepack.props" Condition="Exists('C:\NuGetLocalRepo\ILRepack.2.0.13\build\ILRepack.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{770B76D8-F319-47EE-BF90-5D434DD07CA1}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>D3NsCore</RootNamespace>
+    <AssemblyName>D3NsCore</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>true</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>true</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Dapper, Version=1.50.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>C:\NuGetLocalRepo\Dapper.1.50.2\lib\net45\Dapper.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Mono.Data.Sqlite, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
+      <HintPath>C:\NuGetLocalRepo\Mono.Data.Sqlite.Portable.1.0.3.5\lib\net4\Mono.Data.Sqlite.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>C:\NuGetLocalRepo\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System">
+      <HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data.Portable, Version=4.0.0.0, Culture=neutral, PublicKeyToken=59e704a76bc4613a, processorArchitecture=MSIL">
+      <HintPath>C:\NuGetLocalRepo\Mono.Data.Sqlite.Portable.1.0.3.5\lib\net4\System.Data.Portable.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Transactions" />
+    <Reference Include="System.Transactions.Portable, Version=4.0.0.0, Culture=neutral, PublicKeyToken=59e704a76bc4613a, processorArchitecture=MSIL">
+      <HintPath>C:\NuGetLocalRepo\Mono.Data.Sqlite.Portable.1.0.3.5\lib\net4\System.Transactions.Portable.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BasicServ.cs" />
+    <Compile Include="D3NsClient.cs" />
+    <Compile Include="Entities\ConfigEntry.cs" />
+    <Compile Include="Models\HttpHeader.cs" />
+    <Compile Include="Models\LogEventArgs.cs" />
+    <Compile Include="Models\LogLevel.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Tools\ConfigAdapter.cs" />
+    <Compile Include="Tools\DataAccess.cs" />
+    <Compile Include="Tools\HttpAccess.cs" />
+    <Compile Include="Tools\Utility.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>此项目引用这台计算机上缺少的 NuGet 程序包。使用 NuGet 程序包还原可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('C:\NuGetLocalRepo\ILRepack.2.0.13\build\ILRepack.props')" Text="$([System.String]::Format('$(ErrorText)', 'C:\NuGetLocalRepo\ILRepack.2.0.13\build\ILRepack.props'))" />
+    <Error Condition="!Exists('C:\NuGetLocalRepo\SQLite.Native.3.12.3\build\net45\SQLite.Native.props')" Text="$([System.String]::Format('$(ErrorText)', 'C:\NuGetLocalRepo\SQLite.Native.3.12.3\build\net45\SQLite.Native.props'))" />
+  </Target>
+  <PropertyGroup>
+    <PostBuildEvent>if $(ConfigurationName) == Release if not exist $(TargetDir)Packed md $(TargetDir)Packed
+if $(ConfigurationName) == Release $(ILRepack) /ndebug /out:$(TargetDir)Packed\$(TargetFileName) $(TargetPath) Dapper.dll Mono.Data.Sqlite.dll Newtonsoft.Json.dll System.Data.Portable.dll System.Transactions.Portable.dll
+if $(ConfigurationName) == Release if exist $(TargetDir)Packed\$(TargetFileName).config del $(TargetDir)Packed\$(TargetFileName).config
+if $(ConfigurationName) == Release copy $(TargetDir)sqlite3.dll $(TargetDir)Packed\sqlite3.dll</PostBuildEvent>
+  </PropertyGroup>
+  <Import Project="C:\NuGetLocalRepo\Mono.Data.Sqlite.Portable.1.0.3.5\tools\Mono.Data.Sqlite.Portable.targets" Condition="Exists('C:\NuGetLocalRepo\Mono.Data.Sqlite.Portable.1.0.3.5\tools\Mono.Data.Sqlite.Portable.targets')" />
+  <Target Name="EnsureMonoDataSqlitePortableImported" BeforeTargets="BeforeBuild" Condition="'$(MonoDataSqlitePortableImported)' == ''">
+    <Error Condition="!Exists('C:\NuGetLocalRepo\Mono.Data.Sqlite.Portable.1.0.3.5\tools\Mono.Data.Sqlite.Portable.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them." />
+    <Error Condition="Exists('C:\NuGetLocalRepo\Mono.Data.Sqlite.Portable.1.0.3.5\tools\Mono.Data.Sqlite.Portable.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build." />
+  </Target>
+</Project>

+ 8 - 0
D3NsCore/Entities/ConfigEntry.cs

@@ -0,0 +1,8 @@
+namespace D3NsCore.Entities
+{
+    internal class ConfigEntry
+    {
+        public string Key { get; set; }
+        public string Value { get; set; }
+    }
+}

+ 25 - 0
D3NsCore/Models/HttpHeader.cs

@@ -0,0 +1,25 @@
+namespace D3NsCore.Models
+{
+    internal class HttpHeader
+    {
+        private static readonly HttpHeader[] EmptyArray = new HttpHeader[0];
+
+        public string Name { get; set; }
+        public string Value { get; set; }
+
+        public override string ToString()
+        {
+            return $"{Name}: {Value}";
+        }
+
+        public HttpHeader(string name, string value)
+        {
+            Name = name;
+            Value = value;
+        }
+
+        public HttpHeader()
+        {
+        }
+    }
+}

+ 10 - 0
D3NsCore/Models/LogEventArgs.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace D3NsCore.Models
+{
+    public class LogEventArgs : EventArgs
+    {
+        public LogLevel Level { get; set; }
+        public string Log { get; set; }
+    }
+}

+ 12 - 0
D3NsCore/Models/LogLevel.cs

@@ -0,0 +1,12 @@
+namespace D3NsCore.Models
+{
+    public enum LogLevel
+    {
+        Debug,
+        Trace,
+        Info,
+        Warning,
+        Error,
+        Fatal,
+    }
+}

+ 44 - 0
D3NsCore/Program.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Threading;
+
+namespace D3NsCore
+{
+    internal class Program
+    {
+        private static void Main(string[] args)
+        {
+            Console.WriteLine("Starting...");
+            var svc = new D3NsClient("project.db3");
+            svc.Log += (sender, eventArgs) => Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {(eventArgs.Level + "").PadRight(7)} -- {eventArgs.Log}");
+            svc.Start();
+            try
+            {
+                Console.Title = "Direct DDNS - " + svc.Domain;
+            }
+            catch
+            {
+                //Do nothing
+            }
+
+            Console.WriteLine("Started.");
+
+            if (args.Length > 0 && args[0].ToLower() == "--no-enter")
+            {
+                Console.WriteLine($"To stop, kill me, process id:{System.Diagnostics.Process.GetCurrentProcess().Id}");
+                while (true)
+                {
+                    Thread.Sleep(1000);
+                }
+            }
+
+            Console.WriteLine("Press ENTER to stop.");
+            Console.ReadLine();
+            Console.WriteLine("Stopping...");
+            svc.Stop();
+
+            Console.WriteLine();
+            Console.Write("Stopped. Press ENTER to exit...");
+            Console.ReadLine();
+        }
+    }
+}

+ 36 - 0
D3NsCore/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("D3NsCore")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("D3NsCore")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("770b76d8-f319-47ee-bf90-5d434dd07ca1")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 49 - 0
D3NsCore/Tools/ConfigAdapter.cs

@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Runtime.CompilerServices;
+
+namespace D3NsCore.Tools
+{
+    internal class ConfigAdapter
+    {
+        private readonly Dictionary<string, string> _dicConf;
+
+        public ConfigAdapter(Dictionary<string, string> dicConf)
+        {
+            _dicConf = dicConf;
+        }
+
+        private string GetValue([CallerMemberName] string confKey = "")
+        {
+            return _dicConf.ContainsKey(confKey)
+                ? _dicConf[confKey]
+                : null;
+        }
+
+        private string[] GetValues([CallerMemberName] string confKey = "")
+        {
+            // ReSharper disable once ExplicitCallerInfoArgument
+            return (GetValue(confKey) ?? "").Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
+        }
+
+        private int GetInt32Value([CallerMemberName] string confKey = "")
+        {
+            // ReSharper disable once ExplicitCallerInfoArgument
+            var value = GetValue(confKey);
+
+            if (int.TryParse(value, out var int32Value))
+            {
+                return int32Value;
+            }
+
+            throw new ConfigurationErrorsException($"Bad config {confKey}");
+        }
+
+        public string Key => GetValue();
+        public string Secret => GetValue();
+        public string GetMyIp => GetValue();
+        public string Domain => GetValue();
+        public string DnsRecordName => GetValue();
+    }
+}

+ 77 - 0
D3NsCore/Tools/DataAccess.cs

@@ -0,0 +1,77 @@
+using D3NsCore.Entities;
+using Dapper;
+using Mono.Data.Sqlite;
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.IO;
+using System.Linq;
+
+namespace D3NsCore.Tools
+{
+    internal class DataAccess
+    {
+        private readonly string _filename;
+
+        public DataAccess(string filename)
+        {
+            _filename = filename;
+
+            CreateDatabaseIfNotExist();
+        }
+
+        private void CreateDatabaseIfNotExist()
+        {
+            if (File.Exists(_filename)) return;
+
+            using (var conn = GetConnection())
+            {
+                conn.Execute(
+                    //Create table:Config
+                    "CREATE TABLE Configs("
+                    + $"{nameof(ConfigEntry.Key)} VARCHAR(32) PRIMARY KEY,"
+                    + $"{nameof(ConfigEntry.Value)} VARCHAR(512)"
+                    + ");" +
+
+                    //Init Data
+                    $"INSERT INTO Configs ({nameof(ConfigEntry.Key)}) VALUES ('{nameof(ConfigAdapter.Key)}');"
+                    + $"INSERT INTO Configs ({nameof(ConfigEntry.Key)}) VALUES ('{nameof(ConfigAdapter.Secret)}');"
+                    + $"INSERT INTO Configs ({nameof(ConfigEntry.Key)}) VALUES ('{nameof(ConfigAdapter.GetMyIp)}');"
+                    + $"INSERT INTO Configs ({nameof(ConfigEntry.Key)}) VALUES ('{nameof(ConfigAdapter.Domain)}');"
+                    + $"INSERT INTO Configs ({nameof(ConfigEntry.Key)}) VALUES ('{nameof(ConfigAdapter.DnsRecordName)}');"
+                );
+            }
+        }
+
+        private DbConnection GetConnection()
+        {
+            var conn = new SqliteConnection("Data Source=" + _filename);
+            conn.Open();
+            return conn;
+        }
+
+        // --- common ---
+        public int BulkOperation<T>(IEnumerable<T> items, Func<T, DbConnection, int> proc)
+        {
+            var count = 0;
+            using (var conn = GetConnection())
+            {
+                using (var t = conn.BeginTransaction())
+                {
+                    count += items.Sum(p => proc(p, conn));
+
+                    t.Commit();
+                }
+            }
+
+            return count;
+        }
+
+        public Dictionary<string, string> GetConfigs()
+        {
+            using (var conn = GetConnection())
+                return conn.Query<ConfigEntry>("SELECT * FROM Configs")
+                    .ToDictionary(p => p.Key, p => p.Value);
+        }
+    }
+}

+ 52 - 0
D3NsCore/Tools/HttpAccess.cs

@@ -0,0 +1,52 @@
+using D3NsCore.Models;
+using Newtonsoft.Json;
+using System;
+using System.Net;
+using System.Text;
+
+namespace D3NsCore.Tools
+{
+    internal class HttpAccess
+    {
+        private const string UserAgent = "DirectDDNS";
+
+        public string ProxyServer { get; set; }
+
+        public string GetString(string url, params HttpHeader[] headers)
+        {
+            var wc = new WebClient { Headers = { ["User-Agent"] = UserAgent } };
+            wc.Proxy = new WebProxy();
+            if (ProxyServer != null) wc.Proxy = new WebProxy(new Uri(ProxyServer));
+            foreach (var header in headers) wc.Headers.Add(header.Name, header.Value);
+            var str = wc.DownloadString(url);
+            return str;
+        }
+
+        public string PutString(string url, string content, string contentType = "application/x-www-form-urlencoded;charset=UTF-8", params HttpHeader[] headers)
+        {
+            var wc = new WebClient { Headers = { ["User-Agent"] = UserAgent, ["Content-Type"] = contentType } };
+            if (ProxyServer != null) wc.Proxy = new WebProxy(new Uri(ProxyServer));
+            foreach (var header in headers) wc.Headers.Add(header.Name, header.Value);
+
+            try
+            {
+                var str = wc.UploadString(url, "PUT", content);
+                return str;
+            }
+            catch (WebException e)
+            {
+                if (e.Status == WebExceptionStatus.ProtocolError)
+                {
+                    var str = Encoding.UTF8.GetString(e.Response.GetResponseStream().ToBytes());
+                    throw new WebException(str, e);
+                }
+                throw;
+            }
+        }
+
+        public T GetJsonAnon<T>(T anon, string url, params HttpHeader[] headers)
+        {
+            return JsonConvert.DeserializeAnonymousType(GetString(url, headers), anon);
+        }
+    }
+}

+ 16 - 0
D3NsCore/Tools/Utility.cs

@@ -0,0 +1,16 @@
+using System.IO;
+
+namespace D3NsCore.Tools
+{
+    internal static class Utility
+    {
+        public static byte[] ToBytes(this Stream stream)
+        {
+            using (var ms = new MemoryStream())
+            {
+                stream.CopyTo(ms);
+                return ms.ToArray();
+            }
+        }
+    }
+}

+ 8 - 0
D3NsCore/packages.config

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Dapper" version="1.50.2" targetFramework="net45" />
+  <package id="ILRepack" version="2.0.13" targetFramework="net45" />
+  <package id="Mono.Data.Sqlite.Portable" version="1.0.3.5" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net45" />
+  <package id="SQLite.Native" version="3.12.3" targetFramework="net45" />
+</packages>

+ 22 - 0
DirectDDNS.sln

@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26430.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "D3NsCore", "D3NsCore\D3NsCore.csproj", "{770B76D8-F319-47EE-BF90-5D434DD07CA1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{770B76D8-F319-47EE-BF90-5D434DD07CA1}.Debug|x64.ActiveCfg = Debug|x64
+		{770B76D8-F319-47EE-BF90-5D434DD07CA1}.Debug|x64.Build.0 = Debug|x64
+		{770B76D8-F319-47EE-BF90-5D434DD07CA1}.Release|x64.ActiveCfg = Release|x64
+		{770B76D8-F319-47EE-BF90-5D434DD07CA1}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 6 - 0
NuGet.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?> 
+<configuration> 
+  <config> 
+    <add key="repositorypath" value="C:\NuGetLocalRepo" /> 
+  </config> 
+</configuration>