UNPKG

3.28 kBJavaScriptView Raw
1var Emitter = require("events").EventEmitter;
2var repl = require("repl");
3var util = require("util");
4
5var priv = new Map();
6
7// Ported from
8// https://github.com/jgautier/firmata
9
10function Repl(opts) {
11 if (!Repl.isActive) {
12 Repl.isActive = true;
13
14 if (!(this instanceof Repl)) {
15 return new Repl(opts);
16 }
17
18 // Store context values in instance property
19 // this will be used for managing scope when
20 // injecting new values into an existing Repl
21 // session.
22 this.context = {};
23 this.ready = false;
24
25 var state = {
26 opts: opts,
27 board: opts.board,
28 };
29
30 priv.set(this, state);
31
32 // Store an accessible copy of the Repl instance
33 // on a static property. This is later used by the
34 // Board constructor to automattically setup Repl
35 // sessions for all programs, which reduces the
36 // boilerplate requirement.
37 Repl.ref = this;
38 } else {
39 return Repl.ref;
40 }
41}
42
43// Inherit event api
44util.inherits(Repl, Emitter);
45
46Repl.isActive = false;
47Repl.isBlocked = false;
48
49// See Repl.ref notes above.
50Repl.ref = null;
51
52Repl.prototype.initialize = function(callback) {
53 var state = priv.get(this);
54
55 process.stdin.resume();
56 process.stdin.setEncoding("utf8");
57
58 var replDefaults = {
59 prompt: ">> ",
60 useGlobal: false
61 };
62
63 // Call this immediately before repl.start to
64 // avoid crash on Intel Edison
65 state.board.info("Repl", "Initialized");
66
67 // Initialize the REPL session with the default
68 // repl settings.
69 // Assign the returned repl instance to "cmd"
70 var cmd = repl.start(replDefaults);
71
72 this.ready = true;
73
74 // Assign a reference to the REPL's "content" object
75 // This will be use later by the Repl.prototype.inject
76 // method for allowing user programs to inject their
77 // own explicit values and reference
78 this.cmd = cmd;
79 this.context = cmd.context;
80
81 cmd.on("exit", function() {
82 // Time to wait before forcing exit
83 var failExitTimeout = 1000;
84
85 state.board.emit("exit");
86 state.board.warn("Board", "Closing.");
87
88 // A fail safe timeout if 1 second to force exit.
89 var timeout = setTimeout(function () {
90 process.reallyExit();
91 }, failExitTimeout);
92
93 var interval = setInterval(function () {
94 var pendingIo = false;
95 // More than one board is attached, wait until everyone has no
96 // io pending before exit.
97 if (state.board.length) {
98 for (let i = 0; i < state.board.length; i++) {
99 if (state.board[i].io.pending) {
100 pendingIo = true;
101 break;
102 }
103 }
104 }
105 // Only one board connected, wait until there is no io pending before exit.
106 else {
107 pendingIo = state.board.io.pending;
108 }
109
110 if (!pendingIo) {
111 clearInterval(interval);
112 clearTimeout(timeout);
113 process.nextTick(process.reallyExit);
114 }
115 }, 1);
116 });
117
118 this.inject(state.opts);
119
120 /* istanbul ignore else */
121 if (callback) {
122 process.nextTick(callback);
123 }
124};
125
126Repl.prototype.close = function() {
127 this.cmd.emit("exit");
128};
129
130Repl.prototype.inject = function(obj) {
131 Object.keys(obj).forEach(function(key) {
132 Object.defineProperty(
133 this.context, key, Object.getOwnPropertyDescriptor(obj, key)
134 );
135 }, this);
136};
137
138module.exports = Repl;