Download - Building GUI App with Electron and Lisp
How Building GUI App with Lisp The Case of Pocket Change, Inc.
LISP MEETUP #50 Mar 27, 2017
I’m Eitaro Fukamachi @nitro_idiot fukamachi
Joined Pocket Change in Feb 1
Available at Haneda Airport
Today’s topic
What I want to tell today
What I don’t tell
How we use Common Lisp in our work
How you can use Common Lisp in your work
Touch Screen
Coins BillsIC Card Reader
Receipt Printer
API Server
Touch Screen
Coins BillsIC Card Reader
Receipt Printer
API Server
Building the next version of this software is my work.
How to build Pocket Change
• Windows OS (Rich!)
• Fullscreen GUI application
Web Server (Express)
Main Process (Node.js)
Open
Web Server (Express)
Main Process (Node.js)
Open
Web Server (Express)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
Open
Web Server (Express)
Main Process (Node.js)
Bidirectional Communication
Renderer Process (Chromium)
React.js
Why Electron?
• Easy to deploy
• Can package into a single EXE installer
• Can build GUI with Web technologies
• Embedded Chromium
However
The language is JavaScript. 👎
Why can’t we use Common Lisp?
None (just a launcher)
Main Process (Node.js)
+ Common Lisp
Open
None (just a launcher)
Main Process (Node.js)
+ Common Lisp
Open
None (just a launcher)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
+ Common Lisp
Open
None (just a launcher)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
Spawn
+ Common Lisp
Open
None (just a launcher)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
Common Lisp Process (SBCL)
Spawn
+ Common Lisp
Open
None (just a launcher)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
Common Lisp Process (SBCL)
Spawn
Bidirectional Communication
+ Common Lisp
Open
None (just a launcher)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
Common Lisp Process (SBCL)
Spawn
Bidirectional Communication
+ Common Lisp
Make an SBCL executable and bundle it
Looks a quite easy trick, huh? :)
How communicating between CL and Browser
Open
None (just a launcher)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
Common Lisp Process (SBCL)
Spawn
Bidirectional Communication
+ Common Lisp
Open
None (just a launcher)
Main Process (Node.js)
Renderer Process (Chromium)
React.js
Common Lisp Process (SBCL)
Spawn
Bidirectional Communication
+ Common Lisp
Communication between CL and Browser
• MUST be bidirectional
• MUST be asynchronous
• MUST be easy to handle with JavaScript
• SHOULD be real-time
We decided to use JSON-RPC
• Small specification
• Not depends on a specific transport layer
• We use WebSocket
• http://jsonrpc.org
• https://github.com/fukamachi/jsonrpc
JSON-RPC--> {"jsonrpc": “2.0", "method": “subtract", "params": [42, 23], "id": 1}
Request
JSON-RPC--> {"jsonrpc": “2.0", "method": “subtract", "params": [42, 23], "id": 1}
Request
<-- {"jsonrpc": “2.0", "result": 19, "id": 1}
Response
JSON-RPC--> {"jsonrpc": “2.0", "method": “subtract", "params": [42, 23], "id": 1}
Request
<-- {"jsonrpc": “2.0", "result": 19, "id": 1}
Response
--> {"jsonrpc": “2.0", "method": “update", "params": [1,2,3,4,5]}
Notification (Request without “id”)
How to structure GUI Application with Electron
No best practices (yet) to build an Electron app.
In our case
Renderer Process
Store
View
Action Reducer
Flux Architecture
functionfunctionfunctionfunctionfunctionfunctionfunctionfunctionfunctionfunctionfunction
Renderer Process
Store
View
ActionReducer
Flux Architecture
Common Lisp
JSON-RPC serverfunctionfunctionfunction
functionfunctionfunction
← JSON-RPC over WebSocket →
Not only Browser ⇔ Common Lisp
Coin Counter IC Card Reader PrinterAPI Server
Benefits of Flux + JRPC Architecture
• JavaScript part is just a UI renderer
• Business logics are all in Common Lisp
• Common Lisp functions are easy to test
• Other components are also easy to test
• Because they all talk in JSON-RPC
How to develop the app
Development
• You can use your machine (Mac, Linux, etc)
• Virtual devices are used while development
• Easy to make a mock of components
Development
1. Run a Electron process (npm run dev)
2. Open REPL of the Common Lisp process from Emacs with Swank
3. Enjoy
Packaging
1. Run Windows in Virtual Environment
2. npm run package
3. Wait
Experiments
Coin Counter IC Card Reader PrinterAPI Server
Coin Counter IC Card Reader PrinterAPI Server
Hard to share data.
“brain”, the central storage
• All data(state) are in Common Lisp part
• What service the user chose?
• How much money is in the user’s IC card?
• How many coins are in?
• etc.
• It’s just a hash-table (with thread-lock).
“Propagation Class”Metaclass for synchronize data between components
“Propagation Class”
(defclass user () ((balance :initarg :balance :accessor user-balance) (coins :initarg :coins :accessor user-coins)) (:metaclass propagation-class))
“Propagation Class”
(defclass user () ((balance :initarg :balance :accessor user-balance) (coins :initarg :coins :accessor user-coins)) (:metaclass propagation-class))
(defmethod on-update ((user user) slot-name) (declare (ignore slot-name)) (notify “browser” “user/update-state” user))
“Propagation Class”
(defvar *user* (make-instance ‘user …)))
;; Notify this modification ;; to the browser implicitly. (setf (user-balance *user*) 1730)
Bless the Meta Object Protocol.
So, Why Common Lisp?
Why Common Lisp?
• We ♥ Common Lisp :)
• Good for writing unknown/complicated applications.
• Interactive development with REPL.
Thanks.