ntrip

package module
v0.0.14 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2022 License: Apache-2.0 Imports: 13 Imported by: 3

README

NTRIP Caster / Client / Server implementation in Go

Go Report Card

Examples of NTRIP client implementations in client_test.go.

An example of setting up a Caster can be found in internal/inmemory.

Documentation

Index

Examples

Constants

View Source
const (
	NTRIPVersionHeaderKey     string = "Ntrip-Version"
	NTRIPVersionHeaderValueV2 string = "Ntrip/2.0"
)

Variables

View Source
var (
	ErrorNotAuthorized error = fmt.Errorf("request not authorized")
	ErrorNotFound      error = fmt.Errorf("mount not found")
	ErrorConflict      error = fmt.Errorf("mount in use")
	ErrorBadRequest    error = fmt.Errorf("bad request")

	// TODO: Added this so a SourceService implementation can extract the Request ID, not sure that
	//  smuggling it in the context is the best approach
	RequestIDContextKey contextKey = contextKey("RequestID")
)

It's expected that SourceService implementations will use these errors to signal specific failures. TODO: Could use some kind of response code enum type rather than errors?

Functions

func NewClientRequest added in v0.0.7

func NewClientRequest(url string) (*http.Request, error)

NewClientRequest constructs an http.Request which can be used as an NTRIP v2 Client

Example
package main

import (
	"fmt"
	"net/http"

	"github.com/go-gnss/ntrip"
)

func main() {
	req, _ := ntrip.NewClientRequest("http://hostname:2101/mountpoint")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Printf("error making NTRIP request: %s", err)
	}

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("received non-200 response code: %d", resp.StatusCode)
	}

	// Read from resp.Body until EOF
}
Output:

Example (Sourcetable)
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/go-gnss/ntrip"
)

func main() {
	req, _ := ntrip.NewClientRequest("https://ntrip.data.gnss.ga.gov.au")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Printf("error making NTRIP request: %s", err)
	}

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("received non-200 response code: %d", resp.StatusCode)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("error reading from response body")
	}

	sourcetable, _ := ntrip.ParseSourcetable(string(data))
	fmt.Printf("caster has %d mountpoints available", len(sourcetable.Mounts))
}
Output:

func NewClientV1

func NewClientV1(host string, path, username, password string) (io.ReadCloser, error)

TODO: Remove v1 client

func NewServerRequest added in v0.0.7

func NewServerRequest(url string, r io.ReadCloser) (*http.Request, error)

NewServerRequest constructs an http.Request which can be used as an NTRIP v2 Server Effectively a chunked encoding POST request which is not expected to close

Example
package main

import (
	"fmt"
	"io"
	"net/http"

	"github.com/go-gnss/ntrip"
)

func main() {
	r, w := io.Pipe()

	req, _ := ntrip.NewServerRequest("http://hostname:2101/mountpoint", r)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Printf("error making NTRIP request: %s", err)
	}

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("received non-200 response code: %d", resp.StatusCode)
	}

	w.Write([]byte("write data to the NTRIP caster"))
	w.Close()
}
Output:

Types

type Caster

type Caster struct {
	http.Server
}

Caster wraps http.Server, it provides nothing but timeouts and the Handler

func NewCaster

func NewCaster(addr string, svc SourceService, logger logrus.FieldLogger) *Caster

NewCaster constructs a Caster, setting up the Handler and timeouts - run using ListenAndServe() TODO: Consider not constructing the http.Server, and leaving Caster as a http.Handler

Then the caller can create other routes on the server, such as (for example) a /health endpoint,
or a /stats endpoint - Though those could instead be run on separate http.Server's
Also, middleware can be added to a Caster by doing `c.Handler = someMiddleware(c.Handler)`

type CasterEntry

type CasterEntry struct {
	Host                string
	Port                int
	Identifier          string
	Operator            string
	NMEA                bool
	Country             string
	Latitude            float32
	Longitude           float32
	FallbackHostAddress string
	FallbackHostPort    int
	Misc                string
}

CasterEntry for an NTRIP Sourcetable

func ParseCasterEntry added in v0.0.2

func ParseCasterEntry(casterString string) (CasterEntry, []error)

ParseCasterEntry parses a single caster from a string.

func (CasterEntry) String

func (c CasterEntry) String() string

type NetworkEntry

type NetworkEntry struct {
	Identifier string
	Operator   string
	// TODO: Authentication type - spec says: B, D, N or a comma separated list of these
	Authentication string
	Fee            bool
	NetworkInfoURL string
	StreamInfoURL  string
	// RegistrationAddress is either a URL or Email address
	RegistrationAddress string
	Misc                string
}

NetworkEntry for an NTRIP Sourcetable

func ParseNetworkEntry added in v0.0.2

func ParseNetworkEntry(netString string) (NetworkEntry, []error)

ParseNetworkEntry parses a single network entry from a string.

func (NetworkEntry) String

func (n NetworkEntry) String() string

type SourceService

type SourceService interface {
	GetSourcetable() Sourcetable
	// TODO: Specifying username and password may be limiting, could instead take the content of
	//  the auth header
	// TODO: A SourceService implementation can't support nearest base functionality because it
	//  wouldn't have access to NMEA headers - in general, it may be arbitrarily limiting to not
	//  pass the http.Request object (leaving it up to the implementation to parse headers etc.)
	Publisher(ctx context.Context, mount, username, password string) (io.WriteCloser, error)
	Subscriber(ctx context.Context, mount, username, password string) (chan []byte, error)
}

SourceService represents a provider of stream data

type Sourcetable

type Sourcetable struct {
	Casters  []CasterEntry
	Networks []NetworkEntry
	Mounts   []StreamEntry
}

Sourcetable for NTRIP Casters, returned at / as a way for users to discover available mounts

func GetSourcetable added in v0.0.2

func GetSourcetable(ctx context.Context, url string) (Sourcetable, []error, error)

GetSourcetable fetches a source table from a specific caster.

The funciton returns a list of errors which can be treated as warnings. These warnings indicate that the caster is returning an improper rtcm3 format.

Example
ctx := context.Background()
url := "http://auscors.ga.gov.au:2101"

mapping, warnings, err := GetSourcetable(ctx, url)

fmt.Println(mapping, warnings, err)
Output:

func ParseSourcetable added in v0.0.2

func ParseSourcetable(str string) (Sourcetable, []error)

ParseSourcetable parses a sourcetable from an ioreader into a ntrip style source table.

func (Sourcetable) String

func (st Sourcetable) String() string

type StreamEntry added in v0.0.2

type StreamEntry struct {
	Name          string
	Identifier    string
	Format        string
	FormatDetails string
	Carrier       string
	NavSystem     string
	Network       string
	CountryCode   string
	Latitude      float32
	Longitude     float32
	NMEA          bool
	Solution      bool
	Generator     string
	Compression   string
	// TODO: Authentication type
	Authentication string
	Fee            bool
	Bitrate        int
	Misc           string
}

StreamEntry for an NTRIP Sourcetable

func ParseStreamEntry added in v0.0.2

func ParseStreamEntry(streamString string) (StreamEntry, []error)

ParseStreamEntry parses a single mount entry.

func (StreamEntry) String added in v0.0.2

func (m StreamEntry) String() string

String representation of Mount in NTRIP Sourcetable entry format

Directories

Path Synopsis
cmd
relay
Example of how to implement Client and Server to relay streams
Example of how to implement Client and Server to relay streams
internal

Jump to

Keyboard shortcuts

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