git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: f1da602123429264a1b71fd395efea85c3b7b95e

Files: f1da602123429264a1b71fd395efea85c3b7b95e / actor.js

4557 bytesRaw
1const Message = require('primea-message')
2const LockMap = require('lockmap')
3const CapsStore = require('./capsStore.js')
4const Inbox = require('./inbox.js')
5
6module.exports = class Actor {
7 /**
8 * the Actor manages the varous message passing functions and provides
9 * an interface for the containers to use
10 * @param {Object} opts
11 * @param {Object} opts.id - the UUID of the Actor
12 * @param {Object} opts.state - the state of the container
13 * @param {Object} opts.hypervisor - the instance of the hypervisor
14 * @param {Object} opts.container - the container constuctor and argments
15 */
16 constructor (opts) {
17 this.state = opts.state.value
18 this.code = opts.state.value.code
19 this.treeNode = opts.state.node
20 this.hypervisor = opts.hypervisor
21 this.id = opts.id
22 this.container = new opts.container.Constructor(this, opts.container.args)
23 this.inbox = new Inbox({
24 actor: this,
25 hypervisor: opts.hypervisor
26 })
27
28 this.ticks = 0
29 this.running = false
30 this._sending = new LockMap()
31
32 this.caps = new CapsStore(opts.state.value.caps)
33 }
34
35 /**
36 * Mints a new capabilitly with a given tag
37 * @param {*} tag - a tag which can be used to identify caps
38 * @return {Object}
39 */
40 mintCap (tag = 0) {
41 return {
42 destId: this.id,
43 tag: tag
44 }
45 }
46
47 /**
48 * adds a message to this actor's message queue
49 * @param {string} portName
50 * @param {object} message
51 */
52 queue (message) {
53 this.inbox.queue(message)
54 this._startMessageLoop()
55 }
56
57 /**
58 * runs the creation routine for the actor
59 * @param {object} message
60 * @returns {Promise}
61 */
62 create (message) {
63 // start loop before running intializtion message so the the container state
64 // will be "running" incase the actor recievse a message will running
65 // creation code
66 this._startMessageLoop()
67 return this.runMessage(message, 'onCreation')
68 }
69
70 // waits for the next message
71 async _startMessageLoop () {
72 // this ensure we only every have one loop running at a time
73 if (!this.running) {
74 this.running = true
75 while (1) {
76 const message = await this.inbox.nextMessage()
77 if (!message) break
78
79 // if the message we recived had more ticks then we currently have then
80 // update it
81 if (message._fromTicks > this.ticks) {
82 this.ticks = message._fromTicks
83 this.hypervisor.scheduler.update(this)
84 }
85 // run the next message
86 await this.runMessage(message)
87 }
88
89 this.running = false
90 this.container.onIdle()
91 }
92 }
93
94 /**
95 * Runs the shutdown routine for the actor
96 */
97 shutdown () {
98 this.hypervisor.scheduler.done(this.id)
99 }
100
101 /**
102 * Runs the startup routine for the actor
103 */
104 startup () {
105 return this.container.onStartup()
106 }
107
108 /**
109 * run the Actor with a given message
110 * @param {object} message - the message to run
111 * @param {String} method - which method to run
112 * @returns {Promise}
113 */
114 async runMessage (message, method = 'onMessage') {
115 const responseCap = message.responseCap
116 delete message.responseCap
117
118 let result
119 try {
120 result = await this.container[method](message)
121 } catch (e) {
122 message.emit('execution:error', e)
123 result = {
124 exception: true,
125 exceptionError: e
126 }
127 }
128
129 if (responseCap) {
130 this.send(responseCap, new Message({
131 data: result
132 }))
133 }
134 }
135
136 /**
137 * updates the number of ticks that the actor has run
138 * @param {Number} count - the number of ticks to add
139 */
140 incrementTicks (count) {
141 this.ticks += count
142 this.hypervisor.scheduler.update(this)
143 }
144
145 /**
146 * creates an actor
147 * @param {Integer} type - the type id for the container
148 * @param {Object} message - an intial [message](https://github.com/primea/js-primea-message) to send newly created actor
149 */
150 createActor (type, message) {
151 const id = this._generateNextId()
152 return this.hypervisor.createActor(type, message, id)
153 }
154
155 _generateNextId () {
156 const id = {
157 nonce: this.state.nonce,
158 parent: this.id
159 }
160
161 this.state.nonce++
162 return id
163 }
164
165 /**
166 * sends a message to a given port
167 * @param {Object} portRef - the port
168 * @param {Message} message - the message
169 */
170 send (cap, message) {
171 const resolve = this._sending.lock(cap)
172 message._fromTicks = this.ticks
173 message._fromId = this.id
174 message.tag = cap.tag
175
176 return this.hypervisor.send(cap, message).then(() => resolve(cap))
177 }
178}
179

Built with git-ssb-web