-
Notifications
You must be signed in to change notification settings - Fork 9
Review API from Revamp PR #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
public sealed class ClientConfig : UiPath.Ipc.EndpointConfig, System.IEquatable<UiPath.Ipc.ClientConfig> | ||
{ | ||
public ClientConfig() { } | ||
public string DebugName { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not clear what DebugName does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a CoreIpc-traditional tagging mechanism for reading logs and understanding who's who.
I didn't like how Name
sounded (it seemed more functional than it actually was), so I prefixed it with Debug
.
On support/v21.10
the public ones were ListenerSettings.Name and Connection.Name, both of which are public, and which spin off into internals
(i.e. ServiceClient
inherits the Name
from it's associated Listener
if it's of the callback sort) and all end up in logs, from hundreds of places, i.e: this
{ | ||
protected ClientTransport() { } | ||
public abstract UiPath.Ipc.IClientState CreateState(); | ||
public abstract void Validate(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should think if we really need the Validate feature?
public System.TimeSpan RequestTimeout { get; init; } | ||
} | ||
[System.Serializable] | ||
public sealed class EndpointNotFoundException : System.ArgumentOutOfRangeException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not an argument out of range problem
argument out of range is if we could know statically that the argument is outside of the input domain
public abstract class ListenerConfig : UiPath.Ipc.EndpointConfig, System.IEquatable<UiPath.Ipc.ListenerConfig> | ||
{ | ||
protected ListenerConfig() { } | ||
public System.Security.Cryptography.X509Certificates.X509Certificate? Certificate { get; init; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was this in CoreIpc?
why do we expose this? is it for websocket only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it was, and it was agnostic than merely websockets;
I was wondering the same thing.
We use CoreIpc over Tcp/Ipc, but I can't find a precise usage for this certificate thing.
We have 0 websocket usage.
[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("exception")] | ||
public static UiPath.Ipc.Error? FromException(System.Exception? exception) { } | ||
} | ||
public interface IClient |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IClientConnection name would be better:
- we have the usecase in which we identify the same connection in hashset
- the callback is only valid for that client connection, not if recreated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, but we'll have to discuss whether what you said still holds.
public UiPath.Ipc.IClient Client { get; set; } | ||
[Newtonsoft.Json.JsonIgnore] | ||
public System.TimeSpan RequestTimeout { get; set; } | ||
public TCallbackInterface GetCallback<TCallbackInterface>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe it wouldn't be that bad to force the user to go through IClient(Connection) 😓 . it tells you more e.g. how long the callback is valid, but mostly for the reduced surface area.
"your compiler.", true)] | ||
public IpcServer() { } | ||
public UiPath.Ipc.EndpointCollection Endpoints { get; init; } | ||
public System.Collections.Generic.IReadOnlyList<UiPath.Ipc.ListenerConfig> Listeners { get; init; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can improve the entity model to have better matching between client and server, and generally to simplify it.
The only real relationship differences I can see:
- A client has a single connection while a listener has many. I don't see any problem with the API regarding this.
- A server can have multiple transport configurations "listeners". Of note, we could drop this feature of multiple listeners. A user could simply create more servers calling the same configuration code.
I'd propose this model:
Endpoints = { Client, Server }
Endpoint = (IServiceProvider, Scheduler, RequestTimeout)
Client : Endpoint + (ClientTransport)
Server : Endpoint + (ServerTransport)
} | ||
namespace UiPath.Ipc.Extensibility | ||
{ | ||
public interface IListenerConfig<TSelf, TListenerState, TConnectionState> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IListenerConfig vs ListenerConfig not obvious.
Why other namespace not obvious.
Maybe you'd want to move all transport stuff into UiPath.Ipc.Transport (client included), but I don't see the need.
Too many generics, one of the problems we wanted to avoid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, and we need to discuss it a bit, but this is exclusively for the select few who will do (maybe) a Blazor JSInterop transport.
"_accepter"})] | ||
public void Start() { } | ||
public System.Threading.Tasks.Task WaitForStart() { } | ||
public System.Threading.Tasks.Task WaitForStop() { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what;s the differentce between WaitForStop() and DisposeAsync()?
I'd like to avoid supporting the "restart" scenario.
public System.Threading.Tasks.TaskScheduler? Scheduler { get; set; } | ||
public object? ServiceInstance { get; } | ||
public System.IServiceProvider? ServiceProvider { get; } | ||
public void Validate() { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you've added ServiceProvider and scheduler to IpcBase - so we'd be good to remove them from here, right?
1150dc4
to
9f3573b
Compare
- other simplifications
9f3573b
to
0339141
Compare
- decommission WaitForStop
public bool NewConnection { get; } | ||
} | ||
public abstract class ClientTransport : System.IEquatable<UiPath.Ipc.ClientTransport> { } | ||
public class ContractCollection : System.Collections.Generic.IEnumerable<UiPath.Ipc.ContractSettings>, System.Collections.IEnumerable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's debatable, and based on preference, but if we would have builder methods to add "contracts", for example AddServiceType(Type...) and AddServiceInstance(Type, object), we wouldn't have to expose the ContractCollection class and its dependencies (ContractSettings). Also, the API using fluent builder methods would be easier to use for me, as a CoreIPC user. But again - it's a matter of opinion.
} | ||
namespace UiPath.Ipc.Transport.NamedPipe | ||
{ | ||
public sealed class NamedPipeClientTransport : UiPath.Ipc.ClientTransport, System.IEquatable<UiPath.Ipc.Transport.NamedPipe.NamedPipeClientTransport> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could avoid exposing the whole Transport hierarchy (with abstract classes and all). Even if they look like only "configuration objects", in reality they are the runtime classes. It would be easier/cleaner to add fluent builder interfaces when building the IpcServer and IpcClient and hide the transport classes. Again - more of an opinion.
"Transport", | ||
"_accepter"})] | ||
public void Start() { } | ||
public System.Threading.Tasks.Task WaitForStart() { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need WaitForStart anywhere? If we do, what about Start being async?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a CoreIpc server user, how can I know if a client connected or disconnected?
Or how can I simply send something to the client, without this operation being triggered by a request from the client?
It seems these are missing, no? Maybe not required by Robot, but seems pretty basic.
protected IpcBase() { } | ||
public System.TimeSpan RequestTimeout { get; set; } | ||
public System.Threading.Tasks.TaskScheduler? Scheduler { get; set; } | ||
public System.IServiceProvider? ServiceProvider { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ServiceProvider is mandatory when we don't provide instances for Enpoints or Callbacks but types/interfaces? It's not obvious when building the IpcClient/IpcServer, and we will get a runtime error much later (not during building phase).
Personal opinion: We shouldn't bother with dependency injection in CoreIPC, it's not its responsibility. As a user of CoreIPC, even if I use dependency injection, I would probably want to use constructor injection myself for a service that creates the IpcServer, and give the instances to the IpcServer myself. It's also a matter of responsibilities. CoreIPC shouldn't have the responsibility of building service instances itself. The fact that objects are either given by me, or by the service provider seems also a little bit inconsistent.
But I guess the problem is deeper, because the IpcServer is just a declarative method, and we might want to create a new service instance for each client, but this is abstracted away from the user, so this change might require some rethinking, and a long discussion.
Example how I would do this:
var server = new Server (...);
server.OnClientConnected( (client) =>
{
client.RegisterService(calculatorService);
client.GetProxy() ... etc... }
}
then we can take the client and add it into a list, and so on...
Very broadly speaking, with this design, CoreIPC makes a step towards a high level library like SIgnalR, but it's a very small step, and it's not enough, and the downside is that it's hiding all the low level stuff.
No description provided.