git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: ae084f349c08473f2357c07bd5c87a4cadec8607

Files: ae084f349c08473f2357c07bd5c87a4cadec8607 / actor.js

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

Built with git-ssb-web