Coder Social home page Coder Social logo

emacs-epc's Introduction

EPC : The Emacs RPC

This program is an asynchronous RPC stack for Emacs. Using this RPC stack, the Emacs can communicate with the peer process smoothly. Because the protocol employs S-expression encoding and consists of asynchronous communications, the RPC response is fairly good.

Current implementations for the EPC are followings:

The current status is beta. This library needs more applications to confirm stability of the API and robustness of the implementation.

Applications

Projects using EPC:

Sample Code

Here is a client code.

(require 'epc)

(setq epc (epc:start-epc "perl" '("echo-server.pl")))

(deferred:$
  (epc:call-deferred epc 'echo '(10))
  (deferred:nextc it 
    (lambda (x) (message "Return : %S" x))))

(deferred:$
  (epc:call-deferred epc 'add '(10 40))
  (deferred:nextc it 
    (lambda (x) (message "Return : %S" x))))

;; calling synchronously
(message "%S" (epc:call-sync epc 'echo '(10)))

;; Request peer's methods
(message "%S" (epc:sync epc (epc:query-methods-deferred epc)))

(epc:stop-epc epc)

Here is a server code in perl.

#!/usr/bin/perl

use RPC::EPC::Service;

sub echo_test {
    my $methods = {
    
        'echo' => [sub {
            my $args = shift;
            return $args;
        },"args","just echo back arguments."],
        
        'add' => sub {
            my $args_ref = shift;
            my ($a,$b) = @$args_ref;
            return $a + $b;
        }
    };
    my $server = RPC::EPC::Service->new(0, $methods);
    $server->start;
}

echo_test();

Here is the equivalent server code in emacs lisp.

(require 'epcs)

(let ((connect-function
       (lambda (mngr) 
         (epc:define-method mngr 'echo (lambda (&rest x) x) "args" "just echo back arguments.")
         (epc:define-method mngr 'add '+ "args" "add argument numbers.")
         )) server-process)

  (setq server-process (epcs:server-start connect-function))
  (sleep-for 10)
  (epcs:server-stop server-process))

The elisp server code should be started with some arguments (batch starting and indicating load paths) like the following code:

(setq epc (epc:start-epc "emacs" '("-L" ".." "-L" "~/.emacs.d/elisp" "-batch" "-l" "deferred" "-l" "concurrent" "-l" "epc" "-l" "epcs" "-l" "echo-server.el")))

Installation

Package installation

If you use package.el with MELPA (http://melpa.org/), you just select the package epc and install it.

Manual installation

This program depends on following programs:

Place those programs and this one (epc.el) in your load path and add following code.

(require 'epc)

API Document

This section describes the overview of the EPC and how to use API.

API Overview

The EPC uses a peer-to-peer-architecture. After the connection is established, both peers can define remote methods and call the methods at the other side.

Let we define the words server and client. Server is a process which opens a TCP port and waiting for the connection. Client is a process which connects to the server. In most cases, a client process starts a server process. Then, the server process provides some services to the client process.

This diagram shows the API usage and the relation of processes.

API Overview

Object Serialization

All values which are transferred as arguments and return values between processes, are encoded into the S-expression text format.

The EPC uses S-expression as an object serialization format, not JSON. In these days, JSON is widely employed and many environments has some JSON serializers. However, JSON is not the best format for IPC from the point of view of serialization speed. The current Emacs implementation (23.x and 24.x) can read/write JSON format with json.el about 5-10 times slower than S-expression one. Since the Emacs interpreter is often slower than other interpreters or VMs, we should choose a format so that Emacs can deal faster. In addition, S-expression has good expression power as well as JSON does. So, the EPC stack uses S-expression, though we need more work for writing S-expression serializers on the peer side. (In the future, we may use JSON when Emacs can read/write JSON in native library...)

Simple list structure and some primitive types can be transferred. Complicated objects, such as buffer objects, can not be serialized. The EPC stack doesn't provide transparent remote object service, that is ORB.

The EPC stack can translate following types:

  • nil
  • symbol
  • number
  • string
  • list
  • complex object of list and alist.

The elisp function prin1 is employed for the serialization from objects to string.

The peer EPC stack decodes the S-expression text and reconstructs appropriate objects in the particular language environment.

You may want to translate an alist as a collection object of key-value pairs transparently, so called Hash. However, because we can not distinguish between alist and nested list, it is responsible for the programmer to exchange the alist objects and the hash objects.

EPC Manager Object (epc:manager)

The struct epc:manager defines all information for an EPC activity, such as the connection status, remote methods and sessions. Many API functions needs the instance object as an argument. You, however, doesn't have to learn the internal slots and detailed implementations.

An instance of the struct epc:manager is created by calling the initialization function epc:start-epc. You can stop the EPC connection with calling the termination function epc:stop-epc.

Start EPC (epc:start-epc)

  • epc:start-epc (server-prog server-args)
    • Start the epc server program, establish the connection and return an epc:manager object.
    • Argument
      • server-prog: a path string for the server program
      • server-args: a list of command line arguments
    • Return
      • This function blocks the evaluation and returns an epc:manager object.
    • Error
      • If the server prints out non-numeric value in the first line or does not print out the port number in three seconds, it is regarded as start-up failure.

The established EPC session is registered to the global variable for the connection management interface. (See the Management Interface section.)

Stop EPC (epc:stop-epc)

  • epc:stop-epc (mngr)
    • Disconnect the connection and kill the server process.
    • If the epc:manager object has exit hooks, this function executes those clean-up hooks.
    • Argument
      • an epc:manager object

Define Remote Method (epc:define-method)

  • epc:define-method (mngr method-name task &optional arg-specs docstring)
    • Define a remote method
    • Argument
      • mngr: epc:manager object
      • method-name: the method name
      • task: function symbol or lambda
      • arg-specs: argument signature for the remote method [optional]
      • docstring: short description for the remote method [optional]
    • Return
      • an epc:method object

The documents are referred by the peer process for users to inspect the methods.

Call Remote Method (epc:call-deferred, epc:call-sync)

  • epc:call-deferred (mngr method-name args)
    • Call the remote method asynchronously.
    • Argument
      • mngr: epc:manager object
      • method-name: the method name to call
      • args: a list of the arguments
    • Return
      • Deferred object
      • See the next section for the error handling
  • epc:call-sync (mngr method-name args)
    • Call the remote method synchronously.
    • Argument
      • mngr: epc:manager object
      • method-name: the method name to call
      • args: a list of the arguments
    • Return
      • a result from the remote method

Error Handling

The remote method calling may raise the error. The error has two types, the peer's program (application-error) and the EPC stack (epc-error).

The application-error is a normal error which is caused by peer's program, such as 'division by zero', 'file not found' and so on. The programmers are responsible to this type errors, recovering error handling or just fixing bugs.

The epc-error is a communication error which is caused by EPC stack, such as 'connection closed', 'method not found', 'serialization error' and so on. This type errors are caused by environment problems, bugs of peer's program, our side one or the EPC stack.

Here is a sample robust code:

(deferred:$
    (epc:call-deferred mngr "a-method" '(1 2))
    (deferred:next it
        (lambda (x)
            ;; Normal return
            ;; x: result value
            ))
    (deferred:error it
        (lambda (err)
         (cond
          ((stringp err)
            ;; application error
            ;; err: error message
           )
          ((eq 'epc-error (car err))
            ;; epc error
            ;; err: (cadr err) -> error information
           )))))

In the case of synchronous calling, a signal will be thrown immediately.

Utilities

  • epc:live-p (mngr)
    • If the EPC stack for mngr is eastablished, this function returns t.
  • epc:query-methods-deferred (mngr)
    • Return a list of epc:method objects for the peer process.

Define Server

Following functions require the epcs package.

  • epcs:server-start (connect-function &optional port)
    • Start EPC manager stack and initialize the manager with connect-function.
    • Argument
      • connect-function: a function symbol or lambda with one argument mngr, in which function the manager should define some remote methods.
      • port: TCP port number. (default: determined by the OS)
    • Return
      • process object

Here is a sample code for the EPC server:

(require 'epcs)

(let ((connect-function
       (lambda (mngr) 
         (epc:define-method mngr 'echo (lambda (x) x) "args" "just echo back arguments.")
         (epc:define-method mngr 'add '+ "args" "add argument numbers.")
         )) server-process)

  (setq server-process (epcs:server-start connect-function))

  ;; do something or wait for clients

  (epcs:server-stop server-process))
  • epcs:server-stop (process)
    • Stop EPC manager stack.
    • Argument
      • process: process object

Debug

Because the EPC stack is designed to work asynchronously, sometimes you can not use the debugger for the own programs. Then, logging is useful to analyze the troubles.

The EPC has some debug functions for analyzing low level communication.

  • epc:debug-out
    • If this variable is non-nil, the EPC stack records events and communications into the debug buffer.
  • epc:debug-buffer
    • debug buffer name (default: 'epc log')
  • epc:log (&rest args)
    • logging debug messages

Management Interface

The EPC has a management interface for the EPC connections. Users can check the current connection status, inspect method specs and terminate the connection.

Current Connections

Executing M-x epc:controller, you can display the list of current established connections.

Current Connections

This table shows following information:

Column Note
Process Process name
Proc Process status (process-status for the process)
Conn Connection status (process-status for the TCP connection)
Title Connection title which is defined by the EPC user program.
Command Process command and arguments.
Port TCP port which is opened by the remote process.
Methods Number of methods which are defined at the Emacs side.
Live sessions Number of sessions which are waiting for a return value.

This management buffer provides following key-bind:

Key Command Note
g epc:controller-update-command Refresh the table.
R epc:controller-connection-restart-command Restart the selected connection.
D,K epc:controller-connection-kill-command Kill the selected process and connection.
m,RET epc:controller-methods-show-command Display a method list of the remote process. (See the next sub-section for details.)
B epc:controller-connection-buffer-command Display the connection buffer.

Remote Method List

Displaying a method list, you can inspect the methods which are defined by the remote process.

Remote Method List

This table shows following information:

Column Note
Method Name Method name to call.
Arguments [optional] Argument names.
Document [optional] Method spec document.

Here, 'Arguments' and 'Document' columns may be blank, because those are not essential slots.

Key Command Note
e epc:controller-methods-eval-command Evaluate the selected remote method with some arguments.
q bury-buffer Bury this buffer.

Implementation

This section describes the EPC architecture and the wire-protocol so as to implement the peer stacks.

Protocol Details

The EPC protocol is based on the SWANK protocol.

Message Envelope

A message consists of 6 bytes content-length and a subsequent payload content. The payload content is a S-expression string. The S-expression is a cons cell, car is message type symbol and cdr is message body list.

  • PAYLOAD-LENGTH : 24-bit hex-encoded integer
  • PAYLOAD-CONTENT : S-expression, text, utf-8
    • (MESSAGE-TYPE . MESSAGE-BODY-LIST)

The message type can be chosen from call, return, return-error, epc-error and methods. The message body varies according to the message type.

  • MESSAGE-TYPE : call | return | return-error | epc-error | methods
  • MESSAGE-BODY-LIST : (Dependent on message types.)

Message [call]

This message represents calling a peer's method.

  • MESSAGE-BODY-LIST : (UID METHOD-NAME ARGS)
    • UID : The session ID, which is an unique ID generated by the caller side.
    • METHOD-NAME : A symbol for method name.
    • ARGS : A list of method arguments.

Message [return]

This message represents a return value for normal finish of the method calling.

  • MESSAGE-BODY-LIST : (UID RETURN-VALUE)
    • UID : The session ID to return.
    • RETURN-VALUE : A return object.

Message [return-error]

This message represents an application error, which is due to the application.

  • MESSAGE-BODY-LIST : (UID ERROR-MESSAGE)
    • UID : The session ID to return.
    • ERROR-MESSAGE : An error message.

Message [epc-error]

This message represents an EPC error, which is due to the EPC stack.

  • MESSAGE-BODY-LIST : (UID ERROR-MESSAGE)
    • UID : The session ID to return.
    • ERROR-MESSAGE : An error message.

Message [methods]

This message represents a method query.

  • MESSAGE-BODY-LIST : (UID)
    • UID : The session ID, which is an unique ID generated by the caller side.

The response message is returned by the return message.

EPC Internal

The EPC is developed on deferred.el and concurrent.el. The library deferred.el provides primitive an asynchronous framework and concurrent.el does concurrent programing components.

The EPC user should learn asynchronous programing on deferred.el. The components of concurrent.el are just internally used at epc.el.

EPC Stack

Here is a diagram for the epc.el architecture, which diagram may be helpful for code reading of epc.el.

Internal Architecture

Other Stacks

License

EPC is licensed under GPL v3.

Acknowledgment

I received generous support from @tkf. Thanks!


(C) 2012, 2013, 2014, 2015 SAKURAI Masashi. m.sakurai at kiwanami.net

emacs-epc's People

Contributors

edwardbetts avatar kiwanami avatar niku avatar ramnes avatar syohex avatar tkf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emacs-epc's Issues

concurrent or defferred?

emacs-epc requires 'concurrent, which isn't provided.
Maybe it should use 'defferred ?

Thanks!

Call メソッド の仕様について

Python の EPC binding (https://github.com/tkf/python-epc) を書いているんですが、 call メソッド の仕様について質問があります。

epc:call-deferred の call signature は

(epc:call-deferred MNGR METHOD-NAME ARGS)

となっていますが、 ARGS にはリスト以外のオブジェクト、例えば int を入れてもサーバーに送れるようです。サーバー側で method を呼ぶ際に

  1. method(ARGS)
  2. method(ARGS[0], ARGS[1], ..., ARGS[-1])

の二通りの呼び方があると思うのですが、 ARGS がリスト以外も受け付ける必要がある場合、 2. の呼び方は出来ません。ただ、 1. の呼び方だと method 内部で ARGS を分解する必要があって、面倒です。 1. と 2. のどちらの呼び方を採用すべきですか?

Is EPC + concurrent only on 24.4+?

Currently running Emacs 24.3.1, trying to install jedi => epc => concurrent => deferred.

EPC (20140609.2234 in MELPA) lists concurrent as a direct dependency.
Concurrent (0.3.1 => 20161228.1930) lists 'emacs-24.3' and deferred (0.5.0) as dependencies.
Deferred (0.5.0 => 20170901.630) lists 'emacs-24.4' as a dependency, which is not satisfied by. Does this imply that the minimum version of emacs epc is usable with is 24.4 implicitly? It seems strange for concurrent to be compatible with different versions than it's own dependency.

Specify the type of UID in readme.md.

I could not know the the type of the session ID.

In readme.md, UID is said to be following:

UID : The session ID, which is an unique ID generated by the caller side.

I thought, UID should be String but it actually is Integer.

Could you specify the type in readme.md?
(or, Can I use String instead of Integer?)

README の気になった点など

README 充実しましたね! README あると使ってて安心します。

いくつか気になった点がありました。


The EPC stack can translate following types:

  • nil
  • symbol
  • number
  • string
  • list
  • alist
  • complex object of list and alist.

とありますが、 ここで alist を特別扱いする必要はありますか? リテラルとして listcons (. の扱い) がパース出来れば、 alist を特別扱いする必要は無い気がします。 alist を hash table とかに自動的に変換する必要があれば別ですが、そもそも受け取ったリストが alist かどうかを確実に判断することは不可能なのでそれは無理だと思います。


EPC が双方向にメソッド呼び出しが可能だという特徴が抜けている気がします。 例えば、 API Overview の図だと、クライアントがサーバーを呼び出す使い方しか見せてません。 あまり RPC 詳しく無い人が見ると、なんで epcs: 以下じゃなくて epc: 以下に epc:define-method があるんだ、って思うかもしれません (というか私がそうでした)。


あと細かい所だと API Overview の図で epc:call-deferred のリプライを示す矢印が無いのが気になりました...。

How can I connect to existing process with specified ports?

Hi.

I'm currently working on EPC implementation on Scala (called Scala-elrpc).

I want to use Scala-elrpc to connect to running GUI application, but I don't know how.
Can I use epc:start-epc-debug or is there no way to do that?

(defun epc:start-epc-debug (port)
  "[internal] Return an epc:manager instance which is set up partially."
  (epc:init-epc-layer
   (make-epc:manager :server-process nil
                     :commands (cons "[DEBUG]" nil)
                     :port port
                     :connection (epc:connect "localhost" port))))

Thank you for your help.

Suspicious arguments for epc:process-available-input

epc:process-available-input の末尾の epc:run-when-idle ですが、引数に connection も必要じゃないでしょうか?

diff --git a/epc.el b/epc.el
index 1fbee87..b15d9d6 100644
--- a/epc.el
+++ b/epc.el
@@ -165,7 +165,7 @@ return epc:connection object."
 (defun epc:process-available-input (connection process)
   "Process all complete messages that have arrived from Lisp."
   (with-current-buffer (process-buffer process)
     (while (epc:net-have-input-p)
       (let ((event (epc:net-read-or-lose process))
             (ok nil))
         (epc:log "<< RECV [%S]" event)
         (unwind-protect
             (condition-case err
                 (progn
                   (apply 'cc:signal-send 
                          (cons (epc:connection-channel connection) event))
                   (setq ok t))
               ('error (epc:log "MsgError: %S / <= %S" err event)))
           (unless ok
-            (epc:run-when-idle 'epc:process-available-input process)))))))
+            (epc:run-when-idle 'epc:process-available-input connection process)))))))

 (defun epc:net-have-input-p ()
   "Return true if a complete message is available."

Doom Emacs: Package CL is Depreciated => Latest Version

I was currently installing packages and found the error that emacs displays when i open it up in doom version. I found out that the Unicode module/package is the reason for the message. The moment I installed this package the message above started to show. As soon as I commented the Unicode module the message no longer appeared. So boys, You better find an alternative to the Unicode module in doom emacs.

Error Occurs when:
Unicode
Error is solved when:
;; Unicode

I will submit an alternative to the Unicode package when i find one.

How to tell to peer about error due to S-exp decoding

Python EPC のバグで時々 Emacsから送られてきた s-exp のデコードをミスってエラーを出してしまうのですが、この場合どうやってエラーを通知したら良いんでしょうか。 epc-error で通知しようにも s-exp のデコード前なので uid が不明です。とりあえず uid=0 や nil を返せば "RET-EPC-ERR: NOT FOUND:" と通知してくれるようなので、その方針でいこうと思いますが、いつかプロトコルがはっきりすると良いなと思います。

どちらにせよ Python EPC のバグを直せば問題にならないので急ぎのリクエストでは無いのですが、気になったので。

tkf/emacs-jedi#7 (comment)

No README

This project has no README.

I arrived here from a site that has this project as a dependency, which suggests this project is for real and meant to be used, but it is extremely off-putting that there is not even the smallest README.

At a minimum, I'd expect to find

  • indication of status - is this experimental/alpha/beta/stable etc. If it is totally experimental, that's fine, I know not to use it, but one line to tell me so would be extremely useful.
  • license information
  • installation instructions
  • docs link
  • or, a link to a site that will contain all of the above.

My normal policy is "docs or it doesn't exist"

Thanks!

process epc con 3 not running

M x : webkit-open-url to open url.
I got this error.
system : ubuntu 16.04 LTS
emacs : gnuemacs 26
how i fix this problem?
help me . please

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.