{"id":17345018,"url":"https://github.com/jgranstrom/gonode","last_synced_at":"2025-09-10T12:42:26.946Z","repository":{"id":7652416,"uuid":"9013267","full_name":"jgranstrom/gonode","owner":"jgranstrom","description":"gonode introduces a way to combine the asynchronous nature of node with the simplicity of concurrency in Go.","archived":false,"fork":false,"pushed_at":"2018-03-08T17:01:32.000Z","size":562,"stargazers_count":79,"open_issues_count":1,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-08-24T13:33:17.221Z","etag":null,"topics":["go","integration","node"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jgranstrom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-03-25T18:45:19.000Z","updated_at":"2025-08-19T02:45:00.000Z","dependencies_parsed_at":"2022-09-03T23:20:52.733Z","dependency_job_id":null,"html_url":"https://github.com/jgranstrom/gonode","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jgranstrom/gonode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgranstrom%2Fgonode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgranstrom%2Fgonode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgranstrom%2Fgonode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgranstrom%2Fgonode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jgranstrom","download_url":"https://codeload.github.com/jgranstrom/gonode/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jgranstrom%2Fgonode/sbom","scorecard":{"id":518275,"data":{"date":"2025-08-11","repo":{"name":"github.com/jgranstrom/gonode","commit":"b46857eca2b3346121bac71e228a1cd0d2ab8f7e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 2/25 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 7 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T02:19:55.385Z","repository_id":7652416,"created_at":"2025-08-20T02:19:55.385Z","updated_at":"2025-08-20T02:19:55.385Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274463687,"owners_count":25290115,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","integration","node"],"created_at":"2024-10-15T16:28:37.684Z","updated_at":"2025-09-10T12:42:26.906Z","avatar_url":"https://github.com/jgranstrom.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"gonode - Go for node.js\n===\n\n\u003cimg src=\"http://i49.tinypic.com/345zgbd.png\"\u003e\n\n## What is gonode?\n\n**gonode** acts as a bridge between Go and node.js. It introduces a way to combine the asynchronous nature of node with the simplicity of concurrency in Go. gonode will in a non-blocking fashion run Go code directly from within your node modules, and asynchronously return results from Go. You can code anything you wish as long as the required communication between Go and node.js can be represented with JSON.\n\n## Install\n\nFirst make sure that you have installed [Go][] and set up your [GOPATH][] as [gonodepkg][] and [go-simplejson][] will be automatically installed to the first path specified in your GOPATH.\n\nThen install gonode by running:\n\n```bash\nnpm install gonode\n```\n\n**You should now be all set up and no more commands are required.**\n\n*Note:* Even though the required Go packages are installed automatically with gonode you may find yourself in need of installing or updating them explicitly. In that case do so by running:\n\n```bash\ngo get github.com/jgranstrom/gonodepkg github.com/jgranstrom/go-simplejson\n```\n\n## Introduction\n\nTo set up communications you need to initiate the gonode module in node and also start the gonodepkg in Go.\n\nBasic requirements in node.js:\n\n```js\nvar Go = require('gonode').Go;\nvar go = new Go({\n\tpath\t: 'gofile.go',\n});\n\ngo.init(function(err) {\n\tif (err) throw err;\n\n\t// TODO: Add code to execute commands\n\n\tgo.close();\n});\n```\n\nBasic requirements in Go (gofile.go):\n\n```go\npackage main\n\nimport (\n\tgonode \"github.com/jgranstrom/gonodepkg\"\n\tjson \"github.com/jgranstrom/go-simplejson\"\n)\n\nfunc main() {\t\n\tgonode.Start(process)\n}\n\nfunc process(cmd *json.Json) (response *json.Json) {\n\t// TODO: Add code for processing commands from node\n\treturn cmd\n}\n```\n\n## Initializing gonode\n\nYou can initialize gonode either by explicitly calling `init()` or by settings the option `initAtOnce` to `true` and optionally provide the initialization callback directly in to Go constructor.\n\n```js\nvar Go = require('gonode').Go;\n\nvar options = {\n\tpath\t\t: 'gofile.go',\n\tinitAtOnce\t: true,\t\n}\nvar go = new Go(options, function(err) {\n\tif (err) throw err;\n\n\t// TODO: Add code to execute commands\n\n\tgo.close();\n});\n```\n\nAs you can see `close()` should be called when you no longer need the Go object and will gracefully end the Go process when all executing commands has finished.\n\n###### Initialization options\n* `path`: The path of the go-file to execute. *(Required)*\n* `initAtOnce`: Will initialize Go at once when object created if `true`, and allows initialization callback to be provided in constructor. *(Default: `false`)*\n* `maxCommandsRunning`: Specifies the maximum number of commands allowed to be running simultaneously, may impact performance differently depending on Go implementation. *(Default: `10`)*\n* `defaultCommandTimeoutSec`: Specifies the default command timeout in seconds to be used when not specified in command options. *(Default: `5`)*\n* `cwd`: The working directory of the Go process. *(Default: Current working directory of the node process)*\n\n## Executing commands\n\n**Running commands with gonode** is really simple, the following is an example presuming go is an initialized Go object:\n\n```js\ngo.execute({commandText: 'Hello world from gonode!'}, function(result, response) {\n\tif(result.ok) {\n\t\tconsole.log('Go responded: ' + response.responseText);\n\t}\n});\n```\n\n`execute()` accepts a JSON object to be sent to the Go process, and a callback which will be called when Go returns with a result or when the command reaches a timeout limit or is terminated. \n`result` represents the result of the execution of this command.\n`response` will contain a JSON object with the result of the response only if `result.ok` is set to `true`.\n\n`result` may have one and only one of the following set to `true`:\n* `ok`: The command has executed and responded as expected, response data are in `response`.\n* `timeout`: The command reached a timeout by exceeding the set execution time limit.\n* `terminated`: The command has been internally terminated prior to responding. This is set when external errors are raised, such as Go panic.\n\n`execute()` returns `true` if the command has been registered and eventually will be executed, or `false` if the command was ignored either because gonode hasn't been initialized yet, or because gonode is in the process of closing or terminating.\n\nNote that the JSON object to send can contain anything containable in JSON and in arbitrary structure, and the JSON object returned does not have to obey to any structure of the sent object as they are completely independent. The structure of the returned object depends on the Go implementation responding it.\n\n**Processing the command in Go** is possibly even simpler:\n\n```go\n\tresponse, m, error := json.MakeMap()\n\t\n\tm[\"error\"] = error\n\t\n\tif(cmd.Get(\"commandText\").MustString() == \"Hello\") {\n\t\tm[\"responseText\"] = \"Well hello there!\"\n\t} else {\n\t\tm[\"responseText\"] = \"What?\"\n\t}\n\n\treturn\n}\n```\n\nEach command sent to Go will be delegated to the provided `process()` on a new go-routine and `cmd` will be a pointer to a `Json` object which is a representation of the JSON object received from node.\nEach `process()` call must return a pointer to a `Json` object containing any data to be part of the response back to node.\n\n###### Command options\n* `commandTimeoutSec`: Setting this will override the `defaultCommandTimeoutSec` set for the Go object for a specific command. *(Default: `defaultCommandTimeoutSec` of the Go object)*\n\nCommand options can be provided in any call to `execute()` as such:\n```js\ngo.execute({text: 'Hello world from gonode!'}, function(result, response) {\n\tif(result.ok) {\n\t\tconsole.log('Go responded: ' + response.text);\n\t} else if(result.timeout) {\n\t\tconsole.log('Command timed out!');\n\t}\t\n}, {commandTimeoutSec: 60}); // This command will execute for up to one minute before timing out\n```\n\n## Interacting with JSON\n\nSince gonode supports arbitrary JSON data between Go and node.js you must be able to interact with the data communicated. The following are methods provided to get the JSON data in usable Go types and can be called on `Json` objects:\n* `Get(key string)`: Get the pointer to a `Json` object for a specific key. You can recursively `Get()` through the JSON structure to get to any required data.\n* `GetIndex(index int)`: Get the pointer to a `Json` object for a index within a JSON array.\n* `CheckGet(key string)`: Get the pointer to a `Json` object for a specific key together with a possible error.\n* `Map()`: Assert the `Json` object to `map[string]interface{}`, also returns a possible error.\n* `Array()`: Assert the `Json` object to `[]interface{}`, also returns a possible error.\n* `Bool()`: Assert the `Json` object to `bool`, also returns a possible error.\n* `String()`: Assert the `Json` object to `string`, also returns a possible error.\n* `Float64()`: Assert the `Json` object to `float64`, also returns a possible error.\n* `Int()`: Assert the `Json` object to `int`, also returns a possible error.\n* `Int64()`: Assert the `Json` object to `int64`, also returns a possible error.\n* `Bytes()`: Assert the `Json` object to `[]byte`, also returns a possible error.\n* `StringArray()`: Assert the `Json` object to `[]string`, also returns a possible error.\n* `IntArray()`: Assert the `Json` object to `[]int`, also returns a possible error.\n* `MustString(args ...string)`: Assert the `Json` object to `string`, a default value can optionally be provided as an argument to be returned if the assertion fails.\n* `MustInt(args ...int)`: Assert the `Json` object to `int`, a default value can optionally be provided as an argument to be returned if the assertion fails.\n* `MustFloat64(args ...float64)`: Assert the `Json` object to `float64`, a default value can optionally be provided as an argument to be returned if the assertion fails.\n\nTo create a `Json` object from Go types some additional methods are provided:\n* `Create(data interface{})`: Create a `Json` object with arbitrary data. This can be used to take advantage of a `struct` or for example creating a `Json` object containing a single `int` or array etc.\n* `MakeMap()`: Make a `Json` object containing a `map[string]interface{}` and return a pointer to the `Json` object and the created `map`.\n\n**Example of getting JSON data from a `Json` object:**\n\nProvided JSON data:\n```json\n{\n\t\"data\": {\n\t\t\"array\": [\"abc\", \"efg\", \"klm\"],\n\t\t\"number\": 716\n\t},\n\t\"otherdata\": \"hello\"\n}\n```\nAssuming we have a `Json` object called `json` of the above JSON we can get each data as such:\n```go\nfirstString, err := json.Get(\"data\").Get(\"array\").GetIndex(0).String() \t// \"abc\"\nentireArray, err := json.Get(\"data\").Get(\"array\").StringArray()\t\t\t// [\"abc\" \"efg\" \"klm\"]\nnumber, err := json.Get(\"data\").Get(\"number\").Int()\t\t\t\t\t\t// 716\notherdata := json.Get(\"otherdata\").MustString()\t\t\t\t\t\t\t// \"hello\"\n```\n**Example of creating a `Json` object from Go types:**\n\nThe following code:\n```go\narr := []int{1, 3, 7}\nnumberJson := simplejson.Create(arr)\n```\n\nWould simply generate the following JSON:\n```json\n[1, 3, 7]\n```\n\nWhile the code:\n```go\njson, m := simplejson.MakeMap(arr)\nm[\"array\"] = []int{1, 3, 7}\n```\n\nWould generate:\n```json\n{\n\t\"array\": [1, 3, 7]\n}\n```\n\nThis enables you to construct any complex JSON structures needed for communication between Go and node.js. However of course it is recommended to keep the actual communication and complexity of the structures as low as possible to improve performance.\n\n## Closing gonode\n\nThere are two ways of closing gonode:\n\n* `close()`: Go will be closed when all running commands has finished. No more calls to `execute()` will be allowed after this call, but callbacks for already running commands may still be called. When the callback of the last running command has been returned, Go will close gracefully. Calls to this return `true` if a close has been scheduled, or `false` if either Go is not initialized or if a close/termination is already pending. Calling `close()` more than once has no significant meaning.\n* `terminate()`: Go will be terminated immediately. No more calls to `execute()` will be allowed after this call, and callbacks for already running commands will be called immediately with `result.terminated` set to `true`. Calls to this return `true` if a termination has been scheduled, or `false` if either Go is not initialized or if a termination is already pending. Calling `terminate()` more than once has no significant meaning.\n\nExample:\n\n```js\n// Execute some long running command\ngo.execute({text: 'I will run for quite a while!'}, function(result, response) {\n\tif(result.ok) {\n\t\tconsole.log('Go responded: ' + response.text);\n\t} else if(result.timeout) {\n\t\tconsole.log('Command timed out!');\n\t} else if(result.terminated) {\n\t\tconsole.log('Command was terminated!');\n\t}\n});\n//go.terminate(); // This line would most likely cause the above command to terminate\n//go.close(); // This would cause gonode to close after the above command has finished\n```\n\n*Important:* Always close gonode when you no longer need it, otherwise you will leave Go hanging while waiting for more command to execute. It would waste precious resources and also keep your node process from exiting when you would expect it to.\n\n## Error handling\n\ngonode comes with some error handling concerning the Go process as well as JSON parsing errors. On all errors, except for initialization, gonode will emit the `error` event with information regarding the event. Such events are raised for example when a panic occurs within Go or when there are errors parsing JSON. The error object has two properties;\n* `parser`: `true` if the error is caused by internal parsing errors, otherwise `false.\n* `data`: Contains the actual error data which may be error output from Go possibly including stack trace\n\n**Handling these errors** is straightforward:\n\n```js\nvar Go = require('gonode').Go;\n\nvar go = new Go({\n\tpath\t\t: 'gofile.go',\n\tinitAtOnce\t: true,\t\n}, function(err) {\n\tif (err) throw err; // This may be a failure to locate go-file\n\n\tgo.on('error', function(err) {\n\t\tif(err.parser) {\n\t\t\t// Error is coming from internal parser\n\t\t\tconsole.log('Parser error: ' + err.data.toString())\n\t\t} else {\n\t\t\t// External error possible Go panic\n\t\t\tconsole.log('Go error: ' + err.data.toString())\n\t\t}\n\t});\n\n\t// TODO: Add code to execute commands\n\n\tgo.close();\n});\n```\n\n*Important:* An external error causing the error event to emit with `parser` set to `false` will also cause gonode to terminate. That means such errors are fatal and would require gonode to be reinitialized. Also it will cause all running commands to be immediately terminated, i.e. their callbacks will be invoked with `result.terminated` set to `true`.\n\n*Note:* a big error output like a stack trace caused by a panic may be split up into several error events containing parts of the total output.\n\n## Todo\n\n* Improved error handling\n* Additional benchmarks and examples\n\n[gonodepkg]: https://github.com/jgranstrom/gonodepkg\n[go-simplejson]: https://github.com/jgranstrom/go-simplejson\n[Go]: http://golang.org/doc/install#install\n[GOPATH]: http://golang.org/doc/code.html#tmp_2\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgranstrom%2Fgonode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjgranstrom%2Fgonode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjgranstrom%2Fgonode/lists"}