• Stars
    star
    473
  • Rank 92,832 (Top 2 %)
  • Language
    Emacs Lisp
  • License
    GNU General Publi...
  • Created about 14 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

evented io webserver right inside your emacs.

Elnode

An evented IO webserver in Emacs Lisp.

Requirements

Elnode will not run properly on anything less than Emacs 24. Elnode requires Emacs 24's lexical binding as it makes extensive use of closures.

Rationale

Elnode is a great for these things:

  • nice simple server with few dependancies (just Emacs and cat basically)
  • prototyping webapps
  • browser testing
  • asynchronous apps, like chat apps

Installation

Elnode is packaged in marmalade.

For dealing with package repositories check out the Emacs Wiki but the short version is to add the following to your .emacs or your .emacs.d/init.el:

(add-to-list 
   'package-archives
   '("marmalade" . "http://marmalade-repo.org/packages/"))

And then do:

M-x list-packages

find Elnode in the list and press i or ENTER to install it.

If you don't want to use packages you can just install elnode.el on your load-path somewhere and:

(require 'elnode)

Install from this repository

Installing from the sources is complex and requires the dependancies declared in the file recipes/elnode.

The recipe file is used by elpakit or other tools to build the package.

elpakit can help build elnode, and help with running tests. Install elpakit from marmalade and then you can build Elnode with elpakit by doing:

M-x elpakit-make-multi

in the Elnode directory.

You can build the Elnode package and run the Elnode tests on that package with the following lisp:

(elpakit-test (list elnode-directory) 'elnode-tests 'elnode)

Where elnode-directory specifies your local Elnode repository directory.

The list can include more repository directories which will be combined into a single package archive.

Out of the box

When Elnode initializes it automatically starts a webserver and a Wiki engine.

If you:

M-x customize-group
elnode

you can alter a number of variables pertaining to the default configuration, including the directory used to keep files.

By default the package installs files in your .emacs.d - it uses a directory called elnode for the Wiki root and the webroot. Both are configurable with Elnode config variables.

You can also just ignore the built in stuff completely and write your own servers.

What Elnode servers are running?

Elnode tracks the servers an Emacs instance is running and you can see the view of that with:

M-x list-elnode-servers

The list shows TCP ports and handlers and you can press return on a handler and move to it's source code definition.

You can kill a server by hitting "k" on it.

How does it work?

The simplest thing that Elnode does is let you start a webserver on a directory:

M-x elnode-make-webserver [RET] 
Serve files from: [enter directory] [RET]
TCP Port (try something over 8000): 8009 [RET]

and there will be a webserver started on port 8009 serving files from whatever directory you specified.

By default Elnode starts that server on the host specified by elnode-init-host which is a variable you can customize:

M-x customize-variable [RET] elnode-init-host [RET]

Take care though, you don't want to expose your Emacs session to the Internet.

You can also use the prefix key to specify the host for just this one server:

C-u M-x elnode-make-webserver [RET] 
Docroot: [enter directory] [RET]
Port: 8009 [RET]
Host: 0.0.0.0

Basic Elnode for programmers

Elnode's power is most visible to programmers though.

You can define a handler function:

(defun my-test-handler (httpcon)
  "Demonstration function"
  (elnode-http-start httpcon 200 '("Content-type" . "text/html"))
  (elnode-http-return httpcon "<html><b>HELLO!</b></html>"))

And then start the server:

(elnode-start 'my-test-handler :port 8010 :host "localhost")

You can also start the server interactively... with:

M-x elnode-start

it interactively asks for the handler function and a port.

Stopping the server

If you can remember the port you started your server on then you'll be able to stop it, like:

(elnode-stop 8010)

You can also stop interactively:

M-x elnode-stop

API

Mapping paths to handlers

elnode-hostpath-dispatcher takes a-list of path/handler mappings:

##!emacs-lisp
(defvar 
   my-app-routes 
   '(("^my-host.example.com//wiki/\\(.*\\)" . elnode-wikiserver)
     ("^admin.example.com//admintool/\\(.*\\)" . user-admin)
     ("^.*//\\(.*\\)" . elnode-webserver)))

(defun root-handler (httpcon)
  (elnode-hostpath-dispatcher httpcon my-app-routes))

(elnode-start 'root-handler :port 8009)

This will create a server on port 8009 being handled by root-handler which will root the requests to the appropriate handler.

Any request for the host my-host.example.com with the path /wiki/ will be sent to the Elnode Wiki engine.

Any request for the host admin.example.com with the path /admintool/ will be sent to the user-admin handler, presumably that is defined somewhere.

Any other request will be sent to the default Elnode webserver.

Elnode itself uses a hostpath dispatcher on the default Elnode server. This can actually be configured with the variable elnode-hostpath-default-table, so you can actually change the default behaviour of the Elnode default server just with Emacs config.

The use of regexs in Elnode's mapping is supported by other tools. Sub-expressions are capturable in mapping support routines such as elnode-docroot-for.

When a handler is called by elnode-hostpath-dispatcher then the parts of the match are available through the function elnode-http-mapping. So we could code the user-admin handler like this:

##! emacs-lisp
(defun user-admin (httpcon)
  (let ((username (elnode-http-mapping httpcon 1)))
    (user-admin-send-admin-page httpcon username)))

The (elnode-http-mapping httpcon 1) accesses the first sub-expression of the regex that caused the match:

     ("^admin.example.com//admintool/\\(.*\\)" . user-admin)

so, everything AFTER the admintool/.

Some tools in Elnode do this for you, so you don't have to. Again, look at elnode-docroot-for.

Serving files

There are several helpers for serving files with Elnode. You can serve directories of files directly by making a webserver handler. A function elnode-webserver-handler-maker can make webservers:

##! emacs-lisp

(setq my-webserver
      (elnode-webserver-handler-maker "~/my-webroot"))

(elnode-start my-webserver :port 8010)

The Elnode webserver also produces index pages and can be configured with a number of variables:

  • elnode-webserver-index-page-template defines the page template used for the index
  • elnode-webserver-index-file-template defines the template for each file in the index, normally it's just an A tag ponting to the file.

More controlled serving

If you need more control over serving files you can write handlers with elnode-docroot-for. This does a lot of complex work for you to map a directory tree to a webserver namespace.

This example shows how to use elnode-docroot-for

##! emacs-lisp

(defun elnode-org-handler (httpcon)
  (elnode-docroot-for "~/work/org"
      with org-file
      on httpcon
      do (with-current-buffer (find-file-noselect org-file)
           (let ((org-html
                  ;; This might throw errors so you could condition-case it
                  (org-export-as-html 3 nil nil 'string)))
             (elnode-send-html httpcon org-html)))))

The first argument is the directory of files which you want to serve, then with variable specifies the name of a variable to use in the body of the code which will be bound to the filename of the file the user wants. Then on httpcon specifies the HTTP connection to use and then do .... specifies the code to use.

elnode-docroot-for processes incomming requests on the httpcon you specify by checking the request matches a file in the directory you specify (it sends a 404 if it does not find one).

It also does last modified caching on the file and sends an HTTP 304 response if the file has not been updated since the last request.

If a matching file exists and the it is not cached then elnode-docroot-for runs the do code to send the response correctly.

Sending files

Elnode also has elnode-send-file for sending files to the response, along with elnode-docroot-for this makes a powerful simple webserver tool. elnode-send-file can be used to send any arbitary file:

##! emacs-lisp
(defun my-status-page (httpcon)
  (elnode-http-start httpcon 200 '("Content-type" . "text/html"))
  (elnode-send-file httpcon "~/static-status-file.html"))

A handler that will only ever respond with one static file. Of course, this isn't very interesting, combined with elnode-docroot-for it can be used to serve directories and the like, or you could work out the filename to be sent with some other method.

There is another use for elnode-send-file which is simple templating. You can pass parameters to elnode-send-file and it will template them into the file:

(defun my-templater(httpcon)
  (let ((hash (make-hash-table 
                 :test 'equal 
                 :data "username" "nicferrier")))
     (elnode-http-start httpcon 200 '("Content-type" . "text/html"))
     (elnode-send-file 
         httpcon "~/my-template.html" 
         :replacements hash)))

The template file must have sections marked up like:

<<html &lt;!##E username E##!&gt; html>>

for each of the variables.

This makes for simple but quite powerful templating.

Really Really simple file sending

It's also possible to make send file functions automatically so if you want to map a handler that serves just one file in a dispatcher that's possible:

##! emacs-lisp
`(("^my-host.example.com//wiki/\\(.*\\)" . elnode-wikiserver)
  ("^.*//styles.css" . ,(elnode-make-send-file "~/mainstyles.css"))
  ("^.*//\\(.*\\)" . elnode-webserver))

It's also possible to use templating with this style of programming by passing a function returning the alist variable map as :replacements:

##! emacs-lisp
(defun my-templater ()
  '(("username" . "william occam")))

`(("^my-host.example.com//wiki/\\(.*\\)" . elnode-wikiserver)
  ("^.*//styles.css" . ,(elnode-make-send-file 
                           "~/mainstyles.css"
                           :replacements 'my-templater))
  ("^.*//\\(.*\\)" . elnode-webserver))

This makes templating and setting up very simple websites very easy indeed.

Accessing data in the HTTP request

There are a bunch of functions that do what you would expect about data in the HTTP request:

##! emacs-lisp

(elnode-http-method httpcon)
=> "POST"

(elnode-http-pathinfo httpcon)
=> "/wiki/blah.creole"

(elnode-http-query httpcon)
=> "a=10&b=20&c=the+quick+brown+fox"

(elnode-http-params httpcon)
=> (("a" . "10")("b" . "20")("c" . "the quick brown fox"))

(elnode-http-param httpcon "username")
=> "nicferrier"

(elnode-http-cookie httpcon "session-id")
=> "1213313"

(elnode-http-header httpcon "Date")
=> "Mon, Feb 27 2012 22:10:21 GMT"

(elnode-http-header httpcon 'date)
=> "Mon, Feb 27 2012 22:10:21 GMT"

(elnode-http-header httpcon 'date :time) ;; with convert flag set to :time
=> (20299 65357)

Note that Elnode generally can accept symbol's as well as strings to name things, if it can't it's a bug, please report it.

Also, Elnode can handle some conversions sometimes. I would like to respond to user demand about when and where to do that and what to do. Please give me feedback.

Elnode's raw data

Elnode stores most of it's internal state on the connection object and it's all accessible via a macro elnode/con-get.

Some interesting properties and how to access them:

##! emacs-lisp

(elnode/con-get httpcon :elnode-http-status)
=> "GET / HTTP/1.1"

(elnode/con-get httpcon :elnode-http-resource)
=> "/"

(elnode/con-get httpcon :elnode-http-version)
=> "1.1"

These are not supported by Elnode at all, there is no guarantee that the names of these properties won't change. If you feel that you want official support (ie: a function) then make an issue on the Elnode github.

To Do?

If you're playing with elnode but you can't think of anything to do with it...

  • make an elnode param handler that sanitzes input
    • one way to do that was found by aidalgol:
(require 'htmlize)
(htmlize-protect-string
 "<a href='/blah?a=10&b=2'></a><script>call_func()</script>")
  • an emacsclient with elnode
    • write a command line client that submits data to the server over HTTP
    • it should interact with the emacs user in the same way that emacs server does
    • why? because then a single Emacs could have just 1 server socket open for all sorts of different roles
  • alter elnode-webserver-handler-maker to do indexing better
    • take an optional index producing function?
    • take keyword flags that set the behaviour?
    • eg: :doindexes 't
  • browse-current-buffer
    • start an elnode server on some random port exposing the current buffer
    • automatically open a browser on the started server

More Repositories

1

elmarmalade

emacs-lisp version of the marmalade package repository
Emacs Lisp
112
star
2

emacs-web

a useful HTTP client in EmacsLisp
Emacs Lisp
76
star
3

emacs-noflet

noflet - nic's overriding flet, for fleting functions for the purpose of decorating them
Emacs Lisp
72
star
4

emacs-db

very simple database for emacslisp, can also wrap other databases.
Emacs Lisp
56
star
5

emacs-ejit

Javascript compiler for EmacsLisp
Emacs Lisp
53
star
6

emacs-kv

Key/Value collection type functions: for alists, hashtables and plists. Useful stuff.
Emacs Lisp
48
star
7

elpakit

Let's you build repositories and archives of repositories.
Emacs Lisp
28
star
8

pgdevbox

postgresql dev box - a simple way to get pg working locally
HTML
28
star
9

docker-shell-deploy

a shell script to help with deploying dockers
26
star
10

emacs-fakir

functions and macros to fake bit of Emacs core libraries, like files and processes.
Emacs Lisp
26
star
11

eshell-manual

eshell is great but lacks a good manual, someone wrote one. This packages it.
Emacs Lisp
20
star
12

emacs-contributor-guide

The success of Emacs depends on participation from people like you.
18
star
13

org-presie

Very very very simple presentation mode for Org.
Emacs Lisp
18
star
14

elwikicreole

A WikiCreole parser for EmacsLisp
Emacs Lisp
17
star
15

emacs-world-time-mode

A mode showing your world time alist formatted as a list of whole days with the differing times.
Emacs Lisp
15
star
16

shoes-off

an IRC bouncer written in EmacsLisp
Emacs Lisp
13
star
17

emacs-nm

Emacs interface to Gnome's Network Manager
Emacs Lisp
12
star
18

emacs-pipe

use pipes to communicate with processes in Emacs
Emacs Lisp
11
star
19

md

a maildir client and library
Python
11
star
20

elnode-org

tools and utils for hacking org files with elnode
Emacs Lisp
10
star
21

emacs-maildir

maildir based mail user agent just in emacs-lisp
Emacs Lisp
10
star
22

emacs-uuid

The UUID module from the EmacsWiki, initially by someone called James Mastros.
Emacs Lisp
10
star
23

gnudoc-js

An example GNU doc viewer as a single page browser app
JavaScript
10
star
24

nodejs-self-signed-cert-server-and-client

How to do a self signed cert in nodejs with a client and a server
JavaScript
10
star
25

keepie

Keep passwords and hand them out to authorized endpoints.
JavaScript
9
star
26

phantomjsel

phantomjs handling for emacs
Emacs Lisp
9
star
27

emacs-lxc

lxc tools for emacs
Emacs Lisp
9
star
28

java-fake-socket

How to fake sockets with real connectivity but no wires.
Java
9
star
29

emacs-sql-postgres

Nic's tools for wrangling postgres in Emacs. Notably plpgsql indentation.
Emacs Lisp
9
star
30

emacs-in-a-docker

Dockerfile to build emacs
Shell
9
star
31

docker-bash-completion

Docker completion for the BASH shell
9
star
32

rcirc-notify

Notifications for rcirc, the emacs IRC client
Emacs Lisp
8
star
33

cranker

A pair of servers to implement a scaling scheme.
Clojure
7
star
34

emacs-nic-java-ac

A relic. My old Java complete stuff. I've toyed with Java again and this may be useful.
Emacs Lisp
7
star
35

emacs-meetup

meetup integration with emacs
Emacs Lisp
7
star
36

emacs-clojure-env

Build a clojure-env from inside Emacs
Emacs Lisp
6
star
37

virtualbox

hacking on virtualbox to allow adding limiting of what boxes you start
C
5
star
38

cards

A p2p card game.
JavaScript
5
star
39

elpastebin

emacs lisp interface to pastebin
Emacs Lisp
5
star
40

niclein

simple leiningen integration for Emacs
Emacs Lisp
5
star
41

jarnode

Make node apps sit inside uberjars
C
5
star
42

emacs-twaddle

A sane Twitter client for Emacs.
Emacs Lisp
5
star
43

eimp

Rather good Emacs Image Manipulation library. This is not mine, I am just adopting it for a few reasons.
Emacs Lisp
5
star
44

creole-mode

A WikiCreole mode for Emacs.
Emacs Lisp
4
star
45

curl-url-retrieve

url-retrieve with curl
Emacs Lisp
4
star
46

elpad

elnode pad - collab editing in emacs via the web
JavaScript
4
star
47

java-simple-sse-client

A simple and sadly synchronous Java EventSource
Java
4
star
48

emacs-provisioner-vagrant

Provision Emacs instances and stuff on top of it with Vagrant
Ruby
4
star
49

emacs-mp

multi-procesing for emacs, using daemons as a concurrency enabler.
Emacs Lisp
4
star
50

org-email

Use org as a contact database
Emacs Lisp
4
star
51

elisp-indexer

massive load of work to slightly improve the emacs help system
Emacs Lisp
4
star
52

emacs-docker-swarm

a docker for swarming around emacs
Shell
3
star
53

emacs-marmalade-upload

a simple marmalade upload client for uploading packages from inside Emacs
Emacs Lisp
3
star
54

emacs-swarmhacker

Simple tools for swarm hacking.
Emacs Lisp
3
star
55

nicsblog

Nic's blog files and control code
JavaScript
3
star
56

crontub

a tub of cron
Python
3
star
57

emacsbites

webiste driving my emacs tapas
Emacs Lisp
3
star
58

emacs-proc-net

Manage Emacs Network Processes - network connections and listening sockets.
Emacs Lisp
3
star
59

sqlserver-event-demo

a demo of event sending with MS SQL Server and Node JS
JavaScript
3
star
60

skinny

a blog engine so cool it wears skinny jeans
Emacs Lisp
2
star
61

emacs-git-draft

draft a commit log change from the git index diff
Emacs Lisp
2
star
62

elnode-agenda

get org-mode agenda in your browser
Emacs Lisp
2
star
63

emacs-initd

emacs daemon startup and service script
2
star
64

pyproxyfs

a simple proxy filesystem object for python, with a simple mock.
Python
2
star
65

emacs-lisp-editing-tools

tools for lisp editing
Emacs Lisp
2
star
66

ntlm-java

java ntlm proxy
Java
2
star
67

secondarys

csv files to build lists of secondarys
Python
2
star
68

timelog

a simple shell script time logging application via dhcp
Shell
2
star
69

emacs-js-check

Do eslint of JS files as you type.
Emacs Lisp
2
star
70

lxmlproc

an lxml version of xsltproc
Python
2
star
71

emacs-plsql

Kal Hodgson's plsql mode
Emacs Lisp
2
star
72

java-mindex

Maven Indexer - index all your maven repository
Java
2
star
73

emacs-ci-demo

Demonstration repo for emacs vagrant provisioning.
Emacs Lisp
2
star
74

elwikidoc

make creole wiki from emacs lisp functions
Emacs Lisp
2
star
75

elnode-and-lisp-pres

Elnode and the history of Lisp: a presentation with less beards than you think.
Emacs Lisp
2
star
76

emacs-framesize

allow frame font size to be controlled with keys.
Emacs Lisp
1
star
77

nics-emacs-config

A new config for emacs for my Windows (!) machine
Emacs Lisp
1
star
78

json-editor

a browser based JSON editor which could be extended with different schemas
JavaScript
1
star
79

elisp-process

Elisp process tools. Mainly this is tools for starting and stopping types of Emacs process.
Emacs Lisp
1
star
80

emacs-vagrant-box-nginx

nginx config to download the emacs vagrant box
1
star
81

django-muphan

A Django media hub handler app
Python
1
star
82

nics-json-parser

a JSON parser that models the actual JSON document accurately - so it's good for use with a schema.
JavaScript
1
star
83

seville-marmalade

marmalade provisioning
Puppet
1
star
84

emacs-livecoding

live coding helpers
Emacs Lisp
1
star
85

graph-table

a webservice to help graphing data.
Python
1
star
86

nics-sheet

having a go at making a web based spreadsheet thing
JavaScript
1
star
87

emacs-isea

Inferior shell to an Emacs Daemon
Emacs Lisp
1
star
88

plaintalk

just a thing
ActionScript
1
star
89

emacs-ertx

Extensions for Emacs ERT
Emacs Lisp
1
star
90

pinpop-shop

A little ecommerce system
JavaScript
1
star
91

emacs-s-buffer

string operations on emacs buffers
Emacs Lisp
1
star
92

emacs-dists

Nic's emacs dists
Python
1
star
93

wush

web user shell
JavaScript
1
star
94

elnode-linky

A silly little link app
Emacs Lisp
1
star
95

emacs-db-pg

Postgresql adapter for emacs-db. Uses Hstores to model a kv store.
Emacs Lisp
1
star
96

apacheawk

make awk useful for parsing access log files
Awk
1
star
97

emacs-spork

a spork is a combination of a fork and spoon. yes.
Emacs Lisp
1
star
98

emacs-atlassian

confluence editing tool
Emacs Lisp
1
star
99

xfmedia_scrobbler

a scrobbler for xfmedia
1
star
100

npm-forge-ca-4-tests

A test CA
JavaScript
1
star