using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading;
using Newtonsoft.Json;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using umbraco.interfaces;
namespace Umbraco.Core.Sync
{
///
/// An that works by messaging servers via web services.
///
///
/// this messenger sends ALL instructions to ALL servers, including the local server.
/// the CacheRefresher web service will run ALL instructions, so there may be duplicated,
/// except for "bulk" refresh, where it excludes those coming from the local server
///
//
// TODO see Message() method: stop sending to local server!
// just need to figure out WebServerUtility permissions issues, if any
//
internal class WebServiceServerMessenger : ServerMessengerBase
{
private readonly Func> _getLoginAndPassword;
private volatile bool _hasLoginAndPassword;
private readonly object _locker = new object();
protected string Login { get; private set; }
protected string Password{ get; private set; }
///
/// Initializes a new instance of the class.
///
/// Distribution is disabled.
internal WebServiceServerMessenger()
: base(false)
{ }
///
/// Initializes a new instance of the class with a login and a password.
///
/// The login.
/// The password.
/// Distribution will be enabled based on the umbraco config setting.
internal WebServiceServerMessenger(string login, string password)
: this(login, password, UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled)
{
}
///
/// Initializes a new instance of the class with a login and a password
/// and a value indicating whether distribution is enabled.
///
/// The login.
/// The password.
/// A value indicating whether distribution is enabled.
internal WebServiceServerMessenger(string login, string password, bool distributedEnabled)
: base(distributedEnabled)
{
if (login == null) throw new ArgumentNullException("login");
if (password == null) throw new ArgumentNullException("password");
Login = login;
Password = password;
}
///
/// Initializes a new instance of the with a function providing
/// a login and a password.
///
/// A function providing a login and a password.
/// Distribution will be enabled based on the umbraco config setting.
public WebServiceServerMessenger(Func> getLoginAndPassword)
: base(false) // value will be overriden by EnsureUserAndPassword
{
_getLoginAndPassword = getLoginAndPassword;
}
// lazy-get the login, password, and distributed setting
protected void EnsureLoginAndPassword()
{
if (_hasLoginAndPassword || _getLoginAndPassword == null) return;
lock (_locker)
{
if (_hasLoginAndPassword) return;
_hasLoginAndPassword = true;
try
{
var result = _getLoginAndPassword();
if (result == null)
{
Login = null;
Password = null;
DistributedEnabled = false;
}
else
{
Login = result.Item1;
Password = result.Item2;
DistributedEnabled = UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled;
}
}
catch (Exception ex)
{
LogHelper.Error("Could not resolve username/password delegate, server distribution will be disabled", ex);
Login = null;
Password = null;
DistributedEnabled = false;
}
}
}
// this exists only for legacy reasons - we should just pass the server identity un-hashed
public static string GetCurrentServerHash()
{
if (SystemUtilities.GetCurrentTrustLevel() != System.Web.AspNetHostingPermissionLevel.Unrestricted)
throw new NotSupportedException("FullTrust ASP.NET permission level is required.");
return GetServerHash(NetworkHelper.MachineName, System.Web.HttpRuntime.AppDomainAppId);
}
public static string GetServerHash(string machineName, string appDomainAppId)
{
using (var generator = new HashGenerator())
{
generator.AddString(machineName);
generator.AddString(appDomainAppId);
return generator.GenerateHash();
}
}
protected override bool RequiresDistributed(IEnumerable servers, ICacheRefresher refresher, MessageType messageType)
{
EnsureLoginAndPassword();
return base.RequiresDistributed(servers, refresher, messageType);
}
protected override void DeliverRemote(IEnumerable servers, ICacheRefresher refresher, MessageType messageType, IEnumerable