diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3143f77 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 John Farley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/app/c.js b/app/c.js new file mode 100644 index 0000000..cc2fd33 --- /dev/null +++ b/app/c.js @@ -0,0 +1,43 @@ +function captureFrontMatterAndMarkdown() { + console.log(location.pathname.split('/public')[0]) + const formData = new FormData(document.querySelector("form")) + let frontmatter = "---\n" + for (const k of formData.keys()) { + // draft, iscjklanguage are default implicit (false) params in hugo + if (["draft", "iscjklanguage"].includes(k)){ + console.log(formData.get(k)) + if (formData.get(k) === "true") { + frontmatter += `${k}: true\n` + } + } else if (k.endsWith('[]')) { + formData.set(k, formData.getAll(k)) + var s = JSON.stringify(formData.getAll(k)[0].split(",")) + frontmatter += `${k.slice(0, -2)}: ${s}\n` + } else if (k == "relpath") { + filepath = `${location.pathname.split('/public')[0]}/content/${formData.get(k)}` + gitpath = `${location.pathname.split('/public')[0]}` + } else if (["protocol", "offline"].includes(k)) { + continue + } else { + var s = JSON.stringify(formData.get(k)) + frontmatter += `${k}: ${s}\n` + } + } + frontmatter += "---\n" + const content = document.querySelector('textarea').value + let doc = frontmatter + content + let publish = formData.get("publish") == "on" ? true : false + let offline = formData.get("offline") == "on" ? true : false + return {"hugopage": doc, "filepath": filepath, "gitpath": gitpath, "publish": publish, "offline": offline, "protocol": document.location.protocol.substr(0,4)} +} + +let sb = document.getElementById('sandpointsButton') +if (sb) { + sb.addEventListener( + "click", (e)=> { + e.preventDefault() + chrome.runtime.sendMessage( + captureFrontMatterAndMarkdown() + ); + }); +} diff --git a/app/main.js b/app/main.js new file mode 100644 index 0000000..042cda1 --- /dev/null +++ b/app/main.js @@ -0,0 +1,15 @@ +chrome.runtime.onMessage.addListener((m, n)=> { + var nh = chrome.runtime.connectNative("org.sandpoints.chromeext") + nh.onDisconnect.addListener((e, err)=> { + console.log("event:", e) + console.log("error:", err) + }) + console.log("message:", m) + console.log("sender:", n) + nh.postMessage(m); + nh.onMessage.addListener((m, n)=> { + console.log("native host message:", m) + console.log("native host sender:", n) + }) +}) + diff --git a/app/manifest.json b/app/manifest.json new file mode 100644 index 0000000..9060675 --- /dev/null +++ b/app/manifest.json @@ -0,0 +1,22 @@ +{ + "name": "Sandpoints Local Messaging Host", + "version": "1.0", + "manifest_version": 3, + "description": "Chrome extension to bridge messaging in between files open via file:// to talk to system.", + "action": { + "default_icon": "icon.png" + }, + "background": { + "service_worker": "main.js" + }, + "content_scripts": [ + { + "matches": ["file://*"], + "all_frames": true, + "js": ["c.js"] + } + ], + "permissions": [ + "nativeMessaging" + ] +} diff --git a/native-host/config/org.sandpoints.chromeext.json b/native-host/config/org.sandpoints.chromeext.json new file mode 100644 index 0000000..0c0e8f6 --- /dev/null +++ b/native-host/config/org.sandpoints.chromeext.json @@ -0,0 +1,9 @@ +{ + "name": "org.sandpoints.chromeext", + "description": "Sandpoints Local Native Messaging Host", + "path": "/home/m/bin/natgost", + "type": "stdio", + "allowed_origins": [ + "chrome-extension://bknfdkcponnfbabklbadclgaimgoaipp/" + ] +} diff --git a/native-host/src/go.mod b/native-host/src/go.mod new file mode 100644 index 0000000..a75acd7 --- /dev/null +++ b/native-host/src/go.mod @@ -0,0 +1,5 @@ +module main + +go 1.15 + +require github.com/go-git/go-git/v5 v5.2.0 diff --git a/native-host/src/go.sum b/native-host/src/go.sum new file mode 100644 index 0000000..0dad167 --- /dev/null +++ b/native-host/src/go.sum @@ -0,0 +1,64 @@ +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git v1.0.0 h1:YcN9iDGDoXuIw0vHls6rINwV416HYa0EB2X+RBsyYp4= +github.com/go-git/go-git v4.7.0+incompatible h1:+W9rgGY4DOKKdX2x6HxSR7HNeTxqiKrOvKnuittYVdA= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI= +github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/native-host/src/main.go b/native-host/src/main.go new file mode 100644 index 0000000..772f5b9 --- /dev/null +++ b/native-host/src/main.go @@ -0,0 +1,265 @@ +package main + +import ( + "bufio" + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + "unsafe" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/object" +) + +// this project started by copying: +// https://github.com/jfarleyx/chrome-native-messaging-golang + +// constants for Logger +var ( + // Trace logs general information messages. + Trace *log.Logger + // Error logs error messages. + Error *log.Logger +) + +// nativeEndian used to detect native byte order +var nativeEndian binary.ByteOrder + +// bufferSize used to set size of IO buffer - adjust to accommodate message payloads +var bufferSize = 8192 + +// IncomingMessage represents a message sent to the native host. +type IncomingMessage struct { + Hugopage string `json:"hugopage"` + Filepath string `json:"filepath"` + Gitpath string `json:"gitpath"` + Publish bool `json:"publish"` + Offline bool `json:"offline"` + Protocol string `json:"protocol"` +} + +// OutgoingMessage respresents a response to an incoming message query. +type OutgoingMessage struct { + Query string `json:"query"` + Response string `json:"response"` +} + +// Init initializes logger and determines native byte order. +func Init(traceHandle io.Writer, errorHandle io.Writer) { + Trace = log.New(traceHandle, "TRACE: ", log.Ldate|log.Ltime|log.Lshortfile) + Error = log.New(errorHandle, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) + + // determine native byte order so that we can read message size correctly + var one int16 = 1 + b := (*byte)(unsafe.Pointer(&one)) + if *b == 0 { + nativeEndian = binary.BigEndian + } else { + nativeEndian = binary.LittleEndian + } +} + +func main() { + file, err := os.OpenFile(filepath.Join("/tmp", "sandpoints-chromeext-log.txt"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + Init(os.Stdout, os.Stderr) + Error.Printf("Unable to create and/or open log file. Will log to Stdout and Stderr. Error: %v", err) + } else { + Init(file, file) + // ensure we close the log file when we're done + defer file.Close() + } + + Trace.Printf("Chrome native messaging host started. Native byte order: %v.", nativeEndian) + read() + Trace.Print("Chrome native messaging host exited.") +} + +// read Creates a new buffered I/O reader and reads messages from Stdin. +func read() { + v := bufio.NewReader(os.Stdin) + // adjust buffer size to accommodate your json payload size limits; default is 4096 + s := bufio.NewReaderSize(v, bufferSize) + Trace.Printf("IO buffer reader created with buffer size of %v.", s.Size()) + + lengthBytes := make([]byte, 4) + lengthNum := int(0) + + // we're going to indefinitely read the first 4 bytes in buffer, which gives us the message length. + // if stdIn is closed we'll exit the loop and shut down host + for b, err := s.Read(lengthBytes); b > 0 && err == nil; b, err = s.Read(lengthBytes) { + // convert message length bytes to integer value + lengthNum = readMessageLength(lengthBytes) + Trace.Printf("Message size in bytes: %v", lengthNum) + + // If message length exceeds size of buffer, the message will be truncated. + // This will likely cause an error when we attempt to unmarshal message to JSON. + if lengthNum > bufferSize { + Error.Printf("Message size of %d exceeds buffer size of %d. Message will be truncated and is unlikely to unmarshal to JSON.", lengthNum, bufferSize) + } + + // read the content of the message from buffer + content := make([]byte, lengthNum) + _, err := s.Read(content) + if err != nil && err != io.EOF { + Error.Fatal(err) + } + + // message has been read, now parse and process + parseMessage(content) + } + + Trace.Print("Stdin closed.") +} + +// readMessageLength reads and returns the message length value in native byte order. +func readMessageLength(msg []byte) int { + var length uint32 + buf := bytes.NewBuffer(msg) + err := binary.Read(buf, nativeEndian, &length) + if err != nil { + Error.Printf("Unable to read bytes representing message length: %v", err) + } + return int(length) +} + +// write incoming message to file +func writeMessageToFile(fpath string, content string) { + f, err := os.Create(fpath) + if err != nil { + Error.Printf("Write to file failed: %v", err) + } + defer f.Close() + f.WriteString(content) +} + +// commit edit to git repo +func commitChangeToGit(iMsg IncomingMessage) { + g, err := git.PlainOpen(iMsg.Gitpath) + if err != nil { + Error.Printf("ERROR: Go-git Plain Open:", err) + } + w, err := g.Worktree() + if err != nil { + Error.Printf("ERROR: Go-git Worktree:", err) + } + // filePath := filepath.Base(iMsg.Filepath) + // editFile := filepath.Join(iMsg.Gitpath, filePath) + relPathFile := filepath.Join(strings.ReplaceAll(iMsg.Filepath, iMsg.Gitpath+"/", "")) + // err = ioutil.WriteFile(iMsg.Filepath, []byte(iMsg.Hugopage), 0644) + // check(err) + writeMessageToFile(iMsg.Filepath, iMsg.Hugopage) + _, err = w.Add(relPathFile) + if err != nil { + Error.Printf("ERROR: Go-git Add:", err) + } + tn := time.Now() + w.Commit(fmt.Sprintf("sandpoints-ext - %s - editing via browser...", tn), &git.CommitOptions{ + Author: &object.Signature{ + Name: "Sandpoints Edit Page", + Email: "editpage@sandpoints.org", + When: tn, + }, + }) +} + +// trigger git hook +func triggerGitHook(gitpath string, publish bool, offline bool, protocol string) { + cmd := exec.Command(filepath.Join(gitpath, ".git", "hooks", "post-commit")) + stdin, err := cmd.StdinPipe() + if err != nil { + Error.Printf("StdinPipe:", err) + } + pub := "nope" + if publish { + pub = "publish" + } + offl := "nope" + if offline { + offl = "offline" + } + + go func() { + defer stdin.Close() + io.WriteString(stdin, fmt.Sprintf("sandpoints-ext %s %s %s", pub, offl, protocol)) + }() + out, err := cmd.CombinedOutput() + if err != nil { + Error.Printf("ERROR Combined output: %s", err) + } + Trace.Printf("Git Hook Combined Output: %s", out) +} + +// parseMessage parses incoming message +func parseMessage(msg []byte) { + iMsg := decodeMessage(msg) + Trace.Printf("Message received: %s", msg) + + commitChangeToGit(iMsg) + triggerGitHook(iMsg.Gitpath, iMsg.Publish, iMsg.Offline, iMsg.Protocol) + // start building outgoing json message + oMsg := OutgoingMessage{ + Query: iMsg.Hugopage, + } + + switch iMsg.Hugopage { + case "foo": + oMsg.Response = "bar" + default: + oMsg.Response = "native host says yeah!" + } + + send(oMsg) +} + +// decodeMessage unmarshals incoming json request and returns query value. +func decodeMessage(msg []byte) IncomingMessage { + var iMsg IncomingMessage + err := json.Unmarshal(msg, &iMsg) + if err != nil { + Error.Printf("Unable to unmarshal json to struct: %v", err) + } + return iMsg +} + +// send sends an OutgoingMessage to os.Stdout. +func send(msg OutgoingMessage) { + byteMsg := dataToBytes(msg) + writeMessageLength(byteMsg) + + var msgBuf bytes.Buffer + _, err := msgBuf.Write(byteMsg) + if err != nil { + Error.Printf("Unable to write message length to message buffer: %v", err) + } + + _, err = msgBuf.WriteTo(os.Stdout) + if err != nil { + Error.Printf("Unable to write message buffer to Stdout: %v", err) + } +} + +// dataToBytes marshals OutgoingMessage struct to slice of bytes +func dataToBytes(msg OutgoingMessage) []byte { + byteMsg, err := json.Marshal(msg) + if err != nil { + Error.Printf("Unable to marshal OutgoingMessage struct to slice of bytes: %v", err) + } + return byteMsg +} + +// writeMessageLength determines length of message and writes it to os.Stdout. +func writeMessageLength(msg []byte) { + err := binary.Write(os.Stdout, nativeEndian, uint32(len(msg))) + if err != nil { + Error.Printf("Unable to write message length to Stdout: %v", err) + } +} diff --git a/native-host/src/natgost b/native-host/src/natgost new file mode 100755 index 0000000..ee0d71f Binary files /dev/null and b/native-host/src/natgost differ