127 lines
3.8 KiB
C#
127 lines
3.8 KiB
C#
using Shadowsocks.Model;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace Shadowsocks.Controller.Strategy
|
|
{
|
|
class HighAvailabilityStrategy : IStrategy
|
|
{
|
|
protected Server _currentServer;
|
|
protected Dictionary<Server, ServerStatus> _serverStatus;
|
|
ShadowsocksController _controller;
|
|
Random _random;
|
|
|
|
public class ServerStatus
|
|
{
|
|
// time interval between SYN and SYN+ACK
|
|
public TimeSpan latency;
|
|
|
|
// last time anything received
|
|
public DateTime lastRead;
|
|
|
|
// last time anything sent
|
|
public DateTime lastWrite;
|
|
|
|
// connection refused or closed before anything received
|
|
public DateTime lastFailure;
|
|
|
|
public Server server;
|
|
}
|
|
|
|
/**
|
|
* if last failure is > 10 min
|
|
* and (last write > last read) and (now - last read < 5s) // means not stuck
|
|
* choose the lowest latency
|
|
*/
|
|
|
|
public HighAvailabilityStrategy(ShadowsocksController controller)
|
|
{
|
|
_controller = controller;
|
|
_random = new Random();
|
|
_serverStatus = new Dictionary<Server, ServerStatus>();
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get { return I18N.GetString("High Availability"); }
|
|
}
|
|
|
|
public string ID
|
|
{
|
|
get { return "com.shadowsocks.strategy.ha"; }
|
|
}
|
|
|
|
public void ReloadServers()
|
|
{
|
|
// make a copy to avoid locking
|
|
var newServerStatus = new Dictionary<Server, ServerStatus>(_serverStatus);
|
|
|
|
foreach (var server in _controller.GetCurrentConfiguration().configs)
|
|
{
|
|
if (!newServerStatus.ContainsKey(server))
|
|
{
|
|
var status = new ServerStatus();
|
|
status.server = server;
|
|
newServerStatus[server] = status;
|
|
}
|
|
}
|
|
_serverStatus = newServerStatus;
|
|
|
|
// just leave removed servers there
|
|
|
|
// TODO
|
|
_currentServer = _controller.GetCurrentConfiguration().configs[0];
|
|
}
|
|
|
|
public Server GetAServer(IStrategyCallerType type, System.Net.IPEndPoint localIPEndPoint)
|
|
{
|
|
return _currentServer;
|
|
}
|
|
|
|
public void UpdateLatency(Model.Server server, TimeSpan latency)
|
|
{
|
|
Logging.Debug(String.Format("latency: {0} {1}", server.FriendlyName(), latency));
|
|
|
|
ServerStatus status;
|
|
if (_serverStatus.TryGetValue(server, out status))
|
|
{
|
|
status.latency = latency;
|
|
}
|
|
}
|
|
|
|
public void UpdateLastRead(Model.Server server)
|
|
{
|
|
Logging.Debug(String.Format("last read: {0}", server.FriendlyName()));
|
|
|
|
ServerStatus status;
|
|
if (_serverStatus.TryGetValue(server, out status))
|
|
{
|
|
status.lastRead = DateTime.Now;
|
|
}
|
|
}
|
|
|
|
public void UpdateLastWrite(Model.Server server)
|
|
{
|
|
Logging.Debug(String.Format("last write: {0}", server.FriendlyName()));
|
|
|
|
ServerStatus status;
|
|
if (_serverStatus.TryGetValue(server, out status))
|
|
{
|
|
status.lastWrite = DateTime.Now;
|
|
}
|
|
}
|
|
|
|
public void SetFailure(Model.Server server)
|
|
{
|
|
Logging.Debug(String.Format("failure: {0}", server.FriendlyName()));
|
|
|
|
ServerStatus status;
|
|
if (_serverStatus.TryGetValue(server, out status))
|
|
{
|
|
status.lastFailure = DateTime.Now;
|
|
}
|
|
}
|
|
}
|
|
}
|