介绍
本系列文章介绍请看:概述
本文旨在搞清楚以下问题:
- 代理服务器数据结构
数据结构
-
代理服务器管理界面
-
代理服务器数据结构
代码位置Model/Server.cs
namespace Shadowsocks.Model
{
[Serializable]
public class Server
{
#region ParseLegacyURL
public static readonly Regex
UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase),
DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase);
#endregion ParseLegacyURL
private const int DefaultServerTimeoutSec = 5;
public const int MaxServerTimeoutSec = 20;
public string server; // 代理服务器名字
public int server_port; // 服务器端口
public string password; // 服务器密码
public string method; // 加密方式
public string plugin; // 插件程序
public string plugin_opts; // 插件选项
public string plugin_args; // 插件参数
public string remarks; // 备注
public int timeout; // 超时时间
// 计算hash
public override int GetHashCode(){.........}
// 判断俩Server一样
public override bool Equals(object obj){.........}
// 生成当前server对象的友好名字,格式: IP:PORT:REMARKS
public string FriendlyName(){.........}
// 格式化host name
public string FormatHostName(string hostName){.........}
// 构造函数
public Server(){.........}
// 从SSURL中解析Server对象,这里不去关注ssurl结构和解析方法
private static Server ParseLegacyURL(string ssURL){.........}
// 从SSURL中解析Server对象列表,这里不去关注ssurl结构和解析方法
public static List<Server> GetServers(string ssURL){.........}
// 获得当前服务器对象的标识:IP:PORT
public string Identifier(){.........}
}
}
可以看到,这里的数据结构和上面操作界面图中是一致的。
代理服务器配置管理
有了代理服务器数据结构,就可以进一步看该项目如何管理代理服务器配置了。
- 获得代理服务器列表
call stack:
View/CinfigForm.cs :
ConfigForm::ConfigForm -> ConfigForm::LoadCurrentConfiguration
Controller/ShadowsocksController.cs :
-> controller.GetConfigurationCopy
Model/Configuration.cs :
-> Configuration.Load
这里我们就来看看Configuration.Load是如何实现的
public static Configuration Load()
{
try
{
string configContent = File.ReadAllText(CONFIG_FILE);
Configuration config = JsonConvert.DeserializeObject<Configuration>(configContent);
config.isDefault = false;
if (config.configs == null)
config.configs = new List<Server>();
if (config.configs.Count == 0)
config.configs.Add(GetDefaultServer());
if (config.localPort == 0)
config.localPort = 1080;
if (config.index == -1 && config.strategy == null)
config.index = 0;
if (config.logViewer == null)
config.logViewer = new LogViewerConfig();
if (config.proxy == null)
config.proxy = new ProxyConfig();
if (config.hotkey == null)
config.hotkey = new HotkeyConfig();
config.proxy.CheckConfig();
return config;
}
catch (Exception e)
{
if (!(e is FileNotFoundException))
Logging.LogUsefulException(e);
return new Configuration
{
index = 0,
isDefault = true,
localPort = 1080,
autoCheckUpdate = true,
configs = new List<Server>()
{
GetDefaultServer()
},
logViewer = new LogViewerConfig(),
proxy = new ProxyConfig(),
hotkey = new HotkeyConfig()
};
}
}
代码非常简单,我就不一行一行解释了。客户端的配置使用json格式保存,直接json decode即可。容错处理此处不多说。
返回的config对象中:
config.configs:服务器列表,List
config.localPort:本机端口
config.index:当前服务器索引号
config.logViewer:当前日志配置
config.proxy:当前代理设置
config.hotkey:当前热键设置
这段代码紧接下来就是配置文件保存方法
public static void Save(Configuration config)
{
if (config.index >= config.configs.Count)
config.index = config.configs.Count - 1;
if (config.index < -1)
config.index = -1;
if (config.index == -1 && config.strategy == null)
config.index = 0;
config.isDefault = false;
try
{
using (StreamWriter sw = new StreamWriter(File.Open(CONFIG_FILE, FileMode.Create)))
{
string jsonString = JsonConvert.SerializeObject(config, Formatting.Indented);
sw.Write(jsonString);
sw.Flush();
}
}
catch (IOException e)
{
Logging.LogUsefulException(e);
}
}
看到这里就清楚了,全系统的配置都保存在一个Configuration config对象中,由Model/Configuration类管理。