Hi again Kenton! I finally got around to make the PR (wanted to check it extensively first), it seems to work well: https://github.com/capnproto/pycapnp/pull/169 - I think it works more or less like the BootstrapFactory you described earlier.
This also allowed me to find and fix a little (dangerous) shortcut I took when writing the client - message authorship data was basically sent by client instead of enforced by server, so clients could spoof names if they hacked the program or did some packet filtering. I indeed used a room wrapper for this - the interface is instanced once per client, but the underlying "data-holding" object is instanced once per room (and passed to the interface constructor when the client joins a room). As of yet, rooms don't need to access the client IP, but since they now have a reference to the client object, they can of course get more than just the name. I've been using all the knowledge this allowed me to get on capnchat: https://github.com/Cheaterman/capnchat/ - seems to work fine right now :-) I'm mostly happy with it (except some visual bugs) and will now move on to more serious networking things (multiplayer games come to mind as mentioned :-D). Quick question: as mentioned, my next PR might be about exposing UDP to Python. I think the most maintained way to establish a connection in TwoPartyServer/Client on pycapnp is using connection strings. I was wondering if you think using udp:// prefix in a connection string sounds like a nice way to expose this feature to users (since we already have unix:// for UNIX sockets)? Obviously I'm not asking for a change in Capnp or the C++ side of TwoPartyServer, I'd just implement it at Python level and use bindDatagramPort() instead of listen() at C++ level as mentioned earlier. Thanks again for all your help, and thanks in advance for your answer ^__^ 2018-03-21 17:43 GMT+01:00 The Cheaterman <[email protected]>: > Hi Kenton! > > Thanks for your fantastic answer as usual, I'm sorry I didn't take the > time to respond yesterday but I was implementing the first thing you > suggested! I noticed PyCapnp serves the same instance of the bootstrap > object to all clients (as it is now) so I made the necessary changes to > both re-instanciate the bootstrap object for every cilent, and call its > constructor (and a customizable method) with the client host/port as > arguments, so one can easily track which object is served to which user ; > although in my case - and possibly many others - I will be serving a > "login" interface to the client as bootstrap, and then serve another > capability that will have access to this data as necessary, while tracking > users and rooms in a singleton as I currently do. Why a singleton? Well, I > may need, for instance, all logged in users to be able to communicate with > each other, so I need to keep track of the client capability they send me > at login and their associated nickname (but I probably don't want to keep > track of their host/port there) so that I can serve a client capability to > another user given a username ; or more simply to hold a list of the > available "rooms" so that I can serve them to my clients as requested. > (this might not be the right way to do things in capability-based > environments, so please let me know! I had made an example "new" proto > here, don't know how good it is yet: https://gist.github.com/Cheaterman/ > 767214e4fd04278e1f1eea11c50a83e7 - Login is the bootstrap, and Server is > the capability that will have access to its associated client host/port - I > would wrap its methods just like you suggested with some sort of decorator > or possibly a motherclass to make everything look nice and pretty!) > > I'm going to be cleaning up the commits to PyCapnp I made to have the > bootstrap class be instanced once per client and have its client host/port > be passed to constructor and optional callback, I would love if you could > take a look (I will try to point the relevant locations) to what I did as > the codebase seems to be based on EzRPC so I imagine (despite some of it > being Cython) you would have some great insights as to what seems to be > done right and wrong! > > Speaking of PyCapnp PR's, I will probably be implementing UDP support into > it very soon as well because it seems like it's super simple with KJ? All I > would need is to call bindDatagramPort() instead of listen() on the > NetworkAddress it seems, and I feel like I found the right place, so I'm > going to do that as well relatively soon. > > I don't know if I'll be posting the PR tonight (I need to test it more) > but at least you can get an idea how many things you just set in motion > with your great answer :-) > > Thanks a lot again! I'll keep you in touch about the PR :-) > > > > 2018-03-20 0:09 GMT+01:00 Kenton Varda <[email protected]>: > >> If you've already managed to get the information to your bootstrap >> object, then the right thing to do from there is to have the bootstrap >> object add wrappers to other objects which add knowledge of the IP to them. >> >> For example: >> >> interface Bootstrap { >> getRoom @0 (name :Text) -> (room :Room); >> } >> >> The getRoom() method might do something like: >> >> getRoom(this, name): >> room = rooms.find(name) >> return RoomWrapper(room, this.client_ip) >> >> RoomWrapper is a class that implements the `Room` RPC interface for a >> specific client, with knowledge of that client's IP. Whenever it receives >> an RPC, it can call into the wrapped room object and pass along the IP >> address as well. >> >> This is a common design pattern in Cap'n Proto. Since capnp is >> capability-based, we like to avoid "ambient authority" (information about >> the call context that is not expressed in the parameters). >> >> As for how the bootstrap interface itself gets the info: In C++ there's a >> concept of a BootstrapFactory which receives a callback each time a client >> connects, and receives the identity of the client. I imagine this isn't >> exposed yet in Python, but this would be the way to do it. >> >> -Kenton >> >> On Mon, Mar 19, 2018 at 2:59 PM, The Cheaterman <[email protected] >> > wrote: >> >>> Hi everyone, I hope you're doing great! >>> >>> As you may already know, I'm doing a small chat system to familiarize >>> myself with Capnp before I do more ambitious things. I would like to have >>> some sort of way to implement a banlist on the chat server. I do realize >>> the whole point of capabilities is to have the same behavior no matter >>> where the capability is called from. However, I feel like users >>> (administrators) of server software are used to filter users by IP (when it >>> comes to that). Alternatively, I'd like to find something unique (but >>> persistent for a given computer - OS install? hardware? not sure) I could >>> send during the handshake, to filter undesired users. Basically, I feel >>> like I need some sort of persistent authentication system that's relatively >>> hard to refresh, if I can't get access to the IP:port of the user even in >>> the bootstrap object. I currently managed to hack pycapnp to get a method >>> called on the bootstrap object when a client connects with IP and port as >>> arguments, but even if I store them I have no way of knowing which client >>> calls a given callback (which is a design choice I imagine). >>> >>> I'd like to know your thoughts on the subject :-) thanks a lot in >>> advance! >>> >>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Cap'n Proto" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to [email protected]. >>> Visit this group at https://groups.google.com/group/capnproto. >>> >> >> > -- You received this message because you are subscribed to the Google Groups "Cap'n Proto" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. Visit this group at https://groups.google.com/group/capnproto.
