UNPKG

5.75 kBJavaScriptView Raw
1#!/usr/bin/env node
2/* eslint-disable no-console */
3/*
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17'use strict';
18
19const app = require('express')();
20const bodyParser = require('body-parser');
21const Template = require('@accordproject/cicero-core').Template;
22const Clause = require('@accordproject/cicero-core').Clause;
23const Engine = require('@accordproject/cicero-engine').Engine;
24
25if(!process.env.CICERO_DIR) {
26 throw new Error('You must set the CICERO_DIR environment variable.');
27}
28
29const PORT = process.env.CICERO_PORT | 6001;
30
31// to automatically decode JSON POST
32app.use(bodyParser.json());
33
34// set the port for Express
35app.set('port', PORT);
36
37/**
38 * Handle POST requests to /trigger/:template
39 * The clause is created using the template and the data.
40 *
41 * Template
42 * ----------
43 * The template parameter is the name of a directory under CICERO_DIR that contains
44 * the template to use.
45 *
46 * Request
47 * ----------
48 * The POST body contains three properties:
49 * - request
50 * - data
51 * - state (optional - for stateless execution)
52 *
53 * Response
54 * ----------
55 * JSON formated response object
56 *
57 */
58app.post('/trigger/:template', async function (req, httpResponse, next) {
59 try {
60 const clause = await initTemplateInstance(req);
61
62 const engine = new Engine();
63 let result;
64 if(Object.keys(req.body).length === 3 &&
65 Object.prototype.hasOwnProperty.call(req.body,'request') &&
66 Object.prototype.hasOwnProperty.call(req.body,'state') &&
67 Object.prototype.hasOwnProperty.call(req.body,'data')) {
68 clause.setData(req.body.data);
69 result = await engine.trigger(clause, req.body.request, req.body.state);
70 } else if(Object.keys(req.body).length === 2 &&
71 Object.prototype.hasOwnProperty.call(req.body,'request') &&
72 Object.prototype.hasOwnProperty.call(req.body,'data')) {
73 const state = { '$class' : 'org.accordproject.cicero.contract.AccordContractState', 'stateId' : 'ehlo' };
74 clause.setData(req.body.data);
75 result = await engine.trigger(clause, req.body.request, state);
76 delete result.state;
77 } else {
78 throw new Error('Missing request, state or data in /trigger body');
79 }
80 httpResponse.send(result);
81 }
82 catch(err) {
83 return next(err);
84 }
85});
86
87/**
88 * Handle POST requests to /parse/:template
89 * The body of the POST should contain the sample text.
90 * The clause is created using the template, parsing the text and if parsing succeeds returning the contract data.
91 *
92 * Template
93 * ----------
94 * The template parameter is the name of a directory under CICERO_DIR that contains
95 * the template to use.
96 *
97 * Request
98 * ----------
99 * The POST body contains three properties:
100 * - sample
101 *
102 * Response
103 * ----------
104 * A data string containing the parsed output
105 *
106 */
107app.post('/parse/:template', async function (req, httpResponse, next) {
108 try {
109 const clause = await initTemplateInstance(req);
110 if(Object.keys(req.body).length === 1 &&
111 Object.prototype.hasOwnProperty.call(req.body,'sample')) {
112 clause.parse(req.body.sample.toString());
113 httpResponse.send(clause.getData());
114 } else {
115 throw new Error('Missing sample in /parse body');
116 }
117 } catch(err) {
118 return next(err);
119 }
120});
121
122/**
123 * Handle POST requests to /draft/:template
124 * The body of the POST should contain the request data and any options.
125 * The clause is created using the template and the data.
126 * The call returns the text of the contract.
127 *
128 * Template
129 * ----------
130 * The template parameter is the name of a directory under CICERO_DIR that contains
131 * the template to use.
132 *
133 * Request
134 * ----------
135 * The POST body contains three properties:
136 * - data
137 * - options
138 *
139 * Response
140 * ----------
141 * A string containing the draft output
142 *
143 */
144app.post('/draft/:template', async function (req, httpResponse, next) {
145 try {
146 const clause = await initTemplateInstance(req);
147 if(Object.keys(req.body).length === 1 &&
148 Object.prototype.hasOwnProperty.call(req.body,'data')) {
149 clause.setData(req.body.data);
150 httpResponse.send(clause.draft());
151 } else if(Object.keys(req.body).length === 2 &&
152 Object.prototype.hasOwnProperty.call(req.body,'data') &&
153 Object.prototype.hasOwnProperty.call(req.body,'options')) {
154 clause.setData(req.body.data);
155 httpResponse.send(clause.draft(req.body.options));
156 } else {
157 throw new Error('Missing data or options in /draft body');
158 }
159 }
160 catch(err) {
161 return next(err);
162 }
163});
164
165/**
166 * Helper function to initialise the template.
167 * @param {req} req The request passed in from endpoint.
168 * @returns {object} The template instance object.
169 */
170async function initTemplateInstance(req) {
171 const template = await Template.fromDirectory(`${process.env.CICERO_DIR}/${req.params.template}`);
172 return new Clause(template);
173}
174
175const server = app.listen(app.get('port'), function () {
176 console.log('Server listening on port: ', app.get('port'));
177});
178
179module.exports = server;
\No newline at end of file