-
Notifications
You must be signed in to change notification settings - Fork 1
Server and client for using clojure as a server, like emacs' server and client
License
Neronus/clj-server
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Time-stamp: <2009-08-09 17:38:52 christian> Christian von Essen <christian@mvonessen.de> This project aims to provide a client-server architecture for clojure. Clojure's startup time is pretty bad. Too bad, in fact, to use it as a platform for scripting. So this project aims to provide a client-server architecture compatible to normal usage of clojure. This means, that if you start the client without parameters, the normal clojure REPL is started, and if you pass a file name, that script is executed, and so forth. In fact, I copied clojure.main and modified it to reflect my needs. To achieve this, a server is listening for incoming connections on a configurable port. If a client connects, the connection is used to transfer data that normally goes through *in* *out* and *err*. This server is intended for local use only. This means, that the server should only listen to 127.0.0.1 or some other loopback address, as the data stream is not encrypted. Furthermore, the authentication scheme only works locally. REQUIREMENTS: To check the file permissions, a POSIX library is required. The one used can be found at http://www.bmsi.com/java/posix/package.html. Alternatively, there is a slightly modified version at http://github.com/Neronus/clj-server/tree/master PROTOCOL: * Authentication: As the server executes arbitrary code, some kind of authentication has to be used. This authentication has to work without user interaction, has to be fast and easy to setup, and should require no third party libraries, if possible. This project uses a file based authentication method: A file, which can only be read by the user who started the server is required. To this end, when the communication between client and server begins, the server send a filename to the client; the client then sends the content of the file to the server, which compares the data sent to the data which it reads from the file. If the recieved data and the file's contents are equal, the connection is accepted, and the command line parameter passing is started. * Command line parameter passing: First, the current working directory is transmitted, then the number of command line arguments, then the command line arguments themself, if there are any. * Communication: Communication is done via sockets, obviously. The client just send its data recieved via stdin to the server. The server OTOH uses a simple protocol to address filedescriptors when printing: Everything that is sent from the server to the client is wrapped into a 'chunk' (idea taken from Nailgun). This chunk has a header consisting of 2 integers (4 byte each): First, the number of the filedescriptor to be addressed is sent, then the size of the chunk. After that, the contents of the chunk are sent. The client recieves the chunk, and forwards the data to the given FD. At the time of writing, only two FDs are supported on the server side: stdout and stederr. USAGE: See the file 'clj-server' in the src/ directory for an example. On the server side, you have to start a clojure instance, create a server socket via (create-server <port> <backlog> <path>) (path is the path of the file used for authorization. should be only readable by the user starting the server), and then go into the accepting loop via (server-loop <server-socket> <minThreads> <maxThreads>), where minThreads is the number of threads you want to have for handling connections, and maxThreads is the maximum number for the same job. On the client side, you have to use the clj-client binary. To configure this binary, there is one environment variable: CLJ_CLIENT_PORT the port to connect to. Other than that, the client should work just like using clojure.main in all cases. Each session gets a unique namespace, exclsuively created for it. After the session terminates, the namespace is deleted. NOTES: * By default, a temporary (that is, only existing for the session) namespace is created. You can change this behaviour by setting or binding clojure-server.main/*gensym-ns* * Using vars (other than that of the temporary namespace) is not a good idea, as they are persistend between sessions, and possibly are set by another script. * Each starting namespace gets a symbol *current-working-directory*, which contains the absolute path of the current working directory of the client.
About
Server and client for using clojure as a server, like emacs' server and client
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published