2014-08-13 10:39:27 +01:00
//
// CustomPeerResolverService.cs
//
// Author:
// Marcos Cobena (marcoscobena@gmail.com)
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright 2007 Marcos Cobena (http://www.youcannoteatbits.org/)
//
// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Net.Sockets ;
using System.Transactions ;
using System.Timers ;
namespace System.ServiceModel.PeerResolvers
{
[MonoTODO ("Implement cleanup and refresh")]
[ ServiceBehavior ( ConcurrencyMode = ConcurrencyMode . Multiple ,
InstanceContextMode = InstanceContextMode . Single ,
UseSynchronizationContext = false ) ]
public class CustomPeerResolverService : IPeerResolverContract
{
static ServiceHost localhost ;
2017-10-19 20:04:20 +00:00
static int port ;
2014-08-13 10:39:27 +01:00
static void SetupCustomPeerResolverServiceHost ( )
{
2017-10-19 20:04:20 +00:00
string customPort = Environment . GetEnvironmentVariable ( "MONO_CUSTOMPEERRESOLVERSERVICE_PORT" ) ;
if ( customPort = = null | | ! int . TryParse ( customPort , out port ) )
port = 8931 ;
2014-08-13 10:39:27 +01:00
// launch peer resolver service locally only when it does not seem to be running ...
2017-10-19 20:04:20 +00:00
var t = new TcpListener ( port ) ;
2014-08-13 10:39:27 +01:00
try {
t . Start ( ) ;
t . Stop ( ) ;
} catch {
return ;
}
Console . WriteLine ( "WARNING: it is running peer resolver service locally. This means, the node registration is valid only within this application domain..." ) ;
var host = new ServiceHost ( new LocalPeerResolverService ( TextWriter . Null ) ) ;
host . Description . Behaviors . Find < ServiceBehaviorAttribute > ( ) . InstanceContextMode = InstanceContextMode . Single ;
2017-10-19 20:04:20 +00:00
host . AddServiceEndpoint ( typeof ( ICustomPeerResolverContract ) , new BasicHttpBinding ( ) , $"http://localhost:{port}" ) ;
2014-08-13 10:39:27 +01:00
localhost = host ;
host . Open ( ) ;
}
ICustomPeerResolverClient client ;
bool control_shape , opened ;
TimeSpan refresh_interval , cleanup_interval ;
public CustomPeerResolverService ( )
{
2017-10-19 20:04:20 +00:00
client = ChannelFactory < ICustomPeerResolverClient > . CreateChannel ( new BasicHttpBinding ( ) , new EndpointAddress ( $"http://localhost:{port}" ) ) ;
2014-08-13 10:39:27 +01:00
refresh_interval = new TimeSpan ( 0 , 10 , 0 ) ;
cleanup_interval = new TimeSpan ( 0 , 1 , 0 ) ;
}
public TimeSpan CleanupInterval {
get { return cleanup_interval ; }
set {
if ( ( value < TimeSpan . Zero ) | | ( value > TimeSpan . MaxValue ) )
throw new ArgumentOutOfRangeException (
"The interval is either zero or greater than max value." ) ;
if ( opened )
throw new InvalidOperationException ( "The interval must be set before it is opened" ) ;
cleanup_interval = value ;
}
}
public bool ControlShape {
get { return control_shape ; }
set {
if ( opened )
throw new InvalidOperationException ( "The interval must be set before it is opened" ) ;
control_shape = value ;
}
}
public TimeSpan RefreshInterval {
get { return refresh_interval ; }
set {
if ( ( value < TimeSpan . Zero ) | | ( value > TimeSpan . MaxValue ) )
throw new ArgumentOutOfRangeException (
"The interval is either zero or greater than max value." ) ;
if ( opened )
throw new InvalidOperationException ( "The interval must be set before it is opened" ) ;
refresh_interval = value ;
}
}
[MonoTODO ("Do we have to unregister nodes here?")]
public virtual void Close ( )
{
if ( ! opened )
throw new InvalidOperationException ( "The service has never been opened or it was closed by a previous call to this method." ) ;
client . Close ( ) ;
opened = false ;
if ( localhost ! = null ) {
localhost . Close ( ) ;
localhost = null ;
}
}
public virtual ServiceSettingsResponseInfo GetServiceSettings ( )
{
if ( ! opened )
throw new InvalidOperationException ( "The service has never been opened or it was closed previously." ) ;
return client . GetServiceSettings ( ) ;
}
public virtual void Open ( )
{
if ( localhost = = null )
SetupCustomPeerResolverServiceHost ( ) ;
if ( ( CleanupInterval = = TimeSpan . Zero ) | | ( RefreshInterval = = TimeSpan . Zero ) )
throw new ArgumentException ( "Cleanup interval or refresh interval are set to a time span interval of zero." ) ;
if ( opened )
throw new InvalidOperationException ( "The service has been started by a previous call to this method." ) ;
opened = true ;
client . Open ( ) ;
client . SetCustomServiceSettings ( new PeerServiceSettingsInfo ( ) { ControlMeshShape = control_shape , RefreshInterval = refresh_interval , CleanupInterval = cleanup_interval } ) ;
}
public virtual RefreshResponseInfo Refresh ( RefreshInfo refreshInfo )
{
if ( refreshInfo = = null )
throw new ArgumentException ( "Refresh info cannot be null." ) ;
if ( ! opened )
throw new InvalidOperationException ( "The service has never been opened or it was closed previously." ) ;
return client . Refresh ( refreshInfo ) ;
}
public virtual RegisterResponseInfo Register ( RegisterInfo registerInfo )
{
if ( registerInfo = = null )
throw new ArgumentException ( "Register info cannot be null." ) ;
if ( ! opened )
throw new InvalidOperationException ( "The service has never been opened or it was closed previously." ) ;
return client . Register ( registerInfo ) ;
}
public virtual RegisterResponseInfo Register ( Guid clientId , string meshId , PeerNodeAddress address )
{
return Register ( new RegisterInfo ( clientId , meshId , address ) ) ;
}
public virtual ResolveResponseInfo Resolve ( ResolveInfo resolveInfo )
{
if ( resolveInfo = = null )
throw new ArgumentException ( "Resolve info cannot be null." ) ;
if ( ! opened )
throw new InvalidOperationException ( "The service has never been opened or it was closed previously." ) ;
return client . Resolve ( resolveInfo ) ;
}
public virtual void Unregister ( UnregisterInfo unregisterInfo )
{
if ( unregisterInfo = = null )
throw new ArgumentException ( "Unregister info cannot be null." ) ;
if ( ! opened )
throw new InvalidOperationException ( "The service has never been opened or it was closed previously." ) ;
client . Unregister ( unregisterInfo ) ;
}
public virtual RegisterResponseInfo Update ( UpdateInfo updateInfo )
{
if ( updateInfo = = null )
throw new ArgumentException ( "Update info cannot be null." ) ;
if ( ! opened )
throw new InvalidOperationException ( "The service has never been opened or it was closed previously." ) ;
return client . Update ( updateInfo ) ;
}
}
}