I've got a huge, ancient codebase in C with a very complex, mature combat system in it. I'm trying to figure out the best way for a trusted, external (outside the MUD codebase) Python process to perform function calls and issue commands directly, while receiving responses for each. The process already telnets in to do most of this, but I'm finding this to be a tough way to do certain operations.
If I'd like to skip telnet and directly communicate from the Python process to the C MUD process, what's the best option? A few things about the setup:
The MUD's event loop currently runs on libevent.
The two processes (Python external and C MUD) run on the same machine, and always will.
I'd like to keep latency down under 10ms per call if possible, assuming an average of 10~ calls/second.
I'll be throwing out big bursts of calls at times (20 or more a second), followed by relative quiet (1-5/second).
I've been looking at some RPC libraries (XML-RPC, some based on protobuff-c, etc), but none have blown my socks off so far. Thrift seems to be more geared towards C++, with poor C support and bad documentation. I took a shot at Twisted's AMP protocol implementation (would have been ideal, probably), but couldn't get it to link and run properly.
I've pondered something hackish with ZeroMQ, but wanted to see if there were any other sane ideas before I get too silly with that.
I'm not super strong with C, so simplicity is a big need initially.
You can certainly use an RPC system, however with the amount of cruft involved in calling between languages (packing and unpacking the data on both ends), it might be just as easy to just open a socket between the two processes and let them talk to each other. The MUD can just accept simple commands from the python script, do whatever it does, and send the results (if any) back.
You already have the command parser for the MUD, and could easily just replace or supercede it with a custom one for that socket only. This is how many old multiplayer strategy games used to handle turn based command files. When you ran the client, it would save all the stuff you did as short text command sequences like "MOVE <unit-number> <new-location>" or "ATTACK <unit-number> <target-unit>". The server would then read in the turn files to process all the players actions during update.
In this case, you could do the same thing except sending the text over a socket and processing them as soon as they arrived.
The plus side is that it's dirt simple and easy to debug.
The minus side is, RPC would be more efficient, if that ends up mattering.
The stuff I'd be sending will be on the more complicated side. This is an old MUX codebase, so I'd be sending and receiving formatted function calls. It sounds like this is best handled by some form of RPC.
I guess the question becomes whether anyone can vouch for some form of RPC in C. I hadn't wanted to write my own crappy protocol, my C is pretty bad.
What is the end goal here? From your description, it seems like you really don't want to have to write / maintain C. Yet, you are also trying to do something that will no doubt tie you to it. Maybe it's a really cool combat system, but I doubt that it's a system that you will never be tempted to tweak / improve / fix if needed. And on the flipside, if you decide to break up with it, you may actually challenge yourself to create something both cooler and simpler.
If you are absolutely in love with what that code does, have you considered porting its essence, or maybe figuring out a way to compile and run it as a shared library somehow? It just doesn't strike me as a very strategic choice to have the stuff where responsiveness matters most be sent to another process and back.
It's looking like protobuf-c could be a good fit for me. Simple socket with struct-based marshalling/unmarshalling. There is a protobuff-c-rpc package, but it looks like it depends on a generic server library that's incompatible with what I'm doing.
Also, it doesn't really care what transport you are using. Straight TCP, ZeroMQ, pipes, etc. That's pretty rad.