├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── LICENSE ├── README.md ├── examples ├── behaviors.ts ├── helloWorld.ts ├── inprocessBenchmark.ts ├── promises.ts ├── remote │ ├── generate.sh │ ├── messages.proto │ ├── messages_pb.d.ts │ └── node2.ts ├── spawnBenchmark.ts └── supervision.ts ├── fix-prof.sh ├── generate.sh ├── jsconfig.json ├── package.json ├── protoactor-js.code-workspace ├── src ├── actor.proto ├── actor.ts ├── actor_pb.d.ts ├── dispatcher.ts ├── invoker.ts ├── localContext.ts ├── localProcess.ts ├── mailbox.ts ├── messages.ts ├── pid.ts ├── process.ts ├── processRegistry.ts ├── promiseProcess.ts ├── props.ts ├── queue.ts ├── queue2.ts ├── remote │ ├── remote.proto │ ├── remote.ts │ └── remote_pb.d.ts ├── restartStatistics.ts └── supervision.ts ├── test ├── actorMessagingTests.ts ├── actorSpawningTests.ts ├── mailboxBenchmarkTests.ts ├── mailboxTests.ts ├── mocha.opts ├── queueTests.ts ├── supervisionOneForOneTests.ts └── util │ ├── awaiter.ts │ ├── sleep.ts │ └── timeAction.ts ├── tsconfig.json └── typings └── grpc.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # node files 2 | node_modules/ 3 | package-lock.json 4 | 5 | # node profiler/inspector files 6 | *.log 7 | *.cpuprofile 8 | *.heapsnapshot 9 | *.log.fix 10 | *.log.processed 11 | 12 | # build artifacts 13 | dist/ 14 | tmp/ 15 | 16 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${file}", 12 | "outFiles": ["${workspaceRoot}/dist/**/*.js"] 13 | }, 14 | { 15 | "type": "node", 16 | "request": "attach", 17 | "protocol": "inspector", 18 | "name": "Attach to Port", 19 | "address": "localhost", 20 | "port": 5858, 21 | "outFiles": [] 22 | }, 23 | { 24 | "name": "Run mocha", 25 | "type": "node", 26 | "protocol": "inspector", 27 | "request": "launch", 28 | "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", 29 | "stopOnEntry": false, 30 | "args": [ 31 | " --opts test/mocha.opts", 32 | "--no-timeouts" 33 | ], 34 | "cwd": "${workspaceRoot}", 35 | "runtimeExecutable": null, 36 | "env": { 37 | "NODE_ENV": "testing" 38 | } 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "typescript", 6 | "tsconfig": "tsconfig.json", 7 | "problemMatcher": [ 8 | "$tsc" 9 | ], 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # protoactor-js 2 | 3 | Ultra-fast, distributed, cross-platform actors. 4 | 5 | http://proto.actor/ 6 | 7 | ## Source code 8 | This is the JavaScript repository for Proto Actor. 9 | 10 | Other implementations: 11 | * Go: [https://github.com/AsynkronIT/protoactor-go](https://github.com/AsynkronIT/protoactor-go) 12 | * .NET: [https://github.com/AsynkronIT/protoactor-dotnet](https://github.com/AsynkronIT/protoactor-dotnet) 13 | * Python (unstable/WIP): [https://github.com/AsynkronIT/protoactor-python](https://github.com/AsynkronIT/protoactor-python) 14 | 15 | ## Disclaimer 16 | 17 | This library is in a very early/draft state. There is no pipeline yet for building NPM packages, and the code is far from complete. That said, it is currently a functional prototype - several of the .NET examples (e.g. Hello world, Supervision, Behaviors, Remote activation) have been ported and are working. 18 | 19 | ## How to build and run 20 | 21 | Requires Node 7.6.0+ and TypeScript. 22 | 23 | **Build** 24 | ```bash 25 | npm i 26 | ./generate.sh # generates Protobuf types 27 | tsc 28 | ``` 29 | **Run tests** 30 | ```bash 31 | npm test 32 | ``` 33 | **Run examples** 34 | ```bash 35 | node dist/examples/helloWorld.js 36 | ``` 37 | -------------------------------------------------------------------------------- /examples/behaviors.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../src/actor"; 2 | import { LocalContext } from "../src/localContext"; 3 | 4 | class Hello { 5 | constructor(public Who: string) { 6 | 7 | } 8 | } 9 | 10 | let helloBehavior = (context: LocalContext) => { 11 | var msg = context.Message 12 | if (msg instanceof Hello) { 13 | global.console.log('Hello', msg.Who) 14 | global.console.log('changing to goodbye behavior') 15 | context.PushBehavior(goodbyeBehavior) 16 | } 17 | } 18 | let goodbyeBehavior = (context: LocalContext) => { 19 | var msg = context.Message 20 | if (msg instanceof Hello) { 21 | global.console.log('I already said hello. Goodbye', msg.Who) 22 | global.console.log('reverting to previous behavior') 23 | context.PopBehavior() 24 | } 25 | } 26 | 27 | async function run() { 28 | let props = actor.fromFunc(helloBehavior) 29 | let pid = await actor.spawn(props) 30 | 31 | await pid.Tell(new Hello("Christian")) 32 | await pid.Tell(new Hello("Christian")) 33 | await pid.Tell(new Hello("Christian")) 34 | } 35 | 36 | run() -------------------------------------------------------------------------------- /examples/helloWorld.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../src/actor"; 2 | 3 | class Hello { 4 | constructor(public Who: string) { 5 | 6 | } 7 | } 8 | 9 | async function run() { 10 | var props = actor.fromFunc(context => { 11 | var msg = context.Message 12 | if (msg instanceof Hello) { 13 | global.console.log('Hello', msg.Who) 14 | } 15 | }); 16 | var pid = await actor.spawn(props); 17 | pid.Tell(new Hello("Christian")) 18 | } 19 | 20 | run() -------------------------------------------------------------------------------- /examples/inprocessBenchmark.ts: -------------------------------------------------------------------------------- 1 | import { Dispatcher } from "../src/dispatcher" 2 | import * as actor from "../src/actor" 3 | import {PID} from "../src/pid" 4 | import {LocalContext} from "../src/localContext" 5 | 6 | class Awaiter { 7 | public promise: Promise 8 | public resolve: () => void 9 | constructor() { 10 | this.promise = new Promise(resolve => { 11 | this.resolve = resolve 12 | }) 13 | } 14 | } 15 | class Msg { 16 | constructor(public sender: PID){} 17 | } 18 | class Start { 19 | constructor(public sender: PID){} 20 | } 21 | class PingActor implements actor.IActor { 22 | private batch: number 23 | constructor(private awaiter: Awaiter, private messageCount: number, private batchSize: number){} 24 | Receive(c: LocalContext): Promise { 25 | let msg = c.Message 26 | if (msg instanceof Start) { 27 | this.sendBatch(c, msg.sender) 28 | } 29 | if (msg instanceof Msg) { 30 | this.batch-- 31 | if (this.batch == 0) { 32 | if (!this.sendBatch(c, msg.sender)) { 33 | this.awaiter.resolve() 34 | } 35 | } 36 | } 37 | return actor.done 38 | } 39 | 40 | private sendBatch(c: LocalContext, s: PID): boolean { 41 | if (this.messageCount == 0) { 42 | return false 43 | } 44 | let m = new Msg(c.Self) 45 | for (let i = 0; i < this.batchSize; i++) { 46 | s.Tell(m) 47 | } 48 | 49 | this.messageCount -= this.batchSize 50 | this.batch = this.batchSize 51 | return true 52 | } 53 | } 54 | 55 | let messageCount = 1000000 56 | let batchSize = 100 57 | var tps = [300, 400, 500, 600, 700, 800, 900] 58 | 59 | async function benchmark(t: number) { 60 | var d = new Dispatcher() 61 | d.SetThroughput(t) 62 | 63 | let clientCount = 2 64 | let clients = [] 65 | let echos = [] 66 | let promises = [] 67 | let echoProps = actor.fromFunc(c => { 68 | let msg = c.Message 69 | if (msg instanceof Msg) { 70 | msg.sender.Tell(msg) 71 | } 72 | return actor.done 73 | }).WithDispatcher(d) 74 | 75 | for (let i = 0; i < clientCount; i++) { 76 | let awaiter = new Awaiter() 77 | let clientProps = actor.fromProducer(() => new PingActor(awaiter, messageCount, batchSize)) 78 | .WithDispatcher(d) 79 | let client = actor.spawn(clientProps) 80 | let echo = actor.spawn(echoProps) 81 | promises.push(awaiter.promise) 82 | clients.push(client) 83 | echos.push(echo) 84 | } 85 | 86 | let t0 = new Date().getTime() 87 | for (let i = 0; i < clientCount; i++) { 88 | clients[i].Tell(new Start(echos[i])) 89 | } 90 | await Promise.all(promises) 91 | let t1 = new Date().getTime() 92 | let dt = t1 - t0 93 | 94 | let totalMessages = messageCount*2*clientCount 95 | let x = totalMessages/dt*1000 96 | console.log(`${t}\t\t\t${dt} ms\t\t${x}`) 97 | } 98 | 99 | async function run() { 100 | console.log('Dispatcher\t\tElapsed\t\tMsg/sec') 101 | for (let i = 0; i < tps.length; i++) { 102 | await benchmark(tps[i]) 103 | } 104 | console.log('Done.') 105 | } 106 | 107 | run() -------------------------------------------------------------------------------- /examples/promises.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../src/actor"; 2 | 3 | async function run() { 4 | var props = actor.fromFunc(ctx => { 5 | if (typeof ctx.Message == "string") { 6 | global.console.log('got request', ctx.Message) 7 | ctx.Respond("hey") 8 | } 9 | }) 10 | var pid = await actor.spawn(props) 11 | var reply = await pid.RequestPromise("hello") 12 | global.console.log('got reply', reply) 13 | } 14 | 15 | run() -------------------------------------------------------------------------------- /examples/remote/generate.sh: -------------------------------------------------------------------------------- 1 | #rm -rf generated && mkdir -p generated && protoc --plugin=protoc-gen-ts=node_modules/.bin/protoc-gen-ts --js_out=import_style=commonjs,binary:generated --ts_out=service=true:generated -I src src/actor.proto 2 | mkdir -p tmp 3 | 4 | pbjs='node_modules/protobufjs/cli/bin/pbjs -t static-module -w commonjs' 5 | pbts='node_modules/protobufjs/cli/bin/pbts' 6 | 7 | $pbjs -o dist/examples/remote/messages_pb.js examples/remote/messages.proto 8 | $pbts -o examples/remote/messages_pb.d.ts dist/examples/remote/messages_pb.js 9 | 10 | -------------------------------------------------------------------------------- /examples/remote/messages.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package messages; 3 | 4 | message HelloRequest {} 5 | message HelloResponse { 6 | string Message=1; 7 | } -------------------------------------------------------------------------------- /examples/remote/messages_pb.d.ts: -------------------------------------------------------------------------------- 1 | import * as $protobuf from "protobufjs"; 2 | 3 | /** 4 | * Namespace messages. 5 | * @exports messages 6 | * @namespace 7 | */ 8 | export namespace messages { 9 | 10 | type HelloRequest$Properties = {}; 11 | 12 | /** 13 | * Constructs a new HelloRequest. 14 | * @exports messages.HelloRequest 15 | * @constructor 16 | * @param {messages.HelloRequest$Properties=} [properties] Properties to set 17 | */ 18 | class HelloRequest { 19 | 20 | /** 21 | * Constructs a new HelloRequest. 22 | * @exports messages.HelloRequest 23 | * @constructor 24 | * @param {messages.HelloRequest$Properties=} [properties] Properties to set 25 | */ 26 | constructor(properties?: messages.HelloRequest$Properties); 27 | 28 | /** 29 | * Creates a new HelloRequest instance using the specified properties. 30 | * @param {messages.HelloRequest$Properties=} [properties] Properties to set 31 | * @returns {messages.HelloRequest} HelloRequest instance 32 | */ 33 | public static create(properties?: messages.HelloRequest$Properties): messages.HelloRequest; 34 | 35 | /** 36 | * Encodes the specified HelloRequest message. Does not implicitly {@link messages.HelloRequest.verify|verify} messages. 37 | * @param {messages.HelloRequest$Properties} message HelloRequest message or plain object to encode 38 | * @param {$protobuf.Writer} [writer] Writer to encode to 39 | * @returns {$protobuf.Writer} Writer 40 | */ 41 | public static encode(message: messages.HelloRequest$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 42 | 43 | /** 44 | * Encodes the specified HelloRequest message, length delimited. Does not implicitly {@link messages.HelloRequest.verify|verify} messages. 45 | * @param {messages.HelloRequest$Properties} message HelloRequest message or plain object to encode 46 | * @param {$protobuf.Writer} [writer] Writer to encode to 47 | * @returns {$protobuf.Writer} Writer 48 | */ 49 | public static encodeDelimited(message: messages.HelloRequest$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 50 | 51 | /** 52 | * Decodes a HelloRequest message from the specified reader or buffer. 53 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 54 | * @param {number} [length] Message length if known beforehand 55 | * @returns {messages.HelloRequest} HelloRequest 56 | * @throws {Error} If the payload is not a reader or valid buffer 57 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 58 | */ 59 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): messages.HelloRequest; 60 | 61 | /** 62 | * Decodes a HelloRequest message from the specified reader or buffer, length delimited. 63 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 64 | * @returns {messages.HelloRequest} HelloRequest 65 | * @throws {Error} If the payload is not a reader or valid buffer 66 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 67 | */ 68 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): messages.HelloRequest; 69 | 70 | /** 71 | * Verifies a HelloRequest message. 72 | * @param {Object.} message Plain object to verify 73 | * @returns {?string} `null` if valid, otherwise the reason why it is not 74 | */ 75 | public static verify(message: { [k: string]: any }): string; 76 | 77 | /** 78 | * Creates a HelloRequest message from a plain object. Also converts values to their respective internal types. 79 | * @param {Object.} object Plain object 80 | * @returns {messages.HelloRequest} HelloRequest 81 | */ 82 | public static fromObject(object: { [k: string]: any }): messages.HelloRequest; 83 | 84 | /** 85 | * Creates a HelloRequest message from a plain object. Also converts values to their respective internal types. 86 | * This is an alias of {@link messages.HelloRequest.fromObject}. 87 | * @function 88 | * @param {Object.} object Plain object 89 | * @returns {messages.HelloRequest} HelloRequest 90 | */ 91 | public static from(object: { [k: string]: any }): messages.HelloRequest; 92 | 93 | /** 94 | * Creates a plain object from a HelloRequest message. Also converts values to other types if specified. 95 | * @param {messages.HelloRequest} message HelloRequest 96 | * @param {$protobuf.ConversionOptions} [options] Conversion options 97 | * @returns {Object.} Plain object 98 | */ 99 | public static toObject(message: messages.HelloRequest, options?: $protobuf.ConversionOptions): { [k: string]: any }; 100 | 101 | /** 102 | * Creates a plain object from this HelloRequest message. Also converts values to other types if specified. 103 | * @param {$protobuf.ConversionOptions} [options] Conversion options 104 | * @returns {Object.} Plain object 105 | */ 106 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 107 | 108 | /** 109 | * Converts this HelloRequest to JSON. 110 | * @returns {Object.} JSON object 111 | */ 112 | public toJSON(): { [k: string]: any }; 113 | } 114 | 115 | type HelloResponse$Properties = { 116 | Message?: string; 117 | }; 118 | 119 | /** 120 | * Constructs a new HelloResponse. 121 | * @exports messages.HelloResponse 122 | * @constructor 123 | * @param {messages.HelloResponse$Properties=} [properties] Properties to set 124 | */ 125 | class HelloResponse { 126 | 127 | /** 128 | * Constructs a new HelloResponse. 129 | * @exports messages.HelloResponse 130 | * @constructor 131 | * @param {messages.HelloResponse$Properties=} [properties] Properties to set 132 | */ 133 | constructor(properties?: messages.HelloResponse$Properties); 134 | 135 | /** 136 | * HelloResponse Message. 137 | * @type {string} 138 | */ 139 | public Message: string; 140 | 141 | /** 142 | * Creates a new HelloResponse instance using the specified properties. 143 | * @param {messages.HelloResponse$Properties=} [properties] Properties to set 144 | * @returns {messages.HelloResponse} HelloResponse instance 145 | */ 146 | public static create(properties?: messages.HelloResponse$Properties): messages.HelloResponse; 147 | 148 | /** 149 | * Encodes the specified HelloResponse message. Does not implicitly {@link messages.HelloResponse.verify|verify} messages. 150 | * @param {messages.HelloResponse$Properties} message HelloResponse message or plain object to encode 151 | * @param {$protobuf.Writer} [writer] Writer to encode to 152 | * @returns {$protobuf.Writer} Writer 153 | */ 154 | public static encode(message: messages.HelloResponse$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 155 | 156 | /** 157 | * Encodes the specified HelloResponse message, length delimited. Does not implicitly {@link messages.HelloResponse.verify|verify} messages. 158 | * @param {messages.HelloResponse$Properties} message HelloResponse message or plain object to encode 159 | * @param {$protobuf.Writer} [writer] Writer to encode to 160 | * @returns {$protobuf.Writer} Writer 161 | */ 162 | public static encodeDelimited(message: messages.HelloResponse$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 163 | 164 | /** 165 | * Decodes a HelloResponse message from the specified reader or buffer. 166 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 167 | * @param {number} [length] Message length if known beforehand 168 | * @returns {messages.HelloResponse} HelloResponse 169 | * @throws {Error} If the payload is not a reader or valid buffer 170 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 171 | */ 172 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): messages.HelloResponse; 173 | 174 | /** 175 | * Decodes a HelloResponse message from the specified reader or buffer, length delimited. 176 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 177 | * @returns {messages.HelloResponse} HelloResponse 178 | * @throws {Error} If the payload is not a reader or valid buffer 179 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 180 | */ 181 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): messages.HelloResponse; 182 | 183 | /** 184 | * Verifies a HelloResponse message. 185 | * @param {Object.} message Plain object to verify 186 | * @returns {?string} `null` if valid, otherwise the reason why it is not 187 | */ 188 | public static verify(message: { [k: string]: any }): string; 189 | 190 | /** 191 | * Creates a HelloResponse message from a plain object. Also converts values to their respective internal types. 192 | * @param {Object.} object Plain object 193 | * @returns {messages.HelloResponse} HelloResponse 194 | */ 195 | public static fromObject(object: { [k: string]: any }): messages.HelloResponse; 196 | 197 | /** 198 | * Creates a HelloResponse message from a plain object. Also converts values to their respective internal types. 199 | * This is an alias of {@link messages.HelloResponse.fromObject}. 200 | * @function 201 | * @param {Object.} object Plain object 202 | * @returns {messages.HelloResponse} HelloResponse 203 | */ 204 | public static from(object: { [k: string]: any }): messages.HelloResponse; 205 | 206 | /** 207 | * Creates a plain object from a HelloResponse message. Also converts values to other types if specified. 208 | * @param {messages.HelloResponse} message HelloResponse 209 | * @param {$protobuf.ConversionOptions} [options] Conversion options 210 | * @returns {Object.} Plain object 211 | */ 212 | public static toObject(message: messages.HelloResponse, options?: $protobuf.ConversionOptions): { [k: string]: any }; 213 | 214 | /** 215 | * Creates a plain object from this HelloResponse message. Also converts values to other types if specified. 216 | * @param {$protobuf.ConversionOptions} [options] Conversion options 217 | * @returns {Object.} Plain object 218 | */ 219 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 220 | 221 | /** 222 | * Converts this HelloResponse to JSON. 223 | * @returns {Object.} JSON object 224 | */ 225 | public toJSON(): { [k: string]: any }; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /examples/remote/node2.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../../src/actor"; 2 | import * as remote from "../../src/remote/remote"; 3 | import * as pb from "./messages_pb"; 4 | 5 | remote.Serialization.RegisterTypes('messages', pb.messages) 6 | 7 | let helloProps = actor.fromFunc(ctx => { 8 | let msg = ctx.Message 9 | if (msg instanceof pb.messages.HelloRequest) { 10 | let res = new pb.messages.HelloResponse() 11 | console.log('Got hello request') 12 | res.Message = 'Hello from node 2' 13 | ctx.Respond(res) 14 | } 15 | }) 16 | 17 | remote.Remote.RegisterKnownKind('hello', helloProps) 18 | remote.Remote.Start('localhost', 12000) -------------------------------------------------------------------------------- /examples/spawnBenchmark.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../src/actor"; 2 | import { LocalContext } from "../src/localContext"; 3 | import { Message } from "../src/messages"; 4 | import { PID } from "../src/pid"; 5 | 6 | class Request { 7 | constructor(public Div: number, public Num: number, public Size: number) { 8 | } 9 | } 10 | 11 | var myProps = actor.fromProducer(() => new MyActor()) 12 | 13 | class MyActor implements actor.IActor { 14 | Replies = 0; 15 | ReplyTo: PID | null = null; 16 | Sum = 0; 17 | 18 | async Receive(context: LocalContext) { 19 | var message = context.Message 20 | if (message instanceof Request) { 21 | if (message.Size == 1) { 22 | context.Respond(message.Num) 23 | context.Self.Stop() 24 | return actor.done 25 | } 26 | this.Replies = message.Div 27 | this.ReplyTo = context.Sender 28 | for (var i = 0; i < message.Div; i++) { 29 | var child = actor.spawn(myProps) 30 | var num = message.Num + i * (message.Size / message.Div) 31 | var size = message.Size / message.Div 32 | var div = message.Div 33 | child.Request(new Request(div, num, size), context.Self) 34 | } 35 | return actor.done 36 | } 37 | if (typeof(message) === 'number') { 38 | this.Sum += Number(message) 39 | this.Replies-- 40 | if (this.Replies == 0 && this.ReplyTo) { 41 | this.ReplyTo.Tell(this.Sum) 42 | } 43 | return actor.done 44 | } 45 | } 46 | } 47 | 48 | async function run() { 49 | //while(true){ 50 | var pid = await actor.spawn(myProps) 51 | global.console.log('starting - 10,000') 52 | var hrstart = process.hrtime(); 53 | var response = await pid.RequestPromise(new Request(10, 0, 10 * 1000)) // should be 1M but node can't handle it - runs out of memory 54 | global.console.log(response) 55 | var hr = process.hrtime(hrstart) 56 | var s = hr[0] + hr[1] / (1000 * 1000 * 1000) 57 | global.console.log(s + ' seconds') 58 | //} 59 | } 60 | 61 | run() -------------------------------------------------------------------------------- /examples/supervision.ts: -------------------------------------------------------------------------------- 1 | import { IActor, fromProducer, spawn, done } from "../src/actor"; 2 | import { OneForOneStrategy, IDecider, SupervisorDirective } from "../src/supervision"; 3 | import * as messages from "../src/messages"; 4 | import { LocalContext } from "../src/localContext"; 5 | 6 | class Hello { 7 | constructor(public Who: string) { 8 | 9 | } 10 | } 11 | class Recoverable { } 12 | class Fatal { } 13 | class ParentActor implements IActor { 14 | async Receive(ctx: LocalContext) { 15 | var child 16 | if (!ctx.Children || ctx.Children.length == 0) { 17 | let props = fromProducer(() => new ChildActor()) 18 | child = await ctx.Spawn(props) 19 | } else { 20 | child = ctx.Children[0] 21 | } 22 | let msg = ctx.Message 23 | if (msg instanceof Hello) { 24 | await child.Tell(msg) 25 | } 26 | if (msg instanceof Recoverable) { 27 | await child.Tell(msg) 28 | } 29 | if (msg instanceof Fatal) { 30 | await child.Tell(msg) 31 | } 32 | 33 | return done; 34 | } 35 | } 36 | class ChildActor implements IActor { 37 | Receive(ctx: LocalContext) { 38 | let msg = ctx.Message 39 | if (msg instanceof Hello) { 40 | global.console.log(ctx.Self.ToShortString(), 'Hello', msg.Who) 41 | } 42 | if (msg instanceof Recoverable) { 43 | global.console.log(ctx.Self.ToShortString(), 'Recoverable') 44 | throw msg 45 | } 46 | if (msg instanceof Fatal) { 47 | global.console.log(ctx.Self.ToShortString(), 'Fatal') 48 | throw msg 49 | } 50 | if (msg instanceof messages.Started) { 51 | global.console.log(ctx.Self.ToShortString(), 'Started') 52 | } 53 | if (msg instanceof messages.Stopping) { 54 | global.console.log(ctx.Self.ToShortString(), 'Stopping') 55 | } 56 | if (msg instanceof messages.Stopped) { 57 | global.console.log(ctx.Self.ToShortString(), 'Stopped') 58 | } 59 | if (msg instanceof messages.Stopping) { 60 | global.console.log(ctx.Self.ToShortString(), 'Stopping') 61 | } 62 | if (msg instanceof messages.Restarting) { 63 | global.console.log(ctx.Self.ToShortString(), 'Restarting') 64 | } 65 | 66 | return done; 67 | } 68 | } 69 | 70 | var decider: IDecider = (reason, child) => { 71 | if (reason instanceof Recoverable) 72 | return SupervisorDirective.Restart; 73 | if (reason instanceof Fatal) 74 | return SupervisorDirective.Stop; 75 | return SupervisorDirective.Escalate; 76 | } 77 | 78 | async function run() { 79 | var props = fromProducer(() => new ParentActor()) 80 | .WithSupervisor(new OneForOneStrategy(decider, 1)); 81 | 82 | var pid = await spawn(props) 83 | 84 | pid.Tell(new Hello("Christian")) 85 | pid.Tell(new Recoverable()) 86 | pid.Tell(new Fatal()) 87 | } 88 | 89 | run() -------------------------------------------------------------------------------- /fix-prof.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sed -r 's/C\:\\[^,]+/"&"/g' "$1" | sed -r '/C\:./ { s/\\/\//g }' > "$1.fix" 3 | node --prof-process "$1.fix" > "$1.processed" 4 | -------------------------------------------------------------------------------- /generate.sh: -------------------------------------------------------------------------------- 1 | #rm -rf generated && mkdir -p generated && protoc --plugin=protoc-gen-ts=node_modules/.bin/protoc-gen-ts --js_out=import_style=commonjs,binary:generated --ts_out=service=true:generated -I src src/actor.proto 2 | mkdir -p tmp 3 | 4 | pbjs='node_modules/protobufjs/cli/bin/pbjs -t static-module -w commonjs' 5 | pbts='node_modules/protobufjs/cli/bin/pbts' 6 | 7 | $pbjs -o dist/src/actor_pb.js src/actor.proto 8 | $pbts -o src/actor_pb.d.ts dist/src/actor_pb.js 9 | 10 | $pbjs -o dist/src/remote/remote_pb.js -p src src/remote/remote.proto 11 | $pbts -o src/remote/remote_pb.d.ts dist/src/remote/remote_pb.js 12 | 13 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6" 4 | } 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "protoactor-js", 3 | "version": "0.1.0", 4 | "description": "Proto Actor for JavaScript", 5 | "directories": { 6 | "example": "examples", 7 | "test": "tests" 8 | }, 9 | "scripts": { 10 | "test": "mocha --opts test/mocha.opts -w" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/asynkronit/protoactor-js.git" 15 | }, 16 | "author": "", 17 | "license": "Apache License 2.0", 18 | "bugs": { 19 | "url": "https://github.com/asynkronit/protoactor-js/issues" 20 | }, 21 | "homepage": "https://github.com/asynkronit/protoactor-js#readme", 22 | "devDependencies": { 23 | "@types/chai": "^4.0.0", 24 | "@types/chai-as-promised": "0.0.31", 25 | "@types/long": "^3.0.31", 26 | "@types/mocha": "^2.2.41", 27 | "@types/node": "^7.0.14", 28 | "chai": "^4.0.2", 29 | "chai-as-promised": "^7.0.0", 30 | "mocha": "^3.3.0", 31 | "ts-node": "^3.0.2", 32 | "typescript": "^2.3.1" 33 | }, 34 | "dependencies": { 35 | "grpc": "^1.3.7", 36 | "protobufjs": "^6.7.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /protoactor-js.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } -------------------------------------------------------------------------------- /src/actor.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package actor; 3 | 4 | message PID { 5 | string Address = 1; 6 | string Id = 2; 7 | } 8 | 9 | //user messages 10 | message PoisonPill {} 11 | 12 | //system messages 13 | message Watch { 14 | PID watcher = 1; 15 | } 16 | 17 | message Unwatch { 18 | PID watcher = 1; 19 | } 20 | 21 | message Terminated { 22 | PID who = 1; 23 | bool AddressTerminated = 2; 24 | } 25 | 26 | message Stop {} 27 | -------------------------------------------------------------------------------- /src/actor.ts: -------------------------------------------------------------------------------- 1 | import { Props } from "./props"; 2 | import processRegistry from "./processRegistry"; 3 | import { IContext } from "./localContext"; 4 | import { PID } from "./pid"; 5 | import { Message } from "./messages" 6 | import { ISupervisor } from "./supervision"; 7 | import { RestartStatistics } from "./restartStatistics"; 8 | 9 | export function fromFunc(fn: (context: IContext) => void): Props { 10 | return fromProducer(() => new EmptyActor(fn)) 11 | } 12 | 13 | export function fromProducer(fn: () => IActor): Props { 14 | return new Props().WithProducer(fn) 15 | } 16 | 17 | export function spawn(props: Props): PID { 18 | var name = processRegistry.NextId() 19 | return spawnNamed(props, name) 20 | } 21 | 22 | export function spawnPrefix(props: Props, prefix: string): PID { 23 | var name = prefix + processRegistry.NextId() 24 | return spawnNamed(props, name) 25 | } 26 | 27 | export function spawnNamed(props: Props, name: string): PID { 28 | return props.Spawn(name) 29 | } 30 | 31 | class EmptyActor implements IActor { 32 | constructor(private fn: (context: IContext) => void) { } 33 | 34 | async Receive(context: IContext) { 35 | this.fn(context) 36 | } 37 | } 38 | export interface IActor { 39 | Receive(context: IContext): Promise; 40 | } 41 | 42 | export const done = Promise.resolve(); -------------------------------------------------------------------------------- /src/actor_pb.d.ts: -------------------------------------------------------------------------------- 1 | import * as $protobuf from "protobufjs"; 2 | 3 | /** 4 | * Namespace actor. 5 | * @exports actor 6 | * @namespace 7 | */ 8 | export namespace actor { 9 | 10 | type PID$Properties = { 11 | Address?: string; 12 | Id?: string; 13 | }; 14 | 15 | /** 16 | * Constructs a new PID. 17 | * @exports actor.PID 18 | * @constructor 19 | * @param {actor.PID$Properties=} [properties] Properties to set 20 | */ 21 | class PID { 22 | 23 | /** 24 | * Constructs a new PID. 25 | * @exports actor.PID 26 | * @constructor 27 | * @param {actor.PID$Properties=} [properties] Properties to set 28 | */ 29 | constructor(properties?: actor.PID$Properties); 30 | 31 | /** 32 | * PID Address. 33 | * @type {string} 34 | */ 35 | public Address: string; 36 | 37 | /** 38 | * PID Id. 39 | * @type {string} 40 | */ 41 | public Id: string; 42 | 43 | /** 44 | * Creates a new PID instance using the specified properties. 45 | * @param {actor.PID$Properties=} [properties] Properties to set 46 | * @returns {actor.PID} PID instance 47 | */ 48 | public static create(properties?: actor.PID$Properties): actor.PID; 49 | 50 | /** 51 | * Encodes the specified PID message. Does not implicitly {@link actor.PID.verify|verify} messages. 52 | * @param {actor.PID$Properties} message PID message or plain object to encode 53 | * @param {$protobuf.Writer} [writer] Writer to encode to 54 | * @returns {$protobuf.Writer} Writer 55 | */ 56 | public static encode(message: actor.PID$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 57 | 58 | /** 59 | * Encodes the specified PID message, length delimited. Does not implicitly {@link actor.PID.verify|verify} messages. 60 | * @param {actor.PID$Properties} message PID message or plain object to encode 61 | * @param {$protobuf.Writer} [writer] Writer to encode to 62 | * @returns {$protobuf.Writer} Writer 63 | */ 64 | public static encodeDelimited(message: actor.PID$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 65 | 66 | /** 67 | * Decodes a PID message from the specified reader or buffer. 68 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 69 | * @param {number} [length] Message length if known beforehand 70 | * @returns {actor.PID} PID 71 | * @throws {Error} If the payload is not a reader or valid buffer 72 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 73 | */ 74 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.PID; 75 | 76 | /** 77 | * Decodes a PID message from the specified reader or buffer, length delimited. 78 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 79 | * @returns {actor.PID} PID 80 | * @throws {Error} If the payload is not a reader or valid buffer 81 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 82 | */ 83 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.PID; 84 | 85 | /** 86 | * Verifies a PID message. 87 | * @param {Object.} message Plain object to verify 88 | * @returns {?string} `null` if valid, otherwise the reason why it is not 89 | */ 90 | public static verify(message: { [k: string]: any }): string; 91 | 92 | /** 93 | * Creates a PID message from a plain object. Also converts values to their respective internal types. 94 | * @param {Object.} object Plain object 95 | * @returns {actor.PID} PID 96 | */ 97 | public static fromObject(object: { [k: string]: any }): actor.PID; 98 | 99 | /** 100 | * Creates a PID message from a plain object. Also converts values to their respective internal types. 101 | * This is an alias of {@link actor.PID.fromObject}. 102 | * @function 103 | * @param {Object.} object Plain object 104 | * @returns {actor.PID} PID 105 | */ 106 | public static from(object: { [k: string]: any }): actor.PID; 107 | 108 | /** 109 | * Creates a plain object from a PID message. Also converts values to other types if specified. 110 | * @param {actor.PID} message PID 111 | * @param {$protobuf.ConversionOptions} [options] Conversion options 112 | * @returns {Object.} Plain object 113 | */ 114 | public static toObject(message: actor.PID, options?: $protobuf.ConversionOptions): { [k: string]: any }; 115 | 116 | /** 117 | * Creates a plain object from this PID message. Also converts values to other types if specified. 118 | * @param {$protobuf.ConversionOptions} [options] Conversion options 119 | * @returns {Object.} Plain object 120 | */ 121 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 122 | 123 | /** 124 | * Converts this PID to JSON. 125 | * @returns {Object.} JSON object 126 | */ 127 | public toJSON(): { [k: string]: any }; 128 | } 129 | 130 | type PoisonPill$Properties = {}; 131 | 132 | /** 133 | * Constructs a new PoisonPill. 134 | * @exports actor.PoisonPill 135 | * @constructor 136 | * @param {actor.PoisonPill$Properties=} [properties] Properties to set 137 | */ 138 | class PoisonPill { 139 | 140 | /** 141 | * Constructs a new PoisonPill. 142 | * @exports actor.PoisonPill 143 | * @constructor 144 | * @param {actor.PoisonPill$Properties=} [properties] Properties to set 145 | */ 146 | constructor(properties?: actor.PoisonPill$Properties); 147 | 148 | /** 149 | * Creates a new PoisonPill instance using the specified properties. 150 | * @param {actor.PoisonPill$Properties=} [properties] Properties to set 151 | * @returns {actor.PoisonPill} PoisonPill instance 152 | */ 153 | public static create(properties?: actor.PoisonPill$Properties): actor.PoisonPill; 154 | 155 | /** 156 | * Encodes the specified PoisonPill message. Does not implicitly {@link actor.PoisonPill.verify|verify} messages. 157 | * @param {actor.PoisonPill$Properties} message PoisonPill message or plain object to encode 158 | * @param {$protobuf.Writer} [writer] Writer to encode to 159 | * @returns {$protobuf.Writer} Writer 160 | */ 161 | public static encode(message: actor.PoisonPill$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 162 | 163 | /** 164 | * Encodes the specified PoisonPill message, length delimited. Does not implicitly {@link actor.PoisonPill.verify|verify} messages. 165 | * @param {actor.PoisonPill$Properties} message PoisonPill message or plain object to encode 166 | * @param {$protobuf.Writer} [writer] Writer to encode to 167 | * @returns {$protobuf.Writer} Writer 168 | */ 169 | public static encodeDelimited(message: actor.PoisonPill$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 170 | 171 | /** 172 | * Decodes a PoisonPill message from the specified reader or buffer. 173 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 174 | * @param {number} [length] Message length if known beforehand 175 | * @returns {actor.PoisonPill} PoisonPill 176 | * @throws {Error} If the payload is not a reader or valid buffer 177 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 178 | */ 179 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.PoisonPill; 180 | 181 | /** 182 | * Decodes a PoisonPill message from the specified reader or buffer, length delimited. 183 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 184 | * @returns {actor.PoisonPill} PoisonPill 185 | * @throws {Error} If the payload is not a reader or valid buffer 186 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 187 | */ 188 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.PoisonPill; 189 | 190 | /** 191 | * Verifies a PoisonPill message. 192 | * @param {Object.} message Plain object to verify 193 | * @returns {?string} `null` if valid, otherwise the reason why it is not 194 | */ 195 | public static verify(message: { [k: string]: any }): string; 196 | 197 | /** 198 | * Creates a PoisonPill message from a plain object. Also converts values to their respective internal types. 199 | * @param {Object.} object Plain object 200 | * @returns {actor.PoisonPill} PoisonPill 201 | */ 202 | public static fromObject(object: { [k: string]: any }): actor.PoisonPill; 203 | 204 | /** 205 | * Creates a PoisonPill message from a plain object. Also converts values to their respective internal types. 206 | * This is an alias of {@link actor.PoisonPill.fromObject}. 207 | * @function 208 | * @param {Object.} object Plain object 209 | * @returns {actor.PoisonPill} PoisonPill 210 | */ 211 | public static from(object: { [k: string]: any }): actor.PoisonPill; 212 | 213 | /** 214 | * Creates a plain object from a PoisonPill message. Also converts values to other types if specified. 215 | * @param {actor.PoisonPill} message PoisonPill 216 | * @param {$protobuf.ConversionOptions} [options] Conversion options 217 | * @returns {Object.} Plain object 218 | */ 219 | public static toObject(message: actor.PoisonPill, options?: $protobuf.ConversionOptions): { [k: string]: any }; 220 | 221 | /** 222 | * Creates a plain object from this PoisonPill message. Also converts values to other types if specified. 223 | * @param {$protobuf.ConversionOptions} [options] Conversion options 224 | * @returns {Object.} Plain object 225 | */ 226 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 227 | 228 | /** 229 | * Converts this PoisonPill to JSON. 230 | * @returns {Object.} JSON object 231 | */ 232 | public toJSON(): { [k: string]: any }; 233 | } 234 | 235 | type Watch$Properties = { 236 | watcher?: actor.PID$Properties; 237 | }; 238 | 239 | /** 240 | * Constructs a new Watch. 241 | * @exports actor.Watch 242 | * @constructor 243 | * @param {actor.Watch$Properties=} [properties] Properties to set 244 | */ 245 | class Watch { 246 | 247 | /** 248 | * Constructs a new Watch. 249 | * @exports actor.Watch 250 | * @constructor 251 | * @param {actor.Watch$Properties=} [properties] Properties to set 252 | */ 253 | constructor(properties?: actor.Watch$Properties); 254 | 255 | /** 256 | * Watch watcher. 257 | * @type {(actor.PID$Properties|null)} 258 | */ 259 | public watcher: (actor.PID$Properties|null); 260 | 261 | /** 262 | * Creates a new Watch instance using the specified properties. 263 | * @param {actor.Watch$Properties=} [properties] Properties to set 264 | * @returns {actor.Watch} Watch instance 265 | */ 266 | public static create(properties?: actor.Watch$Properties): actor.Watch; 267 | 268 | /** 269 | * Encodes the specified Watch message. Does not implicitly {@link actor.Watch.verify|verify} messages. 270 | * @param {actor.Watch$Properties} message Watch message or plain object to encode 271 | * @param {$protobuf.Writer} [writer] Writer to encode to 272 | * @returns {$protobuf.Writer} Writer 273 | */ 274 | public static encode(message: actor.Watch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 275 | 276 | /** 277 | * Encodes the specified Watch message, length delimited. Does not implicitly {@link actor.Watch.verify|verify} messages. 278 | * @param {actor.Watch$Properties} message Watch message or plain object to encode 279 | * @param {$protobuf.Writer} [writer] Writer to encode to 280 | * @returns {$protobuf.Writer} Writer 281 | */ 282 | public static encodeDelimited(message: actor.Watch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 283 | 284 | /** 285 | * Decodes a Watch message from the specified reader or buffer. 286 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 287 | * @param {number} [length] Message length if known beforehand 288 | * @returns {actor.Watch} Watch 289 | * @throws {Error} If the payload is not a reader or valid buffer 290 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 291 | */ 292 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Watch; 293 | 294 | /** 295 | * Decodes a Watch message from the specified reader or buffer, length delimited. 296 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 297 | * @returns {actor.Watch} Watch 298 | * @throws {Error} If the payload is not a reader or valid buffer 299 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 300 | */ 301 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Watch; 302 | 303 | /** 304 | * Verifies a Watch message. 305 | * @param {Object.} message Plain object to verify 306 | * @returns {?string} `null` if valid, otherwise the reason why it is not 307 | */ 308 | public static verify(message: { [k: string]: any }): string; 309 | 310 | /** 311 | * Creates a Watch message from a plain object. Also converts values to their respective internal types. 312 | * @param {Object.} object Plain object 313 | * @returns {actor.Watch} Watch 314 | */ 315 | public static fromObject(object: { [k: string]: any }): actor.Watch; 316 | 317 | /** 318 | * Creates a Watch message from a plain object. Also converts values to their respective internal types. 319 | * This is an alias of {@link actor.Watch.fromObject}. 320 | * @function 321 | * @param {Object.} object Plain object 322 | * @returns {actor.Watch} Watch 323 | */ 324 | public static from(object: { [k: string]: any }): actor.Watch; 325 | 326 | /** 327 | * Creates a plain object from a Watch message. Also converts values to other types if specified. 328 | * @param {actor.Watch} message Watch 329 | * @param {$protobuf.ConversionOptions} [options] Conversion options 330 | * @returns {Object.} Plain object 331 | */ 332 | public static toObject(message: actor.Watch, options?: $protobuf.ConversionOptions): { [k: string]: any }; 333 | 334 | /** 335 | * Creates a plain object from this Watch message. Also converts values to other types if specified. 336 | * @param {$protobuf.ConversionOptions} [options] Conversion options 337 | * @returns {Object.} Plain object 338 | */ 339 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 340 | 341 | /** 342 | * Converts this Watch to JSON. 343 | * @returns {Object.} JSON object 344 | */ 345 | public toJSON(): { [k: string]: any }; 346 | } 347 | 348 | type Unwatch$Properties = { 349 | watcher?: actor.PID$Properties; 350 | }; 351 | 352 | /** 353 | * Constructs a new Unwatch. 354 | * @exports actor.Unwatch 355 | * @constructor 356 | * @param {actor.Unwatch$Properties=} [properties] Properties to set 357 | */ 358 | class Unwatch { 359 | 360 | /** 361 | * Constructs a new Unwatch. 362 | * @exports actor.Unwatch 363 | * @constructor 364 | * @param {actor.Unwatch$Properties=} [properties] Properties to set 365 | */ 366 | constructor(properties?: actor.Unwatch$Properties); 367 | 368 | /** 369 | * Unwatch watcher. 370 | * @type {(actor.PID$Properties|null)} 371 | */ 372 | public watcher: (actor.PID$Properties|null); 373 | 374 | /** 375 | * Creates a new Unwatch instance using the specified properties. 376 | * @param {actor.Unwatch$Properties=} [properties] Properties to set 377 | * @returns {actor.Unwatch} Unwatch instance 378 | */ 379 | public static create(properties?: actor.Unwatch$Properties): actor.Unwatch; 380 | 381 | /** 382 | * Encodes the specified Unwatch message. Does not implicitly {@link actor.Unwatch.verify|verify} messages. 383 | * @param {actor.Unwatch$Properties} message Unwatch message or plain object to encode 384 | * @param {$protobuf.Writer} [writer] Writer to encode to 385 | * @returns {$protobuf.Writer} Writer 386 | */ 387 | public static encode(message: actor.Unwatch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 388 | 389 | /** 390 | * Encodes the specified Unwatch message, length delimited. Does not implicitly {@link actor.Unwatch.verify|verify} messages. 391 | * @param {actor.Unwatch$Properties} message Unwatch message or plain object to encode 392 | * @param {$protobuf.Writer} [writer] Writer to encode to 393 | * @returns {$protobuf.Writer} Writer 394 | */ 395 | public static encodeDelimited(message: actor.Unwatch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 396 | 397 | /** 398 | * Decodes an Unwatch message from the specified reader or buffer. 399 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 400 | * @param {number} [length] Message length if known beforehand 401 | * @returns {actor.Unwatch} Unwatch 402 | * @throws {Error} If the payload is not a reader or valid buffer 403 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 404 | */ 405 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Unwatch; 406 | 407 | /** 408 | * Decodes an Unwatch message from the specified reader or buffer, length delimited. 409 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 410 | * @returns {actor.Unwatch} Unwatch 411 | * @throws {Error} If the payload is not a reader or valid buffer 412 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 413 | */ 414 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Unwatch; 415 | 416 | /** 417 | * Verifies an Unwatch message. 418 | * @param {Object.} message Plain object to verify 419 | * @returns {?string} `null` if valid, otherwise the reason why it is not 420 | */ 421 | public static verify(message: { [k: string]: any }): string; 422 | 423 | /** 424 | * Creates an Unwatch message from a plain object. Also converts values to their respective internal types. 425 | * @param {Object.} object Plain object 426 | * @returns {actor.Unwatch} Unwatch 427 | */ 428 | public static fromObject(object: { [k: string]: any }): actor.Unwatch; 429 | 430 | /** 431 | * Creates an Unwatch message from a plain object. Also converts values to their respective internal types. 432 | * This is an alias of {@link actor.Unwatch.fromObject}. 433 | * @function 434 | * @param {Object.} object Plain object 435 | * @returns {actor.Unwatch} Unwatch 436 | */ 437 | public static from(object: { [k: string]: any }): actor.Unwatch; 438 | 439 | /** 440 | * Creates a plain object from an Unwatch message. Also converts values to other types if specified. 441 | * @param {actor.Unwatch} message Unwatch 442 | * @param {$protobuf.ConversionOptions} [options] Conversion options 443 | * @returns {Object.} Plain object 444 | */ 445 | public static toObject(message: actor.Unwatch, options?: $protobuf.ConversionOptions): { [k: string]: any }; 446 | 447 | /** 448 | * Creates a plain object from this Unwatch message. Also converts values to other types if specified. 449 | * @param {$protobuf.ConversionOptions} [options] Conversion options 450 | * @returns {Object.} Plain object 451 | */ 452 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 453 | 454 | /** 455 | * Converts this Unwatch to JSON. 456 | * @returns {Object.} JSON object 457 | */ 458 | public toJSON(): { [k: string]: any }; 459 | } 460 | 461 | type Terminated$Properties = { 462 | who?: actor.PID$Properties; 463 | AddressTerminated?: boolean; 464 | }; 465 | 466 | /** 467 | * Constructs a new Terminated. 468 | * @exports actor.Terminated 469 | * @constructor 470 | * @param {actor.Terminated$Properties=} [properties] Properties to set 471 | */ 472 | class Terminated { 473 | 474 | /** 475 | * Constructs a new Terminated. 476 | * @exports actor.Terminated 477 | * @constructor 478 | * @param {actor.Terminated$Properties=} [properties] Properties to set 479 | */ 480 | constructor(properties?: actor.Terminated$Properties); 481 | 482 | /** 483 | * Terminated who. 484 | * @type {(actor.PID$Properties|null)} 485 | */ 486 | public who: (actor.PID$Properties|null); 487 | 488 | /** 489 | * Terminated AddressTerminated. 490 | * @type {boolean} 491 | */ 492 | public AddressTerminated: boolean; 493 | 494 | /** 495 | * Creates a new Terminated instance using the specified properties. 496 | * @param {actor.Terminated$Properties=} [properties] Properties to set 497 | * @returns {actor.Terminated} Terminated instance 498 | */ 499 | public static create(properties?: actor.Terminated$Properties): actor.Terminated; 500 | 501 | /** 502 | * Encodes the specified Terminated message. Does not implicitly {@link actor.Terminated.verify|verify} messages. 503 | * @param {actor.Terminated$Properties} message Terminated message or plain object to encode 504 | * @param {$protobuf.Writer} [writer] Writer to encode to 505 | * @returns {$protobuf.Writer} Writer 506 | */ 507 | public static encode(message: actor.Terminated$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 508 | 509 | /** 510 | * Encodes the specified Terminated message, length delimited. Does not implicitly {@link actor.Terminated.verify|verify} messages. 511 | * @param {actor.Terminated$Properties} message Terminated message or plain object to encode 512 | * @param {$protobuf.Writer} [writer] Writer to encode to 513 | * @returns {$protobuf.Writer} Writer 514 | */ 515 | public static encodeDelimited(message: actor.Terminated$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 516 | 517 | /** 518 | * Decodes a Terminated message from the specified reader or buffer. 519 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 520 | * @param {number} [length] Message length if known beforehand 521 | * @returns {actor.Terminated} Terminated 522 | * @throws {Error} If the payload is not a reader or valid buffer 523 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 524 | */ 525 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Terminated; 526 | 527 | /** 528 | * Decodes a Terminated message from the specified reader or buffer, length delimited. 529 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 530 | * @returns {actor.Terminated} Terminated 531 | * @throws {Error} If the payload is not a reader or valid buffer 532 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 533 | */ 534 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Terminated; 535 | 536 | /** 537 | * Verifies a Terminated message. 538 | * @param {Object.} message Plain object to verify 539 | * @returns {?string} `null` if valid, otherwise the reason why it is not 540 | */ 541 | public static verify(message: { [k: string]: any }): string; 542 | 543 | /** 544 | * Creates a Terminated message from a plain object. Also converts values to their respective internal types. 545 | * @param {Object.} object Plain object 546 | * @returns {actor.Terminated} Terminated 547 | */ 548 | public static fromObject(object: { [k: string]: any }): actor.Terminated; 549 | 550 | /** 551 | * Creates a Terminated message from a plain object. Also converts values to their respective internal types. 552 | * This is an alias of {@link actor.Terminated.fromObject}. 553 | * @function 554 | * @param {Object.} object Plain object 555 | * @returns {actor.Terminated} Terminated 556 | */ 557 | public static from(object: { [k: string]: any }): actor.Terminated; 558 | 559 | /** 560 | * Creates a plain object from a Terminated message. Also converts values to other types if specified. 561 | * @param {actor.Terminated} message Terminated 562 | * @param {$protobuf.ConversionOptions} [options] Conversion options 563 | * @returns {Object.} Plain object 564 | */ 565 | public static toObject(message: actor.Terminated, options?: $protobuf.ConversionOptions): { [k: string]: any }; 566 | 567 | /** 568 | * Creates a plain object from this Terminated message. Also converts values to other types if specified. 569 | * @param {$protobuf.ConversionOptions} [options] Conversion options 570 | * @returns {Object.} Plain object 571 | */ 572 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 573 | 574 | /** 575 | * Converts this Terminated to JSON. 576 | * @returns {Object.} JSON object 577 | */ 578 | public toJSON(): { [k: string]: any }; 579 | } 580 | 581 | type Stop$Properties = {}; 582 | 583 | /** 584 | * Constructs a new Stop. 585 | * @exports actor.Stop 586 | * @constructor 587 | * @param {actor.Stop$Properties=} [properties] Properties to set 588 | */ 589 | class Stop { 590 | 591 | /** 592 | * Constructs a new Stop. 593 | * @exports actor.Stop 594 | * @constructor 595 | * @param {actor.Stop$Properties=} [properties] Properties to set 596 | */ 597 | constructor(properties?: actor.Stop$Properties); 598 | 599 | /** 600 | * Creates a new Stop instance using the specified properties. 601 | * @param {actor.Stop$Properties=} [properties] Properties to set 602 | * @returns {actor.Stop} Stop instance 603 | */ 604 | public static create(properties?: actor.Stop$Properties): actor.Stop; 605 | 606 | /** 607 | * Encodes the specified Stop message. Does not implicitly {@link actor.Stop.verify|verify} messages. 608 | * @param {actor.Stop$Properties} message Stop message or plain object to encode 609 | * @param {$protobuf.Writer} [writer] Writer to encode to 610 | * @returns {$protobuf.Writer} Writer 611 | */ 612 | public static encode(message: actor.Stop$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 613 | 614 | /** 615 | * Encodes the specified Stop message, length delimited. Does not implicitly {@link actor.Stop.verify|verify} messages. 616 | * @param {actor.Stop$Properties} message Stop message or plain object to encode 617 | * @param {$protobuf.Writer} [writer] Writer to encode to 618 | * @returns {$protobuf.Writer} Writer 619 | */ 620 | public static encodeDelimited(message: actor.Stop$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 621 | 622 | /** 623 | * Decodes a Stop message from the specified reader or buffer. 624 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 625 | * @param {number} [length] Message length if known beforehand 626 | * @returns {actor.Stop} Stop 627 | * @throws {Error} If the payload is not a reader or valid buffer 628 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 629 | */ 630 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Stop; 631 | 632 | /** 633 | * Decodes a Stop message from the specified reader or buffer, length delimited. 634 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 635 | * @returns {actor.Stop} Stop 636 | * @throws {Error} If the payload is not a reader or valid buffer 637 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 638 | */ 639 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Stop; 640 | 641 | /** 642 | * Verifies a Stop message. 643 | * @param {Object.} message Plain object to verify 644 | * @returns {?string} `null` if valid, otherwise the reason why it is not 645 | */ 646 | public static verify(message: { [k: string]: any }): string; 647 | 648 | /** 649 | * Creates a Stop message from a plain object. Also converts values to their respective internal types. 650 | * @param {Object.} object Plain object 651 | * @returns {actor.Stop} Stop 652 | */ 653 | public static fromObject(object: { [k: string]: any }): actor.Stop; 654 | 655 | /** 656 | * Creates a Stop message from a plain object. Also converts values to their respective internal types. 657 | * This is an alias of {@link actor.Stop.fromObject}. 658 | * @function 659 | * @param {Object.} object Plain object 660 | * @returns {actor.Stop} Stop 661 | */ 662 | public static from(object: { [k: string]: any }): actor.Stop; 663 | 664 | /** 665 | * Creates a plain object from a Stop message. Also converts values to other types if specified. 666 | * @param {actor.Stop} message Stop 667 | * @param {$protobuf.ConversionOptions} [options] Conversion options 668 | * @returns {Object.} Plain object 669 | */ 670 | public static toObject(message: actor.Stop, options?: $protobuf.ConversionOptions): { [k: string]: any }; 671 | 672 | /** 673 | * Creates a plain object from this Stop message. Also converts values to other types if specified. 674 | * @param {$protobuf.ConversionOptions} [options] Conversion options 675 | * @returns {Object.} Plain object 676 | */ 677 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 678 | 679 | /** 680 | * Converts this Stop to JSON. 681 | * @returns {Object.} JSON object 682 | */ 683 | public toJSON(): { [k: string]: any }; 684 | } 685 | } 686 | -------------------------------------------------------------------------------- /src/dispatcher.ts: -------------------------------------------------------------------------------- 1 | export class Dispatcher { 2 | throughput = 10; 3 | 4 | Schedule(fn: Function): void { 5 | fn() 6 | } 7 | 8 | GetThroughput(): number { 9 | return this.throughput 10 | } 11 | 12 | SetThroughput(t: number): void { 13 | this.throughput = t 14 | } 15 | } -------------------------------------------------------------------------------- /src/invoker.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "./messages"; 2 | import { PID } from "./pid" 3 | export interface IMessageInvoker { 4 | InvokeSystemMessage(message: any): Promise; 5 | InvokeUserMessage(message: any): Promise; 6 | EscalateFailure(error: any, child?: PID): void; 7 | } -------------------------------------------------------------------------------- /src/localContext.ts: -------------------------------------------------------------------------------- 1 | import { Props } from "./props"; 2 | import * as messages from "./messages"; 3 | import processRegistry from "./processRegistry"; 4 | import { IStrategy, ISupervisor, DefaultStrategy } from "./supervision"; 5 | import { RestartStatistics } from "./restartStatistics"; 6 | import { PID } from "./pid"; 7 | import { IActor, done } from "./actor"; 8 | import {IMessageInvoker} from "./invoker"; 9 | 10 | export interface IContext extends IMessageInvoker, ISupervisor { 11 | Children: PID[]; 12 | Message: any; 13 | Parent?: PID; 14 | Self: PID; 15 | Sender: PID; 16 | 17 | Tell(target: PID, message: any): void; 18 | Request(target: PID, message: any): void; 19 | RequestPromise(target: PID, message: any): Promise; 20 | Respond(message: any): void; 21 | 22 | Spawn(props: Props): PID; 23 | SpawnPrefix(props: Props, prefix: string): PID; 24 | SpawnNamed(props: Props, name: string): PID; 25 | 26 | //Watch(pid: PID) 27 | //Unwatch(pid: PID) 28 | 29 | //ReceiveTimeout: number 30 | //SetReceiveTimeout(timeoutMs: number): void; 31 | //ClearReceiveTimeout(timeoutMs: number): void; 32 | } 33 | 34 | export class LocalContext implements IContext { 35 | private restartStatistics: RestartStatistics; 36 | private restarting: boolean; 37 | private stopping: boolean; 38 | private Actor: IActor; 39 | private _behavior: Function[] = []; 40 | private _receive: Function; 41 | 42 | public Children: PID[] = []; 43 | public Self: PID; 44 | public Message: any; 45 | public Sender: PID; 46 | 47 | constructor(private producer: () => IActor, private supervisorStrategy: IStrategy, public Parent?: PID) { 48 | this._incarnateActor() 49 | } 50 | 51 | InvokeSystemMessage(message: messages.Message) { 52 | if (message instanceof messages.Started) { 53 | return this.InvokeUserMessage(message) 54 | } 55 | if (message instanceof messages.Stop) { 56 | return this._handleStop() 57 | } 58 | if (message instanceof messages.Terminated) { 59 | return this._handleTerminated(message) 60 | } 61 | if (message instanceof messages.Failure) { 62 | this._handleFailure(message) 63 | } 64 | if (message instanceof messages.Restart) { 65 | return this._handleRestart() 66 | } 67 | return done; 68 | } 69 | 70 | InvokeUserMessage(message: messages.Message) { 71 | return this._processMessage(message) 72 | } 73 | 74 | Tell(target: PID, message: any): void { 75 | // todo: sender middleware 76 | target.Tell(message) 77 | } 78 | 79 | Request(target: PID, message: any): void { 80 | target.Request(message, this.Self) 81 | } 82 | 83 | RequestPromise(target: PID, message: any, timeoutMs?: number): Promise { 84 | return target.RequestPromise(message, timeoutMs) 85 | } 86 | 87 | Respond(message: messages.Message) { 88 | return this.Sender.Tell(message) 89 | } 90 | 91 | EscalateFailure(exception: any, who: PID) { 92 | if (!who) { 93 | who = this.Self 94 | } 95 | if (this.restartStatistics == undefined) { 96 | this.restartStatistics = new RestartStatistics() 97 | } 98 | if (!this.Parent) { 99 | // failure.Who was prev this.Self, seemed odd? 100 | DefaultStrategy.HandleFailure(this, who, this.restartStatistics, exception) 101 | } else { 102 | var failure = new messages.Failure(who, exception, this.restartStatistics) 103 | this.Self.SendSystemMessage(messages.SuspendMailbox.Instance) 104 | this.Parent.SendSystemMessage(failure) 105 | } 106 | } 107 | 108 | RestartChildren(...pids: PID[]) { 109 | for (var i = 0; i < pids.length; i++) { 110 | pids[i].SendSystemMessage(messages.Restart.Instance) 111 | } 112 | } 113 | 114 | StopChildren(...pids: PID[]) { 115 | for (var i = 0; i < pids.length; i++) { 116 | pids[i].SendSystemMessage(messages.Stop.Instance) 117 | } 118 | } 119 | 120 | ResumeChildren(...pids: PID[]) { 121 | for (var i = 0; i < pids.length; i++) { 122 | pids[i].SendSystemMessage(messages.ResumeMailbox.Instance) 123 | } 124 | } 125 | 126 | Spawn(props: Props) { 127 | var name = processRegistry.NextId() 128 | return this.SpawnNamed(props, name) 129 | } 130 | 131 | SpawnPrefix(props: Props, prefix: string) { 132 | var name = prefix + processRegistry.NextId() 133 | return this.SpawnNamed(props, name) 134 | } 135 | 136 | SpawnNamed(props: Props, name: string) { 137 | let pid:PID = props.Spawn(this.Self.Id + '/' + name, this.Self) 138 | this.Children.push(pid) 139 | return pid 140 | } 141 | 142 | SetBehavior(receive: Function) { 143 | this._behavior = [] 144 | this.PushBehavior(receive) 145 | } 146 | 147 | PushBehavior(receive: Function) { 148 | this._behavior.push(receive) 149 | this._receive = receive 150 | } 151 | 152 | PopBehavior(receive?: Function) { 153 | if (this._behavior.length <= 1) { 154 | throw "Cannot pop actor's last behavior" 155 | } 156 | this._behavior.pop() 157 | this._receive = this._behavior[this._behavior.length - 1] 158 | } 159 | 160 | _incarnateActor() { 161 | this.Actor = this.producer() 162 | this.SetBehavior(this.Actor.Receive.bind(this.Actor)) 163 | } 164 | 165 | async _handleStop() { 166 | this.restarting = false 167 | this.stopping = true 168 | await this.InvokeUserMessage(messages.Stopping.Instance) 169 | if (this.Children && this.Children.length > 0) { 170 | for (var i = 0; i < this.Children.length; i++) { 171 | this.Children[i].Stop() 172 | } 173 | } 174 | await this._tryRestartOrTerminate() 175 | } 176 | 177 | async _handleTerminated(terminated: messages.Terminated) { 178 | this.Children.splice(this.Children.indexOf(terminated.Who), 1); 179 | await this.InvokeUserMessage(terminated) 180 | await this._tryRestartOrTerminate() 181 | } 182 | 183 | _handleFailure(failure: messages.Failure) { 184 | this.supervisorStrategy.HandleFailure(this, failure.Who, failure.RestartStatistics, failure.Reason); 185 | } 186 | 187 | async _handleRestart() { 188 | this.stopping = false 189 | this.restarting = true 190 | await this.InvokeUserMessage(messages.Restarting.Instance) 191 | if (this.Children && this.Children.length > 0) { 192 | for (var i = 0; i < this.Children.length; i++) { 193 | this.Children[i].Stop() 194 | } 195 | } 196 | await this._tryRestartOrTerminate 197 | } 198 | 199 | _tryRestartOrTerminate() { 200 | if (this.Children && this.Children.length > 0) { 201 | return 202 | } 203 | if (this.restarting) { 204 | return this._restart() 205 | } 206 | if (this.stopping) { 207 | return this._stopped() 208 | } 209 | } 210 | 211 | _restart() { 212 | this._incarnateActor() 213 | this.Self.SendSystemMessage(messages.ResumeMailbox.Instance) 214 | return this.InvokeUserMessage(messages.Started) 215 | } 216 | 217 | _stopped() { 218 | processRegistry.Remove(this.Self) 219 | return this.InvokeUserMessage(messages.Stopped.Instance) 220 | } 221 | 222 | _processMessage(message: messages.Message) { 223 | if (message instanceof messages.MessageSender) { 224 | this.Message = message.Message 225 | this.Sender = message.Sender 226 | } else { 227 | this.Message = message 228 | } 229 | return this._receive(this) 230 | } 231 | } 232 | 233 | 234 | -------------------------------------------------------------------------------- /src/localProcess.ts: -------------------------------------------------------------------------------- 1 | import { IMailbox } from "./mailbox"; 2 | import { PID } from "./pid"; 3 | import { IProcess } from "./process"; 4 | import * as messages from "./messages"; 5 | 6 | export class LocalProcess implements IProcess { 7 | public IsDead:boolean 8 | constructor(private Mailbox: IMailbox) { 9 | 10 | } 11 | 12 | SendUserMessage(pid: PID, message: string, sender?: PID) { 13 | if (sender) { 14 | this.Mailbox.PostUserMessage(new messages.MessageSender(message, sender)) 15 | } 16 | this.Mailbox.PostUserMessage(message) 17 | } 18 | 19 | SendSystemMessage(pid: PID, message: messages.Message) { 20 | this.Mailbox.PostSystemMessage(message) 21 | } 22 | 23 | Stop(pid: PID) { 24 | this.SendSystemMessage(pid, messages.Stop.Instance) 25 | } 26 | } -------------------------------------------------------------------------------- /src/mailbox.ts: -------------------------------------------------------------------------------- 1 | import { IQueue, Queue } from "./queue"; 2 | import { Dispatcher } from "./dispatcher"; 3 | import { IMessageInvoker } from "./invoker"; 4 | import * as messages from "./messages" 5 | // import {Queue2} from "./queue2"; 6 | export interface IStatistics { 7 | UserMessagePosted(message: messages.Message): void; 8 | SystemMessagePosted(message: messages.Message): void; 9 | UserMessageReceived(message: messages.Message): void; 10 | SystemMessageReceived(message: messages.Message): void; 11 | MailboxStarted(): void; 12 | MailboxEmpty(): void; 13 | } 14 | export interface IMailbox { 15 | PostUserMessage(message: messages.Message): void 16 | PostSystemMessage(message: messages.Message): void 17 | RegisterHandlers(invoker: IMessageInvoker, dispatcher: Dispatcher): void; 18 | Start(): void; 19 | } 20 | export class Mailbox implements IMailbox { 21 | private running = false; 22 | private dispatcher: Dispatcher 23 | private invoker: IMessageInvoker 24 | private suspended: boolean = false 25 | constructor(private systemMessageQueue: IQueue, 26 | private userMessageQueue: IQueue, 27 | private mailboxStatistics: IStatistics[] = []) { 28 | } 29 | 30 | PostUserMessage(message: messages.Message) { 31 | for (var i = 0; i < this.mailboxStatistics.length; i++) { 32 | this.mailboxStatistics[i].UserMessagePosted(message) 33 | } 34 | this.userMessageQueue.enqueue(message) 35 | this.processMessages() 36 | } 37 | 38 | PostSystemMessage(message: messages.Message) { 39 | for (var i = 0; i < this.mailboxStatistics.length; i++) { 40 | this.mailboxStatistics[i].SystemMessagePosted(message) 41 | } 42 | this.systemMessageQueue.enqueue(message) 43 | this.processMessages() 44 | } 45 | 46 | RegisterHandlers(invoker: IMessageInvoker, dispatcher: Dispatcher) { 47 | this.invoker = invoker 48 | this.dispatcher = dispatcher 49 | } 50 | 51 | Start() { 52 | for (var i = 0; i < this.mailboxStatistics.length; i++) { 53 | this.mailboxStatistics[i].MailboxStarted() 54 | } 55 | } 56 | 57 | processMessages() { 58 | if (this.running) return 59 | 60 | if (!this.systemMessageQueue.isEmpty() || !this.userMessageQueue.isEmpty()) { 61 | this.schedule() 62 | } 63 | } 64 | 65 | schedule() { 66 | this.running = true; 67 | this.dispatcher.Schedule(this.run.bind(this)); 68 | } 69 | 70 | async run() { 71 | var msg 72 | try { 73 | for (var i = 0; i < this.dispatcher.GetThroughput(); i++) { 74 | msg = this.systemMessageQueue.dequeue() 75 | if (msg != undefined) { 76 | if (msg instanceof messages.SuspendMailbox) { 77 | this.suspended = true 78 | } 79 | if (msg instanceof messages.ResumeMailbox) { 80 | this.suspended = false 81 | } 82 | await this.invoker.InvokeSystemMessage(msg) 83 | for (var j = 0; j < this.mailboxStatistics.length; j++) { 84 | this.mailboxStatistics[i].SystemMessageReceived(msg) 85 | } 86 | continue 87 | } 88 | if (this.suspended) { 89 | break 90 | } 91 | msg = this.userMessageQueue.dequeue() 92 | if (msg != undefined) { 93 | await this.invoker.InvokeUserMessage(msg) 94 | for (var j = 0; j < this.mailboxStatistics.length; j++) { 95 | this.mailboxStatistics[i].UserMessageReceived(msg) 96 | } 97 | } else { 98 | break 99 | } 100 | } 101 | } catch (e) { 102 | this.invoker.EscalateFailure(e) 103 | } 104 | this.running = false; 105 | if (!this.systemMessageQueue.isEmpty() || !this.userMessageQueue.isEmpty()) { 106 | setImmediate(this.schedule.bind(this)); 107 | } else { 108 | for (var i = 0; i < this.mailboxStatistics.length; i++) { 109 | this.mailboxStatistics[i].MailboxEmpty() 110 | } 111 | } 112 | return Promise.resolve() 113 | } 114 | 115 | // experimental (currently slower) implementation... 116 | run2() { 117 | var msg 118 | try { 119 | msg = this.systemMessageQueue.dequeue() 120 | if (msg != undefined) { 121 | if (msg instanceof messages.SuspendMailbox) { 122 | this.suspended = true 123 | } 124 | if (msg instanceof messages.ResumeMailbox) { 125 | this.suspended = false 126 | } 127 | this.invoker.InvokeSystemMessage(msg) 128 | .then(this.handleSuccess(msg)) 129 | .catch(this.handleError) 130 | return 131 | } 132 | if (this.suspended) { 133 | return 134 | } 135 | msg = this.userMessageQueue.dequeue() 136 | if (msg != undefined) { 137 | this.invoker.InvokeUserMessage(msg) 138 | .then(this.handleSuccess(msg)) 139 | .catch(this.handleError) 140 | return 141 | } else { 142 | return 143 | } 144 | } catch (e) { 145 | this.invoker.EscalateFailure(e) 146 | } 147 | this.running = false; 148 | if (!this.systemMessageQueue.isEmpty() || !this.userMessageQueue.isEmpty()) { 149 | setImmediate(this.schedule.bind(this)); 150 | } else { 151 | for (var i = 0; i < this.mailboxStatistics.length; i++) { 152 | this.mailboxStatistics[i].MailboxEmpty() 153 | } 154 | } 155 | } 156 | handleSuccess(msg: any) { 157 | return () => { 158 | for (var i = 0; i < this.mailboxStatistics.length; i++) { 159 | this.mailboxStatistics[i].SystemMessageReceived(msg) 160 | } 161 | setImmediate(this.schedule.bind(this)); 162 | } 163 | } 164 | handleError(reason: any) { 165 | this.invoker.EscalateFailure(reason) 166 | setImmediate(this.schedule.bind(this)); 167 | } 168 | } 169 | 170 | export const Unbounded = (...statistics: IStatistics[]) => new Mailbox(new Queue(), new Queue(), statistics || []); -------------------------------------------------------------------------------- /src/messages.ts: -------------------------------------------------------------------------------- 1 | import { PID } from "./pid"; 2 | import { RestartStatistics } from "./restartStatistics"; 3 | export * from "./actor_pb"; 4 | 5 | export type Message = { } 6 | export class Started { 7 | static Instance: Started = new Started() 8 | private constructor() { } 9 | } 10 | export class Stop { 11 | static Instance: Stop = new Stop() 12 | private constructor() { } 13 | } 14 | export class Stopping { 15 | static Instance: Stopping = new Stopping() 16 | private constructor() { } 17 | } 18 | export class Stopped { 19 | static Instance: Stopped = new Stopped() 20 | private constructor() { } 21 | } 22 | export class Restart { 23 | static Instance: Restart = new Restart() 24 | private constructor() { } 25 | } 26 | export class Restarting { 27 | static Instance: Restarting = new Restarting() 28 | private constructor() { } 29 | } 30 | export class Terminated { 31 | constructor(public Who: PID) { } 32 | } 33 | export class ResumeMailbox { 34 | static Instance: ResumeMailbox = new ResumeMailbox() 35 | private constructor() { } 36 | } 37 | export class SuspendMailbox { 38 | static Instance: SuspendMailbox = new SuspendMailbox() 39 | private constructor() { } 40 | } 41 | export class MessageSender { 42 | constructor(public Message: string, public Sender: PID) { } 43 | } 44 | export class Failure { 45 | constructor(public Who: PID, public Reason: string, public RestartStatistics: RestartStatistics) { } 46 | } 47 | -------------------------------------------------------------------------------- /src/pid.ts: -------------------------------------------------------------------------------- 1 | import { IProcess } from "./process"; 2 | import { PromiseProcess } from "./promiseProcess"; 3 | import processRegistry from "./processRegistry"; 4 | import { Message } from "./messages"; 5 | import * as messages from "./actor_pb"; 6 | import { LocalProcess } from "./localProcess" 7 | 8 | export class PID extends messages.actor.PID { 9 | private _p:IProcess|undefined; 10 | constructor(public Address: string, public Id: string) { 11 | super(); 12 | } 13 | 14 | get Ref():IProcess|undefined { 15 | let p = this._p; 16 | if (p) { 17 | if (p instanceof LocalProcess && p.IsDead) { 18 | this._p = undefined; 19 | } 20 | return this._p 21 | } else { 22 | let reff = processRegistry.Get(this) 23 | this._p = reff 24 | return this._p 25 | } 26 | } 27 | 28 | Tell(message: Message) { 29 | let reff = this.Ref || processRegistry.Get(this) 30 | reff.SendUserMessage(this, message) 31 | } 32 | 33 | SendSystemMessage(message: Message) { 34 | let reff = this.Ref || processRegistry.Get(this) 35 | reff.SendSystemMessage(this, message) 36 | } 37 | 38 | RequestPromise(message: Message, timeoutMs: number = 0) { 39 | let p = new PromiseProcess(timeoutMs) 40 | let id = processRegistry.NextId() 41 | let pid = processRegistry.TryAdd(id, p) 42 | this.Request(message, pid) 43 | return p.Promise; 44 | } 45 | 46 | Request(message: Message, sender: PID) { 47 | let reff = this.Ref || processRegistry.Get(this) 48 | reff.SendUserMessage(this, message, sender) 49 | } 50 | 51 | Stop() { 52 | let reff = this.Ref || processRegistry.Get(this) 53 | reff.Stop() 54 | processRegistry.Remove(this) 55 | } 56 | 57 | ToShortString() { 58 | return this.Address + '/' + this.Id; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/process.ts: -------------------------------------------------------------------------------- 1 | import { PID } from "./pid"; 2 | import { Message } from "./messages"; 3 | 4 | export interface IProcess { 5 | SendUserMessage(pid: PID, message: Message, sender?: PID): void; 6 | SendSystemMessage(pid: PID, message: Message): void; 7 | Stop(pid?: PID): void; 8 | } -------------------------------------------------------------------------------- /src/processRegistry.ts: -------------------------------------------------------------------------------- 1 | import { PID } from "./pid"; 2 | import { IProcess } from "./process"; 3 | 4 | export type IProcessResolver = (pid: PID) => IProcess; 5 | export class ProcessRegistry { 6 | private localActorRefs: { [Id: string]: any } = {}; 7 | private counter = 0; 8 | private hostResolvers: IProcessResolver[] = []; 9 | public Address = "nonhost"; 10 | Get(pid: PID) { 11 | if (pid.Address != "nonhost" && pid.Address != this.Address) { 12 | for(let resolver of this.hostResolvers) { 13 | let ref = resolver(pid) 14 | if (ref) { 15 | return ref 16 | } 17 | } 18 | throw "Unknown host" 19 | } 20 | return this.localActorRefs[pid.Id] // todo - deadletter 21 | } 22 | 23 | TryAdd(id: string, ref: IProcess) { 24 | var pid = new PID(this.Address, id); 25 | this.localActorRefs[pid.Id] = ref; 26 | return pid; 27 | } 28 | 29 | NextId() { 30 | return "$" + this.counter++ 31 | } 32 | 33 | Remove(pid: PID) { 34 | this.localActorRefs[pid.Id] = undefined 35 | } 36 | RegisterHostResolver(resolver: IProcessResolver) { 37 | this.hostResolvers.push(resolver) 38 | } 39 | 40 | } 41 | const processRegistry = new ProcessRegistry(); 42 | 43 | export default processRegistry; 44 | -------------------------------------------------------------------------------- /src/promiseProcess.ts: -------------------------------------------------------------------------------- 1 | import { PID } from "./pid" 2 | import { Message } from "./messages" 3 | import { IProcess } from "./process" 4 | 5 | export class PromiseProcess implements IProcess { 6 | public PID: PID 7 | public Promise: Promise 8 | private timer: any 9 | private resolved: boolean 10 | 11 | constructor(timeoutMs: number) { 12 | this.Promise = new Promise((resolve, reject) => { 13 | this.resolve = value => { 14 | this.resolved = true 15 | resolve(value) 16 | }; 17 | this.reject = reject; 18 | if(timeoutMs) { 19 | this.timer = setTimeout(() => { 20 | if (!this.resolved) { 21 | reject(`Requested promise timed out after ${timeoutMs} ms.`) 22 | } 23 | }, timeoutMs) 24 | } 25 | }); 26 | } 27 | 28 | private resolve: (value?: Message) => void; 29 | private reject: (value?: string) => void; 30 | 31 | SendUserMessage(pid: PID, message: Message, sender?: PID) { 32 | this.resolve(message) 33 | return this.Promise; 34 | //this.PID.Stop() 35 | } 36 | 37 | SendSystemMessage(pid: PID, message: Message) { 38 | global.console.log(`PID:${pid.Id}, SystemMessage:${message}`) 39 | return Promise.resolve() 40 | } 41 | 42 | Stop(pid?: PID) { 43 | throw "Not implemented, PID: " + (pid && pid.Id); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/props.ts: -------------------------------------------------------------------------------- 1 | import * as messages from './messages'; 2 | import { Dispatcher } from './dispatcher'; 3 | import { DefaultStrategy, IStrategy } from './supervision'; 4 | import processRegistry from './processRegistry'; 5 | import { LocalContext } from './localContext'; 6 | import { LocalProcess } from './localProcess'; 7 | import {Unbounded, IMailbox} from "./mailbox"; 8 | import { PID } from './pid'; 9 | import { IActor } from "./actor"; 10 | 11 | export interface ISpawner { 12 | (props: Props, name: string, parent?: PID): PID 13 | } 14 | export class Props { 15 | mailboxProducer = (): IMailbox => Unbounded(); 16 | dispatcher = new Dispatcher(); 17 | supervisorStrategy: IStrategy = DefaultStrategy; 18 | spawner: ISpawner = Props.DefaultSpawner; 19 | producer: () => IActor; 20 | WithProducer(producer: () => IActor) { 21 | this.producer = producer 22 | return this 23 | } 24 | 25 | WithDispatcher(dispatcher: Dispatcher) { 26 | this.dispatcher = dispatcher 27 | return this 28 | } 29 | 30 | WithSupervisor(supervisor: IStrategy) { 31 | this.supervisorStrategy = supervisor 32 | return this 33 | } 34 | 35 | WithSpawner(spawner: ISpawner) { 36 | this.spawner = spawner 37 | return this 38 | } 39 | 40 | Spawn(name: string, parent?: PID): PID { 41 | return this.spawner(this, name, parent) 42 | } 43 | 44 | WithMailbox(producer: () => IMailbox) { 45 | this.mailboxProducer = producer; 46 | return this; 47 | } 48 | 49 | static DefaultSpawner(props: Props, name: string, parent?: PID): PID { 50 | var context = new LocalContext(props.producer, props.supervisorStrategy, parent) 51 | var mailbox = props.mailboxProducer() 52 | var dispatcher = props.dispatcher 53 | var ref = new LocalProcess(mailbox) 54 | var pid = processRegistry.TryAdd(name, ref) 55 | context.Self = pid 56 | mailbox.RegisterHandlers(context, dispatcher) 57 | mailbox.PostSystemMessage(messages.Started.Instance) 58 | mailbox.Start() 59 | return pid 60 | } 61 | } -------------------------------------------------------------------------------- /src/queue.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Adapted from Queue.js. Original license: 3 | 4 | A function to represent a queue 5 | 6 | Created by Stephen Morley - http://code.stephenmorley.org/ - and released under 7 | the terms of the CC0 1.0 Universal legal code: 8 | 9 | http://creativecommons.org/publicdomain/zero/1.0/legalcode 10 | 11 | */ 12 | 13 | export interface IQueue { 14 | getLength(): number 15 | enqueue(item: any): void 16 | dequeue(): any; 17 | peek(): any; 18 | isEmpty(): boolean; 19 | } 20 | 21 | export class Queue implements IQueue { 22 | private queue: any[] = [] 23 | private offset = 0 24 | 25 | getLength(): number { 26 | return this.queue.length - this.offset 27 | } 28 | enqueue(item: any) { 29 | this.queue.push(item) 30 | } 31 | dequeue() { 32 | if (this.queue.length == 0) return undefined; 33 | 34 | // store the item at the front of the queue 35 | var item = this.queue[this.offset]; 36 | 37 | // increment the offset and remove the free space if necessary 38 | if (++this.offset * 2 >= this.queue.length) { 39 | this.queue = this.queue.slice(this.offset); 40 | this.offset = 0; 41 | } 42 | 43 | // return the dequeued item 44 | return item; 45 | } 46 | peek() { 47 | return (this.queue.length > 0 ? this.queue[this.offset] : undefined); 48 | } 49 | isEmpty(): boolean { 50 | return this.queue.length == 0 51 | } 52 | } -------------------------------------------------------------------------------- /src/queue2.ts: -------------------------------------------------------------------------------- 1 | import {IQueue} from "./queue"; 2 | 3 | export class Queue2 implements IQueue { 4 | private buffer: any[] = []; 5 | private head = 0; 6 | private tail = 0; 7 | private dequeuePromise: Promise | null; 8 | 9 | private dequeuePromiseResolve: () => void; 10 | private dequeuePromiseReject: () => void; 11 | 12 | enqueue(o: any) { 13 | this.buffer[this.head++] = o 14 | if (this.head == this.buffer.length) { 15 | if (!this.dequeuePromise) { 16 | this.dequeuePromise = new Promise((resolve, reject) => { 17 | this.dequeuePromiseResolve = resolve; 18 | this.dequeuePromiseReject = reject; 19 | }) 20 | } 21 | return this.dequeuePromise 22 | } 23 | return Promise.resolve() 24 | } 25 | 26 | dequeue() { 27 | if (this.tail == this.head) 28 | return undefined; 29 | var item = this.buffer[this.tail++]; 30 | this.dequeuePromise = null; 31 | this.dequeuePromiseResolve() 32 | return item 33 | } 34 | 35 | getLength() { 36 | return this.head - this.tail 37 | } 38 | 39 | isEmpty() { 40 | return this.getLength() == 0 41 | } 42 | 43 | peek() { 44 | return (this.buffer.length > 0 ? this.buffer[this.tail] : undefined) 45 | } 46 | 47 | _reconstruct() { 48 | this.buffer = this.buffer.slice(this.tail).concat(new Array(this.getLength()*2)) 49 | this.head -= this.tail 50 | this.tail = 0 51 | } 52 | } -------------------------------------------------------------------------------- /src/remote/remote.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | package remote; 4 | 5 | import "actor.proto"; 6 | 7 | message MessageBatch { 8 | repeated string type_names=1; 9 | repeated string target_names=2; 10 | repeated MessageEnvelope envelopes = 3; 11 | } 12 | 13 | message MessageEnvelope { 14 | int32 type_id = 1; 15 | bytes message_data = 2; 16 | int32 target = 3; 17 | actor.PID sender = 4; 18 | } 19 | 20 | message ActorPidRequest { 21 | string name = 1; 22 | string kind = 2; 23 | } 24 | 25 | message ActorPidResponse { 26 | actor.PID pid = 1; 27 | } 28 | 29 | message Unit {} 30 | 31 | service Remoting { 32 | rpc Receive (stream MessageBatch) returns (stream Unit) {} 33 | } 34 | -------------------------------------------------------------------------------- /src/remote/remote.ts: -------------------------------------------------------------------------------- 1 | let grpc = require('grpc') 2 | import * as pb from "google-protobuf"; 3 | import * as messages from "../messages"; 4 | import * as remoteProto from "./remote_pb"; 5 | import processRegistry from "../processRegistry"; 6 | import { IProcess } from "../process"; 7 | import * as actor from "../actor"; 8 | import { PID } from "../pid"; 9 | import { Queue, IQueue } from "../queue"; 10 | import { Props } from "../props"; 11 | import { LocalContext } from "../localContext"; 12 | import { IMessageInvoker } from "../invoker"; 13 | import { Dispatcher } from "../dispatcher"; 14 | import { IMailbox } from "../mailbox"; 15 | import * as protobuf from "protobufjs"; 16 | 17 | // TODO: Should be generated from *.proto ? 18 | class EndpointReader { 19 | Receive(call: { on(event: string, cb: (batch: remoteProto.remote.MessageBatch) => void): void }) { 20 | let self = this 21 | call.on('data', messageBatch => self._processMessageBatch(messageBatch)) 22 | } 23 | 24 | _processMessageBatch(messageBatch: remoteProto.remote.MessageBatch) { 25 | let targetNames = messageBatch.targetNames 26 | let typeNames = messageBatch.typeNames 27 | let envelopes = messageBatch.envelopes 28 | 29 | for (let i = 0; i < envelopes.length; i++) { 30 | let envelope = envelopes[i] 31 | if (envelope.messageData==undefined || envelope.sender==undefined || envelope.target==undefined || envelope.typeId==undefined) { 32 | console.error('Invalid envelope!') 33 | continue; 34 | } 35 | let targetName = targetNames[envelope.target || 0] 36 | 37 | let target = new PID(processRegistry.Address, targetName) 38 | let sender = new PID(envelope.sender.Address || '', envelope.sender.Id || '') 39 | let typeName = typeNames[envelope.typeId || 0] 40 | 41 | let message = Serialization.Deserialize(typeName, envelope.messageData||new Uint8Array(0)) 42 | // todo - handle Terminated and SystemMessages 43 | target.Request(message, sender) 44 | } 45 | } 46 | } 47 | 48 | class EndpointManager implements actor.IActor { 49 | 50 | connections: {[adress: string]: Endpoint } = {} 51 | async Receive(context: LocalContext) { 52 | let msg = context.Message 53 | // todo - handle EndpointTerminatedEvent, RemoteTerminate, RemoteWatch, RemoteUnwatch 54 | if (msg instanceof RemoteDeliver) { 55 | let ep = await this._ensureConnected(msg.Target.Address, context) 56 | ep.Writer.Tell(msg) 57 | } 58 | } 59 | 60 | async _ensureConnected(address: string, context: LocalContext) { 61 | let ep = this.connections[address] 62 | if (!ep) { 63 | let writer = await this._spawnWriter(address, context) 64 | let watcher = await this._spawnWatcher(address, context) 65 | ep = new Endpoint(writer, watcher) 66 | this.connections[address] = ep 67 | } 68 | return ep 69 | } 70 | 71 | async _spawnWriter(address: string, context: LocalContext) { 72 | let props = actor.fromProducer(() => new EndpointWriter(address)) 73 | .WithMailbox(() => new EndpointWriterMailbox(1000)) 74 | let writer = await actor.spawn(props) 75 | return writer 76 | } 77 | 78 | async _spawnWatcher(address: string, context: LocalContext) { 79 | // todo 80 | return null 81 | } 82 | } 83 | 84 | class EndpointWriter implements actor.IActor { 85 | private client: any; 86 | private call: any; 87 | constructor(private address: string) { 88 | 89 | } 90 | 91 | async Receive(context: LocalContext) { 92 | let message = context.Message 93 | if (message instanceof messages.Started) { 94 | await this._started() 95 | } 96 | if (message instanceof RemoteDeliverArray) { 97 | let targetIds: {[targetName: string]: number} = {} 98 | let targetNames = [] 99 | let typeIds: {[typeName: string]: number} = {} 100 | let typeNames = [] 101 | let batch = new remoteProto.remote.MessageBatch() 102 | 103 | for (let rd of message) { 104 | let targetName = rd.Target.Id 105 | if (batch.targetNames.indexOf(targetName) < 0) { 106 | targetIds[targetName] = targetNames.length 107 | batch.targetNames.push(targetName) 108 | } 109 | let targetId = targetIds[targetName] 110 | 111 | //let typeName = rd.constructor.name; 112 | let typeName = Serialization.LookupTypeName(rd.Message) 113 | if (batch.typeNames.indexOf(typeName) < 0) { 114 | typeIds[typeName] = typeNames.length 115 | batch.typeNames.push(typeName) 116 | } 117 | let typeId = typeIds[typeName] 118 | 119 | let bytes = Serialization.Serialize(rd.Message) 120 | let envelope = new remoteProto.remote.MessageEnvelope() 121 | batch.envelopes.push({ 122 | messageData: bytes, 123 | sender: rd.Sender || new PID('', ''), 124 | target: targetId, 125 | typeId: typeId 126 | }) 127 | } 128 | 129 | await this._sendEnvelopes(batch, context) 130 | } 131 | } 132 | 133 | async _started() { 134 | //let rpcImpl = new protobuf.Service('Remoting') 135 | this.client = new RemoteClient(this.address, grpc.credentials.createInsecure()) 136 | this.call = this.client.receive() 137 | } 138 | 139 | async _sendEnvelopes(messageBatch: remoteProto.remote.MessageBatch, context: LocalContext) { 140 | this.call.write(messageBatch) 141 | } 142 | } 143 | class RemoteDeliverArray extends Array { 144 | } 145 | 146 | class EndpointWriterMailbox implements IMailbox { 147 | running: boolean; 148 | systemMessageQueue: IQueue = new Queue() 149 | userMessageQueue: IQueue = new Queue() 150 | constructor(private batchSize: number) { 151 | 152 | } 153 | 154 | async PostUserMessage(message: messages.Message) { 155 | await this.userMessageQueue.enqueue(message) 156 | this.processMessages() 157 | } 158 | 159 | async PostSystemMessage(message: messages.Message) { 160 | await this.systemMessageQueue.enqueue(message) 161 | this.processMessages() 162 | } 163 | private invoker: IMessageInvoker; 164 | private dispatcher: Dispatcher; 165 | RegisterHandlers(invoker: IMessageInvoker, dispatcher: Dispatcher) { 166 | this.invoker = invoker 167 | this.dispatcher = dispatcher 168 | } 169 | 170 | Start() { 171 | } 172 | 173 | async processMessages() { 174 | if (this.running) return 175 | 176 | if (!this.systemMessageQueue.isEmpty() || !this.userMessageQueue.isEmpty()) { 177 | this.schedule() 178 | } 179 | } 180 | 181 | schedule() { 182 | this.running = true; 183 | this.dispatcher.Schedule(this.run.bind(this)); 184 | } 185 | 186 | async run() { 187 | let batch = new RemoteDeliverArray() 188 | 189 | let sys = this.systemMessageQueue.dequeue() 190 | if (sys != undefined) { 191 | await this.invoker.InvokeSystemMessage(sys) 192 | } 193 | 194 | while (batch.length < this.batchSize) { 195 | let msg = this.userMessageQueue.dequeue() 196 | if (!msg) 197 | break 198 | batch.push(msg) 199 | } 200 | await this.invoker.InvokeUserMessage(batch) 201 | 202 | this.running = false; 203 | if (!this.systemMessageQueue.isEmpty() || !this.userMessageQueue.isEmpty()) { 204 | this.schedule(); 205 | } 206 | } 207 | } 208 | 209 | class Endpoint { 210 | constructor(public Writer: PID, public Watcher: null) { 211 | 212 | } 213 | } 214 | 215 | class Activator implements actor.IActor { 216 | async Receive(context: LocalContext) { 217 | let msg = context.Message 218 | if (msg instanceof remoteProto.remote.ActorPidRequest) { 219 | let props = Remote.GetKnownKind(msg.kind) 220 | let name = msg.name 221 | if (!name) { 222 | name = processRegistry.NextId() 223 | } 224 | let pid = actor.spawnNamed(props, name) 225 | let response = new remoteProto.remote.ActorPidResponse({ 226 | pid: pid 227 | }) 228 | context.Respond(response) 229 | } 230 | } 231 | } 232 | 233 | class RemoteProcess implements IProcess { 234 | Stop(pid?: PID): void { 235 | throw new Error('Method not implemented.'); 236 | } 237 | 238 | SendUserMessage(pid: PID, message: any, sender?: PID) { 239 | this._send(pid, message, sender) 240 | } 241 | 242 | SendSystemMessage(pid: PID, message: any) { 243 | this._send(pid, message) 244 | } 245 | 246 | _send(pid: PID, message: any, sender?: PID) { 247 | // todo - handle watch/unwatch 248 | let env = new RemoteDeliver(pid, message, sender) 249 | Remote.EndpointManager.Tell(env) 250 | } 251 | } 252 | 253 | class RemoteDeliver { 254 | constructor(public Target: PID, public Message: any, public Sender?: PID) { 255 | 256 | } 257 | } 258 | 259 | var RemoteService = { 260 | // Sends a greeting 261 | receive: { 262 | path: '/remote.Remoting/Receive', 263 | requestStream: true, 264 | responseStream: true, 265 | requestType: remoteProto.remote.MessageBatch, 266 | responseType: remoteProto.remote.Unit, 267 | requestSerialize: (message: remoteProto.remote.MessageBatch$Properties) => { 268 | let writer = remoteProto.remote.MessageBatch.encode(message) 269 | return writer.finish() 270 | }, 271 | requestDeserialize: remoteProto.remote.MessageBatch.decode, 272 | responseSerialize: (message: remoteProto.remote.Unit$Properties) => { 273 | let writer = remoteProto.remote.Unit.encode(message) 274 | return writer.finish() 275 | }, 276 | responseDeserialize: remoteProto.remote.Unit.decode, 277 | }, 278 | }; 279 | var RemoteClient = grpc.makeGenericClientConstructor(RemoteService) 280 | 281 | export class Remote { 282 | static kinds: { [kind: string]: Props } = {} 283 | static EndpointManager: PID; 284 | static Activator: PID; 285 | static async Start(host: string, port: number) { 286 | let addr = host + ':' + port 287 | processRegistry.RegisterHostResolver(pid => new RemoteProcess()) 288 | 289 | let server = new grpc.Server() 290 | let endpointReader = new EndpointReader() 291 | server.addService(RemoteService, { 292 | receive: endpointReader.Receive.bind(endpointReader) 293 | }) 294 | server.bind(addr, grpc.ServerCredentials.createInsecure()) 295 | server.start() 296 | 297 | processRegistry.Address = addr 298 | 299 | this.EndpointManager = await actor.spawn(actor.fromProducer(() => new EndpointManager())) 300 | this.Activator = await actor.spawnNamed(actor.fromProducer(() => new Activator()), "activator") 301 | } 302 | 303 | static GetKnownKind(kind: string) { 304 | return this.kinds[kind] 305 | } 306 | 307 | static RegisterKnownKind(kind: string, props: Props) { 308 | this.kinds[kind] = props 309 | } 310 | } 311 | 312 | type Parser = { deserializeBinary(bytes: number[]): object } 313 | export class Serialization { 314 | private static typeLookup: { [index: string]: any } = {} 315 | 316 | static RegisterTypes(packageName: string, types: any) { 317 | let keys = Object.keys(types) 318 | for (let i = 0; i < keys.length; i++) { 319 | let key = keys[i] 320 | let type = types[key] 321 | let typeName = packageName + '.' + type.name 322 | this.typeLookup[typeName] = type 323 | } 324 | } 325 | 326 | static Deserialize(typeName: string, bytes: Uint8Array) { 327 | let parser = this.typeLookup[typeName] 328 | let reader = protobuf.Reader.create(bytes) 329 | let o = parser.decode(reader) 330 | return o 331 | } 332 | 333 | static LookupTypeName(type: any) : string { 334 | let i = Object.values(this.typeLookup).indexOf(type.constructor) 335 | let typeName = Object.keys(this.typeLookup)[i] 336 | return typeName 337 | } 338 | 339 | static Serialize(message: any) : Uint8Array { 340 | let encoder = message.constructor.encode 341 | let writer = encoder(message) 342 | let buffer = writer.finish() 343 | return buffer 344 | } 345 | } 346 | 347 | Serialization.RegisterTypes('remote', remoteProto.remote) 348 | 349 | // test 350 | //remote.Start('localhost', 12000) -------------------------------------------------------------------------------- /src/remote/remote_pb.d.ts: -------------------------------------------------------------------------------- 1 | import * as $protobuf from "protobufjs"; 2 | 3 | /** 4 | * Namespace remote. 5 | * @exports remote 6 | * @namespace 7 | */ 8 | export namespace remote { 9 | 10 | type MessageBatch$Properties = { 11 | typeNames?: string[]; 12 | targetNames?: string[]; 13 | envelopes?: remote.MessageEnvelope$Properties[]; 14 | }; 15 | 16 | /** 17 | * Constructs a new MessageBatch. 18 | * @exports remote.MessageBatch 19 | * @constructor 20 | * @param {remote.MessageBatch$Properties=} [properties] Properties to set 21 | */ 22 | class MessageBatch { 23 | 24 | /** 25 | * Constructs a new MessageBatch. 26 | * @exports remote.MessageBatch 27 | * @constructor 28 | * @param {remote.MessageBatch$Properties=} [properties] Properties to set 29 | */ 30 | constructor(properties?: remote.MessageBatch$Properties); 31 | 32 | /** 33 | * MessageBatch typeNames. 34 | * @type {Array.} 35 | */ 36 | public typeNames: string[]; 37 | 38 | /** 39 | * MessageBatch targetNames. 40 | * @type {Array.} 41 | */ 42 | public targetNames: string[]; 43 | 44 | /** 45 | * MessageBatch envelopes. 46 | * @type {Array.} 47 | */ 48 | public envelopes: remote.MessageEnvelope$Properties[]; 49 | 50 | /** 51 | * Creates a new MessageBatch instance using the specified properties. 52 | * @param {remote.MessageBatch$Properties=} [properties] Properties to set 53 | * @returns {remote.MessageBatch} MessageBatch instance 54 | */ 55 | public static create(properties?: remote.MessageBatch$Properties): remote.MessageBatch; 56 | 57 | /** 58 | * Encodes the specified MessageBatch message. Does not implicitly {@link remote.MessageBatch.verify|verify} messages. 59 | * @param {remote.MessageBatch$Properties} message MessageBatch message or plain object to encode 60 | * @param {$protobuf.Writer} [writer] Writer to encode to 61 | * @returns {$protobuf.Writer} Writer 62 | */ 63 | public static encode(message: remote.MessageBatch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 64 | 65 | /** 66 | * Encodes the specified MessageBatch message, length delimited. Does not implicitly {@link remote.MessageBatch.verify|verify} messages. 67 | * @param {remote.MessageBatch$Properties} message MessageBatch message or plain object to encode 68 | * @param {$protobuf.Writer} [writer] Writer to encode to 69 | * @returns {$protobuf.Writer} Writer 70 | */ 71 | public static encodeDelimited(message: remote.MessageBatch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 72 | 73 | /** 74 | * Decodes a MessageBatch message from the specified reader or buffer. 75 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 76 | * @param {number} [length] Message length if known beforehand 77 | * @returns {remote.MessageBatch} MessageBatch 78 | * @throws {Error} If the payload is not a reader or valid buffer 79 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 80 | */ 81 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): remote.MessageBatch; 82 | 83 | /** 84 | * Decodes a MessageBatch message from the specified reader or buffer, length delimited. 85 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 86 | * @returns {remote.MessageBatch} MessageBatch 87 | * @throws {Error} If the payload is not a reader or valid buffer 88 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 89 | */ 90 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): remote.MessageBatch; 91 | 92 | /** 93 | * Verifies a MessageBatch message. 94 | * @param {Object.} message Plain object to verify 95 | * @returns {?string} `null` if valid, otherwise the reason why it is not 96 | */ 97 | public static verify(message: { [k: string]: any }): string; 98 | 99 | /** 100 | * Creates a MessageBatch message from a plain object. Also converts values to their respective internal types. 101 | * @param {Object.} object Plain object 102 | * @returns {remote.MessageBatch} MessageBatch 103 | */ 104 | public static fromObject(object: { [k: string]: any }): remote.MessageBatch; 105 | 106 | /** 107 | * Creates a MessageBatch message from a plain object. Also converts values to their respective internal types. 108 | * This is an alias of {@link remote.MessageBatch.fromObject}. 109 | * @function 110 | * @param {Object.} object Plain object 111 | * @returns {remote.MessageBatch} MessageBatch 112 | */ 113 | public static from(object: { [k: string]: any }): remote.MessageBatch; 114 | 115 | /** 116 | * Creates a plain object from a MessageBatch message. Also converts values to other types if specified. 117 | * @param {remote.MessageBatch} message MessageBatch 118 | * @param {$protobuf.ConversionOptions} [options] Conversion options 119 | * @returns {Object.} Plain object 120 | */ 121 | public static toObject(message: remote.MessageBatch, options?: $protobuf.ConversionOptions): { [k: string]: any }; 122 | 123 | /** 124 | * Creates a plain object from this MessageBatch message. Also converts values to other types if specified. 125 | * @param {$protobuf.ConversionOptions} [options] Conversion options 126 | * @returns {Object.} Plain object 127 | */ 128 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 129 | 130 | /** 131 | * Converts this MessageBatch to JSON. 132 | * @returns {Object.} JSON object 133 | */ 134 | public toJSON(): { [k: string]: any }; 135 | } 136 | 137 | type MessageEnvelope$Properties = { 138 | typeId?: number; 139 | messageData?: Uint8Array; 140 | target?: number; 141 | sender?: actor.PID$Properties; 142 | }; 143 | 144 | /** 145 | * Constructs a new MessageEnvelope. 146 | * @exports remote.MessageEnvelope 147 | * @constructor 148 | * @param {remote.MessageEnvelope$Properties=} [properties] Properties to set 149 | */ 150 | class MessageEnvelope { 151 | 152 | /** 153 | * Constructs a new MessageEnvelope. 154 | * @exports remote.MessageEnvelope 155 | * @constructor 156 | * @param {remote.MessageEnvelope$Properties=} [properties] Properties to set 157 | */ 158 | constructor(properties?: remote.MessageEnvelope$Properties); 159 | 160 | /** 161 | * MessageEnvelope typeId. 162 | * @type {number} 163 | */ 164 | public typeId: number; 165 | 166 | /** 167 | * MessageEnvelope messageData. 168 | * @type {Uint8Array} 169 | */ 170 | public messageData: Uint8Array; 171 | 172 | /** 173 | * MessageEnvelope target. 174 | * @type {number} 175 | */ 176 | public target: number; 177 | 178 | /** 179 | * MessageEnvelope sender. 180 | * @type {(actor.PID$Properties|null)} 181 | */ 182 | public sender: (actor.PID$Properties|null); 183 | 184 | /** 185 | * Creates a new MessageEnvelope instance using the specified properties. 186 | * @param {remote.MessageEnvelope$Properties=} [properties] Properties to set 187 | * @returns {remote.MessageEnvelope} MessageEnvelope instance 188 | */ 189 | public static create(properties?: remote.MessageEnvelope$Properties): remote.MessageEnvelope; 190 | 191 | /** 192 | * Encodes the specified MessageEnvelope message. Does not implicitly {@link remote.MessageEnvelope.verify|verify} messages. 193 | * @param {remote.MessageEnvelope$Properties} message MessageEnvelope message or plain object to encode 194 | * @param {$protobuf.Writer} [writer] Writer to encode to 195 | * @returns {$protobuf.Writer} Writer 196 | */ 197 | public static encode(message: remote.MessageEnvelope$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 198 | 199 | /** 200 | * Encodes the specified MessageEnvelope message, length delimited. Does not implicitly {@link remote.MessageEnvelope.verify|verify} messages. 201 | * @param {remote.MessageEnvelope$Properties} message MessageEnvelope message or plain object to encode 202 | * @param {$protobuf.Writer} [writer] Writer to encode to 203 | * @returns {$protobuf.Writer} Writer 204 | */ 205 | public static encodeDelimited(message: remote.MessageEnvelope$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 206 | 207 | /** 208 | * Decodes a MessageEnvelope message from the specified reader or buffer. 209 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 210 | * @param {number} [length] Message length if known beforehand 211 | * @returns {remote.MessageEnvelope} MessageEnvelope 212 | * @throws {Error} If the payload is not a reader or valid buffer 213 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 214 | */ 215 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): remote.MessageEnvelope; 216 | 217 | /** 218 | * Decodes a MessageEnvelope message from the specified reader or buffer, length delimited. 219 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 220 | * @returns {remote.MessageEnvelope} MessageEnvelope 221 | * @throws {Error} If the payload is not a reader or valid buffer 222 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 223 | */ 224 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): remote.MessageEnvelope; 225 | 226 | /** 227 | * Verifies a MessageEnvelope message. 228 | * @param {Object.} message Plain object to verify 229 | * @returns {?string} `null` if valid, otherwise the reason why it is not 230 | */ 231 | public static verify(message: { [k: string]: any }): string; 232 | 233 | /** 234 | * Creates a MessageEnvelope message from a plain object. Also converts values to their respective internal types. 235 | * @param {Object.} object Plain object 236 | * @returns {remote.MessageEnvelope} MessageEnvelope 237 | */ 238 | public static fromObject(object: { [k: string]: any }): remote.MessageEnvelope; 239 | 240 | /** 241 | * Creates a MessageEnvelope message from a plain object. Also converts values to their respective internal types. 242 | * This is an alias of {@link remote.MessageEnvelope.fromObject}. 243 | * @function 244 | * @param {Object.} object Plain object 245 | * @returns {remote.MessageEnvelope} MessageEnvelope 246 | */ 247 | public static from(object: { [k: string]: any }): remote.MessageEnvelope; 248 | 249 | /** 250 | * Creates a plain object from a MessageEnvelope message. Also converts values to other types if specified. 251 | * @param {remote.MessageEnvelope} message MessageEnvelope 252 | * @param {$protobuf.ConversionOptions} [options] Conversion options 253 | * @returns {Object.} Plain object 254 | */ 255 | public static toObject(message: remote.MessageEnvelope, options?: $protobuf.ConversionOptions): { [k: string]: any }; 256 | 257 | /** 258 | * Creates a plain object from this MessageEnvelope message. Also converts values to other types if specified. 259 | * @param {$protobuf.ConversionOptions} [options] Conversion options 260 | * @returns {Object.} Plain object 261 | */ 262 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 263 | 264 | /** 265 | * Converts this MessageEnvelope to JSON. 266 | * @returns {Object.} JSON object 267 | */ 268 | public toJSON(): { [k: string]: any }; 269 | } 270 | 271 | type ActorPidRequest$Properties = { 272 | name?: string; 273 | kind?: string; 274 | }; 275 | 276 | /** 277 | * Constructs a new ActorPidRequest. 278 | * @exports remote.ActorPidRequest 279 | * @constructor 280 | * @param {remote.ActorPidRequest$Properties=} [properties] Properties to set 281 | */ 282 | class ActorPidRequest { 283 | 284 | /** 285 | * Constructs a new ActorPidRequest. 286 | * @exports remote.ActorPidRequest 287 | * @constructor 288 | * @param {remote.ActorPidRequest$Properties=} [properties] Properties to set 289 | */ 290 | constructor(properties?: remote.ActorPidRequest$Properties); 291 | 292 | /** 293 | * ActorPidRequest name. 294 | * @type {string} 295 | */ 296 | public name: string; 297 | 298 | /** 299 | * ActorPidRequest kind. 300 | * @type {string} 301 | */ 302 | public kind: string; 303 | 304 | /** 305 | * Creates a new ActorPidRequest instance using the specified properties. 306 | * @param {remote.ActorPidRequest$Properties=} [properties] Properties to set 307 | * @returns {remote.ActorPidRequest} ActorPidRequest instance 308 | */ 309 | public static create(properties?: remote.ActorPidRequest$Properties): remote.ActorPidRequest; 310 | 311 | /** 312 | * Encodes the specified ActorPidRequest message. Does not implicitly {@link remote.ActorPidRequest.verify|verify} messages. 313 | * @param {remote.ActorPidRequest$Properties} message ActorPidRequest message or plain object to encode 314 | * @param {$protobuf.Writer} [writer] Writer to encode to 315 | * @returns {$protobuf.Writer} Writer 316 | */ 317 | public static encode(message: remote.ActorPidRequest$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 318 | 319 | /** 320 | * Encodes the specified ActorPidRequest message, length delimited. Does not implicitly {@link remote.ActorPidRequest.verify|verify} messages. 321 | * @param {remote.ActorPidRequest$Properties} message ActorPidRequest message or plain object to encode 322 | * @param {$protobuf.Writer} [writer] Writer to encode to 323 | * @returns {$protobuf.Writer} Writer 324 | */ 325 | public static encodeDelimited(message: remote.ActorPidRequest$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 326 | 327 | /** 328 | * Decodes an ActorPidRequest message from the specified reader or buffer. 329 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 330 | * @param {number} [length] Message length if known beforehand 331 | * @returns {remote.ActorPidRequest} ActorPidRequest 332 | * @throws {Error} If the payload is not a reader or valid buffer 333 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 334 | */ 335 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): remote.ActorPidRequest; 336 | 337 | /** 338 | * Decodes an ActorPidRequest message from the specified reader or buffer, length delimited. 339 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 340 | * @returns {remote.ActorPidRequest} ActorPidRequest 341 | * @throws {Error} If the payload is not a reader or valid buffer 342 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 343 | */ 344 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): remote.ActorPidRequest; 345 | 346 | /** 347 | * Verifies an ActorPidRequest message. 348 | * @param {Object.} message Plain object to verify 349 | * @returns {?string} `null` if valid, otherwise the reason why it is not 350 | */ 351 | public static verify(message: { [k: string]: any }): string; 352 | 353 | /** 354 | * Creates an ActorPidRequest message from a plain object. Also converts values to their respective internal types. 355 | * @param {Object.} object Plain object 356 | * @returns {remote.ActorPidRequest} ActorPidRequest 357 | */ 358 | public static fromObject(object: { [k: string]: any }): remote.ActorPidRequest; 359 | 360 | /** 361 | * Creates an ActorPidRequest message from a plain object. Also converts values to their respective internal types. 362 | * This is an alias of {@link remote.ActorPidRequest.fromObject}. 363 | * @function 364 | * @param {Object.} object Plain object 365 | * @returns {remote.ActorPidRequest} ActorPidRequest 366 | */ 367 | public static from(object: { [k: string]: any }): remote.ActorPidRequest; 368 | 369 | /** 370 | * Creates a plain object from an ActorPidRequest message. Also converts values to other types if specified. 371 | * @param {remote.ActorPidRequest} message ActorPidRequest 372 | * @param {$protobuf.ConversionOptions} [options] Conversion options 373 | * @returns {Object.} Plain object 374 | */ 375 | public static toObject(message: remote.ActorPidRequest, options?: $protobuf.ConversionOptions): { [k: string]: any }; 376 | 377 | /** 378 | * Creates a plain object from this ActorPidRequest message. Also converts values to other types if specified. 379 | * @param {$protobuf.ConversionOptions} [options] Conversion options 380 | * @returns {Object.} Plain object 381 | */ 382 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 383 | 384 | /** 385 | * Converts this ActorPidRequest to JSON. 386 | * @returns {Object.} JSON object 387 | */ 388 | public toJSON(): { [k: string]: any }; 389 | } 390 | 391 | type ActorPidResponse$Properties = { 392 | pid?: actor.PID$Properties; 393 | }; 394 | 395 | /** 396 | * Constructs a new ActorPidResponse. 397 | * @exports remote.ActorPidResponse 398 | * @constructor 399 | * @param {remote.ActorPidResponse$Properties=} [properties] Properties to set 400 | */ 401 | class ActorPidResponse { 402 | 403 | /** 404 | * Constructs a new ActorPidResponse. 405 | * @exports remote.ActorPidResponse 406 | * @constructor 407 | * @param {remote.ActorPidResponse$Properties=} [properties] Properties to set 408 | */ 409 | constructor(properties?: remote.ActorPidResponse$Properties); 410 | 411 | /** 412 | * ActorPidResponse pid. 413 | * @type {(actor.PID$Properties|null)} 414 | */ 415 | public pid: (actor.PID$Properties|null); 416 | 417 | /** 418 | * Creates a new ActorPidResponse instance using the specified properties. 419 | * @param {remote.ActorPidResponse$Properties=} [properties] Properties to set 420 | * @returns {remote.ActorPidResponse} ActorPidResponse instance 421 | */ 422 | public static create(properties?: remote.ActorPidResponse$Properties): remote.ActorPidResponse; 423 | 424 | /** 425 | * Encodes the specified ActorPidResponse message. Does not implicitly {@link remote.ActorPidResponse.verify|verify} messages. 426 | * @param {remote.ActorPidResponse$Properties} message ActorPidResponse message or plain object to encode 427 | * @param {$protobuf.Writer} [writer] Writer to encode to 428 | * @returns {$protobuf.Writer} Writer 429 | */ 430 | public static encode(message: remote.ActorPidResponse$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 431 | 432 | /** 433 | * Encodes the specified ActorPidResponse message, length delimited. Does not implicitly {@link remote.ActorPidResponse.verify|verify} messages. 434 | * @param {remote.ActorPidResponse$Properties} message ActorPidResponse message or plain object to encode 435 | * @param {$protobuf.Writer} [writer] Writer to encode to 436 | * @returns {$protobuf.Writer} Writer 437 | */ 438 | public static encodeDelimited(message: remote.ActorPidResponse$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 439 | 440 | /** 441 | * Decodes an ActorPidResponse message from the specified reader or buffer. 442 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 443 | * @param {number} [length] Message length if known beforehand 444 | * @returns {remote.ActorPidResponse} ActorPidResponse 445 | * @throws {Error} If the payload is not a reader or valid buffer 446 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 447 | */ 448 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): remote.ActorPidResponse; 449 | 450 | /** 451 | * Decodes an ActorPidResponse message from the specified reader or buffer, length delimited. 452 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 453 | * @returns {remote.ActorPidResponse} ActorPidResponse 454 | * @throws {Error} If the payload is not a reader or valid buffer 455 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 456 | */ 457 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): remote.ActorPidResponse; 458 | 459 | /** 460 | * Verifies an ActorPidResponse message. 461 | * @param {Object.} message Plain object to verify 462 | * @returns {?string} `null` if valid, otherwise the reason why it is not 463 | */ 464 | public static verify(message: { [k: string]: any }): string; 465 | 466 | /** 467 | * Creates an ActorPidResponse message from a plain object. Also converts values to their respective internal types. 468 | * @param {Object.} object Plain object 469 | * @returns {remote.ActorPidResponse} ActorPidResponse 470 | */ 471 | public static fromObject(object: { [k: string]: any }): remote.ActorPidResponse; 472 | 473 | /** 474 | * Creates an ActorPidResponse message from a plain object. Also converts values to their respective internal types. 475 | * This is an alias of {@link remote.ActorPidResponse.fromObject}. 476 | * @function 477 | * @param {Object.} object Plain object 478 | * @returns {remote.ActorPidResponse} ActorPidResponse 479 | */ 480 | public static from(object: { [k: string]: any }): remote.ActorPidResponse; 481 | 482 | /** 483 | * Creates a plain object from an ActorPidResponse message. Also converts values to other types if specified. 484 | * @param {remote.ActorPidResponse} message ActorPidResponse 485 | * @param {$protobuf.ConversionOptions} [options] Conversion options 486 | * @returns {Object.} Plain object 487 | */ 488 | public static toObject(message: remote.ActorPidResponse, options?: $protobuf.ConversionOptions): { [k: string]: any }; 489 | 490 | /** 491 | * Creates a plain object from this ActorPidResponse message. Also converts values to other types if specified. 492 | * @param {$protobuf.ConversionOptions} [options] Conversion options 493 | * @returns {Object.} Plain object 494 | */ 495 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 496 | 497 | /** 498 | * Converts this ActorPidResponse to JSON. 499 | * @returns {Object.} JSON object 500 | */ 501 | public toJSON(): { [k: string]: any }; 502 | } 503 | 504 | type Unit$Properties = {}; 505 | 506 | /** 507 | * Constructs a new Unit. 508 | * @exports remote.Unit 509 | * @constructor 510 | * @param {remote.Unit$Properties=} [properties] Properties to set 511 | */ 512 | class Unit { 513 | 514 | /** 515 | * Constructs a new Unit. 516 | * @exports remote.Unit 517 | * @constructor 518 | * @param {remote.Unit$Properties=} [properties] Properties to set 519 | */ 520 | constructor(properties?: remote.Unit$Properties); 521 | 522 | /** 523 | * Creates a new Unit instance using the specified properties. 524 | * @param {remote.Unit$Properties=} [properties] Properties to set 525 | * @returns {remote.Unit} Unit instance 526 | */ 527 | public static create(properties?: remote.Unit$Properties): remote.Unit; 528 | 529 | /** 530 | * Encodes the specified Unit message. Does not implicitly {@link remote.Unit.verify|verify} messages. 531 | * @param {remote.Unit$Properties} message Unit message or plain object to encode 532 | * @param {$protobuf.Writer} [writer] Writer to encode to 533 | * @returns {$protobuf.Writer} Writer 534 | */ 535 | public static encode(message: remote.Unit$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 536 | 537 | /** 538 | * Encodes the specified Unit message, length delimited. Does not implicitly {@link remote.Unit.verify|verify} messages. 539 | * @param {remote.Unit$Properties} message Unit message or plain object to encode 540 | * @param {$protobuf.Writer} [writer] Writer to encode to 541 | * @returns {$protobuf.Writer} Writer 542 | */ 543 | public static encodeDelimited(message: remote.Unit$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 544 | 545 | /** 546 | * Decodes an Unit message from the specified reader or buffer. 547 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 548 | * @param {number} [length] Message length if known beforehand 549 | * @returns {remote.Unit} Unit 550 | * @throws {Error} If the payload is not a reader or valid buffer 551 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 552 | */ 553 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): remote.Unit; 554 | 555 | /** 556 | * Decodes an Unit message from the specified reader or buffer, length delimited. 557 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 558 | * @returns {remote.Unit} Unit 559 | * @throws {Error} If the payload is not a reader or valid buffer 560 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 561 | */ 562 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): remote.Unit; 563 | 564 | /** 565 | * Verifies an Unit message. 566 | * @param {Object.} message Plain object to verify 567 | * @returns {?string} `null` if valid, otherwise the reason why it is not 568 | */ 569 | public static verify(message: { [k: string]: any }): string; 570 | 571 | /** 572 | * Creates an Unit message from a plain object. Also converts values to their respective internal types. 573 | * @param {Object.} object Plain object 574 | * @returns {remote.Unit} Unit 575 | */ 576 | public static fromObject(object: { [k: string]: any }): remote.Unit; 577 | 578 | /** 579 | * Creates an Unit message from a plain object. Also converts values to their respective internal types. 580 | * This is an alias of {@link remote.Unit.fromObject}. 581 | * @function 582 | * @param {Object.} object Plain object 583 | * @returns {remote.Unit} Unit 584 | */ 585 | public static from(object: { [k: string]: any }): remote.Unit; 586 | 587 | /** 588 | * Creates a plain object from an Unit message. Also converts values to other types if specified. 589 | * @param {remote.Unit} message Unit 590 | * @param {$protobuf.ConversionOptions} [options] Conversion options 591 | * @returns {Object.} Plain object 592 | */ 593 | public static toObject(message: remote.Unit, options?: $protobuf.ConversionOptions): { [k: string]: any }; 594 | 595 | /** 596 | * Creates a plain object from this Unit message. Also converts values to other types if specified. 597 | * @param {$protobuf.ConversionOptions} [options] Conversion options 598 | * @returns {Object.} Plain object 599 | */ 600 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 601 | 602 | /** 603 | * Converts this Unit to JSON. 604 | * @returns {Object.} JSON object 605 | */ 606 | public toJSON(): { [k: string]: any }; 607 | } 608 | 609 | /** 610 | * Constructs a new Remoting service. 611 | * @exports remote.Remoting 612 | * @extends $protobuf.rpc.Service 613 | * @constructor 614 | * @param {$protobuf.RPCImpl} rpcImpl RPC implementation 615 | * @param {boolean} [requestDelimited=false] Whether requests are length-delimited 616 | * @param {boolean} [responseDelimited=false] Whether responses are length-delimited 617 | */ 618 | class Remoting extends $protobuf.rpc.Service { 619 | 620 | /** 621 | * Constructs a new Remoting service. 622 | * @exports remote.Remoting 623 | * @extends $protobuf.rpc.Service 624 | * @constructor 625 | * @param {$protobuf.RPCImpl} rpcImpl RPC implementation 626 | * @param {boolean} [requestDelimited=false] Whether requests are length-delimited 627 | * @param {boolean} [responseDelimited=false] Whether responses are length-delimited 628 | */ 629 | constructor(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean); 630 | 631 | /** 632 | * Creates new Remoting service using the specified rpc implementation. 633 | * @param {$protobuf.RPCImpl} rpcImpl RPC implementation 634 | * @param {boolean} [requestDelimited=false] Whether requests are length-delimited 635 | * @param {boolean} [responseDelimited=false] Whether responses are length-delimited 636 | * @returns {Remoting} RPC service. Useful where requests and/or responses are streamed. 637 | */ 638 | public static create(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): Remoting; 639 | 640 | /** 641 | * Calls Receive. 642 | * @param {remote.MessageBatch|Object.} request MessageBatch message or plain object 643 | * @param {Remoting_receive_Callback} callback Node-style callback called with the error, if any, and Unit 644 | * @returns {undefined} 645 | */ 646 | public receive(request: (remote.MessageBatch|{ [k: string]: any }), callback: Remoting_receive_Callback): void; 647 | } 648 | } 649 | 650 | type Remoting_receive_Callback = (error: Error, response?: remote.Unit) => void; 651 | 652 | /** 653 | * Namespace actor. 654 | * @exports actor 655 | * @namespace 656 | */ 657 | export namespace actor { 658 | 659 | type PID$Properties = { 660 | Address?: string; 661 | Id?: string; 662 | }; 663 | 664 | /** 665 | * Constructs a new PID. 666 | * @exports actor.PID 667 | * @constructor 668 | * @param {actor.PID$Properties=} [properties] Properties to set 669 | */ 670 | class PID { 671 | 672 | /** 673 | * Constructs a new PID. 674 | * @exports actor.PID 675 | * @constructor 676 | * @param {actor.PID$Properties=} [properties] Properties to set 677 | */ 678 | constructor(properties?: actor.PID$Properties); 679 | 680 | /** 681 | * PID Address. 682 | * @type {string} 683 | */ 684 | public Address: string; 685 | 686 | /** 687 | * PID Id. 688 | * @type {string} 689 | */ 690 | public Id: string; 691 | 692 | /** 693 | * Creates a new PID instance using the specified properties. 694 | * @param {actor.PID$Properties=} [properties] Properties to set 695 | * @returns {actor.PID} PID instance 696 | */ 697 | public static create(properties?: actor.PID$Properties): actor.PID; 698 | 699 | /** 700 | * Encodes the specified PID message. Does not implicitly {@link actor.PID.verify|verify} messages. 701 | * @param {actor.PID$Properties} message PID message or plain object to encode 702 | * @param {$protobuf.Writer} [writer] Writer to encode to 703 | * @returns {$protobuf.Writer} Writer 704 | */ 705 | public static encode(message: actor.PID$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 706 | 707 | /** 708 | * Encodes the specified PID message, length delimited. Does not implicitly {@link actor.PID.verify|verify} messages. 709 | * @param {actor.PID$Properties} message PID message or plain object to encode 710 | * @param {$protobuf.Writer} [writer] Writer to encode to 711 | * @returns {$protobuf.Writer} Writer 712 | */ 713 | public static encodeDelimited(message: actor.PID$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 714 | 715 | /** 716 | * Decodes a PID message from the specified reader or buffer. 717 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 718 | * @param {number} [length] Message length if known beforehand 719 | * @returns {actor.PID} PID 720 | * @throws {Error} If the payload is not a reader or valid buffer 721 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 722 | */ 723 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.PID; 724 | 725 | /** 726 | * Decodes a PID message from the specified reader or buffer, length delimited. 727 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 728 | * @returns {actor.PID} PID 729 | * @throws {Error} If the payload is not a reader or valid buffer 730 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 731 | */ 732 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.PID; 733 | 734 | /** 735 | * Verifies a PID message. 736 | * @param {Object.} message Plain object to verify 737 | * @returns {?string} `null` if valid, otherwise the reason why it is not 738 | */ 739 | public static verify(message: { [k: string]: any }): string; 740 | 741 | /** 742 | * Creates a PID message from a plain object. Also converts values to their respective internal types. 743 | * @param {Object.} object Plain object 744 | * @returns {actor.PID} PID 745 | */ 746 | public static fromObject(object: { [k: string]: any }): actor.PID; 747 | 748 | /** 749 | * Creates a PID message from a plain object. Also converts values to their respective internal types. 750 | * This is an alias of {@link actor.PID.fromObject}. 751 | * @function 752 | * @param {Object.} object Plain object 753 | * @returns {actor.PID} PID 754 | */ 755 | public static from(object: { [k: string]: any }): actor.PID; 756 | 757 | /** 758 | * Creates a plain object from a PID message. Also converts values to other types if specified. 759 | * @param {actor.PID} message PID 760 | * @param {$protobuf.ConversionOptions} [options] Conversion options 761 | * @returns {Object.} Plain object 762 | */ 763 | public static toObject(message: actor.PID, options?: $protobuf.ConversionOptions): { [k: string]: any }; 764 | 765 | /** 766 | * Creates a plain object from this PID message. Also converts values to other types if specified. 767 | * @param {$protobuf.ConversionOptions} [options] Conversion options 768 | * @returns {Object.} Plain object 769 | */ 770 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 771 | 772 | /** 773 | * Converts this PID to JSON. 774 | * @returns {Object.} JSON object 775 | */ 776 | public toJSON(): { [k: string]: any }; 777 | } 778 | 779 | type PoisonPill$Properties = {}; 780 | 781 | /** 782 | * Constructs a new PoisonPill. 783 | * @exports actor.PoisonPill 784 | * @constructor 785 | * @param {actor.PoisonPill$Properties=} [properties] Properties to set 786 | */ 787 | class PoisonPill { 788 | 789 | /** 790 | * Constructs a new PoisonPill. 791 | * @exports actor.PoisonPill 792 | * @constructor 793 | * @param {actor.PoisonPill$Properties=} [properties] Properties to set 794 | */ 795 | constructor(properties?: actor.PoisonPill$Properties); 796 | 797 | /** 798 | * Creates a new PoisonPill instance using the specified properties. 799 | * @param {actor.PoisonPill$Properties=} [properties] Properties to set 800 | * @returns {actor.PoisonPill} PoisonPill instance 801 | */ 802 | public static create(properties?: actor.PoisonPill$Properties): actor.PoisonPill; 803 | 804 | /** 805 | * Encodes the specified PoisonPill message. Does not implicitly {@link actor.PoisonPill.verify|verify} messages. 806 | * @param {actor.PoisonPill$Properties} message PoisonPill message or plain object to encode 807 | * @param {$protobuf.Writer} [writer] Writer to encode to 808 | * @returns {$protobuf.Writer} Writer 809 | */ 810 | public static encode(message: actor.PoisonPill$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 811 | 812 | /** 813 | * Encodes the specified PoisonPill message, length delimited. Does not implicitly {@link actor.PoisonPill.verify|verify} messages. 814 | * @param {actor.PoisonPill$Properties} message PoisonPill message or plain object to encode 815 | * @param {$protobuf.Writer} [writer] Writer to encode to 816 | * @returns {$protobuf.Writer} Writer 817 | */ 818 | public static encodeDelimited(message: actor.PoisonPill$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 819 | 820 | /** 821 | * Decodes a PoisonPill message from the specified reader or buffer. 822 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 823 | * @param {number} [length] Message length if known beforehand 824 | * @returns {actor.PoisonPill} PoisonPill 825 | * @throws {Error} If the payload is not a reader or valid buffer 826 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 827 | */ 828 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.PoisonPill; 829 | 830 | /** 831 | * Decodes a PoisonPill message from the specified reader or buffer, length delimited. 832 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 833 | * @returns {actor.PoisonPill} PoisonPill 834 | * @throws {Error} If the payload is not a reader or valid buffer 835 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 836 | */ 837 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.PoisonPill; 838 | 839 | /** 840 | * Verifies a PoisonPill message. 841 | * @param {Object.} message Plain object to verify 842 | * @returns {?string} `null` if valid, otherwise the reason why it is not 843 | */ 844 | public static verify(message: { [k: string]: any }): string; 845 | 846 | /** 847 | * Creates a PoisonPill message from a plain object. Also converts values to their respective internal types. 848 | * @param {Object.} object Plain object 849 | * @returns {actor.PoisonPill} PoisonPill 850 | */ 851 | public static fromObject(object: { [k: string]: any }): actor.PoisonPill; 852 | 853 | /** 854 | * Creates a PoisonPill message from a plain object. Also converts values to their respective internal types. 855 | * This is an alias of {@link actor.PoisonPill.fromObject}. 856 | * @function 857 | * @param {Object.} object Plain object 858 | * @returns {actor.PoisonPill} PoisonPill 859 | */ 860 | public static from(object: { [k: string]: any }): actor.PoisonPill; 861 | 862 | /** 863 | * Creates a plain object from a PoisonPill message. Also converts values to other types if specified. 864 | * @param {actor.PoisonPill} message PoisonPill 865 | * @param {$protobuf.ConversionOptions} [options] Conversion options 866 | * @returns {Object.} Plain object 867 | */ 868 | public static toObject(message: actor.PoisonPill, options?: $protobuf.ConversionOptions): { [k: string]: any }; 869 | 870 | /** 871 | * Creates a plain object from this PoisonPill message. Also converts values to other types if specified. 872 | * @param {$protobuf.ConversionOptions} [options] Conversion options 873 | * @returns {Object.} Plain object 874 | */ 875 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 876 | 877 | /** 878 | * Converts this PoisonPill to JSON. 879 | * @returns {Object.} JSON object 880 | */ 881 | public toJSON(): { [k: string]: any }; 882 | } 883 | 884 | type Watch$Properties = { 885 | watcher?: actor.PID$Properties; 886 | }; 887 | 888 | /** 889 | * Constructs a new Watch. 890 | * @exports actor.Watch 891 | * @constructor 892 | * @param {actor.Watch$Properties=} [properties] Properties to set 893 | */ 894 | class Watch { 895 | 896 | /** 897 | * Constructs a new Watch. 898 | * @exports actor.Watch 899 | * @constructor 900 | * @param {actor.Watch$Properties=} [properties] Properties to set 901 | */ 902 | constructor(properties?: actor.Watch$Properties); 903 | 904 | /** 905 | * Watch watcher. 906 | * @type {(actor.PID$Properties|null)} 907 | */ 908 | public watcher: (actor.PID$Properties|null); 909 | 910 | /** 911 | * Creates a new Watch instance using the specified properties. 912 | * @param {actor.Watch$Properties=} [properties] Properties to set 913 | * @returns {actor.Watch} Watch instance 914 | */ 915 | public static create(properties?: actor.Watch$Properties): actor.Watch; 916 | 917 | /** 918 | * Encodes the specified Watch message. Does not implicitly {@link actor.Watch.verify|verify} messages. 919 | * @param {actor.Watch$Properties} message Watch message or plain object to encode 920 | * @param {$protobuf.Writer} [writer] Writer to encode to 921 | * @returns {$protobuf.Writer} Writer 922 | */ 923 | public static encode(message: actor.Watch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 924 | 925 | /** 926 | * Encodes the specified Watch message, length delimited. Does not implicitly {@link actor.Watch.verify|verify} messages. 927 | * @param {actor.Watch$Properties} message Watch message or plain object to encode 928 | * @param {$protobuf.Writer} [writer] Writer to encode to 929 | * @returns {$protobuf.Writer} Writer 930 | */ 931 | public static encodeDelimited(message: actor.Watch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 932 | 933 | /** 934 | * Decodes a Watch message from the specified reader or buffer. 935 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 936 | * @param {number} [length] Message length if known beforehand 937 | * @returns {actor.Watch} Watch 938 | * @throws {Error} If the payload is not a reader or valid buffer 939 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 940 | */ 941 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Watch; 942 | 943 | /** 944 | * Decodes a Watch message from the specified reader or buffer, length delimited. 945 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 946 | * @returns {actor.Watch} Watch 947 | * @throws {Error} If the payload is not a reader or valid buffer 948 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 949 | */ 950 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Watch; 951 | 952 | /** 953 | * Verifies a Watch message. 954 | * @param {Object.} message Plain object to verify 955 | * @returns {?string} `null` if valid, otherwise the reason why it is not 956 | */ 957 | public static verify(message: { [k: string]: any }): string; 958 | 959 | /** 960 | * Creates a Watch message from a plain object. Also converts values to their respective internal types. 961 | * @param {Object.} object Plain object 962 | * @returns {actor.Watch} Watch 963 | */ 964 | public static fromObject(object: { [k: string]: any }): actor.Watch; 965 | 966 | /** 967 | * Creates a Watch message from a plain object. Also converts values to their respective internal types. 968 | * This is an alias of {@link actor.Watch.fromObject}. 969 | * @function 970 | * @param {Object.} object Plain object 971 | * @returns {actor.Watch} Watch 972 | */ 973 | public static from(object: { [k: string]: any }): actor.Watch; 974 | 975 | /** 976 | * Creates a plain object from a Watch message. Also converts values to other types if specified. 977 | * @param {actor.Watch} message Watch 978 | * @param {$protobuf.ConversionOptions} [options] Conversion options 979 | * @returns {Object.} Plain object 980 | */ 981 | public static toObject(message: actor.Watch, options?: $protobuf.ConversionOptions): { [k: string]: any }; 982 | 983 | /** 984 | * Creates a plain object from this Watch message. Also converts values to other types if specified. 985 | * @param {$protobuf.ConversionOptions} [options] Conversion options 986 | * @returns {Object.} Plain object 987 | */ 988 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 989 | 990 | /** 991 | * Converts this Watch to JSON. 992 | * @returns {Object.} JSON object 993 | */ 994 | public toJSON(): { [k: string]: any }; 995 | } 996 | 997 | type Unwatch$Properties = { 998 | watcher?: actor.PID$Properties; 999 | }; 1000 | 1001 | /** 1002 | * Constructs a new Unwatch. 1003 | * @exports actor.Unwatch 1004 | * @constructor 1005 | * @param {actor.Unwatch$Properties=} [properties] Properties to set 1006 | */ 1007 | class Unwatch { 1008 | 1009 | /** 1010 | * Constructs a new Unwatch. 1011 | * @exports actor.Unwatch 1012 | * @constructor 1013 | * @param {actor.Unwatch$Properties=} [properties] Properties to set 1014 | */ 1015 | constructor(properties?: actor.Unwatch$Properties); 1016 | 1017 | /** 1018 | * Unwatch watcher. 1019 | * @type {(actor.PID$Properties|null)} 1020 | */ 1021 | public watcher: (actor.PID$Properties|null); 1022 | 1023 | /** 1024 | * Creates a new Unwatch instance using the specified properties. 1025 | * @param {actor.Unwatch$Properties=} [properties] Properties to set 1026 | * @returns {actor.Unwatch} Unwatch instance 1027 | */ 1028 | public static create(properties?: actor.Unwatch$Properties): actor.Unwatch; 1029 | 1030 | /** 1031 | * Encodes the specified Unwatch message. Does not implicitly {@link actor.Unwatch.verify|verify} messages. 1032 | * @param {actor.Unwatch$Properties} message Unwatch message or plain object to encode 1033 | * @param {$protobuf.Writer} [writer] Writer to encode to 1034 | * @returns {$protobuf.Writer} Writer 1035 | */ 1036 | public static encode(message: actor.Unwatch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 1037 | 1038 | /** 1039 | * Encodes the specified Unwatch message, length delimited. Does not implicitly {@link actor.Unwatch.verify|verify} messages. 1040 | * @param {actor.Unwatch$Properties} message Unwatch message or plain object to encode 1041 | * @param {$protobuf.Writer} [writer] Writer to encode to 1042 | * @returns {$protobuf.Writer} Writer 1043 | */ 1044 | public static encodeDelimited(message: actor.Unwatch$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 1045 | 1046 | /** 1047 | * Decodes an Unwatch message from the specified reader or buffer. 1048 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 1049 | * @param {number} [length] Message length if known beforehand 1050 | * @returns {actor.Unwatch} Unwatch 1051 | * @throws {Error} If the payload is not a reader or valid buffer 1052 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 1053 | */ 1054 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Unwatch; 1055 | 1056 | /** 1057 | * Decodes an Unwatch message from the specified reader or buffer, length delimited. 1058 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 1059 | * @returns {actor.Unwatch} Unwatch 1060 | * @throws {Error} If the payload is not a reader or valid buffer 1061 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 1062 | */ 1063 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Unwatch; 1064 | 1065 | /** 1066 | * Verifies an Unwatch message. 1067 | * @param {Object.} message Plain object to verify 1068 | * @returns {?string} `null` if valid, otherwise the reason why it is not 1069 | */ 1070 | public static verify(message: { [k: string]: any }): string; 1071 | 1072 | /** 1073 | * Creates an Unwatch message from a plain object. Also converts values to their respective internal types. 1074 | * @param {Object.} object Plain object 1075 | * @returns {actor.Unwatch} Unwatch 1076 | */ 1077 | public static fromObject(object: { [k: string]: any }): actor.Unwatch; 1078 | 1079 | /** 1080 | * Creates an Unwatch message from a plain object. Also converts values to their respective internal types. 1081 | * This is an alias of {@link actor.Unwatch.fromObject}. 1082 | * @function 1083 | * @param {Object.} object Plain object 1084 | * @returns {actor.Unwatch} Unwatch 1085 | */ 1086 | public static from(object: { [k: string]: any }): actor.Unwatch; 1087 | 1088 | /** 1089 | * Creates a plain object from an Unwatch message. Also converts values to other types if specified. 1090 | * @param {actor.Unwatch} message Unwatch 1091 | * @param {$protobuf.ConversionOptions} [options] Conversion options 1092 | * @returns {Object.} Plain object 1093 | */ 1094 | public static toObject(message: actor.Unwatch, options?: $protobuf.ConversionOptions): { [k: string]: any }; 1095 | 1096 | /** 1097 | * Creates a plain object from this Unwatch message. Also converts values to other types if specified. 1098 | * @param {$protobuf.ConversionOptions} [options] Conversion options 1099 | * @returns {Object.} Plain object 1100 | */ 1101 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 1102 | 1103 | /** 1104 | * Converts this Unwatch to JSON. 1105 | * @returns {Object.} JSON object 1106 | */ 1107 | public toJSON(): { [k: string]: any }; 1108 | } 1109 | 1110 | type Terminated$Properties = { 1111 | who?: actor.PID$Properties; 1112 | AddressTerminated?: boolean; 1113 | }; 1114 | 1115 | /** 1116 | * Constructs a new Terminated. 1117 | * @exports actor.Terminated 1118 | * @constructor 1119 | * @param {actor.Terminated$Properties=} [properties] Properties to set 1120 | */ 1121 | class Terminated { 1122 | 1123 | /** 1124 | * Constructs a new Terminated. 1125 | * @exports actor.Terminated 1126 | * @constructor 1127 | * @param {actor.Terminated$Properties=} [properties] Properties to set 1128 | */ 1129 | constructor(properties?: actor.Terminated$Properties); 1130 | 1131 | /** 1132 | * Terminated who. 1133 | * @type {(actor.PID$Properties|null)} 1134 | */ 1135 | public who: (actor.PID$Properties|null); 1136 | 1137 | /** 1138 | * Terminated AddressTerminated. 1139 | * @type {boolean} 1140 | */ 1141 | public AddressTerminated: boolean; 1142 | 1143 | /** 1144 | * Creates a new Terminated instance using the specified properties. 1145 | * @param {actor.Terminated$Properties=} [properties] Properties to set 1146 | * @returns {actor.Terminated} Terminated instance 1147 | */ 1148 | public static create(properties?: actor.Terminated$Properties): actor.Terminated; 1149 | 1150 | /** 1151 | * Encodes the specified Terminated message. Does not implicitly {@link actor.Terminated.verify|verify} messages. 1152 | * @param {actor.Terminated$Properties} message Terminated message or plain object to encode 1153 | * @param {$protobuf.Writer} [writer] Writer to encode to 1154 | * @returns {$protobuf.Writer} Writer 1155 | */ 1156 | public static encode(message: actor.Terminated$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 1157 | 1158 | /** 1159 | * Encodes the specified Terminated message, length delimited. Does not implicitly {@link actor.Terminated.verify|verify} messages. 1160 | * @param {actor.Terminated$Properties} message Terminated message or plain object to encode 1161 | * @param {$protobuf.Writer} [writer] Writer to encode to 1162 | * @returns {$protobuf.Writer} Writer 1163 | */ 1164 | public static encodeDelimited(message: actor.Terminated$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 1165 | 1166 | /** 1167 | * Decodes a Terminated message from the specified reader or buffer. 1168 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 1169 | * @param {number} [length] Message length if known beforehand 1170 | * @returns {actor.Terminated} Terminated 1171 | * @throws {Error} If the payload is not a reader or valid buffer 1172 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 1173 | */ 1174 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Terminated; 1175 | 1176 | /** 1177 | * Decodes a Terminated message from the specified reader or buffer, length delimited. 1178 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 1179 | * @returns {actor.Terminated} Terminated 1180 | * @throws {Error} If the payload is not a reader or valid buffer 1181 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 1182 | */ 1183 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Terminated; 1184 | 1185 | /** 1186 | * Verifies a Terminated message. 1187 | * @param {Object.} message Plain object to verify 1188 | * @returns {?string} `null` if valid, otherwise the reason why it is not 1189 | */ 1190 | public static verify(message: { [k: string]: any }): string; 1191 | 1192 | /** 1193 | * Creates a Terminated message from a plain object. Also converts values to their respective internal types. 1194 | * @param {Object.} object Plain object 1195 | * @returns {actor.Terminated} Terminated 1196 | */ 1197 | public static fromObject(object: { [k: string]: any }): actor.Terminated; 1198 | 1199 | /** 1200 | * Creates a Terminated message from a plain object. Also converts values to their respective internal types. 1201 | * This is an alias of {@link actor.Terminated.fromObject}. 1202 | * @function 1203 | * @param {Object.} object Plain object 1204 | * @returns {actor.Terminated} Terminated 1205 | */ 1206 | public static from(object: { [k: string]: any }): actor.Terminated; 1207 | 1208 | /** 1209 | * Creates a plain object from a Terminated message. Also converts values to other types if specified. 1210 | * @param {actor.Terminated} message Terminated 1211 | * @param {$protobuf.ConversionOptions} [options] Conversion options 1212 | * @returns {Object.} Plain object 1213 | */ 1214 | public static toObject(message: actor.Terminated, options?: $protobuf.ConversionOptions): { [k: string]: any }; 1215 | 1216 | /** 1217 | * Creates a plain object from this Terminated message. Also converts values to other types if specified. 1218 | * @param {$protobuf.ConversionOptions} [options] Conversion options 1219 | * @returns {Object.} Plain object 1220 | */ 1221 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 1222 | 1223 | /** 1224 | * Converts this Terminated to JSON. 1225 | * @returns {Object.} JSON object 1226 | */ 1227 | public toJSON(): { [k: string]: any }; 1228 | } 1229 | 1230 | type Stop$Properties = {}; 1231 | 1232 | /** 1233 | * Constructs a new Stop. 1234 | * @exports actor.Stop 1235 | * @constructor 1236 | * @param {actor.Stop$Properties=} [properties] Properties to set 1237 | */ 1238 | class Stop { 1239 | 1240 | /** 1241 | * Constructs a new Stop. 1242 | * @exports actor.Stop 1243 | * @constructor 1244 | * @param {actor.Stop$Properties=} [properties] Properties to set 1245 | */ 1246 | constructor(properties?: actor.Stop$Properties); 1247 | 1248 | /** 1249 | * Creates a new Stop instance using the specified properties. 1250 | * @param {actor.Stop$Properties=} [properties] Properties to set 1251 | * @returns {actor.Stop} Stop instance 1252 | */ 1253 | public static create(properties?: actor.Stop$Properties): actor.Stop; 1254 | 1255 | /** 1256 | * Encodes the specified Stop message. Does not implicitly {@link actor.Stop.verify|verify} messages. 1257 | * @param {actor.Stop$Properties} message Stop message or plain object to encode 1258 | * @param {$protobuf.Writer} [writer] Writer to encode to 1259 | * @returns {$protobuf.Writer} Writer 1260 | */ 1261 | public static encode(message: actor.Stop$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 1262 | 1263 | /** 1264 | * Encodes the specified Stop message, length delimited. Does not implicitly {@link actor.Stop.verify|verify} messages. 1265 | * @param {actor.Stop$Properties} message Stop message or plain object to encode 1266 | * @param {$protobuf.Writer} [writer] Writer to encode to 1267 | * @returns {$protobuf.Writer} Writer 1268 | */ 1269 | public static encodeDelimited(message: actor.Stop$Properties, writer?: $protobuf.Writer): $protobuf.Writer; 1270 | 1271 | /** 1272 | * Decodes a Stop message from the specified reader or buffer. 1273 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 1274 | * @param {number} [length] Message length if known beforehand 1275 | * @returns {actor.Stop} Stop 1276 | * @throws {Error} If the payload is not a reader or valid buffer 1277 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 1278 | */ 1279 | public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): actor.Stop; 1280 | 1281 | /** 1282 | * Decodes a Stop message from the specified reader or buffer, length delimited. 1283 | * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from 1284 | * @returns {actor.Stop} Stop 1285 | * @throws {Error} If the payload is not a reader or valid buffer 1286 | * @throws {$protobuf.util.ProtocolError} If required fields are missing 1287 | */ 1288 | public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): actor.Stop; 1289 | 1290 | /** 1291 | * Verifies a Stop message. 1292 | * @param {Object.} message Plain object to verify 1293 | * @returns {?string} `null` if valid, otherwise the reason why it is not 1294 | */ 1295 | public static verify(message: { [k: string]: any }): string; 1296 | 1297 | /** 1298 | * Creates a Stop message from a plain object. Also converts values to their respective internal types. 1299 | * @param {Object.} object Plain object 1300 | * @returns {actor.Stop} Stop 1301 | */ 1302 | public static fromObject(object: { [k: string]: any }): actor.Stop; 1303 | 1304 | /** 1305 | * Creates a Stop message from a plain object. Also converts values to their respective internal types. 1306 | * This is an alias of {@link actor.Stop.fromObject}. 1307 | * @function 1308 | * @param {Object.} object Plain object 1309 | * @returns {actor.Stop} Stop 1310 | */ 1311 | public static from(object: { [k: string]: any }): actor.Stop; 1312 | 1313 | /** 1314 | * Creates a plain object from a Stop message. Also converts values to other types if specified. 1315 | * @param {actor.Stop} message Stop 1316 | * @param {$protobuf.ConversionOptions} [options] Conversion options 1317 | * @returns {Object.} Plain object 1318 | */ 1319 | public static toObject(message: actor.Stop, options?: $protobuf.ConversionOptions): { [k: string]: any }; 1320 | 1321 | /** 1322 | * Creates a plain object from this Stop message. Also converts values to other types if specified. 1323 | * @param {$protobuf.ConversionOptions} [options] Conversion options 1324 | * @returns {Object.} Plain object 1325 | */ 1326 | public toObject(options?: $protobuf.ConversionOptions): { [k: string]: any }; 1327 | 1328 | /** 1329 | * Converts this Stop to JSON. 1330 | * @returns {Object.} JSON object 1331 | */ 1332 | public toJSON(): { [k: string]: any }; 1333 | } 1334 | } 1335 | -------------------------------------------------------------------------------- /src/restartStatistics.ts: -------------------------------------------------------------------------------- 1 | export interface IRestartStatistics{ 2 | Fail(): void; 3 | IsWithinDuration(withinMs: number): void; 4 | Reset(): void; 5 | FailureCount: number; 6 | } 7 | 8 | export class RestartStatistics implements IRestartStatistics { 9 | public FailureCount = 0; 10 | private LastFailureTime: Date; 11 | Fail() { 12 | this.FailureCount++ 13 | } 14 | 15 | Reset() { 16 | this.FailureCount = 0 17 | } 18 | 19 | Restart() { 20 | this.LastFailureTime = new Date() 21 | } 22 | 23 | IsWithinDuration(withinMs: number) { 24 | if (this.LastFailureTime==undefined) 25 | return true 26 | return (new Date().getTime() - this.LastFailureTime.getTime()) < withinMs; 27 | } 28 | } -------------------------------------------------------------------------------- /src/supervision.ts: -------------------------------------------------------------------------------- 1 | import { RestartStatistics } from "./restartStatistics"; 2 | import { PID } from "./pid"; 3 | 4 | export enum SupervisorDirective { 5 | Resume = 0, 6 | Restart = 1, 7 | Stop = 2, 8 | Escalate = 3 9 | } 10 | export interface IStrategy { 11 | HandleFailure(supervisor: ISupervisor, child: PID, restartStatistics: RestartStatistics, reason: any): void; 12 | } 13 | export class OneForOneStrategy implements IStrategy { 14 | constructor(private decider: IDecider, private maxRetries: number, private withinMs = 0) { 15 | 16 | } 17 | 18 | HandleFailure(supervisor: ISupervisor, child: PID, restartStatistics: RestartStatistics, reason: any) { 19 | let directive = this.decider(reason, child) 20 | switch (directive) { 21 | case SupervisorDirective.Resume: 22 | supervisor.ResumeChildren(child); 23 | break; 24 | case SupervisorDirective.Restart: 25 | if (this.requestRestartPermission(restartStatistics)) { 26 | global.console.log('Restarting', child.ToShortString(), 'Reason', reason) 27 | supervisor.RestartChildren(child) 28 | } else { 29 | global.console.log('Stopping', child.ToShortString(), 'Reason', reason) 30 | supervisor.StopChildren(child) 31 | } 32 | break 33 | case SupervisorDirective.Stop: 34 | global.console.log('Stopping', child.ToShortString(), 'Reason', reason) 35 | supervisor.StopChildren(child) 36 | break 37 | case SupervisorDirective.Escalate: 38 | supervisor.EscalateFailure(reason, child) 39 | break 40 | } 41 | } 42 | 43 | private requestRestartPermission(restartStatistics: RestartStatistics) { 44 | if (this.maxRetries == 0) { 45 | return false 46 | } 47 | restartStatistics.Fail() 48 | if (this.withinMs == 0 || restartStatistics.IsWithinDuration(this.withinMs)) { 49 | return restartStatistics.FailureCount <= this.maxRetries 50 | } 51 | restartStatistics.Reset() 52 | return true 53 | } 54 | } 55 | 56 | const defaultDecider: IDecider = () => SupervisorDirective.Restart 57 | 58 | export const DefaultStrategy = new OneForOneStrategy(defaultDecider, 10, 10 * 1000) 59 | 60 | export interface IDecider { 61 | (reason: any, who: PID): SupervisorDirective 62 | } 63 | 64 | export interface ISupervisor { 65 | ResumeChildren(child: PID): void; 66 | RestartChildren(child: PID): void; 67 | StopChildren(child: PID): void; 68 | EscalateFailure(error: any, child?: PID): void; 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /test/actorMessagingTests.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../src/actor" 2 | import {PID} from "../src/pid" 3 | import processRegistry from "../src/processRegistry" 4 | import * as messages from "../src/messages" 5 | 6 | import {assert, expect, use as chaiUse} from "chai" 7 | import * as chaiAsPromised from "chai-as-promised" 8 | 9 | import {Awaiter} from "./util/awaiter" 10 | 11 | chaiUse(chaiAsPromised) 12 | 13 | describe('actor messaging', () => { 14 | 15 | it('should receive Started message when started', async () => { 16 | let received : any[] = [] 17 | let aw = new Awaiter() 18 | 19 | actor.spawn( 20 | actor.fromFunc(async context => { 21 | var msg = context.Message 22 | if (msg instanceof messages.Started) { 23 | received.push(msg) 24 | aw.resolve() 25 | } 26 | }) 27 | ) 28 | 29 | await aw.promise 30 | assert.equal(received[0], messages.Started.Instance) 31 | }) 32 | 33 | it('should receive Stopping and Stopped message when stopped', async () => { 34 | let received : any[] = [] 35 | let aw = new Awaiter() 36 | let pid = actor.spawn( 37 | actor.fromFunc(async context => { 38 | var msg = context.Message 39 | if (msg instanceof messages.Stopping || msg instanceof messages.Stopped) { 40 | received.push(msg) 41 | } 42 | if (msg instanceof messages.Stopped) { 43 | aw.resolve() 44 | } 45 | }) 46 | ); 47 | 48 | pid.Stop() 49 | 50 | await aw.promise 51 | assert.equal(received[0], messages.Stopping.Instance) 52 | assert.equal(received[1], messages.Stopped.Instance) 53 | }) 54 | 55 | it('should receive message when using Tell', async () => { 56 | let received : any[] = [] 57 | let aw = new Awaiter() 58 | let pid = actor.spawn( 59 | actor.fromFunc(async context => { 60 | var msg = context.Message 61 | if (typeof(msg) === 'string') { 62 | received.push(msg) 63 | aw.resolve() 64 | } 65 | }) 66 | ); 67 | 68 | pid.Tell('hello') 69 | 70 | await aw.promise 71 | assert.equal(received[0], 'hello') 72 | }) 73 | 74 | it('should respond with message when using RequestPromise', async () => { 75 | let pid = actor.spawn( 76 | actor.fromFunc(async context => { 77 | var msg = context.Message 78 | if (typeof(msg) === 'string') { 79 | context.Respond('hey') 80 | } 81 | }) 82 | ); 83 | 84 | let res = await pid.RequestPromise('hello') 85 | 86 | assert.equal(res, 'hey') 87 | }) 88 | 89 | it('should raise timeout if no response is sent when using RequestPromise', async () => { 90 | let pid = actor.spawn( 91 | actor.fromFunc(async context => { }) 92 | ); 93 | 94 | let p = pid.RequestPromise('hello', 10) 95 | 96 | await assert.isRejected(p) 97 | }) 98 | 99 | it('should be added to ProcessRegistry when spawned', async () => { 100 | let pid = actor.spawn( 101 | actor.fromFunc(async context => {}) 102 | ); 103 | 104 | let reff = processRegistry.Get(pid) 105 | assert.isDefined(reff) 106 | assert.isNotNull(reff) 107 | }) 108 | 109 | it('should be removed from ProcessRegistry when stopped', async () => { 110 | let pid = actor.spawn( 111 | actor.fromFunc(async context => {}) 112 | ); 113 | 114 | pid.Stop() 115 | 116 | let reff = processRegistry.Get(pid) 117 | assert.isUndefined(reff) 118 | }) 119 | 120 | 121 | }) -------------------------------------------------------------------------------- /test/actorSpawningTests.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../src/actor" 2 | import {IContext} from "../src/localContext" 3 | import {PID} from "../src/pid" 4 | import processRegistry from "../src/processRegistry" 5 | import * as messages from "../src/messages" 6 | 7 | import {assert, expect, use as chaiUse} from "chai" 8 | import * as chaiAsPromised from "chai-as-promised" 9 | 10 | import {Awaiter} from "./util/awaiter" 11 | 12 | chaiUse(chaiAsPromised) 13 | 14 | describe('actor spawning', () => { 15 | 16 | it('should spawn actor from function', () => { 17 | let pid = actor.spawn( 18 | actor.fromFunc(async context => {}) 19 | ) 20 | 21 | assert.isDefined(pid) 22 | assert.isNotNull(pid) 23 | }) 24 | 25 | it('should spawn actor from producer', () => { 26 | let producer = () => { 27 | return { 28 | receive: async (context: IContext) => { 29 | } 30 | } 31 | } 32 | 33 | let pid = actor.spawn( 34 | actor.fromFunc(async context => {}) 35 | ) 36 | 37 | assert.isDefined(pid) 38 | assert.isNotNull(pid) 39 | }) 40 | 41 | it('should spawn actor with prefix', () => { 42 | let pid = actor.spawnPrefix( 43 | actor.fromFunc(async context => {}), 44 | 'test' 45 | ) 46 | 47 | assert.isDefined(pid) 48 | assert.isNotNull(pid) 49 | assert.isTrue(pid.Id.startsWith('test'), 'PID Id should start with test') 50 | }) 51 | 52 | it('should spawn actor with name', () => { 53 | let pid = actor.spawnNamed( 54 | actor.fromFunc(async context => {}), 55 | 'test' 56 | ) 57 | 58 | assert.isDefined(pid) 59 | assert.isNotNull(pid) 60 | assert.equal(pid.Id, 'test') 61 | }) 62 | }) -------------------------------------------------------------------------------- /test/mailboxBenchmarkTests.ts: -------------------------------------------------------------------------------- 1 | import { createActionTimer } from "./util/timeAction"; 2 | import { Message } from "../src/messages"; 3 | import * as mailbox from "../src/mailbox"; 4 | import { IMessageInvoker } from "../src/invoker"; 5 | import { Dispatcher } from "../src/dispatcher"; 6 | import { Queue } from "../src/queue" 7 | import { Queue2 } from "../src/queue2" 8 | 9 | import * as assert from "assert"; 10 | import "mocha"; 11 | 12 | import { Awaiter } from "./util/awaiter" 13 | 14 | class Invoker implements IMessageInvoker { 15 | 16 | constructor(public awaiter: Awaiter) { } 17 | 18 | EscalateFailure(error: any): void { 19 | console.warn("Method not implemented." + error); 20 | } 21 | c = 0; 22 | hrstart: [number, number] 23 | 24 | async InvokeSystemMessage(msg: Message) { 25 | await Promise.resolve(msg) 26 | } 27 | 28 | async InvokeUserMessage(msg: Message) { 29 | this.increment() 30 | await Promise.resolve(msg) 31 | } 32 | increment() { 33 | if (this.c == 0) { 34 | this.hrstart = process.hrtime() 35 | } 36 | this.c++ 37 | if (this.c == 100 * 1000) { 38 | var hr = process.hrtime(this.hrstart) 39 | var s = hr[0] + hr[1] / (1000 * 1000 * 1000) 40 | var t = this.c / s 41 | this.awaiter.resolve(t) 42 | console.log('received', t / 1000, 'K msg/s') 43 | } 44 | } 45 | } 46 | 47 | 48 | 49 | describe('mailbox with Queue', () => { 50 | 51 | it('should post at least 100,000 messages/s', async () => { 52 | let mb = new mailbox.Mailbox(new Queue(), new Queue()) 53 | let aw = new Awaiter() 54 | mb.RegisterHandlers(new Invoker(aw), new Dispatcher()); 55 | var mbActionTimer = createActionTimer(mb, 500 * 1000); 56 | assert(mbActionTimer(mb => mb.PostUserMessage("hello")) > 100) 57 | await aw.promise 58 | }).timeout(5000) 59 | 60 | }); 61 | 62 | describe('mailbox with Queue2', () => { 63 | 64 | it('should post at least 100,000 messages/s', async () => { 65 | let mb = new mailbox.Mailbox(new Queue2(), new Queue2()) 66 | let aw = new Awaiter() 67 | mb.RegisterHandlers(new Invoker(aw), new Dispatcher()); 68 | var mbActionTimer = createActionTimer(mb, 500 * 1000); 69 | assert(mbActionTimer(mb => mb.PostUserMessage("hello")) > 100) 70 | await aw.promise 71 | }).timeout(5000) 72 | 73 | }); -------------------------------------------------------------------------------- /test/mailboxTests.ts: -------------------------------------------------------------------------------- 1 | import * as mailbox from "../src/mailbox" 2 | import * as messages from "../src/messages" 3 | import {Dispatcher} from "../src/dispatcher" 4 | import {IMessageInvoker} from "../src/invoker" 5 | import {PID} from "../src/pid" 6 | 7 | import {assert, expect, use as chaiUse} from "chai" 8 | import * as chaiAsPromised from "chai-as-promised" 9 | import {Awaiter} from "./util/awaiter" 10 | 11 | class Failure { 12 | constructor(public error: any, public child?: PID) { } 13 | } 14 | class MessageWithAwaiter { 15 | constructor(public awaiter: Awaiter) { } 16 | } 17 | class MessageWithError { 18 | constructor(public error: ErrorWithAwaiter) { } 19 | } 20 | class ErrorWithAwaiter { 21 | constructor(public awaiter: Awaiter) { } 22 | } 23 | class StubInvoker implements IMessageInvoker { 24 | systemMessages: any[] = [] 25 | userMessages: any[] = [] 26 | allMessages: any[] = [] 27 | failures: Failure[] = [] 28 | InvokeSystemMessage(message: any): Promise { 29 | this.systemMessages.push(message) 30 | this.allMessages.push(message) 31 | if (message instanceof MessageWithAwaiter) { 32 | message.awaiter.resolve() 33 | } 34 | if (message instanceof MessageWithError) { 35 | throw message.error 36 | } 37 | return Promise.resolve() 38 | } 39 | InvokeUserMessage(message: any): Promise { 40 | this.userMessages.push(message) 41 | this.allMessages.push(message) 42 | if (message instanceof MessageWithAwaiter) { 43 | message.awaiter.resolve() 44 | } 45 | if (message instanceof MessageWithError) { 46 | throw message.error 47 | } 48 | return Promise.resolve() 49 | } 50 | EscalateFailure(error: any, child?: PID): void { 51 | this.failures.push(new Failure(error, child)) 52 | if (error instanceof ErrorWithAwaiter) { 53 | error.awaiter.resolve() 54 | } 55 | } 56 | } 57 | 58 | describe('mailbox processing', () => { 59 | 60 | it('should invoke system message', async () => { 61 | let mb = mailbox.Unbounded() 62 | let invoker = new StubInvoker() 63 | let dispatcher = new Dispatcher() 64 | mb.RegisterHandlers(invoker, dispatcher) 65 | let aw = new Awaiter() 66 | let msg = new MessageWithAwaiter(aw) 67 | 68 | mb.PostSystemMessage(msg) 69 | 70 | await aw.promise 71 | 72 | assert.strictEqual(invoker.systemMessages[0], msg) 73 | }) 74 | 75 | it('should invoke user message', async () => { 76 | let mb = mailbox.Unbounded() 77 | let invoker = new StubInvoker() 78 | let dispatcher = new Dispatcher() 79 | mb.RegisterHandlers(invoker, dispatcher) 80 | let aw = new Awaiter() 81 | let msg = new MessageWithAwaiter(aw) 82 | 83 | mb.PostUserMessage(msg) 84 | 85 | await aw.promise 86 | 87 | assert.strictEqual(invoker.userMessages[0], msg) 88 | }) 89 | 90 | it('should invoke system messages before user messages', async () => { 91 | let mb = mailbox.Unbounded() 92 | let invoker = new StubInvoker() 93 | let dispatcher = new Dispatcher() 94 | mb.RegisterHandlers(invoker, dispatcher) 95 | let aw = new Awaiter() 96 | let sysMsg1 = {} 97 | let usrMsg1 = {} 98 | let sysMsg2 = {} 99 | let usrMsg2 = new MessageWithAwaiter(aw) 100 | 101 | mb.PostSystemMessage(sysMsg1) 102 | mb.PostUserMessage(usrMsg1) 103 | mb.PostUserMessage(usrMsg2) 104 | mb.PostSystemMessage(sysMsg2) 105 | 106 | await aw.promise 107 | 108 | assert.strictEqual(invoker.allMessages[0], sysMsg1, 'Expected message 1 to be system message 1') 109 | assert.strictEqual(invoker.allMessages[1], sysMsg2, 'Expected message 2 to be system message 2') 110 | assert.strictEqual(invoker.allMessages[2], usrMsg1, 'Expected message 3 to be user message 1') 111 | assert.strictEqual(invoker.allMessages[3], usrMsg2, 'Expected message 4 to be user message 2') 112 | }) 113 | 114 | it('should not process user messages after suspended', async () => { 115 | let mb = mailbox.Unbounded() 116 | let invoker = new StubInvoker() 117 | let dispatcher = new Dispatcher() 118 | mb.RegisterHandlers(invoker, dispatcher) 119 | let aw = new Awaiter() 120 | let msg = new MessageWithAwaiter(aw) 121 | 122 | mb.PostSystemMessage(messages.SuspendMailbox.Instance) 123 | mb.PostUserMessage(msg) 124 | 125 | let isResolved = await aw.isResolvedWithin(10) 126 | assert.isFalse(isResolved) 127 | }) 128 | 129 | it('should process user messages after resumed', async () => { 130 | let mb = mailbox.Unbounded() 131 | let invoker = new StubInvoker() 132 | let dispatcher = new Dispatcher() 133 | mb.RegisterHandlers(invoker, dispatcher) 134 | let aw = new Awaiter() 135 | let msg = new MessageWithAwaiter(aw) 136 | 137 | mb.PostSystemMessage(messages.SuspendMailbox.Instance) 138 | mb.PostUserMessage(msg) 139 | mb.PostSystemMessage(messages.ResumeMailbox.Instance) 140 | 141 | let isResolved = await aw.isResolvedWithin(10) 142 | assert.isTrue(isResolved) 143 | }) 144 | 145 | it('should escalate failure on failing system message', async () => { 146 | let mb = mailbox.Unbounded() 147 | let invoker = new StubInvoker() 148 | let dispatcher = new Dispatcher() 149 | mb.RegisterHandlers(invoker, dispatcher) 150 | let aw = new Awaiter() 151 | let err = new ErrorWithAwaiter(aw) 152 | let msg = new MessageWithError(err) 153 | 154 | mb.PostSystemMessage(msg) 155 | 156 | let isResolved = await aw.isResolvedWithin(10) 157 | assert.isTrue(isResolved) 158 | 159 | assert.equal(invoker.failures[0].error, err) 160 | }) 161 | }) -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | dist/test/**/*Tests.js -------------------------------------------------------------------------------- /test/queueTests.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import { createActionTimer } from "./util/timeAction"; 3 | import { IQueue, Queue } from "../src/queue"; 4 | import { Queue2 } from "../src/queue2"; 5 | 6 | type QueueConstructor = (fn: (_: IQueue) => void) => number; 7 | var queueTests = (ctor: () => QueueConstructor) => () => { 8 | var queueAction: QueueConstructor; 9 | beforeEach(() => queueAction = ctor()) 10 | 11 | describe('enqueue', () => { 12 | it('should have 2000 K msg/s', () => assert(queueAction(q => q.enqueue("hello")) > 2000)); 13 | }); 14 | 15 | describe('dequeue', () => { 16 | beforeEach(() => queueAction(q => q.enqueue("hello"))); 17 | 18 | it('should have 3000 K msg/s', () => assert(queueAction(q => q.dequeue()) > 3000)) 19 | }) 20 | } 21 | describe('queue', queueTests(() => createActionTimer(new Queue(), 1000 * 1000))); 22 | describe('queue2', queueTests(() => createActionTimer(new Queue2(), 1000 * 1000))); -------------------------------------------------------------------------------- /test/supervisionOneForOneTests.ts: -------------------------------------------------------------------------------- 1 | import * as actor from "../src/actor" 2 | import {IContext} from "../src/localContext" 3 | import {Props} from "../src/props" 4 | import {PID} from "../src/pid" 5 | import processRegistry from "../src/processRegistry" 6 | import * as messages from "../src/messages" 7 | import * as supervision from "../src/supervision" 8 | import * as mailbox from "../src/mailbox" 9 | 10 | import {assert, expect, use as chaiUse} from "chai" 11 | import * as chaiAsPromised from "chai-as-promised" 12 | 13 | import {Awaiter} from "./util/awaiter" 14 | import {Sleep} from "./util/sleep" 15 | 16 | chaiUse(chaiAsPromised) 17 | 18 | class ParentActor implements actor.IActor { 19 | private child: PID 20 | constructor(private childProps: Props) {} 21 | Receive(context: IContext): Promise { 22 | let msg = context.Message 23 | if (msg instanceof messages.Started) 24 | this.child = context.Spawn(this.childProps) 25 | if (typeof(msg) == 'string') 26 | this.child.Tell(msg) 27 | return actor.done 28 | } 29 | } 30 | 31 | class ChildActor implements actor.IActor { 32 | constructor(private awaiter: Awaiter) {} 33 | Receive(context: IContext): Promise { 34 | switch (context.Message) { 35 | case 'die': 36 | throw 'BOOM' 37 | case 'hello again': 38 | this.awaiter.resolve() 39 | } 40 | return actor.done 41 | } 42 | } 43 | 44 | class TestMailboxStatistics implements mailbox.IStatistics { 45 | public Posted: any[] = [] 46 | public Received: any[] = [] 47 | UserMessagePosted(message: messages.Message) { 48 | this.Posted.push(message) 49 | } 50 | SystemMessagePosted(message: messages.Message) { 51 | this.Posted.push(message) 52 | } 53 | UserMessageReceived(message: messages.Message) { 54 | this.Received.push(message) 55 | } 56 | SystemMessageReceived(message: messages.Message) { 57 | this.Received.push(message) 58 | } 59 | MailboxStarted() {} 60 | MailboxEmpty() {} 61 | } 62 | 63 | describe('one-for-one supervision', () => { 64 | 65 | it('should resume child on failure', async () => { 66 | let childMailboxStats = new TestMailboxStatistics() 67 | let aw = new Awaiter() 68 | let strategy = new supervision.OneForOneStrategy((reason: any, who: PID) => { return supervision.SupervisorDirective.Resume }, 1) 69 | let childProps = actor.fromProducer(() => new ChildActor(aw)) 70 | .WithMailbox(() => mailbox.Unbounded(childMailboxStats)) 71 | let parentProps = actor.fromProducer(() => new ParentActor(childProps)) 72 | .WithSupervisor(strategy) 73 | let parent = actor.spawn(parentProps) 74 | 75 | parent.Tell('die') 76 | parent.Tell('hello again') 77 | 78 | await aw.promise 79 | 80 | assert.equal(childMailboxStats.Posted[0], messages.Started.Instance) 81 | assert.equal(childMailboxStats.Posted[1], 'die') 82 | assert.equal(childMailboxStats.Posted[2], messages.SuspendMailbox.Instance) 83 | assert.equal(childMailboxStats.Posted[3], messages.ResumeMailbox.Instance) 84 | assert.equal(childMailboxStats.Posted[4], 'hello again') 85 | }) 86 | }) -------------------------------------------------------------------------------- /test/util/awaiter.ts: -------------------------------------------------------------------------------- 1 | import {Sleep} from "./sleep" 2 | 3 | export class Awaiter { 4 | public promise: Promise 5 | public resolve: (v?:T) => void 6 | private isResolved: boolean = false 7 | constructor() { 8 | this.promise = new Promise(resolve => { 9 | this.resolve = (v) => { 10 | resolve(v) 11 | this.isResolved = true 12 | } 13 | }) 14 | } 15 | public async isResolvedWithin(timeoutMs: number) { 16 | let t = 0 17 | await Sleep(timeoutMs) 18 | return this.isResolved 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/util/sleep.ts: -------------------------------------------------------------------------------- 1 | export function Sleep(timeout: number) { 2 | return new Promise(resolve => { 3 | setTimeout(resolve, timeout); 4 | }); 5 | } -------------------------------------------------------------------------------- /test/util/timeAction.ts: -------------------------------------------------------------------------------- 1 | export function createActionTimer(actionableObject: T, count: number) { 2 | return (action: (o: T) => void) => { 3 | var hrstart = process.hrtime(); 4 | for(var i=0;i