host

package module
v1.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 16, 2022 License: MPL-2.0 Imports: 18 Imported by: 1

README

Build Coverage Dependabot GoDev GoDoc License

Native Messaging Host Module for Go

native-messaging-host is a module for sending native messaging protocol message marshalled from struct and receiving native messaging protocol message unmarshalled to struct. native-messaging-host can auto-update itself using update URL that response with Google Chrome update manifest, as well as it provides hook to install and uninstall manifest file to native messaging host location.

Installation and Usage

Package documentation can be found on GoDev or GoDoc.

Installation can be done with a normal go get:

$ go get github.com/rickypc/native-messaging-host
Sending Message
messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
response := &host.H{"key":"value"}

// Write message from response to os.Stdout.
if err := messaging.PostMessage(os.Stdout, response); err != nil {
  log.Fatalf("messaging.PostMessage error: %v", err)
}

// Log response.
log.Printf("response: %+v", response)
Receiving Message
// Ensure func main returned after calling [runtime.Goexit][5].
defer os.Exit(0)

messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
request := &host.H{}

// Read message from os.Stdin to request.
if err := messaging.OnMessage(os.Stdin, request); err != nil {
  log.Fatalf("messaging.OnMessage error: %v", err)
}

// Log request.
log.Printf("request: %+v", request)
Auto Update Configuration

updates.xml example for cross platform executable:

<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='tld.domain.sub.app.name'>
    <updatecheck codebase='https://sub.domain.tld/app.download.all' version='1.0.0' />
  </app>
</gupdate>

updates.xml example for individual platform executable:

<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='tld.domain.sub.app.name'>
    <updatecheck codebase='https://sub.domain.tld/app.download.darwin' os='darwin' version='1.0.0' />
    <updatecheck codebase='https://sub.domain.tld/app.download.linux' os='linux' version='1.0.0' />
    <updatecheck codebase='https://sub.domain.tld/app.download.exe' os='windows' version='1.0.0' />
  </app>
</gupdate>
// It will do daily update check.
messaging := (&host.Host{
  AppName:   "tld.domain.sub.app.name",
  UpdateUrl: "https://sub.domain.tld/updates.xml", // It follows [update manifest][2]
  Version:   "1.0.0",                              // Current version, it must follow [SemVer][6]
}).Init()
Install and Uninstall Hooks
// AllowedExts is a list of extensions that should have access to the native messaging host. 
// See [native messaging manifest](https://bit.ly/3aDA1Hv)
messaging := (&host.Host{
  AppName:     "tld.domain.sub.app.name",
  AllowedExts: []string{"chrome-extension://XXX/", "chrome-extension://YYY/"},
}).Init()

...

// When you need to install.
if err := messaging.Install(); err != nil {
  log.Printf("install error: %v", err)
}

...

// When you need to uninstall.
host.Uninstall()
Syntactic Sugar

You can import client package separately.

import "github.com/rickypc/native-messaging-host/client"
GET call with context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

resp := client.MustGetWithContext(ctx, "https://domain.tld")
defer resp.Body.Close()
GET call with tar.gz content
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

client.MustGetAndUntarWithContext(ctx, "https://domain.tld", "/path/to/extract")
GET call with zip content
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

client.MustGetAndUnzipWithContext(ctx, "https://domain.tld", "/path/to/extract")
POST call with context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

resp := client.MustPostWithContext(ctx, "https://domain.tld", "application/json", strings.NewReader("{}"))
defer resp.Body.Close()

Contributing

If you would like to contribute code to Native Messaging Host repository you can do so through GitHub by forking the repository and sending a pull request.

If you do not agree to Contribution Agreement, do not contribute any code to Native Messaging Host repository.

When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. Please also include appropriate test cases.

That's it! Thank you for your contribution!

License

Copyright (c) 2018 - 2022 Richard Huang.

This utility is free software, licensed under: Mozilla Public License (MPL-2.0).

Documentation and other similar content are provided under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Documentation

Overview

Package host provides native-messaging host configurations, send and receive message handler, manifest install and uninstall, as well as auto update daily check.

* Sending Message

messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
response := &host.H{"key":"value"}

// Write message from response to os.Stdout.
if err := messaging.PostMessage(os.Stdout, response); err != nil {
  log.Fatalf("messaging.PostMessage error: %v", err)
}

// Log response.
log.Printf("response: %+v", response)

* Receiving Message

// Ensure func main returned after calling runtime.Goexit
// See https://golang.org/pkg/runtime/#Goexit.
defer os.Exit(0)

messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
request := &host.H{}

// Read message from os.Stdin to request.
if err := messaging.OnMessage(os.Stdin, request); err != nil {
  log.Fatalf("messaging.OnMessage error: %v", err)
}

// Log request.
log.Printf("request: %+v", request)

* Install and Uninstall Hooks

// AllowedExts is a list of extensions that should have access to the native messaging host.
// See [native messaging manifest][7]
messaging := (&host.Host{
  AppName:     "tld.domain.sub.app.name",
  AllowedExts: []string{"chrome-extension://XXX/", "chrome-extension://YYY/"},
}).Init()

...

// When you need to install.
if err := messaging.Install(); err != nil {
  log.Printf("install error: %v", err)
}

...

// When you need to uninstall.
host.Uninstall()

* Auto Update Configuration

// updates.xml example for cross platform executable:
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='tld.domain.sub.app.name'>
    <updatecheck codebase='https://sub.domain.tld/app.download.all' version='1.0.0' />
  </app>
</gupdate>

// updates.xml example for individual platform executable:
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='tld.domain.sub.app.name'>
    <updatecheck codebase='https://sub.domain.tld/app.download.darwin' os='darwin' version='1.0.0' />
    <updatecheck codebase='https://sub.domain.tld/app.download.linux' os='linux' version='1.0.0' />
    <updatecheck codebase='https://sub.domain.tld/app.download.exe' os='windows' version='1.0.0' />
  </app>
</gupdate>

// It will do daily update check.
messaging := (&host.Host{
  AppName:   "tld.domain.sub.app.name",
  UpdateUrl: "https://sub.domain.tld/updates.xml", // It follows [update manifest][2]
  Version:   "1.0.0",                              // Current version, it must follow [SemVer][6]
}).Init()

Index

Constants

View Source
const (
	HttpContinueTimeout   = 5
	HttpKeepAlive         = 600
	HttpDialTimeout       = 10
	HttpOverallTimeout    = 15
	IdleTimeout           = 90
	MaxConnections        = 100
	ResponseHeaderTimeout = 10
	TLSDialTimeout        = 15
)

The Http connection and timeout configurations.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	AppId   *string   `xml:"appid,attr"`
	Updates []*Update `xml:"updatecheck"`
}

An App is represent one application returned by updates.xml.

<app appid='tld.domain.sub.app.name'></app>

type FileInterface added in v1.13.0

type FileInterface interface {
	io.Closer
	io.Writer
}

FileInterface is an interface for OpenFile first-value return. It helps write testable code.

type FileSystem added in v1.13.0

type FileSystem struct{}

FileSystem is an implementation of FileSystemInterface. It helps write testable code.

func (*FileSystem) OpenFile added in v1.13.0

func (f *FileSystem) OpenFile(name string, flag int, perm os.FileMode) (FileInterface, error)

OpenFile is an implementation of FileSystemInterface.OpenFile and wrap os.OpenFile. It helps write testable code.

type FileSystemInterface added in v1.13.0

type FileSystemInterface interface {
	OpenFile(name string, flag int, perm os.FileMode) (FileInterface, error)
}

FileSystemInterface is an interface for OpenFile to be overridable. It helps write testable code.

type H

type H map[string]interface{}

H is a map[string]interface{} type shortcut and represents a dynamic key-value-pair data.

type Host

type Host struct {
	AppName     string           `json:"name"`
	AppDesc     string           `json:"description"`
	ExecName    string           `json:"path"`
	AppType     string           `json:"type"`
	AllowedExts []string         `json:"allowed_origins"`
	AutoUpdate  bool             `json:"-"`
	ByteOrder   binary.ByteOrder `json:"-"`
	UpdateUrl   string           `json:"-"`
	Version     string           `json:"-"`
}

Host represents a single native messaging host, where all native messaging host operations can be done.

func (*Host) AutoUpdateCheck

func (h *Host) AutoUpdateCheck()

AutoUpdateCheck downloads the latest update as necessary.

func (*Host) Init

func (h *Host) Init() *Host

Init sets default value to its fields and return the Host pointer back.

* AppName is an application name in manifest file and will be defaulted to current executable file name without extension, if any.

* AppDesc is an application description in manifest file and will be defaulted to current AppName.

* AppType is an application communication type in manifest file and will be defaulted to "stdio".

* AutoUpdate indicates whether update check will be perform for this application and will be defaulted to true only if UpdateUrl and application Version are present, otherwise it will be false.

* ByteOrder specifies how to convert byte sequences into unsigned integers and will be defaulted to binary.LittleEndian.

* ExecName is an executable path used across the module and will get assigned to current executable's absolute path after the evaluation of any symbolic links.

messaging := (&host.Host{}).Init()

func (*Host) Install

func (h *Host) Install() error

Install creates native-messaging manifest file on appropriate location. It will return error when it come across one.

See https://developer.chrome.com/extensions/nativeMessaging#native-messaging-host-location-nix

func (*Host) OnMessage

func (h *Host) OnMessage(reader io.Reader, v interface{}) error

OnMessage reads message header and message body from given reader and unmarshal to given struct. It will return error when it come across one.

// Ensure func main returned after calling runtime.Goexit
// See https://golang.org/pkg/runtime/#Goexit.
defer os.Exit(0)

messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
request := &host.H{}

// Read message from os.Stdin to request.
if err := messaging.OnMessage(os.Stdin, request); err != nil {
  log.Fatalf("messaging.OnMessage error: %v", err)
}

// Log request.
log.Printf("request: %+v", request)

func (*Host) PostMessage

func (h *Host) PostMessage(writer io.Writer, v interface{}) error

PostMessage marshals given struct and writes message header and message body to given writer. It will return error when it come across one.

messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
response := &host.H{"key":"value"}

// Write message from response to os.Stdout.
if err := messaging.PostMessage(os.Stdout, response); err != nil {
  log.Fatalf("messaging.PostMessage error: %v", err)
}

// Log response.
log.Printf("response: %+v", response)

func (*Host) Uninstall

func (h *Host) Uninstall()

Uninstall removes native-messaging manifest file from installed location.

See https://developer.chrome.com/extensions/nativeMessaging#native-messaging-host-location-nix

type Update

type Update struct {
	Goos    *string `xml:"os,attr"`
	Url     *string `xml:"codebase,attr"`
	Version *string `xml:"version,attr"`
}

An Update is represent application download URL and latest version.

It can have target OS optionally. This is an extended attribute that is not part of original Google Chrome update manifest.

<updatecheck codebase='https://sub.domain.tld/app.download.all' os='darwin' version='1.0.0' />

type UpdateCheckResponse

type UpdateCheckResponse struct {
	Apps    []*App   `xml:"app"`
	XMLName xml.Name `xml:"gupdate"`
}

An UpdateCheckResponse implements Google Chrome update manifest XML format borrowed from Google's Omaha. See https://developer.chrome.com/apps/autoupdate#update_manifest

<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'></gupdate>

func (*UpdateCheckResponse) GetUrlAndVersion

func (u *UpdateCheckResponse) GetUrlAndVersion(appName string) (string, string)

GetUrlAndVersion returns download URL and latest version of given application name.

Directories

Path Synopsis
Package client provides HTTP client related syntactic sugar.
Package client provides HTTP client related syntactic sugar.
Package packer provides extracting archive related syntactic sugar.
Package packer provides extracting archive related syntactic sugar.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL