blob: dc015e2b73934d0af64c246ccc9bc70e62e4cfbf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using Proto = Apache.Rocketmq.V2;
namespace Org.Apache.Rocketmq
{
public class Endpoints : IEquatable<Endpoints>
{
private const string HttpPrefix = "http://";
private const string HttpsPrefix = "https://";
private const int DefaultPort = 80;
private static readonly AddressListEqualityComparer AddressListComparer = new AddressListEqualityComparer();
private const string EndpointSeparator = ":";
public List<Address> Addresses { get; }
private AddressScheme Scheme { get; }
private readonly int _hashCode;
public Endpoints(Proto.Endpoints endpoints)
{
Addresses = new List<Address>();
foreach (var address in endpoints.Addresses)
{
Addresses.Add(new Address(address));
}
if (!Addresses.Any())
{
throw new NotSupportedException("No available address");
}
switch (endpoints.Scheme)
{
case Proto.AddressScheme.Ipv4:
Scheme = AddressScheme.Ipv4;
break;
case Proto.AddressScheme.Ipv6:
Scheme = AddressScheme.Ipv6;
break;
case Proto.AddressScheme.DomainName:
case Proto.AddressScheme.Unspecified:
default:
Scheme = AddressScheme.DomainName;
if (Addresses.Count > 1)
{
throw new NotSupportedException("Multiple addresses are not allowed in domain scheme");
}
break;
}
unchecked
{
var hash = 17;
hash = (hash * 31) + AddressListComparer.GetHashCode(Addresses);
hash = (hash * 31) + (int)Scheme;
_hashCode = hash;
}
}
// TODO: Multiple addresses has not been supported yet.
public Endpoints(string endpoints)
{
if (endpoints.StartsWith(HttpPrefix))
{
endpoints = endpoints[HttpPrefix.Length..];
}
if (endpoints.StartsWith(HttpsPrefix))
{
endpoints = endpoints[HttpsPrefix.Length..];
}
var index = endpoints.IndexOf(EndpointSeparator, StringComparison.Ordinal);
var port = index > 0 ? int.Parse(endpoints[(1 + index)..]) : DefaultPort;
var host = index > 0 ? endpoints.Substring(0, index) : endpoints;
var uriHostNameType = Uri.CheckHostName(host);
Scheme = AddressScheme.DomainName;
switch (uriHostNameType)
{
case UriHostNameType.IPv4:
Scheme = AddressScheme.Ipv4;
break;
case UriHostNameType.IPv6:
Scheme = AddressScheme.Ipv6;
break;
case UriHostNameType.Dns:
case UriHostNameType.Basic:
case UriHostNameType.Unknown:
default:
Scheme = AddressScheme.DomainName;
break;
}
var address = new Address(host, port);
var addresses = new List<Address> { address };
Addresses = addresses;
unchecked
{
var hash = 17;
hash = (hash * 31) + AddressListComparer.GetHashCode(Addresses);
hash = (hash * 31) + (int)Scheme;
_hashCode = hash;
}
}
public override string ToString()
{
foreach (var address in Addresses)
{
return address.Host + EndpointSeparator + address.Port;
}
throw new ArgumentException("No available address");
}
// TODO: Support multiple addresses.
public string GrpcTarget(bool sslEnabled)
{
var prefix = sslEnabled ? HttpsPrefix : HttpPrefix;
foreach (var address in Addresses)
{
return prefix + address.Host + EndpointSeparator + address.Port;
}
throw new ArgumentException("No available address");
}
public bool Equals(Endpoints other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Addresses.SequenceEqual(other.Addresses) && Scheme == other.Scheme;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return obj.GetType() == GetType() && Equals((Endpoints)obj);
}
public override int GetHashCode()
{
return _hashCode;
}
public Proto.Endpoints ToProtobuf()
{
var endpoints = new Proto.Endpoints();
foreach (var address in Addresses)
{
endpoints.Addresses.Add(address.ToProtobuf());
}
endpoints.Scheme = AddressSchemeHelper.ToProtobuf(Scheme);
return endpoints;
}
}
}