hoverfly

package module
v0.5.15 Latest Latest
Warning

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

Go to latest
Published: Mar 21, 2016 License: Apache-2.0 Imports: 40 Imported by: 0

README

Circle CI ReportCard

Hoverfly

Dependencies without the sting

Hoverfly is a lightweight, open source service virtualization tool. Using Hoverfly, you can virtualize your application dependencies to create a portable, self-contained development or test sandbox.

Hoverfly is a proxy written in Go. It allows you to create "simulated" dependencies by:

  • Capturing HTTP(s) traffic between your application and external services
  • Building your own "synthetic" services from scratch

Another powerful feature: middleware modules, where users can introduce their own custom logic. Middleware modules can be written in any language.

You can use middleware to simulate network latency, failure, rate limits or malformed responses, or generate responses on the fly.

More information about Hoverfly and how to use it:

Installation

Pre-built binary

Pre-built Hoverfly binaries are available here.

OSX, Linux & *BSD

Download a binary, set the correct permissions:

chmod +x hoverfly*

And run it:

./hoverfly*
Windows

Simply download a .exe file and run it.

Build it yourself

To set up your Go environment - look here.

You must have Go > 1.6 installed.

mkdir -p "$GOPATH/src/github.com/SpectoLabs/"
git clone https://github.com/SpectoLabs/hoverfly.git "$GOPATH/src/github.com/SpectoLabs/hoverfly"
cd "$GOPATH/src/github.com/SpectoLabs/hoverfly"
make build

And to run hoverfly:

./cmd/hoverfly/hoverfly

Admin UI

The Hoverfly admin UI is available at http://localhost:8888/. It uses the API (as described below) to change state. It also allows you to wipe the captured requests/responses and shows the number of captured records. For other functions, such as export/import, you can use the API directly.

Hoverfly is a proxy

Configuring your application to use Hoverfly is simple. All you have to do is set the HTTP_PROXY environment variable:

 export HTTP_PROXY=http://localhost:8500/

Destination configuration

You can specify which site to capture or virtualize with a regular expression (by default, Hoverfly processes everything):

./hoverfly -destination="."

Or you can also provide '-dest' flags to identify regexp patterns of multiple hosts that should be virtualized:

./hoverfly -dest www.myservice.org -dest authentication.service.org -dest some-other-host.com

Hoverfly will process only those requests that have a matching destination. Other requests will be passed through. This allows you to start by virtualizing just a view services, adding more later.

Modes (Virtualize / Capture / Synthesize / Modify)

Hoverfly has different operating modes. Each mode changes the behavior of the proxy. Based on the selected mode, Hoverfly can either capture the requests and responses, look for them in the cache, or send them directly to the middleware and respond with a payload that is generated by the middleware (more on middleware below).

Virtualize

By default, the proxy starts in virtualize mode. You can apply middleware to each response.

Capture

When capture mode is active, Hoverfly acts as a "man-in-the-middle". It makes requests on behalf of a client and records the responses. The response is then sent back to the original client.

To switch to capture mode, you can add the "--capture" flag during startup:

./hoverfly --capture

Or you can select "Capture" using the admin UI at http://localhost:8888/

Or you can use API call to change proxy state while running (see API below).

Do a curl request with proxy details:

curl http://mirage.readthedocs.org --proxy http://localhost:8500/

Synthesize

Hoverfly can create responses to requests on the fly. Synthesize mode intercepts requests (it also respects the --destination flag) and applies the supplied middleware (the user is required to supply --middleware flag, you can read more about it below). The middleware is expected to populate response payload, so Hoverfly can then reconstruct it and return it to the client. An example of a synthetic service can be found in this_repo/examples/middleware/synthetic_service/synthetic.py. You can test it by running:

./hoverfly --synthesize --middleware "../../examples/middleware/synthetic_service/synthetic.py"

Modify

Modify mode applies the selected middleware (the user is required to supply the --middleware flag - you can read more about this below) to outgoing requests and incoming responses (before they are returned to the client). It allows users to use Hoverfly without storing any data about requests. It can be used when it's difficult to - or there is little point in - describing a service, and you only need to change certain parts of the requests or responses (eg: adding authentication headers through with middleware). The example below changes the destination host to "mirage.readthedocs.org" and sets the method to "GET":

./hoverfly --modify --middleware "../../examples/middleware/modify_request/modify_request.py

HTTPS capture

Add ca.pem to your trusted certificates or turn off verification. With curl you can make insecure requests with -k:

curl https://www.bbc.co.uk --proxy http://localhost:8500 -k

API

Usage

You can access the administrator API under the default hostname of 'localhost' and port '8888':

Metadata

Hoverfly metadata API provides easy to use key/value storage to make management of multiple Hoverflies easier. Currently it automatically adds metadata with imported sources if it was done using launching flags ("-import http://mystorehostname/service.json").

You can also set any key/values yourself. Let's give our Hoverfly a name! It would look something like this:

curl -H "Content-Type application/json" -X PUT -d '{"key":"name", "value": "Mad Max"}' http://localhost:8888/metadata

and then add some description to it:

curl -H "Content-Type application/json" -X PUT -d '{"key":"description", "value": "Simulates keystone service, use user XXXX and password YYYYY to login"}' http://localhost:8888/metadata

then, to get your Hoverfly's info - use GET request:

curl http://localhost:8888/metadata

result should be something like this:

{
	"data": {
		"description": "Simulates keystone service, use user XXXX and password YYYYY to login",
		"name": "Peters Hoverfly"
	}
}

if you import some resources during launch:

./hoverfly -import ../../resources/keystone_service.json -import ../../resources/nova_service.json

our metadata will look like:

{
	"data": {
		"description": "Simulates keystone service, use user XXXX and password YYYYY to login",
		"import_1": "../../resources/keystone_service.json",
		"import_2": "../../resources/nova_service.json",
		"name": "Peters Hoverfly"
	}
}

Currently available commands:

Importing data on startup:

Hoverfly can import data on startup from given file or url:

./hoverfly -import my_service.json

or:

./hoverfly -import http://mypage.com/service_x.json

Middleware

Hoverfly supports external middleware modules. You can write them in any language you want !. These middleware modules are expected to take standard input (stdin) and should output a structured JSON string to stdout. Payload example:

{
	"response": {
		"status": 200,
		"body": "body here",
		"headers": {
			"Content-Type": ["text/html"],
			"Date": ["Tue, 01 Dec 2015 16:49:08 GMT"],
		}
	},
	"request": {
		"path": "/",
		"method": "GET",
		"destination": "1stalphaomega.readthedocs.org",
		"query": ""
	},
	"id": "5d4f6b1d9f7c2407f78e4d4e211ec769"
}

Middleware is executed only when request is matched so for fully dynamic responses where you are generating response on the fly you can use ""--synthesize" flag.

In order to use your middleware, just add path to executable:

./hoverfly --middleware "../../examples/middleware/modify_response/modify_response.py"

You should be treating Hoverfly middleware as commands, this enables a bit more complex execution:

.hoverfly --middleware "go run ../../examples/middleware/go_example/change_to_custom_404.go"

In this example Hoverfly is also compiling Go middleware on the fly. However this increases time taken to execute middleware (and therefore to respond) so it's better to precompile middleware binaries before using them.

Python middleware example

Basic example of a Python module to change response body, set different status code and add 2 second delay:

#!/usr/bin/env python
import sys
import logging
import json
from time import sleep


logging.basicConfig(filename='middleware.log', level=logging.DEBUG)
logging.debug('Middleware is called')


def main():
    data = sys.stdin.readlines()
    # this is a json string in one line so we are interested in that one line
    payload = data[0]
    logging.debug(payload)

    payload_dict = json.loads(payload)

    payload_dict['response']['status'] = 201
    payload_dict['response']['body'] = "body was replaced by middleware"

    # now let' sleep for 2 seconds
    sleep(2)

    # returning new payload
    print(json.dumps(payload_dict))

if __name__ == "__main__":
    main()

Save this file with python extension, chmod +x it and run hoverfly:

./hoverfly --middleware "./this_file.py"
JavaScript middleware example

You can also execute JavaScript middleware using Node. Make sure that you can execute Node, you can brew install it on OSX.

Below is an example how to take data in, parse JSON, modify it and then encode it back to string and return:

#!/usr/bin/env node

process.stdin.resume();  
process.stdin.setEncoding('utf8');  
process.stdin.on('data', function(data) {
  var parsed_json = JSON.parse(data);
  // changing response
  parsed_json.response.status = 201;
  parsed_json.response.body = "body was replaced by JavaScript middleware\n";

  // stringifying JSON response
  var newJsonString = JSON.stringify(parsed_json);

  process.stdout.write(newJsonString);
});

You see, it's really easy to use it to create a synthetic service to simulate backend when you are working on the frontend side :)

How middleware interacts with different modes

Each mode is affected by middleware in a different way. Since the JSON payload has request and response structures, some middleware will not change anything. Some information about middleware behaviour:

  • Capture Mode: middleware affects only outgoing requests.
  • Virtualize Mode: middleware affects only responses (cache contents remain untouched).
  • Synthesize Mode: middleware creates responses.
  • Modify Mode: middleware affects requests and responses.

Debugging

You can supply "-v" flag to enable verbose logging.

Contributing

Contributions are welcome!

To submit a pull request you should fork the Hoverfly repository, and make your change on a feature branch of your fork. Then generate a pull request from your branch against master of the Hoverfly repository. Include in your pull request details of your change (why and how, as well as the testing you have performed). To read more about forking model, check out this link: forking workflow. Hoverfly is a new project, we will soon provide detailed roadmap.

License

Apache License version 2.0 See LICENSE for details.

(c) SpectoLabs 2015.

Documentation

Index

Constants

View Source
const (
	HoverflyAuthEnabledEV     = "HoverflyAuthEnabled"
	HoverflySecretEV          = "HoverflySecret"
	HoverflyTokenExpirationEV = "HoverflyTokenExpiration"

	HoverflyAdminPortEV = "AdminPort"
	HoverflyProxyPortEV = "ProxyPort"

	HoverflyDBEV         = "HoverflyDB"
	HoverflyMiddlewareEV = "HoverflyMiddleware"
)

Environment variables

View Source
const ActionTypeConfigurationChanged = "configurationChanged"

ActionTypeConfigurationChanged - default action name for identifying configuration changes

View Source
const ActionTypeRequestCaptured = "requestCaptured"

ActionTypeRequestCaptured - default action type name for identifying

View Source
const ActionTypeWipeDB = "wipeDatabase"

ActionTypeWipeDB - default action type for wiping database

View Source
const CaptureMode = "capture"

CaptureMode - requests are captured and stored in cache

View Source
const DefaultAdminPort = "8888"

DefaultAdminPort - default admin interface port

View Source
const DefaultDatabaseName = "requests.db"

DefaultDatabaseName - default database name that will be created or used by Hoverfly

View Source
const DefaultJWTExpirationDelta = 72

DefaultJWTExpirationDelta - default token expiration if environment variable is no provided

View Source
const DefaultPort = "8500"

DefaultPort - default proxy port

View Source
const ModifyMode = "modify"

ModifyMode - middleware is applied to outgoing and incoming traffic

View Source
const SynthesizeMode = "synthesize"

SynthesizeMode - all requests are sent to middleware to create response

View Source
const URL string = `` /* 321-byte string literal not displayed */

URL is regexp to match http urls

View Source
const VirtualizeMode = "virtualize"

VirtualizeMode - default mode when Hoverfly looks for captured requests to respond

Variables

View Source
var TestDB *bolt.DB

TestDB - holds connection to database during tests

Functions

func GetNewMinifiers added in v0.5.15

func GetNewMinifiers() *minify.M

GetNewMinifiers - returns minify.M with prepared xml/json minifiers

func GetRandomName added in v0.5.1

func GetRandomName(n int) []byte

GetRandomName - provides random name for buckets. Each test case gets it's own bucket

func Pipeline

func Pipeline(cmds ...*exec.Cmd) (pipeLineOutput, collectedStandardError []byte, pipeLineError error)

Pipeline - to provide input to the pipeline, assign an io.Reader to the first's Stdin.

func SynthesizeResponse added in v0.5.10

func SynthesizeResponse(req *http.Request, middleware string) (*http.Response, error)

SynthesizeResponse calls middleware to populate response data, nothing gets pass proxy

Types

type ActionType added in v0.5.11

type ActionType string

ActionType - action type can be things such as "RequestCaptured", "GotResponse" - anything

type ActionTypeHooks added in v0.5.11

type ActionTypeHooks map[ActionType][]Hook

ActionTypeHooks type for storing the hooks

func (ActionTypeHooks) Add added in v0.5.11

func (hooks ActionTypeHooks) Add(hook Hook)

Add a hook

func (ActionTypeHooks) Fire added in v0.5.11

func (hooks ActionTypeHooks) Fire(ac ActionType, entry *Entry) error

Fire all the hooks for the passed ActionType

type Cache

type Cache interface {
	Set(key, value []byte) error
	Get(key []byte) ([]byte, error)
	GetAllValues() ([][]byte, error)
	GetAllEntries() (map[string][]byte, error)
	RecordsCount() (int, error)
	Delete(key []byte) error
	DeleteData() error
	GetAllKeys() (map[string]bool, error)
	CloseDB()
}

Cache - cache interface used to store and retrieve request/response payloads or anything else

type Client

type Client struct {
	HTTPClient *http.Client
}

Client structure to be injected into functions to perform HTTP calls

type Configuration

type Configuration struct {
	AdminPort    string
	ProxyPort    string
	Mode         string
	Destination  string
	Middleware   string
	DatabaseName string

	Verbose     bool
	Development bool

	SecretKey          []byte
	JWTExpirationDelta int
	AuthEnabled        bool

	ProxyControlWG sync.WaitGroup
	// contains filtered or unexported fields
}

Configuration - initial structure of configuration

func InitSettings added in v0.5.3

func InitSettings() *Configuration

InitSettings gets and returns initial configuration from env variables or sets defaults

func (*Configuration) GetMode added in v0.5.3

func (c *Configuration) GetMode() (mode string)

GetMode - provides safe way to get current mode

func (*Configuration) SetMode added in v0.5.3

func (c *Configuration) SetMode(mode string)

SetMode - provides safe way to set new mode

type Constructor

type Constructor struct {
	// contains filtered or unexported fields
}

Constructor - holds information about original request (which is needed to create response and also holds payload

func NewConstructor

func NewConstructor(req *http.Request, payload Payload) *Constructor

NewConstructor - returns constructor instance

func (*Constructor) ApplyMiddleware

func (c *Constructor) ApplyMiddleware(middleware string) error

ApplyMiddleware - activates given middleware, middleware should be passed as string to executable, can be full path.

func (*Constructor) ReconstructRequest added in v0.5.10

func (c *Constructor) ReconstructRequest() (*http.Request, error)

ReconstructRequest replaces original request with details provided in Constructor Payload.Request

func (*Constructor) ReconstructResponse added in v0.5.10

func (c *Constructor) ReconstructResponse() *http.Response

ReconstructResponse changes original response with details provided in Constructor Payload.Response

type CounterByMode added in v0.5.8

type CounterByMode struct {
	// contains filtered or unexported fields
}

CounterByMode - container for mode counters, registry and flush interval

func NewModeCounter added in v0.5.8

func NewModeCounter() *CounterByMode

NewModeCounter - returns new counter instance

func (*CounterByMode) Count added in v0.5.8

func (c *CounterByMode) Count(mode string)

Count - counts requests based on mode

func (*CounterByMode) Flush added in v0.5.8

func (c *CounterByMode) Flush() (h Stats)

Flush gets current metrics from stats registry

func (*CounterByMode) Init added in v0.5.8

func (c *CounterByMode) Init()

Init initializes logging

type DBClient

type DBClient struct {
	Cache   Cache
	HTTP    *http.Client
	Cfg     *Configuration
	Counter *CounterByMode
	Hooks   ActionTypeHooks
	AB      backends.AuthBackend
	MD      Metadata

	Proxy *goproxy.ProxyHttpServer
	SL    *StoppableListener

	MIN *minify.M
	// contains filtered or unexported fields
}

DBClient provides access to cache, http client and configuration

func GetNewHoverfly added in v0.5.10

func GetNewHoverfly(cfg *Configuration, cache Cache) DBClient

GetNewHoverfly returns a configured ProxyHttpServer and DBClient

func (*DBClient) AddHook added in v0.5.11

func (d *DBClient) AddHook(hook Hook)

AddHook - adds a hook to DBClient

func (*DBClient) AllMetadataHandler added in v0.5.13

func (d *DBClient) AllMetadataHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

AllMetadataHandler returns JSON content type http response

func (*DBClient) AllRecordsHandler

func (d *DBClient) AllRecordsHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

AllRecordsHandler returns JSON content type http response

func (*DBClient) CurrentStateHandler

func (d *DBClient) CurrentStateHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

CurrentStateHandler returns current state

func (*DBClient) DeleteAllRecordsHandler

func (d *DBClient) DeleteAllRecordsHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

DeleteAllRecordsHandler - deletes all captured requests

func (*DBClient) DeleteMetadataHandler added in v0.5.13

func (d *DBClient) DeleteMetadataHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

DeleteMetadataHandler - deletes all metadata

func (*DBClient) Import added in v0.5.12

func (d *DBClient) Import(uri string) error

Import is a function that based on input decides whether it is a local resource or whether it should fetch it from remote server. It then imports given payload into the database or returns an error

func (*DBClient) ImportFromDisk added in v0.5.12

func (d *DBClient) ImportFromDisk(path string) error

ImportFromDisk - takes one string value and tries to open a file, then parse it into recordedRequests structure (which is default format in which Hoverfly exports captured requests) and imports those requests into the database

func (*DBClient) ImportFromURL added in v0.5.12

func (d *DBClient) ImportFromURL(url string) error

ImportFromURL - takes one string value and tries connect to a remote server, then parse response body into recordedRequests structure (which is default format in which Hoverfly exports captured requests) and imports those requests into the database

func (*DBClient) ImportPayloads added in v0.5.12

func (d *DBClient) ImportPayloads(payloads []Payload) error

ImportPayloads - a function to save given payloads into the database.

func (*DBClient) ImportRecordsHandler

func (d *DBClient) ImportRecordsHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

ImportRecordsHandler - accepts JSON payload and saves it to cache

func (*DBClient) ManualAddHandler added in v0.5.12

func (d *DBClient) ManualAddHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

ManualAddHandler - manually add new request/responses, using a form

func (*DBClient) RecordsCount added in v0.5.1

func (d *DBClient) RecordsCount(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

RecordsCount returns number of captured requests as a JSON payload

func (*DBClient) SetMetadataHandler added in v0.5.13

func (d *DBClient) SetMetadataHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

SetMetadataHandler - sets new metadata

func (*DBClient) StartAdminInterface added in v0.5.10

func (d *DBClient) StartAdminInterface()

StartAdminInterface - starts admin interface web server

func (*DBClient) StartProxy added in v0.5.15

func (d *DBClient) StartProxy() error

StartProxy - starts proxy with current configuration, this method is non blocking.

func (*DBClient) StateHandler added in v0.5.7

func (d *DBClient) StateHandler(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)

StateHandler handles current proxy state

func (*DBClient) StatsHandler added in v0.5.8

func (d *DBClient) StatsHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)

StatsHandler - returns current stats about Hoverfly (request counts, record count)

func (*DBClient) StatsWSHandler added in v0.5.8

func (d *DBClient) StatsWSHandler(w http.ResponseWriter, r *http.Request)

StatsWSHandler - returns current stats about Hoverfly (request counts, record count) through the websocket

func (*DBClient) StopProxy added in v0.5.15

func (d *DBClient) StopProxy()

StopProxy - stops proxy

func (*DBClient) UpdateDestination added in v0.5.15

func (d *DBClient) UpdateDestination(destination string) (err error)

UpdateDestination - updates proxy with new destination regexp

func (*DBClient) UpdateProxy added in v0.5.15

func (d *DBClient) UpdateProxy()

UpdateProxy - applies hooks

type Entry added in v0.5.11

type Entry struct {
	// Contains encoded data
	Data []byte

	// Time at which the action entry was fired
	Time time.Time

	ActionType ActionType

	// Message, can carry additional information
	Message string
}

Entry - holds information about action, based on action type - other clients will be able to decode the data field.

type Hook added in v0.5.11

type Hook interface {
	ActionTypes() []ActionType
	Fire(*Entry) error
}

Hook - an interface to add dynamic hooks to extend functionality

type Meta added in v0.5.15

type Meta struct {
	DS Cache
}

Meta - metadata backend that uses Cache interface

func NewMetadata added in v0.5.15

func NewMetadata(cache Cache) *Meta

NewMetadata - default metadata store

func (*Meta) CloseDB added in v0.5.15

func (m *Meta) CloseDB()

CloseDB - closes database

func (*Meta) Delete added in v0.5.15

func (m *Meta) Delete(key string) error

Delete - deletes given metadata key

func (*Meta) DeleteData added in v0.5.15

func (m *Meta) DeleteData() error

DeleteData - deletes bucket with all saved data

func (*Meta) Get added in v0.5.15

func (m *Meta) Get(key string) (value string, err error)

Get - gets value for given key

func (*Meta) GetAll added in v0.5.15

func (m *Meta) GetAll() (map[string]string, error)

GetAll - returns all key/value pairs

func (*Meta) Set added in v0.5.15

func (m *Meta) Set(key, value string) error

Set - saves given key and value pair to BoltDB

type Metadata added in v0.5.13

type Metadata interface {
	Set(key, value string) error
	Get(key string) (string, error)
	Delete(key string) error
	GetAll() (map[string]string, error)
	DeleteData() error
	CloseDB()
}

Metadata - interface to store and retrieve any metadata that is related to Hoverfly

type Payload

type Payload struct {
	Response ResponseDetails `json:"response"`
	Request  RequestDetails  `json:"request"`
	ID       string          `json:"id"`
}

Payload structure holds request and response structure

func ExecuteMiddleware

func ExecuteMiddleware(middlewares string, payload Payload) (Payload, error)

ExecuteMiddleware - takes command (middleware string) and payload, which is passed to middleware

func (*Payload) Encode added in v0.5.10

func (p *Payload) Encode() ([]byte, error)

Encode method encodes all exported Payload fields to bytes

type RequestContainer added in v0.5.10

type RequestContainer struct {
	Details  RequestDetails
	Minifier *minify.M
}

RequestContainer holds structure for request

func (*RequestContainer) Hash added in v0.5.10

func (r *RequestContainer) Hash() string

Hash returns unique hash key for request

type RequestDetails added in v0.5.10

type RequestDetails struct {
	Path        string              `json:"path"`
	Method      string              `json:"method"`
	Destination string              `json:"destination"`
	Scheme      string              `json:"scheme"`
	Query       string              `json:"query"`
	Body        string              `json:"body"`
	RemoteAddr  string              `json:"remoteAddr"`
	Headers     map[string][]string `json:"headers"`
}

RequestDetails stores information about request, it's used for creating unique hash and also as a payload structure

type ResponseDetails added in v0.5.10

type ResponseDetails struct {
	Status  int                 `json:"status"`
	Body    string              `json:"body"`
	Headers map[string][]string `json:"headers"`
}

ResponseDetails structure hold response body from external service, body is not decoded and is supposed to be bytes, however headers should provide all required information for later decoding by the client.

type Stats added in v0.5.10

type Stats struct {
	Counters    map[string]int64   `json:"counters"`
	Gauges      map[string]int64   `json:"gauges,omitempty"`
	GaugesFloat map[string]float64 `json:"gaugesFloat,omitempty"`
}

Stats - holds information about various system metrics like requests counts

type StoppableListener added in v0.5.15

type StoppableListener struct {
	*net.TCPListener
	// contains filtered or unexported fields
}

StoppableListener - wrapper for tcp listener that can stop

func NewStoppableListener added in v0.5.15

func NewStoppableListener(l net.Listener) (*StoppableListener, error)

NewStoppableListener returns new StoppableListener listener

func (*StoppableListener) Accept added in v0.5.15

func (sl *StoppableListener) Accept() (net.Conn, error)

Accept - TCPListener waits for the next call, implements default interface method

func (*StoppableListener) Stop added in v0.5.15

func (sl *StoppableListener) Stop()

Stop - stops listener

Directories

Path Synopsis
backends
cmd
examples

Jump to

Keyboard shortcuts

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