Skip to content

Commit 21f6bd0

Browse files
committed
Added plugin support
1 parent 9ed4904 commit 21f6bd0

File tree

8 files changed

+301
-32
lines changed

8 files changed

+301
-32
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
*.test
77
*.out
88
*.pb.go
9-
go.sum
109
.vscode
1110
.DS_Store
1211
build

Makefile

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,46 @@
1+
# Paths to packages
2+
GO=$(shell which go)
13

2-
# Go parameters
3-
GO=go
4-
GOFLAGS = -ldflags "-s -w $(GOLDFLAGS)"
5-
BUILDDIR = build
6-
TAGS =
7-
COMMAND = $(wildcard cmd/*)
4+
# Paths to locations, etc
5+
BUILD_DIR = "build"
6+
BUILD_MODULE = "github.com/djthorpe/go-server"
7+
BUILD_LD_FLAGS += -X $(BUILD_MODULE)/pkg/config.GitSource=${BUILD_MODULE}
8+
BUILD_LD_FLAGS += -X $(BUILD_MODULE)/pkg/config.GitTag=$(shell git describe --tags)
9+
BUILD_LD_FLAGS += -X $(BUILD_MODULE)/pkg/config.GitBranch=$(shell git name-rev HEAD --name-only --always)
10+
BUILD_LD_FLAGS += -X $(BUILD_MODULE)/pkg/config.GitHash=$(shell git rev-parse HEAD)
11+
BUILD_LD_FLAGS += -X $(BUILD_MODULE)/pkg/config.GoBuildTime=$(shell date -u '+%Y-%m-%dT%H:%M:%SZ')
12+
BUILD_FLAGS = -ldflags "-s -w $(BUILD_LD_FLAGS)"
13+
BUILD_VERSION = $(shell git describe --tags)
14+
PLUGIN_DIR = $(wildcard plugin/*)
815

9-
# All targets
10-
all: test commands
16+
.PHONY: all server dependencies mkdir clean
1117

12-
# Rules for building
13-
.PHONY: commands $(COMMAND)
14-
commands: mkdir $(COMMAND)
18+
all: clean server plugins $(PLUGIN_DIR)
1519

16-
$(COMMAND):
17-
@echo "Building ${BUILDDIR}/$@"
18-
@$(GO) build -o ${BUILDDIR}/$@ -tags "$(TAGS)" ${GOFLAGS} ./$@
20+
server: dependencies mkdir
21+
@echo Build server
22+
@${GO} build -o ${BUILD_DIR}/server ${BUILD_FLAGS} github.com/djthorpe/go-server/cmd/server
1923

20-
.PHONY: test
21-
test:
22-
@$(GO) test -tags "$(TAGS)" ./pkg/...
24+
plugins:
25+
@echo Build httpserver and log plugins
26+
@${GO} build -buildmode=plugin -o ${BUILD_DIR}/httpserver.plugin ${BUILD_FLAGS} github.com/djthorpe/go-server/plugin/httpserver
27+
@${GO} build -buildmode=plugin -o ${BUILD_DIR}/log.plugin ${BUILD_FLAGS} github.com/djthorpe/go-server/plugin/log
28+
29+
$(PLUGIN_DIR): FORCE
30+
@echo Build plugin $(notdir $@)
31+
@${GO} build -buildmode=plugin -o ${BUILD_DIR}/$(notdir $@).plugin ${BUILD_FLAGS} ./$@
32+
33+
FORCE:
34+
35+
dependencies:
36+
ifeq (,${GO})
37+
$(error "Missing go binary")
38+
endif
2339

24-
.PHONY: mkdir
2540
mkdir:
26-
@install -d $(BUILDDIR)
41+
@install -d ${BUILD_DIR}
2742

28-
.PHONY: clean
29-
clean:
30-
@rm -fr $(BUILDDIR)
31-
$(GO) mod tidy
32-
$(GO) clean
43+
clean:
44+
@rm -fr $(BUILD_DIR)
45+
@${GO} mod tidy
46+
@${GO} clean

etc/server.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Plugins to load, the order of these is important
2+
plugins:
3+
- build/log.plugin
4+
- build/httpserver.plugin
5+
- build/sqlite3.plugin
6+
7+
# HTTP Server parameters
8+
httpserver:
9+
addr: :80
10+
11+
# Handlers for serving plugins
12+
handlers:
13+
sqlite3:
14+
prefix: /
15+
middleware:
16+
- log
17+
18+
sqlite3:
19+
# Databases to load and/or create
20+
databases:
21+
main: ":memory:"
22+
# Set trace to true to enable the ability to profile queries
23+
trace: true
24+

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ go 1.17
44

55
require (
66
github.com/djthorpe/go-errors v1.0.2
7-
github.com/djthorpe/go-marshaler v0.0.4
7+
github.com/djthorpe/go-marshaler v0.0.13
8+
github.com/djthorpe/go-server v1.0.7
89
github.com/hashicorp/go-multierror v1.1.1
910
github.com/mattn/go-sqlite3 v1.14.8
1011
github.com/rjeczalik/notify v0.9.2
1112
golang.org/x/text v0.3.7
13+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
1214
)
1315

1416
require (

go.sum

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
2+
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo=
3+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
6+
github.com/djthorpe/go-errors v1.0.2 h1:kZuNLhb6Yo1iNHaenGa9s5CpRbOG6KxbUtrME4LrAkk=
7+
github.com/djthorpe/go-errors v1.0.2/go.mod h1:HtfrZnMd6HsX75Mtbv9Qcnn0BqOrrFArvCaj3RMnZhY=
8+
github.com/djthorpe/go-marshaler v0.0.4/go.mod h1:xCXhTzj52UL3YStRsqUSfrKses7ofmfTXYQfVedn8Lw=
9+
github.com/djthorpe/go-marshaler v0.0.13 h1:d0qXD6c/L9MVoCeEzxF85GoyFO/S8ey1bxvt3ndFelY=
10+
github.com/djthorpe/go-marshaler v0.0.13/go.mod h1:xCXhTzj52UL3YStRsqUSfrKses7ofmfTXYQfVedn8Lw=
11+
github.com/djthorpe/go-server v1.0.7 h1:zNGbUhUPtAZjrA3T3RTfbjmTpbpVZL6WwfN+qxbflaI=
12+
github.com/djthorpe/go-server v1.0.7/go.mod h1:yio797qn9P5z2P9ZpASvCnHIFamAaRb+l3ejQJjGicE=
13+
github.com/djthorpe/go-sqlite v1.0.28/go.mod h1:TiGX+dIFea54xxIBVmFemTI/8KUjVUlEoDN2A5HKaMs=
14+
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
15+
github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
16+
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
17+
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
18+
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
19+
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
20+
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
21+
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
22+
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
23+
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
24+
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
25+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
26+
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
27+
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
28+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
29+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
30+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
31+
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
32+
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
33+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
34+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
35+
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
36+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
37+
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
38+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
39+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
40+
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
41+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
42+
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
43+
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
44+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
45+
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
46+
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
47+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
48+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
49+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
50+
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
51+
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
52+
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
53+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
54+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
55+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
56+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
57+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
58+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

pkg/sqlite3/pool.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ import (
2626

2727
// PoolConfig is the starting configuration for a pool
2828
type PoolConfig struct {
29-
Max int64 `yaml:"max"` // The maximum number of connections in the pool
30-
Schemas map[string]string `yaml:"db"` // Schema names mapped onto path for database file
31-
Trace bool `yaml:"trace"` // Profiling for statements
29+
Max int64 `yaml:"max"` // The maximum number of connections in the pool
30+
Schemas map[string]string `yaml:"databases"` // Schema names mapped onto path for database file
31+
Trace bool `yaml:"trace"` // Profiling for statements
3232
Auth SQAuth // Authentication and Authorization interface
3333
Flags sqlite3.OpenFlags // Flags for opening connections
3434
}
@@ -164,7 +164,7 @@ func (p *Pool) Cur() int64 {
164164
// Get a connection from the pool, and return it to the pool when the context
165165
// is cancelled or it is put back using the Put method. If there are no
166166
// connections available, nil is returned.
167-
func (p *Pool) Get(ctx context.Context) *Conn {
167+
func (p *Pool) Get(ctx context.Context) SQConnection {
168168
// Return error if maximum number of connections has been reached
169169
if p.Cur() >= p.Max() {
170170
p.err(ErrChannelBlocked.Withf("Maximum number of connections (%d) reached", p.Cur()))
@@ -201,9 +201,11 @@ func (p *Pool) Get(ctx context.Context) *Conn {
201201
}
202202

203203
// Return connection to the pool
204-
func (p *Pool) Put(conn *Conn) {
205-
if conn != nil {
204+
func (p *Pool) Put(conn SQConnection) {
205+
if conn, ok := conn.(*Conn); ok {
206206
conn.c <- struct{}{}
207+
} else {
208+
panic(ErrBadParameter.With("Put"))
207209
}
208210
}
209211

plugin/sqlite3/handlers.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"regexp"
7+
8+
// Modules
9+
server "github.com/djthorpe/go-server"
10+
router "github.com/djthorpe/go-server/pkg/httprouter"
11+
12+
// Some sort of hack
13+
_ "gopkg.in/yaml.v3"
14+
)
15+
16+
///////////////////////////////////////////////////////////////////////////////
17+
// TYPES
18+
19+
type PingResponse struct {
20+
Version string `json:"version"`
21+
Modules []string `json:"modules"`
22+
Schemas []string `json:"schemas"`
23+
}
24+
25+
///////////////////////////////////////////////////////////////////////////////
26+
// ROUTES
27+
28+
var (
29+
reRoutePing = regexp.MustCompile(`^/?$`)
30+
)
31+
32+
///////////////////////////////////////////////////////////////////////////////
33+
// CONSTANTS
34+
35+
const (
36+
maxResultLimit = 1000
37+
)
38+
39+
///////////////////////////////////////////////////////////////////////////////
40+
// LIFECYCLE
41+
42+
func (p *plugin) AddHandlers(ctx context.Context, provider server.Provider) error {
43+
44+
// Add handler for ping
45+
if err := provider.AddHandlerFuncEx(ctx, reRoutePing, p.ServePing); err != nil {
46+
return err
47+
}
48+
49+
// Return success
50+
return nil
51+
}
52+
53+
///////////////////////////////////////////////////////////////////////////////
54+
// HANDLERS
55+
56+
func (p *plugin) ServePing(w http.ResponseWriter, req *http.Request) {
57+
// Get a connection
58+
conn := p.Get(req.Context())
59+
if conn == nil {
60+
router.ServeError(w, http.StatusBadGateway, "No connection")
61+
return
62+
}
63+
defer p.Put(conn)
64+
65+
// Populate response
66+
response := PingResponse{
67+
Modules: []string{},
68+
Schemas: []string{},
69+
}
70+
response.Modules = append(response.Modules, conn.Modules()...)
71+
response.Schemas = append(response.Schemas, conn.Schemas()...)
72+
73+
// Serve response
74+
router.ServeJSON(w, response, http.StatusOK, 0)
75+
}

plugin/sqlite3/main.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
// Modules
8+
server "github.com/djthorpe/go-server"
9+
sqlite3 "github.com/djthorpe/go-sqlite/pkg/sqlite3"
10+
11+
// Namespace imports
12+
. "github.com/djthorpe/go-sqlite"
13+
)
14+
15+
///////////////////////////////////////////////////////////////////////////////
16+
// TYPES
17+
18+
type plugin struct {
19+
SQPool
20+
errs chan error
21+
}
22+
23+
///////////////////////////////////////////////////////////////////////////////
24+
// GLOBALS
25+
26+
const (
27+
tickerDelta = time.Second * 5
28+
)
29+
30+
///////////////////////////////////////////////////////////////////////////////
31+
// LIFECYCLE
32+
33+
// Create the module
34+
func New(ctx context.Context, provider server.Provider) server.Plugin {
35+
p := new(plugin)
36+
37+
// Get configuration
38+
cfg := sqlite3.PoolConfig{}
39+
if err := provider.GetConfig(ctx, &cfg); err != nil {
40+
provider.Print(ctx, err)
41+
return nil
42+
}
43+
44+
// Create a channel for errors
45+
p.errs = make(chan error)
46+
47+
// Create a pool
48+
if pool, err := sqlite3.OpenPool(cfg, p.errs); err != nil {
49+
provider.Print(ctx, err)
50+
return nil
51+
} else {
52+
p.SQPool = pool
53+
}
54+
55+
// Return success
56+
return p
57+
}
58+
59+
///////////////////////////////////////////////////////////////////////////////
60+
// PUBLIC METHODS
61+
62+
func Name() string {
63+
return "sqlite3"
64+
}
65+
66+
func (p *plugin) Run(ctx context.Context, provider server.Provider) error {
67+
// Add handlers
68+
if err := p.AddHandlers(ctx, provider); err != nil {
69+
return err
70+
}
71+
72+
// Run until cancelled
73+
FOR_LOOP:
74+
for {
75+
select {
76+
case <-ctx.Done():
77+
break FOR_LOOP
78+
case err := <-p.errs:
79+
if err != nil {
80+
provider.Print(ctx, err)
81+
}
82+
}
83+
}
84+
85+
// Close the pool
86+
if err := p.SQPool.Close(); err != nil {
87+
provider.Print(ctx, err)
88+
}
89+
90+
// Close error channel
91+
close(p.errs)
92+
93+
// Return success
94+
return nil
95+
}

0 commit comments

Comments
 (0)