<div dir="ltr"><div>I have been working in the abstraction of the remote protocol to separate it from the server and the connection.</div><div>The purpose of this is I need to use the Xapian remote protocol in a server we are working on (named Xapiand:</div><div><a href="https://github.com/Kronuz/Xapiand">https://github.com/Kronuz/Xapiand</a>) which is similar to some extent to the `xapian-tcpsrv` in that it also serves</div><div>databases remotely through TCP, using the binary protocol. What is different about it is that it can serve any</div><div>number of databases using an event driven mechanism for receiving and attending clients. Additionally, it also</div><div>serves clients using a custom HTTP protocol which is JSON based and RESTful.</div><div><br></div><div>I have the following commits in my Xapian fork at <a href="https://github.com/Kronuz/xapian/commits/master">https://github.com/Kronuz/xapian/commits/master</a>:</div><div><br></div><div><br></div><div><div>1. Remote protocol with support for selection of database directory</div><div>-------------------------------------------------------------------</div><div><br></div><div>If the user requests to open a remote database server, it can optionally require</div><div>the remote backend to tell the server what database it wants to open, if the</div><div>remote server is configured as a server without a default directory</div><div>(xapian-tcpsrv remains to always have a default directory at the moment).</div><div><br></div><div>The binary protocol was changed in the way that a new command can be sent to</div><div>the server (MSG_SELECT) in case the server tells the client no default directory</div><div>is selected, the server then reacts to this command by opening and selecting the</div><div>requested database as the active database.</div><div><br></div><div><br></div><div>2. Split msg_query and msg_getmset</div><div>----------------------------------</div><div><br></div><div>Originally, `msg_query()` handled two commands by the client: `MSG_QUERY` and</div><div>also `MSG_GETMSET` (which was marked as "used during a conversation"). This</div><div>changes this and makes it so `msg_query()` returns even when the client hasn't</div><div>yet sent a `MSG_GETMSET`, but instead only keeping the current satate of the</div><div>query in the `MatchState` struct and setting the expected `required_type` for</div><div>the next command.</div><div><br></div><div>The purpose of this is that an event based remote protocol server might still</div><div>not yet have the `MSG_GETMSET` message from the client as a response, and it'd</div><div>be bad practice (or catastrophic) to block the thread while the message arrives.</div><div>This blocking (if any) should be handled further up, by the event loop.</div><div><br></div><div><br></div><div>3. Method run() split in two: run() and run_one()</div><div>-------------------------------------------------</div><div><br></div><div>The method run() calls run_one() in a loop, but we don't always want this</div><div>behavior. The reason is, again, event based messaging might decide to start</div><div>attending other clients on the same thread without blocking, thus an infinite</div><div>while for these type of servers is not desired.</div><div><br></div><div><br></div><div>4. Abstract RemoteProtocol class added</div><div>--------------------------------------</div><div>RemoteServer extends from abstract RemoteProtocol, and only implements a few</div><div>members needed by the protocol. This effectively separates the protocol from the</div><div>connection and the server.</div><div><br></div><div>RemoteProtocol with virtual abstract methods for:</div><div><br></div><div>* get_message - Receives a new message (waiting when needed).</div><div>* send_message - Sends a message to the client.</div><div>* get_db - Reserves a database when the class needs to use it.</div><div>* release_db - Releases the database when the class is not using it.</div><div>* select_db - It's called when the protocol needs to select a new database to work on.</div><div>* shutdown - It's called when the protocol requires to shutdown.</div><div><br></div><div>Each command in the RemoteProtocol now do a two additional things:</div><div><br></div><div>1. Use get_db() to reserve and get a read-only or writable database.</div><div>2. Relese the reserved database using release_db()</div><div><br></div><div>Implements RemoteProtocol on the RemoteServer:</div><div><br></div><div>* get_db - Always returns the same database object (db or wdb)</div><div>* release_db - Does nothing in this server (database is never released).</div><div>* get_message and send_message - Call RemoteConnection methods.</div><div><br></div><div><br></div><div>5. RemoteProtocol implementation moved to remoteprotocol.cc</div><div>-----------------------------------------------------------</div><div><br></div><div>Added `remoteprotocol.cc` with the implementation of `RemoteProtocol` and header</div><div>file remoteprotocol.h with added `RemoteProtocol` abstract class definition</div><div>moved to `include/xapian/remoteprotocol.h`</div><div><br></div><div>The reason for this is other projects might want to use the `RemoteProtocol`</div><div>class for implementing a custom remote server. Xapiand is one of these projects.</div><div>(<a href="https://github.com/Kronuz/Xapiand">https://github.com/Kronuz/Xapiand</a>)</div></div><div><br></div><div><br></div><div>Please, any comments and feedback would be appreciated.</div><div><br></div><div>German M. Bravo (Kronuz)</div><div><br></div></div>