summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--CHANGELOG.md2
-rw-r--r--Makefile12
-rw-r--r--README.md133
-rwxr-xr-xbuild.sh50
-rw-r--r--cmd/rr/.rr.yaml2
-rw-r--r--cmd/rr/cmd/root.go6
-rw-r--r--cmd/rr/cmd/version.go6
-rw-r--r--cmd/rr/debug/debugger.go (renamed from cmd/rr/debug/listener.go)28
-rw-r--r--cmd/rr/main.go2
-rw-r--r--config.go6
-rw-r--r--go.mod30
-rw-r--r--server.go8
-rw-r--r--server_config.go2
-rw-r--r--service/http/config.go2
-rw-r--r--service/http/handler.go10
-rw-r--r--service/http/request.go6
-rw-r--r--service/http/service.go1
-rw-r--r--service/http/uploads.go13
-rw-r--r--service/http/uploads_config.go2
-rw-r--r--service/service.go2
-rw-r--r--service/static/config.go2
-rw-r--r--static_pool.go2
23 files changed, 237 insertions, 94 deletions
diff --git a/.gitignore b/.gitignore
index 14470a50..32f835d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,4 @@
-coverage.txt
-.idea
.idea/*
composer.lock
vendor/
-bin/ \ No newline at end of file
+builds/ \ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 73989e34..e04d02b1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,5 +19,5 @@ v1.0.0 (14.06.2018)
- less dependencies
- yaml/json configs (thx viper)
- CLI application server
-- middlewares and event listeners
+- middleware and event listeners support
- psr7 library for php
diff --git a/Makefile b/Makefile
index 9726ed69..0ee41909 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,16 @@
+all:
+ @./build.sh
+build:
+ @./build.sh all
+clean:
+ rm -rf rr
+install: all
+ cp rr /usr/local/bin/rr
+uninstall:
+ rm -f /usr/local/bin/rr
test:
go test -v -race -cover
go test -v -race -cover ./service
go test -v -race -cover ./service/rpc
go test -v -race -cover ./service/http
- go test -v -race -cover ./service/static \ No newline at end of file
+ go test -v -race -cover ./service/static
diff --git a/README.md b/README.md
index 2b13ad24..4b8b2904 100644
--- a/README.md
+++ b/README.md
@@ -7,13 +7,14 @@ RoadRunner
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/spiral/roadrunner/badges/quality-score.png)](https://scrutinizer-ci.com/g/spiral/roadrunner/?branch=master)
[![Codecov](https://codecov.io/gh/spiral/roadrunner/branch/master/graph/badge.svg)](https://codecov.io/gh/spiral/roadrunner/)
-High-Performance PSR-7 PHP application server, load balancer and process manager.
+RoadRunner is an open source (MIT licensed), high-performance PSR-7 PHP application server, load balancer and process manager.
+It supports service model with ability to extend it's functionality on a project basis.
Features:
--------
- PSR-7 HTTP server (file uploads, error handling, static files, hot reload, middlewares, event listeners)
- extendable service model (plus PHP compatible RPC server)
-- no external services, drop-in (based on [Goridge](https://github.com/spiral/goridge))
+- no external PHP dependencies, drop-in (based on [Goridge](https://github.com/spiral/goridge))
- load balancer, process manager and task pipeline
- frontend agnostic (queue, REST, PSR-7, async php, etc)
- works over TCP, unix sockets and standard pipes
@@ -26,33 +27,32 @@ Features:
- very fast (~250k rpc calls per second on Ryzen 1700X over 16 threads)
- works on Windows
-Installation:
+Getting Started:
--------
-```
-$ go get github.com/spiral/roadrunner
-$ composer require spiral/roadrunner
-```
-Usage:
-------
+#### Getting RoadRunner
+The easiest way to get the latest RoadRunner version is to use one of the pre-built release binaries which are available for
+OSX, Linux, FreeBSD, and Windows. Instructions for using these binaries are on the GitHub [releases page](https://github.com/spiral/roadrunner/releases).
+
+#### Building RoadRunner:
+RoadRunner can be compiled on Linux, OSX, Windows and other 64 bit environments as the only requirement is Go 1.8+ itself.
+
+To build:
```
-$ cd cmd
-$ cd rr
-$ go build && go install
-$ cp .rr.yaml path/to/the/project
+$ make
```
-> TODO: To be updated with build scripts!
+To test:
```
-$ rr serve -v
+$ make test
```
-Example [worker](https://github.com/spiral/roadrunner/blob/master/php-src/tests/http/client.php).
+Using RoadRunner:
+--------
-Example config:
----------------
+In order to use RoadRunner you only have to place `.rr.yaml` file in a root of your php project:
```yaml
# rpc bus allows php application and external clients to talk to rr services.
@@ -95,16 +95,16 @@ http:
# maximum jobs per worker, 0 - unlimited.
maxJobs: 0
- # for how long pool should attempt to allocate free worker (request timeout). In nanoseconds for now :(
- allocateTimeout: 600000000
+ # for how long pool should attempt to allocate free worker (request timeout). Nanoseconds atm.
+ allocateTimeout: 1000000000
- # amount of time given to worker to gracefully destruct itself. In nanoseconds for now :(
- destroyTimeout: 600000000
+ # amount of time given to worker to gracefully destruct itself. Nanoseconds atm.
+ destroyTimeout: 1000000000
# static file serving.
static:
# serve http static files
- enable: false
+ enable: true
# root directory for static file (http would not serve .php and .htaccess files).
dir: "public"
@@ -113,23 +113,76 @@ static:
forbid: [".php", ".htaccess"]
```
-Examples:
+Where `psr-worker.php`:
+
+```php
+$psr7 = new RoadRunner\PSR7Client(new RoadRunner\Worker($relay));
+
+while ($req = $psr7->acceptRequest()) {
+ try {
+ $resp = new \Zend\Diactoros\Response()
+ $resp->getBody()->write("hello world");
+
+ $psr7->respond($resp);
+ } catch (\Throwable $e) {
+ $psr7->getWorker()->error((string)$e);
+ }
+}
+```
+
+> Check how to init relay [here](./php-src/tests/client.php).
+
+Working with RoadRunner service:
--------
+RoadRunner application can be started by calling simple command from the root of your PHP application.
+
+```
+$ rr serve
+```
+
+You can also run RR in debug mode to view all incoming requests.
+
+```
+$ rr serve -d
+```
+
+You can force RR service to reload it's http workers.
+
+```
+$ rr http:reset
+```
+
+> You can attach this command as file watcher in your IDE.
+
+To view status of all active workers in interactive mode.
+
+```
+$ rr http:workers -i
+```
+
+Standalone Usage:
+--------
+You can also use RoadRunner as library in order to drive your application without any additional protocol at top of it.
+
```go
-p, err := rr.NewPool(
- func() *exec.Cmd { return exec.Command("php", "worker.php", "pipes") },
- rr.NewPipeFactory(),
- rr.Config{
- NumWorkers: uint64(runtime.NumCPU()),
- AllocateTimeout: time.Second,
- DestroyTimeout: time.Second,
- },
-)
-defer p.Destroy()
-
-rsp, err := p.Exec(&rr.Payload{Body: []byte("hello")})
+srv := NewServer(
+ &ServerConfig{
+ Command: "php client.php echo pipes",
+ Relay: "pipes",
+ Pool: &Config{
+ NumWorkers: int64(runtime.NumCPU()),
+ AllocateTimeout: time.Second,
+ DestroyTimeout: time.Second,
+ },
+ })
+defer srv.Stop()
+
+srv.Start()
+
+res, err := srv.Exec(&Payload{Body: []byte("hello")})
```
+
```php
<?php
/**
@@ -149,13 +202,9 @@ while ($body = $rr->receive($context)) {
}
}
```
-> Check how to init relay [here](./php-src/tests/client.php). More examples can be found in tests.
+> Check how to init relay [here](./php-src/tests/client.php).
-Testing:
---------
-```
-$ make test
-```
+You can find more examples in tests and `php-src` directory.
License:
--------
diff --git a/build.sh b/build.sh
new file mode 100755
index 00000000..fd84fc79
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+set -e
+
+cd $(dirname "${BASH_SOURCE[0]}")
+OD="$(pwd)"
+
+# Pushes application version into the build information.
+RR_VERSION=1.0.1
+
+# Hardcode some values to the core package
+LDFLAGS="$LDFLAGS -X github.com/spiral/roadrunner/cmd/rr/cmd.Version=${RR_VERSION}"
+LDFLAGS="$LDFLAGS -X github.com/spiral/roadrunner/cmd/rr/cmd.BuildTime=$(date +%FT%T%z)"
+
+build(){
+ echo Packaging $1 Build
+ bdir=roadrunner-${RR_VERSION}-$2-$3
+ rm -rf builds/$bdir && mkdir -p builds/$bdir
+ GOOS=$2 GOARCH=$3 ./build.sh
+
+ if [ "$2" == "windows" ]; then
+ mv rr builds/$bdir/rr.exe
+ else
+ mv rr builds/$bdir
+ fi
+
+ cp README.md builds/$bdir
+ cp CHANGELOG.md builds/$bdir
+ cp LICENSE builds/$bdir
+ cd builds
+
+ if [ "$2" == "linux" ]; then
+ tar -zcf $bdir.tar.gz $bdir
+ else
+ zip -r -q $bdir.zip $bdir
+ fi
+
+ rm -rf $bdir
+ cd ..
+}
+
+if [ "$1" == "all" ]; then
+ rm -rf builds/
+ build "Windows" "windows" "amd64"
+ build "Mac" "darwin" "amd64"
+ build "Linux" "linux" "amd64"
+ build "FreeBSD" "freebsd" "amd64"
+ exit
+fi
+
+CGO_ENABLED=0 go build -ldflags "$LDFLAGS -extldflags '-static'" -o "$OD/rr" cmd/rr/main.go \ No newline at end of file
diff --git a/cmd/rr/.rr.yaml b/cmd/rr/.rr.yaml
index ab0f3e7f..775cd6c3 100644
--- a/cmd/rr/.rr.yaml
+++ b/cmd/rr/.rr.yaml
@@ -47,7 +47,7 @@ http:
# static file serving.
static:
# serve http static files
- enable: false
+ enable: true
# root directory for static file (http would not serve .php and .htaccess files).
dir: "public"
diff --git a/cmd/rr/cmd/root.go b/cmd/rr/cmd/root.go
index b1f3ea9a..1a21cfc9 100644
--- a/cmd/rr/cmd/root.go
+++ b/cmd/rr/cmd/root.go
@@ -45,7 +45,11 @@ var (
Use: "rr",
SilenceErrors: true,
SilenceUsage: true,
- Short: utils.Sprintf("<green>RoadRunner, PHP Application Server.</reset>"),
+ Short: utils.Sprintf(
+ "<green>RoadRunner, PHP Application Server:</reset>\nVersion: <yellow+hb>%s</reset>, %s",
+ Version,
+ BuildTime,
+ ),
}
)
diff --git a/cmd/rr/cmd/version.go b/cmd/rr/cmd/version.go
new file mode 100644
index 00000000..5edb7543
--- /dev/null
+++ b/cmd/rr/cmd/version.go
@@ -0,0 +1,6 @@
+package cmd
+
+var (
+ Version = "1.0.0" // Placeholder for the version
+ BuildTime = "development" // Placeholder for the build time
+)
diff --git a/cmd/rr/debug/listener.go b/cmd/rr/debug/debugger.go
index f137b06f..0621285b 100644
--- a/cmd/rr/debug/listener.go
+++ b/cmd/rr/debug/debugger.go
@@ -7,32 +7,32 @@ import (
"github.com/spiral/roadrunner/service/http"
)
-// Listener provide debug callback for system events. With colors!
-type listener struct{ logger *logrus.Logger }
-
-// NewListener creates new debug listener.
-func NewListener(logger *logrus.Logger) *listener {
- return &listener{logger}
+// Listener creates new debug listener.
+func Listener(logger *logrus.Logger) func(event int, ctx interface{}) {
+ return (&debugger{logger}).listener
}
-// Listener listens to http events and generates nice looking output.
-func (s *listener) Listener(event int, ctx interface{}) {
+// listener provide debug callback for system events. With colors!
+type debugger struct{ logger *logrus.Logger }
+
+// listener listens to http events and generates nice looking output.
+func (s *debugger) listener(event int, ctx interface{}) {
// http events
switch event {
case http.EventResponse:
log := ctx.(*http.Event)
- s.logger.Info(utils.Sprintf("%s <white+hb>%s</reset> %s", statusColor(log.Status), log.Method, log.Uri))
+ s.logger.Info(utils.Sprintf("%s <white+hb>%s</reset> %s", statusColor(log.Status), log.Method, log.URI))
case http.EventError:
log := ctx.(*http.Event)
if _, ok := log.Error.(roadrunner.JobError); ok {
- s.logger.Info(utils.Sprintf("%s <white+hb>%s</reset> %s", statusColor(log.Status), log.Method, log.Uri))
+ s.logger.Info(utils.Sprintf("%s <white+hb>%s</reset> %s", statusColor(log.Status), log.Method, log.URI))
} else {
s.logger.Info(utils.Sprintf(
"%s <white+hb>%s</reset> %s <red>%s</reset>",
statusColor(log.Status),
log.Method,
- log.Uri,
+ log.URI,
log.Error,
))
}
@@ -70,12 +70,6 @@ func (s *listener) Listener(event int, ctx interface{}) {
}
}
-// Serve serves.
-func (s *listener) Serve() error { return nil }
-
-// Stop stops the Listener.
-func (s *listener) Stop() {}
-
func statusColor(status int) string {
if status < 300 {
return utils.Sprintf("<green>%v</reset>", status)
diff --git a/cmd/rr/main.go b/cmd/rr/main.go
index 40f191c6..4ab2fbe2 100644
--- a/cmd/rr/main.go
+++ b/cmd/rr/main.go
@@ -55,7 +55,7 @@ func main() {
cobra.OnInitialize(func() {
if debugMode {
service, _ := rr.Container.Get(http.ID)
- service.(*http.Service).AddListener(debug.NewListener(rr.Logger).Listener)
+ service.(*http.Service).AddListener(debug.Listener(rr.Logger))
}
})
diff --git a/config.go b/config.go
index 02008181..929ca806 100644
--- a/config.go
+++ b/config.go
@@ -18,14 +18,14 @@ type Config struct {
// AllocateTimeout defines for how long pool will be waiting for a worker to
// be freed to handle the task.
- AllocateTimeout time.Duration //todo: to milleseconds?
+ AllocateTimeout time.Duration
// DestroyTimeout defines for how long pool should be waiting for worker to
// properly stop, if timeout reached worker will be killed.
- DestroyTimeout time.Duration //todo: to milleseconds?
+ DestroyTimeout time.Duration
}
-// Reconfigure returns error if cfg not valid
+// Valid returns error if config not valid.
func (cfg *Config) Valid() error {
if cfg.NumWorkers == 0 {
return fmt.Errorf("pool.NumWorkers must be set")
diff --git a/go.mod b/go.mod
new file mode 100644
index 00000000..726bee96
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,30 @@
+module github.com/spiral/roadrunner
+
+require (
+ github.com/buger/goterm v0.0.0-20180423150900-6d19e6a8df12
+ github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e
+ github.com/fsnotify/fsnotify v1.4.7
+ github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
+ github.com/magiconair/properties v1.8.0
+ github.com/mattn/go-colorable v0.0.9
+ github.com/mattn/go-isatty v0.0.3
+ github.com/mattn/go-runewidth v0.0.2
+ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
+ github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675
+ github.com/olekukonko/tablewriter v0.0.0-20180506121414-d4647c9c7a84
+ github.com/pelletier/go-toml v1.2.0
+ github.com/pkg/errors v0.8.0
+ github.com/shirou/gopsutil v0.0.0-20180613084040-c23bcca55e77
+ github.com/sirupsen/logrus v1.0.5
+ github.com/spf13/afero v1.1.1
+ github.com/spf13/cast v1.2.0
+ github.com/spf13/cobra v0.0.3
+ github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec
+ github.com/spf13/pflag v1.0.1
+ github.com/spf13/viper v1.0.2
+ github.com/spiral/goridge v1.0.4
+ golang.org/x/crypto v0.0.0-20180614221331-a8fb68e7206f
+ golang.org/x/sys v0.0.0-20180615093615-8014b7b116a6
+ golang.org/x/text v0.3.0
+ gopkg.in/yaml.v2 v2.2.1
+)
diff --git a/server.go b/server.go
index 8cefe1de..f8b0d64b 100644
--- a/server.go
+++ b/server.go
@@ -7,10 +7,10 @@ import (
)
const (
- // EventPoolConstruct triggered when server creates new pool.
+ // EventServerStart triggered when server creates new pool.
EventServerStart = iota + 200
- // EventPoolConstruct triggered when server creates new pool.
+ // EventServerStop triggered when server creates new pool.
EventServerStop
// EventServerFailure triggered when server is unable to replace dead pool.
@@ -23,7 +23,7 @@ const (
EventPoolDestruct
)
-// Service manages pool creation and swapping.
+// Server manages pool creation and swapping.
type Server struct {
// configures server, pool, cmd creation and factory.
cfg *ServerConfig
@@ -50,7 +50,7 @@ func NewServer(cfg *ServerConfig) *Server {
return &Server{cfg: cfg}
}
-// AddListener attaches server event watcher.
+// Listen attaches server event watcher.
func (s *Server) Listen(l func(event int, ctx interface{})) {
s.mul.Lock()
defer s.mul.Unlock()
diff --git a/server_config.go b/server_config.go
index c6567fc3..ecd7dd2b 100644
--- a/server_config.go
+++ b/server_config.go
@@ -8,7 +8,7 @@ import (
"time"
)
-// Server config combines factory, pool and cmd configurations.
+// ServerConfig config combines factory, pool and cmd configurations.
type ServerConfig struct {
// Command includes command strings with all the parameters, example: "php worker.php pipes".
Command string
diff --git a/service/http/config.go b/service/http/config.go
index de791f45..fb4574b1 100644
--- a/service/http/config.go
+++ b/service/http/config.go
@@ -6,7 +6,7 @@ import (
"strings"
)
-// Configures RoadRunner HTTP server.
+// Config configures RoadRunner HTTP server.
type Config struct {
// Enable enables http svc.
Enable bool
diff --git a/service/http/handler.go b/service/http/handler.go
index 2c7c1fad..6f2617b1 100644
--- a/service/http/handler.go
+++ b/service/http/handler.go
@@ -21,8 +21,8 @@ type Event struct {
// Method of the request.
Method string
- // Uri requested by the client.
- Uri string
+ // URI requested by the client.
+ URI string
// Status is response status.
Status int
@@ -40,7 +40,7 @@ type Handler struct {
lsn func(event int, ctx interface{})
}
-// AddListener attaches pool event watcher.
+// Listen attaches handler event watcher.
func (h *Handler) Listen(l func(event int, ctx interface{})) {
h.mul.Lock()
defer h.mul.Unlock()
@@ -99,7 +99,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// handleError sends error.
func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error) {
- h.throw(EventError, &Event{Method: r.Method, Uri: uri(r), Status: 500, Error: err})
+ h.throw(EventError, &Event{Method: r.Method, URI: uri(r), Status: 500, Error: err})
w.WriteHeader(500)
w.Write([]byte(err.Error()))
@@ -107,7 +107,7 @@ func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error)
// handleResponse triggers response event.
func (h *Handler) handleResponse(req *Request, resp *Response) {
- h.throw(EventResponse, &Event{Method: req.Method, Uri: req.Uri, Status: resp.Status})
+ h.throw(EventResponse, &Event{Method: req.Method, URI: req.URI, Status: resp.Status})
}
// throw invokes event srv if any.
diff --git a/service/http/request.go b/service/http/request.go
index 2e8ae090..3082eeb5 100644
--- a/service/http/request.go
+++ b/service/http/request.go
@@ -26,8 +26,8 @@ type Request struct {
// Method contains name of HTTP method used for the request.
Method string `json:"method"`
- // Uri contains full request Uri with scheme and query.
- Uri string `json:"uri"`
+ // URI contains full request URI with scheme and query.
+ URI string `json:"uri"`
// Headers contains list of request headers.
Headers http.Header `json:"headers"`
@@ -53,7 +53,7 @@ func NewRequest(r *http.Request, cfg *UploadsConfig) (req *Request, err error) {
req = &Request{
Protocol: r.Proto,
Method: r.Method,
- Uri: uri(r),
+ URI: uri(r),
Headers: r.Header,
Cookies: make(map[string]string),
RawQuery: r.URL.RawQuery,
diff --git a/service/http/service.go b/service/http/service.go
index 7a7354fb..3d200845 100644
--- a/service/http/service.go
+++ b/service/http/service.go
@@ -27,6 +27,7 @@ type Service struct {
http *http.Server
}
+// AddMiddleware adds new net/http middleware.
func (s *Service) AddMiddleware(m middleware) {
s.mdws = append(s.mdws, m)
}
diff --git a/service/http/uploads.go b/service/http/uploads.go
index 4607dea4..9b205f00 100644
--- a/service/http/uploads.go
+++ b/service/http/uploads.go
@@ -10,23 +10,23 @@ import (
)
const (
- // There is no error, the file uploaded with success.
+ // UploadErrorOK - no error, the file uploaded with success.
UploadErrorOK = 0
- // No file was uploaded.
+ // UploadErrorNoFile - no file was uploaded.
UploadErrorNoFile = 4
- // Missing a temporary folder.
+ // UploadErrorNoTmpDir - missing a temporary folder.
UploadErrorNoTmpDir = 5
- // Failed to write file to disk.
+ // UploadErrorCantWrite - failed to write file to disk.
UploadErrorCantWrite = 6
- // Forbid file extension.
+ // UploadErrorExtension - forbidden file extension.
UploadErrorExtension = 7
)
-// tree manages uploaded files tree and temporary files.
+// Uploads tree manages uploaded files tree and temporary files.
type Uploads struct {
// associated temp directory and forbidden extensions.
cfg *UploadsConfig
@@ -99,6 +99,7 @@ func NewUpload(f *multipart.FileHeader) *FileUpload {
}
}
+// Open moves file content into temporary file available for PHP.
func (f *FileUpload) Open(cfg *UploadsConfig) error {
if cfg.Forbids(f.Name) {
f.Error = UploadErrorExtension
diff --git a/service/http/uploads_config.go b/service/http/uploads_config.go
index 148ebba3..e90d9b70 100644
--- a/service/http/uploads_config.go
+++ b/service/http/uploads_config.go
@@ -25,7 +25,7 @@ func (cfg *UploadsConfig) TmpDir() string {
return os.TempDir()
}
-// Forbid must return true if file extension is not allowed for the upload.
+// Forbids must return true if file extension is not allowed for the upload.
func (cfg *UploadsConfig) Forbids(filename string) bool {
ext := strings.ToLower(path.Ext(filename))
diff --git a/service/service.go b/service/service.go
index 6ddcda41..6cd12b51 100644
--- a/service/service.go
+++ b/service/service.go
@@ -2,7 +2,7 @@ package service
import "sync"
-// svc provides high level functionality for road runner svc.
+// Service provides high level functionality for road runner modules.
type Service interface {
// Init must return configure service and return true if service hasStatus enabled. Must return error in case of
// misconfiguration. Services must not be used without proper configuration pushed first.
diff --git a/service/static/config.go b/service/static/config.go
index d55fcd66..1020b8cd 100644
--- a/service/static/config.go
+++ b/service/static/config.go
@@ -20,7 +20,7 @@ type Config struct {
Forbid []string
}
-// Forbid must return true if file extension is not allowed for the upload.
+// Forbids must return true if file extension is not allowed for the upload.
func (cfg *Config) Forbids(filename string) bool {
ext := strings.ToLower(path.Ext(filename))
diff --git a/static_pool.go b/static_pool.go
index 975ddbe4..b3e4f488 100644
--- a/static_pool.go
+++ b/static_pool.go
@@ -77,7 +77,7 @@ func NewPool(cmd func() *exec.Cmd, factory Factory, cfg Config) (*StaticPool, er
return p, nil
}
-// AddListener attaches pool event watcher.
+// Listen attaches pool event watcher.
func (p *StaticPool) Listen(l func(event int, ctx interface{})) {
p.mul.Lock()
defer p.mul.Unlock()