Skip to content

Commit

Permalink
Upgrade: Support dynamic combine host from multi-source;
Browse files Browse the repository at this point in the history
  • Loading branch information
ylvict committed Oct 17, 2016
1 parent 0d23e0d commit f524a23
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 19 deletions.
2 changes: 0 additions & 2 deletions src/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
<configuration>
<appSettings>
<add key="Interval" value="3600000"/>
<add key="HostFileSrc" value="https://github.com/fengixng/google-hosts/raw/master/hosts"/>
<add key="CommitInfoLink" value="https://api.github.com/repos/fengixng/google-hosts/commits?path=/hosts"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
Expand Down
69 changes: 52 additions & 17 deletions src/CGitHost.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
using System;
using System.Linq;
using System.Configuration;
using System.IO;
using System.Net;
using System.ServiceProcess;
using System.Timers;
using System.Web.Script.Serialization;
using System.Collections.Generic;

namespace HostSyncer
{
partial class CGitHost : ServiceBase
{
private string EtcPath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "drivers", "etc");

private string LocalHost => Path.Combine(EtcPath, "hosts");

private string LocalHostBak => Path.Combine(EtcPath, "hosts.bak");

private string CommitInfoLink => ConfigurationManager.AppSettings["CommitInfoLink"];

private string HostFileLink => ConfigurationManager.AppSettings["HostFileSrc"];
private List<HostModel> HostRepos => new List<HostModel>
{
new HostModel { Repo = "racaljk/hosts", TempFileSubfix = "racaljk", IgnoreDomain = new string[] { ".googlevideo.com", ".youtube.com" } },
new HostModel { Repo = "fengixng/google-hosts", TempFileSubfix = "fengixng", OnlyDomain = new string[] { ".googlevideo.com", ".youtube.com" } },
};

private JavaScriptSerializer Serializer => new JavaScriptSerializer();

Expand Down Expand Up @@ -46,29 +44,66 @@ public CGitHost()
this.Timer.Elapsed += new ElapsedEventHandler(this.Timer_Elapsed);
}

protected override void OnStart(string[] args) => this.WebClient.DownloadFile(HostFileLink, LocalHost);
protected override void OnStart(string[] args) => this.Handle();

protected override void OnStop() => this.Timer.Stop();

protected void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
//Get current local hosts file update date;
var lastWriteTime = File.GetLastWriteTimeUtc(LocalHost);
var lastWriteTime = File.GetLastWriteTimeUtc(HostModel.LocalHost);

//Get current server latest hosts file update date;
var lastCommitDate = this.GetLatestCommitTime();
DateTime lastCommitDate = this.HostRepos
.Select(repo => this.GetLatestCommitTime(repo.CommitInfoLink))
.OrderBy(x => x).LastOrDefault();

//check if require to update the hosts;
//return if needn`t;
if (lastCommitDate < lastWriteTime.AddMilliseconds(this.Timer.Interval)) return;
if (lastCommitDate < lastWriteTime.AddMilliseconds(this.Timer.Interval))
return;

//check current hosts backup file existing;
//if backup haven`t stored, rename current file as backup;
if (!File.Exists(LocalHostBak)) File.Move(LocalHost, LocalHostBak);
if (!File.Exists(HostModel.LocalHostBak))
File.Move(HostModel.LocalHost, HostModel.LocalHostBak);

//download remote latest hosts file and store on "driver\etc\hosts"
this.WebClient.DownloadFile(HostFileLink, LocalHost);
this.Handle();
}

private void Handle()
{
this.HostRepos.ForEach(repo => this.WebClient.DownloadFile(repo.SrcFile, repo.DestPath));
this.Compose();
#if !DEBUG
this.HostRepos.ForEach(repo => File.Delete(repo.DestPath));
#endif
}

private void Compose()
{
var items = this.HostRepos.SelectMany(repo =>
{
return File.ReadAllLines(repo.DestPath)
.Where(x => !x.Trim().StartsWith("#"))
.Where(x => !String.IsNullOrWhiteSpace(x))
.Select(x => new HostItem(x))
.Where(x => (repo.OnlyDomain == null) || (repo.OnlyDomain.Length > 0 && repo.OnlyDomain.Count(d => x.Domain.EndsWith(d)) > 0))
.Where(x => repo.IgnoreDomain.Count(ig => x.Domain.EndsWith(ig)) <= 0);
}).Select(x => $"{x.IP}\t{x.Domain}");

#if DEBUG
System.Diagnostics.Debugger.Launch();
#endif

File.WriteAllLines(HostModel.LocalHost, items);
}

private DateTime GetLatestCommitTime()
private DateTime GetLatestCommitTime(string commitInfoLink)
{
var request = (HttpWebRequest)WebRequest.Create(CommitInfoLink);
var request = (HttpWebRequest)WebRequest.Create(commitInfoLink);
request.UserAgent = "Chrome/51.0.2704.106";
var response = (HttpWebResponse)request.GetResponse();
var stream = response.GetResponseStream();
Expand Down
35 changes: 35 additions & 0 deletions src/HostItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HostSyncer
{
public class HostItem
{
public string IP { get; set; }
public string Domain { get; set; }

public HostItem(string section)
{
var meta = section.Trim().Split(' ', '\t');
if (meta.Length < 2) throw new NotSupportedException("\"" + section + "\" cannot be resolved!");
this.IP = meta.First().Trim();
this.Domain = meta.Last().Trim();
}
}

public class HostItemComparer : IEqualityComparer<HostItem>
{
public bool Equals(HostItem x, HostItem y)
{
return x.Domain == y.Domain;
}

public int GetHashCode(HostItem obj)
{
string hCode = obj.IP + "^" + obj.Domain;
return hCode.GetHashCode();
}
}
}
32 changes: 32 additions & 0 deletions src/HostModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace HostSyncer
{
public class HostModel
{
public HostModel()
{
this.IgnoreDomain = new string[] { };
this.OnlyDomain = null;
}

private static string EtcPath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "drivers", "etc");
public static string LocalHost => Path.Combine(EtcPath, "hosts");
public static string LocalHostBak => Path.Combine(EtcPath, "hosts.bak");

public string Repo { get; set; }
public string TempFileSubfix { get; set; }

public string SrcFile => $@"https://github.com/{this.Repo}/raw/master/hosts";
public string CommitInfoLink => $@"https://api.github.com/repos/{this.Repo}/commits?path=/hosts";

public string[] IgnoreDomain { get; internal set; }
public string[] OnlyDomain { get; internal set; }

public string DestPath => Path.Combine(HostModel.EtcPath, $@"hosts_{this.TempFileSubfix}");
}
}
2 changes: 2 additions & 0 deletions src/HostSyncer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
<Compile Include="CGitHost.Designer.cs">
<DependentUpon>CGitHost.cs</DependentUpon>
</Compile>
<Compile Include="HostItem.cs" />
<Compile Include="HostModel.cs" />
<Compile Include="Program.cs" />
<Compile Include="ProjectInstaller.cs">
<SubType>Component</SubType>
Expand Down

0 comments on commit f524a23

Please sign in to comment.